private void AnalyzeTypeDecra(SyntaxNodeAnalysisContext context, ContainingOperatorTypes types) { if (context.SemanticModel.GetDeclaredSymbol(context.Node, context.CancellationToken) is not INamedTypeSymbol symbol) { return; } var concurrentBuild = context.Compilation.Options.ConcurrentBuild; bool HasIsOperatorAttribute(INamedTypeSymbol symbol) { foreach (var at in symbol.ConstructedFrom.GetAttributes()) { if (SymbolEqualityComparer.Default.Equals(at.AttributeClass, types.IsOperatorAttribute)) { return(true); } } return(false); } if (concurrentBuild) { if (symbol.AllInterfaces .AsParallel(context.CancellationToken) .Any(HasIsOperatorAttribute)) { goto HasIsOperator; } } else { if (symbol.AllInterfaces .Do(_ => context.CancellationToken.ThrowIfCancellationRequested()) .Any(HasIsOperatorAttribute)) { goto HasIsOperator; } } return; HasIsOperator : { } bool DoesNotHaveMethodImpl(IMethodSymbol m) { return(m.MethodKind switch { MethodKind.ExplicitInterfaceImplementation or MethodKind.Ordinary => !m.GetAttributes().Select(at => at.AttributeClass) .Contains(types.MethodImplAttribute, SymbolEqualityComparer.Default), _ => false, }); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.RegisterCompilationStartAction(compilationStartContext => { if (ContainingOperatorTypes.TryParseTypes(compilationStartContext.Compilation, out var types)) { compilationStartContext.RegisterSyntaxNodeAction( c => AnalyzeTypeDecra(c, types), SyntaxKind.StructDeclaration, SyntaxKind.ClassConstraint); } }); }
public static bool TryParseTypes(Compilation compilation, out ContainingOperatorTypes types) { types = null; var methodImpl = compilation.GetTypeByMetadataName(System_Runtime_CompilerServices_MethodImplAttribute); if (methodImpl is null) { return(false); } var isOperator = compilation.GetTypeByMetadataName(AtCoder_IsOperatorAttribute); if (isOperator is null) { return(false); } types = new ContainingOperatorTypes(methodImpl, isOperator); return(true); }
private void AnalyzeTypeDecra(SyntaxNodeAnalysisContext context, ContainingOperatorTypes types) { if (context.SemanticModel.GetDeclaredSymbol(context.Node, context.CancellationToken) is not INamedTypeSymbol symbol) { return; } var concurrentBuild = context.Compilation.Options.ConcurrentBuild; bool HasIsOperatorAttribute(INamedTypeSymbol symbol) { foreach (var at in symbol.ConstructedFrom.GetAttributes()) { if (SymbolEqualityComparer.Default.Equals(at.AttributeClass, types.IsOperatorAttribute)) { return(true); } } return(false); } if (concurrentBuild) { if (symbol.AllInterfaces .AsParallel(context.CancellationToken) .Any(HasIsOperatorAttribute)) { goto HasIsOperator; } } else { if (symbol.AllInterfaces .Do(_ => context.CancellationToken.ThrowIfCancellationRequested()) .Any(HasIsOperatorAttribute)) { goto HasIsOperator; } } return; HasIsOperator: bool DoesNotHaveMethodImplInlining(IMethodSymbol m) { if (m.MethodKind is not(MethodKind.ExplicitInterfaceImplementation or MethodKind.Ordinary)) { return(false); } if (m.GetAttributes() .FirstOrDefault(at => SymbolEqualityComparer.Default.Equals(at.AttributeClass, types.MethodImplAttribute)) is not { } attr || attr.ConstructorArguments.Length == 0) { return(true); } var arg = attr.ConstructorArguments[0]; if (arg.Kind is TypedConstantKind.Primitive or TypedConstantKind.Enum) { try { return(!((MethodImplOptions)Convert.ToInt32(arg.Value)).HasFlag(MethodImplOptions.AggressiveInlining)); } catch { return(true); } } return(true); } string[] notMethodImplInliningMethods; if (concurrentBuild) { notMethodImplInliningMethods = symbol.GetMembers() .AsParallel(context.CancellationToken) .OfType <IMethodSymbol>() .Where(DoesNotHaveMethodImplInlining) .Select(m => m.Name) .ToArray(); } else { notMethodImplInliningMethods = symbol.GetMembers() .Do(_ => context.CancellationToken.ThrowIfCancellationRequested()) .OfType <IMethodSymbol>() .Where(DoesNotHaveMethodImplInlining) .Select(m => m.Name) .ToArray(); } if (notMethodImplInliningMethods.Length == 0) { return; } var diagnostic = DiagnosticDescriptors.AC0007_AgressiveInlining( context.Node.GetLocation(), notMethodImplInliningMethods); context.ReportDiagnostic(diagnostic); }