public static async Task <LazinatorCompilationAnalyzer> CreateCompilationAnalyzer(Compilation compilation, CancellationToken cancellationToken, ImmutableArray <TextDocument> additionalFiles) { // Check if the attribute type LazinatorAttribute is defined. INamedTypeSymbol lazinatorAttributeType = compilation.GetTypeByMetadataName(LazinatorAttributeName); if (lazinatorAttributeType == null) { return(null); } // Check if the interface type ILazinator is defined. INamedTypeSymbol lazinatorInterfaceType = compilation.GetTypeByMetadataName(LazinatorInterfaceName); if (lazinatorInterfaceType == null) { return(null); } (string configPath, string configString) = await LazinatorConfigLoader.GetConfigPathAndText(additionalFiles, cancellationToken); LazinatorConfig config = new LazinatorConfig(configPath, configString); // Initialize state in the start action. var analyzer = new LazinatorCompilationAnalyzer(lazinatorAttributeType, lazinatorInterfaceType, configPath, configString, config); return(analyzer); }
private static async Task AddDiagnosticsForDocument(ImmutableDictionary <Document, ImmutableArray <Diagnostic> > .Builder builder, Compilation compilation, IEnumerable <TextDocument> additionalDocuments, LazinatorCompilationAnalyzer analyzer, Document doc, CancellationToken cancellationToken, bool suppressRegenerate) { cancellationToken.ThrowIfCancellationRequested(); if (analyzer == null) { analyzer = await LazinatorCompilationAnalyzer.CreateCompilationAnalyzer(compilation, cancellationToken, additionalDocuments.ToImmutableArray()); analyzer.DisableStartingFromInterface = true; } SyntaxNode root = await doc.GetSyntaxRootAsync(cancellationToken); var rootSyntaxTree = root.SyntaxTree; var model = compilation.GetSemanticModel(rootSyntaxTree); var namedTypes = root.DescendantNodesAndSelf() .OfType <TypeDeclarationSyntax>() .Select(x => model.GetDeclaredSymbol(x)) .OfType <INamedTypeSymbol>() .ToList(); foreach (var symbol in namedTypes) { analyzer.AnalyzeNamedType(symbol, compilation); } ImmutableArray <Diagnostic> diagnostics = analyzer.GetDiagnosticsToReport(suppressRegenerate).ToImmutableArray(); if (diagnostics.Any()) { builder.Add(doc, diagnostics); } analyzer.ClearDiagnostics(); }
public override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); try { context.EnableConcurrentExecution(); context.RegisterCompilationStartAction(compilationContext => { var additionalFiles = compilationContext.Options.AdditionalFiles; var compilation = compilationContext.Compilation; var cancellationToken = compilationContext.CancellationToken; var analyzer = LazinatorCompilationAnalyzer.CreateCompilationAnalyzer(compilation, cancellationToken, additionalFiles); if (analyzer == null) { return; } // Register intermediate non-end actions that access and modify the state. compilationContext.RegisterSyntaxNodeAction(analyzer.AnalyzeSyntaxNode, SyntaxKind.StructDeclaration, SyntaxKind.ClassDeclaration); compilationContext.RegisterSymbolAction(analyzer.AnalyzeSymbol, SymbolKind.NamedType, SymbolKind.Method); // Register an end action to report diagnostics based on the final state. compilationContext.RegisterSyntaxTreeAction(analyzer.SyntaxTreeStartAction); compilationContext.RegisterSemanticModelAction(analyzer.SemanticModelEndAction); // NOTE: We could register a compilation end action, but this will not execute at all if full solution analysis is disabled. }); } catch (Exception ex) { // catch exceptions so that we can get a more useful error in the Visual Studio consumer of this analyzer. throw new Exception($"Lazinator analyzer exception encountered. Message {ex.Message} Stack trace: {ex.StackTrace}"); } }
public async Task AddDiagnosticsToBuilder(Document d, ImmutableDictionary <Document, ImmutableArray <Diagnostic> > .Builder builder, CancellationToken cancellationToken, bool suppressRegenerate) { if (d == null) { return; } Project p = d.Project; Compilation compilation = await p.GetCompilationAsync(); var additionalDocuments = p.AdditionalDocuments; LazinatorCompilationAnalyzer analyzer = await LazinatorCompilationAnalyzer.CreateCompilationAnalyzer(compilation, cancellationToken, additionalDocuments.ToImmutableArray()); await AddDiagnosticsForDocument(builder, compilation, additionalDocuments, analyzer, d, cancellationToken, suppressRegenerate); }
public async Task AddDiagnosticsToBuilder(Project p, ImmutableDictionary <Document, ImmutableArray <Diagnostic> > .Builder builder, CancellationToken cancellationToken, bool suppressRegenerate) { if (p == null) { return; } Compilation compilation = await p.GetCompilationAsync(); var additionalDocuments = p.AdditionalDocuments; LazinatorCompilationAnalyzer analyzer = await LazinatorCompilationAnalyzer.CreateCompilationAnalyzer(compilation, cancellationToken, additionalDocuments?.ToImmutableArray() ?? new ImmutableArray <TextDocument>()); if (analyzer == null) { return; } analyzer.DisableStartingFromInterface = true; var config = analyzer.Config; foreach (var doc in p.Documents.Where(x => x.SourceCodeKind == SourceCodeKind.Regular && !(x.FilePath ?? x.Name).EndsWith(config?.GeneratedCodeFileExtension ?? ".laz.cs"))) { await AddDiagnosticsForDocument(builder, compilation, additionalDocuments, analyzer, doc, cancellationToken, suppressRegenerate); } }