diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Helpers/LanguageFeatureHelpers.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Helpers/LanguageFeatureHelpers.cs
index d1da8119d..c0dbfe5ea 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/Helpers/LanguageFeatureHelpers.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/Helpers/LanguageFeatureHelpers.cs
@@ -23,6 +23,17 @@ internal static bool SupportsTuples(this SyntaxNodeAnalysisContext context)
return (csharpParseOptions != null) && (csharpParseOptions.LanguageVersion >= LanguageVersionEx.CSharp7);
}
+ ///
+ /// Checks if the tuple language feature is supported.
+ ///
+ /// The analysis context that will be checked.
+ /// True if tuples are supported by the compiler.
+ internal static bool SupportsTuples(this OperationAnalysisContext context)
+ {
+ var csharpParseOptions = context.Operation.Syntax.SyntaxTree.Options as CSharpParseOptions;
+ return (csharpParseOptions != null) && (csharpParseOptions.LanguageVersion >= LanguageVersionEx.CSharp7);
+ }
+
///
/// Checks if the inferred tuple element names language feature is supported.
///
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IFieldReferenceOperationWrapper.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IFieldReferenceOperationWrapper.cs
new file mode 100644
index 000000000..715c1044b
--- /dev/null
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IFieldReferenceOperationWrapper.cs
@@ -0,0 +1,81 @@
+// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+namespace StyleCop.Analyzers.Lightup
+{
+ using System;
+ using Microsoft.CodeAnalysis;
+
+ internal readonly struct IFieldReferenceOperationWrapper : IOperationWrapper
+ {
+ internal const string WrappedTypeName = "Microsoft.CodeAnalysis.Operations.IFieldReferenceOperation";
+ private static readonly Type WrappedType;
+
+ private static readonly Func FieldAccessor;
+ private static readonly Func IsDeclarationAccessor;
+
+ private readonly IOperation operation;
+
+ static IFieldReferenceOperationWrapper()
+ {
+ WrappedType = WrapperHelper.GetWrappedType(typeof(IFieldReferenceOperationWrapper));
+ FieldAccessor = LightupHelpers.CreateOperationPropertyAccessor(WrappedType, nameof(Field));
+ IsDeclarationAccessor = LightupHelpers.CreateOperationPropertyAccessor(WrappedType, nameof(IsDeclaration));
+ }
+
+ private IFieldReferenceOperationWrapper(IOperation operation)
+ {
+ this.operation = operation;
+ }
+
+ public IOperation WrappedOperation => this.operation;
+
+ public ITypeSymbol Type => this.WrappedOperation.Type;
+
+ public IFieldSymbol Field
+ {
+ get
+ {
+ return FieldAccessor(this.WrappedOperation);
+ }
+ }
+
+ public bool IsDeclaration
+ {
+ get
+ {
+ return IsDeclarationAccessor(this.WrappedOperation);
+ }
+ }
+
+ public IOperation Instance => ((IMemberReferenceOperationWrapper)this).Instance;
+
+ public ISymbol Member => ((IMemberReferenceOperationWrapper)this).Member;
+
+ public static explicit operator IFieldReferenceOperationWrapper(IMemberReferenceOperationWrapper wrapper)
+ => FromOperation(wrapper.WrappedOperation);
+
+ public static implicit operator IMemberReferenceOperationWrapper(IFieldReferenceOperationWrapper wrapper)
+ => IMemberReferenceOperationWrapper.FromUpcast(wrapper.operation);
+
+ public static IFieldReferenceOperationWrapper FromOperation(IOperation operation)
+ {
+ if (operation == null)
+ {
+ return default;
+ }
+
+ if (!IsInstance(operation))
+ {
+ throw new InvalidCastException($"Cannot cast '{operation.GetType().FullName}' to '{WrappedTypeName}'");
+ }
+
+ return new IFieldReferenceOperationWrapper(operation);
+ }
+
+ public static bool IsInstance(IOperation operation)
+ {
+ return operation != null && LightupHelpers.CanWrapOperation(operation, WrappedType);
+ }
+ }
+}
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IMemberReferenceOperationWrapper.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IMemberReferenceOperationWrapper.cs
new file mode 100644
index 000000000..3c5c59941
--- /dev/null
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IMemberReferenceOperationWrapper.cs
@@ -0,0 +1,76 @@
+// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+namespace StyleCop.Analyzers.Lightup
+{
+ using System;
+ using Microsoft.CodeAnalysis;
+
+ internal readonly struct IMemberReferenceOperationWrapper : IOperationWrapper
+ {
+ internal const string WrappedTypeName = "Microsoft.CodeAnalysis.Operations.IMemberReferenceOperation";
+ private static readonly Type WrappedType;
+
+ private static readonly Func InstanceAccessor;
+ private static readonly Func MemberAccessor;
+
+ private readonly IOperation operation;
+
+ static IMemberReferenceOperationWrapper()
+ {
+ WrappedType = WrapperHelper.GetWrappedType(typeof(IFieldReferenceOperationWrapper));
+ InstanceAccessor = LightupHelpers.CreateOperationPropertyAccessor(WrappedType, nameof(Instance));
+ MemberAccessor = LightupHelpers.CreateOperationPropertyAccessor(WrappedType, nameof(Member));
+ }
+
+ private IMemberReferenceOperationWrapper(IOperation operation)
+ {
+ this.operation = operation;
+ }
+
+ public IOperation WrappedOperation => this.operation;
+
+ public ITypeSymbol Type => this.WrappedOperation.Type;
+
+ public IOperation Instance
+ {
+ get
+ {
+ return InstanceAccessor(this.WrappedOperation);
+ }
+ }
+
+ public ISymbol Member
+ {
+ get
+ {
+ return MemberAccessor(this.WrappedOperation);
+ }
+ }
+
+ public static IMemberReferenceOperationWrapper FromOperation(IOperation operation)
+ {
+ if (operation == null)
+ {
+ return default;
+ }
+
+ if (!IsInstance(operation))
+ {
+ throw new InvalidCastException($"Cannot cast '{operation.GetType().FullName}' to '{WrappedTypeName}'");
+ }
+
+ return new IMemberReferenceOperationWrapper(operation);
+ }
+
+ public static bool IsInstance(IOperation operation)
+ {
+ return operation != null && LightupHelpers.CanWrapOperation(operation, WrappedType);
+ }
+
+ internal static IMemberReferenceOperationWrapper FromUpcast(IOperation operation)
+ {
+ return new IMemberReferenceOperationWrapper(operation);
+ }
+ }
+}
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/OperationKindEx.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/OperationKindEx.cs
index ac22f7fc9..16a7c1570 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/OperationKindEx.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/OperationKindEx.cs
@@ -7,6 +7,11 @@ namespace StyleCop.Analyzers.Lightup
internal static class OperationKindEx
{
+ ///
+ /// Indicates an .
+ ///
+ public const OperationKind FieldReference = (OperationKind)26;
+
///
/// Indicates an .
///
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/WrapperHelper.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/WrapperHelper.cs
index f58421c45..8944449ac 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/WrapperHelper.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/WrapperHelper.cs
@@ -57,6 +57,8 @@ static WrapperHelper()
builder.Add(typeof(WhenClauseSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(WhenClauseSyntaxWrapper.WrappedTypeName));
builder.Add(typeof(IArgumentOperationWrapper), codeAnalysisAssembly.GetType(IArgumentOperationWrapper.WrappedTypeName));
+ builder.Add(typeof(IFieldReferenceOperationWrapper), codeAnalysisAssembly.GetType(IFieldReferenceOperationWrapper.WrappedTypeName));
+ builder.Add(typeof(IMemberReferenceOperationWrapper), codeAnalysisAssembly.GetType(IMemberReferenceOperationWrapper.WrappedTypeName));
builder.Add(typeof(IObjectCreationOperationWrapper), codeAnalysisAssembly.GetType(IObjectCreationOperationWrapper.WrappedTypeName));
builder.Add(typeof(IObjectOrCollectionInitializerOperationWrapper), codeAnalysisAssembly.GetType(IObjectOrCollectionInitializerOperationWrapper.WrappedTypeName));
builder.Add(typeof(ITypeParameterObjectCreationOperationWrapper), codeAnalysisAssembly.GetType(ITypeParameterObjectCreationOperationWrapper.WrappedTypeName));
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1142ReferToTupleElementsByName.cs b/StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1142ReferToTupleElementsByName.cs
index 7b5d1e4e6..cd3499d65 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1142ReferToTupleElementsByName.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1142ReferToTupleElementsByName.cs
@@ -26,6 +26,7 @@ internal class SA1142ReferToTupleElementsByName : DiagnosticAnalyzer
private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(ReadabilityResources.SA1142MessageFormat), ReadabilityResources.ResourceManager, typeof(ReadabilityResources));
private static readonly LocalizableString Description = new LocalizableResourceString(nameof(ReadabilityResources.SA1142Description), ReadabilityResources.ResourceManager, typeof(ReadabilityResources));
+ private static readonly Action FieldReferenceOperationAction = HandleFieldReferenceOperation;
private static readonly Action SimpleMemberAccessExpressionAction = HandleSimpleMemberAccessExpression;
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)
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
- context.RegisterSyntaxNodeAction(SimpleMemberAccessExpressionAction, SyntaxKind.SimpleMemberAccessExpression);
+ if (LightupHelpers.SupportsIOperation)
+ {
+ context.RegisterOperationAction(FieldReferenceOperationAction, OperationKindEx.FieldReference);
+ }
+ else
+ {
+ context.RegisterSyntaxNodeAction(SimpleMemberAccessExpressionAction, SyntaxKind.SimpleMemberAccessExpression);
+ }
+ }
+
+ private static void HandleFieldReferenceOperation(OperationAnalysisContext context)
+ {
+ if (!context.SupportsTuples())
+ {
+ return;
+ }
+
+ var fieldReference = IFieldReferenceOperationWrapper.FromOperation(context.Operation);
+
+ if (CheckFieldName(fieldReference.Field))
+ {
+ var location = fieldReference.WrappedOperation.Syntax is MemberAccessExpressionSyntax memberAccessExpression
+ ? memberAccessExpression.Name.GetLocation()
+ : fieldReference.WrappedOperation.Syntax.GetLocation();
+ context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
+ }
}
private static void HandleSimpleMemberAccessExpression(SyntaxNodeAnalysisContext context)