Skip to content

Commit abce8b8

Browse files
Tim-Pohlmannsonartech
authored andcommitted
NET-1244 Write UTs for uncovered extension methods in IOperationExtension
1 parent ea56edc commit abce8b8

File tree

3 files changed

+114
-72
lines changed

3 files changed

+114
-72
lines changed

analyzers/src/SonarAnalyzer.CFG/Extensions/IOperationExtensions.cs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,18 @@ public static IEnumerable<IOperation> DescendantsAndSelf(this IOperation operati
142142
public static IDeclarationPatternOperationWrapper? AsDeclarationPattern(this IOperation operation) =>
143143
operation.As(OperationKindEx.DeclarationPattern, IDeclarationPatternOperationWrapper.FromOperation);
144144

145-
public static IFlowCaptureOperationWrapper? AsFlowCapture(this IOperation operation) =>
146-
operation.As(OperationKindEx.FlowCapture, IFlowCaptureOperationWrapper.FromOperation);
147-
148145
public static IFlowCaptureReferenceOperationWrapper? AsFlowCaptureReference(this IOperation operation) =>
149146
operation.As(OperationKindEx.FlowCaptureReference, IFlowCaptureReferenceOperationWrapper.FromOperation);
150147

151-
// Other LoopKinds (e.g. For, While) are still OperationKindEx.Loop, but cannot be cast to IForEachLoopOperationWrapper so we need an additional check
152-
public static IForEachLoopOperationWrapper? AsForEachLoop(this IOperation operation) =>
153-
IForEachLoopOperationWrapper.IsInstance(operation) ? IForEachLoopOperationWrapper.FromOperation(operation) : null;
148+
public static IForEachLoopOperationWrapper? AsForEachLoop(this IOperation operation)
149+
{
150+
if (operation is null) // null check to be consistent with other the other As methods
151+
{
152+
throw new NullReferenceException(nameof(operation));
153+
}
154+
// Other LoopKinds (e.g. For, While) are still OperationKindEx.Loop, but cannot be cast to IForEachLoopOperationWrapper so we need an additional check
155+
return IForEachLoopOperationWrapper.IsInstance(operation) ? IForEachLoopOperationWrapper.FromOperation(operation) : null;
156+
}
154157

155158
public static IInvocationOperationWrapper? AsInvocation(this IOperation operation) =>
156159
operation.As(OperationKindEx.Invocation, IInvocationOperationWrapper.FromOperation);
@@ -242,12 +245,6 @@ public static IFlowCaptureOperationWrapper ToFlowCapture(this IOperation operati
242245
public static IFlowCaptureReferenceOperationWrapper ToFlowCaptureReference(this IOperation operation) =>
243246
IFlowCaptureReferenceOperationWrapper.FromOperation(operation);
244247

245-
public static IForEachLoopOperationWrapper ToForEachLoop(this IOperation operation) =>
246-
IForEachLoopOperationWrapper.FromOperation(operation);
247-
248-
public static ILoopOperationWrapper ToLoop(this IOperation operation) =>
249-
ILoopOperationWrapper.FromOperation(operation);
250-
251248
public static IIncrementOrDecrementOperationWrapper ToIncrementOrDecrement(this IOperation operation) =>
252249
IIncrementOrDecrementOperationWrapper.FromOperation(operation);
253250

analyzers/tests/SonarAnalyzer.Core.Test/Extensions/IOperationExtensionsTest.cs

Lines changed: 0 additions & 60 deletions
This file was deleted.
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* SonarAnalyzer for .NET
3+
* Copyright (C) 2014-2025 SonarSource SA
4+
* mailto:info AT sonarsource DOT com
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11+
* See the Sonar Source-Available License for more details.
12+
*
13+
* You should have received a copy of the Sonar Source-Available License
14+
* along with this program; if not, see https://sonarsource.com/license/ssal/
15+
*/
16+
17+
using Microsoft.CodeAnalysis.CSharp.Syntax;
18+
using Microsoft.CodeAnalysis.Operations;
19+
20+
namespace SonarAnalyzer.CFG.Extensions.Test;
21+
22+
[TestClass]
23+
public class IOperationExtensionsTest
24+
{
25+
[TestMethod]
26+
public void DescendantsAndSelf_Null_ReturnsNull() =>
27+
IOperationExtensions.DescendantsAndSelf(null).Should().BeEmpty();
28+
29+
[TestMethod]
30+
public void OperationWrapperSonarPropertyShortcuts()
31+
{
32+
var operation = Operation<VariableDeclarationSyntax>("""
33+
public class Sample
34+
{
35+
public void Method()
36+
{
37+
var value = 42;
38+
}
39+
}
40+
""").ToVariableDeclaration();
41+
operation.Parent().Should().NotBeNull();
42+
operation.Parent().Kind.Should().Be(OperationKind.VariableDeclarationGroup);
43+
operation.Children().Should().HaveCount(1);
44+
operation.Children().Single().Kind.Should().Be(OperationKind.VariableDeclarator);
45+
operation.Language().Should().Be("C#");
46+
operation.IsImplicit().Should().Be(false);
47+
operation.SemanticModel().Should().Be(operation.SemanticModel());
48+
}
49+
50+
[TestMethod]
51+
public void AsForEachLoop_ForEachLoop_ConvertsToWrapper() =>
52+
Operation<MethodDeclarationSyntax>("""
53+
public class Sample
54+
{
55+
public void Method(int[] items)
56+
{
57+
foreach (var item in items)
58+
{
59+
// Do something with item
60+
}
61+
}
62+
}
63+
""").Descendants().OfType<ILoopOperation>().Single().AsForEachLoop().Should().NotBeNull();
64+
65+
[DataTestMethod]
66+
[DataRow("for (var i = 0; i < 9; i++) { }")]
67+
[DataRow("while (true) { }")]
68+
[DataRow("do { } while (true);")]
69+
public void AsForEachLoop_OtherLoop_ConvertsToWrapper(string loop) =>
70+
Operation<MethodDeclarationSyntax>($$"""
71+
public class Sample
72+
{
73+
public void Method()
74+
{
75+
{{loop}}
76+
}
77+
}
78+
""").Descendants().OfType<ILoopOperation>().Single().AsForEachLoop().Should().BeNull();
79+
80+
[TestMethod]
81+
public void ExtensionsMethodsUsedByArchitecture()
82+
{
83+
IOperation operation = null;
84+
// These extension methods are used by sonar-architecture. Do not remove them.
85+
Assert.ThrowsException<NullReferenceException>(() => operation.AsForEachLoop());
86+
Assert.ThrowsException<NullReferenceException>(() => operation.AsVariableDeclarator());
87+
operation.ToArrayCreation();
88+
operation.ToCatchClause();
89+
operation.ToConversion();
90+
operation.ToInvocation();
91+
operation.ToIsType();
92+
operation.ToLocalFunction();
93+
operation.ToMemberReference();
94+
operation.ToObjectCreation();
95+
operation.ToPattern();
96+
operation.ToVariableDeclaration();
97+
operation.ToVariableDeclarator();
98+
}
99+
100+
private static IOperation Operation<T>(string code) where T : SyntaxNode
101+
{
102+
var (tree, model) = TestCompiler.CompileCS(code);
103+
return model.GetOperation(tree.Single<T>());
104+
}
105+
}

0 commit comments

Comments
 (0)