Skip to content

Call type refactoring #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Call type refactoring #9

wants to merge 2 commits into from

Conversation

ATrefzer
Copy link
Owner

Preparation for call tracking heuristics. Collect attributes for method call like base, instance etc.

@ATrefzer
Copy link
Owner Author

@CodiumAI-Agent /review

@CodiumAI-Agent
Copy link

CodiumAI-Agent commented Jun 29, 2025

PR Reviewer Guide 🔍

(Review updated until commit 77c4c96)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Null location handling

The new AddRelationshipWithFallbackToContainingType and other overloads require a non-null List<SourceLocation>. Calls passing null or empty arrays (e.g., in identifier or field handling) could cause NRE or incorrect relationships. Verify all call sites provide valid lists and update defaults accordingly.

if (symbol is IPropertySymbol propertySymbol)
{
    var location = memberAccessSyntax.GetSyntaxLocation();
    AddPropertyCallRelationship(sourceElement, propertySymbol, [location], RelationshipAttribute.None);
}
else if (symbol is IFieldSymbol fieldSymbol)
{
    AddRelationshipWithFallbackToContainingType(sourceElement, fieldSymbol, RelationshipType.Uses, [], RelationshipAttribute.None);
}
Attribute merging logic

In the new AddRelationship overload, attributes are merged via bitwise OR. Ensure that repeated calls with different attributes correctly accumulate and that no unintended flags persist across unrelated relationships.

    // For example identifier and member access of field.
    var newLocations = sourceLocations.Except(existingRelationship.SourceLocations);
    existingRelationship.SourceLocations.AddRange(newLocations);


    // We may get different attributes from different calls.
    existingRelationship.Attributes |= attributes;
}
Call attribute determination

The DetermineCallAttributes and AnalyzeMemberAccessCallType methods may not cover all invocation patterns (e.g., reduced forms, nested expressions). Validate that extension method reduced forms and uncommon syntax nodes correctly map to the intended RelationshipAttribute.

private RelationshipAttribute DetermineCallAttributes(InvocationExpressionSyntax invocation,
 IMethodSymbol method, SemanticModel semanticModel)
{
    if (method.IsExtensionMethod)
    {
        return RelationshipAttribute.IsExtensionMethodCall;
    }

    switch (invocation.Expression)
    {
        case MemberAccessExpressionSyntax memberAccess:
            return AnalyzeMemberAccessCallType(memberAccess, method, semanticModel);

        case IdentifierNameSyntax identifier:
            // Direct method call - could be this.Method() or static
            return method.IsStatic ? RelationshipAttribute.IsStaticCall : RelationshipAttribute.None;

        case MemberBindingExpressionSyntax:
            // Conditional access: obj?.Method()
            return RelationshipAttribute.IsInstanceCall;

        default:
            // Fallback for complex expressions
            return RelationshipAttribute.None;
    }
}

private RelationshipAttribute AnalyzeMemberAccessCallType(MemberAccessExpressionSyntax memberAccess,
    IMethodSymbol method, SemanticModel semanticModel)
{
    switch (memberAccess.Expression)
    {
        case BaseExpressionSyntax:
            // base.Method()
            return RelationshipAttribute.IsBaseCall;

        case ThisExpressionSyntax:
            // this.Method()
            return RelationshipAttribute.IsThisCall;

        case IdentifierNameSyntax identifier:
            var symbolInfo = semanticModel.GetSymbolInfo(identifier);
            if (symbolInfo.Symbol is INamedTypeSymbol)
            {
                // Type.StaticMethod()
                return RelationshipAttribute.IsStaticCall;
            }
            else if (symbolInfo.Symbol is IFieldSymbol || symbolInfo.Symbol is IPropertySymbol)
            {
                // field.Method() or property.Method()
                return RelationshipAttribute.IsInstanceCall;
            }
            else
            {
                // Local variable or parameter
                return RelationshipAttribute.IsInstanceCall;
            }

        case MemberAccessExpressionSyntax:
            // Chained calls: obj.Property.Method()
            return RelationshipAttribute.IsInstanceCall;

        case InvocationExpressionSyntax:
            // Method call result: GetObject().Method()
            return RelationshipAttribute.IsInstanceCall;

        case ObjectCreationExpressionSyntax:
            // new Object().Method()
            return RelationshipAttribute.IsInstanceCall;

        default:
            // Complex expression - default to instance call
            return RelationshipAttribute.IsInstanceCall;
    }
}

@ATrefzer
Copy link
Owner Author

@CodiumAI-Agent /review

@CodiumAI-Agent
Copy link

Persistent review updated to latest commit 77c4c96

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.

3 participants