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); } }); }
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); }