Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix S1144 FP: Private attributes #9411

Merged
merged 7 commits into from
Jun 13, 2024
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
Expand Up @@ -53,6 +53,7 @@ private enum SymbolAccess
public IDictionary<ISymbol, SymbolUsage> FieldSymbolUsages { get; } = new Dictionary<ISymbol, SymbolUsage>();
public HashSet<string> DebuggerDisplayValues { get; } = [];
public Dictionary<IPropertySymbol, AccessorAccess> PropertyAccess { get; } = [];
public HashSet<ISymbol> PrivateAttributes { get; } = [];
public HashSet<ISymbol> TypesUsedWithReflection { get; } = [];

public CSharpSymbolUsageCollector(Compilation compilation, IEnumerable<ISymbol> knownSymbols)
Expand Down Expand Up @@ -147,19 +148,26 @@ public override void VisitAttribute(AttributeSyntax node)
{
TypesUsedWithReflection.Add(typeSymbol);
}
else if (model.GetSymbolInfo(node).Symbol is IMethodSymbol { MethodKind: MethodKind.Constructor, ContainingType: ITypeSymbol attribute }
&& attribute.Is(KnownType.System_Diagnostics_DebuggerDisplayAttribute)
&& node.ArgumentList is not null)
else if (model.GetSymbolInfo(node).Symbol is IMethodSymbol { MethodKind: MethodKind.Constructor, ContainingType: ITypeSymbol attribute })
{
var arguments = node.ArgumentList.Arguments
.Where(IsValueNameOrType)
.Select(x => model.GetConstantValue(x.Expression))
.Where(x => x.HasValue)
.Select(x => x.Value)
.OfType<string>();

DebuggerDisplayValues.UnionWith(arguments);
if (attribute.Is(KnownType.System_Diagnostics_DebuggerDisplayAttribute)
&& node.ArgumentList is not null)
{
var arguments = node.ArgumentList.Arguments
.Where(IsValueNameOrType)
.Select(x => model.GetConstantValue(x.Expression))
.Where(x => x.HasValue)
.Select(x => x.Value)
.OfType<string>();

DebuggerDisplayValues.UnionWith(arguments);
}
else if (attribute.GetEffectiveAccessibility() == Accessibility.Private)
{
PrivateAttributes.Add(attribute);
}
}

base.VisitAttribute(node);

static bool IsValueNameOrType(AttributeArgumentSyntax a) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ private static HashSet<ISymbol> GetUnusedSymbols(CSharpSymbolUsageCollector usag
.Except(usageCollector.UsedSymbols)
.Where(x => !IsMentionedInDebuggerDisplay(x, usageCollector)
&& !IsAccessorUsed(x, usageCollector)
&& !usageCollector.PrivateAttributes.Contains(x)
&& !IsUsedWithReflection(x, usageCollector.TypesUsedWithReflection))
.ToHashSet();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ [Private1] private protected void APrivateProtectedMethod() { }
[Public1, Private2] public void APublicMethodWithMultipleAttributes1() { }
[Public1][Private2] public void APublicMethodWithMultipleAttributes2() { }

private class Private1Attribute : Attribute { } // Noncompliant: FP: attribute used on a private protected method
private class Private2Attribute : Attribute { } // Noncompliant: FP: attribute used on a public method
private class Private3Attribute : Attribute { } // Noncompliant: FP: attribute used on a public method
private class Private1Attribute : Attribute { }
private class Private2Attribute : Attribute { }
private class Private3Attribute : Attribute { } // Noncompliant
public class Public1Attribute : Attribute { } // Compliant: public
}
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,6 @@ private class A
private bool a = true; // Noncompliant FP: type argument is inferred and ArgumentList is not present on syntax level (see line 183)
}

class C<T>
{
private int usedByReflection; // Noncompliant - FP
C<T> Create() => Program.CreateInstance<C<T>>(); // Noncompliant - FP
}

private class ClassInstantiatedThroughReflection
{
private const int PrivateConst = 42; // Noncompliant - FP
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,11 @@ class Repro_8342
[Private2] internal void AnInternalMethod() { }
[Private3] protected void AProtectedMethod() { }
[Private4] private void APrivateMethodCalledByAPublicMethod() { }

private class Private1Attribute : Attribute { }
private class Private2Attribute : Attribute { }
private class Private3Attribute : Attribute { }
private class Private4Attribute : Attribute { }
}

// https://github.com/SonarSource/sonar-dotnet/issues/8532
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,11 @@ class Repro_8342
[Private2] internal void AnInternalMethod() { }
[Private3] protected void AProtectedMethod() { }
[Private4] private void APrivateMethodCalledByAPublicMethod() { }

private class Private1Attribute : Attribute { }
private class Private2Attribute : Attribute { }
private class Private3Attribute : Attribute { }
private class Private4Attribute : Attribute { }
}

// https://github.com/SonarSource/sonar-dotnet/issues/8532
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,10 +448,10 @@ [Private2] internal void AnInternalMethod() { }
[Private3] protected void AProtectedMethod() { }
[Private4] private void APrivateMethodCalledByAPublicMethod() { }

private class Private1Attribute : Attribute { } // Noncompliant: FP: attribute used on a public method
private class Private2Attribute : Attribute { } // Noncompliant: FP: attribute used on an internal method
private class Private3Attribute : Attribute { } // Noncompliant: FP: attribute used on a protected method
private class Private4Attribute : Attribute { } // Noncompliant: FP: attribute used on a private method used by a public method
private class Private1Attribute : Attribute { }
private class Private2Attribute : Attribute { }
private class Private3Attribute : Attribute { }
private class Private4Attribute : Attribute { }
}

// https://github.com/SonarSource/sonar-dotnet/issues/8532
Expand Down