Skip to content

Commit e1a8872

Browse files
sagi1623mary-georgiou-sonarsource
authored andcommitted
Fix FNs
1 parent ba9bfe4 commit e1a8872

File tree

4 files changed

+143
-28
lines changed

4 files changed

+143
-28
lines changed

analyzers/src/SonarAnalyzer.CSharp/Rules/InfiniteRecursion.RoslynCfg.cs

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,33 @@ public partial class InfiniteRecursion
2727
{
2828
private sealed class RoslynChecker : IChecker
2929
{
30-
public void CheckForNoExitProperty(SonarSyntaxNodeReportingContext c, PropertyDeclarationSyntax property, IPropertySymbol propertySymbol)
30+
public void CheckForNoExitProperty(SonarSyntaxNodeReportingContext c, PropertyDeclarationSyntax property, IPropertySymbol propertySymbol) =>
31+
CheckForNoExit(c,
32+
propertySymbol,
33+
property.ExpressionBody,
34+
property.AccessorList,
35+
property.Identifier.GetLocation(),
36+
"property's recursion",
37+
"property accessor's recursion");
38+
39+
public void CheckForNoExitIndexer(SonarSyntaxNodeReportingContext c, IndexerDeclarationSyntax indexer, IPropertySymbol propertySymbol) =>
40+
CheckForNoExit(c,
41+
propertySymbol,
42+
indexer.ExpressionBody,
43+
indexer.AccessorList,
44+
indexer.ThisKeyword.GetLocation(),
45+
"indexer's recursion",
46+
"indexer accessor's recursion");
47+
48+
public void CheckForNoExitEvent(SonarSyntaxNodeReportingContext c, EventDeclarationSyntax eventDeclaration, IEventSymbol eventSymbol)
3149
{
32-
if (property.ExpressionBody?.Expression != null)
33-
{
34-
var cfg = ControlFlowGraph.Create(property.ExpressionBody, c.SemanticModel, c.Cancel);
35-
var walker = new RecursionSearcher(new RecursionContext<ControlFlowGraph>(c, cfg, propertySymbol, property.Identifier.GetLocation(), "property's recursion"));
36-
walker.CheckPaths();
37-
}
38-
else if (property.AccessorList != null)
50+
if (eventDeclaration.AccessorList != null)
3951
{
40-
foreach (var accessor in property.AccessorList.Accessors.Where(a => a.HasBodyOrExpressionBody()))
52+
foreach (var accessor in eventDeclaration.AccessorList.Accessors.Where(a => a.HasBodyOrExpressionBody()))
4153
{
4254
var cfg = ControlFlowGraph.Create(accessor, c.SemanticModel, c.Cancel);
43-
var context = new RecursionContext<ControlFlowGraph>(c, cfg, propertySymbol, accessor.Keyword.GetLocation(), "property accessor's recursion");
44-
var walker = new RecursionSearcher(context, !accessor.Keyword.IsAnyKind(SyntaxKind.SetKeyword, SyntaxKindEx.InitKeyword));
55+
var context = new RecursionContext<ControlFlowGraph>(c, cfg, eventSymbol, accessor.Keyword.GetLocation(), "event accessor's recursion");
56+
var walker = new RecursionSearcher(context);
4557
walker.CheckPaths();
4658
}
4759
}
@@ -57,6 +69,32 @@ public void CheckForNoExitMethod(SonarSyntaxNodeReportingContext c, SyntaxNode b
5769
}
5870
}
5971

72+
private static void CheckForNoExit(SonarSyntaxNodeReportingContext c,
73+
IPropertySymbol propertySymbol,
74+
ArrowExpressionClauseSyntax expressionBody,
75+
AccessorListSyntax accessorList,
76+
Location location,
77+
string arrowExpressionMessageArg,
78+
string accessorMessageArg)
79+
{
80+
if (expressionBody?.Expression != null)
81+
{
82+
var cfg = ControlFlowGraph.Create(expressionBody, c.SemanticModel, c.Cancel);
83+
var walker = new RecursionSearcher(new RecursionContext<ControlFlowGraph>(c, cfg, propertySymbol, location, arrowExpressionMessageArg));
84+
walker.CheckPaths();
85+
}
86+
else if (accessorList != null)
87+
{
88+
foreach (var accessor in accessorList.Accessors.Where(a => a.HasBodyOrExpressionBody()))
89+
{
90+
var cfg = ControlFlowGraph.Create(accessor, c.SemanticModel, c.Cancel);
91+
var context = new RecursionContext<ControlFlowGraph>(c, cfg, propertySymbol, accessor.Keyword.GetLocation(), accessorMessageArg);
92+
var walker = new RecursionSearcher(context, !accessor.Keyword.IsAnyKind(SyntaxKind.SetKeyword, SyntaxKindEx.InitKeyword));
93+
walker.CheckPaths();
94+
}
95+
}
96+
}
97+
6098
private sealed class RecursionSearcher : CfgAllPathValidator
6199
{
62100
private readonly RecursionContext<ControlFlowGraph> context;
@@ -97,18 +135,18 @@ when IPropertyReferenceOperationWrapper.FromOperation(operation) is var property
97135
OperationKindEx.Invocation
98136
when IInvocationOperationWrapper.FromOperation(operation) is var invocation && (!invocation.IsVirtual || InstanceReferencesThis(invocation.Instance)) =>
99137
invocation.TargetMethod,
100-
OperationKindEx.Binary
101-
when IBinaryOperationWrapper.FromOperation(operation) is var binaryOperation =>
102-
binaryOperation.OperatorMethod,
103-
OperationKindEx.Decrement
104-
when IIncrementOrDecrementOperationWrapper.FromOperation(operation) is var decrementOperation =>
105-
decrementOperation.OperatorMethod,
106-
OperationKindEx.Increment
107-
when IIncrementOrDecrementOperationWrapper.FromOperation(operation) is var incrementOperation =>
108-
incrementOperation.OperatorMethod,
109-
OperationKindEx.Unary
110-
when IUnaryOperationWrapper.FromOperation(operation) is var unaryOperation =>
111-
unaryOperation.OperatorMethod,
138+
OperationKindEx.Binary =>
139+
IBinaryOperationWrapper.FromOperation(operation).OperatorMethod,
140+
OperationKindEx.Decrement =>
141+
IIncrementOrDecrementOperationWrapper.FromOperation(operation).OperatorMethod,
142+
OperationKindEx.Increment =>
143+
IIncrementOrDecrementOperationWrapper.FromOperation(operation).OperatorMethod,
144+
OperationKindEx.Unary =>
145+
IUnaryOperationWrapper.FromOperation(operation).OperatorMethod,
146+
OperationKindEx.Conversion=>
147+
IConversionOperationWrapper.FromOperation(operation).OperatorMethod,
148+
OperationKindEx.EventReference =>
149+
IEventReferenceOperationWrapper.FromOperation(operation).Member,
112150
_ => null
113151
};
114152

analyzers/src/SonarAnalyzer.CSharp/Rules/InfiniteRecursion.SonarCfg.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,16 @@ public void CheckForNoExitProperty(SonarSyntaxNodeReportingContext c, PropertyDe
6060
}
6161
}
6262

63+
public void CheckForNoExitIndexer(SonarSyntaxNodeReportingContext c, IndexerDeclarationSyntax indexer, IPropertySymbol propertySymbol)
64+
{
65+
// SonarCFG is out of support
66+
}
67+
68+
public void CheckForNoExitEvent(SonarSyntaxNodeReportingContext c, EventDeclarationSyntax eventDeclaration, IEventSymbol eventSymbol)
69+
{
70+
// SonarCFG is out of support
71+
}
72+
6373
public void CheckForNoExitMethod(SonarSyntaxNodeReportingContext c, SyntaxNode body, SyntaxToken identifier, IMethodSymbol symbol)
6474
{
6575
if (CSharpControlFlowGraph.TryGet(body, c.SemanticModel, out var cfg))

analyzers/src/SonarAnalyzer.CSharp/Rules/InfiniteRecursion.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ protected override void Initialize(SonarAnalysisContext context)
6363
},
6464
SyntaxKind.OperatorDeclaration);
6565

66+
context.RegisterNodeAction(
67+
c =>
68+
{
69+
var conversionOperator = (ConversionOperatorDeclarationSyntax)c.Node;
70+
CheckForNoExitMethod(c, conversionOperator.OperatorKeyword);
71+
},
72+
SyntaxKind.ConversionOperatorDeclaration);
73+
6674
context.RegisterNodeAction(
6775
c =>
6876
{
@@ -73,6 +81,28 @@ protected override void Initialize(SonarAnalysisContext context)
7381
}
7482
},
7583
SyntaxKind.PropertyDeclaration);
84+
85+
context.RegisterNodeAction(
86+
c =>
87+
{
88+
var indexer = (IndexerDeclarationSyntax)c.Node;
89+
if (c.SemanticModel.GetDeclaredSymbol(indexer) is { } indexerSymbol)
90+
{
91+
checker.CheckForNoExitIndexer(c, indexer, indexerSymbol);
92+
}
93+
},
94+
SyntaxKind.IndexerDeclaration);
95+
96+
context.RegisterNodeAction(
97+
c =>
98+
{
99+
var eventDeclaration = (EventDeclarationSyntax)c.Node;
100+
if (c.SemanticModel.GetDeclaredSymbol(eventDeclaration) is { } eventSymbol)
101+
{
102+
checker.CheckForNoExitEvent(c, eventDeclaration, eventSymbol);
103+
}
104+
},
105+
SyntaxKind.EventDeclaration);
76106
}
77107

78108
private void CheckForNoExitMethod(SonarSyntaxNodeReportingContext c, SyntaxToken identifier)
@@ -124,6 +154,8 @@ public void ReportIssue() =>
124154
private interface IChecker
125155
{
126156
void CheckForNoExitProperty(SonarSyntaxNodeReportingContext c, PropertyDeclarationSyntax property, IPropertySymbol propertySymbol);
157+
void CheckForNoExitIndexer(SonarSyntaxNodeReportingContext c, IndexerDeclarationSyntax indexer, IPropertySymbol propertySymbol);
158+
void CheckForNoExitEvent(SonarSyntaxNodeReportingContext c, EventDeclarationSyntax eventDeclaration, IEventSymbol eventSymbol);
127159
void CheckForNoExitMethod(SonarSyntaxNodeReportingContext c, SyntaxNode body, SyntaxToken identifier, IMethodSymbol symbol);
128160
}
129161
}

analyzers/tests/SonarAnalyzer.Test/TestCases/InfiniteRecursion.RoslynCfg.cs

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -604,17 +604,38 @@ public IEnumerable<T> Repeat<T>(T element) // Noncompliant FP, it's not a recur
604604
// https://github.com/SonarSource/sonar-dotnet/issues/6642
605605
public class Repro_6642
606606
{
607+
private List<byte> list;
608+
607609
public int this[int i]
608610
{
609-
get { return this[i]; } // FN
610-
set { this[i] = value; } // FN
611+
get { return this[i]; } // Noncompliant
612+
set { this[i] = value; } // Noncompliant
613+
}
614+
615+
public char this[char i] => this[i]; // Noncompliant
616+
617+
public byte this[byte i]
618+
{
619+
get { return list[i]; } // Compliant
620+
set { list[i] = value; } // Compliant
611621
}
622+
623+
public short this[short i] => list[1623]; // Compliant
624+
625+
public string this[string i]
626+
{
627+
get { return this; } // Compliant
628+
}
629+
630+
public static implicit operator string(Repro_6642 d) => "";
612631
}
613632

614633
// https://github.com/SonarSource/sonar-dotnet/issues/6643
615634
public class Repro_6643
616635
{
617-
public static implicit operator byte(Repro_6643 d) => d; // FN
636+
public static implicit operator byte(Repro_6643 d) => d; // Noncompliant
637+
638+
public static explicit operator string(Repro_6643 d) => (string)d; // Noncompliant
618639
}
619640

620641
// https://github.com/SonarSource/sonar-dotnet/issues/6644
@@ -623,15 +644,29 @@ public class Repro_6643
623644
public class Repro_6644
624645
{
625646
public event SomeDelegate SomeEvent
647+
{
648+
add { SomeEvent += value; } // Noncompliant
649+
650+
remove { SomeEvent -= value; } // Noncompliant
651+
}
652+
653+
public event SomeDelegate SomeEvent2
654+
{
655+
add { SomeEvent2 -= value; } // Noncompliant FP
656+
657+
remove { SomeEvent2 += value; } // Noncompliant FP
658+
}
659+
660+
public event SomeDelegate SomeEvent3
626661
{
627662
add
628663
{
629-
SomeEvent += value; // FN
664+
SomeEvent += value; // Compliant
630665
}
631666

632667
remove
633668
{
634-
SomeEvent -= value; // FN
669+
SomeEvent -= value; // Compliant
635670
}
636671
}
637672
}

0 commit comments

Comments
 (0)