protected override InlineDiagnosticsTag?CreateTag(Workspace workspace, DiagnosticData diagnostic) { Debug.Assert(!string.IsNullOrWhiteSpace(diagnostic.Message)); var errorType = GetErrorTypeFromDiagnostic(diagnostic); if (errorType is null) { return(null); } if (diagnostic.DocumentId is null) { return(null); } var project = workspace.CurrentSolution.GetProject(diagnostic.DocumentId.ProjectId); if (project is null) { return(null); } var locationOption = GlobalOptions.GetOption(InlineDiagnosticsOptions.Location, project.Language); var navigateService = workspace.Services.GetRequiredService <INavigateToLinkService>(); return(new InlineDiagnosticsTag(errorType, diagnostic, _editorFormatMap, _classificationFormatMapService, _classificationTypeRegistryService, locationOption, navigateService)); }
/// <summary> /// Return CompilationWithAnalyzer for given project with given stateSets /// </summary> private async Task <CompilationWithAnalyzers?> GetOrCreateCompilationWithAnalyzersAsync(Project project, IEnumerable <StateSet> stateSets, CancellationToken cancellationToken) { if (!project.SupportsCompilation) { return(null); } if (_projectCompilationsWithAnalyzers.TryGetValue(project, out var compilationWithAnalyzers)) { // we have cached one, return that. AssertAnalyzers(compilationWithAnalyzers, stateSets); return(compilationWithAnalyzers); } // Create driver that holds onto compilation and associated analyzers var crashOnAnalyzerException = GlobalOptions.GetOption(InternalDiagnosticsOptions.CrashOnAnalyzerException); var newCompilationWithAnalyzers = await CreateCompilationWithAnalyzersAsync(project, stateSets, includeSuppressedDiagnostics : true, crashOnAnalyzerException, cancellationToken).ConfigureAwait(false); // Add new analyzer driver to the map compilationWithAnalyzers = _projectCompilationsWithAnalyzers.GetValue(project, _ => newCompilationWithAnalyzers); // if somebody has beat us, make sure analyzers are good. if (compilationWithAnalyzers != newCompilationWithAnalyzers) { AssertAnalyzers(compilationWithAnalyzers, stateSets); } return(compilationWithAnalyzers); }
public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapabilities) { // If the LSP editor feature flag is enabled advertise support for LSP features here so they are available locally and remote. var isLspEditorEnabled = GlobalOptions.GetOption(LspOptions.LspEditorFeatureFlag); var serverCapabilities = isLspEditorEnabled ? (VSInternalServerCapabilities)_defaultCapabilitiesProvider.GetCapabilities(clientCapabilities) : new VSInternalServerCapabilities() { // Even if the flag is off, we want to include text sync capabilities. TextDocumentSync = new TextDocumentSyncOptions { Change = TextDocumentSyncKind.Incremental, OpenClose = true, }, }; serverCapabilities.ProjectContextProvider = true; serverCapabilities.BreakableRangeProvider = true; var isPullDiagnostics = GlobalOptions.IsPullDiagnostics(InternalDiagnosticsOptions.NormalDiagnosticMode); if (isPullDiagnostics) { serverCapabilities.SupportsDiagnosticRequests = true; serverCapabilities.MultipleContextSupportProvider = new VSInternalMultipleContextFeatures { SupportsMultipleContextsDiagnostics = true }; } // This capability is always enabled as we provide cntrl+Q VS search only via LSP in ever scenario. serverCapabilities.WorkspaceSymbolProvider = true; // This capability prevents NavigateTo (cntrl+,) from using LSP symbol search when the server also supports WorkspaceSymbolProvider. // Since WorkspaceSymbolProvider=true always to allow cntrl+Q VS search to function, we set DisableGoToWorkspaceSymbols=true // when not running the experimental LSP editor. This ensures NavigateTo uses the existing editor APIs. // However, when the experimental LSP editor is enabled we want LSP to power NavigateTo, so we set DisableGoToWorkspaceSymbols=false. serverCapabilities.DisableGoToWorkspaceSymbols = !isLspEditorEnabled; var isLspSemanticTokensEnabled = GlobalOptions.GetOption(LspOptions.LspSemanticTokensFeatureFlag); if (isLspSemanticTokensEnabled) { // Using only range handling has shown to be more performant than using a combination of full/edits/range handling, // especially for larger files. With range handling, we only need to compute tokens for whatever is in view, while // with full/edits handling we need to compute tokens for the entire file and then potentially run a diff between // the old and new tokens. serverCapabilities.SemanticTokensOptions = new SemanticTokensOptions { Full = false, Range = true, Legend = new SemanticTokensLegend { TokenTypes = SemanticTokenTypes.AllTypes.Concat(SemanticTokensHelpers.RoslynCustomTokenTypes).ToArray(), TokenModifiers = new string[] { SemanticTokenModifiers.Static } } }; } return(serverCapabilities); }
protected override bool ComputeInitialTagsSynchronously(ITextBuffer subjectBuffer) { // If we can't find this doc, or outlining is not enabled for it, no need to computed anything synchronously. var openDocument = subjectBuffer.AsTextContainer().GetRelatedDocuments().FirstOrDefault(); if (openDocument == null) { return(false); } if (!GlobalOptions.GetOption(FeatureOnOffOptions.Outlining, openDocument.Project.Language)) { return(false); } // If we're a metadata-as-source doc, we need to compute the initial set of tags synchronously // so that we can collapse all the .IsImplementation tags to keep the UI clean and condensed. var isMetadataAsSource = openDocument.Project.Solution.Workspace.Kind == WorkspaceKind.MetadataAsSource; if (isMetadataAsSource) { return(true); } // If we contain any #region sections, we want to collapse those automatically on open the first // time a doc is ever opened. So we need to compute the initial tags synchronously in order to // do that. if (ContainsRegionTag(subjectBuffer.CurrentSnapshot)) { return(true); } return(false);
public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapabilities) { var isLspEditorEnabled = GlobalOptions.GetOption(LspOptions.LspEditorFeatureFlag); // If the preview feature flag to turn on the LSP editor in local scenarios is on, advertise no capabilities for this Live Share // LSP server as LSP requests will be serviced by the AlwaysActiveInProcLanguageClient in both local and remote scenarios. if (isLspEditorEnabled) { return(new VSServerCapabilities { TextDocumentSync = new TextDocumentSyncOptions { OpenClose = false, Change = TextDocumentSyncKind.None, } }); } var defaultCapabilities = _defaultCapabilitiesProvider.GetCapabilities(clientCapabilities); // If the LSP semantic tokens feature flag is enabled, advertise no semantic tokens capabilities for this Live Share // LSP server as LSP semantic tokens requests will be serviced by the AlwaysActiveInProcLanguageClient in both local and // remote scenarios. var isLspSemanticTokenEnabled = GlobalOptions.GetOption(LspOptions.LspSemanticTokensFeatureFlag); if (isLspSemanticTokenEnabled) { defaultCapabilities.SemanticTokensOptions = null; } return(defaultCapabilities); }
private void RaiseDiagnosticsRemovedIfRequiredForClosedOrResetDocument(TextDocument document, IEnumerable <StateSet> stateSets, bool documentHadDiagnostics) { // If there was no diagnostic reported for this document, nothing to clean up // This is done for Perf to reduce raising events unnecessarily. if (!documentHadDiagnostics) { return; } // If full solution analysis is enabled for both compiler diagnostics and analyzers, // we don't need to clear diagnostics for individual documents on document close/reset. // This is done for Perf to reduce raising events unnecessarily. var _ = GlobalOptions.IsFullSolutionAnalysisEnabled(document.Project.Language, out var compilerFullAnalysisEnabled, out var analyzersFullAnalysisEnabled); if (compilerFullAnalysisEnabled && analyzersFullAnalysisEnabled) { return; } var removeDiagnosticsOnDocumentClose = GlobalOptions.GetOption(SolutionCrawlerOptionsStorage.RemoveDocumentDiagnosticsOnDocumentClose, document.Project.Language); if (!removeDiagnosticsOnDocumentClose) { return; } RaiseDiagnosticsRemovedForDocument(document.Id, stateSets); }
public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapabilities) { var serverCapabilities = new VSInternalServerCapabilities(); // If the LSP editor feature flag is enabled advertise support for LSP features here so they are available locally and remote. var isLspEditorEnabled = GlobalOptions.GetOption(LspOptions.LspEditorFeatureFlag); if (isLspEditorEnabled) { serverCapabilities = (VSInternalServerCapabilities)_defaultCapabilitiesProvider.GetCapabilities(clientCapabilities); } else { // Even if the flag is off, we want to include text sync capabilities. serverCapabilities.TextDocumentSync = new TextDocumentSyncOptions { Change = TextDocumentSyncKind.Incremental, OpenClose = true, }; } serverCapabilities.SupportsDiagnosticRequests = GlobalOptions.IsPullDiagnostics(InternalDiagnosticsOptions.NormalDiagnosticMode); // This capability is always enabled as we provide cntrl+Q VS search only via LSP in ever scenario. serverCapabilities.WorkspaceSymbolProvider = true; // This capability prevents NavigateTo (cntrl+,) from using LSP symbol search when the server also supports WorkspaceSymbolProvider. // Since WorkspaceSymbolProvider=true always to allow cntrl+Q VS search to function, we set DisableGoToWorkspaceSymbols=true // when not running the experimental LSP editor. This ensures NavigateTo uses the existing editor APIs. // However, when the experimental LSP editor is enabled we want LSP to power NavigateTo, so we set DisableGoToWorkspaceSymbols=false. serverCapabilities.DisableGoToWorkspaceSymbols = !isLspEditorEnabled; return(serverCapabilities); }
public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapabilities) { var isLspExperimentEnabled = GlobalOptions.GetOption(XamlOptions.EnableLspIntelliSenseFeatureFlag); var capabilities = isLspExperimentEnabled ? XamlCapabilities.None : XamlCapabilities.Current; // Only turn on CodeAction support for client scenarios. Hosts will get non-LSP lightbulbs automatically. capabilities.CodeActionProvider = new CodeActionOptions { CodeActionKinds = new[] { CodeActionKind.QuickFix, CodeActionKind.Refactor }, ResolveProvider = true }; return(capabilities); }
protected override async Task ProduceTagsAsync( TaggerContext <StringIndentationTag> context, DocumentSnapshotSpan documentSnapshotSpan, int?caretPosition, CancellationToken cancellationToken) { var document = documentSnapshotSpan.Document; if (document == null) { return; } if (!GlobalOptions.GetOption(FeatureOnOffOptions.StringIdentation, document.Project.Language)) { return; } var service = document.GetLanguageService <IStringIndentationService>(); if (service == null) { return; } var snapshotSpan = documentSnapshotSpan.SnapshotSpan; var regions = await service.GetStringIndentationRegionsAsync(document, snapshotSpan.Span.ToTextSpan(), cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); if (regions.Length == 0) { return; } var snapshot = snapshotSpan.Snapshot; foreach (var region in regions) { var line = snapshot.GetLineFromPosition(region.IndentSpan.End); // If the indent is on the first column, then no need to actually show anything (plus we can't as we // want to draw one column earlier, and that column doesn't exist). if (line.Start == region.IndentSpan.End) { continue; } context.AddTag(new TagSpan <StringIndentationTag>( region.IndentSpan.ToSnapshotSpan(snapshot), new StringIndentationTag( _editorFormatMap, region.OrderedHoleSpans.SelectAsArray(s => s.ToSnapshotSpan(snapshot))))); } }
protected override async Task InitializeServiceForOpenedDocumentAsync(Document document) { // Only pre-populate cache if import completion is enabled if (GlobalOptions.GetOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp) != true) { return; } var service = document.GetRequiredLanguageService <ITypeImportCompletionService>(); service.QueueCacheWarmUpTask(document.Project); await ExtensionMethodImportCompletionHelper.WarmUpCacheAsync(document.Project, CancellationToken.None).ConfigureAwait(false); }
protected override bool ComputeInitialTagsSynchronously(ITextBuffer subjectBuffer) { // If we can't find this doc, or outlining is not enabled for it, no need to computed anything synchronously. var openDocument = subjectBuffer.AsTextContainer().GetRelatedDocuments().FirstOrDefault(); if (openDocument == null) { return(false); } // If the main Outlining option is turned off, we can just skip computing tags synchronously // so when the document first opens, there won't be any tags yet. When the tags do come in // the IsDefaultCollapsed property, which controls the initial collapsing, won't have any effect // because the document will already be open. if (!GlobalOptions.GetOption(FeatureOnOffOptions.Outlining, openDocument.Project.Language)) { return(false); } var options = BlockStructureOptionsStorage.GetBlockStructureOptions(GlobalOptions, openDocument.Project); // If we're a metadata-as-source doc, we need to compute the initial set of tags synchronously // so that we can collapse all the .IsImplementation tags to keep the UI clean and condensed. if (openDocument.Project.Solution.Workspace is MetadataAsSourceWorkspace masWorkspace && masWorkspace.FileService.ShouldCollapseOnOpen(openDocument.FilePath, options)) { return(true); } // If the user wants to collapse imports or #regions then we need to compute // synchronously, but only if there are imports or #regions in the file. To // save some work, we'll look for both in a single pass. var collapseRegions = GlobalOptions.GetOption(BlockStructureOptionsStorage.CollapseRegionsWhenFirstOpened, openDocument.Project.Language); var collapseImports = GlobalOptions.GetOption(BlockStructureOptionsStorage.CollapseImportsWhenFirstOpened, openDocument.Project.Language); if (!collapseRegions && !collapseImports) { return(false); } if (ContainsRegionOrImport(subjectBuffer.CurrentSnapshot, collapseRegions, collapseImports, openDocument.Project.Language)) { return(true); } return(false); }
private async Task AnalyzeProjectAsync(Project project, bool forceAnalyzerRun, CancellationToken cancellationToken) { try { var stateSets = GetStateSetsForFullSolutionAnalysis(_stateManager.GetOrUpdateStateSets(project), project); var options = project.Solution.Options; // PERF: get analyzers that are not suppressed and marked as open file only // this is perf optimization. we cache these result since we know the result. (no diagnostics) var activeAnalyzers = stateSets .Select(s => s.Analyzer) .Where(a => DocumentAnalysisExecutor.IsAnalyzerEnabledForProject(a, project, GlobalOptions) && !a.IsOpenFileOnly(options)); // get driver only with active analyzers. var crashOnAnalyzerException = GlobalOptions.GetOption(InternalDiagnosticsOptions.CrashOnAnalyzerException); var compilationWithAnalyzers = await DocumentAnalysisExecutor.CreateCompilationWithAnalyzersAsync(project, activeAnalyzers, includeSuppressedDiagnostics : true, crashOnAnalyzerException, cancellationToken).ConfigureAwait(false); var result = await GetProjectAnalysisDataAsync(compilationWithAnalyzers, project, stateSets, forceAnalyzerRun, cancellationToken).ConfigureAwait(false); if (result.OldResult == null) { RaiseProjectDiagnosticsIfNeeded(project, stateSets, result.Result); return; } // we might not have compilationWithAnalyzers even if project supports compilation if we are called with no analyzers. var compilation = compilationWithAnalyzers?.Compilation ?? (project.SupportsCompilation ? await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false) : null); // no cancellation after this point. // any analyzer that doesn't have result will be treated as returned empty set // which means we will remove those from error list foreach (var stateSet in stateSets) { var state = stateSet.GetOrCreateProjectState(project.Id); await state.SaveToInMemoryStorageAsync(project, result.GetResult(stateSet.Analyzer)).ConfigureAwait(false); } RaiseProjectDiagnosticsIfNeeded(project, stateSets, result.OldResult, result.Result); } catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } }
protected override async Task ProduceTagsAsync( TaggerContext <LineSeparatorTag> context, DocumentSnapshotSpan documentSnapshotSpan, int?caretPosition, CancellationToken cancellationToken) { var document = documentSnapshotSpan.Document; if (document == null) { return; } if (!GlobalOptions.GetOption(FeatureOnOffOptions.LineSeparator, document.Project.Language)) { return; } using (Logger.LogBlock(FunctionId.Tagger_LineSeparator_TagProducer_ProduceTags, cancellationToken)) { var snapshotSpan = documentSnapshotSpan.SnapshotSpan; var lineSeparatorService = document.GetLanguageService <ILineSeparatorService>(); if (lineSeparatorService == null) { return; } var lineSeparatorSpans = await lineSeparatorService.GetLineSeparatorsAsync(document, snapshotSpan.Span.ToTextSpan(), cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); if (lineSeparatorSpans.Length == 0) { return; } LineSeparatorTag tag; lock (_lineSeperatorTagGate) { tag = _lineSeparatorTag; } foreach (var span in lineSeparatorSpans) { context.AddTag(new TagSpan <LineSeparatorTag>(span.ToSnapshotSpan(snapshotSpan.Snapshot), tag)); } } }
private void RaiseDiagnosticsRemovedIfRequiredForClosedOrResetDocument(TextDocument document, IEnumerable <StateSet> stateSets, bool documentHadDiagnostics) { // if there was no diagnostic reported for this document OR Full solution analysis is enabled, nothing to clean up if (!documentHadDiagnostics || FullAnalysisEnabled(document.Project, forceAnalyzerRun: false)) { // this is Perf to reduce raising events unnecessarily. return; } var removeDiagnosticsOnDocumentClose = GlobalOptions.GetOption(SolutionCrawlerOptionsStorage.RemoveDocumentDiagnosticsOnDocumentClose, document.Project.Language); if (!removeDiagnosticsOnDocumentClose) { return; } RaiseDiagnosticsRemovedForDocument(document.Id, stateSets); }
public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapabilities) { var isLspEditorEnabled = GlobalOptions.GetOption(LspOptions.LspEditorFeatureFlag); // If the preview feature flag to turn on the LSP editor in local scenarios is on, advertise no capabilities for this Live Share // LSP server as LSP requests will be serviced by the AlwaysActiveInProcLanguageClient in both local and remote scenarios. if (isLspEditorEnabled) { return(new VSServerCapabilities { TextDocumentSync = new TextDocumentSyncOptions { OpenClose = false, Change = TextDocumentSyncKind.None, } }); } var defaultCapabilities = _experimentalCapabilitiesProvider.GetCapabilities(clientCapabilities); // If the LSP semantic tokens feature flag is enabled, advertise no semantic tokens capabilities for this Live Share // LSP server as LSP semantic tokens requests will be serviced by the AlwaysActiveInProcLanguageClient in both local and // remote scenarios. var isLspSemanticTokenEnabled = GlobalOptions.GetOption(LspOptions.LspSemanticTokensFeatureFlag); if (isLspSemanticTokenEnabled) { defaultCapabilities.SemanticTokensOptions = null; } // When the lsp pull diagnostics feature flag is enabled we do not advertise pull diagnostics capabilities from here // as the AlwaysActivateInProcLanguageClient will provide pull diagnostics both locally and remote. var isPullDiagnosticsEnabled = GlobalOptions.IsPullDiagnostics(InternalDiagnosticsOptions.NormalDiagnosticMode); if (!isPullDiagnosticsEnabled) { // Pull diagnostics isn't enabled, let the live share server provide pull diagnostics. ((VSInternalServerCapabilities)defaultCapabilities).SupportsDiagnosticRequests = true; } return(defaultCapabilities); }
private async Task AnalyzeDocumentForKindAsync(TextDocument document, AnalysisKind kind, CancellationToken cancellationToken) { try { if (!document.SupportsDiagnostics()) { return; } var isActiveDocument = _documentTrackingService.TryGetActiveDocument() == document.Id; var isOpenDocument = document.IsOpen(); var isGeneratedRazorDocument = document.IsRazorDocument(); // Only analyze open/active documents, unless it is a generated Razor document. if (!isActiveDocument && !isOpenDocument && !isGeneratedRazorDocument) { return; } var stateSets = _stateManager.GetOrUpdateStateSets(document.Project); var compilationWithAnalyzers = await GetOrCreateCompilationWithAnalyzersAsync(document.Project, stateSets, cancellationToken).ConfigureAwait(false); var version = await GetDiagnosticVersionAsync(document.Project, cancellationToken).ConfigureAwait(false); var backgroundAnalysisScope = GlobalOptions.GetBackgroundAnalysisScope(document.Project.Language); var compilerDiagnosticsScope = GlobalOptions.GetOption(SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, document.Project.Language); // TODO: Switch to a more reliable service to determine visible documents. // DocumentTrackingService is known be unreliable at times. var isVisibleDocument = _documentTrackingService.GetVisibleDocuments().Contains(document.Id); // We split the diagnostic computation for document into following steps: // 1. Try to get cached diagnostics for each analyzer, while computing the set of analyzers that do not have cached diagnostics. // 2. Execute all the non-cached analyzers with a single invocation into CompilationWithAnalyzers. // 3. Fetch computed diagnostics per-analyzer from the above invocation, and cache and raise diagnostic reported events. // In near future, the diagnostic computation invocation into CompilationWithAnalyzers will be moved to OOP. // This should help simplify and/or remove the IDE layer diagnostic caching in devenv process. // First attempt to fetch diagnostics from the cache, while computing the state sets for analyzers that are not cached. using var _ = ArrayBuilder <StateSet> .GetInstance(out var nonCachedStateSets); foreach (var stateSet in stateSets) { var data = TryGetCachedDocumentAnalysisData(document, stateSet, kind, version, backgroundAnalysisScope, compilerDiagnosticsScope, isActiveDocument, isVisibleDocument, isOpenDocument, isGeneratedRazorDocument, cancellationToken); if (data.HasValue) { // We need to persist and raise diagnostics for suppressed analyzer. PersistAndRaiseDiagnosticsIfNeeded(data.Value, stateSet); } else { nonCachedStateSets.Add(stateSet); } } // Then, compute the diagnostics for non-cached state sets, and cache and raise diagnostic reported events for these diagnostics. if (nonCachedStateSets.Count > 0) { var analysisScope = new DocumentAnalysisScope(document, span: null, nonCachedStateSets.SelectAsArray(s => s.Analyzer), kind); var executor = new DocumentAnalysisExecutor(analysisScope, compilationWithAnalyzers, _diagnosticAnalyzerRunner, logPerformanceInfo: true, onAnalysisException: OnAnalysisException); var logTelemetry = GlobalOptions.GetOption(DiagnosticOptions.LogTelemetryForBackgroundAnalyzerExecution); foreach (var stateSet in nonCachedStateSets) { var computedData = await ComputeDocumentAnalysisDataAsync(executor, stateSet, logTelemetry, cancellationToken).ConfigureAwait(false); PersistAndRaiseDiagnosticsIfNeeded(computedData, stateSet); } } } catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } void PersistAndRaiseDiagnosticsIfNeeded(DocumentAnalysisData result, StateSet stateSet) { if (result.FromCache == true) { RaiseDocumentDiagnosticsIfNeeded(document, stateSet, kind, result.Items); return; } // no cancellation after this point. var state = stateSet.GetOrCreateActiveFileState(document.Id); state.Save(kind, result.ToPersistData()); RaiseDocumentDiagnosticsIfNeeded(document, stateSet, kind, result.OldItems, result.Items); } void OnAnalysisException() { // Do not re-use cached CompilationWithAnalyzers instance in presence of an exception, as the underlying analysis state might be corrupt. ClearCompilationsWithAnalyzersCache(document.Project); } }
protected override async Task ProduceTagsAsync( TaggerContext <InheritanceMarginTag> context, DocumentSnapshotSpan spanToTag, int?caretPosition, CancellationToken cancellationToken) { var document = spanToTag.Document; if (document == null) { return; } var inheritanceMarginInfoService = document.GetLanguageService <IInheritanceMarginService>(); if (inheritanceMarginInfoService == null) { return; } if (GlobalOptions.GetOption(FeatureOnOffOptions.ShowInheritanceMargin, document.Project.Language) == false) { return; } var includeGlobalImports = GlobalOptions.GetOption(FeatureOnOffOptions.InheritanceMarginIncludeGlobalImports, document.Project.Language); // Use FrozenSemantics Version of document to get the semantics ready, therefore we could have faster // response. (Since the full load might take a long time) // We also subscribe to CompilationAvailableTaggerEventSource, so this will finally reach the correct state. document = document.WithFrozenPartialSemantics(cancellationToken); var spanToSearch = spanToTag.SnapshotSpan.Span.ToTextSpan(); var stopwatch = SharedStopwatch.StartNew(); var inheritanceMemberItems = await inheritanceMarginInfoService.GetInheritanceMemberItemsAsync( document, spanToSearch, includeGlobalImports, cancellationToken).ConfigureAwait(false); var elapsed = stopwatch.Elapsed; if (inheritanceMemberItems.IsEmpty) { return; } InheritanceMarginLogger.LogGenerateBackgroundInheritanceInfo(elapsed); // One line might have multiple members to show, so group them. // For example: // interface IBar { void Foo1(); void Foo2(); } // class Bar : IBar { void Foo1() { } void Foo2() { } } var lineToMembers = inheritanceMemberItems.GroupBy(item => item.LineNumber); var snapshot = spanToTag.SnapshotSpan.Snapshot; foreach (var(lineNumber, membersOnTheLine) in lineToMembers) { var membersOnTheLineArray = membersOnTheLine.ToImmutableArray(); // One line should at least have one member on it. Contract.ThrowIfTrue(membersOnTheLineArray.IsEmpty); var line = snapshot.GetLineFromLineNumber(lineNumber); // We only care about the line, so just tag the start. context.AddTag(new TagSpan <InheritanceMarginTag>( new SnapshotSpan(snapshot, line.Start, length: 0), new InheritanceMarginTag(document.Project.Solution.Workspace, lineNumber, membersOnTheLineArray))); } }
private bool IsXamlLspIntelliSenseEnabled() => GlobalOptions.GetOption(XamlOptions.EnableLspIntelliSenseFeatureFlag);