Beispiel #1
0
 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);
        }
Beispiel #4
0
        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));
        }
Beispiel #5
0
        /// <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));
    }
Beispiel #8
0
        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));
        }
Beispiel #9
0
        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));
        }
Beispiel #11
0
        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));
        }
Beispiel #12
0
        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));
        }
Beispiel #14
0
        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));
        }
Beispiel #16
0
        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();
        }
Beispiel #17
0
        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)));
        }
Beispiel #18
0
        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));
        }
Beispiel #19
0
        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));
        }
Beispiel #20
0
        /// <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;
Beispiel #22
0
 public CSharpCodeGenerationService(HostLanguageServices languageServices)
     : base(languageServices.GetRequiredService <ISymbolDeclarationService>())
 {
 }
Beispiel #23
0
        /// <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>());
Beispiel #30
0
 public static IdeCodeStyleOptions GetCodeStyleOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices)
 => languageServices.GetRequiredService <ICodeStyleOptionsStorage>().GetOptions(globalOptions);