Skip to content

Commit d04c6cd

Browse files
authored
Merge pull request #3229 from sharwell/operation-sa1142
Use IOperation APIs for SA1142 when supported
2 parents 7519395 + 26b47c4 commit d04c6cd

File tree

6 files changed

+202
-1
lines changed

6 files changed

+202
-1
lines changed

StyleCop.Analyzers/StyleCop.Analyzers/Helpers/LanguageFeatureHelpers.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ internal static bool SupportsTuples(this SyntaxNodeAnalysisContext context)
2323
return (csharpParseOptions != null) && (csharpParseOptions.LanguageVersion >= LanguageVersionEx.CSharp7);
2424
}
2525

26+
/// <summary>
27+
/// Checks if the tuple language feature is supported.
28+
/// </summary>
29+
/// <param name="context">The analysis context that will be checked.</param>
30+
/// <returns>True if tuples are supported by the compiler.</returns>
31+
internal static bool SupportsTuples(this OperationAnalysisContext context)
32+
{
33+
var csharpParseOptions = context.Operation.Syntax.SyntaxTree.Options as CSharpParseOptions;
34+
return (csharpParseOptions != null) && (csharpParseOptions.LanguageVersion >= LanguageVersionEx.CSharp7);
35+
}
36+
2637
/// <summary>
2738
/// Checks if the inferred tuple element names language feature is supported.
2839
/// </summary>
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Lightup
5+
{
6+
using System;
7+
using Microsoft.CodeAnalysis;
8+
9+
internal readonly struct IFieldReferenceOperationWrapper : IOperationWrapper
10+
{
11+
internal const string WrappedTypeName = "Microsoft.CodeAnalysis.Operations.IFieldReferenceOperation";
12+
private static readonly Type WrappedType;
13+
14+
private static readonly Func<IOperation, IFieldSymbol> FieldAccessor;
15+
private static readonly Func<IOperation, bool> IsDeclarationAccessor;
16+
17+
private readonly IOperation operation;
18+
19+
static IFieldReferenceOperationWrapper()
20+
{
21+
WrappedType = WrapperHelper.GetWrappedType(typeof(IFieldReferenceOperationWrapper));
22+
FieldAccessor = LightupHelpers.CreateOperationPropertyAccessor<IOperation, IFieldSymbol>(WrappedType, nameof(Field));
23+
IsDeclarationAccessor = LightupHelpers.CreateOperationPropertyAccessor<IOperation, bool>(WrappedType, nameof(IsDeclaration));
24+
}
25+
26+
private IFieldReferenceOperationWrapper(IOperation operation)
27+
{
28+
this.operation = operation;
29+
}
30+
31+
public IOperation WrappedOperation => this.operation;
32+
33+
public ITypeSymbol Type => this.WrappedOperation.Type;
34+
35+
public IFieldSymbol Field
36+
{
37+
get
38+
{
39+
return FieldAccessor(this.WrappedOperation);
40+
}
41+
}
42+
43+
public bool IsDeclaration
44+
{
45+
get
46+
{
47+
return IsDeclarationAccessor(this.WrappedOperation);
48+
}
49+
}
50+
51+
public IOperation Instance => ((IMemberReferenceOperationWrapper)this).Instance;
52+
53+
public ISymbol Member => ((IMemberReferenceOperationWrapper)this).Member;
54+
55+
public static explicit operator IFieldReferenceOperationWrapper(IMemberReferenceOperationWrapper wrapper)
56+
=> FromOperation(wrapper.WrappedOperation);
57+
58+
public static implicit operator IMemberReferenceOperationWrapper(IFieldReferenceOperationWrapper wrapper)
59+
=> IMemberReferenceOperationWrapper.FromUpcast(wrapper.operation);
60+
61+
public static IFieldReferenceOperationWrapper FromOperation(IOperation operation)
62+
{
63+
if (operation == null)
64+
{
65+
return default;
66+
}
67+
68+
if (!IsInstance(operation))
69+
{
70+
throw new InvalidCastException($"Cannot cast '{operation.GetType().FullName}' to '{WrappedTypeName}'");
71+
}
72+
73+
return new IFieldReferenceOperationWrapper(operation);
74+
}
75+
76+
public static bool IsInstance(IOperation operation)
77+
{
78+
return operation != null && LightupHelpers.CanWrapOperation(operation, WrappedType);
79+
}
80+
}
81+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Lightup
5+
{
6+
using System;
7+
using Microsoft.CodeAnalysis;
8+
9+
internal readonly struct IMemberReferenceOperationWrapper : IOperationWrapper
10+
{
11+
internal const string WrappedTypeName = "Microsoft.CodeAnalysis.Operations.IMemberReferenceOperation";
12+
private static readonly Type WrappedType;
13+
14+
private static readonly Func<IOperation, IOperation> InstanceAccessor;
15+
private static readonly Func<IOperation, ISymbol> MemberAccessor;
16+
17+
private readonly IOperation operation;
18+
19+
static IMemberReferenceOperationWrapper()
20+
{
21+
WrappedType = WrapperHelper.GetWrappedType(typeof(IFieldReferenceOperationWrapper));
22+
InstanceAccessor = LightupHelpers.CreateOperationPropertyAccessor<IOperation, IOperation>(WrappedType, nameof(Instance));
23+
MemberAccessor = LightupHelpers.CreateOperationPropertyAccessor<IOperation, ISymbol>(WrappedType, nameof(Member));
24+
}
25+
26+
private IMemberReferenceOperationWrapper(IOperation operation)
27+
{
28+
this.operation = operation;
29+
}
30+
31+
public IOperation WrappedOperation => this.operation;
32+
33+
public ITypeSymbol Type => this.WrappedOperation.Type;
34+
35+
public IOperation Instance
36+
{
37+
get
38+
{
39+
return InstanceAccessor(this.WrappedOperation);
40+
}
41+
}
42+
43+
public ISymbol Member
44+
{
45+
get
46+
{
47+
return MemberAccessor(this.WrappedOperation);
48+
}
49+
}
50+
51+
public static IMemberReferenceOperationWrapper FromOperation(IOperation operation)
52+
{
53+
if (operation == null)
54+
{
55+
return default;
56+
}
57+
58+
if (!IsInstance(operation))
59+
{
60+
throw new InvalidCastException($"Cannot cast '{operation.GetType().FullName}' to '{WrappedTypeName}'");
61+
}
62+
63+
return new IMemberReferenceOperationWrapper(operation);
64+
}
65+
66+
public static bool IsInstance(IOperation operation)
67+
{
68+
return operation != null && LightupHelpers.CanWrapOperation(operation, WrappedType);
69+
}
70+
71+
internal static IMemberReferenceOperationWrapper FromUpcast(IOperation operation)
72+
{
73+
return new IMemberReferenceOperationWrapper(operation);
74+
}
75+
}
76+
}

StyleCop.Analyzers/StyleCop.Analyzers/Lightup/OperationKindEx.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ namespace StyleCop.Analyzers.Lightup
77

88
internal static class OperationKindEx
99
{
10+
/// <summary>
11+
/// Indicates an <see cref="T:Microsoft.CodeAnalysis.Operations.IFieldReferenceOperation"/>.
12+
/// </summary>
13+
public const OperationKind FieldReference = (OperationKind)26;
14+
1015
/// <summary>
1116
/// Indicates an <see cref="T:Microsoft.CodeAnalysis.Operations.IObjectCreationOperation"/>.
1217
/// </summary>

StyleCop.Analyzers/StyleCop.Analyzers/Lightup/WrapperHelper.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ static WrapperHelper()
5757
builder.Add(typeof(WhenClauseSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(WhenClauseSyntaxWrapper.WrappedTypeName));
5858

5959
builder.Add(typeof(IArgumentOperationWrapper), codeAnalysisAssembly.GetType(IArgumentOperationWrapper.WrappedTypeName));
60+
builder.Add(typeof(IFieldReferenceOperationWrapper), codeAnalysisAssembly.GetType(IFieldReferenceOperationWrapper.WrappedTypeName));
61+
builder.Add(typeof(IMemberReferenceOperationWrapper), codeAnalysisAssembly.GetType(IMemberReferenceOperationWrapper.WrappedTypeName));
6062
builder.Add(typeof(IObjectCreationOperationWrapper), codeAnalysisAssembly.GetType(IObjectCreationOperationWrapper.WrappedTypeName));
6163
builder.Add(typeof(IObjectOrCollectionInitializerOperationWrapper), codeAnalysisAssembly.GetType(IObjectOrCollectionInitializerOperationWrapper.WrappedTypeName));
6264
builder.Add(typeof(ITypeParameterObjectCreationOperationWrapper), codeAnalysisAssembly.GetType(ITypeParameterObjectCreationOperationWrapper.WrappedTypeName));

StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1142ReferToTupleElementsByName.cs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ internal class SA1142ReferToTupleElementsByName : DiagnosticAnalyzer
2626
private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(ReadabilityResources.SA1142MessageFormat), ReadabilityResources.ResourceManager, typeof(ReadabilityResources));
2727
private static readonly LocalizableString Description = new LocalizableResourceString(nameof(ReadabilityResources.SA1142Description), ReadabilityResources.ResourceManager, typeof(ReadabilityResources));
2828

29+
private static readonly Action<OperationAnalysisContext> FieldReferenceOperationAction = HandleFieldReferenceOperation;
2930
private static readonly Action<SyntaxNodeAnalysisContext> SimpleMemberAccessExpressionAction = HandleSimpleMemberAccessExpression;
3031

3132
private static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.ReadabilityRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, Description, HelpLink);
@@ -39,7 +40,32 @@ public override void Initialize(AnalysisContext context)
3940
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
4041
context.EnableConcurrentExecution();
4142

42-
context.RegisterSyntaxNodeAction(SimpleMemberAccessExpressionAction, SyntaxKind.SimpleMemberAccessExpression);
43+
if (LightupHelpers.SupportsIOperation)
44+
{
45+
context.RegisterOperationAction(FieldReferenceOperationAction, OperationKindEx.FieldReference);
46+
}
47+
else
48+
{
49+
context.RegisterSyntaxNodeAction(SimpleMemberAccessExpressionAction, SyntaxKind.SimpleMemberAccessExpression);
50+
}
51+
}
52+
53+
private static void HandleFieldReferenceOperation(OperationAnalysisContext context)
54+
{
55+
if (!context.SupportsTuples())
56+
{
57+
return;
58+
}
59+
60+
var fieldReference = IFieldReferenceOperationWrapper.FromOperation(context.Operation);
61+
62+
if (CheckFieldName(fieldReference.Field))
63+
{
64+
var location = fieldReference.WrappedOperation.Syntax is MemberAccessExpressionSyntax memberAccessExpression
65+
? memberAccessExpression.Name.GetLocation()
66+
: fieldReference.WrappedOperation.Syntax.GetLocation();
67+
context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
68+
}
4369
}
4470

4571
private static void HandleSimpleMemberAccessExpression(SyntaxNodeAnalysisContext context)

0 commit comments

Comments
 (0)