Ejemplo n.º 1
0
 public override void Initialize(AnalysisContext context)
 {
     context.EnableConcurrentExecution();
     context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
     context.RegisterCompilationStartAction(compilationStartContext =>
     {
         if (OperatorTypesMatcher.TryParseTypes(compilationStartContext.Compilation, out var types))
         {
             compilationStartContext.RegisterSyntaxNodeAction(
                 c => AnalyzeGenericNode(c, types), SyntaxKind.GenericName);
         }
     });
 }
Ejemplo n.º 2
0
        private void AnalyzeGenericNode(SyntaxNodeAnalysisContext context, OperatorTypesMatcher types)
        {
            var semanticModel = context.SemanticModel;

            if (context.Node is not GenericNameSyntax genericNode)
            {
                return;
            }

            if (genericNode.TypeArgumentList.Arguments.Any(sy => sy.IsKind(SyntaxKind.OmittedTypeArgument)))
            {
                return;
            }
            var concurrentBuild = context.Compilation.Options.ConcurrentBuild;

            ImmutableArray <ITypeParameterSymbol> originalTypes;
            ImmutableArray <ITypeSymbol>          writtenTypes;

            switch (semanticModel.GetSymbolInfo(genericNode, context.CancellationToken).Symbol)
            {
            case INamedTypeSymbol symbol:
                originalTypes = symbol.TypeParameters;
                writtenTypes  = symbol.TypeArguments;
                break;

            case IMethodSymbol symbol:
                originalTypes = symbol.TypeParameters;
                writtenTypes  = symbol.TypeArguments;
                break;

            default:
                return;
            }

            if (originalTypes.Length == 0 || originalTypes.Length != writtenTypes.Length)
            {
                return;
            }

            var notDefinedTypes = new List <string>();

            for (int i = 0; i < originalTypes.Length; i++)
            {
                var originalType = originalTypes[i];
                var writtenType  = writtenTypes[i];

                if (concurrentBuild)
                {
                    if (originalType.ConstraintTypes.OfType <INamedTypeSymbol>()
                        .AsParallel(context.CancellationToken)
                        .Any(s => types.IsMatch(s.ConstructedFrom)))
                    {
                        goto TypeMatch;
                    }
                }
                else
                {
                    if (originalType.ConstraintTypes.OfType <INamedTypeSymbol>()
                        .Do(_ => context.CancellationToken.ThrowIfCancellationRequested())
                        .Any(s => types.IsMatch(s.ConstructedFrom)))
                    {
                        goto TypeMatch;
                    }
                }
                continue;

TypeMatch:
                if (writtenType.TypeKind == TypeKind.Error)
                {
                    notDefinedTypes.Add(writtenType.Name.ToString());
                }
            }
            if (notDefinedTypes.Count == 0)
            {
                return;
            }

            var diagnostic = DiagnosticDescriptors.AC0008_DefineOperatorType(
                genericNode.GetLocation(), notDefinedTypes);

            context.ReportDiagnostic(diagnostic);
        }
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false)
                is not CompilationUnitSyntax root)
            {
                return;
            }
            var config         = AtCoderAnalyzerConfig.Parse(context.Document.Project.AnalyzerOptions.AnalyzerConfigOptionsProvider.GlobalOptions);
            var diagnostic     = context.Diagnostics[0];
            var diagnosticSpan = diagnostic.Location.SourceSpan;

            if (root.FindNode(diagnosticSpan)
                is not GenericNameSyntax genericNode)
            {
                return;
            }

            var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);

            ImmutableArray <ITypeParameterSymbol> originalTypes;
            ImmutableArray <ITypeSymbol>          writtenTypes;

            switch (semanticModel.GetSymbolInfo(genericNode, context.CancellationToken).Symbol)
            {
            case INamedTypeSymbol symbol:
                originalTypes = symbol.TypeParameters;
                writtenTypes  = symbol.TypeArguments;
                break;

            case IMethodSymbol symbol:
                originalTypes = symbol.TypeParameters;
                writtenTypes  = symbol.TypeArguments;
                break;

            default:
                return;
            }


            var writtenTypeSyntaxes = genericNode.TypeArgumentList.Arguments;

            if (originalTypes.Length != writtenTypes.Length)
            {
                return;
            }

            if (!OperatorTypesMatcher.TryParseTypes(semanticModel.Compilation, out var types))
            {
                return;
            }

            var defaultSet           = ImmutableHashSet.Create <ITypeSymbol>(SymbolEqualityComparer.Default);
            var genericDicBuilder    = ImmutableDictionary.CreateBuilder <ITypeParameterSymbol, ITypeSymbol>(SymbolEqualityComparer.Default);
            var constraintDicBuilder = ImmutableDictionary.CreateBuilder <string, ImmutableHashSet <ITypeSymbol> >();

            for (int i = 0; i < originalTypes.Length; i++)
            {
                var writtenTypeSyntax = writtenTypeSyntaxes[i];
                var originalType      = originalTypes[i];
                var constraintTypes   = originalType.ConstraintTypes;
                var writtenType       = writtenTypes[i];

                if (!constraintTypes
                    .OfType <INamedTypeSymbol>()
                    .Select(ty => ty.ConstructedFrom)
                    .Any(ty => types.IsMatch(ty)))
                {
                    genericDicBuilder.Add(originalType, writtenType);
                    continue;
                }

                if (writtenType.TypeKind == TypeKind.Error)
                {
                    var name        = writtenType.Name;
                    var typeSymbols = constraintDicBuilder.GetValueOrDefault(name, defaultSet);
                    constraintDicBuilder[name] = typeSymbols.Union(constraintTypes);
                }
            }
            if (constraintDicBuilder.Count == 0)
            {
                return;
            }

            var genericDic         = genericDicBuilder.ToImmutable();
            var constraintArrayDic = ImmutableDictionary.CreateBuilder <string, ImmutableArray <ITypeSymbol> >();

            foreach (var p in constraintDicBuilder)
            {
                constraintArrayDic[p.Key]
                    = p.Value.Select(sy => SymbolHelpers.ReplaceGenericType(sy, genericDic))
                      .OrderBy(sy => sy.ToDisplayString())
                      .ToImmutableArray();
            }

            var action = CodeAction.Create(title: title,
                                           createChangedDocument: c => new OperatorTypeSyntaxBuilder(semanticModel, config).AddOperatorType(
                                               context.Document,
                                               root,
                                               constraintArrayDic.ToImmutable()),
                                           equivalenceKey: title);

            context.RegisterCodeFix(action, diagnostic);
        }