private Task ProcessSymbolDeclared(CompilationEvent.SymbolDeclared symbolEvent, CancellationToken cancellationToken) { try { return(AnalyzeSymbol(symbolEvent, cancellationToken)); } finally { symbolEvent.FlushCache(); } }
private Task AnalyzeSymbol(CompilationEvent.SymbolDeclared symbolEvent, CancellationToken cancellationToken) { var symbol = symbolEvent.Symbol; Action <Diagnostic> addDiagnostic = diagnostic => AddDiagnostic(diagnostic, symbol); var tasks = ArrayBuilder <Task> .GetInstance(); if ((int)symbol.Kind < DeclarationAnalyzersByKind.Length) { foreach (var da in DeclarationAnalyzersByKind[(int)symbol.Kind]) { // TODO: is the overhead of creating tasks here too high compared to the cost of running them sequentially? tasks.Add(Task.Run(() => { // Catch Exception from da.AnalyzeSymbol ExecuteAndCatchIfThrows(da, addDiagnostic, continueOnError, cancellationToken, () => { cancellationToken.ThrowIfCancellationRequested(); da.AnalyzeSymbol(symbol, Compilation, addDiagnostic, cancellationToken); }); })); } } // TODO: what about syntax references elsewhere, for example in a class base clause? switch (symbol.Kind) { // TODO: what about other syntax, such as base clauses, using directives, top-level attributes, etc? case SymbolKind.Method: case SymbolKind.Field: case SymbolKind.Event: // TODO: should this be restricted to field-like events? foreach (var decl in symbol.DeclaringSyntaxReferences) { tasks.Add(AnalyzeDeclaringReference(symbolEvent, decl, AddDiagnostic, cancellationToken)); } break; } return(Task.WhenAll(tasks.ToImmutableAndFree())); }
private async Task AnalyzeDeclaringReference(CompilationEvent.SymbolDeclared symbolEvent, SyntaxReference decl, Action <Diagnostic> addDiagnostic, CancellationToken cancellationToken) { var symbol = symbolEvent.Symbol; var syntax = await decl.GetSyntaxAsync(); var endedAnalyzers = ArrayBuilder <ICodeBlockEndedAnalyzer> .GetInstance(); endedAnalyzers.AddRange(CodeBlockEndedAnalyzers); var nodeAnalyzers = ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > .GetInstance(); nodeAnalyzers.AddRange(Analyzers.OfType <ISyntaxNodeAnalyzer <TSyntaxKind> >()); foreach (var da in CodeBlockStartedAnalyzers) { // Catch Exception from da.OnCodeBlockStarted ExecuteAndCatchIfThrows(da, addDiagnostic, continueOnError, cancellationToken, () => { var blockStatefulAnalyzer = da.OnCodeBlockStarted(syntax, symbol, symbolEvent.SemanticModel(decl), addDiagnostic, cancellationToken); var endedAnalyzer = blockStatefulAnalyzer as ICodeBlockEndedAnalyzer; if (endedAnalyzer != null) { endedAnalyzers.Add(endedAnalyzer); } var nodeAnalyzer = blockStatefulAnalyzer as ISyntaxNodeAnalyzer <TSyntaxKind>; if (nodeAnalyzer != null) { nodeAnalyzers.Add(nodeAnalyzer); } }); } PooledDictionary <TSyntaxKind, ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > > nodeAnalyzersByKind = null; foreach (var nodeAnalyzer in nodeAnalyzers) { // Catch Exception from nodeAnalyzer.SyntaxKindsOfInterest try { foreach (var kind in nodeAnalyzer.SyntaxKindsOfInterest) { if (nodeAnalyzersByKind == null) { nodeAnalyzersByKind = PooledDictionary <TSyntaxKind, ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > > .GetInstance(); } ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > analyzersForKind; if (!nodeAnalyzersByKind.TryGetValue(kind, out analyzersForKind)) { nodeAnalyzersByKind.Add(kind, analyzersForKind = ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > .GetInstance()); } analyzersForKind.Add(nodeAnalyzer); } } catch (Exception e) { // Create a info diagnostic saying that the analyzer failed addDiagnostic(GetAnalyzerDiagnostic(nodeAnalyzer, e)); } } nodeAnalyzers.Free(); SemanticModel semanticModel = (nodeAnalyzersByKind != null || endedAnalyzers.Any()) ? symbolEvent.SemanticModel(decl) : null; if (nodeAnalyzersByKind != null) { semanticModel = symbolEvent.SemanticModel(decl); foreach (var child in syntax.DescendantNodesAndSelf()) { ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > analyzersForKind; if (nodeAnalyzersByKind.TryGetValue(GetKind(child), out analyzersForKind)) { foreach (var analyzer in analyzersForKind) { // Catch Exception from analyzer.AnalyzeNode ExecuteAndCatchIfThrows(analyzer, addDiagnostic, continueOnError, cancellationToken, () => { analyzer.AnalyzeNode(child, semanticModel, addDiagnostic, cancellationToken); }); } } } foreach (var b in nodeAnalyzersByKind.Values) { b.Free(); } nodeAnalyzersByKind.Free(); } foreach (var a in endedAnalyzers) { // Catch Exception from a.OnCodeBlockEnded ExecuteAndCatchIfThrows(a, addDiagnostic, continueOnError, cancellationToken, () => { a.OnCodeBlockEnded(syntax, symbol, semanticModel, addDiagnostic, cancellationToken); }); } endedAnalyzers.Free(); }