@@ -27,11 +27,14 @@ public override void Initialize(AnalysisContext context)
2727 {
2828 KnownTypeSymbols knownSymbols = new ( context . Compilation ) ;
2929
30- if ( knownSymbols . FunctionOrchestrationAttribute == null || knownSymbols . FunctionNameAttribute == null ||
31- knownSymbols . TaskOrchestratorInterface == null ||
32- knownSymbols . DurableTaskRegistry == null )
30+ // Check if at least one orchestration type can be detected
31+ bool canAnalyzeDurableFunctions = knownSymbols . FunctionOrchestrationAttribute != null && knownSymbols . FunctionNameAttribute != null ;
32+ bool canAnalyzeTaskOrchestrator = knownSymbols . TaskOrchestratorInterface != null && knownSymbols . TaskOrchestrationContext != null ;
33+ bool canAnalyzeFuncOrchestrator = knownSymbols . DurableTaskRegistry != null ;
34+
35+ if ( ! canAnalyzeDurableFunctions && ! canAnalyzeTaskOrchestrator && ! canAnalyzeFuncOrchestrator )
3336 {
34- // symbols not available in this compilation, skip analysis
37+ // no symbols available in this compilation, skip analysis
3538 return ;
3639 }
3740
@@ -42,124 +45,133 @@ public override void Initialize(AnalysisContext context)
4245 }
4346
4447 // look for Durable Functions Orchestrations
45- context . RegisterSyntaxNodeAction (
46- ctx =>
48+ if ( canAnalyzeDurableFunctions )
4749 {
48- ctx . CancellationToken . ThrowIfCancellationRequested ( ) ;
49-
50- if ( ctx . ContainingSymbol is not IMethodSymbol methodSymbol )
50+ context . RegisterSyntaxNodeAction (
51+ ctx =>
5152 {
52- return ;
53- }
53+ ctx . CancellationToken . ThrowIfCancellationRequested ( ) ;
5454
55- if ( ! methodSymbol . ContainsAttributeInAnyMethodArguments ( knownSymbols . FunctionOrchestrationAttribute ) )
56- {
57- return ;
58- }
55+ if ( ctx . ContainingSymbol is not IMethodSymbol methodSymbol )
56+ {
57+ return ;
58+ }
5959
60- if ( ! methodSymbol . TryGetSingleValueFromAttribute ( knownSymbols . FunctionNameAttribute , out string functionName ) )
61- {
62- return ;
63- }
60+ if ( ! methodSymbol . ContainsAttributeInAnyMethodArguments ( knownSymbols . FunctionOrchestrationAttribute ! ) )
61+ {
62+ return ;
63+ }
64+
65+ if ( ! methodSymbol . TryGetSingleValueFromAttribute ( knownSymbols . FunctionNameAttribute ! , out string functionName ) )
66+ {
67+ return ;
68+ }
6469
65- var rootMethodSyntax = ( MethodDeclarationSyntax ) ctx . Node ;
70+ var rootMethodSyntax = ( MethodDeclarationSyntax ) ctx . Node ;
6671
67- visitor . VisitDurableFunction ( ctx . SemanticModel , rootMethodSyntax , methodSymbol , functionName , ctx . ReportDiagnostic ) ;
68- } ,
69- SyntaxKind . MethodDeclaration ) ;
72+ visitor . VisitDurableFunction ( ctx . SemanticModel , rootMethodSyntax , methodSymbol , functionName , ctx . ReportDiagnostic ) ;
73+ } ,
74+ SyntaxKind . MethodDeclaration ) ;
75+ }
7076
7177 // look for ITaskOrchestrator/TaskOrchestrator`2 Orchestrations
72- context . RegisterSyntaxNodeAction (
73- ctx =>
78+ if ( canAnalyzeTaskOrchestrator )
7479 {
75- ctx . CancellationToken . ThrowIfCancellationRequested ( ) ;
76-
77- if ( ctx . ContainingSymbol is not INamedTypeSymbol classSymbol )
80+ context . RegisterSyntaxNodeAction (
81+ ctx =>
7882 {
79- return ;
80- }
83+ ctx . CancellationToken . ThrowIfCancellationRequested ( ) ;
8184
82- bool implementsITaskOrchestrator = classSymbol . AllInterfaces . Any ( i => i . Equals ( knownSymbols . TaskOrchestratorInterface , SymbolEqualityComparer . Default ) ) ;
83- if ( ! implementsITaskOrchestrator )
84- {
85- return ;
86- }
85+ if ( ctx . ContainingSymbol is not INamedTypeSymbol classSymbol )
86+ {
87+ return ;
88+ }
8789
88- IEnumerable < IMethodSymbol > orchestrationMethods = classSymbol . GetMembers ( ) . OfType < IMethodSymbol > ( )
89- . Where ( m => m . Parameters . Any ( p => p . Type . Equals ( knownSymbols . TaskOrchestrationContext , SymbolEqualityComparer . Default ) ) ) ;
90+ bool implementsITaskOrchestrator = classSymbol . AllInterfaces . Any ( i => i . Equals ( knownSymbols . TaskOrchestratorInterface , SymbolEqualityComparer . Default ) ) ;
91+ if ( ! implementsITaskOrchestrator )
92+ {
93+ return ;
94+ }
9095
91- string functionName = classSymbol . Name ;
96+ IEnumerable < IMethodSymbol > orchestrationMethods = classSymbol . GetMembers ( ) . OfType < IMethodSymbol > ( )
97+ . Where ( m => m . Parameters . Any ( p => p . Type . Equals ( knownSymbols . TaskOrchestrationContext , SymbolEqualityComparer . Default ) ) ) ;
9298
93- foreach ( IMethodSymbol ? methodSymbol in orchestrationMethods )
94- {
95- IEnumerable < MethodDeclarationSyntax > methodSyntaxes = methodSymbol . GetSyntaxNodes ( ) ;
96- foreach ( MethodDeclarationSyntax rootMethodSyntax in methodSyntaxes )
99+ string functionName = classSymbol . Name ;
100+
101+ foreach ( IMethodSymbol ? methodSymbol in orchestrationMethods )
97102 {
98- visitor . VisitTaskOrchestrator ( ctx . SemanticModel , rootMethodSyntax , methodSymbol , functionName , ctx . ReportDiagnostic ) ;
103+ IEnumerable < MethodDeclarationSyntax > methodSyntaxes = methodSymbol . GetSyntaxNodes ( ) ;
104+ foreach ( MethodDeclarationSyntax rootMethodSyntax in methodSyntaxes )
105+ {
106+ visitor . VisitTaskOrchestrator ( ctx . SemanticModel , rootMethodSyntax , methodSymbol , functionName , ctx . ReportDiagnostic ) ;
107+ }
99108 }
100- }
101- } ,
102- SyntaxKind . ClassDeclaration ) ;
109+ } ,
110+ SyntaxKind . ClassDeclaration ) ;
111+ }
103112
104113 // look for OrchestratorFunc Orchestrations
105- context . RegisterOperationAction (
106- ctx =>
114+ if ( canAnalyzeFuncOrchestrator )
107115 {
108- if ( ctx . Operation is not IInvocationOperation invocation )
116+ context . RegisterOperationAction (
117+ ctx =>
109118 {
110- return ;
111- }
119+ if ( ctx . Operation is not IInvocationOperation invocation )
120+ {
121+ return ;
122+ }
112123
113- if ( ! SymbolEqualityComparer . Default . Equals ( invocation . Type , knownSymbols . DurableTaskRegistry ) )
114- {
115- return ;
116- }
124+ if ( ! SymbolEqualityComparer . Default . Equals ( invocation . Type , knownSymbols . DurableTaskRegistry ) )
125+ {
126+ return ;
127+ }
117128
118- // there are 8 AddOrchestratorFunc overloads
119- if ( invocation . TargetMethod . Name != "AddOrchestratorFunc" )
120- {
121- return ;
122- }
129+ // there are 8 AddOrchestratorFunc overloads
130+ if ( invocation . TargetMethod . Name != "AddOrchestratorFunc" )
131+ {
132+ return ;
133+ }
123134
124- // all overloads have the parameter 'orchestrator', either as an Action or a Func
125- IArgumentOperation orchestratorArgument = invocation . Arguments . First ( a => a . Parameter ! . Name == "orchestrator" ) ;
126- if ( orchestratorArgument . Value is not IDelegateCreationOperation delegateCreationOperation )
127- {
128- return ;
129- }
135+ // all overloads have the parameter 'orchestrator', either as an Action or a Func
136+ IArgumentOperation orchestratorArgument = invocation . Arguments . First ( a => a . Parameter ! . Name == "orchestrator" ) ;
137+ if ( orchestratorArgument . Value is not IDelegateCreationOperation delegateCreationOperation )
138+ {
139+ return ;
140+ }
130141
131- // obtains the method symbol from the delegate creation operation
132- IMethodSymbol ? methodSymbol = null ;
133- SyntaxNode ? methodSyntax = null ;
134- switch ( delegateCreationOperation . Target )
135- {
136- case IAnonymousFunctionOperation lambdaOperation :
137- // use the containing symbol of the lambda (e.g. the class declaring it) as the method symbol
138- methodSymbol = ctx . ContainingSymbol as IMethodSymbol ;
139- methodSyntax = delegateCreationOperation . Syntax ;
140- break ;
141- case IMethodReferenceOperation methodReferenceOperation :
142- // use the method reference as the method symbol
143- methodSymbol = methodReferenceOperation . Method ;
144- methodSyntax = methodReferenceOperation . Method . DeclaringSyntaxReferences . First ( ) . GetSyntax ( ) ;
145- break ;
146- default :
147- break ;
148- }
149-
150- if ( methodSymbol == null || methodSyntax == null )
151- {
152- return ;
153- }
142+ // obtains the method symbol from the delegate creation operation
143+ IMethodSymbol ? methodSymbol = null ;
144+ SyntaxNode ? methodSyntax = null ;
145+ switch ( delegateCreationOperation . Target )
146+ {
147+ case IAnonymousFunctionOperation _:
148+ // use the containing symbol of the lambda (e.g. the class declaring it) as the method symbol
149+ methodSymbol = ctx . ContainingSymbol as IMethodSymbol ;
150+ methodSyntax = delegateCreationOperation . Syntax ;
151+ break ;
152+ case IMethodReferenceOperation methodReferenceOperation :
153+ // use the method reference as the method symbol
154+ methodSymbol = methodReferenceOperation . Method ;
155+ methodSyntax = methodReferenceOperation . Method . DeclaringSyntaxReferences . First ( ) . GetSyntax ( ) ;
156+ break ;
157+ default :
158+ break ;
159+ }
154160
155- // try to get the name of the orchestration from the method call, otherwise use the containing type name
156- IArgumentOperation nameArgument = invocation . Arguments . First ( a => a . Parameter ! . Name == "name" ) ;
157- Optional < object ? > name = nameArgument . GetConstantValueFromAttribute ( ctx . Operation . SemanticModel ! , ctx . CancellationToken ) ;
158- string orchestrationName = name . Value ? . ToString ( ) ?? methodSymbol . Name ;
161+ if ( methodSymbol == null || methodSyntax == null )
162+ {
163+ return ;
164+ }
159165
160- visitor . VisitFuncOrchestrator ( ctx . Operation . SemanticModel ! , methodSyntax , methodSymbol , orchestrationName , ctx . ReportDiagnostic ) ;
161- } ,
162- OperationKind . Invocation ) ;
166+ // try to get the name of the orchestration from the method call, otherwise use the containing type name
167+ IArgumentOperation nameArgument = invocation . Arguments . First ( a => a . Parameter ! . Name == "name" ) ;
168+ Optional < object ? > name = nameArgument . GetConstantValueFromAttribute ( ctx . Operation . SemanticModel ! , ctx . CancellationToken ) ;
169+ string orchestrationName = name . Value ? . ToString ( ) ?? methodSymbol . Name ;
170+
171+ visitor . VisitFuncOrchestrator ( ctx . Operation . SemanticModel ! , methodSyntax , methodSymbol , orchestrationName , ctx . ReportDiagnostic ) ;
172+ } ,
173+ OperationKind . Invocation ) ;
174+ }
163175 } ) ;
164176 }
165177}
0 commit comments