From 9bd25f3b242d3c4c2de0095ae3b9e78c17ff4466 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Wed, 10 Dec 2025 19:29:11 -0800 Subject: [PATCH 1/3] initial commit --- .../Orchestration/OrchestrationAnalyzer.cs | 9 ++++++++- src/Analyzers/RoslynExtensions.cs | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Analyzers/Orchestration/OrchestrationAnalyzer.cs b/src/Analyzers/Orchestration/OrchestrationAnalyzer.cs index a299d5777..bbf06c376 100644 --- a/src/Analyzers/Orchestration/OrchestrationAnalyzer.cs +++ b/src/Analyzers/Orchestration/OrchestrationAnalyzer.cs @@ -141,7 +141,14 @@ public override void Initialize(AnalysisContext context) case IMethodReferenceOperation methodReferenceOperation: // use the method reference as the method symbol methodSymbol = methodReferenceOperation.Method; - methodSyntax = methodReferenceOperation.Method.DeclaringSyntaxReferences.First().GetSyntax(); + + // Only get syntax for methods in the current project (skip external assemblies) + // If IsEmpty (external method), methodSyntax stays null and we skip analysis below + if (!methodReferenceOperation.Method.DeclaringSyntaxReferences.IsEmpty) + { + methodSyntax = methodReferenceOperation.Method.DeclaringSyntaxReferences.First().GetSyntax(); + } + break; default: break; diff --git a/src/Analyzers/RoslynExtensions.cs b/src/Analyzers/RoslynExtensions.cs index 10339f7a4..f615bd34e 100644 --- a/src/Analyzers/RoslynExtensions.cs +++ b/src/Analyzers/RoslynExtensions.cs @@ -115,6 +115,13 @@ public static bool BaseTypeIsConstructedFrom(this INamedTypeSymbol symbol, IType /// The collection of syntax nodes of a given method symbol. public static IEnumerable GetSyntaxNodes(this IMethodSymbol methodSymbol) { + // If the method has no syntax references (e.g., extension methods from external assemblies), + // return empty to skip analysis rather than throwing ArgumentException. + if (methodSymbol.DeclaringSyntaxReferences.IsEmpty) + { + return Enumerable.Empty(); + } + return methodSymbol.DeclaringSyntaxReferences.Select(r => r.GetSyntax()).OfType(); } @@ -155,6 +162,13 @@ public static bool IsEqualTo(this IMethodSymbol methodSymbol, INamedTypeSymbol? /// The Diagnostic based on the symbol location. public static Diagnostic BuildDiagnostic(DiagnosticDescriptor descriptor, ISymbol symbol, params string[] messageArgs) { + // If the symbol has no syntax references (e.g., symbols from external assemblies), + // fall back to using the symbol's location directly. + if (symbol.DeclaringSyntaxReferences.IsEmpty) + { + return Diagnostic.Create(descriptor, symbol.Locations.FirstOrDefault() ?? Location.None, messageArgs); + } + return BuildDiagnostic(descriptor, symbol.DeclaringSyntaxReferences.First().GetSyntax(), messageArgs); } From a92c5e44d156d4f68cce6340d066aad24f136e7a Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Wed, 10 Dec 2025 19:36:03 -0800 Subject: [PATCH 2/3] udpate --- src/Analyzers/RoslynExtensions.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Analyzers/RoslynExtensions.cs b/src/Analyzers/RoslynExtensions.cs index f615bd34e..597013334 100644 --- a/src/Analyzers/RoslynExtensions.cs +++ b/src/Analyzers/RoslynExtensions.cs @@ -162,13 +162,6 @@ public static bool IsEqualTo(this IMethodSymbol methodSymbol, INamedTypeSymbol? /// The Diagnostic based on the symbol location. public static Diagnostic BuildDiagnostic(DiagnosticDescriptor descriptor, ISymbol symbol, params string[] messageArgs) { - // If the symbol has no syntax references (e.g., symbols from external assemblies), - // fall back to using the symbol's location directly. - if (symbol.DeclaringSyntaxReferences.IsEmpty) - { - return Diagnostic.Create(descriptor, symbol.Locations.FirstOrDefault() ?? Location.None, messageArgs); - } - return BuildDiagnostic(descriptor, symbol.DeclaringSyntaxReferences.First().GetSyntax(), messageArgs); } From e05e664d948f7dfa49ccd680fe475e7aef6acad0 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Thu, 11 Dec 2025 20:57:39 -0800 Subject: [PATCH 3/3] update --- src/Analyzers/Orchestration/OrchestrationAnalyzer.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Analyzers/Orchestration/OrchestrationAnalyzer.cs b/src/Analyzers/Orchestration/OrchestrationAnalyzer.cs index bbf06c376..342b1e6c0 100644 --- a/src/Analyzers/Orchestration/OrchestrationAnalyzer.cs +++ b/src/Analyzers/Orchestration/OrchestrationAnalyzer.cs @@ -323,6 +323,13 @@ void FindInvokedMethods( IEnumerable calleeSyntaxes = calleeMethodSymbol.GetSyntaxNodes(); foreach (MethodDeclarationSyntax calleeSyntax in calleeSyntaxes) { + // Check if the syntax tree is part of the current compilation before trying to get its semantic model. + // Extension methods from external assemblies won't be in the compilation, so skip them. + if (!semanticModel.Compilation.ContainsSyntaxTree(calleeSyntax.SyntaxTree)) + { + continue; + } + // Since the syntax tree of the callee method might be different from the caller method, we need to get the correct semantic model, // avoiding the exception 'Syntax node is not within syntax tree'. SemanticModel sm = semanticModel.SyntaxTree == calleeSyntax.SyntaxTree ?