@@ -336,11 +336,12 @@ public static class Categories
336336 private static readonly DiagnosticDescriptor InputSizeLimitRule = new (
337337 DiagnosticIds . InputSizeLimit ,
338338 title : "Possible input size limit" ,
339- messageFormat : "This method accepts binary data. Note that external libraries have a 5.5MB total input size limit. For large files, use a REST API endpoint or file URL instead." ,
339+ messageFormat : "One or more methods accept binary data. Note that external libraries have a 5.5MB total input size limit. For large files, use a REST API endpoint or file URL instead." ,
340340 category : Categories . Design ,
341341 defaultSeverity : DiagnosticSeverity . Warning ,
342342 isEnabledByDefault : true ,
343343 description : "External libraries have a 5.5MB total input size limit. For large binary files, expose them through a REST API endpoint in your app or provide a URL to download them." ,
344+ customTags : WellKnownDiagnosticTags . CompilationEnd ,
344345 helpLinkUri : "https://success.outsystems.com/documentation/outsystems_developer_cloud/building_apps/extend_your_apps_with_custom_code/external_libraries_sdk_readme/#use-with-large-binary-files"
345346 ) ;
346347
@@ -441,23 +442,27 @@ CompilationStartAnalysisContext compilationContext
441442 SymbolKind . NamedType
442443 ) ;
443444
445+ // Dictionary tracking the earliest 'byte[]' parameter location per syntax tree
446+ var candidateInputSizeLimitDiagnostics =
447+ new ConcurrentDictionary < SyntaxTree , Location > ( ) ;
448+
444449 // Register a symbol action for method-level analysis
445450 compilationContext . RegisterSymbolAction (
446451 context =>
447452 {
448453 if ( context . Symbol is IMethodSymbol methodSymbol )
449454 {
450- AnalyzeMethod ( context , methodSymbol ) ;
455+ AnalyzeMethod ( context , methodSymbol , candidateInputSizeLimitDiagnostics ) ;
451456 }
452457 } ,
453458 SymbolKind . Method
454459 ) ;
455460
456461 // Register a compilation end action to check for any final conditions
457462 // that can only be verified after all symbols have been processed (for example, # of OSInterfaces).
458- compilationContext . RegisterCompilationEndAction ( ctx =>
463+ compilationContext . RegisterCompilationEndAction ( context =>
459464 {
460- AnalyzeCompilationEnd ( ctx , osInterfaces ) ;
465+ AnalyzeCompilationEnd ( context , osInterfaces , candidateInputSizeLimitDiagnostics ) ;
461466 } ) ;
462467 }
463468
@@ -835,13 +840,15 @@ originalNameArg.Key is not null
835840 /// <summary>
836841 /// Analyzes method declarations.
837842 /// <summary>
838- private static void AnalyzeMethod ( SymbolAnalysisContext context , IMethodSymbol methodSymbol )
843+ private static void AnalyzeMethod (
844+ SymbolAnalysisContext context ,
845+ IMethodSymbol methodSymbol ,
846+ ConcurrentDictionary < SyntaxTree , Location > candidateInputSizeLimitDiagnostics
847+ )
839848 {
840849 var syntaxRef = methodSymbol . DeclaringSyntaxReferences . FirstOrDefault ( ) ;
841850 if ( syntaxRef is null )
842851 return ;
843- if ( syntaxRef . GetSyntax ( ) is not MethodDeclarationSyntax methodSyntax )
844- return ;
845852
846853 var containingType = methodSymbol . ContainingType ;
847854
@@ -899,15 +906,27 @@ private static void AnalyzeMethod(SymbolAnalysisContext context, IMethodSymbol m
899906 }
900907 }
901908
902- // Check for potential input size limit issues
903909 if (
904910 parameter . Type is IArrayTypeSymbol arrayType
905911 && arrayType . ElementType . SpecialType == SpecialType . System_Byte
906912 )
907913 {
908- context . ReportDiagnostic (
909- Diagnostic . Create ( InputSizeLimitRule , methodSyntax . GetLocation ( ) )
910- ) ;
914+ var parameterSyntax =
915+ parameter . DeclaringSyntaxReferences . FirstOrDefault ( ) ? . GetSyntax ( )
916+ as ParameterSyntax ;
917+ if ( parameterSyntax ? . Type != null )
918+ {
919+ var location = parameterSyntax . Type . GetLocation ( ) ;
920+ // Update the candidate location for this file if the current 'byte[]' parameter appears earlier
921+ candidateInputSizeLimitDiagnostics . AddOrUpdate (
922+ parameterSyntax . SyntaxTree ,
923+ location ,
924+ ( tree , existingLocation ) =>
925+ location . SourceSpan . Start < existingLocation . SourceSpan . Start
926+ ? location
927+ : existingLocation
928+ ) ;
929+ }
911930 break ;
912931 }
913932
@@ -1101,7 +1120,8 @@ private static void AnalyzeCompilationEnd(
11011120 ConcurrentDictionary <
11021121 string ,
11031122 ( InterfaceDeclarationSyntax Syntax , INamedTypeSymbol Symbol )
1104- > osInterfaces
1123+ > osInterfaces ,
1124+ ConcurrentDictionary < SyntaxTree , Location > candidateInputSizeLimitDiagnostics
11051125 )
11061126 {
11071127 if ( osInterfaces . Count == 0 )
@@ -1214,6 +1234,11 @@ is InterfaceDeclarationSyntax ifDecl
12141234 ) ;
12151235 }
12161236 }
1237+ // Report one InputSizeLimit diagnostic per file at the earliest recorded location
1238+ foreach ( var kvp in candidateInputSizeLimitDiagnostics )
1239+ {
1240+ context . ReportDiagnostic ( Diagnostic . Create ( InputSizeLimitRule , kvp . Value ) ) ;
1241+ }
12171242 }
12181243
12191244 /// <summary>
0 commit comments