1+ using System ;
2+ using System . Collections . Immutable ;
3+ using System . Linq ;
4+ using BusinessCentral . LinterCop . Helpers ;
5+ using Microsoft . Dynamics . Nav . CodeAnalysis ;
6+ using Microsoft . Dynamics . Nav . CodeAnalysis . Diagnostics ;
7+
8+ namespace BusinessCentral . LinterCop . Design ;
9+
10+ [ DiagnosticAnalyzer ]
11+ public class Rule0094UnnecessaryParameterInMethodCall : DiagnosticAnalyzer
12+ {
13+ public override ImmutableArray < DiagnosticDescriptor > SupportedDiagnostics { get ; } =
14+ ImmutableArray . Create ( DiagnosticDescriptors . Rule0094UnnecessaryParameterInMethodCall ) ;
15+
16+ public override void Initialize ( AnalysisContext context ) => context . RegisterOperationAction (
17+ new Action < OperationAnalysisContext > ( this . AnalyzeInvocation ) ,
18+ OperationKind . InvocationExpression ) ;
19+
20+ private void AnalyzeInvocation ( OperationAnalysisContext context )
21+ {
22+ if ( context . IsObsoletePendingOrRemoved ( ) || context . Operation is not IInvocationExpression operation )
23+ return ;
24+
25+ // Procedure does not contain arguments -> nothing to check
26+ if ( operation . Arguments . IsEmpty )
27+ return ;
28+
29+ // ignore Event publisher
30+ if ( operation . TargetMethod is IMethodSymbol methodSymbol && methodSymbol . IsEvent )
31+ return ;
32+
33+ var instance = operation . Instance ;
34+ if ( instance ? . Type is { NavTypeKind : NavTypeKind . Record } )
35+ {
36+ CheckMethodCalledFromRecord ( context , operation ) ;
37+ return ;
38+ }
39+
40+ // method called in current table
41+ if ( instance is null && HelperFunctions . IsOperationInvokedInTable ( context , operation ) )
42+ {
43+ CheckMethodCalledInCurrentTable ( context , operation ) ;
44+ }
45+ }
46+
47+ private void CheckMethodCalledFromRecord ( OperationAnalysisContext context , IInvocationExpression operation )
48+ {
49+ var instanceSyntax = operation . Instance ? . Syntax ;
50+ if ( instanceSyntax == null )
51+ return ;
52+
53+ var semanticModel = context . Compilation . GetSemanticModel ( instanceSyntax . SyntaxTree ) ;
54+ var instanceSymbol = semanticModel . GetSymbolInfo ( instanceSyntax ) . Symbol ;
55+
56+ if ( instanceSymbol == null )
57+ return ;
58+
59+ foreach ( var argument in operation . Arguments )
60+ {
61+ var argumentSymbol = semanticModel . GetSymbolInfo ( argument . Syntax ) . Symbol ;
62+
63+ if ( argumentSymbol != null &&
64+ instanceSymbol . Equals ( argumentSymbol ) )
65+ {
66+ context . ReportDiagnostic ( Diagnostic . Create (
67+ DiagnosticDescriptors . Rule0094UnnecessaryParameterInMethodCall ,
68+ argument . Syntax . GetLocation ( )
69+ ) ) ;
70+ }
71+ }
72+ }
73+
74+ private void CheckMethodCalledInCurrentTable ( OperationAnalysisContext context , IInvocationExpression operation )
75+ {
76+ // Ignore Clear(...) invocations
77+ if ( IsClearInvocation ( operation ) )
78+ return ;
79+
80+ foreach ( var arg in operation . Arguments )
81+ {
82+ var semanticModel = context . Compilation . GetSemanticModel ( arg . Syntax . SyntaxTree ) ;
83+ var symbolInfo = semanticModel . GetSymbolInfo ( arg . Syntax ) . Symbol ;
84+
85+ if ( symbolInfo != null && string . Equals ( symbolInfo . Name , "Rec" , StringComparison . OrdinalIgnoreCase ) )
86+ {
87+ context . ReportDiagnostic ( Diagnostic . Create (
88+ DiagnosticDescriptors . Rule0094UnnecessaryParameterInMethodCall ,
89+ arg . Syntax . GetLocation ( )
90+ ) ) ;
91+ }
92+ }
93+ }
94+
95+ private static bool IsClearInvocation ( IInvocationExpression operation )
96+ {
97+ var methodSymbol = operation . TargetMethod ;
98+ if ( methodSymbol is null )
99+ return false ;
100+
101+ return string . Equals ( methodSymbol . Name , "Clear" , StringComparison . OrdinalIgnoreCase ) ;
102+ }
103+ }
0 commit comments