Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
{
"Issues": [
{
"Id": "S3247",
"Message": "Replace this type-check-and-cast sequence with an \u0027as\u0027 and a null check.",
"Uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/Projects/akka.net/src/core/Akka/Actor/ActorRefProvider.cs#L516",
"Location": "Line 516 Position 17-54"
},
{
"Id": "S3247",
"Message": "Replace this type-check-and-cast sequence with an \u0027as\u0027 and a null check.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ bool IsDuplicatedCastOnSameSymbol(ExpressionSyntax expression, SyntaxNode type)
&& !CSharpFacade.Instance.Syntax.IsInExpressionTree(context.SemanticModel, expression); // see https://github.com/SonarSource/sonar-dotnet/issues/8735#issuecomment-1943419398

bool IsCastOnSameSymbol(ExpressionSyntax expression) =>
Equals(context.SemanticModel.GetSymbolInfo(expression).Symbol, typeExpressionSymbol);
IsEquivalentVariable(expression, typedVariable)
&& Equals(context.SemanticModel.GetSymbolInfo(expression).Symbol, typeExpressionSymbol);
}

private static void ProcessPatternExpression(SonarSyntaxNodeReportingContext analysisContext, SyntaxNode isPattern, SyntaxNode mainVariableExpression, SyntaxNode parentStatement)
Expand Down Expand Up @@ -228,4 +229,24 @@ private static void ReportPatternAtCastLocation(SonarSyntaxNodeReportingContext
context.ReportIssue(Rule, castLocation, [patternLocation.ToSecondary()], message);
}
}

private static bool IsEquivalentVariable(ExpressionSyntax expression, SyntaxNode typedVariable)
{
var left = RemoveThisExpression(typedVariable).WithoutTrivia();
var right = RemoveThisExpression(expression).WithoutTrivia();

return left.IsEquivalentTo(right)
|| (StandaloneIdentifier(left) is { } leftIdentifier && leftIdentifier == StandaloneIdentifier(right));

static string StandaloneIdentifier(SyntaxNode node) =>
node switch
{
IdentifierNameSyntax name => name.Identifier.ValueText,
_ when node.IsKind(SyntaxKindEx.SingleVariableDesignation) => ((SingleVariableDesignationSyntaxWrapper)node).Identifier.ValueText,
_ => null
};

static SyntaxNode RemoveThisExpression(SyntaxNode node) =>
node is MemberAccessExpressionSyntax { Expression: ThisExpressionSyntax } memberAccess ? memberAccess.Name : node;
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
using System;
using System.Collections.Generic;

class Fruit { }
class Fruit
{
public object Property => null;
}

struct SomeStruct { }

class Program
{
private object someField;

private object LocalProperty => null;

public void Foo(Object x)
{
if (x is Fruit) // Noncompliant
Expand All @@ -25,6 +31,32 @@ public void Foo(Object x)
}
}

public void IgnoreMemberAccess(Fruit arg)
{
var differentInstance = new Fruit();
var f = new Fruit();

if (arg.Property is Fruit) // Compliant, the cast is on a different instance
{
_ = (Fruit)differentInstance.Property;
}

if (f.Property is Fruit) // Compliant, the cast is on a different instance
{
_ = (Fruit)differentInstance.Property;
}

if (f.Property is Fruit) // Noncompliant
{
_ = (Fruit)f.Property; // Secondary
}

if (LocalProperty is Fruit) // Noncompliant
{
_ = (Fruit)LocalProperty; // Secondary
}
}

public void Bar(object x)
{
if (!(x is Fruit))
Expand Down