public async Task GenerateForCompilationAsync(Compilation compilation, string projectPath, HostLanguageServices languageServices, GeneratorOptions options) { var projectVertex = new Graph.LsifProject(kind: GetLanguageKind(compilation.Language), new Uri(projectPath), _idFactory); _lsifJsonWriter.Write(projectVertex); _lsifJsonWriter.Write(new Event(Event.EventKind.Begin, projectVertex.GetId(), _idFactory)); var documentIds = new ConcurrentBag <Id <Graph.LsifDocument> >(); // We create a ResultSetTracker to track all top-level symbols in the project. We don't want all writes to immediately go to // the JSON file -- we support parallel processing, so we'll accumulate them and then apply at once to avoid a lot // of contention on shared locks. var topLevelSymbolsWriter = new BatchingLsifJsonWriter(_lsifJsonWriter); var topLevelSymbolsResultSetTracker = new SymbolHoldingResultSetTracker(topLevelSymbolsWriter, compilation, _idFactory); // Disable navigation hints in quick info as computing them both takes too long, and they're never // even emitted in the final lsif hover information. options = options with { SymbolDescriptionOptions = options.SymbolDescriptionOptions with { QuickInfoOptions = options.SymbolDescriptionOptions.QuickInfoOptions with { IncludeNavigationHintsInQuickInfo = false } } }; var tasks = new List <Task>(); foreach (var syntaxTree in compilation.SyntaxTrees) { tasks.Add(Task.Run(async() => { var semanticModel = compilation.GetSemanticModel(syntaxTree); // We generate the document contents into an in-memory copy, and then write that out at once at the end. This // allows us to collect everything and avoid a lot of fine-grained contention on the write to the single // LSIF file. Because of the rule that vertices must be written before they're used by an edge, we'll flush any top- // level symbol result sets made first, since the document contents will point to that. Parallel calls to CopyAndEmpty // are allowed and might flush other unrelated stuff at the same time, but there's no harm -- the "causality" ordering // is preserved. var documentWriter = new BatchingLsifJsonWriter(_lsifJsonWriter); var documentId = await GenerateForDocumentAsync(semanticModel, languageServices, options, topLevelSymbolsResultSetTracker, documentWriter, _idFactory); topLevelSymbolsWriter.FlushToUnderlyingAndEmpty(); documentWriter.FlushToUnderlyingAndEmpty(); documentIds.Add(documentId); })); } await Task.WhenAll(tasks); _lsifJsonWriter.Write(Edge.Create("contains", projectVertex.GetId(), documentIds.ToArray(), _idFactory)); _lsifJsonWriter.Write(new Event(Event.EventKind.End, projectVertex.GetId(), _idFactory)); }
public void GenerateForCompilation(Compilation compilation, string projectPath, HostLanguageServices languageServices, OptionSet options) { var projectVertex = new Graph.LsifProject(kind: GetLanguageKind(compilation.Language), new Uri(projectPath), _idFactory); _lsifJsonWriter.Write(projectVertex); _lsifJsonWriter.Write(new Event(Event.EventKind.Begin, projectVertex.GetId(), _idFactory)); var documentIds = new ConcurrentBag <Id <Graph.LsifDocument> >(); // We create a ResultSetTracker to track all top-level symbols in the project. We don't want all writes to immediately go to // the JSON file -- we support parallel processing, so we'll accumulate them and then apply at once to avoid a lot // of contention on shared locks. var topLevelSymbolsWriter = new BatchingLsifJsonWriter(_lsifJsonWriter); var topLevelSymbolsResultSetTracker = new SymbolHoldingResultSetTracker(topLevelSymbolsWriter, compilation, _idFactory); Parallel.ForEach(compilation.SyntaxTrees, syntaxTree => { var semanticModel = compilation.GetSemanticModel(syntaxTree); // We generate the document contents into an in-memory copy, and then write that out at once at the end. This // allows us to collect everything and avoid a lot of fine-grained contention on the write to the single // LSIF file. Becasue of the rule that vertices must be written before they're used by an edge, we'll flush any top- // level symbol result sets made first, since the document contents will point to that. Parallel calls to CopyAndEmpty // are allowed and might flush other unrelated stuff at the same time, but there's no harm -- the "causality" ordering // is preserved. var documentWriter = new BatchingLsifJsonWriter(_lsifJsonWriter); var documentId = GenerateForDocument(semanticModel, languageServices, options, topLevelSymbolsResultSetTracker, documentWriter, _idFactory); topLevelSymbolsWriter.FlushToUnderlyingAndEmpty(); documentWriter.FlushToUnderlyingAndEmpty(); documentIds.Add(documentId); }); _lsifJsonWriter.Write(Edge.Create("contains", projectVertex.GetId(), documentIds.ToArray(), _idFactory)); _lsifJsonWriter.Write(new Event(Event.EventKind.End, projectVertex.GetId(), _idFactory)); }