diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/ArgumentDescriptor.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/ArgumentDescriptor.cs index b8308cb3228..8cdde505812 100644 --- a/analyzers/src/SonarAnalyzer.Common/Helpers/ArgumentDescriptor.cs +++ b/analyzers/src/SonarAnalyzer.Common/Helpers/ArgumentDescriptor.cs @@ -59,17 +59,17 @@ public class ArgumentDescriptor MethodInvocation(invokedType, methodName, parameterName, x => x == argumentPosition); public static ArgumentDescriptor MethodInvocation(KnownType invokedType, string methodName, string parameterName, Func argumentPosition) => - MethodInvocation(invokedType, methodName, p => p.Name == parameterName, argumentPosition, null); + MethodInvocation(invokedType, methodName, x => x.Name == parameterName, argumentPosition, null); public static ArgumentDescriptor MethodInvocation(KnownType invokedType, string methodName, string parameterName, Func argumentPosition, RefKind refKind) => - MethodInvocation(invokedType, methodName, p => p.Name == parameterName, argumentPosition, refKind); + MethodInvocation(invokedType, methodName, x => x.Name == parameterName, argumentPosition, refKind); public static ArgumentDescriptor MethodInvocation(KnownType invokedType, Func invokedMemberNameConstraint, Func parameterConstraint, Func argumentPosition, RefKind? refKind) => - MethodInvocation(s => invokedType.Matches(s.ContainingType), invokedMemberNameConstraint, parameterConstraint, argumentPosition, refKind); + MethodInvocation(x => invokedType.Matches(x.ContainingType), invokedMemberNameConstraint, parameterConstraint, argumentPosition, refKind); public static ArgumentDescriptor MethodInvocation(Func invokedMemberConstraint, Func invokedMemberNameConstraint, @@ -153,7 +153,7 @@ public class ArgumentDescriptor x => x is { MethodKind: MethodKind.Constructor, ContainingType.Name: { } name } && AttributeClassNameConstraint(attributeName, name, StringComparison.Ordinal), (x, c) => AttributeClassNameConstraint(attributeName, x, c), (_, _, _) => true, - p => p.Name == parameterName, + x => x.Name == parameterName, (_, i) => i is null || i.Value == argumentPosition); public static ArgumentDescriptor AttributeArgument(Func attributeConstructorConstraint, diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/MethodParameterLookupBase.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/MethodParameterLookupBase.cs index 188917b5e23..c146f3a1543 100644 --- a/analyzers/src/SonarAnalyzer.Common/Helpers/MethodParameterLookupBase.cs +++ b/analyzers/src/SonarAnalyzer.Common/Helpers/MethodParameterLookupBase.cs @@ -22,11 +22,11 @@ namespace SonarAnalyzer.Helpers; public interface IMethodParameterLookup { + IMethodSymbol MethodSymbol { get; } bool TryGetSymbol(SyntaxNode argument, out IParameterSymbol parameter); bool TryGetSyntax(IParameterSymbol parameter, out ImmutableArray expressions); bool TryGetSyntax(string parameterName, out ImmutableArray expressions); bool TryGetNonParamsSyntax(IParameterSymbol parameter, out SyntaxNode expression); - IMethodSymbol MethodSymbol { get; } } // This should come from the Roslyn API (https://github.com/dotnet/roslyn/issues/9) @@ -64,7 +64,7 @@ private bool TryGetSymbol(SyntaxNode argument, IMethodSymbol methodSymbol, out I var arg = argument as TArgumentSyntax ?? throw new ArgumentException($"{nameof(argument)} must be of type {typeof(TArgumentSyntax)}", nameof(argument)); if (!argumentList.Contains(arg) - || methodSymbol == null + || methodSymbol is null || methodSymbol.IsVararg) { return false; @@ -72,8 +72,8 @@ private bool TryGetSymbol(SyntaxNode argument, IMethodSymbol methodSymbol, out I if (GetNameColonIdentifier(arg) is { } nameColonIdentifier) { - parameter = methodSymbol.Parameters.FirstOrDefault(symbol => symbol.Name == nameColonIdentifier.ValueText); - return parameter != null; + parameter = methodSymbol.Parameters.FirstOrDefault(x => x.Name == nameColonIdentifier.ValueText); + return parameter is not null; } if (GetNameEqualsIdentifier(arg) is { } nameEqualsIdentifier @@ -83,7 +83,7 @@ private bool TryGetSymbol(SyntaxNode argument, IMethodSymbol methodSymbol, out I && setter.Parameters is { Length: 1 } parameters) { parameter = parameters[0]; - return parameter != null; + return parameter is not null; } var index = argumentList.IndexOf(arg); @@ -91,7 +91,7 @@ private bool TryGetSymbol(SyntaxNode argument, IMethodSymbol methodSymbol, out I { var lastParameter = methodSymbol.Parameters.Last(); parameter = lastParameter.IsParams ? lastParameter : null; - return parameter != null; + return parameter is not null; } parameter = methodSymbol.Parameters[index]; return true; diff --git a/analyzers/src/SonarAnalyzer.Common/Trackers/ArgumentTracker.cs b/analyzers/src/SonarAnalyzer.Common/Trackers/ArgumentTracker.cs index 8af36ba9599..f3518bb0ed1 100644 --- a/analyzers/src/SonarAnalyzer.Common/Trackers/ArgumentTracker.cs +++ b/analyzers/src/SonarAnalyzer.Common/Trackers/ArgumentTracker.cs @@ -33,17 +33,17 @@ public abstract class ArgumentTracker : SyntaxTrackerBase - context => + trackingContext => { - if (context.Node is { } argumentNode + if (trackingContext.Node is { } argumentNode && argumentNode is { Parent.Parent: { } invoked } - && SyntacticChecks(context.SemanticModel, descriptor, argumentNode, invoked) - && (descriptor.InvokedMemberNodeConstraint?.Invoke(context.SemanticModel, Language, invoked) ?? true) - && MethodSymbol(context.SemanticModel, invoked) is { } methodSymbol + && SyntacticChecks(trackingContext.SemanticModel, descriptor, argumentNode, invoked) + && (descriptor.InvokedMemberNodeConstraint?.Invoke(trackingContext.SemanticModel, Language, invoked) ?? true) + && MethodSymbol(trackingContext.SemanticModel, invoked) is { } methodSymbol && Language.MethodParameterLookup(invoked, methodSymbol).TryGetSymbol(argumentNode, out var parameter) && ParameterMatches(parameter, descriptor.ParameterConstraint, descriptor.InvokedMemberConstraint)) { - context.Parameter = parameter; + trackingContext.Parameter = parameter; return true; } return false; @@ -63,9 +63,9 @@ public abstract class ArgumentTracker : SyntaxTrackerBase InvocationMatchesMemberKind(invokedExpression, descriptor.MemberKind) && RefKindMatches(descriptor, argumentNode) - && (descriptor.ArgumentListConstraint == null + && (descriptor.ArgumentListConstraint is null || (ArgumentList(argumentNode) is { } argList && descriptor.ArgumentListConstraint(argList, Position(argumentNode)))) - && (descriptor.InvokedMemberNameConstraint == null + && (descriptor.InvokedMemberNameConstraint is null || InvokedMemberMatches(model, invokedExpression, descriptor.MemberKind, x => descriptor.InvokedMemberNameConstraint(x, Language.NameComparison))); private bool RefKindMatches(ArgumentDescriptor descriptor, SyntaxNode argumentNode) => @@ -89,7 +89,7 @@ private static bool ParameterMatches(IParameterSymbol parameter, Func + where TSyntaxKind : struct + where TContext : BaseContext { - public abstract class TrackerBase - where TSyntaxKind : struct - where TContext : BaseContext - { - public delegate bool Condition(TContext trackingContext); + protected abstract ILanguageFacade Language { get; } - protected abstract ILanguageFacade Language { get; } - } + public delegate bool Condition(TContext trackingContext); } diff --git a/analyzers/tests/SonarAnalyzer.Test/Trackers/ArgumentTrackerTest.cs b/analyzers/tests/SonarAnalyzer.Test/Trackers/ArgumentTrackerTest.cs index 61d1e2d5234..b0323fb58dc 100644 --- a/analyzers/tests/SonarAnalyzer.Test/Trackers/ArgumentTrackerTest.cs +++ b/analyzers/tests/SonarAnalyzer.Test/Trackers/ArgumentTrackerTest.cs @@ -79,7 +79,7 @@ End Class """; var context = ArgumentContextVB(snippet); - var descriptor = ArgumentDescriptor.MethodInvocation(m => m.Name == "M", (s, c) => s.Equals("M", c), p => p.Name == parameterName, _ => true, null); + var descriptor = ArgumentDescriptor.MethodInvocation(x => x.Name == "M", (s, c) => s.Equals("M", c), x => x.Name == parameterName, _ => true, null); var result = MatchArgumentVB(context, descriptor); result.Should().Be(expected); } @@ -295,7 +295,7 @@ void M() """; var context = ArgumentContextCS(snippet); - var descriptor = ArgumentDescriptor.MethodInvocation(m => true, (m, c) => m.Equals("M", c), p => p.Name == "parameter", _ => true, null); + var descriptor = ArgumentDescriptor.MethodInvocation(_ => true, (m, c) => m.Equals("M", c), x => x.Name == "parameter", _ => true, null); var result = MatchArgumentCS(context, descriptor); result.Should().Be(expected); } @@ -354,7 +354,7 @@ End Class """; var context = ArgumentContextVB(snippet); - var descriptor = ArgumentDescriptor.MethodInvocation(m => true, (m, c) => m.Equals("M", c), p => p.Name == "parameter", _ => true, null); + var descriptor = ArgumentDescriptor.MethodInvocation(_ => true, (m, c) => m.Equals("M", c), x => x.Name == "parameter", _ => true, null); var result = MatchArgumentVB(context, descriptor); result.Should().Be(expected); } @@ -485,7 +485,7 @@ public void Method_ParamsArray(string invocation, string parameterName) """; var context = ArgumentContextCS(WrapInMethodCS(snippet)); - var descriptor = ArgumentDescriptor.MethodInvocation(KnownType.System_String, "Format", parameterName, i => i >= 1); + var descriptor = ArgumentDescriptor.MethodInvocation(KnownType.System_String, "Format", parameterName, x => x >= 1); var result = MatchArgumentCS(context, descriptor); result.Should().BeTrue(); } @@ -505,7 +505,7 @@ public void Method_ParamsArray_VB(string invocation, string parameterName) """; var context = ArgumentContextVB(WrapInMethodVB(snippet)); - var descriptor = ArgumentDescriptor.MethodInvocation(KnownType.System_String, "Format", parameterName, i => i >= 1); + var descriptor = ArgumentDescriptor.MethodInvocation(KnownType.System_String, "Format", parameterName, x => x >= 1); var result = MatchArgumentVB(context, descriptor); result.Should().BeTrue(); } @@ -815,7 +815,7 @@ public void M() var descriptor = ArgumentDescriptor.ConstructorInvocation(invokedMethodSymbol: x => x is { MethodKind: MethodKind.Constructor, ContainingSymbol.Name: "C" }, invokedMemberNameConstraint: (c, n) => c.Equals("C", n) || c.Equals("CAlias"), invokedMemberNodeConstraint: (_, _, _) => true, - parameterConstraint: p => p.Name is "i" or "j", + parameterConstraint: x => x.Name is "i" or "j", argumentListConstraint: (n, i) => i is null or 0 or 1 && n.Count > 1, refKind: null); var result = MatchArgumentCS(context, descriptor); @@ -837,7 +837,7 @@ class Base var descriptor = ArgumentDescriptor.ConstructorInvocation(invokedMethodSymbol: x => x is { MethodKind: MethodKind.Constructor, ContainingSymbol.Name: "Base" }, invokedMemberNameConstraint: (c, n) => c.Equals("Base", n), invokedMemberNodeConstraint: (_, _, _) => true, - parameterConstraint: p => p.Name is "i", + parameterConstraint: x => x.Name is "i", argumentListConstraint: (_, _) => true, refKind: null); var result = MatchArgumentCS(context, descriptor); @@ -862,7 +862,7 @@ class Derived: Base var descriptor = ArgumentDescriptor.ConstructorInvocation(invokedMethodSymbol: x => x is { MethodKind: MethodKind.Constructor, ContainingSymbol.Name: "Base" }, invokedMemberNameConstraint: (c, n) => c.Equals("Base", n), invokedMemberNodeConstraint: (_, _, _) => true, - parameterConstraint: p => p.Name is "i", + parameterConstraint: x => x.Name is "i", argumentListConstraint: (_, _) => true, refKind: null); var result = MatchArgumentCS(context, descriptor); @@ -919,7 +919,7 @@ public void Indexer_List_Get() var context = ArgumentContextCS(WrapInMethodCS(snippet)); var descriptor = ArgumentDescriptor.ElementAccess(KnownType.System_Collections_Generic_List_T, "list", - p => p is { Name: "index", Type.SpecialType: SpecialType.System_Int32, ContainingSymbol: IMethodSymbol { MethodKind: MethodKind.PropertyGet } }, 0); + x => x is { Name: "index", Type.SpecialType: SpecialType.System_Int32, ContainingSymbol: IMethodSymbol { MethodKind: MethodKind.PropertyGet } }, 0); var result = MatchArgumentCS(context, descriptor); result.Should().BeTrue(); context.Parameter.Name.Should().Be("index"); @@ -938,7 +938,7 @@ public void Indexer_List_Get_VB() var context = ArgumentContextVB(WrapInMethodVB(snippet)); var descriptor = ArgumentDescriptor.ElementAccess(KnownType.System_Collections_Generic_List_T, "list", - p => p is { Name: "index", Type.SpecialType: SpecialType.System_Int32, ContainingSymbol: IMethodSymbol { MethodKind: MethodKind.PropertyGet } }, 0); + x => x is { Name: "index", Type.SpecialType: SpecialType.System_Int32, ContainingSymbol: IMethodSymbol { MethodKind: MethodKind.PropertyGet } }, 0); var result = MatchArgumentVB(context, descriptor); result.Should().BeTrue(); context.Parameter.Name.Should().Be("index"); @@ -961,7 +961,7 @@ public void Indexer_List_Set(string writeExpression) var context = ArgumentContextCS(WrapInMethodCS(snippet)); var descriptor = ArgumentDescriptor.ElementAccess(KnownType.System_Collections_Generic_List_T, - p => p is { Name: "index", ContainingSymbol: IMethodSymbol { MethodKind: MethodKind.PropertySet } }, 0); + x => x is { Name: "index", ContainingSymbol: IMethodSymbol { MethodKind: MethodKind.PropertySet } }, 0); var result = MatchArgumentCS(context, descriptor); result.Should().BeTrue(); context.Parameter.ContainingSymbol.Should().BeAssignableTo().Which.MethodKind.Should().Be(MethodKind.PropertySet); @@ -980,7 +980,7 @@ public void Indexer_List_Set_VB(string writeExpression) var context = ArgumentContextVB(WrapInMethodVB(snippet)); var descriptor = ArgumentDescriptor.ElementAccess(KnownType.System_Collections_Generic_List_T, - p => p is { Name: "index", ContainingSymbol: IMethodSymbol { MethodKind: MethodKind.PropertySet } }, 0); + x => x is { Name: "index", ContainingSymbol: IMethodSymbol { MethodKind: MethodKind.PropertySet } }, 0); var result = MatchArgumentVB(context, descriptor); result.Should().BeTrue(); context.Parameter.ContainingSymbol.Should().BeAssignableTo().Which.MethodKind.Should().Be(MethodKind.PropertySet); @@ -996,8 +996,8 @@ public void Indexer_DictionaryGet(string environmentVariableAccess) """; var context = ArgumentContextCS(WrapInMethodCS(snippet)); - var descriptor = ArgumentDescriptor.ElementAccess(m => m is { MethodKind: MethodKind.PropertyGet, ContainingType.Name: "IDictionary" }, - (n, c) => n.Equals("GetEnvironmentVariables", c), (_, _, _) => true, p => p.Name == "key", (_, p) => p is null or 0); + var descriptor = ArgumentDescriptor.ElementAccess(x => x is { MethodKind: MethodKind.PropertyGet, ContainingType.Name: "IDictionary" }, + (n, c) => n.Equals("GetEnvironmentVariables", c), (_, _, _) => true, x => x.Name == "key", (_, p) => p is null or 0); var result = MatchArgumentCS(context, descriptor); result.Should().BeTrue(); } @@ -1010,8 +1010,8 @@ public void Indexer_DictionaryGet_VB() """; var context = ArgumentContextVB(WrapInMethodVB(snippet)); - var descriptor = ArgumentDescriptor.ElementAccess(m => m is { MethodKind: MethodKind.PropertyGet, ContainingType.Name: "IDictionary" }, - (n, c) => n.Equals("GetEnvironmentVariables", c), (_, _, _) => true, p => p.Name == "key", (_, p) => p is null or 0); + var descriptor = ArgumentDescriptor.ElementAccess(x => x is { MethodKind: MethodKind.PropertyGet, ContainingType.Name: "IDictionary" }, + (n, c) => n.Equals("GetEnvironmentVariables", c), (_, _, _) => true, x => x.Name == "key", (_, p) => p is null or 0); var result = MatchArgumentVB(context, descriptor); result.Should().BeTrue(); } @@ -1043,10 +1043,10 @@ public class C { var context = ArgumentContextCS(snippet); var descriptor = ArgumentDescriptor.ElementAccess( - m => m is { MethodKind: var kind, ContainingType.Name: "C" } && (isGetter ? kind == MethodKind.PropertyGet : kind == MethodKind.PropertySet), + x => x is { MethodKind: var kind, ContainingType.Name: "C" } && (isGetter ? kind == MethodKind.PropertyGet : kind == MethodKind.PropertySet), (_, _) => true, (_, _, _) => true, - p => p.Name == parameterName, + x => x.Name == parameterName, (_, _) => true); var result = MatchArgumentCS(context, descriptor); result.Should().BeTrue(); @@ -1081,10 +1081,10 @@ End Class var context = ArgumentContextVB(snippet); var descriptor = ArgumentDescriptor.ElementAccess( - m => m is { MethodKind: var kind, ContainingType.Name: "C" } && (isGetter ? kind == MethodKind.PropertyGet : kind == MethodKind.PropertySet), + x => x is { MethodKind: var kind, ContainingType.Name: "C" } && (isGetter ? kind == MethodKind.PropertyGet : kind == MethodKind.PropertySet), (_, _) => true, (_, _, _) => true, - p => p.Name == parameterName, + x => x.Name == parameterName, (_, _) => true); var result = MatchArgumentVB(context, descriptor); result.Should().BeTrue(); @@ -1110,10 +1110,10 @@ public void M(System.Diagnostics.Process process) """; var context = ArgumentContextCS(snippet); - var descriptor = ArgumentDescriptor.ElementAccess(m => m is { MethodKind: MethodKind.PropertyGet, ContainingType.Name: "ProcessModuleCollection" }, + var descriptor = ArgumentDescriptor.ElementAccess(x => x is { MethodKind: MethodKind.PropertyGet, ContainingType.Name: "ProcessModuleCollection" }, (n, c) => n.Equals("Modules", c), (_, _, _) => true, - p => p.Name == "index", + x => x.Name == "index", (_, p) => p is null or 0); var result = MatchArgumentCS(context, descriptor); result.Should().BeTrue(); @@ -1139,7 +1139,7 @@ public void M(System.Diagnostics.ProcessStartInfo processStartInfo) """; var context = ArgumentContextCS(snippet); - var descriptor = ArgumentDescriptor.ElementAccess(KnownType.System_Collections_Generic_IDictionary_TKey_TValue, "Environment", p => p.Name == "key", 0); + var descriptor = ArgumentDescriptor.ElementAccess(KnownType.System_Collections_Generic_IDictionary_TKey_TValue, "Environment", x => x.Name == "key", 0); var result = MatchArgumentCS(context, descriptor); result.Should().BeTrue(); } @@ -1164,7 +1164,7 @@ public void M() var descriptor = ArgumentDescriptor.AttributeArgument(x => x is { MethodKind: MethodKind.Constructor, ContainingType.Name: "ObsoleteAttribute" }, (s, c) => s.StartsWith("Obsolete", c), (_, _, _) => true, - p => p.Name == "message", + x => x.Name == "message", (_, i) => i is 0); var result = MatchArgumentCS(context, descriptor); result.Should().BeTrue(); @@ -1187,7 +1187,7 @@ End Class var descriptor = ArgumentDescriptor.AttributeArgument(x => x is { MethodKind: MethodKind.Constructor, ContainingType.Name: "ObsoleteAttribute" }, (s, c) => s.StartsWith("Obsolete", c), (_, _, _) => true, - p => p.Name == "message", + x => x.Name == "message", (_, i) => i is 0); var result = MatchArgumentVB(context, descriptor); result.Should().BeTrue();