diff --git a/analyzers/its/expected/Nancy/S1117-Nancy-net452.json b/analyzers/its/expected/Nancy/S1117-Nancy-net452.json index a2326af8ba0..6eccc5478b2 100644 --- a/analyzers/its/expected/Nancy/S1117-Nancy-net452.json +++ b/analyzers/its/expected/Nancy/S1117-Nancy-net452.json @@ -1,40 +1,10 @@ { "Issues": [ - { - "Id": "S1117", - "Message": "Rename \u0027assemblies\u0027 which hides the field with the same name.", - "Uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Nancy/src/Nancy/AppDomainAssemblyCatalog.cs#L32", - "Location": "Line 32 Position 17-27" - }, - { - "Id": "S1117", - "Message": "Rename \u0027assemblies\u0027 which hides the field with the same name.", - "Uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Nancy/src/Nancy/AppDomainAssemblyCatalog.cs#L41", - "Location": "Line 41 Position 17-27" - }, - { - "Id": "S1117", - "Message": "Rename \u0027assemblies\u0027 which hides the field with the same name.", - "Uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Nancy/src/Nancy/AppDomainAssemblyCatalog.cs#L56", - "Location": "Line 56 Position 17-27" - }, { "Id": "S1117", "Message": "Rename \u0027parameters\u0027 which hides the field with the same name.", "Uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Nancy/src/Nancy/HttpLink.cs#L230", "Location": "Line 230 Position 17-27" - }, - { - "Id": "S1117", - "Message": "Rename \u0027prefix\u0027 which hides the field with the same name.", - "Uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Nancy/src/Nancy/HttpLinkRelation.cs#L152", - "Location": "Line 152 Position 21-27" - }, - { - "Id": "S1117", - "Message": "Rename \u0027value\u0027 which hides the field with the same name.", - "Uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Nancy/src/Nancy/HttpLinkRelation.cs#L153", - "Location": "Line 153 Position 21-26" } ] } \ No newline at end of file diff --git a/analyzers/its/expected/Nancy/S1117-Nancy-netstandard2.0.json b/analyzers/its/expected/Nancy/S1117-Nancy-netstandard2.0.json index 7264a9461ce..6eccc5478b2 100644 --- a/analyzers/its/expected/Nancy/S1117-Nancy-netstandard2.0.json +++ b/analyzers/its/expected/Nancy/S1117-Nancy-netstandard2.0.json @@ -5,18 +5,6 @@ "Message": "Rename \u0027parameters\u0027 which hides the field with the same name.", "Uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Nancy/src/Nancy/HttpLink.cs#L230", "Location": "Line 230 Position 17-27" - }, - { - "Id": "S1117", - "Message": "Rename \u0027prefix\u0027 which hides the field with the same name.", - "Uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Nancy/src/Nancy/HttpLinkRelation.cs#L152", - "Location": "Line 152 Position 21-27" - }, - { - "Id": "S1117", - "Message": "Rename \u0027value\u0027 which hides the field with the same name.", - "Uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Nancy/src/Nancy/HttpLinkRelation.cs#L153", - "Location": "Line 153 Position 21-26" } ] } \ No newline at end of file diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/VariableShadowsField.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/VariableShadowsField.cs index 1687edf5fc3..3bc36c8a213 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/VariableShadowsField.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/VariableShadowsField.cs @@ -90,7 +90,8 @@ private static List GetContextSymbols(SonarSyntaxNodeReportingContext c private static void ReportOnVariableMatchingField(SonarSyntaxNodeReportingContext context, IEnumerable members, SyntaxToken identifier) { - if (members.FirstOrDefault(x => x.Name == identifier.ValueText) is { } matchingMember) + if (members.FirstOrDefault(x => x.Name == identifier.ValueText + && (x.IsStatic || !identifier.Parent.EnclosingScope().GetModifiers().Any(x => x.Kind() == SyntaxKind.StaticKeyword))) is { } matchingMember) { context.ReportIssue(Diagnostic.Create(Rule, identifier.GetLocation(), identifier.Text, GetSymbolName(matchingMember))); } diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/VariableShadowsField.CSharp12.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/VariableShadowsField.CSharp12.cs index 1046e63080d..5bb0bda1178 100644 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/VariableShadowsField.CSharp12.cs +++ b/analyzers/tests/SonarAnalyzer.Test/TestCases/VariableShadowsField.CSharp12.cs @@ -37,18 +37,13 @@ void MyMethod() // Reproducer for https://github.com/SonarSource/sonar-dotnet/issues/8260 class Repro_8260(int primaryCtorParam) { - private int instanceField = 1; - private int instanceProperty { get; set; } = 1; - private static int staticField = 1; - private static int staticProperty = 1; - public static void StaticMethod() { - var instanceField = 2; // Noncompliant FP (instance field is not accessible from static method) - var instanceProperty = 2; // Noncompliant FP (instance property is not accessible from static method) - var primaryCtorParam = 2; // Noncompliant FP (primary ctor parameter is not accessible from static method) + var primaryCtorParam = 42; // Compliant (primary ctor parameter is not accessible from static method) + } - var staticField = 2; // Noncompliant - var staticProperty = 2; // Noncompliant + public void NonStaticMethod() + { + var primaryCtorParam = 42; // Noncompliant } } diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/VariableShadowsField.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/VariableShadowsField.cs index bb915f8499b..4433a14b5e9 100644 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/VariableShadowsField.cs +++ b/analyzers/tests/SonarAnalyzer.Test/TestCases/VariableShadowsField.cs @@ -159,4 +159,59 @@ public void OutParameter(out object parameter) parameter = null; } } + + public class Base + { + private int privateInstanceField = 1; + private int privateInstanceProperty { get; set; } = 1; + private static int privateStaticField = 1; + private static int privateStaticProperty = 1; + + protected int protectedInstanceField = 1; + protected int protectedInstanceProperty { get; set; } = 1; + protected static int protectedStaticField = 1; + protected static int protectedStaticProperty = 1; + + public static void BaseStaticMethod() + { + var privateInstanceField = 2; // Compliant (instance field is not accessible from static method) + var privateInstanceProperty = 2; // Compliant (instance property is not accessible from static method) + + var privateStaticField = 2; // Noncompliant + var privateStaticProperty = 2; // Noncompliant + } + + public void BaseInstanceMethod() + { + var privateInstanceField = 2; // Noncompliant + var privateInstanceProperty = 2; // Noncompliant + + var privateStaticField = 2; // Noncompliant + var privateStaticProperty = 2; // Noncompliant + } + } + + public class Derived : Base + { + public static void DerivedStaticMethod() + { + var privateStaticField = 2; // Compliant (private field from the base class is not accessible in the derived class) + var privateStaticProperty = 2; // Compliant (private property from the base class is not accessible in the derived class) + + var protectedInstanceField = 2; // Compliant (instance field is not accessible from static method) + var protectedInstanceProperty = 2; // Compliant (instance property is not accessible from static method) + + var protectedStaticField = 2; // FN - members from the base class are not checked + var protectedStaticProperty = 2; // FN + } + + public void DerivedInstanceMethod() + { + var protectedInstanceField = 2; // FN + var protectedInstanceProperty = 2; // FN + + var protectedStaticField = 2; // FN + var protectedStaticProperty = 2; // FN + } + } }