public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { return(new DefaultProjectSnapshotWorker( languageServices.WorkspaceServices.GetRequiredService <ForegroundDispatcher>(), languageServices.GetRequiredService <ProjectExtensibilityConfigurationFactory>(), languageServices.GetRequiredService <TagHelperResolver>())); }
internal LogicalDocument( SourceText sourceText, string language, Document parent, TextSpan spanInParentRootFile) { Parent = parent; SpanInParentRootFile = spanInParentRootFile; SourceText = sourceText; _languageServices = parent.Workspace.Services.GetLanguageServices(language); _lazySyntaxTree = new AsyncLazy <SyntaxTreeBase>(ct => Task.Run(() => { var syntaxTreeFactory = _languageServices.GetRequiredService <ISyntaxTreeFactoryService>(); var syntaxTree = syntaxTreeFactory.ParseSyntaxTree(sourceText, ct); // make sure there is an association between this tree and this doc id before handing it out BindSyntaxTreeToId(syntaxTree, this); return(syntaxTree); }, ct), true); _lazySemanticModel = new AsyncLazy <SemanticModelBase>(ct => Task.Run(async() => { var syntaxTree = await GetSyntaxTreeAsync(ct).ConfigureAwait(false); var compilationFactory = _languageServices.GetRequiredService <ICompilationFactoryService>(); return(compilationFactory.CreateCompilation(syntaxTree).GetSemanticModelBase(ct)); }, ct), true); }
internal Document(HostLanguageServices languageServices, DocumentId documentId, SourceText sourceText, string filePath) { _languageServices = languageServices; Id = documentId; SourceText = sourceText; FilePath = filePath; _lazySyntaxTree = new AsyncLazy <SyntaxTreeBase>(ct => Task.Run(() => { var syntaxTreeFactory = languageServices.GetRequiredService <ISyntaxTreeFactoryService>(); var syntaxTree = syntaxTreeFactory.ParseSyntaxTree(sourceText, ct); // make sure there is an association between this tree and this doc id before handing it out BindSyntaxTreeToId(syntaxTree, this.Id); return(syntaxTree); }, ct), true); _lazySemanticModel = new AsyncLazy <SemanticModelBase>(ct => Task.Run(async() => { var syntaxTree = await GetSyntaxTreeAsync(ct).ConfigureAwait(false); var compilationFactory = languageServices.GetRequiredService <ICompilationFactoryService>(); return(compilationFactory.CreateCompilation(syntaxTree).GetSemanticModelBase(ct)); }, ct), true); }
public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { if (languageServices == null) { throw new ArgumentNullException(nameof(languageServices)); } var textBufferProvider = languageServices.GetRequiredService <RazorTextBufferProvider>(); var textBufferCodeDocumentProvider = languageServices.GetRequiredService <TextBufferCodeDocumentProvider>(); return(new DefaultCodeDocumentProvider(textBufferProvider, textBufferCodeDocumentProvider)); }
/// <summary> /// Generates the LSIF content for a single document. /// </summary> /// <returns>The ID of the outputted Document vertex.</returns> /// <remarks> /// The high level algorithm here is we are going to walk across each token, produce a <see cref="Graph.Range"/> for that token's span, /// bind that token, and then link up the various features. So we'll link that range to the symbols it defines or references, /// will link it to results like Quick Info, and more. This method has a <paramref name="topLevelSymbolsResultSetTracker"/> that /// lets us link symbols across files, and will only talk about "top level" symbols that aren't things like locals that can't /// leak outside a file. /// </remarks> private static async Task <Id <Graph.LsifDocument> > GenerateForDocumentAsync( SemanticModel semanticModel, HostLanguageServices languageServices, GeneratorOptions options, IResultSetTracker topLevelSymbolsResultSetTracker, ILsifJsonWriter lsifJsonWriter, IdFactory idFactory) { var syntaxTree = semanticModel.SyntaxTree; var sourceText = semanticModel.SyntaxTree.GetText(); var syntaxFactsService = languageServices.GetRequiredService <ISyntaxFactsService>(); var semanticFactsService = languageServices.GetRequiredService <ISemanticFactsService>(); string?contentBase64Encoded = null; var uri = syntaxTree.FilePath; // TODO: move to checking the enum member mentioned in https://github.com/dotnet/roslyn/issues/49326 when that // is implemented. In the mean time, we'll use a heuristic of the path being a relative path as a way to indicate // this is a source generated file. if (!PathUtilities.IsAbsolute(syntaxTree.FilePath)) { var text = semanticModel.SyntaxTree.GetText(); // We always use UTF-8 encoding when writing out file contents, as that's expected by LSIF implementations. // TODO: when we move to .NET Core, is there a way to reduce allocations here? contentBase64Encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(text.ToString())); // There is a triple slash here, so the "host" portion of the URI is empty, similar to // how file URIs work. uri = "source-generated:///" + syntaxTree.FilePath.Replace('\\', '/'); } var documentVertex = new Graph.LsifDocument(new Uri(uri, UriKind.RelativeOrAbsolute), GetLanguageKind(semanticModel.Language), contentBase64Encoded, idFactory); lsifJsonWriter.Write(documentVertex); lsifJsonWriter.Write(new Event(Event.EventKind.Begin, documentVertex.GetId(), idFactory)); // As we are processing this file, we are going to encounter symbols that have a shared resultSet with other documents like types // or methods. We're also going to encounter locals that never leave this document. We don't want those locals being held by // the topLevelSymbolsResultSetTracker, so we'll make another tracker for document local symbols, and then have a delegating // one that picks the correct one of the two. var documentLocalSymbolsResultSetTracker = new SymbolHoldingResultSetTracker(lsifJsonWriter, semanticModel.Compilation, idFactory); var symbolResultsTracker = new DelegatingResultSetTracker(symbol => { if (symbol.Kind is SymbolKind.Local or SymbolKind.RangeVariable or SymbolKind.Label) { // These symbols can go in the document local one because they can't escape methods return(documentLocalSymbolsResultSetTracker); }
public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { return(new OOPTagHelperResolver( languageServices.GetRequiredService <RazorProjectEngineFactoryService>(), languageServices.WorkspaceServices.GetRequiredService <ErrorReporter>(), languageServices.WorkspaceServices.Workspace)); }
public static CodeGenerationOptions Create(OptionSet options, CodeGenerationOptions?fallbackOptions, HostLanguageServices languageServices) { var formattingService = languageServices.GetRequiredService <ICodeGenerationService>(); var configOptions = options.AsAnalyzerConfigOptions(languageServices.WorkspaceServices.GetRequiredService <IOptionService>(), languageServices.Language); return(formattingService.GetCodeGenerationOptions(configOptions, fallbackOptions)); }
private static TreeAndVersion CreateTreeAndVersion( ValueSource <TextAndVersion> newTextSource, ProjectId cacheKey, string?filePath, ParseOptions options, AnalyzerConfigSet analyzerConfigSet, HostLanguageServices languageServices, PreservationMode mode, TextAndVersion textAndVersion, CancellationToken cancellationToken) { var text = textAndVersion.Text; var treeFactory = languageServices.GetRequiredService <ISyntaxTreeFactoryService>(); var treeDiagnosticOptions = filePath != null?analyzerConfigSet.GetOptionsForSourcePath(filePath).TreeOptions : null; var tree = treeFactory.ParseSyntaxTree(filePath, options, text, treeDiagnosticOptions, cancellationToken); var root = tree.GetRoot(cancellationToken); if (mode == PreservationMode.PreserveValue && treeFactory.CanCreateRecoverableTree(root)) { tree = treeFactory.CreateRecoverableTree(cacheKey, tree.FilePath, tree.Options, newTextSource, text.Encoding, root, tree.DiagnosticOptions); } Contract.ThrowIfNull(tree); CheckTree(tree, text); // text version for this document should be unique. use it as a starting point. return(TreeAndVersion.Create(tree, textAndVersion.Version)); }
public static FoldingRange[] GetFoldingRanges( SyntaxTree syntaxTree, HostLanguageServices languageServices, OptionSet options, bool isMetadataAsSource, CancellationToken cancellationToken ) { var blockStructureService = (BlockStructureServiceWithProviders)languageServices.GetRequiredService <BlockStructureService>(); var blockStructure = blockStructureService.GetBlockStructure( syntaxTree, options, isMetadataAsSource, cancellationToken ); if (blockStructure == null) { return(Array.Empty <FoldingRange>()); } var text = syntaxTree.GetText(cancellationToken); return(GetFoldingRanges(blockStructure, text)); }
public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { if (languageServices == null) { throw new ArgumentNullException(nameof(languageServices)); } var errorReporter = languageServices.WorkspaceServices.GetRequiredService <ErrorReporter>(); var fileChangeTrackerFactory = languageServices.GetRequiredService <FileChangeTrackerFactory>(); var projectEngineFactoryService = languageServices.GetRequiredService <RazorProjectEngineFactoryService>(); return(new DefaultImportDocumentManager( _foregroundDispatcher, errorReporter, fileChangeTrackerFactory, projectEngineFactoryService)); }
public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { if (languageServices == null) { throw new ArgumentNullException(nameof(languageServices)); } var workspaceServices = languageServices.WorkspaceServices; var errorReporter = workspaceServices.GetRequiredService <ErrorReporter>(); var completionBroker = languageServices.GetRequiredService <VisualStudioCompletionBroker>(); var projectEngineFactoryService = languageServices.GetRequiredService <RazorProjectEngineFactoryService>(); return(new DefaultVisualStudioRazorParserFactory( _foregroundDispatcher, errorReporter, completionBroker, projectEngineFactoryService)); }
internal DocumentState UpdateTree(SyntaxNode newRoot, PreservationMode mode) { if (newRoot == null) { throw new ArgumentNullException(nameof(newRoot)); } var newTextVersion = GetNewerVersion(); var newTreeVersion = GetNewTreeVersionForUpdatedTree(newRoot, newTextVersion, mode); // determine encoding Encoding?encoding; ImmutableDictionary <string, ReportDiagnostic>?treeDiagnosticReportingOptions = null; if (TryGetSyntaxTree(out var priorTree)) { // this is most likely available since UpdateTree is normally called after modifying the existing tree. encoding = priorTree.Encoding; treeDiagnosticReportingOptions = priorTree.DiagnosticOptions; } else if (TryGetText(out var priorText)) { encoding = priorText.Encoding; } else { // the existing encoding was never observed so is unknown. encoding = null; } var syntaxTreeFactory = _languageServices.GetRequiredService <ISyntaxTreeFactoryService>(); var filePath = GetSyntaxTreeFilePath(Attributes); if (treeDiagnosticReportingOptions == null) { // Ideally we'd pass a cancellation token here but we don't have one to pass as the operation previously didn't take a cancellation token. // In practice, I don't suspect it will matter: GetValue will only do work if we haven't already computed the AnalyzerConfigSet for this project, // which would only happen if no tree was observed for any file in this project. Arbitrarily replacing trees without ever looking at the // original one is possible but unlikely. treeDiagnosticReportingOptions = _analyzerConfigSetSource.GetValue(CancellationToken.None).GetOptionsForSourcePath(filePath).TreeOptions; } Contract.ThrowIfNull(_options); var(text, tree) = CreateRecoverableTextAndTree(newRoot, filePath, newTextVersion, newTreeVersion, encoding, Attributes, _options, treeDiagnosticReportingOptions, syntaxTreeFactory, mode); return(new DocumentState( LanguageServices, solutionServices, Services, Attributes, _options, _analyzerConfigSetSource, sourceText: null, textSource: text, treeSource: new ConstantValueSource <TreeAndVersion>(tree))); }
public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { if (languageServices == null) { throw new ArgumentNullException(nameof(languageServices)); } var projectManager = languageServices.GetRequiredService <ProjectSnapshotManager>(); var workspaceEditorSettings = languageServices.GetRequiredService <WorkspaceEditorSettings>(); var importDocumentManager = languageServices.GetRequiredService <ImportDocumentManager>(); return(new DefaultVisualStudioDocumentTrackerFactory( _foregroundDispatcher, projectManager, workspaceEditorSettings, _projectService, _textDocumentFactory, importDocumentManager, languageServices.WorkspaceServices.Workspace)); }
public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { if (languageServices == null) { throw new ArgumentNullException(nameof(languageServices)); } var dispatcher = languageServices.WorkspaceServices.GetRequiredService <ForegroundDispatcher>(); var projectService = languageServices.GetRequiredService <TextBufferProjectService>(); return(new DefaultRazorDocumentManager(dispatcher, _editorFactoryService, projectService)); }
public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { if (languageServices == null) { throw new ArgumentNullException(nameof(languageServices)); } return(new DefaultProjectSnapshotManager( _foregroundDispatcher, languageServices.WorkspaceServices.GetRequiredService <ErrorReporter>(), languageServices.GetRequiredService <ProjectSnapshotWorker>(), _triggers, languageServices.WorkspaceServices.Workspace)); }
internal Document( HostLanguageServices languageServices, DocumentId documentId, SourceText sourceText, string filePath, Document parent, SourceRange?rangeInParent, TextSpan?textSpanInParent) { _languageServices = languageServices; Id = documentId; SourceText = sourceText; FilePath = filePath; var logicalDocumentFactory = languageServices.GetRequiredService <ILogicalDocumentFactory>(); LogicalDocuments = logicalDocumentFactory.GetLogicalDocuments(this).ToImmutableArray(); }
internal DocumentState UpdateTree(SyntaxNode newRoot, PreservationMode mode) { if (!SupportsSyntaxTree) { throw new InvalidOperationException(); } var newTextVersion = GetNewerVersion(); var newTreeVersion = GetNewTreeVersionForUpdatedTree(newRoot, newTextVersion, mode); // determine encoding Encoding?encoding; if (TryGetSyntaxTree(out var priorTree)) { // this is most likely available since UpdateTree is normally called after modifying the existing tree. encoding = priorTree.Encoding; } else if (TryGetText(out var priorText)) { encoding = priorText.Encoding; } else { // the existing encoding was never observed so is unknown. encoding = null; } var syntaxTreeFactory = _languageServices.GetRequiredService <ISyntaxTreeFactoryService>(); var filePath = GetSyntaxTreeFilePath(Attributes); Contract.ThrowIfNull(_options); var(text, tree) = CreateRecoverableTextAndTree(newRoot, filePath, newTextVersion, newTreeVersion, encoding, Attributes, _options, syntaxTreeFactory, mode); return(new DocumentState( LanguageServices, solutionServices, Services, Attributes, _options, sourceText: null, textSource: text, treeSource: new ConstantValueSource <TreeAndVersion>(tree))); }
public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { if (languageServices == null) { throw new ArgumentNullException(nameof(languageServices)); } var workspaceServices = languageServices.WorkspaceServices; var errorReporter = workspaceServices.GetRequiredService <ErrorReporter>(); var completionBroker = languageServices.GetRequiredService <VisualStudioCompletionBroker>(); var projectEngineFactory = workspaceServices.GetRequiredService <ProjectSnapshotProjectEngineFactory>(); return(new DefaultVisualStudioRazorParserFactory( _joinableTaskContext, errorReporter, completionBroker, projectEngineFactory)); }
internal static async Task <Hover?> GetHoverAsync( SemanticModel semanticModel, int position, HostLanguageServices languageServices, CancellationToken cancellationToken) { Debug.Assert(semanticModel.Language == LanguageNames.CSharp || semanticModel.Language == LanguageNames.VisualBasic); // Get the quick info service to compute quick info. // This code path is only invoked for C# and VB, so we can directly cast to QuickInfoServiceWithProviders. var quickInfoService = (QuickInfoServiceWithProviders)languageServices.GetRequiredService <QuickInfoService>(); var info = await quickInfoService.GetQuickInfoAsync(languageServices.WorkspaceServices.Workspace, semanticModel, position, cancellationToken).ConfigureAwait(false); if (info == null) { return(null); } var text = await semanticModel.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); return(await GetHoverAsync(info, text, semanticModel.Language, document : null, clientCapabilities : null, cancellationToken).ConfigureAwait(false)); }
/// <summary> /// Generates the LSIF content for a single document. /// </summary> /// <returns>The ID of the outputted Document vertex.</returns> /// <remarks> /// The high level algorithm here is we are going to walk across each token, produce a <see cref="Graph.Range"/> for that token's span, /// bind that token, and then link up the various features. So we'll link that range to the symbols it defines or references, /// will link it to results like Quick Info, and more. This method has a <paramref name="topLevelSymbolsResultSetTracker"/> that /// lets us link symbols across files, and will only talk about "top level" symbols that aren't things like locals that can't /// leak outside a file. /// </remarks> private static Id <Graph.Document> GenerateForDocument( SemanticModel semanticModel, HostLanguageServices languageServices, IResultSetTracker topLevelSymbolsResultSetTracker, ILsifJsonWriter lsifJsonWriter, IdFactory idFactory) { var syntaxTree = semanticModel.SyntaxTree; var sourceText = semanticModel.SyntaxTree.GetText(); var syntaxFactsService = languageServices.GetRequiredService <ISyntaxFactsService>(); var semanticFactsService = languageServices.GetRequiredService <ISemanticFactsService>(); var documentVertex = new Graph.Document(new Uri(syntaxTree.FilePath), GetLanguageKind(semanticModel.Language), idFactory); lsifJsonWriter.Write(documentVertex); lsifJsonWriter.Write(new Event(Event.EventKind.Begin, documentVertex.GetId(), idFactory)); // As we are processing this file, we are going to encounter symbols that have a shared resultSet with other documents like types // or methods. We're also going to encounter locals that never leave this document. We don't want those locals being held by // the topLevelSymbolsResultSetTracker, so we'll make another tracker for document local symbols, and then have a delegating // one that picks the correct one of the two. var documentLocalSymbolsResultSetTracker = new SymbolHoldingResultSetTracker(lsifJsonWriter, semanticModel.Compilation, idFactory); var symbolResultsTracker = new DelegatingResultSetTracker(symbol => { if (symbol.Kind == SymbolKind.Local || symbol.Kind == SymbolKind.RangeVariable || symbol.Kind == SymbolKind.Label) { // These symbols can go in the document local one because they can't escape methods return(documentLocalSymbolsResultSetTracker); } else if (symbol.ContainingType != null && symbol.DeclaredAccessibility == Accessibility.Private && symbol.ContainingType.Locations.Length == 1) { // This is a private member in a class that isn't partial, so it can't escape the file return(documentLocalSymbolsResultSetTracker); } else { return(topLevelSymbolsResultSetTracker); } }); // We will walk the file token-by-token, making a range for each one and then attaching information for it var rangeVertices = new List <Id <Graph.Range> >(); foreach (var syntaxToken in syntaxTree.GetRoot().DescendantTokens(descendIntoTrivia: true)) { // We'll only create the Range vertex once it's needed, but any number of bits of code might create it first, // so we'll just make it Lazy. var lazyRangeVertex = new Lazy <Graph.Range>(() => { var rangeVertex = Graph.Range.FromTextSpan(syntaxToken.Span, sourceText, idFactory); lsifJsonWriter.Write(rangeVertex); rangeVertices.Add(rangeVertex.GetId()); return(rangeVertex); }, LazyThreadSafetyMode.None); var declaredSymbol = semanticFactsService.GetDeclaredSymbol(semanticModel, syntaxToken, CancellationToken.None); ISymbol?referencedSymbol = null; if (syntaxFactsService.IsBindableToken(syntaxToken)) { var bindableParent = syntaxFactsService.TryGetBindableParent(syntaxToken); if (bindableParent != null) { var symbolInfo = semanticModel.GetSymbolInfo(bindableParent); if (symbolInfo.Symbol != null && IncludeSymbolInReferences(symbolInfo.Symbol)) { referencedSymbol = symbolInfo.Symbol; } } } if (declaredSymbol != null || referencedSymbol != null) { // For now, we will link the range to the original definition, preferring the definition, as this is the symbol // that would be used if we invoke a feature on this range. This is analogous to the logic in // SymbolFinder.FindSymbolAtPositionAsync where if a token is both a reference and definition we'll prefer the // definition. Once we start supporting hover we'll hae to remove the "original defintion" part of this, since // since we show different contents for different constructed types there. var symbolForLinkedResultSet = (declaredSymbol ?? referencedSymbol) !.OriginalDefinition; var symbolForLinkedResultSetId = symbolResultsTracker.GetResultSetIdForSymbol(symbolForLinkedResultSet); lsifJsonWriter.Write(Edge.Create("next", lazyRangeVertex.Value.GetId(), symbolForLinkedResultSetId, idFactory)); if (declaredSymbol != null) { var definitionResultsId = symbolResultsTracker.GetResultIdForSymbol(declaredSymbol, Methods.TextDocumentDefinitionName, () => new DefinitionResult(idFactory)); lsifJsonWriter.Write(new Item(definitionResultsId.As <DefinitionResult, Vertex>(), lazyRangeVertex.Value.GetId(), documentVertex.GetId(), idFactory)); } if (referencedSymbol != null) { // Create the link from the references back to this range. Note: this range can be reference to a // symbol but the range can point a different symbol's resultSet. This can happen if the token is // both a definition of a symbol (where we will point to the definition) but also a reference to some // other symbol. var referenceResultsId = symbolResultsTracker.GetResultIdForSymbol(referencedSymbol.OriginalDefinition, Methods.TextDocumentReferencesName, () => new ReferenceResult(idFactory)); lsifJsonWriter.Write(new Item(referenceResultsId.As <ReferenceResult, Vertex>(), lazyRangeVertex.Value.GetId(), documentVertex.GetId(), idFactory, property: "references")); } } } lsifJsonWriter.Write(Edge.Create("contains", documentVertex.GetId(), rangeVertices, idFactory)); lsifJsonWriter.Write(new Event(Event.EventKind.End, documentVertex.GetId(), idFactory)); return(documentVertex.GetId()); }
public static CodeGenerationOptions GetDefault(HostLanguageServices languageServices) => languageServices.GetRequiredService <ICodeGenerationService>().DefaultOptions;
public CSharpCodeGenerationService(HostLanguageServices languageServices) : base(languageServices.GetRequiredService <ISymbolDeclarationService>()) { }
/// <summary> /// Generates the LSIF content for a single document. /// </summary> /// <returns>The ID of the outputted Document vertex.</returns> /// <remarks> /// The high level algorithm here is we are going to walk across each token, produce a <see cref="Graph.Range"/> for that token's span, /// bind that token, and then link up the various features. So we'll link that range to the symbols it defines or references, /// will link it to results like Quick Info, and more. This method has a <paramref name="topLevelSymbolsResultSetTracker"/> that /// lets us link symbols across files, and will only talk about "top level" symbols that aren't things like locals that can't /// leak outside a file. /// </remarks> private static Id <Graph.LsifDocument> GenerateForDocument( SemanticModel semanticModel, HostLanguageServices languageServices, OptionSet options, IResultSetTracker topLevelSymbolsResultSetTracker, ILsifJsonWriter lsifJsonWriter, IdFactory idFactory) { var syntaxTree = semanticModel.SyntaxTree; var sourceText = semanticModel.SyntaxTree.GetText(); var syntaxFactsService = languageServices.GetRequiredService <ISyntaxFactsService>(); var semanticFactsService = languageServices.GetRequiredService <ISemanticFactsService>(); string?contentBase64Encoded = null; // TODO: move to checking the enum member mentioned in https://github.com/dotnet/roslyn/issues/49326 when that // is implemented. In the mean time, we'll use a heuristic of the path being a relative path as a way to indicate // this is a source generated file. if (!PathUtilities.IsAbsolute(syntaxTree.FilePath)) { var text = semanticModel.SyntaxTree.GetText(); // We always use UTF-8 encoding when writing out file contents, as that's expected by LSIF implementations. // TODO: when we move to .NET Core, is there a way to reduce allocatios here? contentBase64Encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(text.ToString())); } var documentVertex = new Graph.LsifDocument(new Uri(syntaxTree.FilePath, UriKind.RelativeOrAbsolute), GetLanguageKind(semanticModel.Language), contentBase64Encoded, idFactory); lsifJsonWriter.Write(documentVertex); lsifJsonWriter.Write(new Event(Event.EventKind.Begin, documentVertex.GetId(), idFactory)); // As we are processing this file, we are going to encounter symbols that have a shared resultSet with other documents like types // or methods. We're also going to encounter locals that never leave this document. We don't want those locals being held by // the topLevelSymbolsResultSetTracker, so we'll make another tracker for document local symbols, and then have a delegating // one that picks the correct one of the two. var documentLocalSymbolsResultSetTracker = new SymbolHoldingResultSetTracker(lsifJsonWriter, semanticModel.Compilation, idFactory); var symbolResultsTracker = new DelegatingResultSetTracker(symbol => { if (symbol.Kind == SymbolKind.Local || symbol.Kind == SymbolKind.RangeVariable || symbol.Kind == SymbolKind.Label) { // These symbols can go in the document local one because they can't escape methods return(documentLocalSymbolsResultSetTracker); } else if (symbol.ContainingType != null && symbol.DeclaredAccessibility == Accessibility.Private && symbol.ContainingType.Locations.Length == 1) { // This is a private member in a class that isn't partial, so it can't escape the file return(documentLocalSymbolsResultSetTracker); } else { return(topLevelSymbolsResultSetTracker); } }); // We will walk the file token-by-token, making a range for each one and then attaching information for it var rangeVertices = new List <Id <Graph.Range> >(); foreach (var syntaxToken in syntaxTree.GetRoot().DescendantTokens(descendIntoTrivia: true)) { // We'll only create the Range vertex once it's needed, but any number of bits of code might create it first, // so we'll just make it Lazy. var lazyRangeVertex = new Lazy <Graph.Range>(() => { var rangeVertex = Graph.Range.FromTextSpan(syntaxToken.Span, sourceText, idFactory); lsifJsonWriter.Write(rangeVertex); rangeVertices.Add(rangeVertex.GetId()); return(rangeVertex); }, LazyThreadSafetyMode.None); var declaredSymbol = semanticFactsService.GetDeclaredSymbol(semanticModel, syntaxToken, CancellationToken.None); ISymbol?referencedSymbol = null; if (syntaxFactsService.IsBindableToken(syntaxToken)) { var bindableParent = syntaxFactsService.TryGetBindableParent(syntaxToken); if (bindableParent != null) { var symbolInfo = semanticModel.GetSymbolInfo(bindableParent); if (symbolInfo.Symbol != null && IncludeSymbolInReferences(symbolInfo.Symbol)) { referencedSymbol = symbolInfo.Symbol; } } } if (declaredSymbol != null || referencedSymbol != null) { // For now, we will link the range to the original definition, preferring the definition, as this is the symbol // that would be used if we invoke a feature on this range. This is analogous to the logic in // SymbolFinder.FindSymbolAtPositionAsync where if a token is both a reference and definition we'll prefer the // definition. Once we start supporting hover we'll have to remove the "original definition" part of this, since // since we show different contents for different constructed types there. var symbolForLinkedResultSet = (declaredSymbol ?? referencedSymbol) !.OriginalDefinition; var symbolForLinkedResultSetId = symbolResultsTracker.GetResultSetIdForSymbol(symbolForLinkedResultSet); lsifJsonWriter.Write(Edge.Create("next", lazyRangeVertex.Value.GetId(), symbolForLinkedResultSetId, idFactory)); if (declaredSymbol != null) { var definitionResultsId = symbolResultsTracker.GetResultIdForSymbol(declaredSymbol, Methods.TextDocumentDefinitionName, () => new DefinitionResult(idFactory)); lsifJsonWriter.Write(new Item(definitionResultsId.As <DefinitionResult, Vertex>(), lazyRangeVertex.Value.GetId(), documentVertex.GetId(), idFactory)); } if (referencedSymbol != null) { // Create the link from the references back to this range. Note: this range can be reference to a // symbol but the range can point a different symbol's resultSet. This can happen if the token is // both a definition of a symbol (where we will point to the definition) but also a reference to some // other symbol. var referenceResultsId = symbolResultsTracker.GetResultIdForSymbol(referencedSymbol.OriginalDefinition, Methods.TextDocumentReferencesName, () => new ReferenceResult(idFactory)); lsifJsonWriter.Write(new Item(referenceResultsId.As <ReferenceResult, Vertex>(), lazyRangeVertex.Value.GetId(), documentVertex.GetId(), idFactory, property: "references")); } // Write hover information for the symbol, if edge has not already been added. // 'textDocument/hover' edge goes from the symbol ResultSet vertex to the hover result // See https://github.com/Microsoft/language-server-protocol/blob/main/indexFormat/specification.md#resultset for an example. if (symbolResultsTracker.ResultSetNeedsInformationalEdgeAdded(symbolForLinkedResultSet, Methods.TextDocumentHoverName)) { // TODO: Can we avoid the WaitAndGetResult_CanCallOnBackground call by adding a sync method to compute hover? var hover = HoverHandler.GetHoverAsync(semanticModel, syntaxToken.SpanStart, languageServices, CancellationToken.None).WaitAndGetResult_CanCallOnBackground(CancellationToken.None); if (hover != null) { var hoverResult = new HoverResult(hover, idFactory); lsifJsonWriter.Write(hoverResult); lsifJsonWriter.Write(Edge.Create(Methods.TextDocumentHoverName, symbolForLinkedResultSetId, hoverResult.GetId(), idFactory)); } } } } lsifJsonWriter.Write(Edge.Create("contains", documentVertex.GetId(), rangeVertices, idFactory)); // Write the folding ranges for the document. var foldingRanges = FoldingRangesHandler.GetFoldingRanges(syntaxTree, languageServices, options, isMetadataAsSource: false, CancellationToken.None); var foldingRangeResult = new FoldingRangeResult(foldingRanges, idFactory); lsifJsonWriter.Write(foldingRangeResult); lsifJsonWriter.Write(Edge.Create(Methods.TextDocumentFoldingRangeName, documentVertex.GetId(), foldingRangeResult.GetId(), idFactory)); lsifJsonWriter.Write(new Event(Event.EventKind.End, documentVertex.GetId(), idFactory)); return(documentVertex.GetId()); }
public static SimplifierOptions GetSimplifierOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) => languageServices.GetRequiredService <ISimplifierOptionsStorage>().GetOptions(globalOptions);
public static AddImportPlacementOptions GetAddImportPlacementOptions(this AnalyzerConfigOptions options, bool allowInHiddenRegions, AddImportPlacementOptions?fallbackOptions, HostLanguageServices languageServices) => languageServices.GetRequiredService <IAddImportsService>().GetAddImportOptions(options, allowInHiddenRegions, fallbackOptions);
public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { return(new DefaultProjectEngineFactoryService(languageServices.GetRequiredService <ProjectSnapshotManager>())); }
public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { var tagHelperFactsService = languageServices.GetRequiredService <TagHelperFactsService>(); return(new DefaultTagHelperCompletionService(tagHelperFactsService)); }
public static AddImportPlacementOptions GetAddImportPlacementOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) => languageServices.GetRequiredService <IAddImportPlacementOptionsStorage>().GetOptions(globalOptions);
public ILanguageService CreateLanguageService(HostLanguageServices languageServices) => new EmbeddedLanguageClassificationService(languageServices.GetRequiredService <IEmbeddedLanguagesProvider>());
public static IdeCodeStyleOptions GetCodeStyleOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) => languageServices.GetRequiredService <ICodeStyleOptionsStorage>().GetOptions(globalOptions);