Skip to content

Commit

Permalink
Merge pull request #3229 from sharwell/operation-sa1142
Browse files Browse the repository at this point in the history
Use IOperation APIs for SA1142 when supported
  • Loading branch information
sharwell authored Nov 5, 2020
2 parents 7519395 + 26b47c4 commit d04c6cd
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ internal static bool SupportsTuples(this SyntaxNodeAnalysisContext context)
return (csharpParseOptions != null) && (csharpParseOptions.LanguageVersion >= LanguageVersionEx.CSharp7);
}

/// <summary>
/// Checks if the tuple language feature is supported.
/// </summary>
/// <param name="context">The analysis context that will be checked.</param>
/// <returns>True if tuples are supported by the compiler.</returns>
internal static bool SupportsTuples(this OperationAnalysisContext context)
{
var csharpParseOptions = context.Operation.Syntax.SyntaxTree.Options as CSharpParseOptions;
return (csharpParseOptions != null) && (csharpParseOptions.LanguageVersion >= LanguageVersionEx.CSharp7);
}

/// <summary>
/// Checks if the inferred tuple element names language feature is supported.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -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<IOperation, IFieldSymbol> FieldAccessor;
private static readonly Func<IOperation, bool> IsDeclarationAccessor;

private readonly IOperation operation;

static IFieldReferenceOperationWrapper()
{
WrappedType = WrapperHelper.GetWrappedType(typeof(IFieldReferenceOperationWrapper));
FieldAccessor = LightupHelpers.CreateOperationPropertyAccessor<IOperation, IFieldSymbol>(WrappedType, nameof(Field));
IsDeclarationAccessor = LightupHelpers.CreateOperationPropertyAccessor<IOperation, bool>(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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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<IOperation, IOperation> InstanceAccessor;
private static readonly Func<IOperation, ISymbol> MemberAccessor;

private readonly IOperation operation;

static IMemberReferenceOperationWrapper()
{
WrappedType = WrapperHelper.GetWrappedType(typeof(IFieldReferenceOperationWrapper));
InstanceAccessor = LightupHelpers.CreateOperationPropertyAccessor<IOperation, IOperation>(WrappedType, nameof(Instance));
MemberAccessor = LightupHelpers.CreateOperationPropertyAccessor<IOperation, ISymbol>(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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ namespace StyleCop.Analyzers.Lightup

internal static class OperationKindEx
{
/// <summary>
/// Indicates an <see cref="T:Microsoft.CodeAnalysis.Operations.IFieldReferenceOperation"/>.
/// </summary>
public const OperationKind FieldReference = (OperationKind)26;

/// <summary>
/// Indicates an <see cref="T:Microsoft.CodeAnalysis.Operations.IObjectCreationOperation"/>.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<OperationAnalysisContext> FieldReferenceOperationAction = HandleFieldReferenceOperation;
private static readonly Action<SyntaxNodeAnalysisContext> SimpleMemberAccessExpressionAction = HandleSimpleMemberAccessExpression;

private static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.ReadabilityRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, Description, HelpLink);
Expand All @@ -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)
Expand Down

0 comments on commit d04c6cd

Please sign in to comment.