Skip to content

Commit bb4069e

Browse files
committed
CA1024: Do not report on tasks return types
1 parent 9a179e3 commit bb4069e

File tree

2 files changed

+88
-33
lines changed

2 files changed

+88
-33
lines changed

src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/UsePropertiesWhereAppropriate.cs

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -42,47 +42,63 @@ public override void Initialize(AnalysisContext analysisContext)
4242
analysisContext.EnableConcurrentExecution();
4343
analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
4444

45-
analysisContext.RegisterOperationBlockStartAction(context =>
45+
analysisContext.RegisterCompilationStartAction(context =>
4646
{
47+
var taskTypesBuilder = ImmutableHashSet.CreateBuilder<ITypeSymbol>();
4748

48-
if (!(context.OwningSymbol is IMethodSymbol methodSymbol) ||
49-
methodSymbol.ReturnsVoid ||
50-
methodSymbol.ReturnType.Kind == SymbolKind.ArrayType ||
51-
!methodSymbol.Parameters.IsEmpty ||
52-
!methodSymbol.MatchesConfiguredVisibility(context.Options, Rule, context.Compilation, context.CancellationToken) ||
53-
methodSymbol.IsAccessorMethod() ||
54-
!IsPropertyLikeName(methodSymbol.Name))
55-
{
56-
return;
57-
}
49+
taskTypesBuilder.AddIfNotNull(
50+
context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask));
51+
taskTypesBuilder.AddIfNotNull(
52+
context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask1));
53+
taskTypesBuilder.AddIfNotNull(
54+
context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksValueTask));
55+
taskTypesBuilder.AddIfNotNull(
56+
context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksValueTask1));
5857

59-
// A few additional checks to reduce the noise for this diagnostic:
60-
// Ensure that the method is non-generic, non-virtual/override, has no overloads and doesn't have special names: 'GetHashCode' or 'GetEnumerator'.
61-
// Also avoid generating this diagnostic if the method body has any invocation expressions.
62-
// Also avoid implicit interface implementation (explicit are handled through the member accessibility)
63-
if (methodSymbol.IsGenericMethod ||
64-
methodSymbol.IsVirtual ||
65-
methodSymbol.IsOverride ||
66-
methodSymbol.ContainingType.GetMembers(methodSymbol.Name).Length > 1 ||
67-
methodSymbol.Name == GetHashCodeName ||
68-
methodSymbol.Name == GetEnumeratorName ||
69-
methodSymbol.IsImplementationOfAnyImplicitInterfaceMember())
70-
{
71-
return;
72-
}
58+
var taskTypes = taskTypesBuilder.ToImmutable();
7359

74-
bool hasInvocations = false;
75-
context.RegisterOperationAction(operationContext =>
60+
context.RegisterOperationBlockStartAction(context =>
7661
{
77-
hasInvocations = true;
78-
}, OperationKind.Invocation);
62+
if (!(context.OwningSymbol is IMethodSymbol methodSymbol) ||
63+
methodSymbol.ReturnsVoid ||
64+
methodSymbol.ReturnType.Kind == SymbolKind.ArrayType ||
65+
!methodSymbol.Parameters.IsEmpty ||
66+
!methodSymbol.MatchesConfiguredVisibility(context.Options, Rule, context.Compilation, context.CancellationToken) ||
67+
methodSymbol.IsAccessorMethod() ||
68+
!IsPropertyLikeName(methodSymbol.Name))
69+
{
70+
return;
71+
}
7972

80-
context.RegisterOperationBlockEndAction(endContext =>
81-
{
82-
if (!hasInvocations)
73+
// A few additional checks to reduce the noise for this diagnostic:
74+
// Ensure that the method is non-generic, non-virtual/override, has no overloads and doesn't have special names: 'GetHashCode' or 'GetEnumerator'.
75+
// Also avoid generating this diagnostic if the method body has any invocation expressions.
76+
// Also avoid implicit interface implementation (explicit are handled through the member accessibility)
77+
if (methodSymbol.IsGenericMethod ||
78+
methodSymbol.IsVirtual ||
79+
methodSymbol.IsOverride ||
80+
methodSymbol.Name == GetHashCodeName ||
81+
methodSymbol.Name == GetEnumeratorName ||
82+
methodSymbol.ContainingType.GetMembers(methodSymbol.Name).Length > 1 ||
83+
taskTypes.Contains(methodSymbol.ReturnType.OriginalDefinition) ||
84+
methodSymbol.IsImplementationOfAnyImplicitInterfaceMember())
8385
{
84-
endContext.ReportDiagnostic(endContext.OwningSymbol.CreateDiagnostic(Rule));
86+
return;
8587
}
88+
89+
bool hasInvocations = false;
90+
context.RegisterOperationAction(operationContext =>
91+
{
92+
hasInvocations = true;
93+
}, OperationKind.Invocation);
94+
95+
context.RegisterOperationBlockEndAction(endContext =>
96+
{
97+
if (!hasInvocations)
98+
{
99+
endContext.ReportDiagnostic(endContext.OwningSymbol.CreateDiagnostic(Rule));
100+
}
101+
});
86102
});
87103
});
88104
}

src/NetAnalyzers/UnitTests/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/UsePropertiesWhereAppropriateTests.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,45 @@ public object GetContent()
439439
");
440440
}
441441

442+
[Fact, WorkItem(3877, "https://github.com/dotnet/roslyn-analyzers/issues/3877")]
443+
public async Task CA1024_ReturnsTask_NoDiagnostic()
444+
{
445+
await VerifyCS.VerifyAnalyzerAsync(@"
446+
using System.Threading.Tasks;
447+
448+
public class Something
449+
{
450+
public Task GetTask() => default(Task);
451+
public Task<int> GetGenericTask() => default(Task<int>);
452+
453+
public ValueTask GetValueTask() => default(ValueTask);
454+
public ValueTask<int> GetGenericValueTask() => default(ValueTask<int>);
455+
}
456+
");
457+
458+
await VerifyVB.VerifyAnalyzerAsync(@"
459+
Imports System.Threading.Tasks
460+
461+
Public Class Something
462+
Public Function GetTask() As Task
463+
Return Nothing
464+
End Function
465+
466+
Public Function GetGenericTask() As Task(Of Integer)
467+
Return Nothing
468+
End Function
469+
470+
Public Function GetValueTask() As ValueTask
471+
Return Nothing
472+
End Function
473+
474+
Public Function GetGenericValueTask() As ValueTask(Of Integer)
475+
Return Nothing
476+
End Function
477+
End Class
478+
");
479+
}
480+
442481
private static DiagnosticResult GetCA1024CSharpResultAt(int line, int column, string methodName)
443482
=> VerifyCS.Diagnostic()
444483
.WithLocation(line, column)

0 commit comments

Comments
 (0)