diff --git a/src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/DefaultCodeDocumentProvider.cs b/src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/DefaultCodeDocumentProvider.cs index dd9e2f0781..34f06383f9 100644 --- a/src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/DefaultCodeDocumentProvider.cs +++ b/src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/DefaultCodeDocumentProvider.cs @@ -5,7 +5,6 @@ using System; using System.ComponentModel.Composition; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Razor; namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor { diff --git a/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorCodeDocumentProvider.cs b/src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/RazorCodeDocumentProvider.cs similarity index 69% rename from src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorCodeDocumentProvider.cs rename to src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/RazorCodeDocumentProvider.cs index 9eac4f8907..708385b29f 100644 --- a/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorCodeDocumentProvider.cs +++ b/src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/RazorCodeDocumentProvider.cs @@ -2,10 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis; -namespace Microsoft.CodeAnalysis.Razor +namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor { - public abstract class RazorCodeDocumentProvider + internal abstract class RazorCodeDocumentProvider { public abstract bool TryGetFromDocument(TextDocument document, out RazorCodeDocument codeDocument); } diff --git a/src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/RazorDirectiveCompletionProvider.cs b/src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/RazorDirectiveCompletionProvider.cs index 963cfbf127..8713811dba 100644 --- a/src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/RazorDirectiveCompletionProvider.cs +++ b/src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/RazorDirectiveCompletionProvider.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel.Composition; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; @@ -33,10 +34,10 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor CSharpCodeParser.RemoveTagHelperDirectiveDescriptor, CSharpCodeParser.TagHelperPrefixDirectiveDescriptor, }; - private readonly RazorCodeDocumentProvider _codeDocumentProvider; + private readonly Lazy _codeDocumentProvider; [ImportingConstructor] - public RazorDirectiveCompletionProvider(RazorCodeDocumentProvider codeDocumentProvider) + public RazorDirectiveCompletionProvider([Import(typeof(RazorCodeDocumentProvider))] Lazy codeDocumentProvider) { if (codeDocumentProvider == null) { @@ -82,7 +83,17 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor return Task.CompletedTask; } - if (!_codeDocumentProvider.TryGetFromDocument(context.Document, out var codeDocument)) + var result = AddCompletionItems(context); + + return result; + } + + // We do not want this inlined because the work done in this method requires Razor.Workspaces and Razor.Language assemblies. + // If those two assemblies were to load you'd have them load in every C# editor completion scenario. + [MethodImpl(MethodImplOptions.NoInlining)] + private Task AddCompletionItems(CompletionContext context) + { + if (!_codeDocumentProvider.Value.TryGetFromDocument(context.Document, out var codeDocument)) { // A Razor code document has not yet been associated with the document. return Task.CompletedTask; diff --git a/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Editor/RazorDirectiveCompletionProviderTest.cs b/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Editor/RazorDirectiveCompletionProviderTest.cs index 0e73407610..47179d825c 100644 --- a/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Editor/RazorDirectiveCompletionProviderTest.cs +++ b/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Editor/RazorDirectiveCompletionProviderTest.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -12,7 +13,6 @@ using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using Moq; @@ -41,7 +41,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor [RazorDirectiveCompletionProvider.DescriptionKey] = expectedDescription, }).ToImmutableDictionary()); var codeDocumentProvider = new Mock(); - var completionProvider = new RazorDirectiveCompletionProvider(codeDocumentProvider.Object); + var completionProvider = new RazorDirectiveCompletionProvider(new Lazy(() => codeDocumentProvider.Object)); // Act var description = await completionProvider.GetDescriptionAsync(document, item, CancellationToken.None); @@ -60,7 +60,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor var document = CreateDocument(); var item = CompletionItem.Create("TestDirective"); var codeDocumentProvider = new Mock(); - var completionProvider = new RazorDirectiveCompletionProvider(codeDocumentProvider.Object); + var completionProvider = new RazorDirectiveCompletionProvider(new Lazy(() => codeDocumentProvider.Object)); // Act var description = await completionProvider.GetDescriptionAsync(document, item, CancellationToken.None); @@ -75,7 +75,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor { // Arrange var codeDocumentProvider = new Mock(MockBehavior.Strict); - var completionProvider = new FailOnGetCompletionsProvider(codeDocumentProvider.Object); + var completionProvider = new FailOnGetCompletionsProvider(new Lazy(() => codeDocumentProvider.Object)); var document = CreateDocument(); document = document.WithFilePath("NotRazor.cs"); var context = CreateContext(1, completionProvider, document); @@ -92,7 +92,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor var codeDocumentProvider = new Mock(); codeDocumentProvider.Setup(provider => provider.TryGetFromDocument(It.IsAny(), out codeDocument)) .Returns(false); - var completionProvider = new FailOnGetCompletionsProvider(codeDocumentProvider.Object); + var completionProvider = new FailOnGetCompletionsProvider(new Lazy(() => codeDocumentProvider.Object)); var document = CreateDocument(); var context = CreateContext(1, completionProvider, document); @@ -162,7 +162,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor var codeDocument = TestRazorCodeDocument.CreateEmpty(); codeDocumentProvider.Setup(provider => provider.TryGetFromDocument(It.IsAny(), out codeDocument)) .Returns(true); - var completionProvider = new FailOnGetCompletionsProvider(codeDocumentProvider.Object); + var completionProvider = new FailOnGetCompletionsProvider(new Lazy(() => codeDocumentProvider.Object)); var document = CreateDocument(); var context = CreateContext(2, completionProvider, document); @@ -177,7 +177,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor var codeDocumentProvider = CreateCodeDocumentProvider("@", Enumerable.Empty()); var completionProvider = new RazorDirectiveCompletionProvider(codeDocumentProvider); var document = CreateDocument(); - codeDocumentProvider.TryGetFromDocument(document, out var codeDocument); + codeDocumentProvider.Value.TryGetFromDocument(document, out var codeDocument); var syntaxTree = codeDocument.GetSyntaxTree(); // Act @@ -198,7 +198,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor var codeDocumentProvider = CreateCodeDocumentProvider("@", new[] { SectionDirective.Directive }); var completionProvider = new RazorDirectiveCompletionProvider(codeDocumentProvider); var document = CreateDocument(); - codeDocumentProvider.TryGetFromDocument(document, out var codeDocument); + codeDocumentProvider.Value.TryGetFromDocument(document, out var codeDocument); var syntaxTree = codeDocument.GetSyntaxTree(); // Act @@ -221,7 +221,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor var codeDocumentProvider = CreateCodeDocumentProvider("@", new[] { customDirective }); var completionProvider = new RazorDirectiveCompletionProvider(codeDocumentProvider); var document = CreateDocument(); - codeDocumentProvider.TryGetFromDocument(document, out var codeDocument); + codeDocumentProvider.Value.TryGetFromDocument(document, out var codeDocument); var syntaxTree = codeDocument.GetSyntaxTree(); // Act @@ -249,7 +249,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor Assert.Equal(CompletionTags.Intrinsic, tag); } - private static RazorCodeDocumentProvider CreateCodeDocumentProvider(string text, IEnumerable directives) + private static Lazy CreateCodeDocumentProvider(string text, IEnumerable directives) { var codeDocumentProvider = new Mock(); var codeDocument = TestRazorCodeDocument.CreateEmpty(); @@ -266,7 +266,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor codeDocumentProvider.Setup(provider => provider.TryGetFromDocument(It.IsAny(), out codeDocument)) .Returns(true); - return codeDocumentProvider.Object; + return new Lazy(() => codeDocumentProvider.Object); } private static CompletionContext CreateContext(int position, RazorDirectiveCompletionProvider completionProvider, Document document) @@ -301,7 +301,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor { private readonly bool _canGetSnapshotPoint; - public FailOnGetCompletionsProvider(RazorCodeDocumentProvider codeDocumentProvider, bool canGetSnapshotPoint = true) + public FailOnGetCompletionsProvider(Lazy codeDocumentProvider, bool canGetSnapshotPoint = true) : base(codeDocumentProvider) { _canGetSnapshotPoint = canGetSnapshotPoint;