Skip to content

Commit

Permalink
ReportIssue: Remove obsolete overloads from SonarAnalysisContextExten…
Browse files Browse the repository at this point in the history
…sions
  • Loading branch information
pavel-mikula-sonarsource committed May 30, 2024
1 parent 0f941bf commit fad8aef
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,37 +46,19 @@ public static void RegisterSemanticModelAction(this SonarAnalysisContext context
public static void RegisterCodeBlockStartAction(this SonarAnalysisContext context, Action<SonarCodeBlockStartAnalysisContext<SyntaxKind>> action) =>
context.RegisterCodeBlockStartAction(CSharpGeneratedCodeRecognizer.Instance, action);

[Obsolete("Use another overload of ReportIssue, without calling Diagnostic.Create")]
public static void ReportIssue(this SonarCompilationReportingContext context, Diagnostic diagnostic) =>
context.ReportIssue(CSharpGeneratedCodeRecognizer.Instance, diagnostic);

public static void ReportIssue(this SonarCompilationReportingContext context,
DiagnosticDescriptor rule,
Location primaryLocation,
IEnumerable<SecondaryLocation> secondaryLocations,
params string[] messageArgs) =>
context.ReportIssue(CSharpGeneratedCodeRecognizer.Instance, rule, primaryLocation, secondaryLocations, messageArgs);

public static void ReportIssue(this SonarCompilationReportingContext context, DiagnosticDescriptor rule, Location location, params string[] messageArgs) =>
context.ReportIssue(CSharpGeneratedCodeRecognizer.Instance, rule, location, messageArgs);

[Obsolete("Use another overload of ReportIssue, without calling Diagnostic.Create")]
public static void ReportIssue(this SonarSymbolReportingContext context, Diagnostic diagnostic) =>
context.ReportIssue(CSharpGeneratedCodeRecognizer.Instance, diagnostic);

public static void ReportIssue(this SonarSymbolReportingContext context, DiagnosticDescriptor rule, SyntaxNode locationSyntax, params string[] messageArgs) =>
public static void ReportIssue<TContext>(this SonarCompilationReportingContextBase<TContext> context, DiagnosticDescriptor rule, SyntaxNode locationSyntax, params string[] messageArgs) =>
context.ReportIssue(CSharpGeneratedCodeRecognizer.Instance, rule, locationSyntax, messageArgs);

public static void ReportIssue(this SonarSymbolReportingContext context, DiagnosticDescriptor rule, SyntaxToken locationToken, params string[] messageArgs) =>
public static void ReportIssue<TContext>(this SonarCompilationReportingContextBase<TContext> context, DiagnosticDescriptor rule, SyntaxToken locationToken, params string[] messageArgs) =>
context.ReportIssue(CSharpGeneratedCodeRecognizer.Instance, rule, locationToken, messageArgs);

public static void ReportIssue(this SonarSymbolReportingContext context, DiagnosticDescriptor rule, Location location, params string[] messageArgs) =>
public static void ReportIssue<TContext>(this SonarCompilationReportingContextBase<TContext> context, DiagnosticDescriptor rule, Location location, params string[] messageArgs) =>
context.ReportIssue(CSharpGeneratedCodeRecognizer.Instance, rule, location, messageArgs);

public static void ReportIssue(this SonarSymbolReportingContext context,
DiagnosticDescriptor rule,
Location primaryLocation,
IEnumerable<SecondaryLocation> secondaryLocations,
params string[] messageArgs) =>
public static void ReportIssue<TContext>(this SonarCompilationReportingContextBase<TContext> context,
DiagnosticDescriptor rule,
Location primaryLocation,
IEnumerable<SecondaryLocation> secondaryLocations,
params string[] messageArgs) =>
context.ReportIssue(CSharpGeneratedCodeRecognizer.Instance, rule, primaryLocation, secondaryLocations, messageArgs);
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private void RegisterForSymbols(SonarCompilationStartAnalysisContext compilation
{
foreach (var candidate in candidates.Where(x => !(hasActionFiltersOverrides && x.OriginatesFromParameter)))
{
symbolEnd.ReportIssue(Diagnostic.Create(Rule, candidate.Location, candidate.Message));
symbolEnd.ReportIssue(Rule, candidate.Location, candidate.Message);
}
});
}, SymbolKind.NamedType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ protected override void Initialize(SonarAnalysisContext context) =>
{
if (hasResx && !HasNeutralResourcesLanguageAttribute(cc.Compilation.Assembly))
{
cc.ReportIssue(Rule, null, cc.Compilation.AssemblyName);
cc.ReportIssue(Rule, (Location)null, cc.Compilation.AssemblyName);
}
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,10 @@ private void RaiseOnUninvokedEventDeclaration(SonarSymbolReportingContext contex
var usedSymbols = GetInvokedEventSymbols(removableDeclarationCollector)
.Concat(GetPossiblyCopiedSymbols(removableDeclarationCollector))
.ToHashSet();

removableEventFields
.Where(x => !usedSymbols.Contains(x.Symbol))
.ToList()
.ForEach(x => context.ReportIssue(Diagnostic.Create(Rule, GetLocation(x.Node), x.Symbol.Name)));
foreach (var field in removableEventFields.Where(x => !usedSymbols.Contains(x.Symbol)))
{
context.ReportIssue(Rule, GetLocation(field.Node), field.Symbol.Name);
}

Location GetLocation(SyntaxNode node) =>
node is VariableDeclaratorSyntax variableDeclarator
Expand Down
92 changes: 41 additions & 51 deletions analyzers/src/SonarAnalyzer.CSharp/Rules/UnusedPrivateMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,7 @@ protected override void Initialize(SonarAnalysisContext context) =>
{
usageCollector.SafeVisit(syntaxTree.GetRoot());
}
foreach (var diagnostic in DiagnosticsForUnusedPrivateMembers(usageCollector, removableInternalTypes, SyntaxConstants.Internal, new()))
{
cc.ReportIssue(diagnostic);
}
ReportUnusedPrivateMembers(cc, usageCollector, removableInternalTypes, SyntaxConstants.Internal, new());
});
});

Expand All @@ -87,14 +84,8 @@ private static void NamedSymbolAction(SonarSymbolReportingContext context, HashS
&& new CSharpSymbolUsageCollector(context.Compilation, AssociatedSymbols(privateSymbols)) is var usageCollector
&& VisitDeclaringReferences(namedType, usageCollector, context, includeGeneratedFile: true))
{
foreach (var diagnostic in DiagnosticsForUnusedPrivateMembers(usageCollector, privateSymbols, SyntaxConstants.Private, fieldLikeSymbols))
{
context.ReportIssue(diagnostic);
}
foreach (var diagnostic in DiagnosticsForUsedButUnreadFields(usageCollector, privateSymbols))
{
context.ReportIssue(diagnostic);
}
ReportUnusedPrivateMembers(context, usageCollector, privateSymbols, SyntaxConstants.Private, fieldLikeSymbols);
ReportUsedButUnreadFields(context, usageCollector, privateSymbols);
}
}

Expand Down Expand Up @@ -140,28 +131,30 @@ static IEnumerable<BaseTypeDeclarationSyntax> PrivateNestedMembersFromNonGenerat
.SelectMany(x => x.GetSyntax().ChildNodes().OfType<BaseTypeDeclarationSyntax>());
}

private static IEnumerable<Diagnostic> DiagnosticsForUnusedPrivateMembers(CSharpSymbolUsageCollector usageCollector,
ISet<ISymbol> removableSymbols,
string accessibility,
BidirectionalDictionary<ISymbol, SyntaxNode> fieldLikeSymbols)
private static void ReportUnusedPrivateMembers<TContext>(SonarCompilationReportingContextBase<TContext> context,
CSharpSymbolUsageCollector usageCollector,
ISet<ISymbol> removableSymbols,
string accessibility,
BidirectionalDictionary<ISymbol, SyntaxNode> fieldLikeSymbols)
{
var unusedSymbols = GetUnusedSymbols(usageCollector, removableSymbols);

var propertiesWithUnusedAccessor = removableSymbols
.Intersect(usageCollector.UsedSymbols)
.OfType<IPropertySymbol>()
.Where(usageCollector.PropertyAccess.ContainsKey)
.Where(x => !IsMentionedInDebuggerDisplay(x, usageCollector))
.Select(x => GetDiagnosticsForProperty(x, usageCollector.PropertyAccess))
.WhereNotNull();

return GetDiagnosticsForMembers(unusedSymbols, accessibility, fieldLikeSymbols).Concat(propertiesWithUnusedAccessor);
.Where(x => !IsMentionedInDebuggerDisplay(x, usageCollector));
foreach (var property in propertiesWithUnusedAccessor)
{
ReportProperty(context, property, usageCollector.PropertyAccess);
}
ReportDiagnosticsForMembers(context, unusedSymbols, accessibility, fieldLikeSymbols);
}

private static bool IsMentionedInDebuggerDisplay(ISymbol symbol, CSharpSymbolUsageCollector usageCollector) =>
usageCollector.DebuggerDisplayValues.Any(x => x.Contains(symbol.Name));

private static IEnumerable<Diagnostic> DiagnosticsForUsedButUnreadFields(CSharpSymbolUsageCollector usageCollector, IEnumerable<ISymbol> removableSymbols)
private static void ReportUsedButUnreadFields(SonarSymbolReportingContext context, CSharpSymbolUsageCollector usageCollector, IEnumerable<ISymbol> removableSymbols)
{
var unusedSymbols = GetUnusedSymbols(usageCollector, removableSymbols);

Expand All @@ -171,7 +164,10 @@ private static IEnumerable<Diagnostic> DiagnosticsForUsedButUnreadFields(CSharpS
.Where(x => !unusedSymbols.Contains(x.Symbol) && !IsMentionedInDebuggerDisplay(x.Symbol, usageCollector))
.Where(x => x.Declaration is not null && !x.Readings.Any());

return GetDiagnosticsForUnreadFields(usedButUnreadFields);
foreach (var usage in usedButUnreadFields)
{
context.ReportIssue(RuleS4487, usage.Declaration.GetLocation(), GetFieldAccessibilityForMessage(usage.Symbol), usage.Symbol.Name);
}
}

private static HashSet<ISymbol> GetUnusedSymbols(CSharpSymbolUsageCollector usageCollector, IEnumerable<ISymbol> removableSymbols) =>
Expand All @@ -180,9 +176,6 @@ private static HashSet<ISymbol> GetUnusedSymbols(CSharpSymbolUsageCollector usag
.Where(x => !IsMentionedInDebuggerDisplay(x, usageCollector) && !IsAccessorUsed(x, usageCollector))
.ToHashSet();

private static IEnumerable<Diagnostic> GetDiagnosticsForUnreadFields(IEnumerable<SymbolUsage> unreadFields) =>
unreadFields.Select(x => Diagnostic.Create(RuleS4487, x.Declaration.GetLocation(), GetFieldAccessibilityForMessage(x.Symbol), x.Symbol.Name));

private static bool IsAccessorUsed(ISymbol symbol, CSharpSymbolUsageCollector usageCollector) =>
symbol is IMethodSymbol { } accessor
&& accessor.AssociatedSymbol is IPropertySymbol { } property
Expand All @@ -193,11 +186,11 @@ symbol is IMethodSymbol { } accessor
private static string GetFieldAccessibilityForMessage(ISymbol symbol) =>
symbol.DeclaredAccessibility == Accessibility.Private ? SyntaxConstants.Private : "private class";

private static IEnumerable<Diagnostic> GetDiagnosticsForMembers(ICollection<ISymbol> unusedSymbols,
string accessibility,
BidirectionalDictionary<ISymbol, SyntaxNode> fieldLikeSymbols)
private static void ReportDiagnosticsForMembers<TContext>(SonarCompilationReportingContextBase<TContext> context,
ICollection<ISymbol> unusedSymbols,
string accessibility,
BidirectionalDictionary<ISymbol, SyntaxNode> fieldLikeSymbols)
{
var diagnostics = new List<Diagnostic>();
var alreadyReportedFieldLikeSymbols = new HashSet<ISymbol>();
var unusedSymbolSyntaxPairs = unusedSymbols.SelectMany(x => x.DeclaringSyntaxReferences.Select(syntax => new NodeAndSymbol(syntax.GetSyntax(), x)));

Expand All @@ -221,11 +214,16 @@ private static IEnumerable<Diagnostic> GetDiagnosticsForMembers(ICollection<ISym
}
}

diagnostics.Add(CreateS1144Diagnostic(syntaxForLocation, unused.Symbol));
if (unused.Symbol.IsConstructor() && !syntaxForLocation.GetModifiers().Any(SyntaxKind.PrivateKeyword))
{
context.ReportIssue(RuleS1144ForPublicCtor, syntaxForLocation, accessibility, unused.Symbol.ContainingType.Name);
}
else
{
context.ReportIssue(RuleS1144, GetIdentifierLocation(syntaxForLocation), accessibility, unused.Symbol.GetClassification(), GetMemberName(unused.Symbol));
}
}

return diagnostics;

static IEnumerable<VariableDeclaratorSyntax> GetSiblingDeclarators(SyntaxNode variableDeclarator) =>
variableDeclarator.Parent.Parent switch
{
Expand All @@ -234,38 +232,30 @@ static IEnumerable<VariableDeclaratorSyntax> GetSiblingDeclarators(SyntaxNode va
_ => Enumerable.Empty<VariableDeclaratorSyntax>(),
};

Diagnostic CreateS1144Diagnostic(SyntaxNode syntaxNode, ISymbol symbol) =>
symbol.IsConstructor() && !syntaxNode.GetModifiers().Any(SyntaxKind.PrivateKeyword)
? Diagnostic.Create(RuleS1144ForPublicCtor, syntaxNode.GetLocation(), accessibility, symbol.ContainingType.Name)
: Diagnostic.Create(RuleS1144, GetIdentifierLocation(syntaxNode), accessibility, symbol.GetClassification(), GetMemberName(symbol));

static Location GetIdentifierLocation(SyntaxNode syntaxNode) =>
syntaxNode.GetIdentifier() is { } identifier
? identifier.GetLocation()
: syntaxNode.GetLocation();
}

private static Diagnostic GetDiagnosticsForProperty(IPropertySymbol property, IReadOnlyDictionary<IPropertySymbol, AccessorAccess> propertyAccessorAccess)
private static void ReportProperty<TContext>(SonarCompilationReportingContextBase<TContext> context,
IPropertySymbol property,
IReadOnlyDictionary<IPropertySymbol, AccessorAccess> propertyAccessorAccess)
{
var access = propertyAccessorAccess[property];
if (access == AccessorAccess.Get
&& property.SetMethod is { }
&& property.SetMethod is not null
&& GetAccessorSyntax(property.SetMethod) is { } setter)
{
return Diagnostic.Create(RuleS1144, setter.Keyword.GetLocation(), SyntaxConstants.Private, "set accessor in property", property.Name);
context.ReportIssue(RuleS1144, setter.Keyword.GetLocation(), SyntaxConstants.Private, "set accessor in property", property.Name);
}
else if (access == AccessorAccess.Set
&& property.GetMethod is { }
&& GetAccessorSyntax(property.GetMethod) is { } getter
&& getter.HasBodyOrExpressionBody())
&& property.GetMethod is not null
&& GetAccessorSyntax(property.GetMethod) is { } getter
&& getter.HasBodyOrExpressionBody())
{
return Diagnostic.Create(RuleS1144, getter.Keyword.GetLocation(), SyntaxConstants.Private, "get accessor in property", property.Name);
context.ReportIssue(RuleS1144, getter.Keyword.GetLocation(), SyntaxConstants.Private, "get accessor in property", property.Name);
}
else
{
return null;
}

static AccessorDeclarationSyntax GetAccessorSyntax(ISymbol symbol) =>
symbol?.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax() as AccessorDeclarationSyntax;
}
Expand Down Expand Up @@ -534,7 +524,7 @@ private static bool IsRemovable(ISymbol symbol) =>
private static bool HasAttributes(ISymbol symbol)
{
IEnumerable<AttributeData> attributes = symbol.GetAttributes();
if (symbol is IMethodSymbol { MethodKind: MethodKind.PropertyGet or MethodKind.PropertySet} method
if (symbol is IMethodSymbol { MethodKind: MethodKind.PropertyGet or MethodKind.PropertySet } method
&& method.AssociatedSymbol is { } property)
{
attributes = attributes.Union(property.GetAttributes());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,12 @@ public static void RegisterSemanticModelAction(this SonarParametrizedAnalysisCon
public static void RegisterCodeBlockStartAction(this SonarAnalysisContext context, Action<SonarCodeBlockStartAnalysisContext<SyntaxKind>> action) =>
context.RegisterCodeBlockStartAction(VisualBasicGeneratedCodeRecognizer.Instance, action);

public static void ReportIssue(this SonarCompilationReportingContext context, DiagnosticDescriptor rule, Location location, params string[] messageArgs) =>
context.ReportIssue(VisualBasicGeneratedCodeRecognizer.Instance, rule, location, messageArgs);

public static void ReportIssue(this SonarSymbolReportingContext context, DiagnosticDescriptor rule, SyntaxNode locationSyntax, params string[] messageArgs) =>
public static void ReportIssue<TContext>(this SonarCompilationReportingContextBase<TContext> context, DiagnosticDescriptor rule, SyntaxNode locationSyntax, params string[] messageArgs) =>
context.ReportIssue(VisualBasicGeneratedCodeRecognizer.Instance, rule, locationSyntax, messageArgs);

public static void ReportIssue(this SonarSymbolReportingContext context, DiagnosticDescriptor rule, SyntaxToken locationToken, params string[] messageArgs) =>
public static void ReportIssue<TContext>(this SonarCompilationReportingContextBase<TContext> context, DiagnosticDescriptor rule, SyntaxToken locationToken, params string[] messageArgs) =>
context.ReportIssue(VisualBasicGeneratedCodeRecognizer.Instance, rule, locationToken, messageArgs);

public static void ReportIssue(this SonarSymbolReportingContext context, DiagnosticDescriptor rule, Location location, params string[] messageArgs) =>
public static void ReportIssue<TContext>(this SonarCompilationReportingContextBase<TContext> context, DiagnosticDescriptor rule, Location location, params string[] messageArgs) =>
context.ReportIssue(VisualBasicGeneratedCodeRecognizer.Instance, rule, location, messageArgs);
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ protected override void Initialize(SonarAnalysisContext context)
{
if (!c.Compilation.VB().Options.OptionExplicit)
{
c.ReportIssue(Rule, null, string.Format(AssemblyMessageFormat, c.Compilation.AssemblyName));
c.ReportIssue(Rule, (Location)null, string.Format(AssemblyMessageFormat, c.Compilation.AssemblyName));
}
}));
}
Expand Down
Loading

0 comments on commit fad8aef

Please sign in to comment.