Skip to content
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

S3900: Change parameter dereference check to top-down #7004

Merged

Conversation

zsolt-kolbay-sonarsource
Copy link
Contributor

@zsolt-kolbay-sonarsource zsolt-kolbay-sonarsource commented Mar 29, 2023

Minor update for S3900.
Switching from bottom-up search to top-down approach when dealing with operations.
This changed resolved a couple of FPs.

Comment on lines 74 to 85
if (NullDereferenceCandidate(context.Operation.Instance) is { } candidate
&& candidate.Kind == OperationKindEx.ParameterReference
&& candidate.ToParameterReference() is var dereferencedParameter
&& dereferencedParameter.Parameter is var parameter
&& !parameter.Type.IsValueType
&& IsParameterDereferenced(context.Operation)
&& NullableStateIsNotKnownForParameter(parameter)
&& !parameter.HasAttribute(KnownType.Microsoft_AspNetCore_Mvc_FromServicesAttribute))
{
var message = SemanticModel.GetDeclaredSymbol(Node).IsConstructor()
? "Refactor this constructor to avoid using members of parameter '{0}' because it could be null."
: "Refactor this method to add validation of parameter '{0}' before using it.";
ReportIssue(operation, string.Format(message, operation.Syntax), context);
ReportIssue(dereferencedParameter.WrappedOperation, string.Format(message, dereferencedParameter.WrappedOperation.Syntax), context);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I would go with one of the following two:

        if (NullDereferenceCandidate(context.Operation.Instance) is { } candidate
            && candidate.Kind == OperationKindEx.ParameterReference
            && candidate.ToParameterReference() is { Parameter: var parameter, WrappedOperation: var wrappedOperation }
            && !parameter.Type.IsValueType
            && NullableStateIsNotKnownForParameter(parameter)
            && !parameter.HasAttribute(KnownType.Microsoft_AspNetCore_Mvc_FromServicesAttribute))
        {
            var message = SemanticModel.GetDeclaredSymbol(Node).IsConstructor()
                ? "Refactor this constructor to avoid using members of parameter '{0}' because it could be null."
                : "Refactor this method to add validation of parameter '{0}' before using it.";
            ReportIssue(wrappedOperation, string.Format(message, wrappedOperation.Syntax), context);
        }
        if (NullDereferenceCandidate(context.Operation.Instance) is { } candidate
            && IsParameterReference(candidate, out var parameter, out var wrappedOperation)
            && !parameter.Type.IsValueType
            && NullableStateIsNotKnownForParameter(parameter)
            && !parameter.HasAttribute(KnownType.Microsoft_AspNetCore_Mvc_FromServicesAttribute))
        {
            var message = SemanticModel.GetDeclaredSymbol(Node).IsConstructor()
                ? "Refactor this constructor to avoid using members of parameter '{0}' because it could be null."
                : "Refactor this method to add validation of parameter '{0}' before using it.";
            ReportIssue(wrappedOperation, string.Format(message, wrappedOperation.Syntax), context);
        }

Copy link
Contributor

@Tim-Pohlmann Tim-Pohlmann left a comment

Choose a reason for hiding this comment

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

LGTM. One more refactor suggestion. And you have to look into the ITs.

Comment on lines 106 to 114
return candidate?.Kind == OperationKindEx.Conversion
? ConversionOperand(candidate)
: candidate;
}

private static IOperation ConversionOperand(IOperation operation) =>
operation.Kind == OperationKindEx.Conversion
? ConversionOperand(operation.ToConversion().Operand)
: operation;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return candidate?.Kind == OperationKindEx.Conversion
? ConversionOperand(candidate)
: candidate;
}
private static IOperation ConversionOperand(IOperation operation) =>
operation.Kind == OperationKindEx.Conversion
? ConversionOperand(operation.ToConversion().Operand)
: operation;
return UnwrapConversions(candidate);
}
private static IOperation UnwrapConversions(IOperation operation) =>
operation?.Kind == OperationKindEx.Conversion
? UnwrapConversions(operation.ToConversion().Operand)
: operation;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd rather keep the name ConversionOperand, as it shows what the return value will be.

Copy link
Contributor

Choose a reason for hiding this comment

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

The issue I see with that is that it will only return a conversion operand if the operation is a conversion.

@zsolt-kolbay-sonarsource zsolt-kolbay-sonarsource changed the title S3900: Refactor parameter dereference method S3900: Change parameter dereference check to top-down Mar 30, 2023
Copy link
Contributor

@pavel-mikula-sonarsource pavel-mikula-sonarsource left a comment

Choose a reason for hiding this comment

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

Taking shortcuts, will review implementaion in a minute

Copy link
Contributor

@pavel-mikula-sonarsource pavel-mikula-sonarsource left a comment

Choose a reason for hiding this comment

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

Code

Comment on lines -2877 to -2843
"id": "S3900",
"message": "Refactor this method to add validation of parameter 'constraint' before using it.",
"location": {
"uri": "sources\Nancy\src\Nancy\Routing\Constraints\ParameterizedRouteSegmentConstraintBase.cs",
"region": {
"startLine": 21,
Copy link
Contributor

Choose a reason for hiding this comment

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

This actually illustrates why top-to-bottom is better, due to the execution order

Copy link
Contributor

@pavel-mikula-sonarsource pavel-mikula-sonarsource left a comment

Choose a reason for hiding this comment

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

LGTM

@@ -714,3 +714,26 @@ private class CustomClass
public event EventHandler CustomEvent;
}
}

public class DereferencedMultipleTimesOnTheSameExecutionPath
Copy link
Contributor

Choose a reason for hiding this comment

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

Very nice UTs!

OperationKindEx.ArrayElementReference => operation.ToArrayElementReference().ArrayReference,
_ => null,
};

Copy link
Contributor

Choose a reason for hiding this comment

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

This empty line doesn't help. If we would need semicolon, new line, newline as a command separator to make the language readable, we would have to look for another language.

Suggested change

@zsolt-kolbay-sonarsource zsolt-kolbay-sonarsource force-pushed the Zsolt/S3900-refactor-parameter-dereference branch from f587d85 to 1426253 Compare March 31, 2023 12:41
@sonarcloud
Copy link

sonarcloud bot commented Mar 31, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
No Duplication information No Duplication information

@sonarcloud
Copy link

sonarcloud bot commented Mar 31, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

100.0% 100.0% Coverage
0.0% 0.0% Duplication

@zsolt-kolbay-sonarsource zsolt-kolbay-sonarsource merged commit 60dc3c5 into feature/SE Mar 31, 2023
@zsolt-kolbay-sonarsource zsolt-kolbay-sonarsource deleted the Zsolt/S3900-refactor-parameter-dereference branch March 31, 2023 13:01
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