Skip to content

Commit 0bab00a

Browse files
authored
Update DetectPreviewFeatureAnalyzer for runtime async (#50937)
1 parent 171ebf1 commit 0bab00a

File tree

7 files changed

+172
-26
lines changed

7 files changed

+172
-26
lines changed

src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.CSharp.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/CSharpDetectPreviewFeatureAnalyzer.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,30 @@
22

33
using System.Collections.Immutable;
44
using System.Diagnostics.CodeAnalysis;
5+
using Analyzer.Utilities.Lightup;
56
using Microsoft.CodeAnalysis;
7+
using Microsoft.CodeAnalysis.CSharp;
68
using Microsoft.CodeAnalysis.CSharp.Syntax;
79
using Microsoft.CodeAnalysis.Diagnostics;
10+
using Microsoft.CodeAnalysis.Operations;
811
using Microsoft.NetCore.Analyzers.Runtime;
912

1013
namespace Microsoft.NetCore.CSharp.Analyzers.Runtime
1114
{
1215
[DiagnosticAnalyzer(LanguageNames.CSharp)]
1316
public class CSharpDetectPreviewFeatureAnalyzer : DetectPreviewFeatureAnalyzer
1417
{
18+
protected override ISymbol? SymbolFromAwaitOperation(IAwaitOperation operation)
19+
{
20+
if (operation.Syntax is not AwaitExpressionSyntax awaitSyntax)
21+
{
22+
return null;
23+
}
24+
25+
var awaitableInfo = operation.SemanticModel.GetAwaitExpressionInfo(awaitSyntax);
26+
return awaitableInfo.RuntimeAwaitMethod;
27+
}
28+
1529
protected override SyntaxNode? GetPreviewSyntaxNodeForFieldsOrEvents(ISymbol fieldOrEventSymbol, ISymbol previewSymbol)
1630
{
1731
ImmutableArray<SyntaxReference> fieldOrEventReferences = fieldOrEventSymbol.DeclaringSyntaxReferences;

src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureAnalyzer.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,8 @@ public override void Initialize(AnalysisContext context)
269269
OperationKind.ArrayCreation,
270270
OperationKind.CatchClause,
271271
OperationKind.TypeOf,
272-
OperationKind.EventAssignment
272+
OperationKind.EventAssignment,
273+
OperationKind.Await
273274
);
274275

275276
// Handle preview symbol definitions
@@ -809,7 +810,7 @@ private bool OperationUsesPreviewFeatures(OperationAnalysisContext context,
809810
return false;
810811
}
811812

812-
private static ISymbol? GetOperationSymbol(IOperation operation)
813+
private ISymbol? GetOperationSymbol(IOperation operation)
813814
=> operation switch
814815
{
815816
IInvocationOperation iOperation => iOperation.TargetMethod,
@@ -824,6 +825,7 @@ private bool OperationUsesPreviewFeatures(OperationAnalysisContext context,
824825
ICatchClauseOperation catchClauseOperation => catchClauseOperation.ExceptionType,
825826
ITypeOfOperation typeOfOperation => typeOfOperation.TypeOperand,
826827
IEventAssignmentOperation eventAssignment => GetOperationSymbol(eventAssignment.EventReference),
828+
IAwaitOperation awaitOperation => SymbolFromAwaitOperation(awaitOperation),
827829
_ => null,
828830
};
829831

@@ -838,6 +840,8 @@ private bool OperationUsesPreviewFeatures(OperationAnalysisContext context,
838840
return ret;
839841
}
840842

843+
protected abstract ISymbol? SymbolFromAwaitOperation(IAwaitOperation operation);
844+
841845
private bool TypeParametersHavePreviewAttribute(ISymbol namedTypeSymbolOrMethodSymbol,
842846
ImmutableArray<ITypeParameterSymbol> typeParameters,
843847
ConcurrentDictionary<ISymbol, (bool isPreview, string? message, string? url)> requiresPreviewFeaturesSymbols,

src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.VisualBasic.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/BasicDetectPreviewFeatureAnalyzer.vb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
Imports Microsoft.CodeAnalysis
44
Imports Microsoft.CodeAnalysis.Diagnostics
5+
Imports Microsoft.CodeAnalysis.Operations
56
Imports Microsoft.NetCore.Analyzers.Runtime
67
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
78

@@ -16,6 +17,10 @@ Namespace Microsoft.NetCore.VisualBasic.Analyzers.Runtime
1617
Return identifier.ValueText.Equals(previewInterfaceSymbol.Name, StringComparison.OrdinalIgnoreCase)
1718
End Function
1819

20+
Protected Overrides Function SymbolFromAwaitOperation(operation As IAwaitOperation) As ISymbol
21+
Return Nothing
22+
End Function
23+
1924
Private Shared Function GetElementTypeForNullableAndArrayTypeNodes(parameterType As TypeSyntax) As TypeSyntax
2025
Dim ret As TypeSyntax = parameterType
2126
Dim loopVariable = TryCast(parameterType, NullableTypeSyntax)
@@ -334,4 +339,4 @@ Namespace Microsoft.NetCore.VisualBasic.Analyzers.Runtime
334339
End Function
335340
End Class
336341

337-
End Namespace
342+
End Namespace

src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler.CSharp/Analyzer.CSharp.Utilities.projitems

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<ItemGroup>
1111
<Compile Include="$(MSBuildThisFileDirectory)Extensions\SyntaxGeneratorExtensions.cs" />
1212
<Compile Include="$(MSBuildThisFileDirectory)Extensions\SyntaxNodeExtensions.cs" />
13+
<Compile Include="$(MSBuildThisFileDirectory)Lightup\AwaitExpressionInfoWrapper.cs" />
1314
<Compile Include="$(MSBuildThisFileDirectory)Lightup\SyntaxKindEx.cs" />
1415
</ItemGroup>
15-
</Project>
16+
</Project>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
2+
3+
using Microsoft.CodeAnalysis;
4+
using Microsoft.CodeAnalysis.CSharp;
5+
6+
namespace Analyzer.Utilities.Lightup
7+
{
8+
internal static class AwaitExpressionInfoWrapper
9+
{
10+
private static Func<AwaitExpressionInfo, IMethodSymbol?>? s_RuntimeAwaitMethodAccessor;
11+
12+
extension(AwaitExpressionInfo info)
13+
{
14+
public IMethodSymbol? RuntimeAwaitMethod
15+
{
16+
get
17+
{
18+
LazyInitializer.EnsureInitialized(ref s_RuntimeAwaitMethodAccessor, () =>
19+
{
20+
return LightupHelpers.CreatePropertyAccessor<AwaitExpressionInfo, IMethodSymbol?>(
21+
typeof(AwaitExpressionInfo),
22+
"info",
23+
"RuntimeAwaitMethod",
24+
fallbackResult: null);
25+
});
26+
27+
RoslynDebug.Assert(s_RuntimeAwaitMethodAccessor is not null);
28+
return s_RuntimeAwaitMethodAccessor(info);
29+
}
30+
}
31+
}
32+
}
33+
}

src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler/Lightup/LightupHelpers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ internal static Func<TSymbol, TProperty> CreateSymbolPropertyAccessor<TSymbol, T
5353
where TSymbol : ISymbol
5454
=> CreatePropertyAccessor<TSymbol, TProperty>(type, "symbol", propertyName, fallbackResult);
5555

56-
private static Func<T, TProperty> CreatePropertyAccessor<T, TProperty>(Type? type, string parameterName, string propertyName, TProperty fallbackResult)
56+
internal static Func<T, TProperty> CreatePropertyAccessor<T, TProperty>(Type? type, string parameterName, string propertyName, TProperty fallbackResult)
5757
{
5858
if (!TryGetProperty<T, TProperty>(type, propertyName, out var property))
5959
{

0 commit comments

Comments
 (0)