Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/Analyzers/Orchestration/OrchestrationAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -316,6 +323,13 @@ void FindInvokedMethods(
IEnumerable<MethodDeclarationSyntax> 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 ?
Expand Down
7 changes: 7 additions & 0 deletions src/Analyzers/RoslynExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ public static bool BaseTypeIsConstructedFrom(this INamedTypeSymbol symbol, IType
/// <returns>The collection of syntax nodes of a given method symbol.</returns>
public static IEnumerable<MethodDeclarationSyntax> 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<MethodDeclarationSyntax>();
}
Comment on lines +118 to +123
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fix prevents ArgumentException when analyzing extension methods from external assemblies, but there doesn't appear to be test coverage for this scenario. Consider adding a test case that includes an orchestration calling an extension method defined in a separate assembly to ensure this fix works as expected and to prevent regression.

Copilot uses AI. Check for mistakes.

return methodSymbol.DeclaringSyntaxReferences.Select(r => r.GetSyntax()).OfType<MethodDeclarationSyntax>();
}

Expand Down
Loading