private (ImmutableArray <SyntaxTree> added, ImmutableArray <SyntaxTree> removed) UpdateCompilationInternal(DocumentUri documentUri, int?version) { try { var context = this.provider.Create(workspace, documentUri); var output = workspace.UpsertSyntaxTrees(context.Compilation.SyntaxTreeGrouping.SyntaxTrees); // there shouldn't be concurrent upsert requests (famous last words...), so a simple overwrite should be sufficient this.activeContexts[documentUri] = context; // convert all the diagnostics to LSP diagnostics var diagnostics = GetDiagnosticsFromContext(context).ToDiagnostics(context.LineStarts); // publish all the diagnostics this.PublishDocumentDiagnostics(documentUri, version, diagnostics); return(output); } catch (Exception exception) { // this is a fatal error likely due to a code defect // publish a single fatal error diagnostic to tell the user something horrible has occurred // TODO: Tell user how to create an issue on GitHub. var fatalError = new Diagnostic { Range = new Range { Start = new Position(0, 0), End = new Position(1, 0), }, Severity = DiagnosticSeverity.Error, Message = exception.Message, Code = new DiagnosticCode("Fatal") }; // the file is no longer in a state that can be parsed // clear all info to prevent cascading failures elsewhere var closedTrees = CloseCompilationInternal(documentUri, version, fatalError.AsEnumerable()); return(ImmutableArray <SyntaxTree> .Empty, closedTrees); } }
private (ImmutableArray <ISourceFile> added, ImmutableArray <ISourceFile> removed) UpdateCompilationInternal(DocumentUri documentUri, int?version, IDictionary <ISourceFile, ISemanticModel> modelLookup, IEnumerable <ISourceFile> removedFiles, bool reloadBicepConfig = false) { var configuration = this.GetConfigurationSafely(documentUri, out var configurationDiagnostic); try { var context = this.activeContexts.AddOrUpdate( documentUri, (documentUri) => this.provider.Create(workspace, documentUri, modelLookup.ToImmutableDictionary(), configuration), (documentUri, prevContext) => { var sourceDependencies = removedFiles .SelectMany(x => prevContext.Compilation.SourceFileGrouping.GetFilesDependingOn(x)) .ToImmutableHashSet(); // check for semantic models that we can safely reuse from the previous compilation foreach (var sourceFile in prevContext.Compilation.SourceFileGrouping.SourceFiles) { if (!modelLookup.ContainsKey(sourceFile) && !sourceDependencies.Contains(sourceFile)) { // if we have a file with no dependencies on the modified file(s), we can reuse the previous model modelLookup[sourceFile] = prevContext.Compilation.GetSemanticModel(sourceFile); } } var configuration = reloadBicepConfig ? this.GetConfigurationSafely(documentUri.ToUri(), out configurationDiagnostic) : prevContext.Compilation.Configuration; return(this.provider.Create(workspace, documentUri, modelLookup.ToImmutableDictionary(), configuration)); }); foreach (var sourceFile in context.Compilation.SourceFileGrouping.SourceFiles) { // store all the updated models as other compilations may be able to reuse them modelLookup[sourceFile] = context.Compilation.GetSemanticModel(sourceFile); } // this completes immediately this.scheduler.RequestModuleRestore(this, documentUri, context.Compilation.SourceFileGrouping.ModulesToRestore, configuration); var output = workspace.UpsertSourceFiles(context.Compilation.SourceFileGrouping.SourceFiles); // convert all the diagnostics to LSP diagnostics var diagnostics = GetDiagnosticsFromContext(context).ToDiagnostics(context.LineStarts); if (configurationDiagnostic is not null) { diagnostics = diagnostics.Append(configurationDiagnostic); } // publish all the diagnostics this.PublishDocumentDiagnostics(documentUri, version, diagnostics); return(output); } catch (Exception exception) { // this is a fatal error likely due to a code defect // publish a single fatal error diagnostic to tell the user something horrible has occurred // TODO: Tell user how to create an issue on GitHub. var fatalError = new Diagnostic { Range = new Range { Start = new Position(0, 0), End = new Position(1, 0), }, Severity = DiagnosticSeverity.Error, Message = exception.Message, Code = new DiagnosticCode("Fatal") }; this.PublishDocumentDiagnostics(documentUri, version, fatalError.AsEnumerable()); return(ImmutableArray <ISourceFile> .Empty, ImmutableArray <ISourceFile> .Empty); } }