Skip to content

Fix FunctionContext Check and Polymorphic Type Conversions in Activity Analyzer#506

Merged
nytian merged 9 commits intomainfrom
nytian/analyzer-bug
Nov 26, 2025
Merged

Fix FunctionContext Check and Polymorphic Type Conversions in Activity Analyzer#506
nytian merged 9 commits intomainfrom
nytian/analyzer-bug

Conversation

@nytian
Copy link
Copy Markdown
Contributor

@nytian nytian commented Nov 17, 2025

Fix #453

Copilot AI review requested due to automatic review settings November 17, 2025 04:20
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes issue #453 by improving the Activity analyzer to correctly handle FunctionContext parameters and support polymorphic type conversions.

  • Adds special handling to skip validation for activities that use FunctionContext with [ActivityTrigger], preventing false positive warnings
  • Replaces exact type matching with type compatibility checking using Roslyn's ClassifyConversion API and custom collection compatibility logic
  • Adds comprehensive test coverage for FunctionContext handling, polymorphism, collection type compatibility, and incompatible type detection

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/Analyzers/Activities/MatchingInputOutputTypeActivityAnalyzer.cs Adds FunctionContext detection to skip DI parameter validation; implements type compatibility checking with support for polymorphism, inheritance, and collection interface implementations (List to IReadOnlyList)
test/Analyzers.Tests/Activities/MatchingInputOutputTypeActivityAnalyzerTests.cs Adds 6 new test cases covering FunctionContext scenarios, polymorphic input/output types, collection type compatibility, and incompatible type detection

Comment on lines +460 to +466
foreach (INamedTypeSymbol @interface in sourceType.AllInterfaces)
{
if (SymbolEqualityComparer.Default.Equals(@interface.OriginalDefinition, targetInterface.OriginalDefinition))
{
return true;
}
}
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

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

This foreach loop implicitly filters its target sequence - consider filtering the sequence explicitly using '.Where(...)'.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@bachuv bachuv left a comment

Choose a reason for hiding this comment

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

Thanks for opening this PR!

Can you add more details in the PR description?

Copy link
Copy Markdown
Collaborator

@andystaples andystaples left a comment

Choose a reason for hiding this comment

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

One question

}

// One is null, the other isn't = not compatible
if (sourceType == null || targetType == null)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just checking - does this logic support passing null as input to a nullable function parameter? That was also an issue with this analyzer previously

Copilot AI review requested due to automatic review settings November 20, 2025 23:14
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

Comment on lines +462 to +468
// Array implements: IEnumerable<T>, ICollection<T>, IList<T>, IReadOnlyCollection<T>, IReadOnlyList<T>
string targetName = targetInterface.OriginalDefinition.ToDisplayString();
return targetName == "System.Collections.Generic.IEnumerable<T>" ||
targetName == "System.Collections.Generic.ICollection<T>" ||
targetName == "System.Collections.Generic.IList<T>" ||
targetName == "System.Collections.Generic.IReadOnlyCollection<T>" ||
targetName == "System.Collections.Generic.IReadOnlyList<T>";
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

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

[nitpick] The array interface compatibility check uses string comparison of type names, which may not be robust across different compilation contexts or type forwarding scenarios. Consider using GetTypeByMetadataName to get reference symbols for the standard collection interfaces and comparing using SymbolEqualityComparer.Default.Equals instead of string comparison. This would be more reliable and less prone to edge cases with type representation differences.

Copilot uses AI. Check for mistakes.
Comment on lines +365 to +374
if (sourceType == null && targetType != null)
{
// Check if target is a nullable reference type (NullableAnnotation.Annotated)
// or a nullable value type (Nullable<T>)
if (targetType.NullableAnnotation == NullableAnnotation.Annotated ||
targetType.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
{
return true;
}
}
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

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

The null handling logic may incorrectly reject null values passed to reference type parameters when nullable reference types are disabled. When sourceType is null and targetType is a reference type (like string), the code checks for NullableAnnotation.Annotated (line 369), which will be false when nullable reference types are disabled. However, in such projects, all reference types can accept null. Consider adding || targetType.IsReferenceType to line 369 to allow null for all reference types, or checking if nullable context is enabled before applying strict nullable validation.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

turns out this is not right

Copilot AI review requested due to automatic review settings November 21, 2025 19:58
@nytian nytian force-pushed the nytian/analyzer-bug branch from c47ebea to ec21a2a Compare November 21, 2025 19:58
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.

Comments suppressed due to low confidence (1)

src/Analyzers/Activities/MatchingInputOutputTypeActivityAnalyzer.cs:374

  • These 'if' statements can be combined.
            if (sourceType == null && targetType != null)
            {
                // Check if target is a nullable reference type (NullableAnnotation.Annotated)
                // or a nullable value type (Nullable<T>)
                if (targetType.NullableAnnotation == NullableAnnotation.Annotated ||
                    targetType.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
                {
                    return true;
                }
            }

Copilot AI review requested due to automatic review settings November 21, 2025 23:02
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

@nytian nytian requested review from andystaples and bachuv November 24, 2025 23:39
Copilot AI review requested due to automatic review settings November 26, 2025 04:07
@nytian
Copy link
Copy Markdown
Contributor Author

nytian commented Nov 26, 2025

E2E test
-- with latest v1.11.1
image
--with fix
image

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comment on lines +167 to +171
// If the parameter is FunctionContext, skip validation for this activity (it's a DI parameter, not real input)
if (functionContextSymbol != null && SymbolEqualityComparer.Default.Equals(inputParam.Type, functionContextSymbol))
{
return;
}
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

The FunctionContext check (lines 167-171) lacks test coverage. Consider adding a test case that verifies an activity method with a FunctionContext parameter marked with [ActivityTrigger] doesn't generate diagnostics, confirming that DI parameters are properly excluded from input type validation.

Copilot uses AI. Check for mistakes.
Comment on lines +436 to +444
// Check if type arguments are compatible (could be different but compatible types)
for (int i = 0; i < sourceNamed.TypeArguments.Length; i++)
{
if (!SymbolEqualityComparer.Default.Equals(sourceNamed.TypeArguments[i], targetNamedType.TypeArguments[i]))
{
// Type arguments must match exactly for collections (we don't support covariance/contravariance here)
return false;
}
}
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

The comment on line 436 "Check if type arguments are compatible (could be different but compatible types)" is misleading, as the implementation (lines 437-444) requires exact type argument equality, not just compatibility. Consider updating the comment to: "Check if type arguments match exactly (we don't support covariance/contravariance for collections)" to better reflect the actual behavior.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Analyzer Rule DURABLE2001 False Positives

4 participants