Skip to content

Commit f23df4e

Browse files
authored
Update the report location to be on method name and arguments instead of the InvocationExpression (#790)
1 parent 0ad62c6 commit f23df4e

File tree

8 files changed

+66
-18
lines changed

8 files changed

+66
-18
lines changed

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"sdk": {
3-
"version": "9.0.101",
3+
"version": "9.0.201",
44
"rollForward": "latestPatch"
55
}
66
}

src/Meziantou.Analyzer/Internals/ContextExtensions.cs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
using System.Collections.Immutable;
1+
using System;
2+
using System.Collections.Immutable;
23
using System.Linq;
34
using Meziantou.Analyzer.Internals;
45
using Microsoft.CodeAnalysis;
56
using Microsoft.CodeAnalysis.CSharp.Syntax;
67
using Microsoft.CodeAnalysis.Operations;
8+
using Microsoft.CodeAnalysis.Text;
79

810
namespace Meziantou.Analyzer.Internals;
911

@@ -156,14 +158,39 @@ public static void ReportDiagnostic(this DiagnosticReporter context, DiagnosticD
156158

157159
public static void ReportDiagnostic(this DiagnosticReporter context, DiagnosticDescriptor descriptor, ImmutableDictionary<string, string?>? properties, IInvocationOperation operation, DiagnosticInvocationReportOptions options, params string?[]? messageArgs)
158160
{
161+
TextSpan? span = null;
162+
159163
if (options.HasFlag(DiagnosticInvocationReportOptions.ReportOnMember) &&
160164
operation.Syntax.ChildNodes().FirstOrDefault() is MemberAccessExpressionSyntax memberAccessExpression)
161165
{
162-
context.ReportDiagnostic(Diagnostic.Create(descriptor, memberAccessExpression.Name.GetLocation(), properties, messageArgs));
166+
SetSpan(memberAccessExpression.Name.Span);
167+
}
168+
169+
if (options.HasFlag(DiagnosticInvocationReportOptions.ReportOnArguments) &&
170+
operation.Syntax is InvocationExpressionSyntax invocationExpression)
171+
{
172+
SetSpan(invocationExpression.ArgumentList.Span);
173+
}
174+
175+
if (span is not null)
176+
{
177+
context.ReportDiagnostic(Diagnostic.Create(descriptor, Location.Create(operation.Syntax.SyntaxTree, span.Value), properties, messageArgs));
163178
return;
164179
}
165180

166181
context.ReportDiagnostic(descriptor, properties, operation, messageArgs);
182+
183+
void SetSpan(TextSpan newSpan)
184+
{
185+
if (span is null)
186+
{
187+
span = newSpan;
188+
}
189+
else
190+
{
191+
span = TextSpan.FromBounds(Math.Min(span.Value.Start, newSpan.Start), Math.Max(span.Value.End, newSpan.End));
192+
}
193+
}
167194
}
168195

169196
public static void ReportDiagnostic(this DiagnosticReporter context, DiagnosticDescriptor descriptor, AttributeData attribute, params string?[]? messageArgs)

src/Meziantou.Analyzer/Internals/ContextExtensions.g.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ public static void ReportDiagnostic(this SyntaxNodeAnalysisContext context, Diag
6363
public static void ReportDiagnostic(this SyntaxNodeAnalysisContext context, DiagnosticDescriptor descriptor, ImmutableDictionary<string, string?>? properties, SyntaxReference syntaxReference, params string?[]? messageArgs)
6464
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties, syntaxReference, messageArgs);
6565

66+
public static void ReportDiagnostic(this SyntaxNodeAnalysisContext context, DiagnosticDescriptor descriptor, IInvocationOperation operation, DiagnosticInvocationReportOptions options, params string?[] messageArgs)
67+
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties: null, operation, options, messageArgs);
68+
6669
public static void ReportDiagnostic(this SyntaxNodeAnalysisContext context, DiagnosticDescriptor descriptor, ImmutableDictionary<string, string?>? properties, IInvocationOperation operation, DiagnosticInvocationReportOptions options, params string?[] messageArgs)
6770
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties, operation, options, messageArgs);
6871

@@ -134,6 +137,9 @@ public static void ReportDiagnostic(this SymbolAnalysisContext context, Diagnost
134137
public static void ReportDiagnostic(this SymbolAnalysisContext context, DiagnosticDescriptor descriptor, ImmutableDictionary<string, string?>? properties, SyntaxReference syntaxReference, params string?[]? messageArgs)
135138
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties, syntaxReference, messageArgs);
136139

140+
public static void ReportDiagnostic(this SymbolAnalysisContext context, DiagnosticDescriptor descriptor, IInvocationOperation operation, DiagnosticInvocationReportOptions options, params string?[] messageArgs)
141+
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties: null, operation, options, messageArgs);
142+
137143
public static void ReportDiagnostic(this SymbolAnalysisContext context, DiagnosticDescriptor descriptor, ImmutableDictionary<string, string?>? properties, IInvocationOperation operation, DiagnosticInvocationReportOptions options, params string?[] messageArgs)
138144
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties, operation, options, messageArgs);
139145

@@ -205,6 +211,9 @@ public static void ReportDiagnostic(this OperationAnalysisContext context, Diagn
205211
public static void ReportDiagnostic(this OperationAnalysisContext context, DiagnosticDescriptor descriptor, ImmutableDictionary<string, string?>? properties, SyntaxReference syntaxReference, params string?[]? messageArgs)
206212
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties, syntaxReference, messageArgs);
207213

214+
public static void ReportDiagnostic(this OperationAnalysisContext context, DiagnosticDescriptor descriptor, IInvocationOperation operation, DiagnosticInvocationReportOptions options, params string?[] messageArgs)
215+
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties: null, operation, options, messageArgs);
216+
208217
public static void ReportDiagnostic(this OperationAnalysisContext context, DiagnosticDescriptor descriptor, ImmutableDictionary<string, string?>? properties, IInvocationOperation operation, DiagnosticInvocationReportOptions options, params string?[] messageArgs)
209218
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties, operation, options, messageArgs);
210219

@@ -276,6 +285,9 @@ public static void ReportDiagnostic(this OperationBlockAnalysisContext context,
276285
public static void ReportDiagnostic(this OperationBlockAnalysisContext context, DiagnosticDescriptor descriptor, ImmutableDictionary<string, string?>? properties, SyntaxReference syntaxReference, params string?[]? messageArgs)
277286
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties, syntaxReference, messageArgs);
278287

288+
public static void ReportDiagnostic(this OperationBlockAnalysisContext context, DiagnosticDescriptor descriptor, IInvocationOperation operation, DiagnosticInvocationReportOptions options, params string?[] messageArgs)
289+
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties: null, operation, options, messageArgs);
290+
279291
public static void ReportDiagnostic(this OperationBlockAnalysisContext context, DiagnosticDescriptor descriptor, ImmutableDictionary<string, string?>? properties, IInvocationOperation operation, DiagnosticInvocationReportOptions options, params string?[] messageArgs)
280292
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties, operation, options, messageArgs);
281293

@@ -347,6 +359,9 @@ public static void ReportDiagnostic(this CompilationAnalysisContext context, Dia
347359
public static void ReportDiagnostic(this CompilationAnalysisContext context, DiagnosticDescriptor descriptor, ImmutableDictionary<string, string?>? properties, SyntaxReference syntaxReference, params string?[]? messageArgs)
348360
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties, syntaxReference, messageArgs);
349361

362+
public static void ReportDiagnostic(this CompilationAnalysisContext context, DiagnosticDescriptor descriptor, IInvocationOperation operation, DiagnosticInvocationReportOptions options, params string?[] messageArgs)
363+
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties: null, operation, options, messageArgs);
364+
350365
public static void ReportDiagnostic(this CompilationAnalysisContext context, DiagnosticDescriptor descriptor, ImmutableDictionary<string, string?>? properties, IInvocationOperation operation, DiagnosticInvocationReportOptions options, params string?[] messageArgs)
351366
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties, operation, options, messageArgs);
352367

src/Meziantou.Analyzer/Internals/ContextExtensions.tt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ internal static partial class ContextExtensions
6868
public static void ReportDiagnostic(this <#= type #> context, DiagnosticDescriptor descriptor, ImmutableDictionary<string, string?>? properties, SyntaxReference syntaxReference, params string?[]? messageArgs)
6969
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties, syntaxReference, messageArgs);
7070

71+
public static void ReportDiagnostic(this <#= type #> context, DiagnosticDescriptor descriptor, IInvocationOperation operation, DiagnosticInvocationReportOptions options, params string?[] messageArgs)
72+
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties: null, operation, options, messageArgs);
73+
7174
public static void ReportDiagnostic(this <#= type #> context, DiagnosticDescriptor descriptor, ImmutableDictionary<string, string?>? properties, IInvocationOperation operation, DiagnosticInvocationReportOptions options, params string?[] messageArgs)
7275
=> ReportDiagnostic(new DiagnosticReporter(context), descriptor, properties, operation, options, messageArgs);
7376

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22

33
namespace Meziantou.Analyzer.Internals;
44

@@ -7,4 +7,5 @@ public enum DiagnosticInvocationReportOptions
77
{
88
None = 0x0,
99
ReportOnMember = 0x1,
10+
ReportOnArguments = 0x2,
1011
}

src/Meziantou.Analyzer/Internals/ObjectPool.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#pragma warning disable MA0048 // File name must match type name
1+
#pragma warning disable MA0048 // File name must match type name
22
#pragma warning disable RS1035 // Do not use APIs banned for analyzers
33
using System.Collections.Concurrent;
44
using System.Threading;
@@ -56,14 +56,14 @@ internal interface IPooledObjectPolicy<T> where T : notnull
5656
/// Create a <typeparamref name="T"/>.
5757
/// </summary>
5858
/// <returns>The <typeparamref name="T"/> which was created.</returns>
59-
T Create();
59+
public T Create();
6060

6161
/// <summary>
6262
/// Runs some processing when an object was returned to the pool. Can be used to reset the state of an object and indicate if the object should be returned to the pool.
6363
/// </summary>
6464
/// <param name="obj">The object to return to the pool.</param>
6565
/// <returns><see langword="true" /> if the object should be returned to the pool. <see langword="false" /> if it's not possible/desirable for the pool to keep the object.</returns>
66-
bool Return(T obj);
66+
public bool Return(T obj);
6767
}
6868

6969
/// <summary>
@@ -249,7 +249,7 @@ internal interface IResettable
249249
/// <remarks>
250250
/// In general, this method is not expected to be thread-safe.
251251
/// </remarks>
252-
bool TryReset();
252+
public bool TryReset();
253253
}
254254

255255
internal sealed class DisposableObjectPool<T> : DefaultObjectPool<T>, IDisposable where T : class

src/Meziantou.Analyzer/Rules/UseStringComparerAnalyzer.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ namespace Meziantou.Analyzer.Rules;
1414
[DiagnosticAnalyzer(LanguageNames.CSharp)]
1515
public sealed class UseStringComparerAnalyzer : DiagnosticAnalyzer
1616
{
17+
private const DiagnosticInvocationReportOptions DefaultDiagnosticInvocationReportOptions = DiagnosticInvocationReportOptions.ReportOnMember | DiagnosticInvocationReportOptions.ReportOnArguments;
18+
1719
private static readonly string[] EnumerableMethods =
1820
[
1921
"Contains",
@@ -130,7 +132,7 @@ public void AnalyzeInvocation(OperationAnalysisContext ctx)
130132
if ((EqualityComparerStringType is not null && _overloadFinder.HasOverloadWithAdditionalParameterOfType(method, operation, EqualityComparerStringType)) ||
131133
(ComparerStringType is not null && _overloadFinder.HasOverloadWithAdditionalParameterOfType(method, operation, ComparerStringType)))
132134
{
133-
ctx.ReportDiagnostic(Rule, operation);
135+
ctx.ReportDiagnostic(Rule, operation, DefaultDiagnosticInvocationReportOptions);
134136
return;
135137
}
136138

@@ -164,7 +166,7 @@ public void AnalyzeInvocation(OperationAnalysisContext ctx)
164166

165167
if (!HasEqualityComparerArgument(operation.Arguments))
166168
{
167-
ctx.ReportDiagnostic(Rule, operation);
169+
ctx.ReportDiagnostic(Rule, operation, DefaultDiagnosticInvocationReportOptions);
168170
}
169171
}
170172
}

tests/Meziantou.Analyzer.Test/Rules/UseStringComparerAnalyzerTests.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ class TypeName
183183
public void Test()
184184
{
185185
System.Collections.Generic.IEnumerable<string> obj = null;
186-
[||]obj.Contains("""");
186+
obj.[|Contains("""")|];
187187
}
188188
}";
189189
const string CodeFix = @"using System.Linq;
@@ -210,7 +210,7 @@ class TypeName
210210
public void Test()
211211
{
212212
System.Collections.Generic.IEnumerable<string> obj = null;
213-
[||]obj.ToDictionary(p => p);
213+
obj.[|ToDictionary(p => p)|];
214214
}
215215
}";
216216
const string CodeFix = @"using System.Linq;
@@ -237,7 +237,7 @@ class TypeName
237237
public void Test()
238238
{
239239
System.Collections.Generic.IEnumerable<string> obj = null;
240-
[||]obj.Order();
240+
obj.[|Order()|];
241241
}
242242
}";
243243
const string CodeFix = @"using System.Linq;
@@ -265,7 +265,7 @@ class TypeName
265265
public void Test()
266266
{
267267
System.Collections.Generic.IEnumerable<string> obj = null;
268-
[||]obj.OrderBy(p => p);
268+
obj.[|OrderBy(p => p)|];
269269
}
270270
}";
271271
const string CodeFix = @"using System.Linq;
@@ -292,7 +292,7 @@ class TypeName
292292
public void Test()
293293
{
294294
System.Collections.Generic.IEnumerable<string> obj = null;
295-
[||]obj.OrderByDescending(p => p);
295+
obj.[|OrderByDescending(p => p)|];
296296
}
297297
}";
298298
const string CodeFix = @"using System.Linq;
@@ -319,7 +319,7 @@ class TypeName
319319
public void Test()
320320
{
321321
System.Collections.Generic.IEnumerable<string> obj = null;
322-
[||]obj.OrderBy(p => p, System.StringComparer.Ordinal).ThenBy(p => p);
322+
obj.OrderBy(p => p, System.StringComparer.Ordinal).[|ThenBy(p => p)|];
323323
}
324324
}";
325325
const string CodeFix = @"using System.Linq;
@@ -346,7 +346,7 @@ class TypeName
346346
public void Test()
347347
{
348348
System.Collections.Generic.IEnumerable<string> obj = null;
349-
[||]obj.OrderBy(p => p, System.StringComparer.Ordinal).ThenByDescending(p => p);
349+
obj.OrderBy(p => p, System.StringComparer.Ordinal).[|ThenByDescending(p => p)|];
350350
}
351351
}";
352352
const string CodeFix = @"using System.Linq;
@@ -387,7 +387,7 @@ class Usage
387387
void A()
388388
{
389389
var a = new TypeName();
390-
[||]a.Test();
390+
a.[|Test()|];
391391
}
392392
}
393393
";

0 commit comments

Comments
 (0)