From 459fb2aa78c5e16dfc1eb25f078ead54d3a88fb5 Mon Sep 17 00:00:00 2001 From: Phil Allen Date: Fri, 5 Jul 2024 10:34:16 -0700 Subject: [PATCH 01/53] Update version of system.security.cryptography.xml in use in 17.10 (#10525) Analogous to !10464 --- eng/Versions.props | 1 + src/Compiler/Directory.Packages.props | 3 ++- .../Microsoft.AspNetCore.Razor.Microbenchmarks.Compiler.csproj | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index 3d60c774c8e..1a1c25d4f40 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -180,6 +180,7 @@ 5.0.0 6.0.0 6.0.0 + 6.0.1 7.0.0-preview.5.22528.1 diff --git a/src/Compiler/Directory.Packages.props b/src/Compiler/Directory.Packages.props index 38dc34f43ec..e79e7638ae8 100644 --- a/src/Compiler/Directory.Packages.props +++ b/src/Compiler/Directory.Packages.props @@ -1,4 +1,4 @@ - + diff --git a/src/Compiler/perf/Microbenchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks.Compiler.csproj b/src/Compiler/perf/Microbenchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks.Compiler.csproj index 1db9307113d..ff25b1f3ace 100644 --- a/src/Compiler/perf/Microbenchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks.Compiler.csproj +++ b/src/Compiler/perf/Microbenchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks.Compiler.csproj @@ -13,6 +13,7 @@ + From 5191c8320a4954c4433e5ce887a7c3db2b7c5ea4 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Thu, 25 Jul 2024 17:18:16 +1000 Subject: [PATCH 02/53] Switch GetHostDocumentEdits to take TextChange instead of TextEdit --- .../AbstractRazorDocumentMappingService.cs | 131 +++++++----------- .../IRazorDocumentMappingService.cs | 3 +- .../IRazorDocumentMappingServiceExtensions.cs | 12 ++ .../IRazorGeneratedDocumentExtensions.cs | 18 +++ .../VsLspExtensions_TextDocumentIdentifier.cs | 37 +++++ ...RazorCustomMessageTarget_DocumentSymbol.cs | 2 +- ...RazorCustomMessageTarget_HtmlFormatting.cs | 2 +- .../RazorCustomMessageTarget_InlayHints.cs | 2 +- .../RazorCustomMessageTarget_MapCode.cs | 2 +- .../RazorCustomMessageTarget_OnAutoInsert.cs | 2 +- .../RazorCustomMessageTarget_Rename.cs | 2 +- ...RazorCustomMessageTarget_SimplifyMethod.cs | 2 +- .../RazorCustomMessageTarget_SpellCheck.cs | 1 + ...rCustomMessageTarget_ValidateBreakpoint.cs | 2 +- .../Extensions/TextDocumentExtensions.cs | 24 +--- 15 files changed, 129 insertions(+), 113 deletions(-) create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/IRazorGeneratedDocumentExtensions.cs diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs index 03a99f532c1..9609da806c3 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.AspNetCore.Razor.PooledObjects; @@ -31,29 +32,24 @@ internal abstract class AbstractRazorDocumentMappingService( private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory ?? throw new ArgumentNullException(nameof(documentContextFactory)); private readonly ILogger _logger = logger; - public TextEdit[] GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument, TextEdit[] generatedDocumentEdits) + public IEnumerable GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument, IEnumerable generatedDocumentChanges) { - using var _1 = ListPool.GetPooledObject(out var hostDocumentEdits); - var generatedDocumentSourceText = GetGeneratedSourceText(generatedDocument); + var generatedDocumentSourceText = generatedDocument.GetGeneratedSourceText(); var lastNewLineAddedToLine = 0; - foreach (var edit in generatedDocumentEdits) + foreach (var change in generatedDocumentChanges) { - var range = edit.Range; - if (!IsRangeWithinDocument(range.ToLinePositionSpan(), generatedDocumentSourceText)) + var span = change.Span; + if (!IsSpanWithinDocument(span, generatedDocumentSourceText)) { continue; } - var startSync = generatedDocumentSourceText.TryGetAbsoluteIndex(range.Start, out var startIndex); - var endSync = generatedDocumentSourceText.TryGetAbsoluteIndex(range.End, out var endIndex); - if (startSync is false || endSync is false) - { - break; - } + generatedDocumentSourceText.GetLineAndOffset(span.Start, out var startLine, out var startCharacter); + generatedDocumentSourceText.GetLineAndOffset(span.End, out var endLine, out var endCharacter); - var mappedStart = this.TryMapToHostDocumentPosition(generatedDocument, startIndex, out Position? hostDocumentStart, out _); - var mappedEnd = this.TryMapToHostDocumentPosition(generatedDocument, endIndex, out Position? hostDocumentEnd, out _); + var mappedStart = this.TryMapToHostDocumentPosition(generatedDocument, span.Start, out var hostDocumentStart, out var hostStartIndex); + var mappedEnd = this.TryMapToHostDocumentPosition(generatedDocument, span.End, out var hostDocumentEnd, out var hostEndIndex); // Ideal case, both start and end can be mapped so just return the edit if (mappedStart && mappedEnd) @@ -61,8 +57,8 @@ public TextEdit[] GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument // If the previous edit was on the same line, and added a newline, then we need to add a space // between this edit and the previous one, because the normalization will have swallowed it. See // below for a more info. - var newText = (lastNewLineAddedToLine == range.Start.Line ? " " : "") + edit.NewText; - hostDocumentEdits.Add(VsLspFactory.CreateTextEdit(hostDocumentStart!, hostDocumentEnd!, newText)); + var newText = (lastNewLineAddedToLine == startLine ? " " : "") + change.NewText; + yield return new TextChange(TextSpan.FromBounds(hostStartIndex, hostEndIndex), newText); continue; } @@ -82,33 +78,34 @@ public TextEdit[] GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument // To indent the 'var x' line the formatter will return an edit that starts the line before, // with a NewText of '\n '. The start of that edit is outside our mapping, but we // still want to know how to format the 'var x' line, so we have to break up the edit. - if (!mappedStart && mappedEnd && range.SpansMultipleLines()) + if (!mappedStart && mappedEnd && startLine != endLine) { // Construct a theoretical edit that is just for the last line of the edit that the C# formatter // gave us, and see if we can map that. // The +1 here skips the newline character that is found, but also protects from Substring throwing // if there are no newlines (which should be impossible anyway) - var lastNewLine = edit.NewText.LastIndexOfAny(new char[] { '\n', '\r' }) + 1; + var lastNewLine = change.NewText.AssumeNotNull().LastIndexOfAny(['\n', '\r']) + 1; // Strictly speaking we could be dropping more lines than we need to, because our mapping point could be anywhere within the edit // but we know that the C# formatter will only be returning blank lines up until the first bit of content that needs to be indented // so we can ignore all but the last line. This assert ensures that is true, just in case something changes in Roslyn - Debug.Assert(lastNewLine == 0 || edit.NewText[..(lastNewLine - 1)].All(c => c == '\r' || c == '\n'), "We are throwing away part of an edit that has more than just empty lines!"); + Debug.Assert(lastNewLine == 0 || change.NewText[..(lastNewLine - 1)].All(c => c == '\r' || c == '\n'), "We are throwing away part of an edit that has more than just empty lines!"); - var proposedRange = VsLspFactory.CreateSingleLineRange(range.End.Line, character: 0, length: range.End.Character); - startSync = generatedDocumentSourceText.TryGetAbsoluteIndex(proposedRange.Start, out startIndex); - endSync = generatedDocumentSourceText.TryGetAbsoluteIndex(proposedRange.End, out endIndex); + var proposedStart = new LinePosition(endLine, 0); + var proposedEnd = new LinePosition(endLine, endCharacter); + var startSync = proposedStart.TryGetAbsoluteIndex(generatedDocumentSourceText, _logger, out var startIndex); + var endSync = proposedEnd.TryGetAbsoluteIndex(generatedDocumentSourceText, _logger, out var endIndex); if (startSync is false || endSync is false) { break; } - mappedStart = this.TryMapToHostDocumentPosition(generatedDocument, startIndex, out hostDocumentStart, out _); - mappedEnd = this.TryMapToHostDocumentPosition(generatedDocument, endIndex, out hostDocumentEnd, out _); + mappedStart = this.TryMapToHostDocumentPosition(generatedDocument, startIndex, out _, out hostStartIndex); + mappedEnd = this.TryMapToHostDocumentPosition(generatedDocument, endIndex, out _, out hostEndIndex); if (mappedStart && mappedEnd) { - hostDocumentEdits.Add(VsLspFactory.CreateTextEdit(hostDocumentStart!, hostDocumentEnd!, edit.NewText[lastNewLine..])); + yield return new TextChange(TextSpan.FromBounds(hostStartIndex, hostEndIndex), change.NewText[lastNewLine..]); continue; } } @@ -136,15 +133,15 @@ public TextEdit[] GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument // with "public class Goo" would come in as one edit for "public", one for "class" and one for "Goo", all on the same line. // When we map the edit for "public" we will push everything down a line, so we don't want to do it for other edits // on that line. - if (!mappedStart && !mappedEnd && !range.SpansMultipleLines()) + if (!mappedStart && !mappedEnd && startLine == endLine) { // If the new text doesn't have any content we don't care - throwing away invisible whitespace is fine - if (string.IsNullOrWhiteSpace(edit.NewText)) + if (string.IsNullOrWhiteSpace(change.NewText)) { continue; } - var line = generatedDocumentSourceText.Lines[range.Start.Line]; + var line = generatedDocumentSourceText.Lines[startLine]; // If the line isn't blank, then this isn't a functions directive if (line.GetFirstNonWhitespaceOffset() is not null) @@ -153,40 +150,30 @@ public TextEdit[] GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument } // Only do anything if the end of the line in question is a valid mapping point (ie, a transition) - var endOfLine = line.Span.End; - if (this.TryMapToHostDocumentPosition(generatedDocument, endOfLine, out Position? hostDocumentIndex, out _)) + if (this.TryMapToHostDocumentPosition(generatedDocument, line.Span.End, out _, out hostEndIndex)) { - if (range.Start.Line == lastNewLineAddedToLine) + if (startLine == lastNewLineAddedToLine) { // If we already added a newline to this line, then we don't want to add another one, but // we do need to add a space between this edit and the previous one, because the normalization // will have swallowed it. - hostDocumentEdits.Add(VsLspFactory.CreateTextEdit(hostDocumentIndex, " " + edit.NewText)); + yield return new TextChange(new TextSpan(hostEndIndex, 0), " " + change.NewText); } else { // Otherwise, add a newline and the real content, and remember where we added it - lastNewLineAddedToLine = range.Start.Line; - hostDocumentEdits.Add(VsLspFactory.CreateTextEdit( - hostDocumentIndex, - Environment.NewLine + new string(' ', range.Start.Character) + edit.NewText)); + lastNewLineAddedToLine = startLine; + yield return new TextChange(new TextSpan(hostEndIndex, 0), " " + Environment.NewLine + new string(' ', startCharacter) + change.NewText); } continue; } } } - - return hostDocumentEdits.ToArray(); } public bool TryMapToHostDocumentRange(IRazorGeneratedDocument generatedDocument, LinePositionSpan generatedDocumentRange, MappingBehavior mappingBehavior, out LinePositionSpan hostDocumentRange) { - if (generatedDocument is null) - { - throw new ArgumentNullException(nameof(generatedDocument)); - } - if (mappingBehavior == MappingBehavior.Strict) { return TryMapToHostDocumentRangeStrict(generatedDocument, generatedDocumentRange, out hostDocumentRange); @@ -207,11 +194,6 @@ public bool TryMapToHostDocumentRange(IRazorGeneratedDocument generatedDocument, public bool TryMapToGeneratedDocumentRange(IRazorGeneratedDocument generatedDocument, LinePositionSpan hostDocumentRange, out LinePositionSpan generatedDocumentRange) { - if (generatedDocument is null) - { - throw new ArgumentNullException(nameof(generatedDocument)); - } - if (generatedDocument.CodeDocument is not { } codeDocument) { throw new InvalidOperationException("Cannot use document mapping service on a generated document that has a null CodeDocument."); @@ -220,8 +202,8 @@ public bool TryMapToGeneratedDocumentRange(IRazorGeneratedDocument generatedDocu generatedDocumentRange = default; if (hostDocumentRange.End.Line < hostDocumentRange.Start.Line || - hostDocumentRange.End.Line == hostDocumentRange.Start.Line && - hostDocumentRange.End.Character < hostDocumentRange.Start.Character) + (hostDocumentRange.End.Line == hostDocumentRange.Start.Line && + hostDocumentRange.End.Character < hostDocumentRange.Start.Character)) { _logger.LogWarning($"RazorDocumentMappingService:TryMapToGeneratedDocumentRange original range end < start '{hostDocumentRange}'"); Debug.Fail($"RazorDocumentMappingService:TryMapToGeneratedDocumentRange original range end < start '{hostDocumentRange}'"); @@ -265,11 +247,6 @@ public bool TryMapToGeneratedDocumentRange(IRazorGeneratedDocument generatedDocu public bool TryMapToHostDocumentPosition(IRazorGeneratedDocument generatedDocument, int generatedDocumentIndex, out LinePosition hostDocumentPosition, out int hostDocumentIndex) { - if (generatedDocument is null) - { - throw new ArgumentNullException(nameof(generatedDocument)); - } - if (generatedDocument.CodeDocument is not { } codeDocument) { throw new InvalidOperationException("Cannot use document mapping service on a generated document that has a null CodeDocument."); @@ -324,11 +301,6 @@ public bool TryMapToGeneratedDocumentPosition(IRazorGeneratedDocument generatedD private static bool TryMapToGeneratedDocumentPositionInternal(IRazorGeneratedDocument generatedDocument, int hostDocumentIndex, bool nextCSharpPositionOnFailure, out LinePosition generatedPosition, out int generatedIndex) { - if (generatedDocument is null) - { - throw new ArgumentNullException(nameof(generatedDocument)); - } - if (generatedDocument.CodeDocument is not { } codeDocument) { throw new InvalidOperationException("Cannot use document mapping service on a generated document that has a null CodeDocument."); @@ -375,18 +347,13 @@ private static bool TryMapToGeneratedDocumentPositionInternal(IRazorGeneratedDoc static LinePosition GetGeneratedPosition(IRazorGeneratedDocument generatedDocument, int generatedIndex) { - var generatedSource = GetGeneratedSourceText(generatedDocument); - return generatedSource.GetLinePosition(generatedIndex); + var generatedSource = generatedDocument.GetGeneratedSourceText(); + return generatedSource.Lines.GetLinePosition(generatedIndex); } } public RazorLanguageKind GetLanguageKind(RazorCodeDocument codeDocument, int hostDocumentIndex, bool rightAssociative) { - if (codeDocument is null) - { - throw new ArgumentNullException(nameof(codeDocument)); - } - var classifiedSpans = GetClassifiedSpans(codeDocument); var tagHelperSpans = GetTagHelperSpans(codeDocument); var documentLength = codeDocument.Source.Text.Length; @@ -555,7 +522,7 @@ private bool TryMapToHostDocumentRangeStrict(IRazorGeneratedDocument generatedDo { hostDocumentRange = default; - var generatedSourceText = GetGeneratedSourceText(generatedDocument); + var generatedSourceText = generatedDocument.GetGeneratedSourceText(); var range = generatedDocumentRange; if (!IsRangeWithinDocument(range, generatedSourceText)) { @@ -594,7 +561,7 @@ private bool TryMapToHostDocumentRangeInclusive(IRazorGeneratedDocument generate hostDocumentRange = default; - var generatedSourceText = GetGeneratedSourceText(generatedDocument); + var generatedSourceText = generatedDocument.GetGeneratedSourceText(); if (!IsRangeWithinDocument(generatedDocumentRange, generatedSourceText)) { @@ -679,7 +646,7 @@ private bool TryMapToHostDocumentRangeInferred(IRazorGeneratedDocument generated // Doesn't map so lets try and infer some mappings hostDocumentRange = default; - var generatedSourceText = GetGeneratedSourceText(generatedDocument); + var generatedSourceText = generatedDocument.GetGeneratedSourceText(); if (!IsRangeWithinDocument(generatedDocumentRange, generatedSourceText)) { @@ -749,6 +716,12 @@ private bool TryMapToHostDocumentRangeInferred(IRazorGeneratedDocument generated private static bool s_haveAsserted = false; + private static bool IsSpanWithinDocument(TextSpan span, SourceText sourceText) + => span.Start >= 0 && + span.Start < sourceText.Length && + span.End is >= 0 && + span.End < sourceText.Length; + private bool IsRangeWithinDocument(LinePositionSpan range, SourceText sourceText) { // This might happen when the document that ranges were created against was not the same as the document we're consulting. @@ -794,7 +767,7 @@ private async Task RemapVersionedDocumentEditsAsync(TextDocu var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); var remappedEdits = RemapTextEditsCore(generatedDocumentUri, codeDocument, entry.Edits); - if (remappedEdits is null || remappedEdits.Length == 0) + if (remappedEdits.Length == 0) { // Nothing to do. continue; @@ -811,7 +784,7 @@ private async Task RemapVersionedDocumentEditsAsync(TextDocu }); } - return remappedDocumentEdits.ToArray(); + return [.. remappedDocumentEdits]; } private async Task> RemapDocumentEditsAsync(Dictionary changes, CancellationToken cancellationToken) @@ -836,7 +809,7 @@ private async Task> RemapDocumentEditsAsync(Dicti var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); var remappedEdits = RemapTextEditsCore(uri, codeDocument, edits); - if (remappedEdits is null || remappedEdits.Length == 0) + if (remappedEdits.Length == 0) { // Nothing to do. continue; @@ -871,7 +844,7 @@ private TextEdit[] RemapTextEditsCore(Uri generatedDocumentUri, RazorCodeDocumen remappedEdits.Add(edit); } - return remappedEdits.ToArray(); + return [.. remappedEdits]; } private IRazorGeneratedDocument? GetGeneratedDocumentFromGeneratedDocumentUri(Uri generatedDocumentUri, RazorCodeDocument codeDocument) @@ -890,16 +863,6 @@ private TextEdit[] RemapTextEditsCore(Uri generatedDocumentUri, RazorCodeDocumen } } - private static SourceText GetGeneratedSourceText(IRazorGeneratedDocument generatedDocument) - { - if (generatedDocument.CodeDocument is not { } codeDocument) - { - throw new InvalidOperationException("Cannot use document mapping service on a generated document that has a null CodeDocument."); - } - - return codeDocument.GetGeneratedSourceText(generatedDocument); - } - private static ImmutableArray GetClassifiedSpans(RazorCodeDocument document) { // Since this service is called so often, we get a good performance improvement by caching these values diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingService.cs index 358235732a6..4cbdb21a09b 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingService.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; @@ -13,7 +14,7 @@ namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; internal interface IRazorDocumentMappingService { - TextEdit[] GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument, TextEdit[] generatedDocumentEdits); + IEnumerable GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument, IEnumerable generatedDocumentEdits); bool TryMapToHostDocumentRange(IRazorGeneratedDocument generatedDocument, LinePositionSpan generatedDocumentRange, MappingBehavior mappingBehavior, out LinePositionSpan hostDocumentRange); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs index 0fdc80e24b4..6752e19c3e6 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs @@ -3,8 +3,10 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; @@ -16,6 +18,16 @@ namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; internal static class IRazorDocumentMappingServiceExtensions { + public static TextEdit[] GetHostDocumentEdits(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, TextEdit[] generatedDocumentEdits) + { + var generatedDocumentSourceText = generatedDocument.GetGeneratedSourceText(); + var documentText = generatedDocument.CodeDocument.AssumeNotNull().GetSourceText(); + + var changes = generatedDocumentEdits.Select(e => e.ToTextChange(generatedDocumentSourceText)); + var mappedChanges = service.GetHostDocumentEdits(generatedDocument, changes); + return mappedChanges.Select(c => c.ToTextEdit(documentText)).ToArray(); + } + public static bool TryMapToHostDocumentRange(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, LinePositionSpan projectedRange, out LinePositionSpan originalRange) => service.TryMapToHostDocumentRange(generatedDocument, projectedRange, MappingBehavior.Strict, out originalRange); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/IRazorGeneratedDocumentExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/IRazorGeneratedDocumentExtensions.cs new file mode 100644 index 00000000000..b58fb204e2b --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/IRazorGeneratedDocumentExtensions.cs @@ -0,0 +1,18 @@ +using System; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Razor.Workspaces; + +internal static class IRazorGeneratedDocumentExtensions +{ + public static SourceText GetGeneratedSourceText(this IRazorGeneratedDocument generatedDocument) + { + if (generatedDocument.CodeDocument is not { } codeDocument) + { + throw new InvalidOperationException("Cannot use document mapping service on a generated document that has a null CodeDocument."); + } + + return codeDocument.GetGeneratedSourceText(generatedDocument); + } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_TextDocumentIdentifier.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_TextDocumentIdentifier.cs index 44017ad6256..561a8fdbe9a 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_TextDocumentIdentifier.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_TextDocumentIdentifier.cs @@ -9,4 +9,41 @@ internal static partial class VsLspExtensions => textDocumentIdentifier is VSTextDocumentIdentifier vsIdentifier ? vsIdentifier.ProjectContext : null; + + /// + /// Returns a copy of the passed in with the passed in . + /// + public static TextDocumentIdentifier WithUri(this TextDocumentIdentifier textDocumentIdentifier, Uri uri) + { + if (textDocumentIdentifier is VSTextDocumentIdentifier vsTdi) + { + return new VSTextDocumentIdentifier + { + Uri = uri, + ProjectContext = vsTdi.ProjectContext + }; + } + + return new TextDocumentIdentifier + { + Uri = uri + }; + } + + public static RLSP.TextDocumentIdentifier WithUri(this RLSP.TextDocumentIdentifier textDocumentIdentifier, Uri uri) + { + if (textDocumentIdentifier is RLSP.VSTextDocumentIdentifier vsTdi) + { + return new RLSP.VSTextDocumentIdentifier + { + Uri = uri, + ProjectContext = vsTdi.ProjectContext + }; + } + + return new RLSP.TextDocumentIdentifier + { + Uri = uri + }; + } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_DocumentSymbol.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_DocumentSymbol.cs index 99ffec04426..1392f2b3e47 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_DocumentSymbol.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_DocumentSymbol.cs @@ -4,8 +4,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Protocol; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using StreamJsonRpc; namespace Microsoft.VisualStudio.Razor.LanguageClient.Endpoints; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_HtmlFormatting.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_HtmlFormatting.cs index a50e120f2e8..7dfc66364dc 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_HtmlFormatting.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_HtmlFormatting.cs @@ -7,8 +7,8 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.Formatting; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using StreamJsonRpc; namespace Microsoft.VisualStudio.Razor.LanguageClient.Endpoints; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_InlayHints.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_InlayHints.cs index 0930e048132..376c7cf01a0 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_InlayHints.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_InlayHints.cs @@ -4,8 +4,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Protocol; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using StreamJsonRpc; namespace Microsoft.VisualStudio.Razor.LanguageClient.Endpoints; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_MapCode.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_MapCode.cs index bf8e5a895ee..2a6f3ad7f2d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_MapCode.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_MapCode.cs @@ -4,8 +4,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Protocol; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using StreamJsonRpc; namespace Microsoft.VisualStudio.Razor.LanguageClient.Endpoints; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_OnAutoInsert.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_OnAutoInsert.cs index 603053b273d..5477b331a2b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_OnAutoInsert.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_OnAutoInsert.cs @@ -4,8 +4,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Protocol; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using StreamJsonRpc; namespace Microsoft.VisualStudio.Razor.LanguageClient.Endpoints; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Rename.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Rename.cs index 4bb2b66677d..f325ec335d0 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Rename.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Rename.cs @@ -4,8 +4,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Protocol; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using StreamJsonRpc; namespace Microsoft.VisualStudio.Razor.LanguageClient.Endpoints; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SimplifyMethod.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SimplifyMethod.cs index f1ac1f0567e..200eef05ff6 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SimplifyMethod.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SimplifyMethod.cs @@ -5,8 +5,8 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using StreamJsonRpc; namespace Microsoft.VisualStudio.Razor.LanguageClient.Endpoints; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SpellCheck.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SpellCheck.cs index ba4b1a825fc..fd9bada7650 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SpellCheck.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SpellCheck.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Protocol; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using StreamJsonRpc; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_ValidateBreakpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_ValidateBreakpoint.cs index c0e2ce15b1e..06152dc5712 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_ValidateBreakpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_ValidateBreakpoint.cs @@ -4,8 +4,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Protocol; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using StreamJsonRpc; namespace Microsoft.VisualStudio.Razor.LanguageClient.Endpoints; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/TextDocumentExtensions.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/TextDocumentExtensions.cs index 14c3bd36ce5..4bad30c426a 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/TextDocumentExtensions.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/TextDocumentExtensions.cs @@ -4,31 +4,15 @@ using System; using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; using Microsoft.VisualStudio.LanguageServer.Protocol; +using RLSP = Roslyn.LanguageServer.Protocol; namespace Microsoft.VisualStudio.Razor.LanguageClient.Extensions; internal static class TextDocumentExtensions { - /// - /// Returns a copy of the passed in with the passed in . - /// - public static TextDocumentIdentifier WithUri(this TextDocumentIdentifier textDocumentIdentifier, Uri uri) - { - if (textDocumentIdentifier is VSTextDocumentIdentifier vsTdi) - { - return new VSTextDocumentIdentifier - { - Uri = uri, - ProjectContext = vsTdi.ProjectContext - }; - } - - return new TextDocumentIdentifier - { - Uri = uri - }; - } - public static RazorTextDocumentIdentifier ToRazorTextDocumentIdentifier(this TextDocumentIdentifier textDocumentIdentifier) => new RazorTextDocumentIdentifier(textDocumentIdentifier.Uri, (textDocumentIdentifier as VSTextDocumentIdentifier)?.ProjectContext?.Id); + + public static RazorTextDocumentIdentifier ToRazorTextDocumentIdentifier(this RLSP.TextDocumentIdentifier textDocumentIdentifier) + => new RazorTextDocumentIdentifier(textDocumentIdentifier.Uri, (textDocumentIdentifier as RLSP.VSTextDocumentIdentifier)?.ProjectContext?.Id); } From 6e4cf07062d5e9daf3c0c9725c3ea36da9b62ee0 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Thu, 25 Jul 2024 17:18:46 +1000 Subject: [PATCH 03/53] Don't regenerate documents more than once for the same snapshot --- .../DocumentContextExtensions.cs | 22 +++++++++++-- .../ProjectSystem/RemoteDocumentSnapshot.cs | 33 +++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextExtensions.cs index 8bd847b64fb..b7828bf67db 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextExtensions.cs @@ -19,6 +19,12 @@ public static async Task GetGeneratedDocumentAsync(this VersionedDocum Debug.Assert(documentContext.Snapshot is RemoteDocumentSnapshot, "This method only works on document contexts created in the OOP process"); var snapshot = (RemoteDocumentSnapshot)documentContext.Snapshot; + + if (snapshot.TryGetGeneratedDocument(out var generatedDocument)) + { + return generatedDocument; + } + var razorDocument = snapshot.TextDocument; var solution = razorDocument.Project.Solution; @@ -27,13 +33,25 @@ public static async Task GetGeneratedDocumentAsync(this VersionedDocum var projectKey = razorDocument.Project.ToProjectKey(); var generatedFilePath = filePathService.GetRazorCSharpFilePath(projectKey, razorDocument.FilePath.AssumeNotNull()); var generatedDocumentId = solution.GetDocumentIdsWithFilePath(generatedFilePath).First(d => d.ProjectId == razorDocument.Project.Id); - var generatedDocument = solution.GetDocument(generatedDocumentId).AssumeNotNull(); + generatedDocument = solution.GetDocument(generatedDocumentId).AssumeNotNull(); var csharpSourceText = await documentContext.GetCSharpSourceTextAsync(cancellationToken).ConfigureAwait(false); // HACK: We're not in the same solution fork as the LSP server that provides content for this document generatedDocument = generatedDocument.WithText(csharpSourceText); - return generatedDocument; + // Obviously this lock is not sufficient to avoid wasted work, but it does at least avoid mutating the snapshot + // any more than just a once of caching of the generated document, which is what is really happening with the set + // method call below. + lock (snapshot) + { + if (snapshot.TryGetGeneratedDocument(out var generatedDocument2)) + { + return generatedDocument2; + } + + snapshot.SetGeneratedDocument(generatedDocument); + return generatedDocument; + } } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs index 165080486d4..29aedb06393 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs @@ -13,6 +13,9 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; internal class RemoteDocumentSnapshot(TextDocument textDocument, RemoteProjectSnapshot projectSnapshot) : IDocumentSnapshot { + // TODO: Delete this field when the source generator is hooked up + private Document? _generatedDocument; + private readonly TextDocument _textDocument = textDocument; private readonly RemoteProjectSnapshot _projectSnapshot = projectSnapshot; @@ -81,4 +84,34 @@ public IDocumentSnapshot WithText(SourceText text) return new RemoteDocumentSnapshot(newDocument, _projectSnapshot); } + + public bool TryGetGeneratedDocument([NotNullWhen(true)] out Document? generatedDocument) + { + // TODO: Delete this method when the source generator is hooked up + generatedDocument = _generatedDocument; + return _generatedDocument is not null; + } + + /// + /// Sets the generated C# document for this snapshot + /// + /// + /// You're right, dear reader, it's very strange for a seemingly immutable object to have a set method, but we can get away + /// with it here for some arguably tenuous reasons: + /// 1. The generated document is generated from this snapshot, and we're only allowing setting it because it could be + /// expensive to generate in the constructor. + /// 2. This is only temporary until the source generator is properly hooked up. + /// 3. If the Razor document changes, which would invalidate this generated document, then a new document snapshot would + /// be created and this instance would never be used again + /// + public void SetGeneratedDocument(Document generatedDocument) + { + // TODO: Delete this method when the source generator is hooked up + if (_generatedDocument is not null) + { + ThrowHelper.ThrowInvalidOperationException("A single document snapshot can only ever possibly have a single generated document"); + } + + _generatedDocument = generatedDocument; + } } From 2437736ced5b5c014ce15d6a65215eb542fbc458 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Thu, 25 Jul 2024 17:19:04 +1000 Subject: [PATCH 04/53] Add more services tests --- .../RazorServicesTest.cs | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Remote.Razor.Test/RazorServicesTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Remote.Razor.Test/RazorServicesTest.cs index 40215a782ac..bad7572de81 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Remote.Razor.Test/RazorServicesTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Remote.Razor.Test/RazorServicesTest.cs @@ -5,18 +5,24 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; using System.Xml; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.CodeAnalysis.Remote.Razor; +using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; +using System.Reflection.Metadata.Ecma335; namespace Microsoft.CodeAnalysis.Razor.Remote; public class RazorServicesTest(ITestOutputHelper testOutputHelper) : ToolingTestBase(testOutputHelper) { + private const string Prefix = "IRemote"; + private const string Suffix = "Service"; + private readonly static XmlDocument s_servicesFile = LoadServicesFile(); [Theory] @@ -34,6 +40,32 @@ public void JsonServicesAreListedProperly(Type serviceType, Type? callbackType) VerifyService(serviceType, callbackType); } + [Theory] + [MemberData(nameof(JsonServices))] + public void JsonServicesHaveTheRightParameters(Type serviceType, Type? _) + { + Assert.True(typeof(IRemoteJsonService).IsAssignableFrom(serviceType)); + + var found = false; + foreach (var method in serviceType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) + { + if (method.Name != "RunServiceAsync" && + method.GetParameters() is [{ ParameterType: { } parameterType }, ..]) + { + if (typeof(RazorPinnedSolutionInfoWrapper).IsAssignableFrom(parameterType)) + { + Assert.Fail($"Method {method.Name} in a Json service has a pinned solution info wrapper parameter that isn't Json serializable"); + } + else if (typeof(JsonSerializableRazorPinnedSolutionInfoWrapper).IsAssignableFrom(parameterType)) + { + found = true; + } + } + } + + Assert.True(found, "Didn't find a method to validate, which means maybe this test is invalid"); + } + [Fact] public void RazorServicesContainsAllServices() { @@ -82,16 +114,13 @@ private static XmlDocument LoadServicesFile() private static void VerifyService(Type serviceType, Type? callbackType) { - const string prefix = "IRemote"; - const string suffix = "Service"; - Assert.Null(callbackType); var serviceName = serviceType.Name; - Assert.StartsWith(prefix, serviceName); - Assert.EndsWith(suffix, serviceName); + Assert.StartsWith(Prefix, serviceName); + Assert.EndsWith(Suffix, serviceName); - var shortName = serviceName.Substring(prefix.Length, serviceName.Length - prefix.Length - suffix.Length); + var shortName = serviceName.Substring(Prefix.Length, serviceName.Length - Prefix.Length - Suffix.Length); var servicePropsEntry = $"Microsoft.VisualStudio.Razor.{shortName}"; var serviceNode = s_servicesFile.SelectSingleNode($"/Project/ItemGroup/ServiceHubService[@Include='{servicePropsEntry}']"); From f179fb92598c70cdcdadaf7c9745c69cee9605ef Mon Sep 17 00:00:00 2001 From: David Wengier Date: Thu, 25 Jul 2024 17:21:26 +1000 Subject: [PATCH 05/53] Create isolated workspaces in case tests overlap This was done because originally with inlay hints I was changing global options in Roslyn, but ended up moving away from that. Still makes sense though. --- .../RemoteWorkspaceAccessor.cs | 7 +++++++ .../Cohost/CohostEndpointTestBase.cs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteWorkspaceAccessor.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteWorkspaceAccessor.cs index f8e3087df91..8fde1707e6d 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteWorkspaceAccessor.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteWorkspaceAccessor.cs @@ -19,4 +19,11 @@ internal static class RemoteWorkspaceAccessor /// public static Workspace GetWorkspace() => RazorBrokeredServiceImplementation.GetWorkspace(); + + /// + /// Because of IVT this project is the only place that this code can exist, so please please please please please + /// only call it from tests. Thanks. + /// + public static Workspace CreateWorkspace_TestOnly() + => TestHelpers.CreateTestWorkspace(); } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTestBase.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTestBase.cs index 54d9602b0b3..91fc4fc02e1 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTestBase.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTestBase.cs @@ -94,7 +94,7 @@ protected TextDocument CreateProjectAndRazorDocument(string contents, string? fi // Importantly, we use Roslyn's remote workspace here so that when our OOP services call into Roslyn, their code // will be able to access their services. - var workspace = RemoteWorkspaceAccessor.GetWorkspace(); + var workspace = RemoteWorkspaceAccessor.CreateWorkspace_TestOnly(); var solution = workspace.CurrentSolution.AddProject(projectInfo); solution = solution From 3a21f347ded4c605f7574ceee12caf25269ff6b4 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Thu, 25 Jul 2024 17:22:22 +1000 Subject: [PATCH 06/53] Add inlay hint support to cohosting --- eng/targets/Services.props | 1 + .../InlayHints/InlayHintEndpoint.cs | 4 +- .../RazorLanguageServer.cs | 9 +- .../InlayHints/InlayHintDataWrapper.cs | 8 + .../Remote/IRemoteInlayHintService.cs | 16 ++ .../Remote/RazorServices.cs | 1 + .../InlayHints/RemoteInlayHintService.cs | 114 ++++++++++ .../Cohost/CohostInlayHintEndpoint.cs | 77 +++++++ .../Cohost/CohostInlayHintResolveEndpoint.cs | 122 ++++++++++ .../InlayHints/InlayHintEndpointTest.cs | 3 +- .../Cohost/CohostInlayHintEndpointTest.cs | 212 ++++++++++++++++++ 11 files changed, 557 insertions(+), 10 deletions(-) create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/InlayHints/InlayHintDataWrapper.cs create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/IRemoteInlayHintService.cs create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs create mode 100644 src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintEndpoint.cs create mode 100644 src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintResolveEndpoint.cs create mode 100644 src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostInlayHintEndpointTest.cs diff --git a/eng/targets/Services.props b/eng/targets/Services.props index ede89dc2165..747b8e2a392 100644 --- a/eng/targets/Services.props +++ b/eng/targets/Services.props @@ -24,5 +24,6 @@ + diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintEndpoint.cs index 3a4f746604a..1df042a9964 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintEndpoint.cs @@ -6,16 +6,14 @@ using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.AspNetCore.Razor.Threading; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.InlayHints; [RazorLanguageServerEndpoint(Methods.TextDocumentInlayHintName)] -internal sealed class InlayHintEndpoint(LanguageServerFeatureOptions featureOptions, IInlayHintService inlayHintService, IClientConnection clientConnection) +internal sealed class InlayHintEndpoint(IInlayHintService inlayHintService, IClientConnection clientConnection) : IRazorRequestHandler, ICapabilitiesProvider { - private readonly LanguageServerFeatureOptions _featureOptions = featureOptions; private readonly IInlayHintService _inlayHintService = inlayHintService; private readonly IClientConnection _clientConnection = clientConnection; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs index f6c83b1a43a..2c6eaa8cd79 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs @@ -189,6 +189,10 @@ static void AddHandlers(IServiceCollection services, LanguageServerFeatureOption services.AddHandlerWithCapabilities(); services.AddHandlerWithCapabilities(); services.AddHandlerWithCapabilities(); + + services.AddSingleton(); + services.AddHandlerWithCapabilities(); + services.AddHandler(); } services.AddHandler(); @@ -204,11 +208,6 @@ static void AddHandlers(IServiceCollection services, LanguageServerFeatureOption services.AddHandlerWithCapabilities(); services.AddHandlerWithCapabilities(); services.AddHandlerWithCapabilities(); - - services.AddSingleton(); - - services.AddHandlerWithCapabilities(); - services.AddHandler(); } } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/InlayHints/InlayHintDataWrapper.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/InlayHints/InlayHintDataWrapper.cs new file mode 100644 index 00000000000..78dd8b5f351 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/InlayHints/InlayHintDataWrapper.cs @@ -0,0 +1,8 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.Razor.Protocol.InlayHints; + +internal record class InlayHintDataWrapper(TextDocumentIdentifier TextDocument, object? OriginalData, Position OriginalPosition); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/IRemoteInlayHintService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/IRemoteInlayHintService.cs new file mode 100644 index 00000000000..978e8d0ecb8 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/IRemoteInlayHintService.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ExternalAccess.Razor; +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.Razor.Remote; + +internal interface IRemoteInlayHintService : IRemoteJsonService +{ + ValueTask GetInlayHintsAsync(JsonSerializableRazorPinnedSolutionInfoWrapper solutionInfo, JsonSerializableDocumentId razorDocumentId, InlayHintParams inlayHintParams, bool displayAllOverride, CancellationToken cancellationToken); + + ValueTask ResolveHintAsync(JsonSerializableRazorPinnedSolutionInfoWrapper solutionInfo, JsonSerializableDocumentId razorDocumentId, InlayHint inlayHint, CancellationToken cancellationToken); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/RazorServices.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/RazorServices.cs index 644881de001..47d908d75ed 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/RazorServices.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/RazorServices.cs @@ -27,6 +27,7 @@ internal static class RazorServices internal static readonly IEnumerable<(Type, Type?)> JsonServices = [ (typeof(IRemoteSignatureHelpService), null), + (typeof(IRemoteInlayHintService), null), ]; private const string ComponentName = "Razor"; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs new file mode 100644 index 00000000000..7a10c649662 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs @@ -0,0 +1,114 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.Syntax; +using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.CodeAnalysis.ExternalAccess.Razor; +using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; +using Microsoft.CodeAnalysis.Razor.DocumentMapping; +using Microsoft.CodeAnalysis.Razor.Protocol.InlayHints; +using Microsoft.CodeAnalysis.Razor.Remote; +using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.Remote.Razor; + +internal sealed partial class RemoteInlayHintService(in ServiceArgs args) : RazorDocumentServiceBase(in args), IRemoteInlayHintService +{ + internal sealed class Factory : FactoryBase + { + protected override IRemoteInlayHintService CreateService(in ServiceArgs args) + => new RemoteInlayHintService(in args); + } + + private readonly IRazorDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); + private readonly IFilePathService _filePathService = args.ExportProvider.GetExportedValue(); + + public ValueTask GetInlayHintsAsync(JsonSerializableRazorPinnedSolutionInfoWrapper solutionInfo, JsonSerializableDocumentId razorDocumentId, InlayHintParams inlayHintParams, bool displayAllOverride, CancellationToken cancellationToken) + => RunServiceAsync( + solutionInfo, + razorDocumentId, + context => GetInlayHintsAsync(context, inlayHintParams, displayAllOverride, cancellationToken), + cancellationToken); + + private async ValueTask GetInlayHintsAsync(RemoteDocumentContext context, InlayHintParams inlayHintParams, bool displayAllOverride, CancellationToken cancellationToken) + { + var codeDocument = await context.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + var csharpDocument = codeDocument.GetCSharpDocument(); + + var span = inlayHintParams.Range.ToLinePositionSpan(); + + // We are given a range by the client, but our mapping only succeeds if the start and end of the range can both be mapped + // to C#. Since that doesn't logically match what we want from inlay hints, we instead get the minimum range of mappable + // C# to get hints for. We'll filter that later, to remove the sections that can't be mapped back. + if (!_documentMappingService.TryMapToGeneratedDocumentRange(csharpDocument, span, out var projectedLinePositionSpan) && + !codeDocument.TryGetMinimalCSharpRange(span, out projectedLinePositionSpan)) + { + // There's no C# in the range. + return null; + } + + var generatedDocument = await context.GetGeneratedDocumentAsync(_filePathService, cancellationToken).ConfigureAwait(false); + + var textDocument = inlayHintParams.TextDocument.WithUri(generatedDocument.CreateUri()); + var range = projectedLinePositionSpan.ToRLSPRange(); + + var hints = await InlayHints.GetInlayHintsAsync(generatedDocument, textDocument, range, displayAllOverride, cancellationToken).ConfigureAwait(false); + + if (hints is null) + { + return null; + } + + using var inlayHintsBuilder = new PooledArrayBuilder(); + var razorSourceText = codeDocument.Source.Text; + var csharpSourceText = codeDocument.GetCSharpSourceText(); + var syntaxTree = codeDocument.GetSyntaxTree(); + foreach (var hint in hints) + { + if (hint.Position.ToLinePosition().TryGetAbsoluteIndex(csharpSourceText, null, out var absoluteIndex) && + _documentMappingService.TryMapToHostDocumentPosition(csharpDocument, absoluteIndex, out var hostDocumentPosition, out var hostDocumentIndex)) + { + // We know this C# maps to Razor, but does it map to Razor that we like? + var node = syntaxTree.Root.FindInnermostNode(hostDocumentIndex); + if (node?.FirstAncestorOrSelf() is not null) + { + continue; + } + + if (hint.TextEdits is not null) + { + var changes = hint.TextEdits.Select(e => e.ToTextChange(csharpSourceText)); + var mappedChanges = _documentMappingService.GetHostDocumentEdits(csharpDocument, changes); + hint.TextEdits = mappedChanges.Select(c => c.ToRLSPTextEdit(razorSourceText)).ToArray(); + } + + hint.Data = new InlayHintDataWrapper(inlayHintParams.TextDocument, hint.Data, hint.Position); + hint.Position = hostDocumentPosition.ToRLSPPosition(); + + inlayHintsBuilder.Add(hint); + } + } + + return inlayHintsBuilder.ToArray(); + } + + public ValueTask ResolveHintAsync(JsonSerializableRazorPinnedSolutionInfoWrapper solutionInfo, JsonSerializableDocumentId razorDocumentId, InlayHint inlayHint, CancellationToken cancellationToken) + => RunServiceAsync( + solutionInfo, + razorDocumentId, + context => ResolveInlayHintAsync(context, inlayHint, cancellationToken), + cancellationToken); + + private async ValueTask ResolveInlayHintAsync(RemoteDocumentContext context, InlayHint inlayHint, CancellationToken cancellationToken) + { + var generatedDocument = await context.GetGeneratedDocumentAsync(_filePathService, cancellationToken).ConfigureAwait(false); + + return await InlayHints.ResolveInlayHintAsync(generatedDocument, inlayHint, cancellationToken).ConfigureAwait(false); + } +} diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintEndpoint.cs new file mode 100644 index 00000000000..e5f361f55df --- /dev/null +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintEndpoint.cs @@ -0,0 +1,77 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; +using Microsoft.CodeAnalysis.Razor.Remote; +using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; +using Roslyn.LanguageServer.Protocol; +using VSLSP = Microsoft.VisualStudio.LanguageServer.Protocol; + +namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost; + +#pragma warning disable RS0030 // Do not use banned APIs +[Shared] +[CohostEndpoint(Methods.TextDocumentInlayHintName)] +[Export(typeof(IDynamicRegistrationProvider))] +[ExportCohostStatelessLspService(typeof(CohostInlayHintEndpoint))] +[method: ImportingConstructor] +#pragma warning restore RS0030 // Do not use banned APIs +internal class CohostInlayHintEndpoint(IRemoteServiceInvoker remoteServiceInvoker) + : AbstractRazorCohostDocumentRequestHandler, IDynamicRegistrationProvider +{ + private readonly IRemoteServiceInvoker _remoteServiceInvoker = remoteServiceInvoker; + + protected override bool MutatesSolutionState => false; + + protected override bool RequiresLSPSolution => true; + + public VSLSP.Registration? GetRegistration(VSLSP.VSInternalClientCapabilities clientCapabilities, VSLSP.DocumentFilter[] filter, RazorCohostRequestContext requestContext) + { + if (clientCapabilities.TextDocument?.InlayHint?.DynamicRegistration == true) + { + return new VSLSP.Registration + { + Method = Methods.TextDocumentInlayHintName, + RegisterOptions = new VSLSP.InlayHintRegistrationOptions() + { + DocumentSelector = filter + } + }; + } + + return null; + } + + protected override RazorTextDocumentIdentifier? GetRazorTextDocumentIdentifier(InlayHintParams request) + => request.TextDocument.ToRazorTextDocumentIdentifier(); + + protected override Task HandleRequestAsync(InlayHintParams request, RazorCohostRequestContext context, CancellationToken cancellationToken) + { + // TODO: Once the platform team have finished the work, check the "Show inlay hints while key pressed" option, and pass it along + return HandleRequestAsync(request, context.TextDocument.AssumeNotNull(), displayAllOverride: false, cancellationToken); + } + + private async Task HandleRequestAsync(InlayHintParams request, TextDocument razorDocument, bool displayAllOverride, CancellationToken cancellationToken) + { + // Normally we could remove the await here, but in this case it neatly converts from ValueTask to Task for us, + // and more importantly this method is essentially a public API entry point (via LSP) so having it appear in + // call stacks is desirable + return await _remoteServiceInvoker.TryInvokeAsync( + razorDocument.Project.Solution, + (service, solutionInfo, cancellationToken) => service.GetInlayHintsAsync(solutionInfo, razorDocument.Id, request, displayAllOverride, cancellationToken), + cancellationToken).ConfigureAwait(false); + } + + internal TestAccessor GetTestAccessor() => new(this); + + internal readonly struct TestAccessor(CohostInlayHintEndpoint instance) + { + public Task HandleRequestAsync(InlayHintParams request, TextDocument razorDocument, bool displayAllOverride, CancellationToken cancellationToken) + => instance.HandleRequestAsync(request, razorDocument, displayAllOverride, cancellationToken); + } +} diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintResolveEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintResolveEndpoint.cs new file mode 100644 index 00000000000..46c2cbcdefc --- /dev/null +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintResolveEndpoint.cs @@ -0,0 +1,122 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Composition; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; +using Microsoft.CodeAnalysis.Razor.Logging; +using Microsoft.CodeAnalysis.Razor.Protocol.InlayHints; +using Microsoft.CodeAnalysis.Razor.Remote; +using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; +using Roslyn.LanguageServer.Protocol; +using VSLSP = Microsoft.VisualStudio.LanguageServer.Protocol; + +namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost; + +#pragma warning disable RS0030 // Do not use banned APIs +[Shared] +[CohostEndpoint(Methods.InlayHintResolveName)] +[Export(typeof(IDynamicRegistrationProvider))] +[ExportCohostStatelessLspService(typeof(CohostInlayHintResolveEndpoint))] +[method: ImportingConstructor] +#pragma warning restore RS0030 // Do not use banned APIs +internal class CohostInlayHintResolveEndpoint(IRemoteServiceInvoker remoteServiceInvoker, ILoggerFactory loggerFactory) + : AbstractRazorCohostDocumentRequestHandler, IDynamicRegistrationProvider +{ + private readonly IRemoteServiceInvoker _remoteServiceInvoker = remoteServiceInvoker; + private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); + + protected override bool MutatesSolutionState => false; + + protected override bool RequiresLSPSolution => true; + + public VSLSP.Registration? GetRegistration(VSLSP.VSInternalClientCapabilities clientCapabilities, VSLSP.DocumentFilter[] filter, RazorCohostRequestContext requestContext) + { + if (clientCapabilities.TextDocument?.InlayHint?.DynamicRegistration == true) + { + return new VSLSP.Registration + { + Method = Methods.TextDocumentInlayHintName, + RegisterOptions = new VSLSP.InlayHintRegistrationOptions() + { + DocumentSelector = filter + } + }; + } + + return null; + } + + protected override RazorTextDocumentIdentifier? GetRazorTextDocumentIdentifier(InlayHint request) + => GetTextDocumentIdentifier(request)?.ToRazorTextDocumentIdentifier() ?? null; + + private TextDocumentIdentifier? GetTextDocumentIdentifier(InlayHint request) + { + var data = GetInlayHintResolveData(request); + if (data is null) + { + _logger.LogError($"Got a resolve request for an inlay hint but couldn't extract the data object. Raw data is: {request.Data}"); + return null; + } + + return data.TextDocument; + } + + protected override Task HandleRequestAsync(InlayHint request, RazorCohostRequestContext context, CancellationToken cancellationToken) + => HandleRequestAsync(request, context.TextDocument.AssumeNotNull(), cancellationToken); + + private async Task HandleRequestAsync(InlayHint request, TextDocument razorDocument, CancellationToken cancellationToken) + { + var razorData = GetInlayHintResolveData(request).AssumeNotNull(); + var razorPosition = request.Position; + request.Data = razorData.OriginalData; + request.Position = razorData.OriginalPosition; + + var hint = await _remoteServiceInvoker.TryInvokeAsync( + razorDocument.Project.Solution, + (service, solutionInfo, cancellationToken) => service.ResolveHintAsync(solutionInfo, razorDocument.Id, request, cancellationToken), + cancellationToken).ConfigureAwait(false); + + if (hint is null) + { + return null; + } + + Debug.Assert(request.Position == hint.Position, "Resolving inlay hints should not change the position of them."); + hint.Position = razorPosition; + + return hint; + } + + private static InlayHintDataWrapper? GetInlayHintResolveData(InlayHint inlayHint) + { + if (inlayHint.Data is InlayHintDataWrapper) + { + return (InlayHintDataWrapper)inlayHint.Data; + } + + if (inlayHint.Data is JsonElement json) + { + return JsonSerializer.Deserialize(json); + } + + return null; + } + + internal TestAccessor GetTestAccessor() => new(this); + + internal readonly struct TestAccessor(CohostInlayHintResolveEndpoint instance) + { + public TextDocumentIdentifier? GetTextDocumentIdentifier(InlayHint request) + => instance.GetTextDocumentIdentifier(request); + + public Task HandleRequestAsync(InlayHint request, TextDocument razorDocument, CancellationToken cancellationToken) + => instance.HandleRequestAsync(request, razorDocument, cancellationToken); + } +} diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/InlayHints/InlayHintEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/InlayHints/InlayHintEndpointTest.cs index 82b4e407c2d..49e8758c700 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/InlayHints/InlayHintEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/InlayHints/InlayHintEndpointTest.cs @@ -6,7 +6,6 @@ using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; @@ -96,7 +95,7 @@ private async Task VerifyInlayHintsAsync(string input, Dictionary VerifyInlayHintsAsync( + input: """ + +
+ + @functions { + private void M(string thisIsMyString) + { + var {|int:x|} = 5; + + var {|string:y|} = "Hello"; + + M({|thisIsMyString:"Hello"|}); + } + } + + """, + toolTipMap: new Dictionary + { + { "int", "struct System.Int32" }, + { "string", "class System.String" }, + { "thisIsMyString", "(parameter) string thisIsMyStr" } + }, + output: """ + +
+ + @functions { + private void M(string thisIsMyString) + { + int x = 5; + + string y = "Hello"; + + M(thisIsMyString: "Hello"); + } + } + + """); + + [Fact] + public Task InlayHints_DisplayAllOverride() + => VerifyInlayHintsAsync( + input: """ + +
+ + @functions { + private void M(string thisIsMyString) + { + {|int:var|} x = 5; + + {|string:var|} y = "Hello"; + + M({|thisIsMyString:"Hello"|}); + } + } + + """, + toolTipMap: new Dictionary + { + { "int", "struct System.Int32" }, + { "string", "class System.String" }, + { "thisIsMyString", "(parameter) string thisIsMyStr" } + }, + output: """ + +
+ + @functions { + private void M(string thisIsMyString) + { + int x = 5; + + string y = "Hello"; + + M(thisIsMyString: "Hello"); + } + } + + """, + displayAllOverride: true); + + + [Fact] + public Task InlayHints_ComponentAttributes() + => VerifyInlayHintsAsync( + input: """ + +
+ + + +
+ + """, + toolTipMap: new Dictionary + { + }, + output: """ + +
+ + + +
+ + """); + + private async Task VerifyInlayHintsAsync(string input, Dictionary toolTipMap, string output, bool displayAllOverride = false) + { + TestFileMarkupParser.GetSpans(input, out input, out ImmutableDictionary> spansDict); + var document = CreateProjectAndRazorDocument(input); + var inputText = await document.GetTextAsync(DisposalToken); + + var endpoint = new CohostInlayHintEndpoint(RemoteServiceInvoker); + var resolveEndpoint = new CohostInlayHintResolveEndpoint(RemoteServiceInvoker, LoggerFactory); + + var request = new InlayHintParams() + { + TextDocument = new TextDocumentIdentifier() { Uri = document.CreateUri() }, + Range = new() + { + Start = new(0, 0), + End = new(inputText.Lines.Count, 0) + } + }; + + var hints = await endpoint.GetTestAccessor().HandleRequestAsync(request, document, displayAllOverride, DisposalToken); + + // Assert + Assert.NotNull(hints); + Assert.Equal(spansDict.Values.Count(), hints.Length); + + foreach (var hint in hints) + { + // Because our test input data can't have colons in the input, but parameter info returned from Roslyn does, we have to strip them off. + var label = hint.Label.First.TrimEnd(':'); + Assert.True(spansDict.TryGetValue(label, out var spans), $"Expected {label} to be in test provided markers"); + + var span = Assert.Single(spans); + var expectedRange = span.ToRLSPRange(inputText); + // Inlay hints only have a position, so we ignore the end of the range that comes from the test input + Assert.Equal(expectedRange.Start, hint.Position); + + // This looks weird, but its what we have to do to satisfy the compiler :) + string? expectedTooltip = null; + Assert.True(toolTipMap?.TryGetValue(label, out expectedTooltip)); + Assert.NotNull(expectedTooltip); + + // We need to pretend we're making real LSP requests by serializing the data blob at least + var serializedHint = JsonSerializer.Deserialize(JsonSerializer.SerializeToElement(hint)).AssumeNotNull(); + // Make sure we can resolve the document correctly + var tdi = resolveEndpoint.GetTestAccessor().GetTextDocumentIdentifier(serializedHint); + Assert.NotNull(tdi); + Assert.Equal(document.CreateUri(), tdi.Uri); + + // Make sure we, or really Roslyn, can resolve the hint correctly + var resolvedHint = await resolveEndpoint.GetTestAccessor().HandleRequestAsync(serializedHint, document, DisposalToken); + Assert.NotNull(resolvedHint); + Assert.NotNull(resolvedHint.ToolTip); + + if (resolvedHint.ToolTip.Value.TryGetFirst(out var plainTextTooltip)) + { + Assert.Equal(expectedTooltip, plainTextTooltip); + } + else if (resolvedHint.ToolTip.Value.TryGetSecond(out var markupTooltip)) + { + Assert.Contains(expectedTooltip, markupTooltip.Value); + } + } + + // To validate edits, we have to collect them all together, and apply them backwards + var edits = hints + .SelectMany(h => h.TextEdits ?? []) + .OrderByDescending(e => e.Range.Start.Line) + .ThenByDescending(e => e.Range.Start.Character) + .ToArray(); + foreach (var edit in edits) + { + var change = edit.ToTextChange(inputText); + inputText = inputText.WithChanges(change); + } + + AssertEx.EqualOrDiff(output, inputText.ToString()); + } +} From 51756c1a79806daaeaa9529211b2a61fc0176c14 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Thu, 25 Jul 2024 17:22:40 +1000 Subject: [PATCH 07/53] Cleanup --- .../LanguageClient/Cohost/CohostSignatureHelpEndpoint.cs | 1 + .../Completion/TestDocumentMappingService.cs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSignatureHelpEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSignatureHelpEndpoint.cs index 1acfee411eb..76073f37a38 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSignatureHelpEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSignatureHelpEndpoint.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Remote; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.LanguageClient; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs index 2e384656518..4d19dee877a 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; @@ -18,8 +19,8 @@ internal class TestDocumentMappingService : IRazorDocumentMappingService public LinePosition? GeneratedPosition { get; set; } public int GeneratedIndex { get; set; } - public TextEdit[] GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument, TextEdit[] generatedDocumentEdits) - => Array.Empty(); + public IEnumerable GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument, IEnumerable generatedDocumentEdits) + => []; public RazorLanguageKind GetLanguageKind(RazorCodeDocument codeDocument, int hostDocumentIndex, bool rightAssociative) => LanguageKind; From ed53daf7c4ddccf5886eac3b3185644695811c5f Mon Sep 17 00:00:00 2001 From: David Wengier Date: Thu, 25 Jul 2024 17:30:07 +1000 Subject: [PATCH 08/53] Cleanup --- .../LanguageClient/Cohost/CohostInlayHintResolveEndpoint.cs | 1 - .../LanguageClient/Cohost/CohostSignatureHelpEndpoint.cs | 1 - .../Endpoints/RazorCustomMessageTarget_Completion.cs | 1 - .../Endpoints/RazorCustomMessageTarget_Diagnostics.cs | 1 - .../Endpoints/RazorCustomMessageTarget_FoldingRange.cs | 1 - .../Endpoints/RazorCustomMessageTarget_SpellCheck.cs | 1 - .../LanguageClient/Extensions/TextDocumentExtensions.cs | 1 - 7 files changed, 7 deletions(-) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintResolveEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintResolveEndpoint.cs index 46c2cbcdefc..a0410382983 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintResolveEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintResolveEndpoint.cs @@ -3,7 +3,6 @@ using System.Composition; using System.Diagnostics; -using System.Diagnostics.Contracts; using System.Text.Json; using System.Threading; using System.Threading.Tasks; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSignatureHelpEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSignatureHelpEndpoint.cs index 76073f37a38..22a7035793b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSignatureHelpEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSignatureHelpEndpoint.cs @@ -16,7 +16,6 @@ using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.LanguageClient; using Microsoft.VisualStudio.Razor.LanguageClient.Cohost; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using Microsoft.VisualStudio.Razor.Settings; using static Roslyn.LanguageServer.Protocol.RoslynLspExtensions; using RoslynLspFactory = Roslyn.LanguageServer.Protocol.RoslynLspFactory; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs index 6f86ccd57dd..21bf886e1ba 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Razor.Protocol.Completion; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using Microsoft.VisualStudio.Razor.Snippets; using StreamJsonRpc; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs index 0ac519a37af..3329cf7980e 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Razor.Protocol.Diagnostics; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using StreamJsonRpc; namespace Microsoft.VisualStudio.Razor.LanguageClient.Endpoints; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_FoldingRange.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_FoldingRange.cs index a9be7721d86..4aff2d9d5f0 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_FoldingRange.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_FoldingRange.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.Folding; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using StreamJsonRpc; namespace Microsoft.VisualStudio.Razor.LanguageClient.Endpoints; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SpellCheck.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SpellCheck.cs index fd9bada7650..f6b3ed8d50b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SpellCheck.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SpellCheck.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using StreamJsonRpc; namespace Microsoft.VisualStudio.Razor.LanguageClient.Endpoints; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/TextDocumentExtensions.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/TextDocumentExtensions.cs index 4bad30c426a..5ecffa0214c 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/TextDocumentExtensions.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/TextDocumentExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; using Microsoft.VisualStudio.LanguageServer.Protocol; using RLSP = Roslyn.LanguageServer.Protocol; From 0fe459e8e76456a3464710618f3e77abefaa20c0 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Thu, 25 Jul 2024 21:58:29 +1000 Subject: [PATCH 09/53] Fixes after rebasing on new extensions/conversions API --- .../AbstractRazorDocumentMappingService.cs | 23 ++++------- .../IRazorDocumentMappingServiceExtensions.cs | 6 +-- .../IRazorGeneratedDocumentExtensions.cs | 3 +- .../RoslynLspExtensions_SourceText.cs | 23 +++++++++++ ...lynLspExtensions_TextDocumentIdentifier.cs | 33 +++++++++++++++ .../VsLspExtensions_TextDocumentIdentifier.cs | 21 +++------- .../InlayHints/RemoteInlayHintService.cs | 11 ++--- ...stDocumentHighlightPresentationEndpoint.cs | 1 - .../Cohost/CohostFoldingRangeEndpoint.cs | 1 - .../Cohost/CohostInlayHintEndpoint.cs | 1 - .../Cohost/CohostInlayHintResolveEndpoint.cs | 5 +-- .../CohostLinkedEditingRangeEndpoint.cs | 5 +-- .../CohostSemanticTokensRangeEndpoint.cs | 6 +-- .../Cohost/CohostUriPresentationEndpoint.cs | 1 - .../RazorCohostRequestContextExtensions.cs | 41 ------------------- .../Extensions/TextDocumentExtensions.cs | 17 -------- .../Cohost/CohostInlayHintEndpointTest.cs | 18 +++----- .../CohostLinkedEditingRangeEndpointTest.cs | 2 +- .../CohostSemanticTokensRangeEndpointTest.cs | 4 +- 19 files changed, 89 insertions(+), 133 deletions(-) create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_SourceText.cs create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_TextDocumentIdentifier.cs delete mode 100644 src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/RazorCohostRequestContextExtensions.cs delete mode 100644 src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/TextDocumentExtensions.cs diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs index 9609da806c3..fddca113c15 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs @@ -40,13 +40,14 @@ public IEnumerable GetHostDocumentEdits(IRazorGeneratedDocument gene foreach (var change in generatedDocumentChanges) { var span = change.Span; - if (!IsSpanWithinDocument(span, generatedDocumentSourceText)) + // Deliberately doing a naive check to avoid telemetry for truly bad data + if (span.Start <= 0 || span.Start >= generatedDocumentSourceText.Length || span.End <= 0 || span.End >= generatedDocumentSourceText.Length) { continue; } - generatedDocumentSourceText.GetLineAndOffset(span.Start, out var startLine, out var startCharacter); - generatedDocumentSourceText.GetLineAndOffset(span.End, out var endLine, out var endCharacter); + var (startLine, startChar) = generatedDocumentSourceText.GetLinePosition(span.Start); + var (endLine, _) = generatedDocumentSourceText.GetLinePosition(span.End); var mappedStart = this.TryMapToHostDocumentPosition(generatedDocument, span.Start, out var hostDocumentStart, out var hostStartIndex); var mappedEnd = this.TryMapToHostDocumentPosition(generatedDocument, span.End, out var hostDocumentEnd, out var hostEndIndex); @@ -91,17 +92,13 @@ public IEnumerable GetHostDocumentEdits(IRazorGeneratedDocument gene // so we can ignore all but the last line. This assert ensures that is true, just in case something changes in Roslyn Debug.Assert(lastNewLine == 0 || change.NewText[..(lastNewLine - 1)].All(c => c == '\r' || c == '\n'), "We are throwing away part of an edit that has more than just empty lines!"); - var proposedStart = new LinePosition(endLine, 0); - var proposedEnd = new LinePosition(endLine, endCharacter); - var startSync = proposedStart.TryGetAbsoluteIndex(generatedDocumentSourceText, _logger, out var startIndex); - var endSync = proposedEnd.TryGetAbsoluteIndex(generatedDocumentSourceText, _logger, out var endIndex); - if (startSync is false || endSync is false) + var startSync = generatedDocumentSourceText.TryGetAbsoluteIndex((endLine, 0), out var startIndex); + if (startSync is false) { break; } mappedStart = this.TryMapToHostDocumentPosition(generatedDocument, startIndex, out _, out hostStartIndex); - mappedEnd = this.TryMapToHostDocumentPosition(generatedDocument, endIndex, out _, out hostEndIndex); if (mappedStart && mappedEnd) { @@ -163,7 +160,7 @@ public IEnumerable GetHostDocumentEdits(IRazorGeneratedDocument gene { // Otherwise, add a newline and the real content, and remember where we added it lastNewLineAddedToLine = startLine; - yield return new TextChange(new TextSpan(hostEndIndex, 0), " " + Environment.NewLine + new string(' ', startCharacter) + change.NewText); + yield return new TextChange(new TextSpan(hostEndIndex, 0), " " + Environment.NewLine + new string(' ', startChar) + change.NewText); } continue; @@ -716,12 +713,6 @@ private bool TryMapToHostDocumentRangeInferred(IRazorGeneratedDocument generated private static bool s_haveAsserted = false; - private static bool IsSpanWithinDocument(TextSpan span, SourceText sourceText) - => span.Start >= 0 && - span.Start < sourceText.Length && - span.End is >= 0 && - span.End < sourceText.Length; - private bool IsRangeWithinDocument(LinePositionSpan range, SourceText sourceText) { // This might happen when the document that ranges were created against was not the same as the document we're consulting. diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs index 6752e19c3e6..9ead7ef2509 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs @@ -21,11 +21,11 @@ internal static class IRazorDocumentMappingServiceExtensions public static TextEdit[] GetHostDocumentEdits(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, TextEdit[] generatedDocumentEdits) { var generatedDocumentSourceText = generatedDocument.GetGeneratedSourceText(); - var documentText = generatedDocument.CodeDocument.AssumeNotNull().GetSourceText(); + var documentText = generatedDocument.CodeDocument.AssumeNotNull().Source.Text; - var changes = generatedDocumentEdits.Select(e => e.ToTextChange(generatedDocumentSourceText)); + var changes = generatedDocumentEdits.Select(generatedDocumentSourceText.GetTextChange); var mappedChanges = service.GetHostDocumentEdits(generatedDocument, changes); - return mappedChanges.Select(c => c.ToTextEdit(documentText)).ToArray(); + return mappedChanges.Select(documentText.GetTextEdit).ToArray(); } public static bool TryMapToHostDocumentRange(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, LinePositionSpan projectedRange, out LinePositionSpan originalRange) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/IRazorGeneratedDocumentExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/IRazorGeneratedDocumentExtensions.cs index b58fb204e2b..214efe87b4d 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/IRazorGeneratedDocumentExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/IRazorGeneratedDocumentExtensions.cs @@ -1,8 +1,7 @@ using System; -using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Razor.Workspaces; +namespace Microsoft.AspNetCore.Razor.Language; internal static class IRazorGeneratedDocumentExtensions { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_SourceText.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_SourceText.cs new file mode 100644 index 00000000000..fbeb95c1b9f --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_SourceText.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Razor; +using Microsoft.CodeAnalysis.Text; + +namespace Roslyn.LanguageServer.Protocol; + +internal static partial class RoslynLspExtensions +{ + public static Range GetRange(this SourceText text, TextSpan span) + => text.GetLinePositionSpan(span).ToRange(); + + public static TextSpan GetTextSpan(this SourceText text, Range range) + => text.GetTextSpan(range.Start.Line, range.Start.Character, range.End.Line, range.End.Character); + + public static TextChange GetTextChange(this SourceText text, TextEdit edit) + => new(text.GetTextSpan(edit.Range), edit.NewText); + + public static TextEdit GetTextEdit(this SourceText text, TextChange change) + => RoslynLspFactory.CreateTextEdit(text.GetRange(change.Span), change.NewText.AssumeNotNull()); + +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_TextDocumentIdentifier.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_TextDocumentIdentifier.cs new file mode 100644 index 00000000000..1d610d572d3 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_TextDocumentIdentifier.cs @@ -0,0 +1,33 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System; +using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; + +namespace Roslyn.LanguageServer.Protocol; + +internal static partial class RoslynLspExtensions +{ + /// + /// Returns a copy of the passed in with the passed in . + /// + public static TextDocumentIdentifier WithUri(this TextDocumentIdentifier textDocumentIdentifier, Uri uri) + { + if (textDocumentIdentifier is VSTextDocumentIdentifier vsTdi) + { + return new VSTextDocumentIdentifier + { + Uri = uri, + ProjectContext = vsTdi.ProjectContext + }; + } + + return new TextDocumentIdentifier + { + Uri = uri + }; + } + + public static RazorTextDocumentIdentifier ToRazorTextDocumentIdentifier(this TextDocumentIdentifier textDocumentIdentifier) + => new RazorTextDocumentIdentifier(textDocumentIdentifier.Uri, (textDocumentIdentifier as VSTextDocumentIdentifier)?.ProjectContext?.Id); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_TextDocumentIdentifier.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_TextDocumentIdentifier.cs index 561a8fdbe9a..f265744db95 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_TextDocumentIdentifier.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_TextDocumentIdentifier.cs @@ -1,6 +1,9 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. +using System; +using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; + namespace Microsoft.VisualStudio.LanguageServer.Protocol; internal static partial class VsLspExtensions @@ -30,20 +33,6 @@ public static TextDocumentIdentifier WithUri(this TextDocumentIdentifier textDoc }; } - public static RLSP.TextDocumentIdentifier WithUri(this RLSP.TextDocumentIdentifier textDocumentIdentifier, Uri uri) - { - if (textDocumentIdentifier is RLSP.VSTextDocumentIdentifier vsTdi) - { - return new RLSP.VSTextDocumentIdentifier - { - Uri = uri, - ProjectContext = vsTdi.ProjectContext - }; - } - - return new RLSP.TextDocumentIdentifier - { - Uri = uri - }; - } + public static RazorTextDocumentIdentifier ToRazorTextDocumentIdentifier(this TextDocumentIdentifier textDocumentIdentifier) + => new RazorTextDocumentIdentifier(textDocumentIdentifier.Uri, (textDocumentIdentifier as VSTextDocumentIdentifier)?.ProjectContext?.Id); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs index 7a10c649662..0bbb9c8fccd 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Razor.Remote; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Text; using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.Remote.Razor; @@ -56,7 +57,7 @@ protected override IRemoteInlayHintService CreateService(in ServiceArgs args) var generatedDocument = await context.GetGeneratedDocumentAsync(_filePathService, cancellationToken).ConfigureAwait(false); var textDocument = inlayHintParams.TextDocument.WithUri(generatedDocument.CreateUri()); - var range = projectedLinePositionSpan.ToRLSPRange(); + var range = projectedLinePositionSpan.ToRange(); var hints = await InlayHints.GetInlayHintsAsync(generatedDocument, textDocument, range, displayAllOverride, cancellationToken).ConfigureAwait(false); @@ -71,7 +72,7 @@ protected override IRemoteInlayHintService CreateService(in ServiceArgs args) var syntaxTree = codeDocument.GetSyntaxTree(); foreach (var hint in hints) { - if (hint.Position.ToLinePosition().TryGetAbsoluteIndex(csharpSourceText, null, out var absoluteIndex) && + if (csharpSourceText.TryGetAbsoluteIndex(hint.Position.ToLinePosition(), out var absoluteIndex) && _documentMappingService.TryMapToHostDocumentPosition(csharpDocument, absoluteIndex, out var hostDocumentPosition, out var hostDocumentIndex)) { // We know this C# maps to Razor, but does it map to Razor that we like? @@ -83,13 +84,13 @@ protected override IRemoteInlayHintService CreateService(in ServiceArgs args) if (hint.TextEdits is not null) { - var changes = hint.TextEdits.Select(e => e.ToTextChange(csharpSourceText)); + var changes = hint.TextEdits.Select(csharpSourceText.GetTextChange); var mappedChanges = _documentMappingService.GetHostDocumentEdits(csharpDocument, changes); - hint.TextEdits = mappedChanges.Select(c => c.ToRLSPTextEdit(razorSourceText)).ToArray(); + hint.TextEdits = mappedChanges.Select(razorSourceText.GetTextEdit).ToArray(); } hint.Data = new InlayHintDataWrapper(inlayHintParams.TextDocument, hint.Data, hint.Position); - hint.Position = hostDocumentPosition.ToRLSPPosition(); + hint.Position = hostDocumentPosition.ToPosition(); inlayHintsBuilder.Add(hint); } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentHighlightPresentationEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentHighlightPresentationEndpoint.cs index e832f7561d8..bece5d33b1c 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentHighlightPresentationEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentHighlightPresentationEndpoint.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostFoldingRangeEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostFoldingRangeEndpoint.cs index be3ab94f529..b93a861c4e7 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostFoldingRangeEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostFoldingRangeEndpoint.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.Razor.Remote; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintEndpoint.cs index e5f361f55df..6cba8cd5cb5 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintEndpoint.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; using Microsoft.CodeAnalysis.Razor.Remote; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using Roslyn.LanguageServer.Protocol; using VSLSP = Microsoft.VisualStudio.LanguageServer.Protocol; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintResolveEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintResolveEndpoint.cs index a0410382983..0ed49f2c31c 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintResolveEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostInlayHintResolveEndpoint.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Protocol.InlayHints; using Microsoft.CodeAnalysis.Razor.Remote; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using Roslyn.LanguageServer.Protocol; using VSLSP = Microsoft.VisualStudio.LanguageServer.Protocol; @@ -95,9 +94,9 @@ internal class CohostInlayHintResolveEndpoint(IRemoteServiceInvoker remoteServic private static InlayHintDataWrapper? GetInlayHintResolveData(InlayHint inlayHint) { - if (inlayHint.Data is InlayHintDataWrapper) + if (inlayHint.Data is InlayHintDataWrapper wrapper) { - return (InlayHintDataWrapper)inlayHint.Data; + return wrapper; } if (inlayHint.Data is JsonElement json) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostLinkedEditingRangeEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostLinkedEditingRangeEndpoint.cs index f1f42f472dc..b98eb1bed4a 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostLinkedEditingRangeEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostLinkedEditingRangeEndpoint.cs @@ -8,12 +8,10 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; using Microsoft.CodeAnalysis.Razor.LinkedEditingRange; -using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Remote; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost; @@ -24,11 +22,10 @@ namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost; [ExportCohostStatelessLspService(typeof(CohostLinkedEditingRangeEndpoint))] [method: ImportingConstructor] #pragma warning restore RS0030 // Do not use banned APIs -internal class CohostLinkedEditingRangeEndpoint(IRemoteServiceInvoker remoteServiceInvoker, ILoggerFactory loggerFactory) +internal class CohostLinkedEditingRangeEndpoint(IRemoteServiceInvoker remoteServiceInvoker) : AbstractRazorCohostDocumentRequestHandler, IDynamicRegistrationProvider { private readonly IRemoteServiceInvoker _remoteServiceInvoker = remoteServiceInvoker; - private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); protected override bool MutatesSolutionState => false; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs index 77504ae52e2..bd113a4c82d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs @@ -11,12 +11,10 @@ using Microsoft.AspNetCore.Razor.Telemetry; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; -using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Remote; using Microsoft.CodeAnalysis.Razor.SemanticTokens; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using Microsoft.VisualStudio.Razor.Settings; namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost; @@ -32,15 +30,13 @@ internal sealed class CohostSemanticTokensRangeEndpoint( IRemoteServiceInvoker remoteServiceInvoker, IClientSettingsManager clientSettingsManager, ISemanticTokensLegendService semanticTokensLegendService, - ITelemetryReporter telemetryReporter, - ILoggerFactory loggerFactory) + ITelemetryReporter telemetryReporter) : AbstractRazorCohostDocumentRequestHandler, IDynamicRegistrationProvider { private readonly IRemoteServiceInvoker _remoteServiceInvoker = remoteServiceInvoker; private readonly IClientSettingsManager _clientSettingsManager = clientSettingsManager; private readonly ISemanticTokensLegendService _semanticTokensLegendService = semanticTokensLegendService; private readonly ITelemetryReporter _telemetryReporter = telemetryReporter; - private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); protected override bool MutatesSolutionState => false; protected override bool RequiresLSPSolution => true; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostUriPresentationEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostUriPresentationEndpoint.cs index 4582ca61358..4a4c494d00a 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostUriPresentationEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostUriPresentationEndpoint.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/RazorCohostRequestContextExtensions.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/RazorCohostRequestContextExtensions.cs deleted file mode 100644 index f276e5bec5b..00000000000 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/RazorCohostRequestContextExtensions.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT license. See License.txt in the project root for license information. - -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; -using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.VisualStudio.Razor.LanguageClient.Cohost; -using StreamJsonRpc; - -namespace Microsoft.VisualStudio.Razor.LanguageClient.Extensions; - -internal static class RazorCohostRequestContextExtensions -{ - public static async Task DelegateRequestAsync(this RazorCohostRequestContext requestContext, string target, TDelegatedParams @params, ILogger logger, CancellationToken cancellationToken) - { - var clientConnection = requestContext.GetClientConnection(); - - try - { - return await clientConnection.SendRequestAsync(target, @params, cancellationToken).ConfigureAwait(false); - } - catch (RemoteInvocationException e) - { - logger.LogError(e, $"Error calling delegate server for {target}"); - throw; - } - } - - public static RazorCohostClientConnection GetClientConnection(this RazorCohostRequestContext requestContext) - { - // TODO: We can't MEF import IRazorCohostClientLanguageServerManager in the constructor. We can make this work - // by having it implement a base class, RazorClientConnectionBase or something, that in turn implements - // AbstractRazorLspService (defined in Roslyn) and then move everything from importing IClientConnection - // to importing the new base class, so we can continue to share services. - // - // Until then we have to get the service from the request context. - var clientLanguageServerManager = requestContext.GetRequiredService(); - return new RazorCohostClientConnection(clientLanguageServerManager); - } -} diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/TextDocumentExtensions.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/TextDocumentExtensions.cs deleted file mode 100644 index 5ecffa0214c..00000000000 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Extensions/TextDocumentExtensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT license. See License.txt in the project root for license information. - -using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; -using Microsoft.VisualStudio.LanguageServer.Protocol; -using RLSP = Roslyn.LanguageServer.Protocol; - -namespace Microsoft.VisualStudio.Razor.LanguageClient.Extensions; - -internal static class TextDocumentExtensions -{ - public static RazorTextDocumentIdentifier ToRazorTextDocumentIdentifier(this TextDocumentIdentifier textDocumentIdentifier) - => new RazorTextDocumentIdentifier(textDocumentIdentifier.Uri, (textDocumentIdentifier as VSTextDocumentIdentifier)?.ProjectContext?.Id); - - public static RazorTextDocumentIdentifier ToRazorTextDocumentIdentifier(this RLSP.TextDocumentIdentifier textDocumentIdentifier) - => new RazorTextDocumentIdentifier(textDocumentIdentifier.Uri, (textDocumentIdentifier as RLSP.VSTextDocumentIdentifier)?.ProjectContext?.Id); -} diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostInlayHintEndpointTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostInlayHintEndpointTest.cs index 32d3c3287d9..f7a3df1d975 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostInlayHintEndpointTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostInlayHintEndpointTest.cs @@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Razor; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ExternalAccess.Razor; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Roslyn.LanguageServer.Protocol; @@ -106,7 +105,6 @@ private void M(string thisIsMyString) """, displayAllOverride: true); - [Fact] public Task InlayHints_ComponentAttributes() => VerifyInlayHintsAsync( @@ -119,9 +117,7 @@ public Task InlayHints_ComponentAttributes() """, - toolTipMap: new Dictionary - { - }, + toolTipMap: [], output: """
@@ -164,7 +160,7 @@ private async Task VerifyInlayHintsAsync(string input, Dictionary h.TextEdits ?? []) .OrderByDescending(e => e.Range.Start.Line) .ThenByDescending(e => e.Range.Start.Character) - .ToArray(); - foreach (var edit in edits) - { - var change = edit.ToTextChange(inputText); - inputText = inputText.WithChanges(change); - } + .Select(inputText.GetTextChange); + inputText = inputText.WithChanges(changes); AssertEx.EqualOrDiff(output, inputText.ToString()); } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostLinkedEditingRangeEndpointTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostLinkedEditingRangeEndpointTest.cs index cd2c7baddaa..28c05827166 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostLinkedEditingRangeEndpointTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostLinkedEditingRangeEndpointTest.cs @@ -162,7 +162,7 @@ private async Task VerifyLinkedEditingRangeAsync(string input) var document = CreateProjectAndRazorDocument(input); var sourceText = await document.GetTextAsync(DisposalToken); - var endpoint = new CohostLinkedEditingRangeEndpoint(RemoteServiceInvoker, LoggerFactory); + var endpoint = new CohostLinkedEditingRangeEndpoint(RemoteServiceInvoker); var request = new LinkedEditingRangeParams() { diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSemanticTokensRangeEndpointTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSemanticTokensRangeEndpointTest.cs index 8f688ce3712..42b792b7ad5 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSemanticTokensRangeEndpointTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSemanticTokensRangeEndpointTest.cs @@ -9,8 +9,6 @@ using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.AspNetCore.Razor.Telemetry; using Microsoft.CodeAnalysis.Razor.Settings; -using Microsoft.CodeAnalysis.Razor.Workspaces; -using Microsoft.CodeAnalysis.Remote.Razor; using Microsoft.CodeAnalysis.Remote.Razor.SemanticTokens; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Razor.Settings; @@ -107,7 +105,7 @@ private async Task VerifySemanticTokensAsync(string input, bool colorBackground, var clientSettingsManager = new ClientSettingsManager([], null, null); clientSettingsManager.Update(ClientAdvancedSettings.Default with { ColorBackground = colorBackground }); - var endpoint = new CohostSemanticTokensRangeEndpoint(RemoteServiceInvoker, clientSettingsManager, legend, NoOpTelemetryReporter.Instance, LoggerFactory); + var endpoint = new CohostSemanticTokensRangeEndpoint(RemoteServiceInvoker, clientSettingsManager, legend, NoOpTelemetryReporter.Instance); var span = new LinePositionSpan(new(0, 0), new(sourceText.Lines.Count, 0)); From 08f7362727c3cd248737f9cf5572be79aa57fa8d Mon Sep 17 00:00:00 2001 From: David Wengier Date: Thu, 25 Jul 2024 22:21:57 +1000 Subject: [PATCH 10/53] Cleanup --- .../RazorServicesTest.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Remote.Razor.Test/RazorServicesTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Remote.Razor.Test/RazorServicesTest.cs index bad7572de81..4b4a579532c 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Remote.Razor.Test/RazorServicesTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Remote.Razor.Test/RazorServicesTest.cs @@ -9,12 +9,11 @@ using System.Xml; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Test.Common; -using Microsoft.CodeAnalysis.Remote.Razor; using Microsoft.CodeAnalysis.ExternalAccess.Razor; +using Microsoft.CodeAnalysis.Remote.Razor; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; -using System.Reflection.Metadata.Ecma335; namespace Microsoft.CodeAnalysis.Razor.Remote; From 40e409e33b7652a3c11b3557ba2d34e5525933b6 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Fri, 26 Jul 2024 14:35:41 +1000 Subject: [PATCH 11/53] Fix excerpt service to allow for multi line verbatim strings that kinda are but kinda aren't supported in Razor --- .../RazorDocumentExcerptService.cs | 8 +- .../RazorDocumentExcerptServiceTest.cs | 182 ++++++++++++++++++ 2 files changed, 188 insertions(+), 2 deletions(-) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorDocumentExcerptService.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorDocumentExcerptService.cs index 3c7fb61c775..075a4769f70 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorDocumentExcerptService.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorDocumentExcerptService.cs @@ -135,9 +135,13 @@ internal class RazorDocumentExcerptService( var offset = primarySpan.Start - secondarySpan.Start; foreach (var classifiedSecondarySpan in classifiedSecondarySpans) { - Debug.Assert(secondarySpan.Contains(classifiedSecondarySpan.TextSpan)); + // It's possible for the classified span to extend past our secondary span, so we cap it + var classifiedSpan = classifiedSecondarySpan.TextSpan.End > secondarySpan.End + ? TextSpan.FromBounds(classifiedSecondarySpan.TextSpan.Start, secondarySpan.End) + : classifiedSecondarySpan.TextSpan; + Debug.Assert(secondarySpan.Contains(classifiedSpan)); - var updated = new TextSpan(classifiedSecondarySpan.TextSpan.Start + offset, classifiedSecondarySpan.TextSpan.Length); + var updated = new TextSpan(classifiedSpan.Start + offset, classifiedSpan.Length); Debug.Assert(primarySpan.Contains(updated)); // Make sure that we're not introducing a gap. Remember, we need to fill in the whitespace. diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorDocumentExcerptServiceTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorDocumentExcerptServiceTest.cs index ae6ff1ddcac..d9565002185 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorDocumentExcerptServiceTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorDocumentExcerptServiceTest.cs @@ -248,6 +248,188 @@ public async Task TryGetExcerptInternalAsync_SingleLine_CanClassifyCSharp_Comple }); } + [Fact] + public async Task TryGetExcerptInternalAsync_MultiLine_MultilineString() + { + // Arrange + var razorSource = """ + + @{ + [|string|] bigString = @" + Razor shows 3 lines in a + tooltip maximum, so this + multi-line verbatim + string must be longer + than that. + "; + } + + """; + + var (primary, secondary, secondarySpan) = await InitializeWithSnapshotAsync(razorSource); + + var service = CreateExcerptService(primary); + + // Act + var options = RazorClassificationOptionsWrapper.Default; + var result = await service.TryGetExcerptInternalAsync(secondary, secondarySpan, ExcerptModeInternal.Tooltip, options, DisposalToken); + + // Assert + Assert.NotNull(result); + Assert.Equal(secondarySpan, result.Value.Span); + Assert.Same(secondary, result.Value.Document); + + // Verifies that the right part of the primary document will be highlighted. + Assert.Equal( + (await secondary.GetTextAsync()).GetSubText(secondarySpan).ToString(), + result.Value.Content.GetSubText(result.Value.MappedSpan).ToString(), + ignoreLineEndingDifferences: true); + + Assert.Equal(""" + + @{ + string bigString = @" + Razor shows 3 lines in a + tooltip maximum, so this + multi-line verbatim + """, + result.Value.Content.ToString(), ignoreLineEndingDifferences: true); + + Assert.Collection( + result.Value.ClassifiedSpans, + c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(""" + + @{ + """, + result.Value.Content.GetSubText(c.TextSpan).ToString(), + ignoreLineEndingDifferences: true); + }, + c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal("\r\n ", result.Value.Content.GetSubText(c.TextSpan).ToString(), ignoreLineEndingDifferences: true); + }, + c => + { + Assert.Equal(ClassificationTypeNames.Keyword, c.ClassificationType); + Assert.Equal("string", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => + { + Assert.Equal(ClassificationTypeNames.LocalName, c.ClassificationType); + Assert.Equal("bigString", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => + { + Assert.Equal(ClassificationTypeNames.Operator, c.ClassificationType); + Assert.Equal("=", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => + { + Assert.Equal(ClassificationTypeNames.VerbatimStringLiteral, c.ClassificationType); + Assert.Equal(""" + @" + Razor shows 3 lines in a + tooltip maximum, so this + multi-line verbatim + """, result.Value.Content.GetSubText(c.TextSpan).ToString()); + }); + } + + [Fact] + public async Task TryGetExcerptInternalAsync_SingleLine_MultilineString() + { + // Arrange + var razorSource = """ + + @{ + [|string|] bigString = @" + This is a + multi-line verbatim + string. + "; + } + + """; + + var (primary, secondary, secondarySpan) = await InitializeWithSnapshotAsync(razorSource); + + var service = CreateExcerptService(primary); + + // Act + var options = RazorClassificationOptionsWrapper.Default; + var result = await service.TryGetExcerptInternalAsync(secondary, secondarySpan, ExcerptModeInternal.SingleLine, options, DisposalToken); + + // Assert + Assert.NotNull(result); + Assert.Equal(secondarySpan, result.Value.Span); + Assert.Same(secondary, result.Value.Document); + + // Verifies that the right part of the primary document will be highlighted. + Assert.Equal( + (await secondary.GetTextAsync()).GetSubText(secondarySpan).ToString(), + result.Value.Content.GetSubText(result.Value.MappedSpan).ToString(), + ignoreLineEndingDifferences: true); + + Assert.Equal("string bigString = @\"", result.Value.Content.ToString(), ignoreLineEndingDifferences: true); + + Assert.Collection( + result.Value.ClassifiedSpans, + c => + { + Assert.Equal(ClassificationTypeNames.Keyword, c.ClassificationType); + Assert.Equal("string", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => + { + Assert.Equal(ClassificationTypeNames.LocalName, c.ClassificationType); + Assert.Equal("bigString", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => + { + Assert.Equal(ClassificationTypeNames.Operator, c.ClassificationType); + Assert.Equal("=", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => + { + Assert.Equal(ClassificationTypeNames.VerbatimStringLiteral, c.ClassificationType); + Assert.Equal("@\"", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }); + } + [Fact] public async Task TryGetExcerptInternalAsync_MultiLine_CanClassifyCSharp() { From 8806e92225d1c47d6122b308c1c163416d55a5e0 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Mon, 29 Jul 2024 16:47:55 -0700 Subject: [PATCH 12/53] Snap Razor 17.2P1 (#10681) --- eng/Versions.props | 2 +- eng/config/PublishData.json | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index 6aa6e7cad14..04198d90816 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -30,7 +30,7 @@ imported. This OK because we want to just have an obvious salt for a local build. --> - 17.12.1 + 17.12.2 17.12 $(AddinMajorVersion) $(AddinVersion).$(OfficialBuildId) diff --git a/eng/config/PublishData.json b/eng/config/PublishData.json index beb8ad1ffff..85867dd8334 100644 --- a/eng/config/PublishData.json +++ b/eng/config/PublishData.json @@ -28,8 +28,8 @@ ], "vsBranch": "main", "vsMajorVersion": 17, - "insertionCreateDraftPR": false, - "insertionTitlePrefix": "[d17.12 P1]" + "insertionCreateDraftPR": true, + "insertionTitlePrefix": "[d17.12 P2]" }, "release/dev17.5": { "nugetKind": [ @@ -95,6 +95,16 @@ "vsMajorVersion": 17, "insertionCreateDraftPR": false, "insertionTitlePrefix": "[17.11]" - } + }, + "release/dev17.12": { + "nugetKind": [ + "Shipping", + "NonShipping" + ], + "vsBranch": "main", + "vsMajorVersion": 17, + "insertionCreateDraftPR": false, + "insertionTitlePrefix": "[d17.12 P1]" + }, } } From 88b3813e83abed93fc2bd47bada06486dcc0332f Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 30 Jul 2024 11:25:34 -0700 Subject: [PATCH 13/53] Update PublishData.json (#10685) --- eng/config/PublishData.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/config/PublishData.json b/eng/config/PublishData.json index 85867dd8334..d5938bf2f90 100644 --- a/eng/config/PublishData.json +++ b/eng/config/PublishData.json @@ -105,6 +105,6 @@ "vsMajorVersion": 17, "insertionCreateDraftPR": false, "insertionTitlePrefix": "[d17.12 P1]" - }, + } } } From db8eade83b4d52276c3ba9f7b86d21a819760333 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 30 Jul 2024 11:25:45 -0700 Subject: [PATCH 14/53] Remove 17.5 from servicing (#10686) --- eng/config/PublishData.json | 9 --------- 1 file changed, 9 deletions(-) diff --git a/eng/config/PublishData.json b/eng/config/PublishData.json index d5938bf2f90..a9fed190dc0 100644 --- a/eng/config/PublishData.json +++ b/eng/config/PublishData.json @@ -31,15 +31,6 @@ "insertionCreateDraftPR": true, "insertionTitlePrefix": "[d17.12 P2]" }, - "release/dev17.5": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.5", - "vsMajorVersion": 17, - "insertionTitlePrefix": "[17.5]" - }, "release/dev17.6": { "nugetKind": [ "Shipping", From 02854ec421ad7ca4dbbd6ac16d1c61cb1bf1d9e2 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Wed, 31 Jul 2024 08:29:56 +1000 Subject: [PATCH 15/53] Bump to a real Roslyn build --- eng/Versions.props | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index 6aa6e7cad14..d18ec9e740f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -53,25 +53,25 @@ 9.0.0-beta.24352.2 1.0.0-beta.23475.1 1.0.0-beta.23475.1 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 - 4.12.0-1.24366.6 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 + 4.12.0-1.24379.11 - + https://github.com/dotnet/roslyn - 30edd04fd41dec9e8f9f48e698ebd5b80d9f7677 + cf82d399c36008e7936d545cde24141f8d3790fa From 0f56e69685c800d95ddbb8b56b1d674f787b78b7 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 5 Aug 2024 18:03:56 +1000 Subject: [PATCH 21/53] Move down and interface-ize component search engine, and introduce IProjectCollectionResolver --- ...omponentAccessibilityCodeActionProvider.cs | 3 +- .../Definition/DefinitionEndpoint.cs | 6 +-- .../IServiceCollectionExtensions.cs | 1 + .../LspProjectSnapshotManager.cs | 8 +++- .../RazorLanguageServer.cs | 5 +-- .../Refactoring/RenameEndpoint.cs | 12 +++--- .../IProjectCollectionResolver.cs | 12 ++++++ .../IRazorComponentSearchEngine.cs} | 6 +-- .../RazorComponentSearchEngine.cs} | 17 ++++---- .../RemoteProjectCollectionResolver.cs | 27 ++++++++++++ .../DefinitionEndpointDelegationTest.cs | 3 +- ...t.cs => RazorComponentSearchEngineTest.cs} | 43 +++++++++++-------- .../RenameEndpointDelegationTest.cs | 3 +- .../Refactoring/RenameEndpointTest.cs | 2 +- .../TestProjectSnapshotManager.cs | 9 +++- 15 files changed, 110 insertions(+), 47 deletions(-) create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/IProjectCollectionResolver.cs rename src/Razor/src/{Microsoft.AspNetCore.Razor.LanguageServer/RazorComponentSearchEngine.cs => Microsoft.CodeAnalysis.Razor.Workspaces/IRazorComponentSearchEngine.cs} (56%) rename src/Razor/src/{Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorComponentSearchEngine.cs => Microsoft.CodeAnalysis.Razor.Workspaces/RazorComponentSearchEngine.cs} (83%) create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectCollectionResolver.cs rename src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/{DefaultRazorComponentSearchEngineTest.cs => RazorComponentSearchEngineTest.cs} (83%) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ComponentAccessibilityCodeActionProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ComponentAccessibilityCodeActionProvider.cs index 1404d1910a9..2e8ec37c2f9 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ComponentAccessibilityCodeActionProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ComponentAccessibilityCodeActionProvider.cs @@ -16,6 +16,7 @@ using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.AspNetCore.Razor.Utilities; using Microsoft.CodeAnalysis.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.Editor.Razor; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -157,7 +158,7 @@ private static async Task AddComponentAccessFromTagAsync(RazorCodeActionContext { // if fqn contains a generic typeparam, we should strip it out. Otherwise, replacing tag name will leave generic parameters in razor code, which are illegal // e.g. -> /> - var fullyQualifiedName = DefaultRazorComponentSearchEngine.RemoveGenericContent(tagHelperPair.Short.Name.AsMemory()).ToString(); + var fullyQualifiedName = RazorComponentSearchEngine.RemoveGenericContent(tagHelperPair.Short.Name.AsMemory()).ToString(); // If the match was case insensitive, then see if we can work out a new tag name to use as part of adding a using statement TextDocumentEdit? additionalEdit = null; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs index 3a6aad8e6f6..df34aebc583 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs @@ -29,14 +29,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition; [RazorLanguageServerEndpoint(Methods.TextDocumentDefinitionName)] internal sealed class DefinitionEndpoint( - RazorComponentSearchEngine componentSearchEngine, + IRazorComponentSearchEngine componentSearchEngine, IRazorDocumentMappingService documentMappingService, LanguageServerFeatureOptions languageServerFeatureOptions, IClientConnection clientConnection, ILoggerFactory loggerFactory) : AbstractRazorDelegatingEndpoint(languageServerFeatureOptions, documentMappingService, clientConnection, loggerFactory.GetOrCreateLogger()), ICapabilitiesProvider { - private readonly RazorComponentSearchEngine _componentSearchEngine = componentSearchEngine ?? throw new ArgumentNullException(nameof(componentSearchEngine)); + private readonly IRazorComponentSearchEngine _componentSearchEngine = componentSearchEngine ?? throw new ArgumentNullException(nameof(componentSearchEngine)); private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); protected override bool PreferCSharpOverHtmlIfPossible => true; @@ -73,7 +73,7 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V return default; } - var originComponentDocumentSnapshot = await _componentSearchEngine.TryLocateComponentAsync(originTagDescriptor).ConfigureAwait(false); + var originComponentDocumentSnapshot = await _componentSearchEngine.TryLocateComponentAsync(documentContext.Snapshot, originTagDescriptor).ConfigureAwait(false); if (originComponentDocumentSnapshot is null) { Logger.LogInformation($"Origin TagHelper document snapshot is null."); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs index 167a0c55101..ad0a81ca49b 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs @@ -226,6 +226,7 @@ public static void AddDocumentManagementServices(this IServiceCollection service // Add project snapshot manager services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(sp => (LspProjectSnapshotManager)sp.GetRequiredService()); } public static void AddHandlerWithCapabilities(this IServiceCollection services) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/LspProjectSnapshotManager.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/LspProjectSnapshotManager.cs index fbde37237cd..ba2bbca8924 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/LspProjectSnapshotManager.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/LspProjectSnapshotManager.cs @@ -9,16 +9,22 @@ using Microsoft.AspNetCore.Razor.ProjectEngineHost; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.Workspaces; namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; internal class LspProjectSnapshotManager( IProjectEngineFactoryProvider projectEngineFactoryProvider, ILoggerFactory loggerFactory) - : ProjectSnapshotManager(projectEngineFactoryProvider, loggerFactory, initializer: AddMiscFilesProject) + : ProjectSnapshotManager(projectEngineFactoryProvider, loggerFactory, initializer: AddMiscFilesProject), IProjectCollectionResolver { private static void AddMiscFilesProject(Updater updater) { updater.ProjectAdded(MiscFilesHostProject.Instance); } + + public IEnumerable EnumerateProjects(IDocumentSnapshot snapshot) + { + return GetProjects(); + } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs index 2c6eaa8cd79..3f8f6483676 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs @@ -20,15 +20,12 @@ using Microsoft.AspNetCore.Razor.LanguageServer.LinkedEditingRange; using Microsoft.AspNetCore.Razor.LanguageServer.MapCode; using Microsoft.AspNetCore.Razor.LanguageServer.ProjectContexts; -using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; using Microsoft.AspNetCore.Razor.LanguageServer.Refactoring; using Microsoft.AspNetCore.Razor.LanguageServer.SignatureHelp; using Microsoft.AspNetCore.Razor.LanguageServer.WrapWithTag; using Microsoft.AspNetCore.Razor.Telemetry; -using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.FoldingRanges; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CommonLanguageServerProtocol.Framework; using Microsoft.Extensions.DependencyInjection; @@ -153,7 +150,7 @@ protected override ILspServices ConstructLspServices() } // Other - services.AddSingleton(); + services.AddSingleton(); // Get the DefaultSession for telemetry. This is set by VS with // TelemetryService.SetDefaultSession and provides the correct diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs index 761ae07fc07..d28f56bcb24 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs @@ -27,8 +27,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Refactoring; [RazorLanguageServerEndpoint(Methods.TextDocumentRenameName)] internal sealed class RenameEndpoint( - RazorComponentSearchEngine componentSearchEngine, - IProjectSnapshotManager projectManager, + IRazorComponentSearchEngine componentSearchEngine, + IProjectCollectionResolver projectResolver, LanguageServerFeatureOptions languageServerFeatureOptions, IRazorDocumentMappingService documentMappingService, IClientConnection clientConnection, @@ -39,8 +39,8 @@ internal sealed class RenameEndpoint( clientConnection, loggerFactory.GetOrCreateLogger()), ICapabilitiesProvider { - private readonly IProjectSnapshotManager _projectManager = projectManager; - private readonly RazorComponentSearchEngine _componentSearchEngine = componentSearchEngine; + private readonly IProjectCollectionResolver _projectResolver = projectResolver; + private readonly IRazorComponentSearchEngine _componentSearchEngine = componentSearchEngine; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions = languageServerFeatureOptions; private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; @@ -117,7 +117,7 @@ protected override bool IsSupported() return null; } - var originComponentDocumentSnapshot = await _componentSearchEngine.TryLocateComponentAsync(originTagHelpers.First()).ConfigureAwait(false); + var originComponentDocumentSnapshot = await _componentSearchEngine.TryLocateComponentAsync(documentContext.Snapshot, originTagHelpers.First()).ConfigureAwait(false); if (originComponentDocumentSnapshot is null) { return null; @@ -162,7 +162,7 @@ protected override bool IsSupported() using var documentSnapshots = new PooledArrayBuilder(); using var _ = StringHashSetPool.GetPooledObject(out var documentPaths); - var projects = _projectManager.GetProjects(); + var projects = _projectResolver.EnumerateProjects(skipDocumentContext.Snapshot); foreach (var project in projects) { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/IProjectCollectionResolver.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/IProjectCollectionResolver.cs new file mode 100644 index 00000000000..6c337d1838e --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/IProjectCollectionResolver.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.CodeAnalysis.Razor.ProjectSystem; + +namespace Microsoft.CodeAnalysis.Razor.Workspaces; + +internal interface IProjectCollectionResolver +{ + IEnumerable EnumerateProjects(IDocumentSnapshot snapshot); +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorComponentSearchEngine.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/IRazorComponentSearchEngine.cs similarity index 56% rename from src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorComponentSearchEngine.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/IRazorComponentSearchEngine.cs index d12b5ef1ed6..1d519fc416e 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorComponentSearchEngine.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/IRazorComponentSearchEngine.cs @@ -5,9 +5,9 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -namespace Microsoft.AspNetCore.Razor.LanguageServer; +namespace Microsoft.CodeAnalysis.Razor.Workspaces; -internal abstract class RazorComponentSearchEngine +internal interface IRazorComponentSearchEngine { - public abstract Task TryLocateComponentAsync(TagHelperDescriptor tagHelper); + Task TryLocateComponentAsync(IDocumentSnapshot contextSnapshot, TagHelperDescriptor tagHelper); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorComponentSearchEngine.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorComponentSearchEngine.cs similarity index 83% rename from src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorComponentSearchEngine.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorComponentSearchEngine.cs index 09de8ae52f2..23bd2720ea8 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorComponentSearchEngine.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorComponentSearchEngine.cs @@ -7,15 +7,15 @@ using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -namespace Microsoft.AspNetCore.Razor.LanguageServer; +namespace Microsoft.CodeAnalysis.Razor.Workspaces; -internal class DefaultRazorComponentSearchEngine( - IProjectSnapshotManager projectManager, +internal class RazorComponentSearchEngine( + IProjectCollectionResolver projectCollectionResolver, ILoggerFactory loggerFactory) - : RazorComponentSearchEngine + : IRazorComponentSearchEngine { - private readonly IProjectSnapshotManager _projectManager = projectManager; - private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); + private readonly IProjectCollectionResolver _projectResolver = projectCollectionResolver; + private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); /// Search for a component in a project based on its tag name and fully qualified name. /// @@ -24,10 +24,11 @@ internal class DefaultRazorComponentSearchEngine( /// component is present in has the same name as the assembly its corresponding tag helper is loaded from. /// Implicitly, this method inherits any assumptions made by TrySplitNamespaceAndType. /// + /// A document snapshot that provides context to enumerate project snapshots /// A TagHelperDescriptor to find the corresponding Razor component for. /// The corresponding DocumentSnapshot if found, null otherwise. /// Thrown if is null. - public override async Task TryLocateComponentAsync(TagHelperDescriptor tagHelper) + public async Task TryLocateComponentAsync(IDocumentSnapshot contextSnapshot, TagHelperDescriptor tagHelper) { if (tagHelper is null) { @@ -44,7 +45,7 @@ internal class DefaultRazorComponentSearchEngine( var lookupSymbolName = RemoveGenericContent(typeName.AsMemory()); - var projects = _projectManager.GetProjects(); + var projects = _projectResolver.EnumerateProjects(contextSnapshot); foreach (var project in projects) { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectCollectionResolver.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectCollectionResolver.cs new file mode 100644 index 00000000000..45f6a5b482b --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectCollectionResolver.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Composition; +using System.Diagnostics; +using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.Workspaces; + +namespace Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; + +[Export(typeof(IProjectCollectionResolver)), Shared] +[method: ImportingConstructor] +internal class RemoteProjectCollectionResolver(ProjectSnapshotFactory projectSnapshotFactory) : IProjectCollectionResolver +{ + public IEnumerable EnumerateProjects(IDocumentSnapshot snapshot) + { + Debug.Assert(snapshot is RemoteDocumentSnapshot); + + var projects = ((RemoteDocumentSnapshot)snapshot).TextDocument.Project.Solution.Projects; + + foreach (var project in projects) + { + yield return projectSnapshotFactory.GetOrCreate(project); + } + } +} diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointDelegationTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointDelegationTest.cs index 7526d0b052b..2711a8dc359 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointDelegationTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointDelegationTest.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -236,7 +237,7 @@ await projectManager.UpdateAsync(updater => rootNamespace: "project")); }); - var searchEngine = new DefaultRazorComponentSearchEngine(projectManager, LoggerFactory); + var searchEngine = new RazorComponentSearchEngine(projectManager, LoggerFactory); var razorUri = new Uri(razorFilePath); Assert.True(DocumentContextFactory.TryCreateForOpenDocument(razorUri, out var documentContext)); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DefaultRazorComponentSearchEngineTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorComponentSearchEngineTest.cs similarity index 83% rename from src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DefaultRazorComponentSearchEngineTest.cs rename to src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorComponentSearchEngineTest.cs index 28155a96fbb..453c64f7064 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DefaultRazorComponentSearchEngineTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorComponentSearchEngineTest.cs @@ -12,6 +12,8 @@ using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Moq; using Xunit; @@ -20,7 +22,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Test; -public class DefaultRazorComponentSearchEngineTest(ITestOutputHelper testOutput) : LanguageServerTestBase(testOutput) +public class RazorComponentSearchEngineTest(ITestOutputHelper testOutput) : LanguageServerTestBase(testOutput) { private static readonly string s_project1BasePath = PathUtilities.CreateRootedPath("First"); private static readonly string s_project2BasePath = PathUtilities.CreateRootedPath("Second"); @@ -99,11 +101,12 @@ public async Task Handle_SearchFound_GenericComponent() // Arrange var tagHelperDescriptor1 = CreateRazorComponentTagHelperDescriptor("First", RootNamespace1, "Component1", typeName: "Component1"); var tagHelperDescriptor2 = CreateRazorComponentTagHelperDescriptor("Second", RootNamespace2, "Component3", typeName: "Component3"); - var searchEngine = new DefaultRazorComponentSearchEngine(_projectManager, LoggerFactory); + var searchEngine = new RazorComponentSearchEngine(_projectManager, LoggerFactory); + var snapshot = StrictMock.Of(); // Act - var documentSnapshot1 = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor1); - var documentSnapshot2 = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor2); + var documentSnapshot1 = await searchEngine.TryLocateComponentAsync(snapshot, tagHelperDescriptor1); + var documentSnapshot2 = await searchEngine.TryLocateComponentAsync(snapshot, tagHelperDescriptor2); // Assert Assert.NotNull(documentSnapshot1); @@ -118,11 +121,12 @@ public async Task Handle_SearchFound() // Arrange var tagHelperDescriptor1 = CreateRazorComponentTagHelperDescriptor("First", RootNamespace1, "Component1"); var tagHelperDescriptor2 = CreateRazorComponentTagHelperDescriptor("Second", RootNamespace2, "Component3"); - var searchEngine = new DefaultRazorComponentSearchEngine(_projectManager, LoggerFactory); + var searchEngine = new RazorComponentSearchEngine(_projectManager, LoggerFactory); + var snapshot = StrictMock.Of(); // Act - var documentSnapshot1 = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor1); - var documentSnapshot2 = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor2); + var documentSnapshot1 = await searchEngine.TryLocateComponentAsync(snapshot, tagHelperDescriptor1); + var documentSnapshot2 = await searchEngine.TryLocateComponentAsync(snapshot, tagHelperDescriptor2); // Assert Assert.NotNull(documentSnapshot1); @@ -136,10 +140,11 @@ public async Task Handle_SearchFound_SetNamespace() { // Arrange var tagHelperDescriptor = CreateRazorComponentTagHelperDescriptor("First", "Test", "Component2"); - var searchEngine = new DefaultRazorComponentSearchEngine(_projectManager, LoggerFactory); + var searchEngine = new RazorComponentSearchEngine(_projectManager, LoggerFactory); + var snapshot = StrictMock.Of(); // Act - var documentSnapshot = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor); + var documentSnapshot = await searchEngine.TryLocateComponentAsync(snapshot, tagHelperDescriptor); // Assert Assert.NotNull(documentSnapshot); @@ -151,10 +156,11 @@ public async Task Handle_SearchMissing_IncorrectAssembly() { // Arrange var tagHelperDescriptor = CreateRazorComponentTagHelperDescriptor("Third", RootNamespace1, "Component3"); - var searchEngine = new DefaultRazorComponentSearchEngine(_projectManager, LoggerFactory); + var searchEngine = new RazorComponentSearchEngine(_projectManager, LoggerFactory); + var snapshot = StrictMock.Of(); // Act - var documentSnapshot = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor); + var documentSnapshot = await searchEngine.TryLocateComponentAsync(snapshot, tagHelperDescriptor); // Assert Assert.Null(documentSnapshot); @@ -165,10 +171,11 @@ public async Task Handle_SearchMissing_IncorrectNamespace() { // Arrange var tagHelperDescriptor = CreateRazorComponentTagHelperDescriptor("First", RootNamespace1, "Component2"); - var searchEngine = new DefaultRazorComponentSearchEngine(_projectManager, LoggerFactory); + var searchEngine = new RazorComponentSearchEngine(_projectManager, LoggerFactory); + var snapshot = StrictMock.Of(); // Act - var documentSnapshot = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor); + var documentSnapshot = await searchEngine.TryLocateComponentAsync(snapshot, tagHelperDescriptor); // Assert Assert.Null(documentSnapshot); @@ -179,10 +186,11 @@ public async Task Handle_SearchMissing_IncorrectComponent() { // Arrange var tagHelperDescriptor = CreateRazorComponentTagHelperDescriptor("First", RootNamespace1, "Component3"); - var searchEngine = new DefaultRazorComponentSearchEngine(_projectManager, LoggerFactory); + var searchEngine = new RazorComponentSearchEngine(_projectManager, LoggerFactory); + var snapshot = StrictMock.Of(); // Act - var documentSnapshot = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor); + var documentSnapshot = await searchEngine.TryLocateComponentAsync(snapshot, tagHelperDescriptor); // Assert Assert.Null(documentSnapshot); @@ -193,10 +201,11 @@ public async Task Handle_FilePathAndAssemblyNameDifferent() { // Arrange var tagHelperDescriptor = CreateRazorComponentTagHelperDescriptor("AssemblyName", "Test", "Component2"); - var searchEngine = new DefaultRazorComponentSearchEngine(_projectManager, LoggerFactory); + var searchEngine = new RazorComponentSearchEngine(_projectManager, LoggerFactory); + var snapshot = StrictMock.Of(); // Act - var documentSnapshot = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor); + var documentSnapshot = await searchEngine.TryLocateComponentAsync(snapshot, tagHelperDescriptor); // Assert Assert.NotNull(documentSnapshot); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs index f11cb0b851f..b4f067970fb 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Test.Common.Mef; using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -63,7 +64,7 @@ await projectManager.UpdateAsync(updater => rootNamespace: "project")); }); - var searchEngine = new DefaultRazorComponentSearchEngine(projectManager, LoggerFactory); + var searchEngine = new RazorComponentSearchEngine(projectManager, LoggerFactory); var endpoint = new RenameEndpoint( searchEngine, diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs index 879c0bf5fbe..bde6e054c50 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs @@ -671,7 +671,7 @@ await projectManager.UpdateAsync(updater => await projectService.UpdateDocumentAsync(s_componentFilePath4, SourceText.From(ComponentText4), version: 42, DisposalToken); await projectService.UpdateDocumentAsync(s_componentWithParamFilePath, SourceText.From(ComponentWithParamText), version: 42, DisposalToken); - var searchEngine = new DefaultRazorComponentSearchEngine(projectManager, LoggerFactory); + var searchEngine = new RazorComponentSearchEngine(projectManager, LoggerFactory); options ??= StrictMock.Of(o => o.SupportsFileManipulation == true && o.SingleServerSupport == false && diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshotManager.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshotManager.cs index 49491cfbc99..01f551ba04c 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshotManager.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshotManager.cs @@ -2,12 +2,14 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.LanguageServer; using Microsoft.AspNetCore.Razor.ProjectEngineHost; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.Workspaces; namespace Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; @@ -16,7 +18,7 @@ internal partial class TestProjectSnapshotManager( ILoggerFactory loggerFactory, CancellationToken disposalToken, Action? initializer = null) - : ProjectSnapshotManager(projectEngineFactoryProvider, loggerFactory, initializer) + : ProjectSnapshotManager(projectEngineFactoryProvider, loggerFactory, initializer), IProjectCollectionResolver { private readonly CancellationToken _disposalToken = disposalToken; @@ -33,6 +35,11 @@ public Task CreateAndAddDocumentAsync(ProjectSnapshot proj _disposalToken); } + public IEnumerable EnumerateProjects(IDocumentSnapshot snapshot) + { + return GetProjects(); + } + public Listener ListenToNotifications() => new(this); public Task UpdateAsync(Action updater) From 59e626041122165f9dd6a7d2dde18c64368e5464 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Mon, 5 Aug 2024 09:53:41 -0700 Subject: [PATCH 22/53] Insert release/dev17.12 to VS rel/d17.12 (#10707) --- eng/config/PublishData.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/config/PublishData.json b/eng/config/PublishData.json index a9fed190dc0..0430b2b4e1f 100644 --- a/eng/config/PublishData.json +++ b/eng/config/PublishData.json @@ -28,7 +28,7 @@ ], "vsBranch": "main", "vsMajorVersion": 17, - "insertionCreateDraftPR": true, + "insertionCreateDraftPR": false, "insertionTitlePrefix": "[d17.12 P2]" }, "release/dev17.6": { @@ -92,7 +92,7 @@ "Shipping", "NonShipping" ], - "vsBranch": "main", + "vsBranch": "rel/d17.12", "vsMajorVersion": 17, "insertionCreateDraftPR": false, "insertionTitlePrefix": "[d17.12 P1]" From ea2e567f28a375667384ea1bc9f7fccf11025059 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 08:47:43 -0700 Subject: [PATCH 23/53] Small amount of clean up in AbstractRazorDocumentMappingService --- .../AbstractRazorDocumentMappingService.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs index 56e0a854e44..afdc7ca2d93 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs @@ -28,8 +28,8 @@ internal abstract class AbstractRazorDocumentMappingService( ILogger logger) : IRazorDocumentMappingService { - private readonly IFilePathService _documentFilePathService = filePathService ?? throw new ArgumentNullException(nameof(filePathService)); - private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory ?? throw new ArgumentNullException(nameof(documentContextFactory)); + private readonly IFilePathService _filePathService = filePathService; + private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; private readonly ILogger _logger = logger; public IEnumerable GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument, IEnumerable generatedDocumentChanges) @@ -384,16 +384,16 @@ public async Task RemapWorkspaceEditAsync(WorkspaceEdit workspace public async Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync(Uri generatedDocumentUri, LinePositionSpan generatedDocumentRange, CancellationToken cancellationToken) { - var razorDocumentUri = _documentFilePathService.GetRazorDocumentUri(generatedDocumentUri); + var razorDocumentUri = _filePathService.GetRazorDocumentUri(generatedDocumentUri); // For Html we just map the Uri, the range will be the same - if (_documentFilePathService.IsVirtualHtmlFile(generatedDocumentUri)) + if (_filePathService.IsVirtualHtmlFile(generatedDocumentUri)) { return (razorDocumentUri, generatedDocumentRange); } // We only map from C# files - if (!_documentFilePathService.IsVirtualCSharpFile(generatedDocumentUri)) + if (!_filePathService.IsVirtualCSharpFile(generatedDocumentUri)) { return (generatedDocumentUri, generatedDocumentRange); } @@ -741,14 +741,14 @@ private async Task RemapVersionedDocumentEditsAsync(TextDocu var generatedDocumentUri = entry.TextDocument.Uri; // Check if the edit is actually for a generated document, because if not we don't need to do anything - if (!_documentFilePathService.IsVirtualDocumentUri(generatedDocumentUri)) + if (!_filePathService.IsVirtualDocumentUri(generatedDocumentUri)) { // This location doesn't point to a background razor file. No need to remap. remappedDocumentEdits.Add(entry); continue; } - var razorDocumentUri = _documentFilePathService.GetRazorDocumentUri(generatedDocumentUri); + var razorDocumentUri = _filePathService.GetRazorDocumentUri(generatedDocumentUri); if (!_documentContextFactory.TryCreateForOpenDocument(razorDocumentUri, entry.TextDocument.GetProjectContext(), out var documentContext)) { @@ -787,7 +787,7 @@ private async Task> RemapDocumentEditsAsync(Dicti var edits = entry.Value; // Check if the edit is actually for a generated document, because if not we don't need to do anything - if (!_documentFilePathService.IsVirtualDocumentUri(uri)) + if (!_filePathService.IsVirtualDocumentUri(uri)) { remappedChanges[entry.Key] = entry.Value; continue; @@ -806,7 +806,7 @@ private async Task> RemapDocumentEditsAsync(Dicti continue; } - var razorDocumentUri = _documentFilePathService.GetRazorDocumentUri(uri); + var razorDocumentUri = _filePathService.GetRazorDocumentUri(uri); remappedChanges[razorDocumentUri.AbsoluteUri] = remappedEdits; } @@ -840,11 +840,11 @@ private TextEdit[] RemapTextEditsCore(Uri generatedDocumentUri, RazorCodeDocumen private IRazorGeneratedDocument? GetGeneratedDocumentFromGeneratedDocumentUri(Uri generatedDocumentUri, RazorCodeDocument codeDocument) { - if (_documentFilePathService.IsVirtualCSharpFile(generatedDocumentUri)) + if (_filePathService.IsVirtualCSharpFile(generatedDocumentUri)) { return codeDocument.GetCSharpDocument(); } - else if (_documentFilePathService.IsVirtualHtmlFile(generatedDocumentUri)) + else if (_filePathService.IsVirtualHtmlFile(generatedDocumentUri)) { return codeDocument.GetHtmlDocument(); } From a5ddcd711f9c8a5cfc9fef1a6bcde4f78281edbc Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 10:22:37 -0700 Subject: [PATCH 24/53] Rework DocumentContext This change updates `DocumentContext` is several ways: 1. Fields used for caching are now assigned with `Interlocked.Initialize(...)` to ensure that the same value are used in race scenarios. 2. All public async methods now return `ValueTask` rather than `Task`. This has lower overhead since the async methods will return synchronously after the first call. 3. Members are no longer virtual. This appears to have been originally done to allow `DocumentContext` to be mocked for tests, which isn't the right way to handle testing. Instead, since `DocumentContext` delegates its implementation to its `IDocumentSnapshot`, the snapshot should be mocked to change the implementation. 4. The Identifier property has been converted to a method, since it creates a new object every time. --- .../AutoInsert/OnAutoInsertEndpoint.cs | 2 +- .../Razor/GenerateMethodCodeActionResolver.cs | 4 +- .../DelegatedCompletionItemResolver.cs | 8 +- .../DelegatedCompletionListProvider.cs | 2 +- .../ValidateBreakpointRangeEndpoint.cs | 2 +- .../Definition/DefinitionEndpoint.cs | 6 +- .../DocumentPullDiagnosticsEndpoint.cs | 2 +- .../DocumentHighlightEndpoint.cs | 6 +- .../DocumentSymbols/DocumentSymbolEndpoint.cs | 2 +- .../FindAllReferencesEndpoint.cs | 6 +- .../Formatting/RazorFormattingService.cs | 2 +- .../Hover/HoverEndpoint.cs | 6 +- .../Implementation/ImplementationEndpoint.cs | 6 +- .../InlayHints/InlayHintService.cs | 4 +- .../MapCode/MapCodeEndpoint.cs | 2 +- .../Refactoring/RenameEndpoint.cs | 8 +- .../LSPCSharpSemanticTokensProvider.cs | 7 +- .../SignatureHelp/SignatureHelpEndpoint.cs | 6 +- .../SpellCheck/DocumentSpellCheckEndpoint.cs | 2 +- .../ProjectSystem/DocumentContext.cs | 169 ++++++++++++------ .../ProjectSystem/VersionedDocumentContext.cs | 17 +- ...legatedCompletionItemResolverTest.NetFx.cs | 20 ++- .../Completion/TagHelperServiceTestBase.cs | 7 +- .../Semantic/SemanticTokensTest.cs | 41 ++--- .../StrictMock`1.cs | 2 +- 25 files changed, 207 insertions(+), 132 deletions(-) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs index ea7d46e8e45..53db73065d8 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs @@ -170,7 +170,7 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return Task.FromResult(new DelegatedOnAutoInsertParams( - documentContext.Identifier, + documentContext.GetTextDocumentIdentifierAndVersion(), positionInfo.Position, positionInfo.LanguageKind, request.Character, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs index f79fe80a516..eff10d67736 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs @@ -166,7 +166,7 @@ private async Task GenerateMethodInCodeBlockAsync( character: 0, editToSendToRoslyn.NewText); - var delegatedParams = new DelegatedSimplifyMethodParams(documentContext.Identifier, RequiresVirtualDocument: true, tempTextEdit); + var delegatedParams = new DelegatedSimplifyMethodParams(documentContext.GetTextDocumentIdentifierAndVersion(), RequiresVirtualDocument: true, tempTextEdit); var result = await _clientConnection.SendRequestAsync( CustomMessageNames.RazorSimplifyMethodEndpointName, delegatedParams, @@ -194,7 +194,7 @@ private async Task GenerateMethodInCodeBlockAsync( var remappedEdit = VsLspFactory.CreateTextEdit(remappedRange, unformattedMethodSignature); - var delegatedParams = new DelegatedSimplifyMethodParams(documentContext.Identifier, RequiresVirtualDocument: true, remappedEdit); + var delegatedParams = new DelegatedSimplifyMethodParams(documentContext.GetTextDocumentIdentifierAndVersion(), RequiresVirtualDocument: true, remappedEdit); var result = await _clientConnection.SendRequestAsync( CustomMessageNames.RazorSimplifyMethodEndpointName, delegatedParams, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionItemResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionItemResolver.cs index 7d58f7bfbd6..f977eb4b4ff 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionItemResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionItemResolver.cs @@ -105,7 +105,13 @@ private async Task PostProcessCompletionItemAsync( return resolvedCompletionItem; } - var formattingOptions = await _clientConnection.SendRequestAsync(CodeAnalysis.Razor.Protocol.LanguageServerConstants.RazorGetFormattingOptionsEndpointName, documentContext.Identifier, cancellationToken).ConfigureAwait(false); + var formattingOptions = await _clientConnection + .SendRequestAsync( + LanguageServerConstants.RazorGetFormattingOptionsEndpointName, + documentContext.GetTextDocumentIdentifierAndVersion(), + cancellationToken) + .ConfigureAwait(false); + if (formattingOptions is null) { return resolvedCompletionItem; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs index e830fee0ff0..41fc0ab7c55 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs @@ -77,7 +77,7 @@ public DelegatedCompletionListProvider( var shouldIncludeSnippets = await ShouldIncludeSnippetsAsync(documentContext, absoluteIndex, cancellationToken).ConfigureAwait(false); var delegatedParams = new DelegatedCompletionParams( - documentContext.Identifier, + documentContext.GetTextDocumentIdentifierAndVersion(), positionInfo.Position, positionInfo.LanguageKind, completionContext, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/ValidateBreakpointRangeEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/ValidateBreakpointRangeEndpoint.cs index 5f5c32bb01d..59b8866dd3d 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/ValidateBreakpointRangeEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/ValidateBreakpointRangeEndpoint.cs @@ -67,7 +67,7 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return new DelegatedValidateBreakpointRangeParams( - documentContext.Identifier, + documentContext.GetTextDocumentIdentifierAndVersion(), projectedRange, positionInfo.LanguageKind); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs index df34aebc583..603714fb6b3 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs @@ -112,9 +112,9 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return Task.FromResult(new DelegatedPositionParams( - documentContext.Identifier, - positionInfo.Position, - positionInfo.LanguageKind)); + documentContext.GetTextDocumentIdentifierAndVersion(), + positionInfo.Position, + positionInfo.LanguageKind)); } protected async override Task HandleDelegatedResponseAsync(DefinitionResult? response, TextDocumentPositionParams originalRequest, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs index b4277742608..68d893f9b24 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs @@ -147,7 +147,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalDocumentDiagno private async Task<(VSInternalDiagnosticReport[]? CSharpDiagnostics, VSInternalDiagnosticReport[]? HtmlDiagnostics)> GetHtmlCSharpDiagnosticsAsync(VersionedDocumentContext documentContext, Guid correlationId, CancellationToken cancellationToken) { - var delegatedParams = new DelegatedDiagnosticParams(documentContext.Identifier, correlationId); + var delegatedParams = new DelegatedDiagnosticParams(documentContext.GetTextDocumentIdentifierAndVersion(), correlationId); var delegatedResponse = await _clientConnection.SendRequestAsync( CustomMessageNames.RazorPullDiagnosticEndpointName, delegatedParams, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs index 5854d01677e..08e1818189b 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs @@ -56,9 +56,9 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return Task.FromResult(new DelegatedPositionParams( - documentContext.Identifier, - positionInfo.Position, - positionInfo.LanguageKind)); + documentContext.GetTextDocumentIdentifierAndVersion(), + positionInfo.Position, + positionInfo.LanguageKind)); } protected override async Task HandleDelegatedResponseAsync(DocumentHighlight[]? response, DocumentHighlightParams request, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSymbols/DocumentSymbolEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSymbols/DocumentSymbolEndpoint.cs index e64bb4e1df1..ea902244737 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSymbols/DocumentSymbolEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSymbols/DocumentSymbolEndpoint.cs @@ -62,7 +62,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(DocumentSymbolParams req return null; } - var delegatedParams = new DelegatedDocumentSymbolParams(documentContext.Identifier); + var delegatedParams = new DelegatedDocumentSymbolParams(documentContext.GetTextDocumentIdentifierAndVersion()); var result = await _clientConnection.SendRequestAsync?>( CustomMessageNames.RazorDocumentSymbolEndpoint, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs index b3b9da23856..adb2ab359dd 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs @@ -67,9 +67,9 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return Task.FromResult(new DelegatedPositionParams( - documentContext.Identifier, - positionInfo.Position, - positionInfo.LanguageKind)); + documentContext.GetTextDocumentIdentifierAndVersion(), + positionInfo.Position, + positionInfo.LanguageKind)); } protected override async Task HandleDelegatedResponseAsync(VSInternalReferenceItem[] delegatedResponse, ReferenceParams originalRequest, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingService.cs index 007250d2bdd..7989815323b 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingService.cs @@ -153,7 +153,7 @@ private async Task ApplyFormattedEditsAsync( collapseEdits |= formattedEdits.Length == 1; var documentSnapshot = documentContext.Snapshot; - var uri = documentContext.Identifier.Uri; + var uri = documentContext.Uri; var codeDocument = await documentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false); using var context = FormattingContext.CreateForOnTypeFormatting(uri, documentSnapshot, codeDocument, options, _workspaceFactory, automaticallyAddUsings: automaticallyAddUsings, hostDocumentIndex, triggerCharacter); var result = new FormattingResult(formattedEdits, kind); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs index 956c0fec725..3417fcc9957 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs @@ -51,9 +51,9 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return Task.FromResult(new DelegatedPositionParams( - documentContext.Identifier, - positionInfo.Position, - positionInfo.LanguageKind)); + documentContext.GetTextDocumentIdentifierAndVersion(), + positionInfo.Position, + positionInfo.LanguageKind)); } protected override Task TryHandleAsync(TextDocumentPositionParams request, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Implementation/ImplementationEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Implementation/ImplementationEndpoint.cs index fc5c3807078..760bd7226ec 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Implementation/ImplementationEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Implementation/ImplementationEndpoint.cs @@ -53,9 +53,9 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return Task.FromResult(new DelegatedPositionParams( - documentContext.Identifier, - positionInfo.Position, - positionInfo.LanguageKind)); + documentContext.GetTextDocumentIdentifierAndVersion(), + positionInfo.Position, + positionInfo.LanguageKind)); } protected async override Task HandleDelegatedResponseAsync(ImplementationResult delegatedResponse, TextDocumentPositionParams request, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs index c0debade37d..e6aa690bb03 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs @@ -42,7 +42,7 @@ internal sealed class InlayHintService(IRazorDocumentMappingService documentMapp // For now we only support C# inlay hints. Once Web Tools adds support we'll need to request from both servers and combine // the results, much like folding ranges. var delegatedRequest = new DelegatedInlayHintParams( - Identifier: documentContext.Identifier, + Identifier: documentContext.GetTextDocumentIdentifierAndVersion(), ProjectedRange: projectedLinePositionSpan.ToRange(), ProjectedKind: RazorLanguageKind.CSharp ); @@ -78,7 +78,7 @@ internal sealed class InlayHintService(IRazorDocumentMappingService documentMapp hint.Data = new RazorInlayHintWrapper { - TextDocument = documentContext.Identifier, + TextDocument = documentContext.GetTextDocumentIdentifierAndVersion(), OriginalData = hint.Data, OriginalPosition = hint.Position }; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs index f076c975592..fa6066328aa 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs @@ -202,7 +202,7 @@ private async Task TryMapCodeAsync( } var csharpMappingSuccessful = await TrySendCSharpDelegatedMappingRequestAsync( - documentContext.Identifier, + documentContext.GetTextDocumentIdentifierAndVersion(), csharpBody, csharpFocusLocations, mapCodeCorrelationId, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs index d28f56bcb24..ebe295c2918 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs @@ -91,10 +91,10 @@ protected override bool IsSupported() } return Task.FromResult(new DelegatedRenameParams( - documentContext.Identifier, - positionInfo.Position, - positionInfo.LanguageKind, - request.NewName)); + documentContext.GetTextDocumentIdentifierAndVersion(), + positionInfo.Position, + positionInfo.LanguageKind, + request.NewName)); } protected override async Task HandleDelegatedResponseAsync(WorkspaceEdit? response, RenameParams request, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/LSPCSharpSemanticTokensProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/LSPCSharpSemanticTokensProvider.cs index 841b15ba463..6a2e9d8dceb 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/LSPCSharpSemanticTokensProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/LSPCSharpSemanticTokensProvider.cs @@ -41,7 +41,12 @@ internal class LSPCSharpSemanticTokensProvider(LanguageServerFeatureOptions lang var csharpRanges = csharpRangeList.ToArray(); - var parameter = new ProvideSemanticTokensRangesParams(documentContext.Identifier.TextDocumentIdentifier, documentVersion, csharpRanges, correlationId); + var parameter = new ProvideSemanticTokensRangesParams( + documentContext.GetTextDocumentIdentifierAndVersion().TextDocumentIdentifier, + documentVersion, + csharpRanges, + correlationId); + ProvideSemanticTokensResponse? csharpResponse; if (_languageServerFeatureOptions.UsePreciseSemanticTokenRanges) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SignatureHelp/SignatureHelpEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SignatureHelp/SignatureHelpEndpoint.cs index 790cd537f07..dc760893697 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SignatureHelp/SignatureHelpEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SignatureHelp/SignatureHelpEndpoint.cs @@ -54,8 +54,8 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } return Task.FromResult(new DelegatedPositionParams( - documentContext.Identifier, - positionInfo.Position, - positionInfo.LanguageKind)); + documentContext.GetTextDocumentIdentifierAndVersion(), + positionInfo.Position, + positionInfo.LanguageKind)); } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SpellCheck/DocumentSpellCheckEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SpellCheck/DocumentSpellCheckEndpoint.cs index ca84457a042..711f49c6dc5 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SpellCheck/DocumentSpellCheckEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SpellCheck/DocumentSpellCheckEndpoint.cs @@ -129,7 +129,7 @@ MarkupMinimizedTagHelperDirectiveAttributeSyntax or private async Task AddCSharpSpellCheckRangesAsync(List ranges, VersionedDocumentContext documentContext, CancellationToken cancellationToken) { - var delegatedParams = new DelegatedSpellCheckParams(documentContext.Identifier); + var delegatedParams = new DelegatedSpellCheckParams(documentContext.GetTextDocumentIdentifierAndVersion()); var delegatedResponse = await _clientConnection.SendRequestAsync( CustomMessageNames.RazorSpellCheckEndpoint, delegatedParams, diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs index 36a01ebd20f..a99c792531f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs @@ -2,117 +2,172 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; +using RazorSyntaxNode = Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxNode; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.AspNetCore.Razor.Language.Syntax; - -internal class DocumentContext +internal class DocumentContext(Uri uri, IDocumentSnapshot snapshot, VSProjectContext? projectContext) { + private readonly VSProjectContext? _projectContext = projectContext; private RazorCodeDocument? _codeDocument; private SourceText? _sourceText; - private readonly VSProjectContext? _projectContext; - - public DocumentContext( - Uri uri, - IDocumentSnapshot snapshot, - VSProjectContext? projectContext) - { - Uri = uri; - Snapshot = snapshot; - _projectContext = projectContext; - } - - public virtual Uri Uri { get; } - - public virtual IDocumentSnapshot Snapshot { get; } - public virtual string FilePath => Snapshot.FilePath.AssumeNotNull(); + public Uri Uri { get; } = uri; + public IDocumentSnapshot Snapshot { get; } = snapshot; + public string FilePath => Snapshot.FilePath.AssumeNotNull(); + public string FileKind => Snapshot.FileKind.AssumeNotNull(); + public IProjectSnapshot Project => Snapshot.Project; - public virtual string FileKind => Snapshot.FileKind.AssumeNotNull(); - - public virtual IProjectSnapshot Project => Snapshot.Project; + public TextDocumentIdentifier GetTextDocumentIdentifier() + => new VSTextDocumentIdentifier() + { + Uri = Uri, + ProjectContext = _projectContext, + }; - public virtual TextDocumentIdentifier Identifier => new VSTextDocumentIdentifier() + private bool TryGetCodeDocument([NotNullWhen(true)] out RazorCodeDocument? codeDocument) { - Uri = Uri, - ProjectContext = _projectContext, - }; + codeDocument = _codeDocument; + return codeDocument is not null; + } - public virtual async Task GetCodeDocumentAsync(CancellationToken cancellationToken) + public ValueTask GetCodeDocumentAsync(CancellationToken cancellationToken) { - if (_codeDocument is null) + return TryGetCodeDocument(out var codeDocument) + ? new(codeDocument) + : GetCodeDocumentCoreAsync(cancellationToken); + + async ValueTask GetCodeDocumentCoreAsync(CancellationToken cancellationToken) { var codeDocument = await Snapshot.GetGeneratedOutputAsync().ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); - _codeDocument = codeDocument; + // Interlock to ensure that we only ever return one instance of RazorCodeDocument. + // In race scenarios, when more than one RazorCodeDocument is produced, we want to + // return whichever RazorCodeDocument is cached. + return InterlockedOperations.Initialize(ref _codeDocument, codeDocument); } - - return _codeDocument; } - public virtual async Task GetSourceTextAsync(CancellationToken cancellationToken) + public ValueTask GetSourceTextAsync(CancellationToken cancellationToken) { - if (_sourceText is null) + return _sourceText is SourceText sourceText + ? new(sourceText) + : GetSourceTextCoreAsync(cancellationToken); + + async ValueTask GetSourceTextCoreAsync(CancellationToken cancellationToken) { var sourceText = await Snapshot.GetTextAsync().ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); - _sourceText = sourceText; + // Interlock to ensure that we only ever return one instance of RazorCodeDocument. + // In race scenarios, when more than one RazorCodeDocument is produced, we want to + // return whichever RazorCodeDocument is cached. + return InterlockedOperations.Initialize(ref _sourceText, sourceText); } - - return _sourceText; } - public virtual async Task GetSyntaxTreeAsync(CancellationToken cancellationToken) + public ValueTask GetSyntaxTreeAsync(CancellationToken cancellationToken) { - var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var syntaxTree = codeDocument.GetSyntaxTree(); + return TryGetCodeDocument(out var codeDocument) + ? new(GetSyntaxTreeCore(codeDocument)) + : GetSyntaxTreeCoreAsync(cancellationToken); - return syntaxTree; + static RazorSyntaxTree GetSyntaxTreeCore(RazorCodeDocument codeDocument) + { + return codeDocument.GetSyntaxTree().AssumeNotNull(); + } + + async ValueTask GetSyntaxTreeCoreAsync(CancellationToken cancellationToken) + { + var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + return GetSyntaxTreeCore(codeDocument); + } } - public virtual async Task GetTagHelperContextAsync(CancellationToken cancellationToken) + public ValueTask GetTagHelperContextAsync(CancellationToken cancellationToken) { - var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var tagHelperContext = codeDocument.GetTagHelperContext(); + return TryGetCodeDocument(out var codeDocument) + ? new(GetTagHelperContextCore(codeDocument)) + : GetTagHelperContextCoreAsync(cancellationToken); - return tagHelperContext; + static TagHelperDocumentContext GetTagHelperContextCore(RazorCodeDocument codeDocument) + { + return codeDocument.GetTagHelperContext().AssumeNotNull(); + } + + async ValueTask GetTagHelperContextCoreAsync(CancellationToken cancellationToken) + { + var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + return GetTagHelperContextCore(codeDocument); + } } - public virtual async Task GetCSharpSourceTextAsync(CancellationToken cancellationToken) + public ValueTask GetCSharpSourceTextAsync(CancellationToken cancellationToken) { - var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var sourceText = codeDocument.GetCSharpSourceText(); + return TryGetCodeDocument(out var codeDocument) + ? new(GetCSharpSourceTextCore(codeDocument)) + : GetCSharpSourceTextCoreAsync(cancellationToken); - return sourceText; + static SourceText GetCSharpSourceTextCore(RazorCodeDocument codeDocument) + { + return codeDocument.GetCSharpSourceText(); + } + + async ValueTask GetCSharpSourceTextCoreAsync(CancellationToken cancellationToken) + { + var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + return GetCSharpSourceTextCore(codeDocument); + } } - public virtual async Task GetHtmlSourceTextAsync(CancellationToken cancellationToken) + public ValueTask GetHtmlSourceTextAsync(CancellationToken cancellationToken) { - var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var sourceText = codeDocument.GetHtmlSourceText(); + return TryGetCodeDocument(out var codeDocument) + ? new(GetHtmlSourceTextCore(codeDocument)) + : GetHtmlSourceTextCoreAsync(cancellationToken); - return sourceText; + static SourceText GetHtmlSourceTextCore(RazorCodeDocument codeDocument) + { + return codeDocument.GetHtmlSourceText(); + } + + async ValueTask GetHtmlSourceTextCoreAsync(CancellationToken cancellationToken) + { + var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + return GetHtmlSourceTextCore(codeDocument); + } } - public async Task GetSyntaxNodeAsync(int absoluteIndex, CancellationToken cancellationToken) + public ValueTask GetSyntaxNodeAsync(int absoluteIndex, CancellationToken cancellationToken) { - var syntaxTree = await GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - if (syntaxTree.Root is null) + return TryGetCodeDocument(out var codeDocument) + ? new(GetSyntaxNodeCore(codeDocument, absoluteIndex)) + : GetSyntaxNodeCoreAsync(absoluteIndex, cancellationToken); + + static RazorSyntaxNode? GetSyntaxNodeCore(RazorCodeDocument codeDocument, int absoluteIndex) { - return null; + var syntaxTree = codeDocument.GetSyntaxTree().AssumeNotNull(); + + return syntaxTree.Root is RazorSyntaxNode root + ? root.FindInnermostNode(absoluteIndex) + : null; } - return syntaxTree.Root.FindInnermostNode(absoluteIndex); + async ValueTask GetSyntaxNodeCoreAsync(int absoluteIndex, CancellationToken cancellationToken) + { + var codeDocument = await GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + return GetSyntaxNodeCore(codeDocument, absoluteIndex); + } } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/VersionedDocumentContext.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/VersionedDocumentContext.cs index b203540027e..6c4bbcf8ade 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/VersionedDocumentContext.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/VersionedDocumentContext.cs @@ -7,18 +7,11 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -internal class VersionedDocumentContext : DocumentContext +internal class VersionedDocumentContext(Uri uri, IDocumentSnapshot snapshot, VSProjectContext? projectContext, int version) + : DocumentContext(uri, snapshot, projectContext) { - public virtual int Version { get; } + public int Version { get; } = version; - public VersionedDocumentContext(Uri uri, IDocumentSnapshot snapshot, VSProjectContext? projectContext, int version) - : base(uri, snapshot, projectContext) - { - Version = version; - } - - // Sadly we target net472 which doesn't support covariant return types, so this can't override. - public new TextDocumentIdentifierAndVersion Identifier => new TextDocumentIdentifierAndVersion( - base.Identifier, - Version); + public TextDocumentIdentifierAndVersion GetTextDocumentIdentifierAndVersion() + => new(GetTextDocumentIdentifier(), Version); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs index b39900715b0..90b3f93b7db 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs @@ -52,8 +52,24 @@ public DelegatedCompletionItemResolverTest(ITestOutputHelper testOutput) }; var documentContext = TestDocumentContext.From("C:/path/to/file.cshtml", hostDocumentVersion: 0); - _csharpCompletionParams = new DelegatedCompletionParams(documentContext.Identifier, VsLspFactory.CreatePosition(10, 6), RazorLanguageKind.CSharp, new VSInternalCompletionContext(), ProvisionalTextEdit: null, ShouldIncludeSnippets: false, CorrelationId: Guid.Empty); - _htmlCompletionParams = new DelegatedCompletionParams(documentContext.Identifier, VsLspFactory.DefaultPosition, RazorLanguageKind.Html, new VSInternalCompletionContext(), ProvisionalTextEdit: null, ShouldIncludeSnippets: false, CorrelationId: Guid.Empty); + _csharpCompletionParams = new DelegatedCompletionParams( + documentContext.GetTextDocumentIdentifierAndVersion(), + VsLspFactory.CreatePosition(10, 6), + RazorLanguageKind.CSharp, + new VSInternalCompletionContext(), + ProvisionalTextEdit: null, + ShouldIncludeSnippets: false, + CorrelationId: Guid.Empty); + + _htmlCompletionParams = new DelegatedCompletionParams( + documentContext.GetTextDocumentIdentifierAndVersion(), + VsLspFactory.DefaultPosition, + RazorLanguageKind.Html, + new VSInternalCompletionContext(), + ProvisionalTextEdit: null, + ShouldIncludeSnippets: false, + CorrelationId: Guid.Empty); + _documentContextFactory = new TestDocumentContextFactory(); _formattingService = new AsyncLazy(() => TestRazorFormattingService.CreateWithFullSupportAsync(LoggerFactory)); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperServiceTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperServiceTestBase.cs index a684d4632e8..7a2dbb635fc 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperServiceTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperServiceTestBase.cs @@ -248,14 +248,17 @@ public TagHelperServiceTestBase(ITestOutputHelper testOutput) RazorTagHelperCompletionService = new LspTagHelperCompletionService(); } + protected static string GetFileName(bool isRazorFile) + => isRazorFile ? RazorFile : CSHtmlFile; + internal static RazorCodeDocument CreateCodeDocument(string text, bool isRazorFile, ImmutableArray tagHelpers) { - return CreateCodeDocument(text, isRazorFile ? RazorFile : CSHtmlFile, tagHelpers); + return CreateCodeDocument(text, GetFileName(isRazorFile), tagHelpers); } internal static RazorCodeDocument CreateCodeDocument(string text, bool isRazorFile, params TagHelperDescriptor[] tagHelpers) { - return CreateCodeDocument(text, isRazorFile ? RazorFile : CSHtmlFile, tagHelpers); + return CreateCodeDocument(text, GetFileName(isRazorFile), tagHelpers); } internal static RazorCodeDocument CreateCodeDocument(string text, string filePath, ImmutableArray tagHelpers) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs index 4c460d0cffd..086eb0e0d3d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs @@ -923,34 +923,31 @@ private static VersionedDocumentContext CreateDocumentContext( string documentText, bool isRazorFile, ImmutableArray tagHelpers, - int? documentVersion) + int version) { var document = CreateCodeDocument(documentText, isRazorFile, tagHelpers); - var random = new Random(); - var projectSnapshot = new Mock(MockBehavior.Strict); + var projectSnapshot = new StrictMock(); projectSnapshot - .Setup(p => p.Version) - .Returns(default(VersionStamp)); + .SetupGet(p => p.Version) + .Returns(VersionStamp.Default); - var documentSnapshot = Mock.Of(MockBehavior.Strict); - var documentContext = new Mock(MockBehavior.Strict, new Uri("c:/path/to/file.razor"), documentSnapshot, /* projectContext */ null, 0); - documentContext.Setup(d => d.GetCodeDocumentAsync(It.IsAny())) - .ReturnsAsync(document); - - documentContext.SetupGet(d => d.Version) - .Returns(documentVersion ?? random.Next()); - - documentContext.Setup(d => d.Project) + var documentSnapshotMock = new StrictMock(); + documentSnapshotMock + .SetupGet(x => x.Project) .Returns(projectSnapshot.Object); - - documentContext.Setup(d => d.GetSourceTextAsync(It.IsAny())) - .Returns(Task.FromResult(document.Source.Text)); - - documentContext.Setup(d => d.Uri) - .Returns(new Uri($"c:\\${(isRazorFile ? RazorFile : CSHtmlFile)}")); - - return documentContext.Object; + documentSnapshotMock + .Setup(x => x.GetGeneratedOutputAsync()) + .ReturnsAsync(document); + documentSnapshotMock + .Setup(x => x.GetTextAsync()) + .ReturnsAsync(document.Source.Text); + + return new VersionedDocumentContext( + uri: new Uri($@"c:\${GetFileName(isRazorFile)}"), + snapshot: documentSnapshotMock.Object, + projectContext: null, + version); } private async Task CreateServiceAsync( diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/StrictMock`1.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/StrictMock`1.cs index c71e952f94c..062f31cbf03 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/StrictMock`1.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/StrictMock`1.cs @@ -13,7 +13,7 @@ public StrictMock() { } - public StrictMock(params object[] args) + public StrictMock(params object?[] args) : base(MockBehavior.Strict, args) { } From c0bc542d882acac2dc0a41a3e485fcc427ced403 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 11:16:54 -0700 Subject: [PATCH 25/53] Introduce IEditMappingService In order to remove `IDocumentContextFactory` from `AbstractRazorDocumentMappingService`, it's necessary to split `IRazorDocumentMappingService` into different services. The goal is to make `IRazorDocumentMappingService` provide APIs that only perform mapping using Roslyn primitives, such as `LinePosition`, `LinePositionSpan`, and `TextChange`. `IEditMappingService` contains an API moved from `IRazorDocumentMappingService` that remaps a `WorkspaceEdit`. --- .../Html/DefaultHtmlCodeActionProvider.cs | 11 +- .../Html/DefaultHtmlCodeActionResolver.cs | 6 +- .../EditMappingService.cs | 173 ++++++++++++++++++ .../IServiceCollectionExtensions.cs | 1 + .../Refactoring/RenameEndpoint.cs | 5 +- .../AbstractRazorDocumentMappingService.cs | 128 ------------- .../DocumentMapping/IEditMappingService.cs | 13 ++ .../IRazorDocumentMappingService.cs | 3 - .../Html/DefaultHtmlCodeActionProviderTest.cs | 11 +- .../Html/DefaultHtmlCodeActionResolverTest.cs | 11 +- .../Completion/TestDocumentMappingService.cs | 6 - .../RenameEndpointDelegationTest.cs | 1 + .../Refactoring/RenameEndpointTest.cs | 49 +++-- .../SingleServerDelegatingEndpointTestBase.cs | 4 +- 14 files changed, 247 insertions(+), 175 deletions(-) create mode 100644 src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IEditMappingService.cs diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionProvider.cs index 5f7f6d007e0..87ecec1b541 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionProvider.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -14,9 +13,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; -internal sealed class DefaultHtmlCodeActionProvider(IRazorDocumentMappingService documentMappingService) : IHtmlCodeActionProvider +internal sealed class DefaultHtmlCodeActionProvider(IEditMappingService editMappingService) : IHtmlCodeActionProvider { - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IEditMappingService _editMappingService = editMappingService; public async Task> ProvideAsync( RazorCodeActionContext context, @@ -28,7 +27,7 @@ public async Task> ProvideAsync( { if (codeAction.Edit is not null) { - await RemapAndFixHtmlCodeActionEditAsync(_documentMappingService, context.CodeDocument, codeAction, cancellationToken).ConfigureAwait(false); + await RemapAndFixHtmlCodeActionEditAsync(_editMappingService, context.CodeDocument, codeAction, cancellationToken).ConfigureAwait(false); results.Add(codeAction); } @@ -41,11 +40,11 @@ public async Task> ProvideAsync( return results.ToImmutable(); } - public static async Task RemapAndFixHtmlCodeActionEditAsync(IRazorDocumentMappingService documentMappingService, RazorCodeDocument codeDocument, CodeAction codeAction, CancellationToken cancellationToken) + public static async Task RemapAndFixHtmlCodeActionEditAsync(IEditMappingService editMappingService, RazorCodeDocument codeDocument, CodeAction codeAction, CancellationToken cancellationToken) { Assumes.NotNull(codeAction.Edit); - codeAction.Edit = await documentMappingService.RemapWorkspaceEditAsync(codeAction.Edit, cancellationToken).ConfigureAwait(false); + codeAction.Edit = await editMappingService.RemapWorkspaceEditAsync(codeAction.Edit, cancellationToken).ConfigureAwait(false); if (codeAction.Edit.TryGetDocumentChanges(out var documentEdits) == true) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionResolver.cs index 604f02a3458..0fce29fdc6f 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionResolver.cs @@ -16,10 +16,10 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; internal sealed class DefaultHtmlCodeActionResolver( IDocumentContextFactory documentContextFactory, IClientConnection clientConnection, - IRazorDocumentMappingService documentMappingService) : HtmlCodeActionResolver(clientConnection) + IEditMappingService editMappingService) : HtmlCodeActionResolver(clientConnection) { private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IEditMappingService _editMappingService = editMappingService; public override string Action => LanguageServerConstants.CodeActions.Default; @@ -41,7 +41,7 @@ public async override Task ResolveAsync( } var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - await DefaultHtmlCodeActionProvider.RemapAndFixHtmlCodeActionEditAsync(_documentMappingService, codeDocument, resolvedCodeAction, cancellationToken).ConfigureAwait(false); + await DefaultHtmlCodeActionProvider.RemapAndFixHtmlCodeActionEditAsync(_editMappingService, codeDocument, resolvedCodeAction, cancellationToken).ConfigureAwait(false); return resolvedCodeAction; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs new file mode 100644 index 00000000000..3b8c6a30d68 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs @@ -0,0 +1,173 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.CodeAnalysis.Razor.DocumentMapping; +using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.VisualStudio.LanguageServer.Protocol; + +namespace Microsoft.AspNetCore.Razor.LanguageServer; + +internal sealed class EditMappingService( + IRazorDocumentMappingService documentMappingService, + IFilePathService filePathService, + IDocumentContextFactory documentContextFactory) : IEditMappingService +{ + private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IFilePathService _filePathService = filePathService; + private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; + + public async Task RemapWorkspaceEditAsync(WorkspaceEdit workspaceEdit, CancellationToken cancellationToken) + { + if (workspaceEdit.TryGetDocumentChanges(out var documentChanges)) + { + // The LSP spec says, we should prefer `DocumentChanges` property over `Changes` if available. + var remappedEdits = await RemapVersionedDocumentEditsAsync(documentChanges, cancellationToken).ConfigureAwait(false); + + return new WorkspaceEdit() + { + DocumentChanges = remappedEdits + }; + } + + if (workspaceEdit.Changes is { } changeMap) + { + var remappedEdits = await RemapDocumentEditsAsync(changeMap, cancellationToken).ConfigureAwait(false); + + return new WorkspaceEdit() + { + Changes = remappedEdits + }; + } + + return workspaceEdit; + } + + private async Task RemapVersionedDocumentEditsAsync(TextDocumentEdit[] documentEdits, CancellationToken cancellationToken) + { + using var remappedDocumentEdits = new PooledArrayBuilder(documentEdits.Length); + + foreach (var entry in documentEdits) + { + var generatedDocumentUri = entry.TextDocument.Uri; + + // Check if the edit is actually for a generated document, because if not we don't need to do anything + if (!_filePathService.IsVirtualDocumentUri(generatedDocumentUri)) + { + // This location doesn't point to a background razor file. No need to remap. + remappedDocumentEdits.Add(entry); + continue; + } + + var razorDocumentUri = _filePathService.GetRazorDocumentUri(generatedDocumentUri); + + if (!_documentContextFactory.TryCreateForOpenDocument(razorDocumentUri, entry.TextDocument.GetProjectContext(), out var documentContext)) + { + continue; + } + + var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + + var remappedEdits = RemapTextEditsCore(generatedDocumentUri, codeDocument, entry.Edits); + if (remappedEdits.Length == 0) + { + // Nothing to do. + continue; + } + + remappedDocumentEdits.Add(new() + { + TextDocument = new OptionalVersionedTextDocumentIdentifier() + { + Uri = razorDocumentUri, + Version = documentContext.Version + }, + Edits = remappedEdits + }); + } + + return remappedDocumentEdits.ToArray(); + } + + private async Task> RemapDocumentEditsAsync(Dictionary changes, CancellationToken cancellationToken) + { + var remappedChanges = new Dictionary(capacity: changes.Count); + + foreach (var (uriString, edits) in changes) + { + var uri = new Uri(uriString); + + // Check if the edit is actually for a generated document, because if not we don't need to do anything + if (!_filePathService.IsVirtualDocumentUri(uri)) + { + remappedChanges[uriString] = edits; + continue; + } + + if (!_documentContextFactory.TryCreate(uri, out var documentContext)) + { + continue; + } + + var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + var remappedEdits = RemapTextEditsCore(uri, codeDocument, edits); + if (remappedEdits.Length == 0) + { + // Nothing to do. + continue; + } + + var razorDocumentUri = _filePathService.GetRazorDocumentUri(uri); + remappedChanges[razorDocumentUri.AbsoluteUri] = remappedEdits; + } + + return remappedChanges; + } + + private TextEdit[] RemapTextEditsCore(Uri generatedDocumentUri, RazorCodeDocument codeDocument, TextEdit[] edits) + { + var generatedDocument = GetGeneratedDocumentFromGeneratedDocumentUri(generatedDocumentUri, codeDocument); + if (generatedDocument is null) + { + return edits; + } + + using var remappedEdits = new PooledArrayBuilder(edits.Length); + + foreach (var edit in edits) + { + var generatedRange = edit.Range; + if (!_documentMappingService.TryMapToHostDocumentRange(generatedDocument, generatedRange, MappingBehavior.Strict, out var hostDocumentRange)) + { + // Can't map range. Discard this edit. + continue; + } + + var remappedEdit = VsLspFactory.CreateTextEdit(hostDocumentRange, edit.NewText); + remappedEdits.Add(remappedEdit); + } + + return remappedEdits.ToArray(); + } + + private IRazorGeneratedDocument? GetGeneratedDocumentFromGeneratedDocumentUri(Uri generatedDocumentUri, RazorCodeDocument codeDocument) + { + if (_filePathService.IsVirtualCSharpFile(generatedDocumentUri)) + { + return codeDocument.GetCSharpDocument(); + } + + if (_filePathService.IsVirtualHtmlFile(generatedDocumentUri)) + { + return codeDocument.GetHtmlDocument(); + } + + return null; + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs index ad0a81ca49b..07765b13cbf 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs @@ -203,6 +203,7 @@ public static void AddDocumentManagementServices(this IServiceCollection service services.AddSingleton((services) => (RazorProjectService)services.GetRequiredService()); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(sp => sp.GetRequiredService()); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs index ebe295c2918..65d6787d33a 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs @@ -31,6 +31,7 @@ internal sealed class RenameEndpoint( IProjectCollectionResolver projectResolver, LanguageServerFeatureOptions languageServerFeatureOptions, IRazorDocumentMappingService documentMappingService, + IEditMappingService editMappingService, IClientConnection clientConnection, ILoggerFactory loggerFactory) : AbstractRazorDelegatingEndpoint( @@ -42,7 +43,7 @@ internal sealed class RenameEndpoint( private readonly IProjectCollectionResolver _projectResolver = projectResolver; private readonly IRazorComponentSearchEngine _componentSearchEngine = componentSearchEngine; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions = languageServerFeatureOptions; - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IEditMappingService _editMappingService = editMappingService; public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, VSInternalClientCapabilities clientCapabilities) { @@ -104,7 +105,7 @@ protected override bool IsSupported() return null; } - return await _documentMappingService.RemapWorkspaceEditAsync(response, cancellationToken).ConfigureAwait(false); + return await _editMappingService.RemapWorkspaceEditAsync(response, cancellationToken).ConfigureAwait(false); } private async Task TryGetRazorComponentRenameEditsAsync(RenameParams request, int absoluteIndex, DocumentContext documentContext, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs index afdc7ca2d93..d80f679a6f0 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs @@ -359,29 +359,6 @@ public RazorLanguageKind GetLanguageKind(RazorCodeDocument codeDocument, int hos return languageKind; } - public async Task RemapWorkspaceEditAsync(WorkspaceEdit workspaceEdit, CancellationToken cancellationToken) - { - if (workspaceEdit.TryGetDocumentChanges(out var documentChanges)) - { - // The LSP spec says, we should prefer `DocumentChanges` property over `Changes` if available. - var remappedEdits = await RemapVersionedDocumentEditsAsync(documentChanges, cancellationToken).ConfigureAwait(false); - return new WorkspaceEdit() - { - DocumentChanges = remappedEdits - }; - } - else if (workspaceEdit.Changes != null) - { - var remappedEdits = await RemapDocumentEditsAsync(workspaceEdit.Changes, cancellationToken).ConfigureAwait(false); - return new WorkspaceEdit() - { - Changes = remappedEdits - }; - } - - return workspaceEdit; - } - public async Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync(Uri generatedDocumentUri, LinePositionSpan generatedDocumentRange, CancellationToken cancellationToken) { var razorDocumentUri = _filePathService.GetRazorDocumentUri(generatedDocumentUri); @@ -733,111 +710,6 @@ static bool IsPositionWithinDocument(LinePosition linePosition, SourceText sourc } } - private async Task RemapVersionedDocumentEditsAsync(TextDocumentEdit[] documentEdits, CancellationToken cancellationToken) - { - using var _ = ListPool.GetPooledObject(out var remappedDocumentEdits); - foreach (var entry in documentEdits) - { - var generatedDocumentUri = entry.TextDocument.Uri; - - // Check if the edit is actually for a generated document, because if not we don't need to do anything - if (!_filePathService.IsVirtualDocumentUri(generatedDocumentUri)) - { - // This location doesn't point to a background razor file. No need to remap. - remappedDocumentEdits.Add(entry); - continue; - } - - var razorDocumentUri = _filePathService.GetRazorDocumentUri(generatedDocumentUri); - - if (!_documentContextFactory.TryCreateForOpenDocument(razorDocumentUri, entry.TextDocument.GetProjectContext(), out var documentContext)) - { - continue; - } - - var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - - var remappedEdits = RemapTextEditsCore(generatedDocumentUri, codeDocument, entry.Edits); - if (remappedEdits.Length == 0) - { - // Nothing to do. - continue; - } - - remappedDocumentEdits.Add(new TextDocumentEdit() - { - TextDocument = new OptionalVersionedTextDocumentIdentifier() - { - Uri = razorDocumentUri, - Version = documentContext.Version - }, - Edits = remappedEdits - }); - } - - return [.. remappedDocumentEdits]; - } - - private async Task> RemapDocumentEditsAsync(Dictionary changes, CancellationToken cancellationToken) - { - var remappedChanges = new Dictionary(); - foreach (var entry in changes) - { - var uri = new Uri(entry.Key); - var edits = entry.Value; - - // Check if the edit is actually for a generated document, because if not we don't need to do anything - if (!_filePathService.IsVirtualDocumentUri(uri)) - { - remappedChanges[entry.Key] = entry.Value; - continue; - } - - if (!_documentContextFactory.TryCreate(uri, out var documentContext)) - { - continue; - } - - var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var remappedEdits = RemapTextEditsCore(uri, codeDocument, edits); - if (remappedEdits.Length == 0) - { - // Nothing to do. - continue; - } - - var razorDocumentUri = _filePathService.GetRazorDocumentUri(uri); - remappedChanges[razorDocumentUri.AbsoluteUri] = remappedEdits; - } - - return remappedChanges; - } - - private TextEdit[] RemapTextEditsCore(Uri generatedDocumentUri, RazorCodeDocument codeDocument, TextEdit[] edits) - { - var generatedDocument = GetGeneratedDocumentFromGeneratedDocumentUri(generatedDocumentUri, codeDocument); - if (generatedDocument is null) - { - return edits; - } - - using var _ = ListPool.GetPooledObject(out var remappedEdits); - for (var i = 0; i < edits.Length; i++) - { - var generatedRange = edits[i].Range; - if (!this.TryMapToHostDocumentRange(generatedDocument, generatedRange, MappingBehavior.Strict, out var originalRange)) - { - // Can't map range. Discard this edit. - continue; - } - - var edit = VsLspFactory.CreateTextEdit(originalRange, edits[i].NewText); - remappedEdits.Add(edit); - } - - return [.. remappedEdits]; - } - private IRazorGeneratedDocument? GetGeneratedDocumentFromGeneratedDocumentUri(Uri generatedDocumentUri, RazorCodeDocument codeDocument) { if (_filePathService.IsVirtualCSharpFile(generatedDocumentUri)) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IEditMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IEditMappingService.cs new file mode 100644 index 00000000000..1cf7c098da4 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IEditMappingService.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; + +internal interface IEditMappingService +{ + Task RemapWorkspaceEditAsync(WorkspaceEdit workspaceEdit, CancellationToken cancellationToken); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingService.cs index 4cbdb21a09b..1f737b7be69 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingService.cs @@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; @@ -28,8 +27,6 @@ internal interface IRazorDocumentMappingService RazorLanguageKind GetLanguageKind(RazorCodeDocument codeDocument, int hostDocumentIndex, bool rightAssociative); - Task RemapWorkspaceEditAsync(WorkspaceEdit workspaceEdit, CancellationToken cancellationToken); - /// /// Maps a range in the specified generated document uri to a range in the Razor document that owns the /// generated document. If the uri passed in is not for a generated document, or the range cannot be mapped diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionProviderTest.cs index 5104d53b0fa..a02a209f947 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionProviderTest.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Models; +using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -42,7 +43,7 @@ public async Task ProvideAsync_WrapsResolvableCodeActions() var context = CreateRazorCodeActionContext(request, location, documentPath, contents); context.CodeDocument.SetFileKind(FileKinds.Legacy); - var documentMappingService = Mock.Of(MockBehavior.Strict); + var documentMappingService = StrictMock.Of(); var provider = new DefaultHtmlCodeActionProvider(documentMappingService); ImmutableArray codeActions = [ new RazorVSInternalCodeAction() { Name = "Test" } ]; @@ -90,12 +91,12 @@ public async Task ProvideAsync_RemapsAndFixesEdits() } }; - var documentMappingServiceMock = new Mock(MockBehavior.Strict); - documentMappingServiceMock - .Setup(c => c.RemapWorkspaceEditAsync(It.IsAny(), It.IsAny())) + var editMappingServiceMock = new StrictMock(); + editMappingServiceMock + .Setup(x => x.RemapWorkspaceEditAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(remappedEdit); - var provider = new DefaultHtmlCodeActionProvider(documentMappingServiceMock.Object); + var provider = new DefaultHtmlCodeActionProvider(editMappingServiceMock.Object); ImmutableArray codeActions = [ diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionResolverTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionResolverTest.cs index 5d7704aa426..9593a139a17 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionResolverTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionResolverTest.cs @@ -7,14 +7,13 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Models; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; +using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Moq; using Xunit; @@ -56,12 +55,12 @@ public async Task ResolveAsync_RemapsAndFixesEdits() Edit = remappedEdit }; - var documentMappingServiceMock = new Mock(MockBehavior.Strict); - documentMappingServiceMock - .Setup(c => c.RemapWorkspaceEditAsync(It.IsAny(), It.IsAny())) + var editMappingServiceMock = new StrictMock(); + editMappingServiceMock + .Setup(x => x.RemapWorkspaceEditAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(remappedEdit); - var resolver = new DefaultHtmlCodeActionResolver(documentContextFactory, CreateLanguageServer(resolvedCodeAction), documentMappingServiceMock.Object); + var resolver = new DefaultHtmlCodeActionResolver(documentContextFactory, CreateLanguageServer(resolvedCodeAction), editMappingServiceMock.Object); var codeAction = new RazorVSInternalCodeAction() { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs index 4d19dee877a..5b98eb4fd1c 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion; @@ -30,11 +29,6 @@ public RazorLanguageKind GetLanguageKind(RazorCodeDocument codeDocument, int hos throw new NotImplementedException(); } - public Task RemapWorkspaceEditAsync(WorkspaceEdit workspaceEdit, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - public bool TryMapToGeneratedDocumentOrNextCSharpPosition(IRazorGeneratedDocument generatedDocument, int hostDocumentIndex, out LinePosition generatedPosition, out int generatedIndex) { throw new NotImplementedException(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs index b4f067970fb..4188b6bc72b 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs @@ -71,6 +71,7 @@ await projectManager.UpdateAsync(updater => projectManager, LanguageServerFeatureOptions, DocumentMappingService, + EditMappingService, languageServer, LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs index bde6e054c50..3f0e0a3863b 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs @@ -530,9 +530,6 @@ public async Task Handle_Rename_SingleServer_CallsDelegatedLanguageServer() documentMappingServiceMock .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(RazorLanguageKind.CSharp); - documentMappingServiceMock - .Setup(c => c.RemapWorkspaceEditAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(delegatedEdit); var projectedPosition = new LinePosition(1, 1); var projectedIndex = 1; @@ -540,7 +537,16 @@ public async Task Handle_Rename_SingleServer_CallsDelegatedLanguageServer() .Setup(c => c.TryMapToGeneratedDocumentPosition(It.IsAny(), It.IsAny(), out projectedPosition, out projectedIndex)) .Returns(true); - var (endpoint, documentContextFactory) = await CreateEndpointAndDocumentContextFactoryAsync(options, documentMappingServiceMock.Object, clientConnectionMock.Object); + var editMappingServiceMock = new StrictMock(); + editMappingServiceMock + .Setup(c => c.RemapWorkspaceEditAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(delegatedEdit); + + var (endpoint, documentContextFactory) = await CreateEndpointAndDocumentContextFactoryAsync( + options, + documentMappingServiceMock.Object, + editMappingServiceMock.Object, + clientConnectionMock.Object); var uri = PathUtilities.GetUri(s_componentWithParamFilePath); var request = new RenameParams @@ -575,7 +581,13 @@ public async Task Handle_Rename_SingleServer_DoesNotDelegateForRazor() .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(RazorLanguageKind.Razor); - var (endpoint, documentContextFactory) = await CreateEndpointAndDocumentContextFactoryAsync(options, documentMappingServiceMock.Object, clientConnection); + var editMappingService = StrictMock.Of(); + + var (endpoint, documentContextFactory) = await CreateEndpointAndDocumentContextFactoryAsync( + options, + documentMappingServiceMock.Object, + editMappingService, + clientConnection); var request = new RenameParams { @@ -597,6 +609,7 @@ public async Task Handle_Rename_SingleServer_DoesNotDelegateForRazor() private async Task<(RenameEndpoint, IDocumentContextFactory)> CreateEndpointAndDocumentContextFactoryAsync( LanguageServerFeatureOptions? options = null, IRazorDocumentMappingService? documentMappingService = null, + IEditMappingService? editMappingService = null, IClientConnection? clientConnection = null) { using PooledArrayBuilder builder = []; @@ -677,16 +690,21 @@ await projectManager.UpdateAsync(updater => o.SingleServerSupport == false && o.ReturnCodeActionAndRenamePathsWithPrefixedSlash == false); - var documentMappingServiceMock = new StrictMock(); - documentMappingServiceMock - .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) - .Returns(RazorLanguageKind.Html); - var projectedPosition = new LinePosition(1, 1); - var projectedIndex = 1; - documentMappingServiceMock - .Setup(c => c.TryMapToGeneratedDocumentPosition(It.IsAny(), It.IsAny(), out projectedPosition, out projectedIndex)) - .Returns(true); - documentMappingService ??= documentMappingServiceMock.Object; + if (documentMappingService == null) + { + var documentMappingServiceMock = new StrictMock(); + documentMappingServiceMock + .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(RazorLanguageKind.Html); + var projectedPosition = new LinePosition(1, 1); + var projectedIndex = 1; + documentMappingServiceMock + .Setup(c => c.TryMapToGeneratedDocumentPosition(It.IsAny(), It.IsAny(), out projectedPosition, out projectedIndex)) + .Returns(true); + documentMappingService = documentMappingServiceMock.Object; + } + + editMappingService ??= StrictMock.Of(); clientConnection ??= StrictMock.Of(); @@ -695,6 +713,7 @@ await projectManager.UpdateAsync(updater => projectManager, options, documentMappingService, + editMappingService, clientConnection, LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs index 6d5d6cca9a2..ece9afaf242 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs @@ -25,8 +25,9 @@ public abstract partial class SingleServerDelegatingEndpointTestBase(ITestOutput private protected IDocumentContextFactory? DocumentContextFactory { get; private set; } private protected LanguageServerFeatureOptions? LanguageServerFeatureOptions { get; private set; } private protected IRazorDocumentMappingService? DocumentMappingService { get; private set; } + private protected IEditMappingService? EditMappingService { get; private set; } - [MemberNotNull(nameof(DocumentContextFactory), nameof(LanguageServerFeatureOptions), nameof(DocumentMappingService))] + [MemberNotNull(nameof(DocumentContextFactory), nameof(LanguageServerFeatureOptions), nameof(DocumentMappingService), nameof(EditMappingService))] private protected async Task CreateLanguageServerAsync( RazorCodeDocument codeDocument, string razorFilePath, @@ -65,6 +66,7 @@ private protected async Task CreateLanguageServerAsync( MockBehavior.Strict); DocumentMappingService = new RazorDocumentMappingService(FilePathService, DocumentContextFactory, LoggerFactory); + EditMappingService = new EditMappingService(DocumentMappingService, FilePathService, DocumentContextFactory); var csharpServer = await CSharpTestLspServerHelpers.CreateCSharpLspServerAsync( csharpFiles, From d638bce9f078ab27fd2707e29696907686863606 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 11:25:12 -0700 Subject: [PATCH 26/53] Add RazorCodeDocument.TryGetGeneratedDocument(...) extension method This allows `EditMappingService` and `AbstractRazorDocumentMappingService` to share a helper method. --- .../EditMappingService.cs | 18 +------------ .../AbstractRazorDocumentMappingService.cs | 23 +++-------------- .../Extensions/RazorCodeDocumentExtensions.cs | 25 +++++++++++++++++++ 3 files changed, 30 insertions(+), 36 deletions(-) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs index 3b8c6a30d68..4dfb076fc6b 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs @@ -132,8 +132,7 @@ private async Task> RemapDocumentEditsAsync(Dicti private TextEdit[] RemapTextEditsCore(Uri generatedDocumentUri, RazorCodeDocument codeDocument, TextEdit[] edits) { - var generatedDocument = GetGeneratedDocumentFromGeneratedDocumentUri(generatedDocumentUri, codeDocument); - if (generatedDocument is null) + if (!codeDocument.TryGetGeneratedDocument(generatedDocumentUri, _filePathService, out var generatedDocument)) { return edits; } @@ -155,19 +154,4 @@ private TextEdit[] RemapTextEditsCore(Uri generatedDocumentUri, RazorCodeDocumen return remappedEdits.ToArray(); } - - private IRazorGeneratedDocument? GetGeneratedDocumentFromGeneratedDocumentUri(Uri generatedDocumentUri, RazorCodeDocument codeDocument) - { - if (_filePathService.IsVirtualCSharpFile(generatedDocumentUri)) - { - return codeDocument.GetCSharpDocument(); - } - - if (_filePathService.IsVirtualHtmlFile(generatedDocumentUri)) - { - return codeDocument.GetHtmlDocument(); - } - - return null; - } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs index d80f679a6f0..16450f5a5f7 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs @@ -381,10 +381,11 @@ public RazorLanguageKind GetLanguageKind(RazorCodeDocument codeDocument, int hos } var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var generatedDocument = GetGeneratedDocumentFromGeneratedDocumentUri(generatedDocumentUri, codeDocument); - // We already checked that the uri was for a generated document, above - Assumes.NotNull(generatedDocument); + if (!codeDocument.TryGetGeneratedDocument(generatedDocumentUri, _filePathService, out var generatedDocument)) + { + return Assumed.Unreachable<(Uri, LinePositionSpan)>(); + } if (TryMapToHostDocumentRange(generatedDocument, generatedDocumentRange, MappingBehavior.Strict, out var mappedRange)) { @@ -710,22 +711,6 @@ static bool IsPositionWithinDocument(LinePosition linePosition, SourceText sourc } } - private IRazorGeneratedDocument? GetGeneratedDocumentFromGeneratedDocumentUri(Uri generatedDocumentUri, RazorCodeDocument codeDocument) - { - if (_filePathService.IsVirtualCSharpFile(generatedDocumentUri)) - { - return codeDocument.GetCSharpDocument(); - } - else if (_filePathService.IsVirtualHtmlFile(generatedDocumentUri)) - { - return codeDocument.GetHtmlDocument(); - } - else - { - return null; - } - } - private static ImmutableArray GetClassifiedSpans(RazorCodeDocument document) { // Since this service is called so often, we get a good performance improvement by caching these values diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs index c542c6e3cf3..8341fe945df 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs @@ -1,11 +1,14 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. +using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.AspNetCore.Razor.Language.Intermediate; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Protocol; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; namespace Microsoft.AspNetCore.Razor.Language; @@ -43,6 +46,28 @@ public static SourceText GetHtmlSourceText(this RazorCodeDocument document) return sourceText.AssumeNotNull(); } + public static bool TryGetGeneratedDocument( + this RazorCodeDocument codeDocument, + Uri generatedDocumentUri, + IFilePathService filePathService, + [NotNullWhen(true)] out IRazorGeneratedDocument? generatedDocument) + { + if (filePathService.IsVirtualCSharpFile(generatedDocumentUri)) + { + generatedDocument = codeDocument.GetCSharpDocument(); + return true; + } + + if (filePathService.IsVirtualHtmlFile(generatedDocumentUri)) + { + generatedDocument = codeDocument.GetHtmlDocument(); + return true; + } + + generatedDocument = null; + return false; + } + public static SourceText GetGeneratedSourceText(this RazorCodeDocument document, IRazorGeneratedDocument generatedDocument) => generatedDocument switch { From 75e06cbaa29b366398fd6beac6fd8bcce3069959 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 11:42:57 -0700 Subject: [PATCH 27/53] Remove IDocumentContextFactory from AbstractRazorDocumentMappingService This change removes `IDocumentContextFactory` from the `AbstracRazorDocumentMappingService` and replaces the single usage with a new protected abstract method. --- .../RazorDocumentMappingService.cs | 23 +++++++++++++++---- .../AbstractRazorDocumentMappingService.cs | 15 ++++-------- .../RemoteDocumentMappingService.cs | 15 +++++++----- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentMappingService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentMappingService.cs index 61d7886acef..37f56bf372e 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentMappingService.cs @@ -1,6 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -9,9 +13,20 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer; internal sealed class RazorDocumentMappingService( - IFilePathService filePathService, - IDocumentContextFactory documentContextFactory, - ILoggerFactory loggerFactory) - : AbstractRazorDocumentMappingService(filePathService, documentContextFactory, loggerFactory.GetOrCreateLogger()) + IFilePathService filePathService, + IDocumentContextFactory documentContextFactory, + ILoggerFactory loggerFactory) + : AbstractRazorDocumentMappingService(filePathService, loggerFactory.GetOrCreateLogger()) { + private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; + + protected override async ValueTask TryGetCodeDocumentAsync(Uri razorDocumentUri, CancellationToken cancellationToken) + { + if (!_documentContextFactory.TryCreate(razorDocumentUri, out var documentContext)) + { + return null; + } + + return await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs index 16450f5a5f7..4af45dbecb4 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs @@ -14,7 +14,6 @@ using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; @@ -22,16 +21,13 @@ namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; -internal abstract class AbstractRazorDocumentMappingService( - IFilePathService filePathService, - IDocumentContextFactory documentContextFactory, - ILogger logger) - : IRazorDocumentMappingService +internal abstract class AbstractRazorDocumentMappingService(IFilePathService filePathService, ILogger logger) : IRazorDocumentMappingService { private readonly IFilePathService _filePathService = filePathService; - private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; private readonly ILogger _logger = logger; + protected abstract ValueTask TryGetCodeDocumentAsync(Uri razorDocumentUri, CancellationToken cancellationToken); + public IEnumerable GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument, IEnumerable generatedDocumentChanges) { var generatedDocumentSourceText = generatedDocument.GetGeneratedSourceText(); @@ -375,13 +371,12 @@ public RazorLanguageKind GetLanguageKind(RazorCodeDocument codeDocument, int hos return (generatedDocumentUri, generatedDocumentRange); } - if (!_documentContextFactory.TryCreate(razorDocumentUri, out var documentContext)) + var codeDocument = await TryGetCodeDocumentAsync(razorDocumentUri, cancellationToken).ConfigureAwait(false); + if (codeDocument is null) { return (generatedDocumentUri, generatedDocumentRange); } - var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - if (!codeDocument.TryGetGeneratedDocument(generatedDocumentUri, _filePathService, out var generatedDocument)) { return Assumed.Unreachable<(Uri, LinePositionSpan)>(); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs index 746868a1236..57f65b116ec 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs @@ -1,10 +1,13 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. +using System; using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; namespace Microsoft.CodeAnalysis.Remote.Razor.DocumentMapping; @@ -13,11 +16,11 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.DocumentMapping; [method: ImportingConstructor] internal sealed class RemoteDocumentMappingService( IFilePathService filePathService, - IDocumentContextFactory documentContextFactory, ILoggerFactory loggerFactory) - : AbstractRazorDocumentMappingService( - filePathService, - documentContextFactory, - loggerFactory.GetOrCreateLogger()) + : AbstractRazorDocumentMappingService(filePathService, loggerFactory.GetOrCreateLogger()) { + protected override ValueTask TryGetCodeDocumentAsync(Uri razorDocumentUri, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } From e3d92581f29b3356a00647cfb5c8e9069dfe5e05 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 11:58:56 -0700 Subject: [PATCH 28/53] Rename IRazorDocumentMappingService to IDocumentMappingService --- .../RazorCodeActionsBenchmark.cs | 2 +- .../RazorCompletionBenchmark.cs | 4 ++-- .../RazorDiagnosticsBenchmark.cs | 4 ++-- .../RazorDocumentMappingBenchmark.cs | 4 ++-- .../RazorSemanticTokensBenchmark.cs | 2 +- ...zorSemanticTokensRangeEndpointBenchmark.cs | 2 +- .../AbstractRazorDelegatingEndpoint.cs | 4 ++-- .../AutoInsert/OnAutoInsertEndpoint.cs | 2 +- ...AttributeValuesDocumentPositionStrategy.cs | 2 +- ...mattedRemappingCSharpCodeActionResolver.cs | 4 ++-- .../CodeActions/CodeActionEndpoint.cs | 4 ++-- .../Razor/GenerateMethodCodeActionResolver.cs | 4 ++-- .../DelegatedCompletionListProvider.cs | 4 ++-- .../Debugging/RazorBreakpointSpanEndpoint.cs | 4 ++-- .../RazorProximityExpressionsEndpoint.cs | 4 ++-- .../ValidateBreakpointRangeEndpoint.cs | 4 ++-- .../DefaultDocumentPositionInfoStrategy.cs | 2 +- .../Definition/DefinitionEndpoint.cs | 6 ++--- .../RazorTranslateDiagnosticsService.cs | 6 ++--- .../DocumentHighlightEndpoint.cs | 4 ++-- ...actTextDocumentPresentationEndpointBase.cs | 12 +++++----- .../TextDocumentTextPresentationEndpoint.cs | 4 ++-- .../TextDocumentUriPresentationEndpoint.cs | 4 ++-- .../DocumentSymbols/DocumentSymbolEndpoint.cs | 4 ++-- .../EditMappingService.cs | 4 ++-- .../IServiceCollectionExtensions.cs | 2 +- .../FindAllReferencesEndpoint.cs | 4 ++-- .../Formatting/CSharpFormatter.cs | 4 ++-- .../Formatting/CSharpFormattingPass.cs | 2 +- .../Formatting/CSharpFormattingPassBase.cs | 2 +- .../Formatting/CSharpOnTypeFormattingPass.cs | 2 +- .../DocumentOnTypeFormattingEndpoint.cs | 6 ++--- .../FormattingContentValidationPass.cs | 2 +- .../FormattingDiagnosticValidationPass.cs | 2 +- .../Formatting/FormattingPassBase.cs | 4 ++-- .../Formatting/HtmlFormattingPass.cs | 2 +- .../Formatting/RazorFormattingPass.cs | 2 +- .../Hover/HoverEndpoint.cs | 2 +- .../Hover/HoverService.cs | 8 +++---- .../IDocumentPositionInfoStrategy.cs | 2 +- .../Implementation/ImplementationEndpoint.cs | 4 ++-- .../InlayHints/InlayHintService.cs | 4 ++-- .../InlineCompletionEndPoint.cs | 4 ++-- .../MapCode/MapCodeEndpoint.cs | 4 ++-- .../Mapping/RazorLanguageQueryEndpoint.cs | 4 ++-- .../RazorMapToDocumentRangesEndpoint.cs | 4 ++-- ...tributeNameDocumentPositionInfoStrategy.cs | 2 +- .../Refactoring/RenameEndpoint.cs | 2 +- .../RazorSemanticTokensInfoService.cs | 2 +- .../SignatureHelp/SignatureHelpEndpoint.cs | 2 +- .../SpellCheck/DocumentSpellCheckEndpoint.cs | 4 ++-- .../WrapWithTag/WrapWithTagEndpoint.cs | 6 ++--- .../AbstractRazorDocumentMappingService.cs | 2 +- ...gService.cs => IDocumentMappingService.cs} | 2 +- .../IRazorDocumentMappingServiceExtensions.cs | 22 +++++++++---------- .../FoldingRanges/FoldingRangeService.cs | 4 ++-- .../AbstractRazorSemanticTokensInfoService.cs | 4 ++-- .../RemoteDocumentHighlightService.cs | 2 +- .../RemoteDocumentMappingService.cs | 2 +- .../FoldingRanges/OOPFoldingRangeService.cs | 2 +- .../InlayHints/RemoteInlayHintService.cs | 2 +- .../RazorSemanticTokensInfoService.cs | 2 +- .../RemoteSignatureHelpService.cs | 2 +- .../RemoteUriPresentationService.cs | 2 +- .../CodeActions/CodeActionEndpointTest.cs | 10 ++++----- .../Completion/TestDocumentMappingService.cs | 2 +- .../RazorBreakpointSpanEndpointTest.cs | 2 +- .../RazorProximityExpressionsEndpointTest.cs | 2 +- .../RazorDiagnosticsPublisherTest.cs | 16 +++++++------- ...xtDocumentTextPresentationEndpointTests.cs | 8 +++---- ...extDocumentUriPresentationEndpointTests.cs | 22 +++++++++---------- .../DocumentOnTypeFormattingEndpointTest.cs | 4 ++-- .../Hover/HoverServiceTest.cs | 8 +++---- .../Mapping/RazorLanguageQueryEndpointTest.cs | 12 +++++----- .../RazorMapToDocumentRangesEndpointTest.cs | 18 +++++++-------- .../Refactoring/RenameEndpointTest.cs | 8 +++---- .../SingleServerDelegatingEndpointTestBase.cs | 2 +- .../WrapWithTag/WrapWithTagEndpointTests.cs | 14 ++++++------ 78 files changed, 182 insertions(+), 182 deletions(-) rename src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/{IRazorDocumentMappingService.cs => IDocumentMappingService.cs} (97%) diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs index 8f8a680ae8f..efeead6a96e 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs @@ -49,7 +49,7 @@ public enum FileTypes public async Task SetupAsync() { CodeActionEndpoint = new CodeActionEndpoint( - documentMappingService: RazorLanguageServerHost.GetRequiredService(), + documentMappingService: RazorLanguageServerHost.GetRequiredService(), razorCodeActionProviders: RazorLanguageServerHost.GetRequiredService>(), csharpCodeActionProviders: RazorLanguageServerHost.GetRequiredService>(), htmlCodeActionProviders: RazorLanguageServerHost.GetRequiredService>(), diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs index f9baad11704..0bf6c9fea83 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs @@ -38,7 +38,7 @@ public async Task SetupAsync() var razorCompletionListProvider = RazorLanguageServerHost.GetRequiredService(); var lspServices = RazorLanguageServerHost.GetRequiredService(); var responseRewriters = lspServices.GetRequiredServices(); - var documentMappingService = lspServices.GetRequiredService(); + var documentMappingService = lspServices.GetRequiredService(); var clientConnection = lspServices.GetRequiredService(); var completionListCache = lspServices.GetRequiredService(); var loggerFactory = lspServices.GetRequiredService(); @@ -141,7 +141,7 @@ public async Task RazorCompletionAsync() private class TestDelegatedCompletionListProvider : DelegatedCompletionListProvider { - public TestDelegatedCompletionListProvider(IEnumerable responseRewriters, IRazorDocumentMappingService documentMappingService, IClientConnection clientConnection, CompletionListCache completionListCache) + public TestDelegatedCompletionListProvider(IEnumerable responseRewriters, IDocumentMappingService documentMappingService, IClientConnection clientConnection, CompletionListCache completionListCache) : base(responseRewriters, documentMappingService, clientConnection, completionListCache) { } diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs index 7cb21677aa5..9e50156d7f5 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs @@ -115,9 +115,9 @@ private protected override LanguageServerFeatureOptions BuildFeatureOptions() MockBehavior.Strict); } - private IRazorDocumentMappingService BuildRazorDocumentMappingService() + private IDocumentMappingService BuildRazorDocumentMappingService() { - var razorDocumentMappingService = new Mock(MockBehavior.Strict); + var razorDocumentMappingService = new Mock(MockBehavior.Strict); Range? hostDocumentRange; razorDocumentMappingService.Setup( diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs index d489b9ec124..c3371b04891 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs @@ -19,7 +19,7 @@ public class RazorDocumentMappingBenchmark : RazorLanguageServerBenchmarkBase { private string _filePath; - private IRazorDocumentMappingService DocumentMappingService { get; set; } + private IDocumentMappingService DocumentMappingService { get; set; } private IDocumentSnapshot DocumentSnapshot { get; set; } @@ -171,6 +171,6 @@ public async Task CleanupServerAsync() private void EnsureServicesInitialized() { - DocumentMappingService = RazorLanguageServerHost.GetRequiredService(); + DocumentMappingService = RazorLanguageServerHost.GetRequiredService(); } } diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs index 6f053edeadc..d7825241214 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs @@ -108,7 +108,7 @@ internal class TestRazorSemanticTokensInfoService : RazorSemanticTokensInfoServi { public TestRazorSemanticTokensInfoService( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, RazorSemanticTokensLegendService razorSemanticTokensLegendService, ILoggerFactory loggerFactory) : base(documentMappingService, razorSemanticTokensLegendService, csharpSemanticTokensProvider: null!, languageServerFeatureOptions, loggerFactory) diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensRangeEndpointBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensRangeEndpointBenchmark.cs index 6bd676543de..8258f197fc8 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensRangeEndpointBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensRangeEndpointBenchmark.cs @@ -140,7 +140,7 @@ internal class TestCustomizableRazorSemanticTokensInfoService : RazorSemanticTok { public TestCustomizableRazorSemanticTokensInfoService( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, RazorSemanticTokensLegendService razorSemanticTokensLegendService, ILoggerFactory loggerFactory) : base(documentMappingService, razorSemanticTokensLegendService, csharpSemanticTokensProvider: null!, languageServerFeatureOptions, loggerFactory) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AbstractRazorDelegatingEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AbstractRazorDelegatingEndpoint.cs index 88574c846ba..dfef778fe71 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AbstractRazorDelegatingEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AbstractRazorDelegatingEndpoint.cs @@ -22,13 +22,13 @@ internal abstract class AbstractRazorDelegatingEndpoint : I where TRequest : ITextDocumentPositionParams { private readonly LanguageServerFeatureOptions _languageServerFeatureOptions; - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly IClientConnection _clientConnection; protected readonly ILogger Logger; protected AbstractRazorDelegatingEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, ILogger logger) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs index 53db73065d8..30565f8c181 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert; [RazorLanguageServerEndpoint(VSInternalMethods.OnAutoInsertName)] internal class OnAutoInsertEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, IEnumerable onAutoInsertProvider, RazorLSPOptionsMonitor optionsMonitor, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionStrategy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionStrategy.cs index 3169a1d7648..8df88d48145 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionStrategy.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionStrategy.cs @@ -20,7 +20,7 @@ internal class PreferHtmlInAttributeValuesDocumentPositionInfoStrategy : IDocume { public static IDocumentPositionInfoStrategy Instance { get; } = new PreferHtmlInAttributeValuesDocumentPositionInfoStrategy(); - public async Task TryGetPositionInfoAsync(IRazorDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, CancellationToken cancellationToken) + public async Task TryGetPositionInfoAsync(IDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, CancellationToken cancellationToken) { var defaultDocumentPositionInfo = await DefaultDocumentPositionInfoStrategy.Instance.TryGetPositionInfoAsync(documentMappingService, documentContext, position, cancellationToken).ConfigureAwait(false); if (defaultDocumentPositionInfo is null) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/UnformattedRemappingCSharpCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/UnformattedRemappingCSharpCodeActionResolver.cs index df9aaf7fe45..964f576f653 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/UnformattedRemappingCSharpCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/UnformattedRemappingCSharpCodeActionResolver.cs @@ -23,10 +23,10 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; internal sealed class UnformattedRemappingCSharpCodeActionResolver( IDocumentContextFactory documentContextFactory, IClientConnection clientConnection, - IRazorDocumentMappingService documentMappingService) : CSharpCodeActionResolver(clientConnection) + IDocumentMappingService documentMappingService) : CSharpCodeActionResolver(clientConnection) { private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; public override string Action => LanguageServerConstants.CodeActions.UnformattedRemap; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs index 124f3fc5935..4a72ea63208 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs @@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; [RazorLanguageServerEndpoint(LspEndpointName)] internal sealed class CodeActionEndpoint( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IEnumerable razorCodeActionProviders, IEnumerable csharpCodeActionProviders, IEnumerable htmlCodeActionProviders, @@ -42,7 +42,7 @@ internal sealed class CodeActionEndpoint( { private const string LspEndpointName = Methods.TextDocumentCodeActionName; - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); + private readonly IDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); private readonly IEnumerable _razorCodeActionProviders = razorCodeActionProviders ?? throw new ArgumentNullException(nameof(razorCodeActionProviders)); private readonly IEnumerable _csharpCodeActionProviders = csharpCodeActionProviders ?? throw new ArgumentNullException(nameof(csharpCodeActionProviders)); private readonly IEnumerable _htmlCodeActionProviders = htmlCodeActionProviders ?? throw new ArgumentNullException(nameof(htmlCodeActionProviders)); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs index eff10d67736..86af5075d71 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs @@ -29,13 +29,13 @@ internal sealed class GenerateMethodCodeActionResolver( IDocumentContextFactory documentContextFactory, RazorLSPOptionsMonitor razorLSPOptionsMonitor, IClientConnection clientConnection, - IRazorDocumentMappingService razorDocumentMappingService, + IDocumentMappingService documentMappingService, IRazorFormattingService razorFormattingService) : IRazorCodeActionResolver { private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; private readonly RazorLSPOptionsMonitor _razorLSPOptionsMonitor = razorLSPOptionsMonitor; private readonly IClientConnection _clientConnection = clientConnection; - private readonly IRazorDocumentMappingService _documentMappingService = razorDocumentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; private readonly IRazorFormattingService _razorFormattingService = razorFormattingService; private const string ReturnType = "$$ReturnType$$"; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs index 41fc0ab7c55..2c8e023b46d 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs @@ -28,13 +28,13 @@ internal class DelegatedCompletionListProvider .Union(s_razorTriggerCharacters); private readonly ImmutableArray _responseRewriters; - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly IClientConnection _clientConnection; private readonly CompletionListCache _completionListCache; public DelegatedCompletionListProvider( IEnumerable responseRewriters, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, CompletionListCache completionListCache) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorBreakpointSpanEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorBreakpointSpanEndpoint.cs index f28856851d3..1bcb7c82ec0 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorBreakpointSpanEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorBreakpointSpanEndpoint.cs @@ -21,13 +21,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Debugging; [RazorLanguageServerEndpoint(LanguageServerConstants.RazorBreakpointSpanEndpoint)] internal class RazorBreakpointSpanEndpoint : IRazorDocumentlessRequestHandler, ITextDocumentIdentifierHandler { - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly ILogger _logger; public bool MutatesSolutionState => false; public RazorBreakpointSpanEndpoint( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) { if (loggerFactory is null) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorProximityExpressionsEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorProximityExpressionsEndpoint.cs index cf6700e9a68..844da19f1a8 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorProximityExpressionsEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorProximityExpressionsEndpoint.cs @@ -22,11 +22,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Debugging; [RazorLanguageServerEndpoint(LanguageServerConstants.RazorProximityExpressionsEndpoint)] internal class RazorProximityExpressionsEndpoint : IRazorDocumentlessRequestHandler, ITextDocumentIdentifierHandler { - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly ILogger _logger; public RazorProximityExpressionsEndpoint( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) { if (documentMappingService is null) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/ValidateBreakpointRangeEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/ValidateBreakpointRangeEndpoint.cs index 59b8866dd3d..fb811f96c82 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/ValidateBreakpointRangeEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/ValidateBreakpointRangeEndpoint.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Debugging; [RazorLanguageServerEndpoint(VSInternalMethods.TextDocumentValidateBreakableRangeName)] internal class ValidateBreakpointRangeEndpoint( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, LanguageServerFeatureOptions languageServerFeatureOptions, IClientConnection clientConnection, ILoggerFactory loggerFactory) @@ -27,7 +27,7 @@ internal class ValidateBreakpointRangeEndpoint( clientConnection, loggerFactory.GetOrCreateLogger()), ICapabilitiesProvider { - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; protected override bool OnlySingleServer => false; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentPositionInfoStrategy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentPositionInfoStrategy.cs index a9ebe134264..976829713ad 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentPositionInfoStrategy.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentPositionInfoStrategy.cs @@ -15,7 +15,7 @@ internal class DefaultDocumentPositionInfoStrategy : IDocumentPositionInfoStrate public static IDocumentPositionInfoStrategy Instance { get; } = new DefaultDocumentPositionInfoStrategy(); public async Task TryGetPositionInfoAsync( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs index 603714fb6b3..f45eb05ed72 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs @@ -30,14 +30,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition; [RazorLanguageServerEndpoint(Methods.TextDocumentDefinitionName)] internal sealed class DefinitionEndpoint( IRazorComponentSearchEngine componentSearchEngine, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, LanguageServerFeatureOptions languageServerFeatureOptions, IClientConnection clientConnection, ILoggerFactory loggerFactory) : AbstractRazorDelegatingEndpoint(languageServerFeatureOptions, documentMappingService, clientConnection, loggerFactory.GetOrCreateLogger()), ICapabilitiesProvider { private readonly IRazorComponentSearchEngine _componentSearchEngine = componentSearchEngine ?? throw new ArgumentNullException(nameof(componentSearchEngine)); - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); + private readonly IDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); protected override bool PreferCSharpOverHtmlIfPossible => true; @@ -267,7 +267,7 @@ private async Task GetNavigateRangeAsync(IDocumentSnapshot documentSnapsh return VsLspFactory.DefaultRange; } - internal static async Task TryGetPropertyRangeAsync(RazorCodeDocument codeDocument, string propertyName, IRazorDocumentMappingService documentMappingService, ILogger logger, CancellationToken cancellationToken) + internal static async Task TryGetPropertyRangeAsync(RazorCodeDocument codeDocument, string propertyName, IDocumentMappingService documentMappingService, ILogger logger, CancellationToken cancellationToken) { // Parse the C# file and find the property that matches the name. // We don't worry about parameter attributes here for two main reasons: diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs index 7831e806f0b..343c772cdec 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs @@ -28,13 +28,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics; /// Contains several methods for mapping and filtering Razor and C# diagnostics. It allows for /// translating code diagnostics from one representation into another, such as from C# to Razor. /// -/// The . +/// The . /// The . /// -internal class RazorTranslateDiagnosticsService(IRazorDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) +internal class RazorTranslateDiagnosticsService(IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) { private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; // Internal for testing internal static readonly IReadOnlyCollection CSharpDiagnosticsToIgnore = new HashSet() diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs index 08e1818189b..65537539ec2 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs @@ -19,11 +19,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.DocumentHighlighting; [RazorLanguageServerEndpoint(Methods.TextDocumentDocumentHighlightName)] internal class DocumentHighlightEndpoint : AbstractRazorDelegatingEndpoint, ICapabilitiesProvider { - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; public DocumentHighlightEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, ILoggerFactory loggerFactory) : base(languageServerFeatureOptions, documentMappingService, clientConnection, loggerFactory.GetOrCreateLogger()) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs index e2134c10ed2..b61b08aa239 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs @@ -25,18 +25,18 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.DocumentPresentation; internal abstract class AbstractTextDocumentPresentationEndpointBase : IRazorRequestHandler, ICapabilitiesProvider where TParams : IPresentationParams { - private readonly IRazorDocumentMappingService _razorDocumentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly IClientConnection _clientConnection; private readonly IFilePathService _filePathService; private readonly ILogger _logger; protected AbstractTextDocumentPresentationEndpointBase( - IRazorDocumentMappingService razorDocumentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, IFilePathService filePathService, ILogger logger) { - _razorDocumentMappingService = razorDocumentMappingService; + _documentMappingService = documentMappingService; _clientConnection = clientConnection; _filePathService = filePathService; _logger = logger; @@ -79,7 +79,7 @@ protected AbstractTextDocumentPresentationEndpointBase( return null; } - var languageKind = _razorDocumentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: false); + var languageKind = _documentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: false); // See if we can handle this directly in Razor. If not, we'll let things flow to the below delegated handling. var result = await TryGetRazorWorkspaceEditAsync(languageKind, request, cancellationToken).ConfigureAwait(false); if (result is not null) @@ -107,7 +107,7 @@ protected AbstractTextDocumentPresentationEndpointBase( // For CSharp we need to map the range to the generated document if (languageKind == RazorLanguageKind.CSharp) { - if (!_razorDocumentMappingService.TryMapToGeneratedDocumentRange(codeDocument.GetCSharpDocument(), request.Range, out var projectedRange)) + if (!_documentMappingService.TryMapToGeneratedDocumentRange(codeDocument.GetCSharpDocument(), request.Range, out var projectedRange)) { return null; } @@ -233,7 +233,7 @@ private TextEdit[] MapTextEdits(bool mapRanges, RazorCodeDocument codeDocument, using var mappedEdits = new PooledArrayBuilder(); foreach (var edit in edits) { - if (!_razorDocumentMappingService.TryMapToHostDocumentRange(codeDocument.GetCSharpDocument(), edit.Range, out var newRange)) + if (!_documentMappingService.TryMapToHostDocumentRange(codeDocument.GetCSharpDocument(), edit.Range, out var newRange)) { return []; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentTextPresentationEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentTextPresentationEndpoint.cs index 69aea0a8c69..c01cc3dbe92 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentTextPresentationEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentTextPresentationEndpoint.cs @@ -15,11 +15,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.DocumentPresentation; internal class TextDocumentTextPresentationEndpoint( - IRazorDocumentMappingService razorDocumentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, IFilePathService filePathService, ILoggerFactory loggerFactory) - : AbstractTextDocumentPresentationEndpointBase(razorDocumentMappingService, clientConnection, filePathService, loggerFactory.GetOrCreateLogger()), ITextDocumentTextPresentationHandler + : AbstractTextDocumentPresentationEndpointBase(documentMappingService, clientConnection, filePathService, loggerFactory.GetOrCreateLogger()), ITextDocumentTextPresentationHandler { public override string EndpointName => CustomMessageNames.RazorTextPresentationEndpoint; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs index 72cf2558498..cb8937d4a19 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs @@ -17,12 +17,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.DocumentPresentation; internal class TextDocumentUriPresentationEndpoint( - IRazorDocumentMappingService razorDocumentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, IFilePathService filePathService, IDocumentContextFactory documentContextFactory, ILoggerFactory loggerFactory) - : AbstractTextDocumentPresentationEndpointBase(razorDocumentMappingService, clientConnection, filePathService, loggerFactory.GetOrCreateLogger()), ITextDocumentUriPresentationHandler + : AbstractTextDocumentPresentationEndpointBase(documentMappingService, clientConnection, filePathService, loggerFactory.GetOrCreateLogger()), ITextDocumentUriPresentationHandler { private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory ?? throw new ArgumentNullException(nameof(documentContextFactory)); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSymbols/DocumentSymbolEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSymbols/DocumentSymbolEndpoint.cs index ea902244737..6a783934424 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSymbols/DocumentSymbolEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSymbols/DocumentSymbolEndpoint.cs @@ -21,12 +21,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.DocumentSymbols; internal class DocumentSymbolEndpoint : IRazorRequestHandler?>, ICapabilitiesProvider { private readonly IClientConnection _clientConnection; - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions; public DocumentSymbolEndpoint( IClientConnection clientConnection, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, LanguageServerFeatureOptions languageServerFeatureOptions) { _clientConnection = clientConnection ?? throw new ArgumentNullException(nameof(clientConnection)); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs index 4dfb076fc6b..da57af39f48 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/EditMappingService.cs @@ -15,11 +15,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer; internal sealed class EditMappingService( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IFilePathService filePathService, IDocumentContextFactory documentContextFactory) : IEditMappingService { - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; private readonly IFilePathService _filePathService = filePathService; private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs index 07765b13cbf..a505aa69c2d 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs @@ -202,7 +202,7 @@ public static void AddDocumentManagementServices(this IServiceCollection service services.AddSingleton(); services.AddSingleton((services) => (RazorProjectService)services.GetRequiredService()); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(sp => sp.GetRequiredService()); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs index adb2ab359dd..ccd2e6e93a1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs @@ -23,11 +23,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.FindAllReferences; internal sealed class FindAllReferencesEndpoint : AbstractRazorDelegatingEndpoint, ICapabilitiesProvider { private readonly IFilePathService _filePathService; - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; public FindAllReferencesEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, ILoggerFactory loggerFactory, IFilePathService filePathService) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormatter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormatter.cs index 47089246f24..f87c51192c1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormatter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormatter.cs @@ -19,11 +19,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; -internal sealed class CSharpFormatter(IRazorDocumentMappingService documentMappingService) +internal sealed class CSharpFormatter(IDocumentMappingService documentMappingService) { private const string MarkerId = "RazorMarker"; - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; public async Task FormatAsync(FormattingContext context, Range rangeToFormat, CancellationToken cancellationToken) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPass.cs index ae44807e53d..7db855f9bd1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPass.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal sealed class CSharpFormattingPass( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) : CSharpFormattingPassBase(documentMappingService) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPassBase.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPassBase.cs index ab97332f801..590189a5362 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPassBase.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPassBase.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal abstract class CSharpFormattingPassBase : FormattingPassBase { - protected CSharpFormattingPassBase(IRazorDocumentMappingService documentMappingService) + protected CSharpFormattingPassBase(IDocumentMappingService documentMappingService) : base(documentMappingService) { CSharpFormatter = new CSharpFormatter(documentMappingService); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs index 1c60b4fa464..bad1194d899 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal sealed class CSharpOnTypeFormattingPass( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) : CSharpFormattingPassBase(documentMappingService) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs index 71389874fcc..77c5b6a37ae 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs @@ -20,13 +20,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; [RazorLanguageServerEndpoint(Methods.TextDocumentOnTypeFormattingName)] internal class DocumentOnTypeFormattingEndpoint( IRazorFormattingService razorFormattingService, - IRazorDocumentMappingService razorDocumentMappingService, + IDocumentMappingService documentMappingService, RazorLSPOptionsMonitor optionsMonitor, ILoggerFactory loggerFactory) : IRazorRequestHandler, ICapabilitiesProvider { private readonly IRazorFormattingService _razorFormattingService = razorFormattingService ?? throw new ArgumentNullException(nameof(razorFormattingService)); - private readonly IRazorDocumentMappingService _razorDocumentMappingService = razorDocumentMappingService ?? throw new ArgumentNullException(nameof(razorDocumentMappingService)); + private readonly IDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); private readonly RazorLSPOptionsMonitor _optionsMonitor = optionsMonitor ?? throw new ArgumentNullException(nameof(optionsMonitor)); private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); @@ -95,7 +95,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(DocumentOnTypeFormatting return null; } - var triggerCharacterKind = _razorDocumentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: false); + var triggerCharacterKind = _documentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: false); if (triggerCharacterKind is not (RazorLanguageKind.CSharp or RazorLanguageKind.Html)) { _logger.LogInformation($"Unsupported trigger character language {triggerCharacterKind:G}."); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContentValidationPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContentValidationPass.cs index ec990b20f27..ff1eccb1f1c 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContentValidationPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContentValidationPass.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal sealed class FormattingContentValidationPass( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) : FormattingPassBase(documentMappingService) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingDiagnosticValidationPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingDiagnosticValidationPass.cs index ed7d5014b05..8f7cfda5c60 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingDiagnosticValidationPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingDiagnosticValidationPass.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal sealed class FormattingDiagnosticValidationPass( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) : FormattingPassBase(documentMappingService) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingPassBase.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingPassBase.cs index 79a5af2ee64..8f0f6e1dc86 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingPassBase.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingPassBase.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; -internal abstract class FormattingPassBase(IRazorDocumentMappingService documentMappingService) : IFormattingPass +internal abstract class FormattingPassBase(IDocumentMappingService documentMappingService) : IFormattingPass { protected static readonly int DefaultOrder = 1000; @@ -20,7 +20,7 @@ internal abstract class FormattingPassBase(IRazorDocumentMappingService document public virtual int Order => DefaultOrder; - protected IRazorDocumentMappingService DocumentMappingService { get; } = documentMappingService; + protected IDocumentMappingService DocumentMappingService { get; } = documentMappingService; public abstract Task ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormattingPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormattingPass.cs index 988494d9858..f522ea5790c 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormattingPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormattingPass.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal sealed class HtmlFormattingPass( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, IDocumentVersionCache documentVersionCache, ILoggerFactory loggerFactory) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingPass.cs index d4d86a468c9..0fe7872f2d9 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingPass.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal sealed class RazorFormattingPass( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, RazorLSPOptionsMonitor optionsMonitor) : FormattingPassBase(documentMappingService) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs index 3417fcc9957..82455da7d44 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs @@ -23,7 +23,7 @@ internal sealed class HoverEndpoint : AbstractRazorDelegatingEndpoint()) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverService.cs index fe063b11312..4fb546a09d6 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverService.cs @@ -27,12 +27,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Hover; internal sealed partial class HoverService( LSPTagHelperTooltipFactory lspTagHelperTooltipFactory, VSLSPTagHelperTooltipFactory vsLspTagHelperTooltipFactory, - IRazorDocumentMappingService mappingService, + IDocumentMappingService documentMappingService, IClientCapabilitiesService clientCapabilitiesService) : IHoverService { private readonly LSPTagHelperTooltipFactory _lspTagHelperTooltipFactory = lspTagHelperTooltipFactory; private readonly VSLSPTagHelperTooltipFactory _vsLspTagHelperTooltipFactory = vsLspTagHelperTooltipFactory; - private readonly IRazorDocumentMappingService _mappingService = mappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; private readonly IClientCapabilitiesService _clientCapabilitiesService = clientCapabilitiesService; public async Task GetRazorHoverInfoAsync(VersionedDocumentContext documentContext, DocumentPositionInfo positionInfo, Position position, CancellationToken cancellationToken) @@ -48,7 +48,7 @@ internal sealed partial class HoverService( // Sometimes what looks like a html attribute can actually map to C#, in which case its better to let Roslyn try to handle this. // We can only do this if we're in single server mode though, otherwise we won't be delegating to Roslyn at all - if (_mappingService.TryMapToGeneratedDocumentPosition(codeDocument.GetCSharpDocument(), positionInfo.HostDocumentIndex, out _, out _)) + if (_documentMappingService.TryMapToGeneratedDocumentPosition(codeDocument.GetCSharpDocument(), positionInfo.HostDocumentIndex, out _, out _)) { return null; } @@ -76,7 +76,7 @@ internal sealed partial class HoverService( } else if (positionInfo.LanguageKind == RazorLanguageKind.CSharp) { - if (_mappingService.TryMapToHostDocumentRange(codeDocument.GetCSharpDocument(), response.Range, out var projectedRange)) + if (_documentMappingService.TryMapToHostDocumentRange(codeDocument.GetCSharpDocument(), response.Range, out var projectedRange)) { response.Range = projectedRange; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentPositionInfoStrategy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentPositionInfoStrategy.cs index c575fc47796..dc7b13c4880 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentPositionInfoStrategy.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentPositionInfoStrategy.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer; internal interface IDocumentPositionInfoStrategy { Task TryGetPositionInfoAsync( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, CancellationToken cancellationToken); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Implementation/ImplementationEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Implementation/ImplementationEndpoint.cs index 760bd7226ec..a2e89c2bbf7 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Implementation/ImplementationEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Implementation/ImplementationEndpoint.cs @@ -21,11 +21,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Implementation; [RazorLanguageServerEndpoint(Methods.TextDocumentImplementationName)] internal sealed class ImplementationEndpoint : AbstractRazorDelegatingEndpoint, ICapabilitiesProvider { - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; public ImplementationEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, ILoggerFactory loggerFactory) : base(languageServerFeatureOptions, documentMappingService, clientConnection, loggerFactory.GetOrCreateLogger()) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs index e6aa690bb03..294a6adc827 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs @@ -18,9 +18,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.InlayHints; -internal sealed class InlayHintService(IRazorDocumentMappingService documentMappingService) : IInlayHintService +internal sealed class InlayHintService(IDocumentMappingService documentMappingService) : IInlayHintService { - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; public async Task GetInlayHintsAsync(IClientConnection clientConnection, VersionedDocumentContext documentContext, Range range, CancellationToken cancellationToken) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlineCompletion/InlineCompletionEndPoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlineCompletion/InlineCompletionEndPoint.cs index 9593b528e87..0a452d66217 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlineCompletion/InlineCompletionEndPoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlineCompletion/InlineCompletionEndPoint.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.InlineCompletion; [RazorLanguageServerEndpoint(VSInternalMethods.TextDocumentInlineCompletionName)] internal sealed class InlineCompletionEndpoint( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, IAdhocWorkspaceFactory adhocWorkspaceFactory, ILoggerFactory loggerFactory) @@ -36,7 +36,7 @@ internal sealed class InlineCompletionEndpoint( "if", "indexer", "interface", "invoke", "iterator", "iterindex", "lock", "mbox", "namespace", "#if", "#region", "prop", "propfull", "propg", "sim", "struct", "svm", "switch", "try", "tryf", "unchecked", "unsafe", "using", "while"); - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); + private readonly IDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); private readonly IClientConnection _clientConnection = clientConnection ?? throw new ArgumentNullException(nameof(clientConnection)); private readonly IAdhocWorkspaceFactory _adhocWorkspaceFactory = adhocWorkspaceFactory ?? throw new ArgumentNullException(nameof(adhocWorkspaceFactory)); private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs index fa6066328aa..e38ace89ca0 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs @@ -37,12 +37,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.MapCode; /// [RazorLanguageServerEndpoint(VSInternalMethods.WorkspaceMapCodeName)] internal sealed class MapCodeEndpoint( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IDocumentContextFactory documentContextFactory, IClientConnection clientConnection, ITelemetryReporter telemetryReporter) : IRazorDocumentlessRequestHandler, ICapabilitiesProvider { - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); + private readonly IDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory ?? throw new ArgumentNullException(nameof(documentContextFactory)); private readonly IClientConnection _clientConnection = clientConnection ?? throw new ArgumentNullException(nameof(clientConnection)); private readonly ITelemetryReporter _telemetryReporter = telemetryReporter ?? throw new ArgumentNullException(nameof(telemetryReporter)); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorLanguageQueryEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorLanguageQueryEndpoint.cs index b4e6da2b476..62f55e00a19 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorLanguageQueryEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorLanguageQueryEndpoint.cs @@ -14,10 +14,10 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Mapping; [RazorLanguageServerEndpoint(LanguageServerConstants.RazorLanguageQueryEndpoint)] -internal sealed class RazorLanguageQueryEndpoint(IRazorDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) +internal sealed class RazorLanguageQueryEndpoint(IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) : IRazorRequestHandler { - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); public bool MutatesSolutionState { get; } = false; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorMapToDocumentRangesEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorMapToDocumentRangesEndpoint.cs index 18f308dc13c..a6e0c6f6a29 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorMapToDocumentRangesEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorMapToDocumentRangesEndpoint.cs @@ -20,9 +20,9 @@ internal sealed class RazorMapToDocumentRangesEndpoint : IRazorDocumentlessRequestHandler, ITextDocumentIdentifierHandler { - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; - public RazorMapToDocumentRangesEndpoint(IRazorDocumentMappingService documentMappingService) + public RazorMapToDocumentRangesEndpoint(IDocumentMappingService documentMappingService) { _documentMappingService = documentMappingService; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PreferAttributeNameDocumentPositionInfoStrategy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PreferAttributeNameDocumentPositionInfoStrategy.cs index 3bd88203f85..98b8fcac5d1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PreferAttributeNameDocumentPositionInfoStrategy.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PreferAttributeNameDocumentPositionInfoStrategy.cs @@ -20,7 +20,7 @@ internal class PreferAttributeNameDocumentPositionInfoStrategy : IDocumentPositi public static IDocumentPositionInfoStrategy Instance { get; } = new PreferAttributeNameDocumentPositionInfoStrategy(); public async Task TryGetPositionInfoAsync( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs index 65d6787d33a..6960617a980 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs @@ -30,7 +30,7 @@ internal sealed class RenameEndpoint( IRazorComponentSearchEngine componentSearchEngine, IProjectCollectionResolver projectResolver, LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IEditMappingService editMappingService, IClientConnection clientConnection, ILoggerFactory loggerFactory) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/RazorSemanticTokensInfoService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/RazorSemanticTokensInfoService.cs index 4a2bd4da4e4..507671b5527 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/RazorSemanticTokensInfoService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/RazorSemanticTokensInfoService.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic; internal class RazorSemanticTokensInfoService( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ISemanticTokensLegendService semanticTokensLegendService, ICSharpSemanticTokensProvider csharpSemanticTokensProvider, LanguageServerFeatureOptions languageServerFeatureOptions, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SignatureHelp/SignatureHelpEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SignatureHelp/SignatureHelpEndpoint.cs index dc760893697..e7c488771e3 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SignatureHelp/SignatureHelpEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SignatureHelp/SignatureHelpEndpoint.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.SignatureHelp; [RazorLanguageServerEndpoint(Methods.TextDocumentSignatureHelpName)] internal sealed class SignatureHelpEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions, - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IClientConnection clientConnection, RazorLSPOptionsMonitor optionsMonitor, ILoggerFactory loggerProvider) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SpellCheck/DocumentSpellCheckEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SpellCheck/DocumentSpellCheckEndpoint.cs index 711f49c6dc5..3d2b69e43a5 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SpellCheck/DocumentSpellCheckEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SpellCheck/DocumentSpellCheckEndpoint.cs @@ -21,12 +21,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.SpellCheck; [RazorLanguageServerEndpoint(VSInternalMethods.TextDocumentSpellCheckableRangesName)] internal sealed class DocumentSpellCheckEndpoint : IRazorRequestHandler, ICapabilitiesProvider { - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions; private readonly IClientConnection _clientConnection; public DocumentSpellCheckEndpoint( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, LanguageServerFeatureOptions languageServerFeatureOptions, IClientConnection clientConnection) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WrapWithTag/WrapWithTagEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WrapWithTag/WrapWithTagEndpoint.cs index b290be86aef..990dbc07a6e 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WrapWithTag/WrapWithTagEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WrapWithTag/WrapWithTagEndpoint.cs @@ -20,12 +20,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.WrapWithTag; [RazorLanguageServerEndpoint(LanguageServerConstants.RazorWrapWithTagEndpoint)] internal class WrapWithTagEndpoint( IClientConnection clientConnection, - IRazorDocumentMappingService razorDocumentMappingService, + IDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) : IRazorRequestHandler { private readonly IClientConnection _clientConnection = clientConnection ?? throw new ArgumentNullException(nameof(clientConnection)); - private readonly IRazorDocumentMappingService _razorDocumentMappingService = razorDocumentMappingService ?? throw new ArgumentNullException(nameof(razorDocumentMappingService)); + private readonly IDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); public bool MutatesSolutionState => false; @@ -69,7 +69,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(WrapWithTagParams reques // // Instead of C#, which certainly would be expected to go in an if statement, we'll see HTML, which obviously // is the better choice for this operation. - var languageKind = _razorDocumentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: true); + var languageKind = _documentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: true); if (languageKind is not RazorLanguageKind.Html) { // In general, we don't support C# for obvious reasons, but we can support implicit expressions. ie diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs index 4af45dbecb4..1da1ba17714 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; -internal abstract class AbstractRazorDocumentMappingService(IFilePathService filePathService, ILogger logger) : IRazorDocumentMappingService +internal abstract class AbstractRazorDocumentMappingService(IFilePathService filePathService, ILogger logger) : IDocumentMappingService { private readonly IFilePathService _filePathService = filePathService; private readonly ILogger _logger = logger; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingService.cs similarity index 97% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingService.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingService.cs index 1f737b7be69..7df5479ed21 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingService.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; -internal interface IRazorDocumentMappingService +internal interface IDocumentMappingService { IEnumerable GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument, IEnumerable generatedDocumentEdits); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs index 9ead7ef2509..81a02ac75eb 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; internal static class IRazorDocumentMappingServiceExtensions { - public static TextEdit[] GetHostDocumentEdits(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, TextEdit[] generatedDocumentEdits) + public static TextEdit[] GetHostDocumentEdits(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, TextEdit[] generatedDocumentEdits) { var generatedDocumentSourceText = generatedDocument.GetGeneratedSourceText(); var documentText = generatedDocument.CodeDocument.AssumeNotNull().Source.Text; @@ -28,13 +28,13 @@ public static TextEdit[] GetHostDocumentEdits(this IRazorDocumentMappingService return mappedChanges.Select(documentText.GetTextEdit).ToArray(); } - public static bool TryMapToHostDocumentRange(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, LinePositionSpan projectedRange, out LinePositionSpan originalRange) + public static bool TryMapToHostDocumentRange(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, LinePositionSpan projectedRange, out LinePositionSpan originalRange) => service.TryMapToHostDocumentRange(generatedDocument, projectedRange, MappingBehavior.Strict, out originalRange); - public static bool TryMapToHostDocumentRange(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, Range projectedRange, [NotNullWhen(true)] out Range? originalRange) + public static bool TryMapToHostDocumentRange(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, Range projectedRange, [NotNullWhen(true)] out Range? originalRange) => service.TryMapToHostDocumentRange(generatedDocument, projectedRange, MappingBehavior.Strict, out originalRange); - public static async Task GetPositionInfoAsync(this IRazorDocumentMappingService service, DocumentContext documentContext, int hostDocumentIndex, CancellationToken cancellationToken) + public static async Task GetPositionInfoAsync(this IDocumentMappingService service, DocumentContext documentContext, int hostDocumentIndex, CancellationToken cancellationToken) { var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); var sourceText = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); @@ -43,7 +43,7 @@ public static async Task GetPositionInfoAsync(this IRazorD } public static DocumentPositionInfo GetPositionInfo( - this IRazorDocumentMappingService service, + this IDocumentMappingService service, RazorCodeDocument codeDocument, SourceText sourceText, int hostDocumentIndex) @@ -74,35 +74,35 @@ public static DocumentPositionInfo GetPositionInfo( return new DocumentPositionInfo(languageKind, position, hostDocumentIndex); } - public static bool TryMapToHostDocumentRange(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, Range generatedDocumentRange, MappingBehavior mappingBehavior, [NotNullWhen(true)] out Range? hostDocumentRange) + public static bool TryMapToHostDocumentRange(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, Range generatedDocumentRange, MappingBehavior mappingBehavior, [NotNullWhen(true)] out Range? hostDocumentRange) { var result = service.TryMapToHostDocumentRange(generatedDocument, generatedDocumentRange.ToLinePositionSpan(), mappingBehavior, out var hostDocumentLinePositionSpan); hostDocumentRange = result ? hostDocumentLinePositionSpan.ToRange() : null; return result; } - public static bool TryMapToGeneratedDocumentRange(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, Range hostDocumentRange, [NotNullWhen(true)] out Range? generatedDocumentRange) + public static bool TryMapToGeneratedDocumentRange(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, Range hostDocumentRange, [NotNullWhen(true)] out Range? generatedDocumentRange) { var result = service.TryMapToGeneratedDocumentRange(generatedDocument, hostDocumentRange.ToLinePositionSpan(), out var generatedDocumentLinePositionSpan); generatedDocumentRange = result ? generatedDocumentLinePositionSpan.ToRange() : null; return result; } - public static bool TryMapToHostDocumentPosition(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, int generatedDocumentIndex, [NotNullWhen(true)] out Position? hostDocumentPosition, out int hostDocumentIndex) + public static bool TryMapToHostDocumentPosition(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, int generatedDocumentIndex, [NotNullWhen(true)] out Position? hostDocumentPosition, out int hostDocumentIndex) { var result = service.TryMapToHostDocumentPosition(generatedDocument, generatedDocumentIndex, out var hostDocumentLinePosition, out hostDocumentIndex); hostDocumentPosition = result ? hostDocumentLinePosition.ToPosition() : null; return result; } - public static bool TryMapToGeneratedDocumentPosition(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, int hostDocumentIndex, [NotNullWhen(true)] out Position? generatedPosition, out int generatedIndex) + public static bool TryMapToGeneratedDocumentPosition(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, int hostDocumentIndex, [NotNullWhen(true)] out Position? generatedPosition, out int generatedIndex) { var result = service.TryMapToGeneratedDocumentPosition(generatedDocument, hostDocumentIndex, out var generatedLinePosition, out generatedIndex); generatedPosition = result ? generatedLinePosition.ToPosition() : null; return result; } - public static bool TryMapToGeneratedDocumentOrNextCSharpPosition(this IRazorDocumentMappingService service, IRazorGeneratedDocument generatedDocument, int hostDocumentIndex, [NotNullWhen(true)] out Position? generatedPosition, out int generatedIndex) + public static bool TryMapToGeneratedDocumentOrNextCSharpPosition(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, int hostDocumentIndex, [NotNullWhen(true)] out Position? generatedPosition, out int generatedIndex) { var result = service.TryMapToGeneratedDocumentOrNextCSharpPosition(generatedDocument, hostDocumentIndex, out var generatedLinePosition, out generatedIndex); generatedPosition = result ? generatedLinePosition.ToPosition() : null; @@ -114,7 +114,7 @@ public static bool TryMapToGeneratedDocumentOrNextCSharpPosition(this IRazorDocu /// generated document. If the uri passed in is not for a generated document, or the range cannot be mapped /// for some other reason, the original passed in range is returned unchanged. /// - public static async Task<(Uri MappedDocumentUri, Range MappedRange)> MapToHostDocumentUriAndRangeAsync(this IRazorDocumentMappingService service, Uri generatedDocumentUri, Range generatedDocumentRange, CancellationToken cancellationToken) + public static async Task<(Uri MappedDocumentUri, Range MappedRange)> MapToHostDocumentUriAndRangeAsync(this IDocumentMappingService service, Uri generatedDocumentUri, Range generatedDocumentRange, CancellationToken cancellationToken) { var result = await service.MapToHostDocumentUriAndRangeAsync(generatedDocumentUri, generatedDocumentRange.ToLinePositionSpan(), cancellationToken).ConfigureAwait(false); return (result.MappedDocumentUri, result.MappedRange.ToRange()); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/FoldingRangeService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/FoldingRangeService.cs index def3567e4b3..194ccb94d8c 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/FoldingRangeService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/FoldingRangeService.cs @@ -17,12 +17,12 @@ namespace Microsoft.CodeAnalysis.Razor.FoldingRanges; internal class FoldingRangeService( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, IEnumerable foldingRangeProviders, ILoggerFactory loggerFactory) : IFoldingRangeService { - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; private readonly IEnumerable _foldingRangeProviders = foldingRangeProviders; private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs index 2fa4acdd54d..712506f4e53 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs @@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.Razor.SemanticTokens; internal abstract class AbstractRazorSemanticTokensInfoService( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ISemanticTokensLegendService semanticTokensLegendService, ICSharpSemanticTokensProvider csharpSemanticTokensProvider, LanguageServerFeatureOptions languageServerFeatureOptions, @@ -29,7 +29,7 @@ internal abstract class AbstractRazorSemanticTokensInfoService( { private const int TokenSize = 5; - private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; private readonly ISemanticTokensLegendService _semanticTokensLegendService = semanticTokensLegendService; private readonly ICSharpSemanticTokensProvider _csharpSemanticTokensProvider = csharpSemanticTokensProvider; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions = languageServerFeatureOptions; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentHighlight/RemoteDocumentHighlightService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentHighlight/RemoteDocumentHighlightService.cs index 61252f6d011..ec782be065c 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentHighlight/RemoteDocumentHighlightService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentHighlight/RemoteDocumentHighlightService.cs @@ -28,7 +28,7 @@ protected override IRemoteDocumentHighlightService CreateService(in ServiceArgs => new RemoteDocumentHighlightService(in args); } - private readonly IRazorDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); + private readonly IDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); private readonly IFilePathService _filePathService = args.ExportProvider.GetExportedValue(); public ValueTask GetHighlightsAsync( diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs index 57f65b116ec..5dddaea4cec 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.DocumentMapping; -[Export(typeof(IRazorDocumentMappingService)), Shared] +[Export(typeof(IDocumentMappingService)), Shared] [method: ImportingConstructor] internal sealed class RemoteDocumentMappingService( IFilePathService filePathService, diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/FoldingRanges/OOPFoldingRangeService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/FoldingRanges/OOPFoldingRangeService.cs index 67565c459a4..fcf9db1bdf7 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/FoldingRanges/OOPFoldingRangeService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/FoldingRanges/OOPFoldingRangeService.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.FoldingRanges; [Export(typeof(IFoldingRangeService)), Shared] [method: ImportingConstructor] internal sealed class OOPFoldingRangeService( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, [ImportMany] IEnumerable foldingRangeProviders, ILoggerFactory loggerFactory) : FoldingRangeService(documentMappingService, foldingRangeProviders, loggerFactory) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs index 0bbb9c8fccd..ae06c498c58 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/InlayHints/RemoteInlayHintService.cs @@ -27,7 +27,7 @@ protected override IRemoteInlayHintService CreateService(in ServiceArgs args) => new RemoteInlayHintService(in args); } - private readonly IRazorDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); + private readonly IDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); private readonly IFilePathService _filePathService = args.ExportProvider.GetExportedValue(); public ValueTask GetInlayHintsAsync(JsonSerializableRazorPinnedSolutionInfoWrapper solutionInfo, JsonSerializableDocumentId razorDocumentId, InlayHintParams inlayHintParams, bool displayAllOverride, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RazorSemanticTokensInfoService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RazorSemanticTokensInfoService.cs index 9414fa0ec1f..a9b19f9a2c2 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RazorSemanticTokensInfoService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RazorSemanticTokensInfoService.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.SemanticTokens; [Export(typeof(IRazorSemanticTokensInfoService)), Shared] [method: ImportingConstructor] internal class RazorSemanticTokensInfoService( - IRazorDocumentMappingService documentMappingService, + IDocumentMappingService documentMappingService, ISemanticTokensLegendService semanticTokensLegendService, ICSharpSemanticTokensProvider csharpSemanticTokensProvider, LanguageServerFeatureOptions languageServerFeatureOptions, diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SignatureHelp/RemoteSignatureHelpService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SignatureHelp/RemoteSignatureHelpService.cs index 08971e58191..fb4fa23635a 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SignatureHelp/RemoteSignatureHelpService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SignatureHelp/RemoteSignatureHelpService.cs @@ -26,7 +26,7 @@ protected override IRemoteSignatureHelpService CreateService(in ServiceArgs args } private readonly IFilePathService _filePathService = args.ExportProvider.GetExportedValue(); - private readonly IRazorDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); + private readonly IDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); public ValueTask GetSignatureHelpAsync(JsonSerializableRazorPinnedSolutionInfoWrapper solutionInfo, JsonSerializableDocumentId documentId, Position position, CancellationToken cancellationToken) => RunServiceAsync( diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs index db920ccee6c..92a20f8dd8f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs @@ -25,7 +25,7 @@ protected override IRemoteUriPresentationService CreateService(in ServiceArgs ar => new RemoteUriPresentationService(in args); } - private readonly IRazorDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); + private readonly IDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); public ValueTask GetPresentationAsync( RazorPinnedSolutionInfoWrapper solutionInfo, diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndpointTest.cs index e5dc42a3fb7..7c44e564389 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndpointTest.cs @@ -28,14 +28,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; public class CodeActionEndpointTest : LanguageServerTestBase { - private readonly IRazorDocumentMappingService _documentMappingService; + private readonly IDocumentMappingService _documentMappingService; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions; private readonly IClientConnection _clientConnection; public CodeActionEndpointTest(ITestOutputHelper testOutput) : base(testOutput) { - _documentMappingService = Mock.Of( + _documentMappingService = Mock.Of( s => s.TryMapToGeneratedDocumentRange( It.IsAny(), It.IsAny(), @@ -688,7 +688,7 @@ public async Task GetCSharpCodeActionsFromLanguageServerAsync_InvalidRangeMappin var codeDocument = CreateCodeDocument("@code {}"); var documentContext = CreateDocumentContext(documentPath, codeDocument); LinePositionSpan projectedRange = default; - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( d => d.TryMapToGeneratedDocumentRange(It.IsAny(), It.IsAny(), out projectedRange) == false , MockBehavior.Strict); var codeActionEndpoint = new CodeActionEndpoint( @@ -782,14 +782,14 @@ public async Task GetCSharpCodeActionsFromLanguageServerAsync_ReturnsCodeActions Assert.Equal(projectedRange, diagnostics[1].Range); } - private static IRazorDocumentMappingService CreateDocumentMappingService(LinePositionSpan projectedRange = default) + private static IDocumentMappingService CreateDocumentMappingService(LinePositionSpan projectedRange = default) { if (projectedRange == default) { projectedRange = new LinePositionSpan(new(5, 2), new(5, 2)); } - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( d => d.TryMapToGeneratedDocumentRange(It.IsAny(), It.IsAny(), out projectedRange) == true && d.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny()) == RazorLanguageKind.CSharp , MockBehavior.Strict); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs index 5b98eb4fd1c..874158e576e 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TestDocumentMappingService.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion; -internal class TestDocumentMappingService : IRazorDocumentMappingService +internal class TestDocumentMappingService : IDocumentMappingService { public RazorLanguageKind LanguageKind { get; set; } public LinePosition? GeneratedPosition { get; set; } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs index bfae068bda8..a97ffd32335 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Debugging; public class RazorBreakpointSpanEndpointTest : LanguageServerTestBase { - private readonly IRazorDocumentMappingService _mappingService; + private readonly IDocumentMappingService _mappingService; public RazorBreakpointSpanEndpointTest(ITestOutputHelper testOutput) : base(testOutput) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs index e8bfb086782..8d4c0fbe3fa 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Debugging; public class RazorProximityExpressionsEndpointTest : LanguageServerTestBase { - private readonly IRazorDocumentMappingService _mappingService; + private readonly IDocumentMappingService _mappingService; public RazorProximityExpressionsEndpointTest(ITestOutputHelper testOutput) : base(testOutput) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs index e5910df49ec..5ca3cc79c2c 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs @@ -111,7 +111,7 @@ public async Task DocumentProcessed_NewWorkQueued_RestartsTimer() .Verifiable(); var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); @@ -275,7 +275,7 @@ public async Task PublishDiagnosticsAsync_NewRazorDiagnosticsGetPublished() .Returns(Task.CompletedTask); var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); @@ -333,7 +333,7 @@ public async Task PublishDiagnosticsAsync_NewCSharpDiagnosticsGetPublished() .Returns(Task.CompletedTask); var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); @@ -422,7 +422,7 @@ public async Task PublishDiagnosticsAsync_NoopsIfCSharpDiagnosticsAreSameAsPrevi .Returns(Task.CompletedTask); var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); @@ -453,7 +453,7 @@ public void ClearClosedDocuments_ClearsDiagnosticsForClosedDocument() .Returns(Task.CompletedTask); var documentContextFactory = new TestDocumentContextFactory(); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); @@ -473,7 +473,7 @@ public void ClearClosedDocuments_NoopsIfDocumentIsStillOpen() // Arrange var clientConnectionMock = new StrictMock(); var documentContextFactory = new TestDocumentContextFactory(); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); @@ -490,7 +490,7 @@ public void ClearClosedDocuments_NoopsIfDocumentIsClosedButNoDiagnostics() // Arrange var clientConnectionMock = new StrictMock(); var documentContextFactory = new TestDocumentContextFactory(); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); @@ -507,7 +507,7 @@ public void ClearClosedDocuments_RestartsTimerIfDocumentsStillOpen() // Arrange var clientConnectionMock = new StrictMock(); var documentContextFactory = new TestDocumentContextFactory(); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); var publisherAccessor = publisher.GetTestAccessor(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentTextPresentationEndpointTests.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentTextPresentationEndpointTests.cs index f5af246e6e4..7c36bf571c9 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentTextPresentationEndpointTests.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentTextPresentationEndpointTests.cs @@ -25,7 +25,7 @@ public async Task Handle_Html_MakesRequest() { // Arrange var codeDocument = TestRazorCodeDocument.Create("
"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var uri = new Uri("file://path/test.razor"); @@ -72,7 +72,7 @@ public async Task Handle_CSharp_DoesNotMakeRequest() var uri = new Uri("file://path/test.razor"); var documentContext = CreateDocumentContext(uri, codeDocument); var projectedRange = It.IsAny(); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.CSharp && s.TryMapToGeneratedDocumentRange(csharpDocument, It.IsAny(), out projectedRange) == true, MockBehavior.Strict); @@ -109,7 +109,7 @@ public async Task Handle_DocumentNotFound_ReturnsNull() var codeDocument = TestRazorCodeDocument.Create("
"); var uri = new Uri("file://path/test.razor"); var documentContext = CreateDocumentContext(uri, codeDocument); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var response = (WorkspaceEdit?)null; @@ -151,7 +151,7 @@ public async Task Handle_UnsupportedCodeDocument_ReturnsNull() codeDocument.SetUnsupported(); var uri = new Uri("file://path/test.razor"); var documentContext = CreateDocumentContext(uri, codeDocument); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var response = new WorkspaceEdit(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs index 3e0c2fecef4..318436e546a 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs @@ -34,7 +34,7 @@ public async Task Handle_SimpleComponent_ReturnsResult() await projectManager.CreateAndAddDocumentAsync(project, "c:/path/index.razor"); await projectManager.CreateAndAddDocumentAsync(project, "c:/path/MyTagHelper.razor"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var droppedUri = new Uri("file:///c:/path/MyTagHelper.razor"); @@ -92,7 +92,7 @@ public async Task Handle_SimpleComponentWithChildFile_ReturnsResult() await projectManager.CreateAndAddDocumentAsync(project, "c:/path/index.razor"); await projectManager.CreateAndAddDocumentAsync(project, "c:/path/MyTagHelper.razor"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var droppedUri = new Uri("file:///c:/path/MyTagHelper.razor"); @@ -155,7 +155,7 @@ public async Task Handle_ComponentWithRequiredAttribute_ReturnsResult() await projectManager.CreateAndAddDocumentAsync(project, "c:/path/index.razor"); await projectManager.CreateAndAddDocumentAsync(project, "c:/path/fetchdata.razor"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var droppedUri = new Uri("file:///c:/path/fetchdata.razor"); @@ -214,7 +214,7 @@ public async Task Handle_NoTypeNameIdentifier_ReturnsNull() { // Arrange var codeDocument = TestRazorCodeDocument.Create("
"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var componentCodeDocument = TestRazorCodeDocument.Create("
"); @@ -265,7 +265,7 @@ public async Task Handle_MultipleUris_ReturnsNull() { // Arrange var codeDocument = TestRazorCodeDocument.Create("
"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var documentSnapshot = Mock.Of(s => s.GetGeneratedOutputAsync() == Task.FromResult(codeDocument), MockBehavior.Strict); @@ -316,7 +316,7 @@ public async Task Handle_NotComponent_ReturnsNull() { // Arrange var codeDocument = TestRazorCodeDocument.Create("
"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var documentSnapshot = Mock.Of(s => s.GetGeneratedOutputAsync() == Task.FromResult(codeDocument), MockBehavior.Strict); @@ -368,7 +368,7 @@ public async Task Handle_ComponentWithNestedFiles_ReturnsResult() await projectManager.CreateAndAddDocumentAsync(project, "c:/path/index.razor"); await projectManager.CreateAndAddDocumentAsync(project, "c:/path/fetchdata.razor"); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var droppedUri1 = new Uri("file:///c:/path/fetchdata.razor.cs"); @@ -426,7 +426,7 @@ public async Task Handle_CSharp_ReturnsNull() var uri = new Uri("file://path/test.razor"); var documentContext = CreateDocumentContext(uri, codeDocument); var projectedRange = It.IsAny(); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.CSharp && s.TryMapToGeneratedDocumentRange(csharpDocument, It.IsAny(), out projectedRange) == true, MockBehavior.Strict); @@ -471,7 +471,7 @@ public async Task Handle_DocumentNotFound_ReturnsNull() var codeDocument = TestRazorCodeDocument.Create("
"); var uri = new Uri("file://path/test.razor"); var documentContext = CreateDocumentContext(uri, codeDocument); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var documentSnapshot = Mock.Of(s => s.GetGeneratedOutputAsync() == Task.FromResult(codeDocument), MockBehavior.Strict); @@ -516,7 +516,7 @@ public async Task Handle_UnsupportedCodeDocument_ReturnsNull() codeDocument.SetUnsupported(); var uri = new Uri("file://path/test.razor"); var documentContext = CreateDocumentContext(uri, codeDocument); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var documentSnapshot = Mock.Of(s => s.GetGeneratedOutputAsync() == Task.FromResult(codeDocument), MockBehavior.Strict); @@ -560,7 +560,7 @@ public async Task Handle_NoUris_ReturnsNull() var codeDocument = TestRazorCodeDocument.Create("
"); var uri = new Uri("file://path/test.razor"); var documentContext = CreateDocumentContext(uri, codeDocument); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var documentSnapshot = Mock.Of(s => s.GetGeneratedOutputAsync() == Task.FromResult(codeDocument), MockBehavior.Strict); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentOnTypeFormattingEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentOnTypeFormattingEndpointTest.cs index 0ba0f51c73c..f887c280c3d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentOnTypeFormattingEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentOnTypeFormattingEndpointTest.cs @@ -124,7 +124,7 @@ public async Task Handle_OnTypeFormatting_HtmlLanguageKind_ReturnsNull() var documentContext = CreateDocumentContext(uri, codeDocument); var formattingService = new DummyRazorFormattingService(); - var documentMappingService = new Mock(MockBehavior.Strict); + var documentMappingService = new Mock(MockBehavior.Strict); documentMappingService.Setup(s => s.GetLanguageKind(codeDocument, 17, false)).Returns(RazorLanguageKind.Html); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new DocumentOnTypeFormattingEndpoint( @@ -160,7 +160,7 @@ public async Task Handle_OnTypeFormatting_RazorLanguageKind_ReturnsNull() var documentContext = CreateDocumentContext(uri, codeDocument); var formattingService = new DummyRazorFormattingService(); - var documentMappingService = new Mock(MockBehavior.Strict); + var documentMappingService = new Mock(MockBehavior.Strict); documentMappingService.Setup(s => s.GetLanguageKind(codeDocument, 17, false)).Returns(RazorLanguageKind.Razor); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new DocumentOnTypeFormattingEndpoint( diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs index 335945678d6..aea2cf20f65 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs @@ -725,7 +725,7 @@ public async Task Handle_Hover_SingleServer_CallsDelegatedLanguageServer() .Setup(c => c.SendRequestAsync(CustomMessageNames.RazorHoverEndpointName, It.IsAny(), It.IsAny())) .ReturnsAsync(delegatedHover); - var documentMappingServiceMock = new Mock(MockBehavior.Strict); + var documentMappingServiceMock = new Mock(MockBehavior.Strict); documentMappingServiceMock .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(RazorLanguageKind.CSharp); @@ -936,12 +936,12 @@ public void Increment(){ private HoverEndpoint CreateEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions = null, - IRazorDocumentMappingService documentMappingService = null, + IDocumentMappingService documentMappingService = null, IClientConnection clientConnection = null) { languageServerFeatureOptions ??= Mock.Of(options => options.SupportsFileManipulation == true && options.SingleServerSupport == false, MockBehavior.Strict); - var documentMappingServiceMock = new Mock(MockBehavior.Strict); + var documentMappingServiceMock = new Mock(MockBehavior.Strict); documentMappingServiceMock .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(RazorLanguageKind.Html); @@ -961,7 +961,7 @@ private HoverEndpoint CreateEndpoint( return endpoint; } - private HoverService GetHoverService(IRazorDocumentMappingService mappingService = null) + private HoverService GetHoverService(IDocumentMappingService mappingService = null) { var projectManager = CreateProjectSnapshotManager(); var lspTagHelperTooltipFactory = new DefaultLSPTagHelperTooltipFactory(projectManager); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs index 7f056bbde56..89cbae748bc 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs @@ -19,12 +19,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Mapping; public class RazorLanguageQueryEndpointTest : LanguageServerTestBase { - private readonly IRazorDocumentMappingService _mappingService; + private readonly IDocumentMappingService _documentMappingService; public RazorLanguageQueryEndpointTest(ITestOutputHelper testOutput) : base(testOutput) { - _mappingService = new RazorDocumentMappingService( + _documentMappingService = new RazorDocumentMappingService( FilePathService, new TestDocumentContextFactory(), LoggerFactory); @@ -37,7 +37,7 @@ public async Task Handle_ResolvesLanguageRequest_Razor() var documentPath = new Uri("C:/path/to/document.cshtml"); var codeDocument = CreateCodeDocument("@{}"); var documentContext = CreateDocumentContext(documentPath, codeDocument); - var languageEndpoint = new RazorLanguageQueryEndpoint(_mappingService, LoggerFactory); + var languageEndpoint = new RazorLanguageQueryEndpoint(_documentMappingService, LoggerFactory); var request = new RazorLanguageQueryParams() { Uri = documentPath, @@ -64,7 +64,7 @@ public async Task Handle_ResolvesLanguageRequest_Html() var documentPath = new Uri("C:/path/to/document.cshtml"); var codeDocument = CreateCodeDocument("@DateTime.Now

"); var documentContext = CreateDocumentContext(documentPath, codeDocument); - var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_mappingService); + var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_documentMappingService); var request = new RazorMapToDocumentRangesParams() { Kind = RazorLanguageKind.Html, @@ -196,7 +196,7 @@ public async Task Handle_MapToDocumentRanges_Razor() var documentPath = new Uri("C:/path/to/document.cshtml"); var codeDocument = CreateCodeDocument("

@DateTime.Now

"); var documentContext = CreateDocumentContext(documentPath, codeDocument); - var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_mappingService); + var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_documentMappingService); var request = new RazorMapToDocumentRangesParams() { Kind = RazorLanguageKind.Razor, @@ -230,7 +230,7 @@ public async Task Handle_MapToDocumentRanges_Unsupported() ]); codeDocument.SetUnsupported(); var documentContext = CreateDocumentContext(documentPath, codeDocument); - var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_mappingService); + var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_documentMappingService); var request = new RazorMapToDocumentRangesParams() { Kind = RazorLanguageKind.CSharp, diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs index 3f0e0a3863b..c812fcdbaae 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs @@ -526,7 +526,7 @@ public async Task Handle_Rename_SingleServer_CallsDelegatedLanguageServer() .Setup(c => c.SendRequestAsync(CustomMessageNames.RazorRenameEndpointName, It.IsAny(), It.IsAny())) .ReturnsAsync(delegatedEdit); - var documentMappingServiceMock = new StrictMock(); + var documentMappingServiceMock = new StrictMock(); documentMappingServiceMock .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(RazorLanguageKind.CSharp); @@ -576,7 +576,7 @@ public async Task Handle_Rename_SingleServer_DoesNotDelegateForRazor() o.ReturnCodeActionAndRenamePathsWithPrefixedSlash == false); var clientConnection = StrictMock.Of(); - var documentMappingServiceMock = new StrictMock(); + var documentMappingServiceMock = new StrictMock(); documentMappingServiceMock .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(RazorLanguageKind.Razor); @@ -608,7 +608,7 @@ public async Task Handle_Rename_SingleServer_DoesNotDelegateForRazor() private async Task<(RenameEndpoint, IDocumentContextFactory)> CreateEndpointAndDocumentContextFactoryAsync( LanguageServerFeatureOptions? options = null, - IRazorDocumentMappingService? documentMappingService = null, + IDocumentMappingService? documentMappingService = null, IEditMappingService? editMappingService = null, IClientConnection? clientConnection = null) { @@ -692,7 +692,7 @@ await projectManager.UpdateAsync(updater => if (documentMappingService == null) { - var documentMappingServiceMock = new StrictMock(); + var documentMappingServiceMock = new StrictMock(); documentMappingServiceMock .Setup(c => c.GetLanguageKind(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(RazorLanguageKind.Html); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs index ece9afaf242..33a2c247fd0 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs @@ -24,7 +24,7 @@ public abstract partial class SingleServerDelegatingEndpointTestBase(ITestOutput { private protected IDocumentContextFactory? DocumentContextFactory { get; private set; } private protected LanguageServerFeatureOptions? LanguageServerFeatureOptions { get; private set; } - private protected IRazorDocumentMappingService? DocumentMappingService { get; private set; } + private protected IDocumentMappingService? DocumentMappingService { get; private set; } private protected IEditMappingService? EditMappingService { get; private set; } [MemberNotNull(nameof(DocumentContextFactory), nameof(LanguageServerFeatureOptions), nameof(DocumentMappingService), nameof(EditMappingService))] diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WrapWithTag/WrapWithTagEndpointTests.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WrapWithTag/WrapWithTagEndpointTests.cs index fc85888a50b..80a563b38d4 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WrapWithTag/WrapWithTagEndpointTests.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WrapWithTag/WrapWithTagEndpointTests.cs @@ -35,7 +35,7 @@ public async Task Handle_Html_ReturnsResult() .Setup(l => l.SendRequestAsync(LanguageServerConstants.RazorWrapWithTagEndpoint, It.IsAny(), It.IsAny())) .ReturnsAsync(response); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var endpoint = new WrapWithTagEndpoint( clientConnection.Object, @@ -70,7 +70,7 @@ public async Task Handle_CSharp_ReturnsNull() .Setup(l => l.SendRequestAsync(LanguageServerConstants.RazorWrapWithTagEndpoint, It.IsAny(), It.IsAny())) .ReturnsAsync(response); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.CSharp, MockBehavior.Strict); var endpoint = new WrapWithTagEndpoint( clientConnection.Object, @@ -105,7 +105,7 @@ public async Task Handle_CSharp_WholeImplicitStatement_ReturnsResult() .Setup(l => l.SendRequestAsync(LanguageServerConstants.RazorWrapWithTagEndpoint, It.IsAny(), It.IsAny())) .ReturnsAsync(response); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.CSharp, MockBehavior.Strict); var endpoint = new WrapWithTagEndpoint( clientConnection.Object, @@ -140,7 +140,7 @@ public async Task Handle_CSharp_PartOfImplicitStatement_ReturnsNull() .Setup(l => l.SendRequestAsync(LanguageServerConstants.RazorWrapWithTagEndpoint, It.IsAny(), It.IsAny())) .ReturnsAsync(response); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.CSharp, MockBehavior.Strict); var endpoint = new WrapWithTagEndpoint( clientConnection.Object, @@ -175,7 +175,7 @@ public async Task Handle_CSharp_InImplicitStatement_ReturnsResult() .Setup(l => l.SendRequestAsync(LanguageServerConstants.RazorWrapWithTagEndpoint, It.IsAny(), It.IsAny())) .ReturnsAsync(response); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.CSharp, MockBehavior.Strict); var endpoint = new WrapWithTagEndpoint( clientConnection.Object, @@ -206,7 +206,7 @@ public async Task Handle_DocumentNotFound_ReturnsNull() var clientConnection = new Mock(MockBehavior.Strict); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var endpoint = new WrapWithTagEndpoint(clientConnection.Object, documentMappingService, LoggerFactory); @@ -234,7 +234,7 @@ public async Task Handle_UnsupportedCodeDocument_ReturnsNull() var clientConnection = new Mock(MockBehavior.Strict); - var documentMappingService = Mock.Of( + var documentMappingService = Mock.Of( s => s.GetLanguageKind(codeDocument, It.IsAny(), It.IsAny()) == RazorLanguageKind.Html, MockBehavior.Strict); var endpoint = new WrapWithTagEndpoint(clientConnection.Object, documentMappingService, LoggerFactory); From f3f3ac7fa7cc83cc26fa5e44a18f138f00c7f798 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 11:59:44 -0700 Subject: [PATCH 29/53] Rename AbstractRazorDocumentMappingService to AbstractDocumentMappingService --- .../RazorDocumentMappingService.cs | 2 +- ...umentMappingService.cs => AbstractDocumentMappingService.cs} | 2 +- .../DocumentMapping/RemoteDocumentMappingService.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/{AbstractRazorDocumentMappingService.cs => AbstractDocumentMappingService.cs} (99%) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentMappingService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentMappingService.cs index 37f56bf372e..e615cd754d2 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentMappingService.cs @@ -16,7 +16,7 @@ internal sealed class RazorDocumentMappingService( IFilePathService filePathService, IDocumentContextFactory documentContextFactory, ILoggerFactory loggerFactory) - : AbstractRazorDocumentMappingService(filePathService, loggerFactory.GetOrCreateLogger()) + : AbstractDocumentMappingService(filePathService, loggerFactory.GetOrCreateLogger()) { private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractDocumentMappingService.cs similarity index 99% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractDocumentMappingService.cs index 1da1ba17714..60fc096d910 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractDocumentMappingService.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; -internal abstract class AbstractRazorDocumentMappingService(IFilePathService filePathService, ILogger logger) : IDocumentMappingService +internal abstract class AbstractDocumentMappingService(IFilePathService filePathService, ILogger logger) : IDocumentMappingService { private readonly IFilePathService _filePathService = filePathService; private readonly ILogger _logger = logger; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs index 5dddaea4cec..768af10ce8f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs @@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.DocumentMapping; internal sealed class RemoteDocumentMappingService( IFilePathService filePathService, ILoggerFactory loggerFactory) - : AbstractRazorDocumentMappingService(filePathService, loggerFactory.GetOrCreateLogger()) + : AbstractDocumentMappingService(filePathService, loggerFactory.GetOrCreateLogger()) { protected override ValueTask TryGetCodeDocumentAsync(Uri razorDocumentUri, CancellationToken cancellationToken) { From d5dc280eae1901b032d3932b5fe641c7e14830ff Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 13:13:59 -0700 Subject: [PATCH 30/53] Rename IRazorDocumentMappingServiceExtensions to IDocumentMappingServiceExtensions --- ...erviceExtensions.cs => IDocumentMappingServiceExtensions.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/{IRazorDocumentMappingServiceExtensions.cs => IDocumentMappingServiceExtensions.cs} (99%) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingServiceExtensions.cs similarity index 99% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingServiceExtensions.cs index 81a02ac75eb..1eeb671409e 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingServiceExtensions.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; -internal static class IRazorDocumentMappingServiceExtensions +internal static class IDocumentMappingServiceExtensions { public static TextEdit[] GetHostDocumentEdits(this IDocumentMappingService service, IRazorGeneratedDocument generatedDocument, TextEdit[] generatedDocumentEdits) { From 58161c0f0d6e919b3352c469d86fb582e5360423 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 13:21:12 -0700 Subject: [PATCH 31/53] Rename RazorDocumentMappingService to LspDocumentMappingService --- .../IServiceCollectionExtensions.cs | 2 +- ...ervice.cs => LspDocumentMappingService.cs} | 4 +- .../CodeActionEndToEndTest.NetFx.cs | 2 +- .../TestDelegatedCompletionListProvider.cs | 2 +- .../RazorBreakpointSpanEndpointTest.cs | 2 +- .../RazorProximityExpressionsEndpointTest.cs | 2 +- .../Definition/DefinitionEndpointTest.cs | 2 +- .../DocumentPullDiagnosticsEndpointTest.cs | 2 +- .../RazorDiagnosticsPublisherTest.cs | 4 +- .../DocumentHighlightEndpointTest.cs | 2 +- .../DocumentOnTypeFormattingEndpointTest.cs | 8 +- .../FormattingContentValidationPassTest.cs | 2 +- .../FormattingDiagnosticValidationPassTest.cs | 2 +- .../Formatting_NetFx/FormattingTestBase.cs | 4 +- .../TestRazorFormattingService.cs | 2 +- .../Hover/HoverServiceTest.cs | 2 +- .../MapCode/MapCodeTest.cs | 2 +- .../Mapping/RazorLanguageQueryEndpointTest.cs | 2 +- .../RazorMapToDocumentRangesEndpointTest.cs | 2 +- .../RazorDocumentMappingServiceTest.cs | 92 +++++++++---------- .../Semantic/SemanticTokensTest.cs | 4 +- .../SingleServerDelegatingEndpointTestBase.cs | 2 +- 22 files changed, 74 insertions(+), 74 deletions(-) rename src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/{RazorDocumentMappingService.cs => LspDocumentMappingService.cs} (91%) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs index a505aa69c2d..be6e74d6c5d 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs @@ -202,7 +202,7 @@ public static void AddDocumentManagementServices(this IServiceCollection service services.AddSingleton(); services.AddSingleton((services) => (RazorProjectService)services.GetRequiredService()); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(sp => sp.GetRequiredService()); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentMappingService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LspDocumentMappingService.cs similarity index 91% rename from src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentMappingService.cs rename to src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LspDocumentMappingService.cs index e615cd754d2..f8f568366c6 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LspDocumentMappingService.cs @@ -12,11 +12,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer; -internal sealed class RazorDocumentMappingService( +internal sealed class LspDocumentMappingService( IFilePathService filePathService, IDocumentContextFactory documentContextFactory, ILoggerFactory loggerFactory) - : AbstractDocumentMappingService(filePathService, loggerFactory.GetOrCreateLogger()) + : AbstractDocumentMappingService(filePathService, loggerFactory.GetOrCreateLogger()) { private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs index 2196a72ccfa..e9992610258 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs @@ -55,7 +55,7 @@ private GenerateMethodCodeActionResolver[] CreateRazorCodeActionResolvers( new GenerateMethodResolverDocumentContextFactory(filePath, codeDocument), optionsMonitor ?? TestRazorLSPOptionsMonitor.Create(), clientConnection, - new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory), + new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory), razorFormattingService) ]; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/TestDelegatedCompletionListProvider.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/TestDelegatedCompletionListProvider.cs index bb8dee4338e..746ba8cc729 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/TestDelegatedCompletionListProvider.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/TestDelegatedCompletionListProvider.cs @@ -26,7 +26,7 @@ private TestDelegatedCompletionListProvider( ILoggerFactory loggerFactory) : base( responseRewriters, - new RazorDocumentMappingService(new LSPFilePathService(TestLanguageServerFeatureOptions.Instance), new TestDocumentContextFactory(), loggerFactory), + new LspDocumentMappingService(new LSPFilePathService(TestLanguageServerFeatureOptions.Instance), new TestDocumentContextFactory(), loggerFactory), new TestLanguageServer(new Dictionary>>() { [LanguageServerConstants.RazorCompletionEndpointName] = completionFactory.OnDelegationAsync, diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs index a97ffd32335..718cbcfc0d5 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs @@ -20,7 +20,7 @@ public class RazorBreakpointSpanEndpointTest : LanguageServerTestBase public RazorBreakpointSpanEndpointTest(ITestOutputHelper testOutput) : base(testOutput) { - _mappingService = new RazorDocumentMappingService( + _mappingService = new LspDocumentMappingService( FilePathService, new TestDocumentContextFactory(), LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs index 8d4c0fbe3fa..66f45a89fc0 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs @@ -20,7 +20,7 @@ public class RazorProximityExpressionsEndpointTest : LanguageServerTestBase public RazorProximityExpressionsEndpointTest(ITestOutputHelper testOutput) : base(testOutput) { - _mappingService = new RazorDocumentMappingService( + _mappingService = new LspDocumentMappingService( FilePathService, new TestDocumentContextFactory(), LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointTest.cs index ebfb6b65708..02ae91c9c9b 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointTest.cs @@ -395,7 +395,7 @@ private async Task VerifyNavigatePositionAsync(string content, string propertyNa SetupDocument(out var codeDocument, out _, content); var expectedRange = codeDocument.Source.Text.GetRange(selection); - var mappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var mappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); var range = await DefinitionEndpoint.TryGetPropertyRangeAsync(codeDocument, propertyName, mappingService, Logger, DisposalToken); Assert.NotNull(range); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/DocumentPullDiagnosticsEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/DocumentPullDiagnosticsEndpointTest.cs index b5d4b12c60a..ecbadccdd23 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/DocumentPullDiagnosticsEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/DocumentPullDiagnosticsEndpointTest.cs @@ -18,7 +18,7 @@ public sealed class DocumentPullDiagnosticsEndpointTest(ITestOutputHelper testOu public void ApplyCapabilities_AddsExpectedCapabilities() { // Arrange - var documentMappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); var razorTranslate = new Mock(MockBehavior.Strict, documentMappingService, LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs index 5ca3cc79c2c..4cdbc79137d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs @@ -218,7 +218,7 @@ public async Task PublishDiagnosticsAsync_NewDocumentDiagnosticsGetPublished(boo var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); var filePathService = new LSPFilePathService(TestLanguageServerFeatureOptions.Instance); - var documentMappingService = new RazorDocumentMappingService(filePathService, documentContextFactory, LoggerFactory); + var documentMappingService = new LspDocumentMappingService(filePathService, documentContextFactory, LoggerFactory); var translateDiagnosticsService = new RazorTranslateDiagnosticsService(documentMappingService, LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); @@ -370,7 +370,7 @@ public async Task PublishDiagnosticsAsync_NoopsIfRazorDiagnosticsAreSameAsPrevio var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); var filePathService = new LSPFilePathService(TestLanguageServerFeatureOptions.Instance); - var documentMappingService = new RazorDocumentMappingService(filePathService, documentContextFactory, LoggerFactory); + var documentMappingService = new LspDocumentMappingService(filePathService, documentContextFactory, LoggerFactory); var translateDiagnosticsService = new RazorTranslateDiagnosticsService(documentMappingService, LoggerFactory); using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentHighlighting/DocumentHighlightEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentHighlighting/DocumentHighlightEndpointTest.cs index 59b5b074499..060c282439d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentHighlighting/DocumentHighlightEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentHighlighting/DocumentHighlightEndpointTest.cs @@ -121,7 +121,7 @@ private async Task VerifyHighlightingRangesAsync(string input) MockBehavior.Strict); var languageServer = new DocumentHighlightServer(csharpServer, csharpDocumentUri); - var documentMappingService = new RazorDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); var endpoint = new DocumentHighlightEndpoint( languageServerFeatureOptions, documentMappingService, languageServer, LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentOnTypeFormattingEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentOnTypeFormattingEndpointTest.cs index f887c280c3d..17177a8e49c 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentOnTypeFormattingEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/DocumentOnTypeFormattingEndpointTest.cs @@ -24,7 +24,7 @@ public async Task Handle_OnTypeFormatting_FormattingDisabled_ReturnsNull() // Arrange var uri = new Uri("file://path/test.razor"); var formattingService = new DummyRazorFormattingService(); - var documentMappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); var optionsMonitor = GetOptionsMonitor(enableFormatting: false); var endpoint = new DocumentOnTypeFormattingEndpoint( @@ -53,7 +53,7 @@ public async Task Handle_OnTypeFormatting_DocumentNotFound_ReturnsNull() var documentContext = CreateDocumentContext(new Uri("file://path/testDifferentFile.razor"), codeDocument); var formattingService = new DummyRazorFormattingService(); - var documentMappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new DocumentOnTypeFormattingEndpoint( @@ -88,7 +88,7 @@ public async Task Handle_OnTypeFormatting_RemapFailed_ReturnsNull() var documentContext = CreateDocumentContext(uri, codeDocument); var formattingService = new DummyRazorFormattingService(); - var documentMappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new DocumentOnTypeFormattingEndpoint( @@ -195,7 +195,7 @@ public async Task Handle_OnTypeFormatting_UnexpectedTriggerCharacter_ReturnsNull var documentContextFactory = CreateDocumentContextFactory(uri, codeDocument); var formattingService = new DummyRazorFormattingService(); - var documentMappingService = new RazorDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new DocumentOnTypeFormattingEndpoint( diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs index 4e9160ab8b6..d42f0778dc8 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs @@ -110,7 +110,7 @@ public class Foo { } private FormattingContentValidationPass GetPass() { - var mappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var mappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); var pass = new FormattingContentValidationPass(mappingService, LoggerFactory) { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs index ed17457db2a..c0f06e9831e 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs @@ -107,7 +107,7 @@ public class Foo { } private FormattingDiagnosticValidationPass GetPass() { - var mappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var mappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); var pass = new FormattingDiagnosticValidationPass(mappingService, LoggerFactory) { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs index 9ec26d51add..112e7ae0016 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs @@ -116,7 +116,7 @@ private protected async Task RunOnTypeFormattingTestAsync( var (codeDocument, documentSnapshot) = CreateCodeDocumentAndSnapshot(razorSourceText, uri.AbsolutePath, fileKind: fileKind, inGlobalNamespace: inGlobalNamespace); var filePathService = new LSPFilePathService(TestLanguageServerFeatureOptions.Instance); - var mappingService = new RazorDocumentMappingService( + var mappingService = new LspDocumentMappingService( filePathService, new TestDocumentContextFactory(), LoggerFactory); var languageKind = mappingService.GetLanguageKind(codeDocument, positionAfterTrigger, rightAssociative: false); @@ -177,7 +177,7 @@ protected async Task RunCodeActionFormattingTestAsync( var (codeDocument, documentSnapshot) = CreateCodeDocumentAndSnapshot(razorSourceText, uri.AbsolutePath, fileKind: fileKind, inGlobalNamespace: inGlobalNamespace); var filePathService = new LSPFilePathService(TestLanguageServerFeatureOptions.Instance); - var mappingService = new RazorDocumentMappingService(filePathService, new TestDocumentContextFactory(), LoggerFactory); + var mappingService = new LspDocumentMappingService(filePathService, new TestDocumentContextFactory(), LoggerFactory); var languageKind = mappingService.GetLanguageKind(codeDocument, positionAfterTrigger, rightAssociative: false); if (languageKind == RazorLanguageKind.Html) { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/TestRazorFormattingService.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/TestRazorFormattingService.cs index 9a32d0ce57d..12c22645152 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/TestRazorFormattingService.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/TestRazorFormattingService.cs @@ -27,7 +27,7 @@ public static async Task CreateWithFullSupportAsync( codeDocument ??= TestRazorCodeDocument.CreateEmpty(); var filePathService = new LSPFilePathService(TestLanguageServerFeatureOptions.Instance); - var mappingService = new RazorDocumentMappingService(filePathService, new TestDocumentContextFactory(), loggerFactory); + var mappingService = new LspDocumentMappingService(filePathService, new TestDocumentContextFactory(), loggerFactory); var projectManager = StrictMock.Of(); var versionCache = new DocumentVersionCache(projectManager); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs index aea2cf20f65..d7a1c2bc4a2 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs @@ -880,7 +880,7 @@ private async Task GetResultFromSingleServerEndpointAsync(strin options.UseRazorCohostServer == false , MockBehavior.Strict); var languageServer = new HoverLanguageServer(csharpServer, csharpDocumentUri, DisposalToken); - var documentMappingService = new RazorDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); var service = GetHoverService(documentMappingService); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MapCode/MapCodeTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MapCode/MapCodeTest.cs index ba8a4a7fce8..22d3bf89399 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MapCode/MapCodeTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MapCode/MapCodeTest.cs @@ -290,7 +290,7 @@ private async Task VerifyCodeMappingAsync( var documentContextFactory = new TestDocumentContextFactory(razorFilePath, codeDocument, version: 1337); var languageServer = new MapCodeServer(csharpServer, csharpDocumentUri); - var documentMappingService = new RazorDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); var endpoint = new MapCodeEndpoint(documentMappingService, documentContextFactory, languageServer, NoOpTelemetryReporter.Instance); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs index 89cbae748bc..4d52de66276 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs @@ -24,7 +24,7 @@ public class RazorLanguageQueryEndpointTest : LanguageServerTestBase public RazorLanguageQueryEndpointTest(ITestOutputHelper testOutput) : base(testOutput) { - _documentMappingService = new RazorDocumentMappingService( + _documentMappingService = new LspDocumentMappingService( FilePathService, new TestDocumentContextFactory(), LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorMapToDocumentRangesEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorMapToDocumentRangesEndpointTest.cs index ea388b4149e..271ebda9975 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorMapToDocumentRangesEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorMapToDocumentRangesEndpointTest.cs @@ -23,7 +23,7 @@ public class RazorMapToDocumentRangesEndpointTest : LanguageServerTestBase public RazorMapToDocumentRangesEndpointTest(ITestOutputHelper testOutput) : base(testOutput) { - _documentMappingService = new RazorDocumentMappingService( + _documentMappingService = new LspDocumentMappingService( FilePathService, new TestDocumentContextFactory(), LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorDocumentMappingServiceTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorDocumentMappingServiceTest.cs index 511b5a2ae2f..8bd5c180295 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorDocumentMappingServiceTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorDocumentMappingServiceTest.cs @@ -35,7 +35,7 @@ public RazorDocumentMappingServiceTest(ITestOutputHelper testOutput) public void TryMapToHostDocumentRange_Strict_StartOnlyMaps_ReturnsFalse() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -58,7 +58,7 @@ public void TryMapToHostDocumentRange_Strict_StartOnlyMaps_ReturnsFalse() public void TryMapToHostDocumentRange_Strict_EndOnlyMaps_ReturnsFalse() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -81,7 +81,7 @@ public void TryMapToHostDocumentRange_Strict_EndOnlyMaps_ReturnsFalse() public void TryMapToHostDocumentRange_Strict_StartAndEndMap_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -105,7 +105,7 @@ public void TryMapToHostDocumentRange_Strict_StartAndEndMap_ReturnsTrue() public void TryMapToHostDocumentRange_Inclusive_DirectlyMaps_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -129,7 +129,7 @@ public void TryMapToHostDocumentRange_Inclusive_DirectlyMaps_ReturnsTrue() public void TryMapToHostDocumentRange_Inclusive_StartSinglyIntersects_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -153,7 +153,7 @@ public void TryMapToHostDocumentRange_Inclusive_StartSinglyIntersects_ReturnsTru public void TryMapToHostDocumentRange_Inclusive_EndSinglyIntersects_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -177,7 +177,7 @@ public void TryMapToHostDocumentRange_Inclusive_EndSinglyIntersects_ReturnsTrue( public void TryMapToHostDocumentRange_Inclusive_StartDoublyIntersects_ReturnsFalse() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -204,7 +204,7 @@ public void TryMapToHostDocumentRange_Inclusive_StartDoublyIntersects_ReturnsFal public void TryMapToHostDocumentRange_Inclusive_EndDoublyIntersects_ReturnsFalse() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -231,7 +231,7 @@ public void TryMapToHostDocumentRange_Inclusive_EndDoublyIntersects_ReturnsFalse public void TryMapToHostDocumentRange_Inclusive_OverlapsSingleMapping_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -255,7 +255,7 @@ public void TryMapToHostDocumentRange_Inclusive_OverlapsSingleMapping_ReturnsTru public void TryMapToHostDocumentRange_Inclusive_OverlapsTwoMappings_ReturnsFalse() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -282,7 +282,7 @@ public void TryMapToHostDocumentRange_Inclusive_OverlapsTwoMappings_ReturnsFalse public void TryMapToHostDocumentRange_Inferred_DirectlyMaps_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "__o = DateTime.Now;", @@ -306,7 +306,7 @@ public void TryMapToHostDocumentRange_Inferred_DirectlyMaps_ReturnsTrue() public void TryMapToHostDocumentRange_Inferred_BeginningOfDocAndProjection_ReturnsFalse() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "@

@DateTime.Now

", "(__builder) => { };__o = DateTime.Now;", @@ -329,7 +329,7 @@ public void TryMapToHostDocumentRange_Inferred_BeginningOfDocAndProjection_Retur public void TryMapToHostDocumentRange_Inferred_InbetweenProjections_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "@{ var abc = @ }", " var abc = (__builder) => { } ", @@ -356,7 +356,7 @@ public void TryMapToHostDocumentRange_Inferred_InbetweenProjections_ReturnsTrue( public void TryMapToHostDocumentRange_Inferred_InbetweenProjectionAndEndOfDoc_ReturnsTrue() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "@{ var abc = @", " var abc = (__builder) => { }", @@ -380,7 +380,7 @@ public void TryMapToHostDocumentRange_Inferred_InbetweenProjectionAndEndOfDoc_Re public void TryMapToHostDocumentRange_Inferred_OutsideDoc_ReturnsFalse() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "@{ var abc = @", " var abc = (__builder) => { }", @@ -416,7 +416,7 @@ public void TryMapToHostDocumentRange_Inferred_OutOfOrderMappings_DoesntThrow() // that has some very strange mappings! // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "@{ var abc = @", " var abc = (__builder) => { }", @@ -443,7 +443,7 @@ public void TryMapToHostDocumentRange_Inferred_OutOfOrderMappings_DoesntThrow() public void TryMapToGeneratedDocumentPosition_NotMatchingAnyMapping() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "test razor source", "test C# source", @@ -466,7 +466,7 @@ public void TryMapToGeneratedDocumentPosition_NotMatchingAnyMapping() public void TryMapToGeneratedDocumentPosition_CSharp_OnLeadingEdge() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "Line 1\nLine 2 @{ var abc;\nvar def; }", "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -496,7 +496,7 @@ public void TryMapToGeneratedDocumentPosition_CSharp_OnLeadingEdge() public void TryMapToGeneratedDocumentPosition_CSharp_InMiddle() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "Line 1\nLine 2 @{ var abc;\nvar def; }", "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -526,7 +526,7 @@ public void TryMapToGeneratedDocumentPosition_CSharp_InMiddle() public void TryMapToGeneratedDocumentPosition_CSharp_OnTrailingEdge() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( "Line 1\nLine 2 @{ var abc;\nvar def; }", "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -556,7 +556,7 @@ public void TryMapToGeneratedDocumentPosition_CSharp_OnTrailingEdge() public void TryMapToHostDocumentPosition_NotMatchingAnyMapping() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( razorSource: "test razor source", projectedCSharpSource: "projectedCSharpSource: test C# source", @@ -579,7 +579,7 @@ public void TryMapToHostDocumentPosition_NotMatchingAnyMapping() public void TryMapToHostDocumentPosition_CSharp_OnLeadingEdge() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( razorSource: "Line 1\nLine 2 @{ var abc;\nvar def; }", projectedCSharpSource: "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -609,7 +609,7 @@ public void TryMapToHostDocumentPosition_CSharp_OnLeadingEdge() public void TryMapToHostDocumentPosition_CSharp_InMiddle() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( razorSource: "Line 1\nLine 2 @{ var abc;\nvar def; }", projectedCSharpSource: "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -639,7 +639,7 @@ public void TryMapToHostDocumentPosition_CSharp_InMiddle() public void TryMapToHostDocumentPosition_CSharp_OnTrailingEdge() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( razorSource: "Line 1\nLine 2 @{ var abc;\nvar def; }", projectedCSharpSource: "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -669,7 +669,7 @@ public void TryMapToHostDocumentPosition_CSharp_OnTrailingEdge() public void TryMapToGeneratedDocumentRange_CSharp() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( razorSource: "Line 1\nLine 2 @{ var abc;\nvar def; }", projectedCSharpSource: "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -700,7 +700,7 @@ public void TryMapToGeneratedDocumentRange_CSharp() public void TryMapToGeneratedDocumentRange_CSharp_MissingSourceMappings() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( razorSource: "Line 1\nLine 2 @{ var abc;\nvar def; }", projectedCSharpSource: "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -724,7 +724,7 @@ public void TryMapToGeneratedDocumentRange_CSharp_MissingSourceMappings() public void TryMapToGeneratedDocumentRange_CSharp_End_LessThan_Start() { // Arrange - var service = new RazorDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); + var service = new LspDocumentMappingService(_filePathService, new TestDocumentContextFactory(), LoggerFactory); var codeDoc = CreateCodeDocumentWithCSharpProjection( razorSource: "Line 1\nLine 2 @{ var abc;\nvar def; }", projectedCSharpSource: "\n// Prefix\n var abc;\nvar def; \n// Suffix", @@ -760,7 +760,7 @@ public void GetLanguageKindCore_TagHelperElementOwnsName() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text, new[] { descriptor.Build() }); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 32 + Environment.NewLine.Length, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 32 + Environment.NewLine.Length, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.Html, languageKind); @@ -780,7 +780,7 @@ public void GetLanguageKindCore_TagHelpersDoNotOwnTrailingEdge() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text, new[] { descriptor.Build() }); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 42 + Environment.NewLine.Length, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 42 + Environment.NewLine.Length, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.Razor, languageKind); @@ -806,7 +806,7 @@ public void GetLanguageKindCore_TagHelperNestedCSharpAttribute() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text, new[] { descriptor.Build() }); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 46 + Environment.NewLine.Length, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 46 + Environment.NewLine.Length, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -820,7 +820,7 @@ public void GetLanguageKindCore_CSharp() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 5, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 5, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -834,7 +834,7 @@ public void GetLanguageKindCore_Html() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 5, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 5, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.Html, languageKind); @@ -848,7 +848,7 @@ public void GetLanguageKindCore_DefaultsToRazorLanguageIfCannotLocateOwner() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length + 1, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length + 1, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.Razor, languageKind); @@ -876,7 +876,7 @@ public void GetLanguageKindCore_GetsLastClassifiedSpanLanguageIfAtEndOfDocument( var tagHelperSpans = ImmutableArray.Empty; // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.Html, languageKind); @@ -890,7 +890,7 @@ public void GetLanguageKindCore_HtmlEdgeEnd() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.Html, languageKind); @@ -904,7 +904,7 @@ public void GetLanguageKindCore_CSharpEdgeEnd() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, text.Length, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -918,7 +918,7 @@ public void GetLanguageKindCore_RazorEdgeWithCSharp() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 2, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 2, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -932,7 +932,7 @@ public void GetLanguageKindCore_CSharpEdgeWithCSharpMarker() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 12, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 12, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -946,7 +946,7 @@ public void GetLanguageKindCore_ExplicitExpressionStartCSharp() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 2, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 2, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -960,7 +960,7 @@ public void GetLanguageKindCore_ExplicitExpressionInProgressCSharp() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 4, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 4, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -974,7 +974,7 @@ public void GetLanguageKindCore_ImplicitExpressionStartCSharp() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 1, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 1, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -988,7 +988,7 @@ public void GetLanguageKindCore_ImplicitExpressionInProgressCSharp() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 3, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 3, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -1002,7 +1002,7 @@ public void GetLanguageKindCore_RazorEdgeWithHtml() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 2, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 2, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.Html, languageKind); @@ -1016,7 +1016,7 @@ public void GetLanguageKindCore_HtmlInCSharpLeftAssociative() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 13, text.Length, rightAssociative: false); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 13, text.Length, rightAssociative: false); // Assert Assert.Equal(RazorLanguageKind.CSharp, languageKind); @@ -1030,7 +1030,7 @@ public void GetLanguageKindCore_HtmlInCSharpRightAssociative() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text); // Act\ - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 13, text.Length, rightAssociative: true); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 13, text.Length, rightAssociative: true); // Assert Assert.Equal(RazorLanguageKind.Html, languageKind); @@ -1052,7 +1052,7 @@ public void GetLanguageKindCore_TagHelperInCSharpRightAssociative() var (classifiedSpans, tagHelperSpans) = GetClassifiedSpans(text, new[] { descriptor.Build() }); // Act\ - var languageKind = RazorDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 40, text.Length, rightAssociative: true); + var languageKind = LspDocumentMappingService.GetLanguageKindCore(classifiedSpans, tagHelperSpans, 40, text.Length, rightAssociative: true); // Assert Assert.Equal(RazorLanguageKind.Html, languageKind); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs index 086eb0e0d3d..0bcf1c28d4e 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs @@ -974,7 +974,7 @@ private async Task CreateServiceAsync( : It.Is(x => x.Tokens == null)); var documentContextFactory = new TestDocumentContextFactory(documentSnapshot); - var documentMappingService = new RazorDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, documentContextFactory, LoggerFactory); var configurationSyncService = new Mock(MockBehavior.Strict); @@ -1110,7 +1110,7 @@ private string GetBaselineFileContents(string baselineFileName) private ImmutableArray? GetMappedCSharpRanges(RazorCodeDocument codeDocument, LinePositionSpan razorRange, bool precise) { - var documentMappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); + var documentMappingService = new LspDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); if (precise) { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs index 33a2c247fd0..853c036a485 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.cs @@ -65,7 +65,7 @@ private protected async Task CreateLanguageServerAsync( options.HtmlVirtualDocumentSuffix == DefaultLanguageServerFeatureOptions.DefaultHtmlVirtualDocumentSuffix, MockBehavior.Strict); - DocumentMappingService = new RazorDocumentMappingService(FilePathService, DocumentContextFactory, LoggerFactory); + DocumentMappingService = new LspDocumentMappingService(FilePathService, DocumentContextFactory, LoggerFactory); EditMappingService = new EditMappingService(DocumentMappingService, FilePathService, DocumentContextFactory); var csharpServer = await CSharpTestLspServerHelpers.CreateCSharpLspServerAsync( From a550cbb536ba12b42c9a319ce2c373d366b9c9db Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 14:38:33 -0700 Subject: [PATCH 32/53] Remove remote DocumentContextFactory --- .../ProjectSystem/DocumentContextFactory.cs | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextFactory.cs diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextFactory.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextFactory.cs deleted file mode 100644 index a23e018bcd1..00000000000 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextFactory.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT license. See License.txt in the project root for license information. - -using System; -using System.Composition; -using System.Diagnostics.CodeAnalysis; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.VisualStudio.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; - -[Export(typeof(IDocumentContextFactory)), Shared] -internal class DocumentContextFactory : IDocumentContextFactory -{ - public bool TryCreate( - Uri documentUri, - VSProjectContext? projectContext, - bool versioned, - [NotNullWhen(true)] out DocumentContext? context) - { - throw new NotSupportedException("OOP doesn't support this yet, because we don't have a way to pass in the right solution snapshot to use"); - } -} From 655a88c40041e026f81d2100df55970dd569dc8e Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 16:13:58 -0700 Subject: [PATCH 33/53] Clean up RemoteDocumentSnapshot a bit --- .../DocumentState.ComputedStateTracker.cs | 2 +- .../ProjectSystem/DocumentState.cs | 4 +- .../IDocumentSnapshotExtensions.cs | 2 +- .../DocumentContextExtensions.cs | 49 ++++++------- .../ProjectSystem/RemoteDocumentSnapshot.cs | 62 +++++------------ .../ProjectSystem/RemoteProjectSnapshot.cs | 68 +++++++++++++------ 6 files changed, 89 insertions(+), 98 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs index 258f1d38b6b..a22e2c4d746 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs @@ -218,7 +218,7 @@ static void PropagateToTaskCompletionSource( var tagHelpers = await project.GetTagHelpersAsync(CancellationToken.None).ConfigureAwait(false); var forceRuntimeCodeGeneration = project.Configuration.LanguageServerFlags?.ForceRuntimeCodeGeneration ?? false; - var codeDocument = await GenerateCodeDocumentAsync(tagHelpers, project.GetProjectEngine(), document, imports, forceRuntimeCodeGeneration).ConfigureAwait(false); + var codeDocument = await GenerateCodeDocumentAsync(document, project.GetProjectEngine(), imports, tagHelpers, forceRuntimeCodeGeneration).ConfigureAwait(false); return (codeDocument, inputVersion); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs index 4055cd936f9..bfa1384c983 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs @@ -265,7 +265,7 @@ internal static ImmutableArray GetImportsCore(IProjectSnapsho return imports.ToImmutable(); } - internal static async Task GenerateCodeDocumentAsync(ImmutableArray tagHelpers, RazorProjectEngine projectEngine, IDocumentSnapshot document, ImmutableArray imports, bool forceRuntimeCodeGeneration) + internal static async Task GenerateCodeDocumentAsync(IDocumentSnapshot document, RazorProjectEngine projectEngine, ImmutableArray imports, ImmutableArray tagHelpers, bool forceRuntimeCodeGeneration) { // OK we have to generate the code. using var importSources = new PooledArrayBuilder(imports.Length); @@ -288,7 +288,7 @@ internal static async Task GenerateCodeDocumentAsync(Immutabl } internal static Task GenerateFormattingCodeDocumentAsync(ImmutableArray tagHelpers, RazorProjectEngine projectEngine, IDocumentSnapshot document, ImmutableArray imports) - => GenerateCodeDocumentAsync(tagHelpers, projectEngine, document, imports, forceRuntimeCodeGeneration: false); + => GenerateCodeDocumentAsync(document, projectEngine, imports, tagHelpers, forceRuntimeCodeGeneration: false); internal static async Task> GetImportsAsync(IDocumentSnapshot document, RazorProjectEngine projectEngine) { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs index 7e97774f9ed..ef8b26ca9e9 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs @@ -82,6 +82,6 @@ private static async Task GetDesignTimeDocumentAsync(IDocumen var tagHelpers = await project.GetTagHelpersAsync(CancellationToken.None).ConfigureAwait(false); var projectEngine = project.GetProjectEngine(); var imports = await DocumentState.GetImportsAsync(documentSnapshot, projectEngine).ConfigureAwait(false); - return await DocumentState.GenerateCodeDocumentAsync(tagHelpers, project.GetProjectEngine(), documentSnapshot, imports, false).ConfigureAwait(false); + return await DocumentState.GenerateCodeDocumentAsync(documentSnapshot, project.GetProjectEngine(), imports, tagHelpers, false).ConfigureAwait(false); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextExtensions.cs index 7ba739e1ba5..bd29cf52ab3 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/DocumentContextExtensions.cs @@ -14,44 +14,35 @@ namespace Microsoft.CodeAnalysis.Remote.Razor; internal static class DocumentContextExtensions { - public static async Task GetGeneratedDocumentAsync(this VersionedDocumentContext documentContext, IFilePathService filePathService, CancellationToken cancellationToken) + public static async Task GetGeneratedDocumentAsync( + this VersionedDocumentContext documentContext, + IFilePathService filePathService, + CancellationToken cancellationToken) { Debug.Assert(documentContext.Snapshot is RemoteDocumentSnapshot, "This method only works on document contexts created in the OOP process"); var snapshot = (RemoteDocumentSnapshot)documentContext.Snapshot; - if (snapshot.TryGetGeneratedDocument(out var generatedDocument)) - { - return generatedDocument; - } - - var razorDocument = snapshot.TextDocument; - var solution = razorDocument.Project.Solution; - - // TODO: A real implementation needs to get the SourceGeneratedDocument from the solution + return await snapshot.GetOrAddGeneratedDocumentAsync( + (snapshot, documentContext, filePathService, cancellationToken), + static async arg => + { + var (snapshot, documentContext, filePathService, cancellationToken) = arg; - var projectKey = razorDocument.Project.ToProjectKey(); - var generatedFilePath = filePathService.GetRazorCSharpFilePath(projectKey, razorDocument.FilePath.AssumeNotNull()); - var generatedDocumentId = solution.GetDocumentIdsWithFilePath(generatedFilePath).First(d => d.ProjectId == razorDocument.Project.Id); - generatedDocument = solution.GetRequiredDocument(generatedDocumentId); + var razorDocument = snapshot.TextDocument; + var projectKey = snapshot.Project.Key; + var solution = razorDocument.Project.Solution; - var csharpSourceText = await documentContext.GetCSharpSourceTextAsync(cancellationToken).ConfigureAwait(false); + // TODO: A real implementation needs to get the SourceGeneratedDocument from the solution - // HACK: We're not in the same solution fork as the LSP server that provides content for this document - generatedDocument = generatedDocument.WithText(csharpSourceText); + var generatedFilePath = filePathService.GetRazorCSharpFilePath(projectKey, razorDocument.FilePath.AssumeNotNull()); + var generatedDocumentId = solution.GetDocumentIdsWithFilePath(generatedFilePath).First(d => d.ProjectId == razorDocument.Project.Id); + var generatedDocument = solution.GetRequiredDocument(generatedDocumentId); - // Obviously this lock is not sufficient to avoid wasted work, but it does at least avoid mutating the snapshot - // any more than just a once of caching of the generated document, which is what is really happening with the set - // method call below. - lock (snapshot) - { - if (snapshot.TryGetGeneratedDocument(out var generatedDocument2)) - { - return generatedDocument2; - } + var csharpSourceText = await documentContext.GetCSharpSourceTextAsync(cancellationToken).ConfigureAwait(false); - snapshot.SetGeneratedDocument(generatedDocument); - return generatedDocument; - } + // HACK: We're not in the same solution fork as the LSP server that provides content for this document + return generatedDocument.WithText(csharpSourceText); + }); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs index 048058709b3..e7a2232c0a6 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. +using System; using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; @@ -13,12 +14,12 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; internal class RemoteDocumentSnapshot(TextDocument textDocument, RemoteProjectSnapshot projectSnapshot) : IDocumentSnapshot { - // TODO: Delete this field when the source generator is hooked up - private Document? _generatedDocument; - private readonly TextDocument _textDocument = textDocument; private readonly RemoteProjectSnapshot _projectSnapshot = projectSnapshot; + // TODO: Delete this field when the source generator is hooked up + private Document? _generatedDocument; + private RazorCodeDocument? _codeDocument; public TextDocument TextDocument => _textDocument; @@ -46,9 +47,9 @@ public async Task GetGeneratedOutputAsync() // TODO: We don't need to worry about locking if we get called from the didOpen/didChange LSP requests, as CLaSP // takes care of that for us, and blocks requests until those are complete. If that doesn't end up happening, // then a locking mechanism here would prevent concurrent compilations. - if (_codeDocument is not null) + if (TryGetGeneratedOutput(out var codeDocument)) { - return _codeDocument; + return codeDocument; } // The non-cohosted DocumentSnapshot implementation uses DocumentState to get the generated output, and we could do that too @@ -66,15 +67,11 @@ public async Task GetGeneratedOutputAsync() // TODO: Get the configuration for forceRuntimeCodeGeneration // var forceRuntimeCodeGeneration = _projectSnapshot.Configuration.LanguageServerFlags?.ForceRuntimeCodeGeneration ?? false; - _codeDocument = await DocumentState.GenerateCodeDocumentAsync(tagHelpers, projectEngine, this, imports, forceRuntimeCodeGeneration: false).ConfigureAwait(false); + codeDocument = await DocumentState + .GenerateCodeDocumentAsync(this, projectEngine, imports, tagHelpers, forceRuntimeCodeGeneration: false) + .ConfigureAwait(false); - return _codeDocument; - } - - public bool TryGetGeneratedOutput([NotNullWhen(true)] out RazorCodeDocument? result) - { - result = _codeDocument; - return result is not null; + return InterlockedOperations.Initialize(ref _codeDocument, codeDocument); } public IDocumentSnapshot WithText(SourceText text) @@ -85,43 +82,20 @@ public IDocumentSnapshot WithText(SourceText text) return new RemoteDocumentSnapshot(newDocument, _projectSnapshot); } - public bool TryGetGeneratedDocument([NotNullWhen(true)] out Document? generatedDocument) - { - // TODO: Delete this method when the source generator is hooked up - generatedDocument = _generatedDocument; - return _generatedDocument is not null; - } - - public void SetGeneratedDocument(Document generatedDocument) + public bool TryGetGeneratedOutput([NotNullWhen(true)] out RazorCodeDocument? result) { - if (_generatedDocument is not null) - { - ThrowHelper.ThrowInvalidOperationException("A single document snapshot can only ever possibly have a single generated document"); - } - - _generatedDocument = generatedDocument; + result = _codeDocument; + return result is not null; } - /// - /// Sets the generated C# document for this snapshot - /// - /// - /// You're right, dear reader, it's very strange for a seemingly immutable object to have a set method, but we can get away - /// with it here for some arguably tenuous reasons: - /// 1. The generated document is generated from this snapshot, and we're only allowing setting it because it could be - /// expensive to generate in the constructor. - /// 2. This is only temporary until the source generator is properly hooked up. - /// 3. If the Razor document changes, which would invalidate this generated document, then a new document snapshot would - /// be created and this instance would never be used again - /// - internal Document GetOrAddGeneratedDocument(Document generatedDocument) + public async Task GetOrAddGeneratedDocumentAsync(TArg arg, Func> createGeneratedDocument) { - // TODO: Delete this method when the source generator is hooked up - if (_generatedDocument is null) + if (_generatedDocument is Document generatedDocument) { - _generatedDocument = generatedDocument; + return generatedDocument; } - return generatedDocument; + generatedDocument = await createGeneratedDocument(arg); + return InterlockedOperations.Initialize(ref _generatedDocument, generatedDocument); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs index 2676dd1ab5f..cfd8e70171a 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs @@ -25,22 +25,23 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; internal class RemoteProjectSnapshot : IProjectSnapshot { + public ProjectKey Key { get; } + private readonly Project _project; private readonly DocumentSnapshotFactory _documentSnapshotFactory; private readonly ITelemetryReporter _telemetryReporter; - private readonly ProjectKey _projectKey; private readonly Lazy _lazyConfiguration; private readonly Lazy _lazyProjectEngine; private readonly Lazy>> _importsToRelatedDocumentsLazy; - private ImmutableArray? _tagHelpers; + private ImmutableArray _tagHelpers; public RemoteProjectSnapshot(Project project, DocumentSnapshotFactory documentSnapshotFactory, ITelemetryReporter telemetryReporter) { _project = project; _documentSnapshotFactory = documentSnapshotFactory; _telemetryReporter = telemetryReporter; - _projectKey = _project.ToProjectKey(); + Key = _project.ToProjectKey(); _lazyConfiguration = new Lazy(CreateRazorConfiguration); _lazyProjectEngine = new Lazy(() => @@ -59,24 +60,39 @@ public RemoteProjectSnapshot(Project project, DocumentSnapshotFactory documentSn _importsToRelatedDocumentsLazy = new Lazy>>(() => { var importsToRelatedDocuments = ImmutableDictionary.Create>(FilePathNormalizingComparer.Instance); - foreach (var document in DocumentFilePaths) + foreach (var documentFilePath in DocumentFilePaths) { - var importTargetPaths = ProjectState.GetImportDocumentTargetPaths(document, FileKinds.GetFileKindFromFilePath(document), _lazyProjectEngine.Value); - importsToRelatedDocuments = ProjectState.AddToImportsToRelatedDocuments(importsToRelatedDocuments, document, importTargetPaths); + var importTargetPaths = ProjectState.GetImportDocumentTargetPaths(documentFilePath, FileKinds.GetFileKindFromFilePath(documentFilePath), _lazyProjectEngine.Value); + importsToRelatedDocuments = ProjectState.AddToImportsToRelatedDocuments(importsToRelatedDocuments, documentFilePath, importTargetPaths); } return importsToRelatedDocuments; }); } - public ProjectKey Key => _projectKey; - public RazorConfiguration Configuration => throw new InvalidOperationException("Should not be called for cohosted projects."); public IEnumerable DocumentFilePaths - => _project.AdditionalDocuments - .Where(d => d.FilePath!.EndsWith(".razor", StringComparison.OrdinalIgnoreCase) || d.FilePath.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase)) - .Select(d => d.FilePath.AssumeNotNull()); + { + get + { + foreach (var additionalDocument in _project.AdditionalDocuments) + { + if (additionalDocument.FilePath is not string filePath) + { + continue; + } + + if (!filePath.EndsWith(".razor", StringComparison.OrdinalIgnoreCase) && + !filePath.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + yield return filePath; + } + } + } public string FilePath => _project.FilePath!; @@ -92,13 +108,23 @@ public IEnumerable DocumentFilePaths public async ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken) { - if (_tagHelpers is null) + if (_tagHelpers.IsDefault) { - var resolver = new CompilationTagHelperResolver(_telemetryReporter); - _tagHelpers = await resolver.GetTagHelpersAsync(_project, _lazyProjectEngine.Value, cancellationToken).ConfigureAwait(false); + var computedTagHelpers = await ComputeTagHelpersAsync(_project, _lazyProjectEngine.Value, _telemetryReporter, cancellationToken); + ImmutableInterlocked.InterlockedInitialize(ref _tagHelpers, computedTagHelpers); } - return _tagHelpers.GetValueOrDefault(); + return _tagHelpers; + + static ValueTask> ComputeTagHelpersAsync( + Project project, + RazorProjectEngine projectEngine, + ITelemetryReporter telemetryReporter, + CancellationToken cancellationToken) + { + var resolver = new CompilationTagHelperResolver(telemetryReporter); + return resolver.GetTagHelpersAsync(project, projectEngine, cancellationToken); + } } public ProjectWorkspaceState ProjectWorkspaceState => throw new InvalidOperationException("Should not be called for cohosted projects."); @@ -134,26 +160,26 @@ public ImmutableArray GetRelatedDocuments(IDocumentSnapshot d if (!_importsToRelatedDocumentsLazy.Value.TryGetValue(targetPath, out var relatedDocuments)) { - return ImmutableArray.Empty; + return []; } - using var _ = ArrayBuilderPool.GetPooledObject(out var builder); - builder.SetCapacityIfLarger(relatedDocuments.Length); + using var builder = new PooledArrayBuilder(relatedDocuments.Length); foreach (var relatedDocumentFilePath in relatedDocuments) { - if (GetDocument(relatedDocumentFilePath) is { } relatedDocument) + if (TryGetDocument(relatedDocumentFilePath, out var relatedDocument)) { builder.Add(relatedDocument); } } - return builder.ToImmutableArray(); + return builder.DrainToImmutable(); } public bool IsImportDocument(IDocumentSnapshot document) { - return document.TargetPath is { } targetPath && _importsToRelatedDocumentsLazy.Value.ContainsKey(targetPath); + return document.TargetPath is { } targetPath && + _importsToRelatedDocumentsLazy.Value.ContainsKey(targetPath); } private RazorConfiguration CreateRazorConfiguration() From 20dd630ed92fa63e6a557a806f665b5c63b32c62 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 16:16:14 -0700 Subject: [PATCH 34/53] Remove unused DocumentState method --- .../ProjectSystem/DocumentState.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs index bfa1384c983..859673968b2 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs @@ -287,9 +287,6 @@ internal static async Task GenerateCodeDocumentAsync(IDocumen return projectEngine.ProcessDesignTime(documentSource, fileKind: document.FileKind, importSources.DrainToImmutable(), tagHelpers); } - internal static Task GenerateFormattingCodeDocumentAsync(ImmutableArray tagHelpers, RazorProjectEngine projectEngine, IDocumentSnapshot document, ImmutableArray imports) - => GenerateCodeDocumentAsync(document, projectEngine, imports, tagHelpers, forceRuntimeCodeGeneration: false); - internal static async Task> GetImportsAsync(IDocumentSnapshot document, RazorProjectEngine projectEngine) { var imports = GetImportsCore(document.Project, projectEngine, document.FilePath.AssumeNotNull(), document.FileKind.AssumeNotNull()); From fc6aa07bc2f4b054707d769a4db5df70f87d5176 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 16:21:42 -0700 Subject: [PATCH 35/53] Fix small typo in comment --- .../RemoteWorkspaceAccessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteWorkspaceAccessor.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteWorkspaceAccessor.cs index f8e3087df91..8daf670d224 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteWorkspaceAccessor.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteWorkspaceAccessor.cs @@ -15,7 +15,7 @@ internal static class RemoteWorkspaceAccessor /// process that is explicitly denied via an exception. This method serves as a workaround when a workspace is /// needed (eg, the Go To Definition API requires one). /// - /// This should be used sparingly nad carefully, and no updates should be made to the workspace. + /// This should be used sparingly and carefully, and no updates should be made to the workspace. /// public static Workspace GetWorkspace() => RazorBrokeredServiceImplementation.GetWorkspace(); From 50a3d417da7756bd2ce0cb3483ce6b933bdf5d2b Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 17:01:49 -0700 Subject: [PATCH 36/53] Move MapToHostDocuementUriAndRangeAsync to extension methods This change also removes the `AbstractDocumentMappingService.TryGetCodeDocumentAsync(...)` method that was added in an an early commit. --- .../Definition/DefinitionEndpoint.cs | 4 +- .../IDocumentMappingServiceExtensions.cs | 55 ++++++++++++++++ .../LspDocumentMappingService.cs | 36 ++++++++++- .../AbstractDocumentMappingService.cs | 47 ++------------ .../IDocumentMappingService.cs | 10 --- .../IDocumentMappingServiceExtensions.cs | 12 ---- .../IDocumentMappingServiceExtensions.cs | 60 +++++++++++++++++ .../RemoteDocumentMappingService.cs | 64 ++++++++++++++++++- 8 files changed, 216 insertions(+), 72 deletions(-) create mode 100644 src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentMappingServiceExtensions.cs create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/IDocumentMappingServiceExtensions.cs diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs index f45eb05ed72..304c7729526 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs @@ -36,8 +36,8 @@ internal sealed class DefinitionEndpoint( ILoggerFactory loggerFactory) : AbstractRazorDelegatingEndpoint(languageServerFeatureOptions, documentMappingService, clientConnection, loggerFactory.GetOrCreateLogger()), ICapabilitiesProvider { - private readonly IRazorComponentSearchEngine _componentSearchEngine = componentSearchEngine ?? throw new ArgumentNullException(nameof(componentSearchEngine)); - private readonly IDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); + private readonly IRazorComponentSearchEngine _componentSearchEngine = componentSearchEngine; + private readonly IDocumentMappingService _documentMappingService = documentMappingService; protected override bool PreferCSharpOverHtmlIfPossible => true; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentMappingServiceExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentMappingServiceExtensions.cs new file mode 100644 index 00000000000..57a1d184ab4 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentMappingServiceExtensions.cs @@ -0,0 +1,55 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Razor.DocumentMapping; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.LanguageServer.Protocol; +using LspRange = Microsoft.VisualStudio.LanguageServer.Protocol.Range; + +namespace Microsoft.AspNetCore.Razor.LanguageServer; + +internal static class IDocumentMappingServiceExtensions +{ + /// + /// Maps a range in the specified generated document uri to a range in the Razor document that owns the + /// generated document. If the uri passed in is not for a generated document, or the range cannot be mapped + /// for some other reason, the original passed in range is returned unchanged. + /// + public static Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync( + this IDocumentMappingService service, + Uri generatedDocumentUri, + LinePositionSpan generatedDocumentRange, + CancellationToken cancellationToken) + { + if (service is LspDocumentMappingService lspService) + { + return lspService.MapToHostDocumentUriAndRangeAsync(generatedDocumentUri, generatedDocumentRange, cancellationToken); + } + + return Assumed.Unreachable>(); + } + + /// + /// Maps a range in the specified generated document uri to a range in the Razor document that owns the + /// generated document. If the uri passed in is not for a generated document, or the range cannot be mapped + /// for some other reason, the original passed in range is returned unchanged. + /// + public static async Task<(Uri MappedDocumentUri, LspRange MappedRange)> MapToHostDocumentUriAndRangeAsync( + this IDocumentMappingService service, + Uri generatedDocumentUri, + LspRange generatedDocumentRange, + CancellationToken cancellationToken) + { + var (mappedDocumentUri, mappedRange) = await service + .MapToHostDocumentUriAndRangeAsync( + generatedDocumentUri, + generatedDocumentRange.ToLinePositionSpan(), + cancellationToken) + .ConfigureAwait(false); + + return (mappedDocumentUri, mappedRange.ToRange()); + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LspDocumentMappingService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LspDocumentMappingService.cs index f8f568366c6..23df0beeb18 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LspDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LspDocumentMappingService.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; namespace Microsoft.AspNetCore.Razor.LanguageServer; @@ -20,13 +21,42 @@ internal sealed class LspDocumentMappingService( { private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory; - protected override async ValueTask TryGetCodeDocumentAsync(Uri razorDocumentUri, CancellationToken cancellationToken) + public async Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync( + Uri generatedDocumentUri, + LinePositionSpan generatedDocumentRange, + CancellationToken cancellationToken) { + var razorDocumentUri = FilePathService.GetRazorDocumentUri(generatedDocumentUri); + + // For Html we just map the Uri, the range will be the same + if (FilePathService.IsVirtualHtmlFile(generatedDocumentUri)) + { + return (razorDocumentUri, generatedDocumentRange); + } + + // We only map from C# files + if (!FilePathService.IsVirtualCSharpFile(generatedDocumentUri)) + { + return (generatedDocumentUri, generatedDocumentRange); + } + if (!_documentContextFactory.TryCreate(razorDocumentUri, out var documentContext)) { - return null; + return (generatedDocumentUri, generatedDocumentRange); + } + + var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + + if (!codeDocument.TryGetGeneratedDocument(generatedDocumentUri, FilePathService, out var generatedDocument)) + { + return Assumed.Unreachable<(Uri, LinePositionSpan)>(); + } + + if (TryMapToHostDocumentRange(generatedDocument, generatedDocumentRange, MappingBehavior.Strict, out var mappedRange)) + { + return (razorDocumentUri, mappedRange); } - return await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + return (generatedDocumentUri, generatedDocumentRange); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractDocumentMappingService.cs index 60fc096d910..60949687b5e 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractDocumentMappingService.cs @@ -6,8 +6,6 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; -using System.Threading; -using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Legacy; @@ -23,10 +21,8 @@ namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; internal abstract class AbstractDocumentMappingService(IFilePathService filePathService, ILogger logger) : IDocumentMappingService { - private readonly IFilePathService _filePathService = filePathService; - private readonly ILogger _logger = logger; - - protected abstract ValueTask TryGetCodeDocumentAsync(Uri razorDocumentUri, CancellationToken cancellationToken); + protected readonly IFilePathService FilePathService = filePathService; + protected readonly ILogger Logger = logger; public IEnumerable GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument, IEnumerable generatedDocumentChanges) { @@ -198,7 +194,7 @@ public bool TryMapToGeneratedDocumentRange(IRazorGeneratedDocument generatedDocu (hostDocumentRange.End.Line == hostDocumentRange.Start.Line && hostDocumentRange.End.Character < hostDocumentRange.Start.Character)) { - _logger.LogWarning($"RazorDocumentMappingService:TryMapToGeneratedDocumentRange original range end < start '{hostDocumentRange}'"); + Logger.LogWarning($"RazorDocumentMappingService:TryMapToGeneratedDocumentRange original range end < start '{hostDocumentRange}'"); Debug.Fail($"RazorDocumentMappingService:TryMapToGeneratedDocumentRange original range end < start '{hostDocumentRange}'"); return false; } @@ -355,41 +351,6 @@ public RazorLanguageKind GetLanguageKind(RazorCodeDocument codeDocument, int hos return languageKind; } - public async Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync(Uri generatedDocumentUri, LinePositionSpan generatedDocumentRange, CancellationToken cancellationToken) - { - var razorDocumentUri = _filePathService.GetRazorDocumentUri(generatedDocumentUri); - - // For Html we just map the Uri, the range will be the same - if (_filePathService.IsVirtualHtmlFile(generatedDocumentUri)) - { - return (razorDocumentUri, generatedDocumentRange); - } - - // We only map from C# files - if (!_filePathService.IsVirtualCSharpFile(generatedDocumentUri)) - { - return (generatedDocumentUri, generatedDocumentRange); - } - - var codeDocument = await TryGetCodeDocumentAsync(razorDocumentUri, cancellationToken).ConfigureAwait(false); - if (codeDocument is null) - { - return (generatedDocumentUri, generatedDocumentRange); - } - - if (!codeDocument.TryGetGeneratedDocument(generatedDocumentUri, _filePathService, out var generatedDocument)) - { - return Assumed.Unreachable<(Uri, LinePositionSpan)>(); - } - - if (TryMapToHostDocumentRange(generatedDocument, generatedDocumentRange, MappingBehavior.Strict, out var mappedRange)) - { - return (razorDocumentUri, mappedRange); - } - - return (generatedDocumentUri, generatedDocumentRange); - } - // Internal for testing internal static RazorLanguageKind GetLanguageKindCore( ImmutableArray classifiedSpans, @@ -695,7 +656,7 @@ private bool IsRangeWithinDocument(LinePositionSpan range, SourceText sourceText { s_haveAsserted = true; var sourceTextLinesCount = sourceText.Lines.Count; - _logger.LogWarning($"Attempted to map a range ({range.Start.Line},{range.Start.Character})-({range.End.Line},{range.End.Character}) outside of the Source (line count {sourceTextLinesCount}.) This could happen if the Roslyn and Razor LSP servers are not in sync."); + Logger.LogWarning($"Attempted to map a range ({range.Start.Line},{range.Start.Character})-({range.End.Line},{range.End.Character}) outside of the Source (line count {sourceTextLinesCount}.) This could happen if the Roslyn and Razor LSP servers are not in sync."); } return result; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingService.cs index 7df5479ed21..486a7e28a67 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingService.cs @@ -1,10 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Text; @@ -26,11 +23,4 @@ internal interface IDocumentMappingService bool TryMapToGeneratedDocumentOrNextCSharpPosition(IRazorGeneratedDocument generatedDocument, int hostDocumentIndex, out LinePosition generatedPosition, out int generatedIndex); RazorLanguageKind GetLanguageKind(RazorCodeDocument codeDocument, int hostDocumentIndex, bool rightAssociative); - - /// - /// Maps a range in the specified generated document uri to a range in the Razor document that owns the - /// generated document. If the uri passed in is not for a generated document, or the range cannot be mapped - /// for some other reason, the original passed in range is returned unchanged. - /// - Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync(Uri generatedDocumentUri, LinePositionSpan generatedDocumentRange, CancellationToken cancellationToken); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingServiceExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingServiceExtensions.cs index 1eeb671409e..f592d5e12ee 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingServiceExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingServiceExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; @@ -108,15 +107,4 @@ public static bool TryMapToGeneratedDocumentOrNextCSharpPosition(this IDocumentM generatedPosition = result ? generatedLinePosition.ToPosition() : null; return result; } - - /// - /// Maps a range in the specified generated document uri to a range in the Razor document that owns the - /// generated document. If the uri passed in is not for a generated document, or the range cannot be mapped - /// for some other reason, the original passed in range is returned unchanged. - /// - public static async Task<(Uri MappedDocumentUri, Range MappedRange)> MapToHostDocumentUriAndRangeAsync(this IDocumentMappingService service, Uri generatedDocumentUri, Range generatedDocumentRange, CancellationToken cancellationToken) - { - var result = await service.MapToHostDocumentUriAndRangeAsync(generatedDocumentUri, generatedDocumentRange.ToLinePositionSpan(), cancellationToken).ConfigureAwait(false); - return (result.MappedDocumentUri, result.MappedRange.ToRange()); - } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/IDocumentMappingServiceExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/IDocumentMappingServiceExtensions.cs new file mode 100644 index 00000000000..f51c649eb18 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/IDocumentMappingServiceExtensions.cs @@ -0,0 +1,60 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor; +using Microsoft.CodeAnalysis.Razor.DocumentMapping; +using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Text; +using Roslyn.LanguageServer.Protocol; +using RoslynRange = Roslyn.LanguageServer.Protocol.Range; + +namespace Microsoft.CodeAnalysis.Remote.Razor.DocumentMapping; + +internal static class IDocumentMappingServiceExtensions +{ + /// + /// Maps a range in the specified generated document uri to a range in the Razor document that owns the + /// generated document. If the uri passed in is not for a generated document, or the range cannot be mapped + /// for some other reason, the original passed in range is returned unchanged. + /// + public static Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync( + this IDocumentMappingService service, + RemoteDocumentSnapshot originSnapshot, + Uri generatedDocumentUri, + LinePositionSpan generatedDocumentRange, + CancellationToken cancellationToken) + { + if (service is RemoteDocumentMappingService remoteService) + { + return remoteService.MapToHostDocumentUriAndRangeAsync(originSnapshot, generatedDocumentUri, generatedDocumentRange, cancellationToken); + } + + return Assumed.Unreachable>(); + } + + /// + /// Maps a range in the specified generated document uri to a range in the Razor document that owns the + /// generated document. If the uri passed in is not for a generated document, or the range cannot be mapped + /// for some other reason, the original passed in range is returned unchanged. + /// + public static async Task<(Uri MappedDocumentUri, RoslynRange MappedRange)> MapToHostDocumentUriAndRangeAsync( + this IDocumentMappingService service, + RemoteDocumentSnapshot originSnapshot, + Uri generatedDocumentUri, + RoslynRange generatedDocumentRange, + CancellationToken cancellationToken) + { + var (mappedDocumentUri, mappedRange) = await service + .MapToHostDocumentUriAndRangeAsync( + originSnapshot, + generatedDocumentUri, + generatedDocumentRange.ToLinePositionSpan(), + cancellationToken) + .ConfigureAwait(false); + + return (mappedDocumentUri, mappedRange.ToRange()); + } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs index 768af10ce8f..c1782e6c205 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs @@ -5,10 +5,15 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; +using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Remote.Razor.DocumentMapping; @@ -16,11 +21,66 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.DocumentMapping; [method: ImportingConstructor] internal sealed class RemoteDocumentMappingService( IFilePathService filePathService, + IProjectCollectionResolver projectCollectionResolver, ILoggerFactory loggerFactory) : AbstractDocumentMappingService(filePathService, loggerFactory.GetOrCreateLogger()) { - protected override ValueTask TryGetCodeDocumentAsync(Uri razorDocumentUri, CancellationToken cancellationToken) + private readonly IProjectCollectionResolver _projectCollectionResolver = projectCollectionResolver; + + public async Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync( + RemoteDocumentSnapshot originSnapshot, + Uri generatedDocumentUri, + LinePositionSpan generatedDocumentRange, + CancellationToken cancellationToken) { - throw new NotImplementedException(); + var razorDocumentUri = FilePathService.GetRazorDocumentUri(generatedDocumentUri); + + // For Html we just map the Uri, the range will be the same + if (FilePathService.IsVirtualHtmlFile(generatedDocumentUri)) + { + return (razorDocumentUri, generatedDocumentRange); + } + + // We only map from C# files + if (!FilePathService.IsVirtualCSharpFile(generatedDocumentUri)) + { + return (generatedDocumentUri, generatedDocumentRange); + } + + var razorFilePath = razorDocumentUri.GetAbsoluteOrUNCPath(); + IDocumentSnapshot? razorDocumentSnapshot = null; + + foreach (var project in _projectCollectionResolver.EnumerateProjects(originSnapshot)) + { + if (project.TryGetDocument(razorFilePath, out razorDocumentSnapshot)) + { + break; + } + } + + if (razorDocumentSnapshot is not RemoteDocumentSnapshot targetDocumentSnapshot) + { + return (generatedDocumentUri, generatedDocumentRange); + } + + var codeDocument = await targetDocumentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false); + cancellationToken.ThrowIfCancellationRequested(); + + if (codeDocument is null) + { + return (generatedDocumentUri, generatedDocumentRange); + } + + if (!codeDocument.TryGetGeneratedDocument(generatedDocumentUri, FilePathService, out var generatedDocument)) + { + return Assumed.Unreachable<(Uri, LinePositionSpan)>(); + } + + if (TryMapToHostDocumentRange(generatedDocument, generatedDocumentRange, MappingBehavior.Strict, out var mappedRange)) + { + return (razorDocumentUri, mappedRange); + } + + return (generatedDocumentUri, generatedDocumentRange); } } From e4a6932dfc22507ecb6fea33f05eac515330c453 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 6 Aug 2024 17:25:17 -0700 Subject: [PATCH 37/53] Use Uri.LocalPath rather than GetAbsoluteOrUNCPath() --- .../DocumentMapping/RemoteDocumentMappingService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs index c1782e6c205..503a363f000 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -47,13 +46,14 @@ internal sealed class RemoteDocumentMappingService( return (generatedDocumentUri, generatedDocumentRange); } - var razorFilePath = razorDocumentUri.GetAbsoluteOrUNCPath(); + var razorFilePath = razorDocumentUri.LocalPath; IDocumentSnapshot? razorDocumentSnapshot = null; foreach (var project in _projectCollectionResolver.EnumerateProjects(originSnapshot)) { - if (project.TryGetDocument(razorFilePath, out razorDocumentSnapshot)) + if (project.TryGetDocument(razorFilePath, out var snapshot)) { + razorDocumentSnapshot = snapshot; break; } } From 358c2bfdc62dfd203fc97954aaa1aecb0ad61b43 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Wed, 7 Aug 2024 08:56:56 -0700 Subject: [PATCH 38/53] Add extension methods that convert URIs to Roslyn file paths --- .../Extensions/SolutionExtensions.cs | 10 ++++++++-- .../UriExtensions.cs | 8 ++++++++ .../DocumentMapping/RemoteDocumentMappingService.cs | 3 ++- .../UriPresentation/RemoteUriPresentationService.cs | 3 +-- .../LanguageServer/CSharpTestLspServerHelpers.cs | 5 ++--- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SolutionExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SolutionExtensions.cs index 537828f3a09..9aaf5b9a5c9 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SolutionExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SolutionExtensions.cs @@ -1,19 +1,25 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. +using System; +using System.Collections.Immutable; using Microsoft.AspNetCore.Razor; +using Microsoft.CodeAnalysis.Razor; namespace Microsoft.CodeAnalysis; internal static class SolutionExtensions { - internal static Project GetRequiredProject(this Solution solution, ProjectId projectId) + public static ImmutableArray GetDocumentIdsWithUri(this Solution solution, Uri uri) + => solution.GetDocumentIdsWithFilePath(uri.GetDocumentFilePath()); + + public static Project GetRequiredProject(this Solution solution, ProjectId projectId) { return solution.GetProject(projectId) ?? ThrowHelper.ThrowInvalidOperationException($"The projectId {projectId} did not exist in {solution}."); } - internal static Document GetRequiredDocument(this Solution solution, DocumentId documentId) + public static Document GetRequiredDocument(this Solution solution, DocumentId documentId) { return solution.GetDocument(documentId) ?? ThrowHelper.ThrowInvalidOperationException($"The document {documentId} did not exist in {solution.FilePath ?? "solution"}."); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/UriExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/UriExtensions.cs index c4e2063f81c..b1ae800478f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/UriExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/UriExtensions.cs @@ -4,11 +4,19 @@ using System; using System.Net; using Microsoft.AspNetCore.Razor.Utilities; +using Microsoft.CodeAnalysis.ExternalAccess.Razor; namespace Microsoft.CodeAnalysis.Razor; internal static class UriExtensions { + /// + /// Converts the specified into a file path that matches + /// a Roslyn . + /// + public static string GetDocumentFilePath(this Uri uri) + => RazorUri.GetDocumentFilePathFromUri(uri); + public static string GetAbsoluteOrUNCPath(this Uri uri) { if (uri is null) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs index 503a363f000..ab06e7ec518 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -46,7 +47,7 @@ internal sealed class RemoteDocumentMappingService( return (generatedDocumentUri, generatedDocumentRange); } - var razorFilePath = razorDocumentUri.LocalPath; + var razorFilePath = razorDocumentUri.GetDocumentFilePath(); IDocumentSnapshot? razorDocumentSnapshot = null; foreach (var project in _projectCollectionResolver.EnumerateProjects(originSnapshot)) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs index 92a20f8dd8f..23336fb656d 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs @@ -73,8 +73,7 @@ private async ValueTask GetPresentationAsync( var solution = context.TextDocument.Project.Solution; // Make sure we go through Roslyn to go from the Uri the client sent us, to one that it has a chance of finding in the solution - var uriToFind = RazorUri.GetDocumentFilePathFromUri(razorFileUri); - var ids = solution.GetDocumentIdsWithFilePath(uriToFind); + var ids = solution.GetDocumentIdsWithUri(razorFileUri); if (ids.Length == 0) { return Response.CallHtml; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/CSharpTestLspServerHelpers.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/CSharpTestLspServerHelpers.cs index ddae8ddf089..ecf351fe1e8 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/CSharpTestLspServerHelpers.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/CSharpTestLspServerHelpers.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Composition; @@ -150,9 +151,7 @@ private static AdhocWorkspace CreateCSharpTestWorkspace( var documentCount = 0; foreach (var (documentUri, csharpSourceText) in files) { - // File path logic here has to match https://github.com/dotnet/roslyn/blob/3db75baf44332efd490bc0d166983103552370a3/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs#L163 - // or the Roslyn side won't see the file in the project/solution - var documentFilePath = documentUri.IsFile ? documentUri.LocalPath : documentUri.AbsolutePath; + var documentFilePath = documentUri.GetDocumentFilePath(); var textAndVersion = TextAndVersion.Create(csharpSourceText, VersionStamp.Default, documentFilePath); foreach (var projectInfo in projectInfos) From a2c21cfac5466e4a0e82ec4b0a9b839991bc3970 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Wed, 7 Aug 2024 09:16:28 -0700 Subject: [PATCH 39/53] Find razor document correctly in RemoveDocumentMappingService --- .../RemoteDocumentMappingService.cs | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs index ab06e7ec518..a4b946fc645 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs @@ -3,14 +3,13 @@ using System; using System.Composition; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; @@ -21,11 +20,11 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.DocumentMapping; [method: ImportingConstructor] internal sealed class RemoteDocumentMappingService( IFilePathService filePathService, - IProjectCollectionResolver projectCollectionResolver, + DocumentSnapshotFactory documentSnapshotFactory, ILoggerFactory loggerFactory) : AbstractDocumentMappingService(filePathService, loggerFactory.GetOrCreateLogger()) { - private readonly IProjectCollectionResolver _projectCollectionResolver = projectCollectionResolver; + private readonly DocumentSnapshotFactory _documentSnapshotFactory = documentSnapshotFactory; public async Task<(Uri MappedDocumentUri, LinePositionSpan MappedRange)> MapToHostDocumentUriAndRangeAsync( RemoteDocumentSnapshot originSnapshot, @@ -47,32 +46,28 @@ internal sealed class RemoteDocumentMappingService( return (generatedDocumentUri, generatedDocumentRange); } - var razorFilePath = razorDocumentUri.GetDocumentFilePath(); - IDocumentSnapshot? razorDocumentSnapshot = null; + var solution = originSnapshot.TextDocument.Project.Solution; - foreach (var project in _projectCollectionResolver.EnumerateProjects(originSnapshot)) - { - if (project.TryGetDocument(razorFilePath, out var snapshot)) - { - razorDocumentSnapshot = snapshot; - break; - } - } + var razorDocumentId = solution.GetDocumentIdsWithUri(razorDocumentUri).FirstOrDefault(); - if (razorDocumentSnapshot is not RemoteDocumentSnapshot targetDocumentSnapshot) + // If we couldn't locate the .razor file, just return the generated file. + if (razorDocumentId is null || + solution.GetAdditionalDocument(razorDocumentId) is not TextDocument razorDocument) { return (generatedDocumentUri, generatedDocumentRange); } - var codeDocument = await targetDocumentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false); + var razorDocumentSnapshot = _documentSnapshotFactory.GetOrCreate(razorDocument); + + var razorCodeDocument = await razorDocumentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); - if (codeDocument is null) + if (razorCodeDocument is null) { return (generatedDocumentUri, generatedDocumentRange); } - if (!codeDocument.TryGetGeneratedDocument(generatedDocumentUri, FilePathService, out var generatedDocument)) + if (!razorCodeDocument.TryGetGeneratedDocument(generatedDocumentUri, FilePathService, out var generatedDocument)) { return Assumed.Unreachable<(Uri, LinePositionSpan)>(); } From 2c0e2528aef183a51967b3e8b4872ee69cf76986 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Thu, 8 Aug 2024 17:03:26 +1000 Subject: [PATCH 40/53] Remove unnecessary parameter, because it can be trivially retrieved --- .../DocumentMapping/IDocumentMappingServiceExtensions.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingServiceExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingServiceExtensions.cs index f592d5e12ee..ce8bf2f4218 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingServiceExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IDocumentMappingServiceExtensions.cs @@ -36,17 +36,16 @@ public static bool TryMapToHostDocumentRange(this IDocumentMappingService servic public static async Task GetPositionInfoAsync(this IDocumentMappingService service, DocumentContext documentContext, int hostDocumentIndex, CancellationToken cancellationToken) { var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var sourceText = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - return service.GetPositionInfo(codeDocument, sourceText, hostDocumentIndex); + return service.GetPositionInfo(codeDocument, hostDocumentIndex); } public static DocumentPositionInfo GetPositionInfo( this IDocumentMappingService service, RazorCodeDocument codeDocument, - SourceText sourceText, int hostDocumentIndex) { + var sourceText = codeDocument.Source.Text; var position = sourceText.GetPosition(hostDocumentIndex); var languageKind = service.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: false); From 00e584a722ceefae985c41db4f75a3d860dbdbc3 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Thu, 8 Aug 2024 21:15:00 +1000 Subject: [PATCH 41/53] Don't pass code document and source text around in diagnostics translator, plus some cleanup --- .../RazorTranslateDiagnosticsService.cs | 68 +++++++++---------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs index 343c772cdec..f93731a0c75 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs @@ -36,12 +36,11 @@ internal class RazorTranslateDiagnosticsService(IDocumentMappingService document private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); private readonly IDocumentMappingService _documentMappingService = documentMappingService; - // Internal for testing - internal static readonly IReadOnlyCollection CSharpDiagnosticsToIgnore = new HashSet() - { + private static readonly HashSet s_cSharpDiagnosticsToIgnore = + [ "RemoveUnnecessaryImportsFixable", "IDE0005_gen", // Using directive is unnecessary - }; + ]; /// /// Translates code diagnostics from one representation into another. @@ -64,11 +63,9 @@ internal async Task TranslateAsync( return []; } - var sourceText = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - var filteredDiagnostics = diagnosticKind == RazorLanguageKind.CSharp - ? FilterCSharpDiagnostics(diagnostics, codeDocument, sourceText) - : FilterHTMLDiagnostics(diagnostics, codeDocument, sourceText); + ? FilterCSharpDiagnostics(diagnostics, codeDocument) + : FilterHTMLDiagnostics(diagnostics, codeDocument); if (filteredDiagnostics.Length == 0) { _logger.LogDebug($"No diagnostics remaining after filtering."); @@ -81,24 +78,23 @@ internal async Task TranslateAsync( diagnosticKind, filteredDiagnostics, documentContext.Snapshot, - codeDocument, - sourceText); + codeDocument); return mappedDiagnostics; } - private Diagnostic[] FilterCSharpDiagnostics(Diagnostic[] unmappedDiagnostics, RazorCodeDocument codeDocument, SourceText sourceText) + private Diagnostic[] FilterCSharpDiagnostics(Diagnostic[] unmappedDiagnostics, RazorCodeDocument codeDocument) { return unmappedDiagnostics.Where(d => - !ShouldFilterCSharpDiagnosticBasedOnErrorCode(d, codeDocument, sourceText)).ToArray(); + !ShouldFilterCSharpDiagnosticBasedOnErrorCode(d, codeDocument)).ToArray(); } private static Diagnostic[] FilterHTMLDiagnostics( Diagnostic[] unmappedDiagnostics, - RazorCodeDocument codeDocument, - SourceText sourceText) + RazorCodeDocument codeDocument) { var syntaxTree = codeDocument.GetSyntaxTree(); + var sourceText = codeDocument.Source.Text; var processedAttributes = new Dictionary(); @@ -115,22 +111,19 @@ private static Diagnostic[] FilterHTMLDiagnostics( private Diagnostic[] MapDiagnostics( RazorLanguageKind languageKind, - IReadOnlyList diagnostics, + Diagnostic[] diagnostics, IDocumentSnapshot documentSnapshot, - RazorCodeDocument codeDocument, - SourceText sourceText) + RazorCodeDocument codeDocument) { var projects = RazorDiagnosticConverter.GetProjectInformation(documentSnapshot); using var mappedDiagnostics = new PooledArrayBuilder(); - for (var i = 0; i < diagnostics.Count; i++) + foreach (var diagnostic in diagnostics) { - var diagnostic = diagnostics[i]; - // C# requests don't map directly to where they are in the document. if (languageKind == RazorLanguageKind.CSharp) { - if (!TryGetOriginalDiagnosticRange(diagnostic, codeDocument, sourceText, out var originalRange)) + if (!TryGetOriginalDiagnosticRange(diagnostic, codeDocument, out var originalRange)) { continue; } @@ -253,7 +246,8 @@ static bool IsCSharpInStyleBlock(Diagnostic diagnostic, SourceText sourceText, R var element = owner.FirstAncestorOrSelf(static n => n.StartTag?.Name.Content == "style"); var csharp = owner.FirstAncestorOrSelf(); - return element?.Body.Any(static c => c is CSharpCodeBlockSyntax) ?? false || csharp is not null; + return csharp is not null || + (element?.Body.Any(static c => c is CSharpCodeBlockSyntax) ?? false); } // Ideally this would be solved instead by not emitting the "!" at the HTML backing file, @@ -405,26 +399,26 @@ n is GenericBlockSyntax || } } - private bool ShouldFilterCSharpDiagnosticBasedOnErrorCode(Diagnostic diagnostic, RazorCodeDocument codeDocument, SourceText sourceText) + private bool ShouldFilterCSharpDiagnosticBasedOnErrorCode(Diagnostic diagnostic, RazorCodeDocument codeDocument) { - if (!diagnostic.Code.HasValue) + if (diagnostic.Code is not { } code || + !code.TryGetSecond(out var str) || + str is null) { return false; } - diagnostic.Code.Value.TryGetSecond(out var str); - return str switch { - "CS1525" => ShouldIgnoreCS1525(diagnostic, codeDocument, sourceText), - _ => CSharpDiagnosticsToIgnore.Contains(str) && - diagnostic.Severity != DiagnosticSeverity.Error, + "CS1525" => ShouldIgnoreCS1525(diagnostic, codeDocument), + _ => s_cSharpDiagnosticsToIgnore.Contains(str) && + diagnostic.Severity != DiagnosticSeverity.Error }; - bool ShouldIgnoreCS1525(Diagnostic diagnostic, RazorCodeDocument codeDocument, SourceText sourceText) + bool ShouldIgnoreCS1525(Diagnostic diagnostic, RazorCodeDocument codeDocument) { if (CheckIfDocumentHasRazorDiagnostic(codeDocument, RazorDiagnosticFactory.TagHelper_EmptyBoundAttribute.Id) && - TryGetOriginalDiagnosticRange(diagnostic, codeDocument, sourceText, out var originalRange) && + TryGetOriginalDiagnosticRange(diagnostic, codeDocument, out var originalRange) && originalRange.IsUndefined()) { // Empty attribute values will take the following form in the generated C# document: @@ -440,17 +434,16 @@ bool ShouldIgnoreCS1525(Diagnostic diagnostic, RazorCodeDocument codeDocument, S } } - // Internal & virtual for testing - internal virtual bool CheckIfDocumentHasRazorDiagnostic(RazorCodeDocument codeDocument, string razorDiagnosticCode) + private static bool CheckIfDocumentHasRazorDiagnostic(RazorCodeDocument codeDocument, string razorDiagnosticCode) { return codeDocument.GetSyntaxTree().Diagnostics.Any(d => d.Id.Equals(razorDiagnosticCode, StringComparison.Ordinal)); } - private bool TryGetOriginalDiagnosticRange(Diagnostic diagnostic, RazorCodeDocument codeDocument, SourceText sourceText, [NotNullWhen(true)] out Range? originalRange) + private bool TryGetOriginalDiagnosticRange(Diagnostic diagnostic, RazorCodeDocument codeDocument, [NotNullWhen(true)] out Range? originalRange) { if (IsRudeEditDiagnostic(diagnostic)) { - if (TryRemapRudeEditRange(diagnostic.Range, codeDocument, sourceText, out originalRange)) + if (TryRemapRudeEditRange(diagnostic.Range, codeDocument, out originalRange)) { return true; } @@ -487,14 +480,15 @@ private static bool IsRudeEditDiagnostic(Diagnostic diagnostic) str.StartsWith("ENC"); } - private bool TryRemapRudeEditRange(Range diagnosticRange, RazorCodeDocument codeDocument, SourceText sourceText, [NotNullWhen(true)] out Range? remappedRange) + private bool TryRemapRudeEditRange(Range diagnosticRange, RazorCodeDocument codeDocument, [NotNullWhen(true)] out Range? remappedRange) { // This is a rude edit diagnostic that has already been mapped to the Razor document. The mapping isn't absolutely correct though, // it's based on the runtime code generation of the Razor document therefore we need to re-map the already mapped diagnostic in a // semi-intelligent way. var syntaxTree = codeDocument.GetSyntaxTree(); - var span = codeDocument.Source.Text.GetTextSpan(diagnosticRange); + var sourceText = codeDocument.Source.Text; + var span = sourceText.GetTextSpan(diagnosticRange); var owner = syntaxTree.Root.FindNode(span, getInnermostNodeForTie: true); switch (owner?.Kind) From 53ec3abbf2f56e246cc2e445639d89dc69bb0db8 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Thu, 8 Aug 2024 09:44:38 -0700 Subject: [PATCH 42/53] Merge TagHelperDescriptorProviderContext and DefaultContext --- .../TagHelperDescriptorProviderContext.cs | 46 +++++-------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs index d89fde61427..f759c203f04 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs @@ -1,49 +1,27 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - -using System; using System.Collections.Generic; namespace Microsoft.AspNetCore.Razor.Language; -public abstract class TagHelperDescriptorProviderContext +public sealed class TagHelperDescriptorProviderContext { - public virtual bool ExcludeHidden { get; set; } - - public virtual bool IncludeDocumentation { get; set; } + public bool ExcludeHidden { get; set; } + public bool IncludeDocumentation { get; set; } - public abstract ItemCollection Items { get; } + public ItemCollection Items { get; } + public ICollection Results { get; } - public abstract ICollection Results { get; } - - public static TagHelperDescriptorProviderContext Create() + private TagHelperDescriptorProviderContext(ICollection results) { - return new DefaultContext(new List()); + Results = results; + Items = []; } - public static TagHelperDescriptorProviderContext Create(ICollection results) - { - if (results == null) - { - throw new ArgumentNullException(nameof(results)); - } - - return new DefaultContext(results); - } - - private class DefaultContext : TagHelperDescriptorProviderContext - { - public DefaultContext(ICollection results) - { - Results = results; - - Items = new ItemCollection(); - } - - public override ItemCollection Items { get; } + public static TagHelperDescriptorProviderContext Create() + => new([]); - public override ICollection Results { get; } - } + public static TagHelperDescriptorProviderContext Create(ICollection results) + => new(results); } From adff92a959b6aee144c98dc9646d0f010ede43a2 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Thu, 8 Aug 2024 09:47:38 -0700 Subject: [PATCH 43/53] Make Compilation a TagHelperDescriptorProviderContext property Every single `TagHelperDescriptorProviderContext` created in Razor compiler or tooling code adds a valid compilation. So, adding the compilation to the `ItemsCollection` is pure overhead and no `ITagHelperDescriptorProvider` needs to check it for null. I removed a single test that verified the behavior if a compilation was never set. Now that a compilation is required, this test is no longer needed. --- ...omponentTagHelperDescriptorProviderTest.cs | 4 +- ...omponentTagHelperDescriptorProviderTest.cs | 4 +- ...omponentTagHelperDescriptorProviderTest.cs | 4 +- .../CSharp/BindTagHelperDescriptorProvider.cs | 6 +- .../src/CSharp/CompilationTagHelperFeature.cs | 10 +- .../ComponentTagHelperDescriptorProvider.cs | 9 +- .../DefaultTagHelperDescriptorProvider.cs | 7 +- ...EventHandlerTagHelperDescriptorProvider.cs | 6 +- .../FormNameTagHelperDescriptorProvider.cs | 6 +- .../CSharp/KeyTagHelperDescriptorProvider.cs | 6 +- .../CSharp/RefTagHelperDescriptorProvider.cs | 6 +- .../RenderModeTagHelperDescriptorProvider.cs | 6 +- .../SplatTagHelperDescriptorProvider.cs | 6 +- ...lperDescriptorProviderContextExtensions.cs | 32 ------ .../TagHelperDescriptorProviderContext.cs | 14 ++- ...iewComponentTagHelperDescriptorProvider.cs | 8 +- ...iewComponentTagHelperDescriptorProvider.cs | 8 +- ...iewComponentTagHelperDescriptorProvider.cs | 8 +- .../StaticCompilationTagHelperFeature.cs | 3 +- .../BindTagHelperDescriptorProviderTest.cs | 47 +++----- .../test/CompilationTagHelperFeatureTest.cs | 13 +-- ...omponentTagHelperDescriptorProviderTest.cs | 106 +++++------------- .../DefaultTagHelperDescriptorProviderTest.cs | 26 +---- ...tHandlerTagHelperDescriptorProviderTest.cs | 4 +- .../KeyTagHelperDescriptorProviderTest.cs | 4 +- .../RefTagHelperDescriptorProviderTest.cs | 4 +- .../SplatTagHelperDescriptorProviderTest.cs | 4 +- .../CompilationTagHelperResolver.cs | 16 +-- 28 files changed, 90 insertions(+), 287 deletions(-) delete mode 100644 src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/TagHelperDescriptorProviderContextExtensions.cs diff --git a/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/ViewComponentTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/ViewComponentTagHelperDescriptorProviderTest.cs index 6374829f5eb..ab563dda4ce 100644 --- a/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/ViewComponentTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/ViewComponentTagHelperDescriptorProviderTest.cs @@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Razor; using Xunit; using static Microsoft.AspNetCore.Razor.Language.CommonMetadata; @@ -28,8 +27,7 @@ public class StringParameterViewComponent var compilation = MvcShim.BaseCompilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(code)); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ViewComponentTagHelperDescriptorProvider() { diff --git a/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/ViewComponentTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/ViewComponentTagHelperDescriptorProviderTest.cs index 228dbee93cb..8192f48af6d 100644 --- a/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/ViewComponentTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/ViewComponentTagHelperDescriptorProviderTest.cs @@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Razor; using Xunit; using static Microsoft.AspNetCore.Razor.Language.CommonMetadata; @@ -28,8 +27,7 @@ public class StringParameterViewComponent var compilation = MvcShim.BaseCompilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(code)); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ViewComponentTagHelperDescriptorProvider() { diff --git a/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ViewComponentTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ViewComponentTagHelperDescriptorProviderTest.cs index 11de487c208..68961a39485 100644 --- a/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ViewComponentTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ViewComponentTagHelperDescriptorProviderTest.cs @@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Razor; using Xunit; using static Microsoft.AspNetCore.Razor.Language.CommonMetadata; @@ -28,8 +27,7 @@ public class StringParameterViewComponent var compilation = MvcShim.BaseCompilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(code)); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ViewComponentTagHelperDescriptorProvider() { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs index d806c859e57..ba7f1436257 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs @@ -91,11 +91,7 @@ public void Execute(TagHelperDescriptorProviderContext context) // we have. Case #4 is data-driven based on component definitions. // // We provide a good set of attributes that map to the HTML dom. This set is user extensible. - var compilation = context.GetCompilation(); - if (compilation == null) - { - return; - } + var compilation = context.Compilation; var bindMethods = compilation.GetTypeByMetadataName(ComponentsApi.BindConverter.FullTypeName); if (bindMethods == null) diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/CompilationTagHelperFeature.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/CompilationTagHelperFeature.cs index 09ca7e652ef..af9a69e4160 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/CompilationTagHelperFeature.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/CompilationTagHelperFeature.cs @@ -17,15 +17,15 @@ public sealed class CompilationTagHelperFeature : RazorEngineFeatureBase, ITagHe public IReadOnlyList GetDescriptors() { - var results = new List(); - - var context = TagHelperDescriptorProviderContext.Create(results); var compilation = CSharpCompilation.Create("__TagHelpers", references: _referenceFeature.References); - if (IsValidCompilation(compilation)) + if (!IsValidCompilation(compilation)) { - context.SetCompilation(compilation); + return []; } + var results = new List(); + var context = TagHelperDescriptorProviderContext.Create(compilation, results); + for (var i = 0; i < _providers.Length; i++) { _providers[i].Execute(context); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/ComponentTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/ComponentTagHelperDescriptorProvider.cs index 55c244c0500..15315e2bf0c 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/ComponentTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/ComponentTagHelperDescriptorProvider.cs @@ -10,7 +10,6 @@ using System.Linq; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; -using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.PooledObjects; using static Microsoft.AspNetCore.Razor.Language.CommonMetadata; @@ -34,13 +33,7 @@ public void Execute(TagHelperDescriptorProviderContext context) throw new ArgumentNullException(nameof(context)); } - var compilation = context.GetCompilation(); - if (compilation == null) - { - // No compilation, nothing to do. - return; - } - + var compilation = context.Compilation; var targetSymbol = context.Items.GetTargetSymbol(); var collector = new Collector(compilation, targetSymbol); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/DefaultTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/DefaultTagHelperDescriptorProvider.cs index a7f69392c35..b97810e3a92 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/DefaultTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/DefaultTagHelperDescriptorProvider.cs @@ -21,12 +21,7 @@ public void Execute(TagHelperDescriptorProviderContext context) throw new ArgumentNullException(nameof(context)); } - var compilation = context.GetCompilation(); - if (compilation == null) - { - // No compilation, nothing to do. - return; - } + var compilation = context.Compilation; var tagHelperTypeSymbol = compilation.GetTypeByMetadataName(TagHelperTypes.ITagHelper); if (tagHelperTypeSymbol == null || tagHelperTypeSymbol.TypeKind == TypeKind.Error) diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/EventHandlerTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/EventHandlerTagHelperDescriptorProvider.cs index 058f6485b3e..e49f629ffe7 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/EventHandlerTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/EventHandlerTagHelperDescriptorProvider.cs @@ -25,11 +25,7 @@ public void Execute(TagHelperDescriptorProviderContext context) throw new ArgumentNullException(nameof(context)); } - var compilation = context.GetCompilation(); - if (compilation == null) - { - return; - } + var compilation = context.Compilation; if (compilation.GetTypeByMetadataName(ComponentsApi.EventHandlerAttribute.FullTypeName) is not INamedTypeSymbol eventHandlerAttribute) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/FormNameTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/FormNameTagHelperDescriptorProvider.cs index 030030882eb..fe834bd4db2 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/FormNameTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/FormNameTagHelperDescriptorProvider.cs @@ -25,11 +25,7 @@ public void Execute(TagHelperDescriptorProviderContext context) throw new ArgumentNullException(nameof(context)); } - var compilation = context.GetCompilation(); - if (compilation == null) - { - return; - } + var compilation = context.Compilation; var renderTreeBuilders = compilation.GetTypesByMetadataName(ComponentsApi.RenderTreeBuilder.FullTypeName) .Where(static t => t.DeclaredAccessibility == Accessibility.Public && diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/KeyTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/KeyTagHelperDescriptorProvider.cs index 22a999350e1..2a12fbb0087 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/KeyTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/KeyTagHelperDescriptorProvider.cs @@ -26,11 +26,7 @@ public void Execute(TagHelperDescriptorProviderContext context) throw new ArgumentNullException(nameof(context)); } - var compilation = context.GetCompilation(); - if (compilation == null) - { - return; - } + var compilation = context.Compilation; var renderTreeBuilderType = compilation.GetTypeByMetadataName(ComponentsApi.RenderTreeBuilder.FullTypeName); if (renderTreeBuilderType == null) diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RefTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RefTagHelperDescriptorProvider.cs index 7ade45235d5..dc2014716bf 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RefTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RefTagHelperDescriptorProvider.cs @@ -26,11 +26,7 @@ public void Execute(TagHelperDescriptorProviderContext context) throw new ArgumentNullException(nameof(context)); } - var compilation = context.GetCompilation(); - if (compilation == null) - { - return; - } + var compilation = context.Compilation; var elementReference = compilation.GetTypeByMetadataName(ComponentsApi.ElementReference.FullTypeName); if (elementReference == null) diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RenderModeTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RenderModeTagHelperDescriptorProvider.cs index 81d214463e7..16d38f9df6a 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RenderModeTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RenderModeTagHelperDescriptorProvider.cs @@ -26,11 +26,7 @@ public void Execute(TagHelperDescriptorProviderContext context) throw new ArgumentNullException(nameof(context)); } - var compilation = context.GetCompilation(); - if (compilation == null) - { - return; - } + var compilation = context.Compilation; var iComponentRenderMode = compilation.GetTypeByMetadataName(ComponentsApi.IComponentRenderMode.FullTypeName); if (iComponentRenderMode == null) diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SplatTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SplatTagHelperDescriptorProvider.cs index e1d44045aa0..796fc145acb 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SplatTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SplatTagHelperDescriptorProvider.cs @@ -26,11 +26,7 @@ public void Execute(TagHelperDescriptorProviderContext context) throw new ArgumentNullException(nameof(context)); } - var compilation = context.GetCompilation(); - if (compilation == null) - { - return; - } + var compilation = context.Compilation; var renderTreeBuilder = compilation.GetTypeByMetadataName(ComponentsApi.RenderTreeBuilder.FullTypeName); if (renderTreeBuilder == null) diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/TagHelperDescriptorProviderContextExtensions.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/TagHelperDescriptorProviderContextExtensions.cs deleted file mode 100644 index 23273e15454..00000000000 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/TagHelperDescriptorProviderContextExtensions.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#nullable disable - -using System; -using Microsoft.AspNetCore.Razor.Language; - -namespace Microsoft.CodeAnalysis.Razor; - -public static class TagHelperDescriptorProviderContextExtensions -{ - public static Compilation GetCompilation(this TagHelperDescriptorProviderContext context) - { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - return (Compilation)context.Items[typeof(Compilation)]; - } - - public static void SetCompilation(this TagHelperDescriptorProviderContext context, Compilation compilation) - { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - context.Items[typeof(Compilation)] = compilation; - } -} diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs index f759c203f04..5625641a296 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs @@ -2,26 +2,30 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using Microsoft.CodeAnalysis; namespace Microsoft.AspNetCore.Razor.Language; public sealed class TagHelperDescriptorProviderContext { + public Compilation Compilation { get; } + public bool ExcludeHidden { get; set; } public bool IncludeDocumentation { get; set; } public ItemCollection Items { get; } public ICollection Results { get; } - private TagHelperDescriptorProviderContext(ICollection results) + private TagHelperDescriptorProviderContext(Compilation compilation, ICollection results) { + Compilation = compilation; Results = results; Items = []; } - public static TagHelperDescriptorProviderContext Create() - => new([]); + public static TagHelperDescriptorProviderContext Create(Compilation compilation) + => new(compilation, results: []); - public static TagHelperDescriptorProviderContext Create(ICollection results) - => new(results); + public static TagHelperDescriptorProviderContext Create(Compilation compilation, ICollection results) + => new(compilation, results); } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version1_X/ViewComponentTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version1_X/ViewComponentTagHelperDescriptorProvider.cs index f53efafa6e8..70ed5efa619 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version1_X/ViewComponentTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version1_X/ViewComponentTagHelperDescriptorProvider.cs @@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Razor; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X; @@ -23,12 +22,7 @@ public void Execute(TagHelperDescriptorProviderContext context) throw new ArgumentNullException(nameof(context)); } - var compilation = context.GetCompilation(); - if (compilation == null) - { - // No compilation, nothing to do. - return; - } + var compilation = context.Compilation; var vcAttribute = compilation.GetTypeByMetadataName(ViewComponentTypes.ViewComponentAttribute); var nonVCAttribute = compilation.GetTypeByMetadataName(ViewComponentTypes.NonViewComponentAttribute); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version2_X/ViewComponentTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version2_X/ViewComponentTagHelperDescriptorProvider.cs index 1b699e6aa40..a3c6c11d5d9 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version2_X/ViewComponentTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version2_X/ViewComponentTagHelperDescriptorProvider.cs @@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Razor; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X; @@ -23,12 +22,7 @@ public void Execute(TagHelperDescriptorProviderContext context) throw new ArgumentNullException(nameof(context)); } - var compilation = context.GetCompilation(); - if (compilation == null) - { - // No compilation, nothing to do. - return; - } + var compilation = context.Compilation; var vcAttribute = compilation.GetTypeByMetadataName(ViewComponentTypes.ViewComponentAttribute); var nonVCAttribute = compilation.GetTypeByMetadataName(ViewComponentTypes.NonViewComponentAttribute); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc/ViewComponentTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc/ViewComponentTagHelperDescriptorProvider.cs index ead9211e953..178508686ac 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc/ViewComponentTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc/ViewComponentTagHelperDescriptorProvider.cs @@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Razor; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions; @@ -23,12 +22,7 @@ public void Execute(TagHelperDescriptorProviderContext context) throw new ArgumentNullException(nameof(context)); } - var compilation = context.GetCompilation(); - if (compilation == null) - { - // No compilation, nothing to do. - return; - } + var compilation = context.Compilation; var vcAttribute = compilation.GetTypeByMetadataName(ViewComponentTypes.ViewComponentAttribute); var nonVCAttribute = compilation.GetTypeByMetadataName(ViewComponentTypes.NonViewComponentAttribute); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs index 15f35d54f51..0efcc84523b 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs @@ -22,8 +22,7 @@ public void CollectDescriptors(ISymbol? targetSymbol, List return; } - var context = TagHelperDescriptorProviderContext.Create(results); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation, results); if (targetSymbol is not null) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs index 35fc97d894f..718c0128b2c 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs @@ -5,7 +5,6 @@ using System; using System.Linq; -using System.Threading; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; using Xunit; @@ -49,8 +48,7 @@ public Task SetParametersAsync(ParameterView parameters) Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation); // We run after component discovery and depend on the results. var componentProvider = new ComponentTagHelperDescriptorProvider(); @@ -184,8 +182,7 @@ public void Execute_BindTagHelperReturnsValuesWhenProvidedNoTargetSymbol() Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation); var bindTagHelperProvider = new BindTagHelperDescriptorProvider(); @@ -209,8 +206,7 @@ public void Execute_BindTagHelperReturnsValuesWhenProvidedCorrectAssemblyTargetS Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation); var bindConverterSymbol = compilation.GetTypeByMetadataName(ComponentsApi.BindConverter.FullTypeName); context.Items.SetTargetSymbol(bindConverterSymbol.ContainingAssembly); @@ -237,8 +233,7 @@ public void Execute_BindTagHelperReturnsEmptyWhenCompilationAssemblyTargetSymbol Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation); context.Items.SetTargetSymbol(compilation.Assembly); var bindTagHelperProvider = new BindTagHelperDescriptorProvider(); @@ -281,8 +276,7 @@ public Task SetParametersAsync(ParameterView parameters) Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation); // We run after component discovery and depend on the results. var componentProvider = new ComponentTagHelperDescriptorProvider(); @@ -432,8 +426,7 @@ public Task SetParametersAsync(ParameterView parameters) Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation); // We run after component discovery and depend on the results. var componentProvider = new ComponentTagHelperDescriptorProvider(); @@ -468,9 +461,7 @@ public class BindAttributes Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new BindTagHelperDescriptorProvider(); // Act @@ -729,9 +720,7 @@ public class BindAttributes Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new BindTagHelperDescriptorProvider(); // Act @@ -814,9 +803,7 @@ public class BindAttributes Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new BindTagHelperDescriptorProvider(); // Act @@ -890,9 +877,7 @@ public class BindAttributes Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new BindTagHelperDescriptorProvider(); // Act @@ -987,9 +972,7 @@ public class BindAttributes Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new BindTagHelperDescriptorProvider(); // Act @@ -1086,9 +1069,7 @@ public class BindAttributes Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new BindTagHelperDescriptorProvider(); // Act @@ -1115,9 +1096,7 @@ public void Execute_BindFallback_CreatesDescriptor() var compilation = BaseCompilation; Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new BindTagHelperDescriptorProvider(); // Act diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/CompilationTagHelperFeatureTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/CompilationTagHelperFeatureTest.cs index 052185a68f6..e93e5617c6e 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/CompilationTagHelperFeatureTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/CompilationTagHelperFeatureTest.cs @@ -70,11 +70,8 @@ public void IsValidCompilation_ReturnsTrueIfWellKnownTypesAreFound() public void GetDescriptors_DoesNotSetCompilation_IfCompilationIsInvalid() { // Arrange - Compilation compilation = null; var provider = new Mock(); - provider.Setup(c => c.Execute(It.IsAny())) - .Callback(c => compilation = c.GetCompilation()) - .Verifiable(); + provider.Setup(c => c.Execute(It.IsAny())); var engine = RazorProjectEngine.Create( configure => @@ -91,8 +88,7 @@ public void GetDescriptors_DoesNotSetCompilation_IfCompilationIsInvalid() // Assert Assert.Empty(result); - provider.Verify(); - Assert.Null(compilation); + provider.Verify(c => c.Execute(It.IsAny()), Times.Never); } [Fact] @@ -101,8 +97,9 @@ public void GetDescriptors_SetsCompilation_IfCompilationIsValid() // Arrange Compilation compilation = null; var provider = new Mock(); - provider.Setup(c => c.Execute(It.IsAny())) - .Callback(c => compilation = c.GetCompilation()) + provider + .Setup(c => c.Execute(It.IsAny())) + .Callback(c => compilation = c.Compilation) .Verifiable(); var references = new[] diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs index 2786fd31756..13205705dc7 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs @@ -41,9 +41,7 @@ public Task SetParametersAsync(ParameterView parameters) Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -166,9 +164,7 @@ public Task SetParametersAsync(ParameterView parameters) Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -230,9 +226,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -272,9 +266,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -312,9 +304,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -352,9 +342,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -405,9 +393,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -453,9 +439,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -501,9 +485,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -565,9 +547,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -640,9 +620,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -690,9 +668,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -752,9 +728,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -803,9 +777,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -858,9 +830,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -921,9 +891,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -978,9 +946,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1053,9 +1019,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1125,9 +1089,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1207,9 +1169,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1289,9 +1249,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1375,9 +1333,7 @@ public class Context Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1461,9 +1417,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1553,9 +1507,7 @@ public string this[int i] Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1609,9 +1561,7 @@ public class MyDerivedComponent2 : MyDerivedComponent1 Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1669,8 +1619,7 @@ public Task SetParametersAsync(ParameterView parameters) Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation); context.Items.SetTargetSymbol((IAssemblySymbol)compilation.GetAssemblyOrModuleSymbol(compilation.References.First(r => r.Display.Contains("Microsoft.CodeAnalysis.Razor.Test.dll")))); var provider = new ComponentTagHelperDescriptorProvider(); @@ -1715,8 +1664,7 @@ public Task SetParametersAsync(ParameterView parameters) Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs index eec507e0ae8..2c3f5a3593a 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs @@ -3,10 +3,8 @@ #nullable disable -using System.Diagnostics; using System.Linq; using System.Reflection; -using System.Threading; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.CSharp; using Xunit; @@ -25,8 +23,7 @@ public void Execute_DoesNotAddEditorBrowsableNeverDescriptorsAtDesignTime() var compilation = TestCompilation.Create(_assembly); var descriptorProvider = new DefaultTagHelperDescriptorProvider(); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation); context.ExcludeHidden = true; // Act @@ -40,21 +37,6 @@ public void Execute_DoesNotAddEditorBrowsableNeverDescriptorsAtDesignTime() Assert.Empty(editorBrowsableDescriptor); } - [Fact] - public void Execute_NoOpsIfCompilationIsNotSet() - { - // Arrange - var descriptorProvider = new DefaultTagHelperDescriptorProvider(); - - var context = TagHelperDescriptorProviderContext.Create(); - - // Act - descriptorProvider.Execute(context); - - // Assert - Assert.Empty(context.Results); - } - [Fact] public void Execute_WithDefaultDiscoversTagHelpersFromAssemblyAndReference() { @@ -73,8 +55,7 @@ public override void Process(TagHelperContext context, TagHelperOutput output) { var compilation = TestCompilation.Create(_assembly, CSharpSyntaxTree.ParseText(csharp)); var descriptorProvider = new DefaultTagHelperDescriptorProvider(); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation); // Act descriptorProvider.Execute(context); @@ -104,8 +85,7 @@ public override void Process(TagHelperContext context, TagHelperOutput output) { var compilation = TestCompilation.Create(_assembly, CSharpSyntaxTree.ParseText(csharp)); var descriptorProvider = new DefaultTagHelperDescriptorProvider(); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); + var context = TagHelperDescriptorProviderContext.Create(compilation); context.Items.SetTargetSymbol((IAssemblySymbol)compilation.GetAssemblyOrModuleSymbol(compilation.References.First(r => r.Display.Contains("Microsoft.CodeAnalysis.Razor.Test.dll")))); // Act diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/EventHandlerTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/EventHandlerTagHelperDescriptorProviderTest.cs index b5d097adc6d..5f49881ab64 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/EventHandlerTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/EventHandlerTagHelperDescriptorProviderTest.cs @@ -33,9 +33,7 @@ public class EventHandlers Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(compilation); - + var context = TagHelperDescriptorProviderContext.Create(compilation); var provider = new EventHandlerTagHelperDescriptorProvider(); // Act diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/KeyTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/KeyTagHelperDescriptorProviderTest.cs index 8d3fbc8a7a7..d24a0959ece 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/KeyTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/KeyTagHelperDescriptorProviderTest.cs @@ -16,9 +16,7 @@ public class KeyTagHelperDescriptorProviderTest : TagHelperDescriptorProviderTes public void Execute_CreatesDescriptor() { // Arrange - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(BaseCompilation); - + var context = TagHelperDescriptorProviderContext.Create(BaseCompilation); var provider = new KeyTagHelperDescriptorProvider(); // Act diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/RefTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/RefTagHelperDescriptorProviderTest.cs index 82246df560e..3f0ec75f345 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/RefTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/RefTagHelperDescriptorProviderTest.cs @@ -16,9 +16,7 @@ public class RefTagHelperDescriptorProviderTest : TagHelperDescriptorProviderTes public void Execute_CreatesDescriptor() { // Arrange - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(BaseCompilation); - + var context = TagHelperDescriptorProviderContext.Create(BaseCompilation); var provider = new RefTagHelperDescriptorProvider(); // Act diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/SplatTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/SplatTagHelperDescriptorProviderTest.cs index 66e5380a54c..b0563a10af2 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/SplatTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/SplatTagHelperDescriptorProviderTest.cs @@ -16,9 +16,7 @@ public class SplatTagHelperDescriptorProviderTest : TagHelperDescriptorProviderT public void Execute_CreatesDescriptor() { // Arrange - var context = TagHelperDescriptorProviderContext.Create(); - context.SetCompilation(BaseCompilation); - + var context = TagHelperDescriptorProviderContext.Create(BaseCompilation); var provider = new SplatTagHelperDescriptorProvider(); // Act diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs index adf4da162be..4db479a3d89 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs @@ -37,20 +37,20 @@ public async ValueTask> GetTagHelpersAsync( var providers = projectEngine.Engine.Features.OfType().OrderBy(f => f.Order).ToArray(); if (providers.Length == 0) { - return ImmutableArray.Empty; + return []; } - using var _ = HashSetPool.GetPooledObject(out var results); - var context = TagHelperDescriptorProviderContext.Create(results); - context.ExcludeHidden = true; - context.IncludeDocumentation = true; - var compilation = await workspaceProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false); - if (CompilationTagHelperFeature.IsValidCompilation(compilation)) + if (compilation is null || !CompilationTagHelperFeature.IsValidCompilation(compilation)) { - context.SetCompilation(compilation); + return []; } + using var _ = HashSetPool.GetPooledObject(out var results); + var context = TagHelperDescriptorProviderContext.Create(compilation, results); + context.ExcludeHidden = true; + context.IncludeDocumentation = true; + ExecuteProviders(providers, context, _telemetryReporter); return results.ToImmutableArray(); From ec5cd16335327bd38cc52f9ed6ba2d34e747101c Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Thu, 8 Aug 2024 10:07:39 -0700 Subject: [PATCH 44/53] Make TargetSymbol a TagHelperDescriptorProviderContext property --- .../CSharp/BindTagHelperDescriptorProvider.cs | 3 +-- .../ComponentTagHelperDescriptorProvider.cs | 2 +- .../DefaultTagHelperDescriptorProvider.cs | 2 +- ...EventHandlerTagHelperDescriptorProvider.cs | 2 +- .../FormNameTagHelperDescriptorProvider.cs | 3 +-- .../CSharp/KeyTagHelperDescriptorProvider.cs | 3 +-- .../CSharp/RefTagHelperDescriptorProvider.cs | 3 +-- .../RenderModeTagHelperDescriptorProvider.cs | 3 +-- .../SplatTagHelperDescriptorProvider.cs | 3 +-- .../CSharp/TagHelperTargetSymbolExtensions.cs | 26 ------------------- .../TagHelperDescriptorProviderContext.cs | 13 +++++++--- .../StaticCompilationTagHelperFeature.cs | 8 +----- .../BindTagHelperDescriptorProviderTest.cs | 7 ++--- ...omponentTagHelperDescriptorProviderTest.cs | 6 +++-- .../DefaultTagHelperDescriptorProviderTest.cs | 6 +++-- 15 files changed, 29 insertions(+), 61 deletions(-) delete mode 100644 src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/TagHelperTargetSymbolExtensions.cs diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs index ba7f1436257..b1999846c33 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs @@ -101,8 +101,7 @@ public void Execute(TagHelperDescriptorProviderContext context) return; } - var targetSymbol = context.Items.GetTargetSymbol(); - if (targetSymbol is not null && !SymbolEqualityComparer.Default.Equals(targetSymbol, bindMethods.ContainingAssembly)) + if (context.TargetSymbol is { } targetSymbol && !SymbolEqualityComparer.Default.Equals(targetSymbol, bindMethods.ContainingAssembly)) { return; } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/ComponentTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/ComponentTagHelperDescriptorProvider.cs index 15315e2bf0c..afd68b5eac0 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/ComponentTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/ComponentTagHelperDescriptorProvider.cs @@ -34,7 +34,7 @@ public void Execute(TagHelperDescriptorProviderContext context) } var compilation = context.Compilation; - var targetSymbol = context.Items.GetTargetSymbol(); + var targetSymbol = context.TargetSymbol; var collector = new Collector(compilation, targetSymbol); collector.Collect(context); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/DefaultTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/DefaultTagHelperDescriptorProvider.cs index b97810e3a92..4a7d1c98cc2 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/DefaultTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/DefaultTagHelperDescriptorProvider.cs @@ -30,7 +30,7 @@ public void Execute(TagHelperDescriptorProviderContext context) return; } - var targetSymbol = context.Items.GetTargetSymbol(); + var targetSymbol = context.TargetSymbol; var factory = new DefaultTagHelperDescriptorFactory(compilation, context.IncludeDocumentation, context.ExcludeHidden); var collector = new Collector(compilation, targetSymbol, factory, tagHelperTypeSymbol); collector.Collect(context); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/EventHandlerTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/EventHandlerTagHelperDescriptorProvider.cs index e49f629ffe7..7817c7fafa5 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/EventHandlerTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/EventHandlerTagHelperDescriptorProvider.cs @@ -33,7 +33,7 @@ public void Execute(TagHelperDescriptorProviderContext context) return; } - var targetSymbol = context.Items.GetTargetSymbol(); + var targetSymbol = context.TargetSymbol; var collector = new Collector(compilation, targetSymbol, eventHandlerAttribute); collector.Collect(context); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/FormNameTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/FormNameTagHelperDescriptorProvider.cs index fe834bd4db2..208e1ecc038 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/FormNameTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/FormNameTagHelperDescriptorProvider.cs @@ -36,8 +36,7 @@ public void Execute(TagHelperDescriptorProviderContext context) return; } - var targetSymbol = context.Items.GetTargetSymbol(); - if (targetSymbol is not null && !SymbolEqualityComparer.Default.Equals(targetSymbol, renderTreeBuilder.ContainingAssembly)) + if (context.TargetSymbol is { } targetSymbol && !SymbolEqualityComparer.Default.Equals(targetSymbol, renderTreeBuilder.ContainingAssembly)) { return; } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/KeyTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/KeyTagHelperDescriptorProvider.cs index 2a12fbb0087..359071fbc3e 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/KeyTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/KeyTagHelperDescriptorProvider.cs @@ -36,8 +36,7 @@ public void Execute(TagHelperDescriptorProviderContext context) return; } - var targetSymbol = context.Items.GetTargetSymbol(); - if (targetSymbol is not null && !SymbolEqualityComparer.Default.Equals(targetSymbol, renderTreeBuilderType.ContainingAssembly)) + if (context.TargetSymbol is { } targetSymbol && !SymbolEqualityComparer.Default.Equals(targetSymbol, renderTreeBuilderType.ContainingAssembly)) { return; } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RefTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RefTagHelperDescriptorProvider.cs index dc2014716bf..40f50698d20 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RefTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RefTagHelperDescriptorProvider.cs @@ -36,8 +36,7 @@ public void Execute(TagHelperDescriptorProviderContext context) return; } - var targetSymbol = context.Items.GetTargetSymbol(); - if (targetSymbol is not null && !SymbolEqualityComparer.Default.Equals(targetSymbol, elementReference.ContainingAssembly)) + if (context.TargetSymbol is { } targetSymbol && !SymbolEqualityComparer.Default.Equals(targetSymbol, elementReference.ContainingAssembly)) { return; } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RenderModeTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RenderModeTagHelperDescriptorProvider.cs index 16d38f9df6a..8feb1499e26 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RenderModeTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RenderModeTagHelperDescriptorProvider.cs @@ -36,8 +36,7 @@ public void Execute(TagHelperDescriptorProviderContext context) return; } - var targetSymbol = context.Items.GetTargetSymbol(); - if (targetSymbol is not null && !SymbolEqualityComparer.Default.Equals(targetSymbol, iComponentRenderMode.ContainingAssembly)) + if (context.TargetSymbol is { } targetSymbol && !SymbolEqualityComparer.Default.Equals(targetSymbol, iComponentRenderMode.ContainingAssembly)) { return; } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SplatTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SplatTagHelperDescriptorProvider.cs index 796fc145acb..5ec98d1eaa5 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SplatTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SplatTagHelperDescriptorProvider.cs @@ -36,8 +36,7 @@ public void Execute(TagHelperDescriptorProviderContext context) return; } - var targetSymbol = context.Items.GetTargetSymbol(); - if (targetSymbol is not null && !SymbolEqualityComparer.Default.Equals(targetSymbol, renderTreeBuilder.ContainingAssembly)) + if (context.TargetSymbol is { } targetSymbol && !SymbolEqualityComparer.Default.Equals(targetSymbol, renderTreeBuilder.ContainingAssembly)) { return; } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/TagHelperTargetSymbolExtensions.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/TagHelperTargetSymbolExtensions.cs deleted file mode 100644 index 6e9b1609e7f..00000000000 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/TagHelperTargetSymbolExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.AspNetCore.Razor.Language; - -namespace Microsoft.CodeAnalysis.Razor; - -internal static class TagHelperTargetSymbolExtensions -{ - private static readonly object TargetSymbolKey = new object(); - - public static ISymbol? GetTargetSymbol(this ItemCollection items) - { - if (items.Count == 0 || items[TargetSymbolKey] is not ISymbol symbol) - { - return null; - } - - return symbol; - } - - public static void SetTargetSymbol(this ItemCollection items, ISymbol symbol) - { - items[TargetSymbolKey] = symbol; - } -} diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs index 5625641a296..af2f09c4d28 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs @@ -9,6 +9,7 @@ namespace Microsoft.AspNetCore.Razor.Language; public sealed class TagHelperDescriptorProviderContext { public Compilation Compilation { get; } + public ISymbol? TargetSymbol { get; } public bool ExcludeHidden { get; set; } public bool IncludeDocumentation { get; set; } @@ -16,16 +17,20 @@ public sealed class TagHelperDescriptorProviderContext public ItemCollection Items { get; } public ICollection Results { get; } - private TagHelperDescriptorProviderContext(Compilation compilation, ICollection results) + private TagHelperDescriptorProviderContext(Compilation compilation, ISymbol? targetSymbol, ICollection results) { Compilation = compilation; + TargetSymbol = targetSymbol; Results = results; Items = []; } - public static TagHelperDescriptorProviderContext Create(Compilation compilation) - => new(compilation, results: []); + public static TagHelperDescriptorProviderContext Create(Compilation compilation, ISymbol? targetSymbol = null) + => new(compilation, targetSymbol, results: []); public static TagHelperDescriptorProviderContext Create(Compilation compilation, ICollection results) - => new(compilation, results); + => new(compilation, targetSymbol: null, results); + + public static TagHelperDescriptorProviderContext Create(Compilation compilation, ISymbol? targetSymbol, ICollection results) + => new(compilation, targetSymbol, results); } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs index 0efcc84523b..8da3ba40778 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs @@ -6,7 +6,6 @@ using System.Linq; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Razor; namespace Microsoft.NET.Sdk.Razor.SourceGenerators { @@ -22,12 +21,7 @@ public void CollectDescriptors(ISymbol? targetSymbol, List return; } - var context = TagHelperDescriptorProviderContext.Create(compilation, results); - - if (targetSymbol is not null) - { - context.Items.SetTargetSymbol(targetSymbol); - } + var context = TagHelperDescriptorProviderContext.Create(compilation, targetSymbol, results); foreach (var provider in _providers) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs index 718c0128b2c..1c3f5c37019 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs @@ -206,10 +206,8 @@ public void Execute_BindTagHelperReturnsValuesWhenProvidedCorrectAssemblyTargetS Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); - var bindConverterSymbol = compilation.GetTypeByMetadataName(ComponentsApi.BindConverter.FullTypeName); - context.Items.SetTargetSymbol(bindConverterSymbol.ContainingAssembly); + var context = TagHelperDescriptorProviderContext.Create(compilation, bindConverterSymbol.ContainingAssembly); var bindTagHelperProvider = new BindTagHelperDescriptorProvider(); @@ -233,8 +231,7 @@ public void Execute_BindTagHelperReturnsEmptyWhenCompilationAssemblyTargetSymbol Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); - context.Items.SetTargetSymbol(compilation.Assembly); + var context = TagHelperDescriptorProviderContext.Create(compilation, compilation.Assembly); var bindTagHelperProvider = new BindTagHelperDescriptorProvider(); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs index 13205705dc7..54ae8aef5cb 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs @@ -1619,8 +1619,10 @@ public Task SetParametersAsync(ParameterView parameters) Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); - context.Items.SetTargetSymbol((IAssemblySymbol)compilation.GetAssemblyOrModuleSymbol(compilation.References.First(r => r.Display.Contains("Microsoft.CodeAnalysis.Razor.Test.dll")))); + var targetSymbol = (IAssemblySymbol)compilation.GetAssemblyOrModuleSymbol( + compilation.References.First(static r => r.Display.Contains("Microsoft.CodeAnalysis.Razor.Test.dll"))); + + var context = TagHelperDescriptorProviderContext.Create(compilation, targetSymbol); var provider = new ComponentTagHelperDescriptorProvider(); // Act diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs index 2c3f5a3593a..a38a1fc025f 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs @@ -85,8 +85,10 @@ public override void Process(TagHelperContext context, TagHelperOutput output) { var compilation = TestCompilation.Create(_assembly, CSharpSyntaxTree.ParseText(csharp)); var descriptorProvider = new DefaultTagHelperDescriptorProvider(); - var context = TagHelperDescriptorProviderContext.Create(compilation); - context.Items.SetTargetSymbol((IAssemblySymbol)compilation.GetAssemblyOrModuleSymbol(compilation.References.First(r => r.Display.Contains("Microsoft.CodeAnalysis.Razor.Test.dll")))); + var targetSymbol = (IAssemblySymbol)compilation.GetAssemblyOrModuleSymbol( + compilation.References.First(static r => r.Display.Contains("Microsoft.CodeAnalysis.Razor.Test.dll"))); + + var context = TagHelperDescriptorProviderContext.Create(compilation, targetSymbol); // Act descriptorProvider.Execute(context); From 45625bc1a23337594aa93814e98638d6b964b2c1 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Thu, 8 Aug 2024 10:09:29 -0700 Subject: [PATCH 45/53] Remove TagHelperDescriptorProviderContext.Items property This can be safely removed now that there are no more references. --- .../src/Language/TagHelperDescriptorProviderContext.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs index af2f09c4d28..5d7c950c16b 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs @@ -14,7 +14,6 @@ public sealed class TagHelperDescriptorProviderContext public bool ExcludeHidden { get; set; } public bool IncludeDocumentation { get; set; } - public ItemCollection Items { get; } public ICollection Results { get; } private TagHelperDescriptorProviderContext(Compilation compilation, ISymbol? targetSymbol, ICollection results) @@ -22,7 +21,6 @@ private TagHelperDescriptorProviderContext(Compilation compilation, ISymbol? tar Compilation = compilation; TargetSymbol = targetSymbol; Results = results; - Items = []; } public static TagHelperDescriptorProviderContext Create(Compilation compilation, ISymbol? targetSymbol = null) From 9476634170ea39c92663ad2da01ce95a2325b090 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Thu, 8 Aug 2024 10:14:05 -0700 Subject: [PATCH 46/53] Swap TagHelperDescriptorProviderContext.Create methods for constructors --- ...omponentTagHelperDescriptorProviderTest.cs | 2 +- ...omponentTagHelperDescriptorProviderTest.cs | 2 +- ...omponentTagHelperDescriptorProviderTest.cs | 2 +- .../src/CSharp/CompilationTagHelperFeature.cs | 2 +- .../TagHelperDescriptorProviderContext.cs | 26 ++++----- .../StaticCompilationTagHelperFeature.cs | 2 +- .../BindTagHelperDescriptorProviderTest.cs | 26 ++++----- ...omponentTagHelperDescriptorProviderTest.cs | 54 +++++++++---------- .../DefaultTagHelperDescriptorProviderTest.cs | 6 +-- ...tHandlerTagHelperDescriptorProviderTest.cs | 2 +- .../KeyTagHelperDescriptorProviderTest.cs | 2 +- .../RefTagHelperDescriptorProviderTest.cs | 2 +- .../SplatTagHelperDescriptorProviderTest.cs | 2 +- .../CompilationTagHelperResolver.cs | 2 +- 14 files changed, 63 insertions(+), 69 deletions(-) diff --git a/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/ViewComponentTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/ViewComponentTagHelperDescriptorProviderTest.cs index ab563dda4ce..b79da5d4bf9 100644 --- a/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/ViewComponentTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/ViewComponentTagHelperDescriptorProviderTest.cs @@ -27,7 +27,7 @@ public class StringParameterViewComponent var compilation = MvcShim.BaseCompilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(code)); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ViewComponentTagHelperDescriptorProvider() { diff --git a/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/ViewComponentTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/ViewComponentTagHelperDescriptorProviderTest.cs index 8192f48af6d..8776cd20f16 100644 --- a/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/ViewComponentTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/ViewComponentTagHelperDescriptorProviderTest.cs @@ -27,7 +27,7 @@ public class StringParameterViewComponent var compilation = MvcShim.BaseCompilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(code)); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ViewComponentTagHelperDescriptorProvider() { diff --git a/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ViewComponentTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ViewComponentTagHelperDescriptorProviderTest.cs index 68961a39485..e4712707c84 100644 --- a/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ViewComponentTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ViewComponentTagHelperDescriptorProviderTest.cs @@ -27,7 +27,7 @@ public class StringParameterViewComponent var compilation = MvcShim.BaseCompilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(code)); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ViewComponentTagHelperDescriptorProvider() { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/CompilationTagHelperFeature.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/CompilationTagHelperFeature.cs index af9a69e4160..cfa7f57f20b 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/CompilationTagHelperFeature.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/CompilationTagHelperFeature.cs @@ -24,7 +24,7 @@ public IReadOnlyList GetDescriptors() } var results = new List(); - var context = TagHelperDescriptorProviderContext.Create(compilation, results); + var context = new TagHelperDescriptorProviderContext(compilation, results); for (var i = 0; i < _providers.Length; i++) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs index 5d7c950c16b..cee1a15c3b4 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs @@ -6,29 +6,23 @@ namespace Microsoft.AspNetCore.Razor.Language; -public sealed class TagHelperDescriptorProviderContext +public sealed class TagHelperDescriptorProviderContext(Compilation compilation, ISymbol? targetSymbol, ICollection results) { - public Compilation Compilation { get; } - public ISymbol? TargetSymbol { get; } + public Compilation Compilation { get; } = compilation; + public ISymbol? TargetSymbol { get; } = targetSymbol; public bool ExcludeHidden { get; set; } public bool IncludeDocumentation { get; set; } - public ICollection Results { get; } + public ICollection Results { get; } = results; - private TagHelperDescriptorProviderContext(Compilation compilation, ISymbol? targetSymbol, ICollection results) + public TagHelperDescriptorProviderContext(Compilation compilation, ISymbol? targetSymbol = null) + : this(compilation, targetSymbol, results: []) { - Compilation = compilation; - TargetSymbol = targetSymbol; - Results = results; } - public static TagHelperDescriptorProviderContext Create(Compilation compilation, ISymbol? targetSymbol = null) - => new(compilation, targetSymbol, results: []); - - public static TagHelperDescriptorProviderContext Create(Compilation compilation, ICollection results) - => new(compilation, targetSymbol: null, results); - - public static TagHelperDescriptorProviderContext Create(Compilation compilation, ISymbol? targetSymbol, ICollection results) - => new(compilation, targetSymbol, results); + public TagHelperDescriptorProviderContext(Compilation compilation, ICollection results) + : this(compilation, targetSymbol: null, results) + { + } } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs index 8da3ba40778..812c7bb3381 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs @@ -21,7 +21,7 @@ public void CollectDescriptors(ISymbol? targetSymbol, List return; } - var context = TagHelperDescriptorProviderContext.Create(compilation, targetSymbol, results); + var context = new TagHelperDescriptorProviderContext(compilation, targetSymbol, results); foreach (var provider in _providers) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs index 1c3f5c37019..6b568a1b353 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs @@ -48,7 +48,7 @@ public Task SetParametersAsync(ParameterView parameters) Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); // We run after component discovery and depend on the results. var componentProvider = new ComponentTagHelperDescriptorProvider(); @@ -182,7 +182,7 @@ public void Execute_BindTagHelperReturnsValuesWhenProvidedNoTargetSymbol() Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var bindTagHelperProvider = new BindTagHelperDescriptorProvider(); @@ -207,7 +207,7 @@ public void Execute_BindTagHelperReturnsValuesWhenProvidedCorrectAssemblyTargetS Assert.Empty(compilation.GetDiagnostics()); var bindConverterSymbol = compilation.GetTypeByMetadataName(ComponentsApi.BindConverter.FullTypeName); - var context = TagHelperDescriptorProviderContext.Create(compilation, bindConverterSymbol.ContainingAssembly); + var context = new TagHelperDescriptorProviderContext(compilation, bindConverterSymbol.ContainingAssembly); var bindTagHelperProvider = new BindTagHelperDescriptorProvider(); @@ -231,7 +231,7 @@ public void Execute_BindTagHelperReturnsEmptyWhenCompilationAssemblyTargetSymbol Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation, compilation.Assembly); + var context = new TagHelperDescriptorProviderContext(compilation, compilation.Assembly); var bindTagHelperProvider = new BindTagHelperDescriptorProvider(); @@ -273,7 +273,7 @@ public Task SetParametersAsync(ParameterView parameters) Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); // We run after component discovery and depend on the results. var componentProvider = new ComponentTagHelperDescriptorProvider(); @@ -423,7 +423,7 @@ public Task SetParametersAsync(ParameterView parameters) Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); // We run after component discovery and depend on the results. var componentProvider = new ComponentTagHelperDescriptorProvider(); @@ -458,7 +458,7 @@ public class BindAttributes Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new BindTagHelperDescriptorProvider(); // Act @@ -717,7 +717,7 @@ public class BindAttributes Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new BindTagHelperDescriptorProvider(); // Act @@ -800,7 +800,7 @@ public class BindAttributes Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new BindTagHelperDescriptorProvider(); // Act @@ -874,7 +874,7 @@ public class BindAttributes Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new BindTagHelperDescriptorProvider(); // Act @@ -969,7 +969,7 @@ public class BindAttributes Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new BindTagHelperDescriptorProvider(); // Act @@ -1066,7 +1066,7 @@ public class BindAttributes Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new BindTagHelperDescriptorProvider(); // Act @@ -1093,7 +1093,7 @@ public void Execute_BindFallback_CreatesDescriptor() var compilation = BaseCompilation; Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new BindTagHelperDescriptorProvider(); // Act diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs index 54ae8aef5cb..3a37a47cd1b 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs @@ -41,7 +41,7 @@ public Task SetParametersAsync(ParameterView parameters) Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -164,7 +164,7 @@ public Task SetParametersAsync(ParameterView parameters) Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -226,7 +226,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -266,7 +266,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -304,7 +304,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -342,7 +342,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -393,7 +393,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -439,7 +439,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -485,7 +485,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -547,7 +547,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -620,7 +620,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -668,7 +668,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -728,7 +728,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -777,7 +777,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -830,7 +830,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -891,7 +891,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -946,7 +946,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1019,7 +1019,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1089,7 +1089,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1169,7 +1169,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1249,7 +1249,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1333,7 +1333,7 @@ public class Context Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1417,7 +1417,7 @@ public class MyComponent : ComponentBase Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1507,7 +1507,7 @@ public string this[int i] Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1561,7 +1561,7 @@ public class MyDerivedComponent2 : MyDerivedComponent1 Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1622,7 +1622,7 @@ public Task SetParametersAsync(ParameterView parameters) var targetSymbol = (IAssemblySymbol)compilation.GetAssemblyOrModuleSymbol( compilation.References.First(static r => r.Display.Contains("Microsoft.CodeAnalysis.Razor.Test.dll"))); - var context = TagHelperDescriptorProviderContext.Create(compilation, targetSymbol); + var context = new TagHelperDescriptorProviderContext(compilation, targetSymbol); var provider = new ComponentTagHelperDescriptorProvider(); // Act @@ -1666,7 +1666,7 @@ public Task SetParametersAsync(ParameterView parameters) Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new ComponentTagHelperDescriptorProvider(); // Act diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs index a38a1fc025f..83702d37e3f 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs @@ -23,7 +23,7 @@ public void Execute_DoesNotAddEditorBrowsableNeverDescriptorsAtDesignTime() var compilation = TestCompilation.Create(_assembly); var descriptorProvider = new DefaultTagHelperDescriptorProvider(); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); context.ExcludeHidden = true; // Act @@ -55,7 +55,7 @@ public override void Process(TagHelperContext context, TagHelperOutput output) { var compilation = TestCompilation.Create(_assembly, CSharpSyntaxTree.ParseText(csharp)); var descriptorProvider = new DefaultTagHelperDescriptorProvider(); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); // Act descriptorProvider.Execute(context); @@ -88,7 +88,7 @@ public override void Process(TagHelperContext context, TagHelperOutput output) { var targetSymbol = (IAssemblySymbol)compilation.GetAssemblyOrModuleSymbol( compilation.References.First(static r => r.Display.Contains("Microsoft.CodeAnalysis.Razor.Test.dll"))); - var context = TagHelperDescriptorProviderContext.Create(compilation, targetSymbol); + var context = new TagHelperDescriptorProviderContext(compilation, targetSymbol); // Act descriptorProvider.Execute(context); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/EventHandlerTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/EventHandlerTagHelperDescriptorProviderTest.cs index 5f49881ab64..101927ad544 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/EventHandlerTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/EventHandlerTagHelperDescriptorProviderTest.cs @@ -33,7 +33,7 @@ public class EventHandlers Assert.Empty(compilation.GetDiagnostics()); - var context = TagHelperDescriptorProviderContext.Create(compilation); + var context = new TagHelperDescriptorProviderContext(compilation); var provider = new EventHandlerTagHelperDescriptorProvider(); // Act diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/KeyTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/KeyTagHelperDescriptorProviderTest.cs index d24a0959ece..a9238bd8afe 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/KeyTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/KeyTagHelperDescriptorProviderTest.cs @@ -16,7 +16,7 @@ public class KeyTagHelperDescriptorProviderTest : TagHelperDescriptorProviderTes public void Execute_CreatesDescriptor() { // Arrange - var context = TagHelperDescriptorProviderContext.Create(BaseCompilation); + var context = new TagHelperDescriptorProviderContext(BaseCompilation); var provider = new KeyTagHelperDescriptorProvider(); // Act diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/RefTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/RefTagHelperDescriptorProviderTest.cs index 3f0ec75f345..5109439c9cf 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/RefTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/RefTagHelperDescriptorProviderTest.cs @@ -16,7 +16,7 @@ public class RefTagHelperDescriptorProviderTest : TagHelperDescriptorProviderTes public void Execute_CreatesDescriptor() { // Arrange - var context = TagHelperDescriptorProviderContext.Create(BaseCompilation); + var context = new TagHelperDescriptorProviderContext(BaseCompilation); var provider = new RefTagHelperDescriptorProvider(); // Act diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/SplatTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/SplatTagHelperDescriptorProviderTest.cs index b0563a10af2..19e2c970bfd 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/SplatTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/SplatTagHelperDescriptorProviderTest.cs @@ -16,7 +16,7 @@ public class SplatTagHelperDescriptorProviderTest : TagHelperDescriptorProviderT public void Execute_CreatesDescriptor() { // Arrange - var context = TagHelperDescriptorProviderContext.Create(BaseCompilation); + var context = new TagHelperDescriptorProviderContext(BaseCompilation); var provider = new SplatTagHelperDescriptorProvider(); // Act diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs index 4db479a3d89..63cda097147 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs @@ -47,7 +47,7 @@ public async ValueTask> GetTagHelpersAsync( } using var _ = HashSetPool.GetPooledObject(out var results); - var context = TagHelperDescriptorProviderContext.Create(compilation, results); + var context = new TagHelperDescriptorProviderContext(compilation, results); context.ExcludeHidden = true; context.IncludeDocumentation = true; From eae0d53793687727c7399a8babe5c0b145dc8a14 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Thu, 8 Aug 2024 10:19:35 -0700 Subject: [PATCH 47/53] Make ExcludeHidden and IncludeDocumentation init-only properties --- .../src/Language/TagHelperDescriptorProviderContext.cs | 7 +++---- .../test/DefaultTagHelperDescriptorProviderTest.cs | 6 ++++-- .../CompilationTagHelperResolver.cs | 8 +++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs index cee1a15c3b4..1305d7888af 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderContext.cs @@ -10,12 +10,11 @@ public sealed class TagHelperDescriptorProviderContext(Compilation compilation, { public Compilation Compilation { get; } = compilation; public ISymbol? TargetSymbol { get; } = targetSymbol; - - public bool ExcludeHidden { get; set; } - public bool IncludeDocumentation { get; set; } - public ICollection Results { get; } = results; + public bool ExcludeHidden { get; init; } + public bool IncludeDocumentation { get; init; } + public TagHelperDescriptorProviderContext(Compilation compilation, ISymbol? targetSymbol = null) : this(compilation, targetSymbol, results: []) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs index 83702d37e3f..f5d46a59aec 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/DefaultTagHelperDescriptorProviderTest.cs @@ -23,8 +23,10 @@ public void Execute_DoesNotAddEditorBrowsableNeverDescriptorsAtDesignTime() var compilation = TestCompilation.Create(_assembly); var descriptorProvider = new DefaultTagHelperDescriptorProvider(); - var context = new TagHelperDescriptorProviderContext(compilation); - context.ExcludeHidden = true; + var context = new TagHelperDescriptorProviderContext(compilation) + { + ExcludeHidden = true + }; // Act descriptorProvider.Execute(context); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs index 63cda097147..73e1d766d06 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs @@ -47,9 +47,11 @@ public async ValueTask> GetTagHelpersAsync( } using var _ = HashSetPool.GetPooledObject(out var results); - var context = new TagHelperDescriptorProviderContext(compilation, results); - context.ExcludeHidden = true; - context.IncludeDocumentation = true; + var context = new TagHelperDescriptorProviderContext(compilation, results) + { + ExcludeHidden = true, + IncludeDocumentation = true + }; ExecuteProviders(providers, context, _telemetryReporter); From 5fbfc0d454eba158ee903f877a6bc67141c93f88 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Thu, 8 Aug 2024 12:28:46 -0700 Subject: [PATCH 48/53] Clean up all ITagHelperDescriptorProviders a bit (and found a bug!) - Enable nullability - Mark all as sealed - Use `Lazy` for singleton `ITagHelperDescriptorProviders` - Introduce `TagHelperDescriptorProviderBase` - Inherit from `TagHelperDescriptorProviderBase` - Remove unnecessary properties - Remove unnecessary property setters In addition, I spotted a bug in `EventHandlerTagDescriptorProvider` while addressing nullability warnings. The buggy code is right here: https://github.com/dotnet/razor/blob/fb84ae5d9bb8132972c2c23cf209721161f81deb/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/EventHandlerTagHelperDescriptorProvider.cs#L70-L76 When reading the constructor arguments of an `EventHandlerAttribute` it appears that we swap the last two arguments of the 4-argument variant. The constructor is defined like so: ```C# EventHandlerAttribute(string attributeName, Type eventArgsType, bool enableStopPropagation, bool enablePreventDefault); ``` Unfortunately, the compiler reads the third parameter as `enablePreventDefaeult` and the fourth parameter as `enableStopPropagation`. This has been broken since support for the 4-argument constructor variant was added in https://github.com/dotnet/razor/commit/7635bba6ef2d3e6798d0846ceb96da6d5908e1b0. Fixing this bug is tracked by https://github.com/dotnet/razor/issues/10497. --- .../CSharp/BindTagHelperDescriptorProvider.cs | 183 ++++++++---------- .../ComponentTagHelperDescriptorProvider.cs | 170 ++++++++-------- .../DefaultTagHelperDescriptorProvider.cs | 17 +- ...EventHandlerTagHelperDescriptorProvider.cs | 89 +++++---- .../FormNameTagHelperDescriptorProvider.cs | 16 +- .../CSharp/KeyTagHelperDescriptorProvider.cs | 83 ++++---- .../CSharp/RefTagHelperDescriptorProvider.cs | 83 ++++---- .../RenderModeTagHelperDescriptorProvider.cs | 22 +-- .../SplatTagHelperDescriptorProvider.cs | 82 ++++---- .../src/CSharp/SymbolExtensions.cs | 3 + .../TagHelperDescriptorProviderBase.cs | 11 ++ ...iewComponentTagHelperDescriptorProvider.cs | 19 +- .../ViewComponentTypeVisitor.cs | 10 +- ...iewComponentTagHelperDescriptorProvider.cs | 19 +- .../ViewComponentTypeVisitor.cs | 10 +- ...iewComponentTagHelperDescriptorProvider.cs | 19 +- .../src/Mvc/ViewComponentTypeVisitor.cs | 8 +- 17 files changed, 386 insertions(+), 458 deletions(-) create mode 100644 src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderBase.cs diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs index b1999846c33..e2c3d9f77c5 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/BindTagHelperDescriptorProvider.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; using Microsoft.AspNetCore.Razor.PooledObjects; @@ -12,21 +13,14 @@ namespace Microsoft.CodeAnalysis.Razor; -internal class BindTagHelperDescriptorProvider : ITagHelperDescriptorProvider +// Run after the component tag helper provider, because we need to see the results. +internal sealed class BindTagHelperDescriptorProvider() : TagHelperDescriptorProviderBase(order: 1000) { - private static TagHelperDescriptor? s_fallbackBindTagHelper; + private static readonly Lazy s_fallbackBindTagHelper = new(CreateFallbackBindTagHelper); - // Run after the component tag helper provider, because we need to see the results. - public int Order { get; set; } = 1000; - - public RazorEngine? Engine { get; set; } - - public void Execute(TagHelperDescriptorProviderContext context) + public override void Execute(TagHelperDescriptorProviderContext context) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } + ArgHelper.ThrowIfNull(context); // This provider returns tag helper information for 'bind' which doesn't necessarily // map to any real component. Bind behaviors more like a macro, which can map a single LValue to @@ -107,7 +101,7 @@ public void Execute(TagHelperDescriptorProviderContext context) } // Tag Helper definition for case #1. This is the most general case. - context.Results.Add(GetOrCreateFallbackBindTagHelper()); + context.Results.Add(s_fallbackBindTagHelper.Value); var bindElementAttribute = compilation.GetTypeByMetadataName(ComponentsApi.BindElementAttribute.FullTypeName); var bindInputElementAttribute = compilation.GetTypeByMetadataName(ComponentsApi.BindInputElementAttribute.FullTypeName); @@ -124,112 +118,107 @@ public void Execute(TagHelperDescriptorProviderContext context) collector.Collect(context); } - private static TagHelperDescriptor GetOrCreateFallbackBindTagHelper() + private static TagHelperDescriptor CreateFallbackBindTagHelper() { - return s_fallbackBindTagHelper ??= CreateFallbackBindTagHelper(); - - static TagHelperDescriptor CreateFallbackBindTagHelper() + using var _ = TagHelperDescriptorBuilder.GetPooledInstance( + ComponentMetadata.Bind.TagHelperKind, "Bind", ComponentsApi.AssemblyName, + out var builder); + + builder.CaseSensitive = true; + builder.SetDocumentation(DocumentationDescriptor.BindTagHelper_Fallback); + + builder.SetMetadata( + SpecialKind(ComponentMetadata.Bind.TagHelperKind), + MakeTrue(TagHelperMetadata.Common.ClassifyAttributesOnly), + RuntimeName(ComponentMetadata.Bind.RuntimeName), + MakeTrue(ComponentMetadata.Bind.FallbackKey), + TypeName("Microsoft.AspNetCore.Components.Bind"), + TypeNamespace("Microsoft.AspNetCore.Components"), + TypeNameIdentifier("Bind")); + + builder.TagMatchingRule(rule => { - using var _ = TagHelperDescriptorBuilder.GetPooledInstance( - ComponentMetadata.Bind.TagHelperKind, "Bind", ComponentsApi.AssemblyName, - out var builder); - - builder.CaseSensitive = true; - builder.SetDocumentation(DocumentationDescriptor.BindTagHelper_Fallback); - - builder.SetMetadata( - SpecialKind(ComponentMetadata.Bind.TagHelperKind), - MakeTrue(TagHelperMetadata.Common.ClassifyAttributesOnly), - RuntimeName(ComponentMetadata.Bind.RuntimeName), - MakeTrue(ComponentMetadata.Bind.FallbackKey), - TypeName("Microsoft.AspNetCore.Components.Bind"), - TypeNamespace("Microsoft.AspNetCore.Components"), - TypeNameIdentifier("Bind")); - - builder.TagMatchingRule(rule => + rule.TagName = "*"; + rule.Attribute(attribute => { - rule.TagName = "*"; - rule.Attribute(attribute => - { - attribute.Name = "@bind-"; - attribute.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch; - attribute.SetMetadata(Attributes.IsDirectiveAttribute); - }); + attribute.Name = "@bind-"; + attribute.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch; + attribute.SetMetadata(Attributes.IsDirectiveAttribute); }); + }); - builder.BindAttribute(attribute => - { - attribute.SetDocumentation(DocumentationDescriptor.BindTagHelper_Fallback); + builder.BindAttribute(attribute => + { + attribute.SetDocumentation(DocumentationDescriptor.BindTagHelper_Fallback); - var attributeName = "@bind-..."; - attribute.Name = attributeName; - attribute.AsDictionary("@bind-", typeof(object).FullName); + var attributeName = "@bind-..."; + attribute.Name = attributeName; + attribute.AsDictionary("@bind-", typeof(object).FullName); - attribute.SetMetadata( - PropertyName("Bind"), - IsDirectiveAttribute); + attribute.SetMetadata( + PropertyName("Bind"), + IsDirectiveAttribute); - attribute.TypeName = "System.Collections.Generic.Dictionary"; + attribute.TypeName = "System.Collections.Generic.Dictionary"; - attribute.BindAttributeParameter(parameter => - { - parameter.Name = "format"; - parameter.TypeName = typeof(string).FullName; - parameter.SetDocumentation(DocumentationDescriptor.BindTagHelper_Fallback_Format); + attribute.BindAttributeParameter(parameter => + { + parameter.Name = "format"; + parameter.TypeName = typeof(string).FullName; + parameter.SetDocumentation(DocumentationDescriptor.BindTagHelper_Fallback_Format); - parameter.SetMetadata(Parameters.Format); - }); + parameter.SetMetadata(Parameters.Format); + }); - attribute.BindAttributeParameter(parameter => - { - parameter.Name = "event"; - parameter.TypeName = typeof(string).FullName; - parameter.SetDocumentation( - DocumentationDescriptor.From( - DocumentationId.BindTagHelper_Fallback_Event, attributeName)); + attribute.BindAttributeParameter(parameter => + { + parameter.Name = "event"; + parameter.TypeName = typeof(string).FullName; + parameter.SetDocumentation( + DocumentationDescriptor.From( + DocumentationId.BindTagHelper_Fallback_Event, attributeName)); - parameter.SetMetadata(Parameters.Event); - }); + parameter.SetMetadata(Parameters.Event); + }); - attribute.BindAttributeParameter(parameter => - { - parameter.Name = "culture"; - parameter.TypeName = typeof(CultureInfo).FullName; - parameter.SetDocumentation(DocumentationDescriptor.BindTagHelper_Element_Culture); + attribute.BindAttributeParameter(parameter => + { + parameter.Name = "culture"; + parameter.TypeName = typeof(CultureInfo).FullName; + parameter.SetDocumentation(DocumentationDescriptor.BindTagHelper_Element_Culture); - parameter.SetMetadata(Parameters.Culture); - }); + parameter.SetMetadata(Parameters.Culture); + }); - attribute.BindAttributeParameter(parameter => - { - parameter.Name = "get"; - parameter.TypeName = typeof(object).FullName; - parameter.SetDocumentation(DocumentationDescriptor.BindTagHelper_Element_Get); + attribute.BindAttributeParameter(parameter => + { + parameter.Name = "get"; + parameter.TypeName = typeof(object).FullName; + parameter.SetDocumentation(DocumentationDescriptor.BindTagHelper_Element_Get); - parameter.SetMetadata(Parameters.Get); - }); + parameter.SetMetadata(Parameters.Get); + }); - attribute.BindAttributeParameter(parameter => - { - parameter.Name = "set"; - parameter.TypeName = typeof(Delegate).FullName; - parameter.SetDocumentation(DocumentationDescriptor.BindTagHelper_Element_Set); + attribute.BindAttributeParameter(parameter => + { + parameter.Name = "set"; + parameter.TypeName = typeof(Delegate).FullName; + parameter.SetDocumentation(DocumentationDescriptor.BindTagHelper_Element_Set); - parameter.SetMetadata(Parameters.Set); - }); + parameter.SetMetadata(Parameters.Set); + }); - attribute.BindAttributeParameter(parameter => - { - parameter.Name = "after"; - parameter.TypeName = typeof(Delegate).FullName; - parameter.SetDocumentation(DocumentationDescriptor.BindTagHelper_Element_After); + attribute.BindAttributeParameter(parameter => + { + parameter.Name = "after"; + parameter.TypeName = typeof(Delegate).FullName; + parameter.SetDocumentation(DocumentationDescriptor.BindTagHelper_Element_After); - parameter.SetMetadata(Parameters.After); - }); + parameter.SetMetadata(Parameters.After); }); + }); - return builder.Build(); - } + return builder.Build(); } private class Collector( diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/ComponentTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/ComponentTagHelperDescriptorProvider.cs index afd68b5eac0..99c6e5e6943 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/ComponentTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/ComponentTagHelperDescriptorProvider.cs @@ -1,13 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; using Microsoft.AspNetCore.Razor.PooledObjects; @@ -15,23 +14,16 @@ namespace Microsoft.CodeAnalysis.Razor; -internal partial class ComponentTagHelperDescriptorProvider : RazorEngineFeatureBase, ITagHelperDescriptorProvider +internal sealed class ComponentTagHelperDescriptorProvider : TagHelperDescriptorProviderBase { private static readonly SymbolDisplayFormat GloballyQualifiedFullNameTypeDisplayFormat = SymbolDisplayFormat.FullyQualifiedFormat .WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Included) .WithMiscellaneousOptions(SymbolDisplayFormat.FullyQualifiedFormat.MiscellaneousOptions & (~SymbolDisplayMiscellaneousOptions.UseSpecialTypes)); - public bool IncludeDocumentation { get; set; } - - public int Order { get; set; } - - public void Execute(TagHelperDescriptorProviderContext context) + public override void Execute(TagHelperDescriptorProviderContext context) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } + ArgHelper.ThrowIfNull(context); var compilation = context.Compilation; var targetSymbol = context.TargetSymbol; @@ -40,7 +32,7 @@ public void Execute(TagHelperDescriptorProviderContext context) collector.Collect(context); } - private sealed class Collector(Compilation compilation, ISymbol targetSymbol) + private sealed class Collector(Compilation compilation, ISymbol? targetSymbol) : TagHelperCollector(compilation, targetSymbol) { protected override void Collect(ISymbol symbol, ICollection results) @@ -136,7 +128,7 @@ private static TagHelperDescriptor CreateNameMatchingDescriptor( foreach (var attribute in type.GetAttributes()) { - if (attribute.AttributeClass.HasFullName(ComponentsApi.CascadingTypeParameterAttribute.MetadataName) && + if (attribute.HasFullName(ComponentsApi.CascadingTypeParameterAttribute.MetadataName) && attribute.ConstructorArguments.FirstOrDefault() is { Value: string value }) { cascadeGenericTypeAttributes.Add(value); @@ -198,7 +190,7 @@ private static void CreateProperty(TagHelperDescriptorBuilder builder, INamedTyp pb.ContainingType = containingSymbol.ToDisplayString(SymbolExtensions.FullNameTypeDisplayFormat); pb.TypeName = property.Type.ToDisplayString(SymbolExtensions.FullNameTypeDisplayFormat); pb.IsEditorRequired = property.GetAttributes().Any( - static a => a.AttributeClass.HasFullName("Microsoft.AspNetCore.Components.EditorRequiredAttribute")); + static a => a.HasFullName("Microsoft.AspNetCore.Components.EditorRequiredAttribute")); pb.CaseSensitive = false; @@ -231,7 +223,7 @@ private static void CreateProperty(TagHelperDescriptorBuilder builder, INamedTyp metadata.Add(MakeTrue(ComponentMetadata.Component.GenericTypedKey)); } - if (property.SetMethod.IsInitOnly) + if (property.SetMethod.AssumeNotNull().IsInitOnly) { metadata.Add(MakeTrue(ComponentMetadata.Component.InitOnlyProperty)); } @@ -293,101 +285,98 @@ static bool HasTypeParameter(ITypeSymbol type) private static string IsAwaitable(IPropertySymbol prop) { - var methodSymbol = ((INamedTypeSymbol)prop.Type).DelegateInvokeMethod; + var methodSymbol = ((INamedTypeSymbol)prop.Type).DelegateInvokeMethod.AssumeNotNull(); if (methodSymbol.ReturnsVoid) { return bool.FalseString; } - else + + var members = methodSymbol.ReturnType.GetMembers(); + foreach (var candidate in members) { - var members = methodSymbol.ReturnType.GetMembers(); - foreach (var candidate in members) + if (candidate is not IMethodSymbol method || !string.Equals(candidate.Name, "GetAwaiter", StringComparison.Ordinal)) { - if (candidate is not IMethodSymbol method || !string.Equals(candidate.Name, "GetAwaiter", StringComparison.Ordinal)) - { - continue; - } + continue; + } - if (!VerifyGetAwaiter(method)) - { - continue; - } + if (!VerifyGetAwaiter(method)) + { + continue; + } + + return bool.TrueString; + } - return bool.TrueString; + return methodSymbol.IsAsync ? bool.TrueString : bool.FalseString; + + static bool VerifyGetAwaiter(IMethodSymbol getAwaiter) + { + var returnType = getAwaiter.ReturnType; + if (returnType == null) + { + return false; } - return methodSymbol.IsAsync ? bool.TrueString : bool.FalseString; + var foundIsCompleted = false; + var foundOnCompleted = false; + var foundGetResult = false; - static bool VerifyGetAwaiter(IMethodSymbol getAwaiter) + foreach (var member in returnType.GetMembers()) { - var returnType = getAwaiter.ReturnType; - if (returnType == null) + if (!foundIsCompleted && + member is IPropertySymbol property && + IsProperty_IsCompleted(property)) { - return false; + foundIsCompleted = true; } - - var foundIsCompleted = false; - var foundOnCompleted = false; - var foundGetResult = false; - - foreach (var member in returnType.GetMembers()) + if (!(foundOnCompleted && foundGetResult) && member is IMethodSymbol method) { - if (!foundIsCompleted && - member is IPropertySymbol property && - IsProperty_IsCompleted(property)) + if (IsMethod_OnCompleted(method)) { - foundIsCompleted = true; + foundOnCompleted = true; } - - if (!(foundOnCompleted && foundGetResult) && member is IMethodSymbol method) + else if (IsMethod_GetResult(method)) { - if (IsMethod_OnCompleted(method)) - { - foundOnCompleted = true; - } - else if (IsMethod_GetResult(method)) - { - foundGetResult = true; - } + foundGetResult = true; } + } - if (foundIsCompleted && foundOnCompleted && foundGetResult) - { - return true; - } + if (foundIsCompleted && foundOnCompleted && foundGetResult) + { + return true; } + } - return false; + return false; - static bool IsProperty_IsCompleted(IPropertySymbol property) + static bool IsProperty_IsCompleted(IPropertySymbol property) + { + return property is { - return property is - { - Name: WellKnownMemberNames.IsCompleted, - Type.SpecialType: SpecialType.System_Boolean, - GetMethod: not null - }; - } + Name: WellKnownMemberNames.IsCompleted, + Type.SpecialType: SpecialType.System_Boolean, + GetMethod: not null + }; + } - static bool IsMethod_OnCompleted(IMethodSymbol method) + static bool IsMethod_OnCompleted(IMethodSymbol method) + { + return method is { - return method is - { - Name: WellKnownMemberNames.OnCompleted, - ReturnsVoid: true, - Parameters: [{ Type.TypeKind: TypeKind.Delegate }] - }; - } + Name: WellKnownMemberNames.OnCompleted, + ReturnsVoid: true, + Parameters: [{ Type.TypeKind: TypeKind.Delegate }] + }; + } - static bool IsMethod_GetResult(IMethodSymbol method) + static bool IsMethod_GetResult(IMethodSymbol method) + { + return method is { - return method is - { - Name: WellKnownMemberNames.GetResult, - Parameters: [] - }; - } + Name: WellKnownMemberNames.GetResult, + Parameters: [] + }; } } } @@ -400,7 +389,7 @@ private static void CreateTypeParameterProperty(TagHelperDescriptorBuilder build pb.Name = typeParameter.Name; pb.TypeName = typeof(Type).FullName; - using var _ = ListPool>.GetPooledObject(out var metadataPairs); + using var _ = ListPool>.GetPooledObject(out var metadataPairs); metadataPairs.Add(PropertyName(typeParameter.Name)); metadataPairs.Add(MakeTrue(ComponentMetadata.Component.TypeParameterKey)); metadataPairs.Add(new(ComponentMetadata.Component.TypeParameterIsCascadingKey, cascade.ToString())); @@ -458,7 +447,7 @@ private static void CreateTypeParameterProperty(TagHelperDescriptorBuilder build builder.Name)); }); - static bool TryGetWhereClauseText(ITypeParameterSymbol typeParameter, PooledList constraints, [NotNullWhen(true)] out string constraintsText) + static bool TryGetWhereClauseText(ITypeParameterSymbol typeParameter, PooledList constraints, [NotNullWhen(true)] out string? constraintsText) { if (constraints.Count == 0) { @@ -547,7 +536,7 @@ private static TagHelperDescriptor CreateChildContentDescriptor(TagHelperDescrip return descriptor; } - private static void CreateContextParameter(TagHelperDescriptorBuilder builder, string childContentName) + private static void CreateContextParameter(TagHelperDescriptorBuilder builder, string? childContentName) { builder.BindAttribute(b => { @@ -579,9 +568,10 @@ private static void CreateContextParameter(TagHelperDescriptorBuilder builder, s using var names = new PooledHashSet(StringHashSetPool.Ordinal); using var results = new PooledArrayBuilder<(IPropertySymbol, PropertyKind)>(); + var currentType = type; do { - if (type.HasFullName(ComponentsApi.ComponentBase.MetadataName)) + if (currentType.HasFullName(ComponentsApi.ComponentBase.MetadataName)) { // The ComponentBase base class doesn't have any [Parameter]. // Bail out now to avoid walking through its many members, plus the members @@ -589,7 +579,7 @@ private static void CreateContextParameter(TagHelperDescriptorBuilder builder, s break; } - foreach (var member in type.GetMembers()) + foreach (var member in currentType.GetMembers()) { if (member is not IPropertySymbol property) { @@ -632,7 +622,7 @@ private static void CreateContextParameter(TagHelperDescriptorBuilder builder, s kind = PropertyKind.Ignored; } - if (!property.GetAttributes().Any(static a => a.AttributeClass.HasFullName(ComponentsApi.ParameterAttribute.MetadataName))) + if (!property.GetAttributes().Any(static a => a.HasFullName(ComponentsApi.ParameterAttribute.MetadataName))) { if (property.IsOverride) { @@ -661,9 +651,9 @@ var p when IsDelegate(p) => PropertyKind.Delegate, results.Add((property, kind)); } - type = type.BaseType; + currentType = currentType.BaseType; } - while (type != null); + while (currentType != null); return results.DrainToImmutable(); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/DefaultTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/DefaultTagHelperDescriptorProvider.cs index 4a7d1c98cc2..3953596d2f9 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/DefaultTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/DefaultTagHelperDescriptorProvider.cs @@ -1,25 +1,18 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - -using System; using System.Collections.Generic; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; namespace Microsoft.CodeAnalysis.Razor; -public sealed class DefaultTagHelperDescriptorProvider : RazorEngineFeatureBase, ITagHelperDescriptorProvider +public sealed class DefaultTagHelperDescriptorProvider : TagHelperDescriptorProviderBase { - public int Order { get; set; } - - public void Execute(TagHelperDescriptorProviderContext context) + public override void Execute(TagHelperDescriptorProviderContext context) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } + ArgHelper.ThrowIfNull(context); var compilation = context.Compilation; @@ -37,7 +30,7 @@ public void Execute(TagHelperDescriptorProviderContext context) } private class Collector( - Compilation compilation, ISymbol targetSymbol, DefaultTagHelperDescriptorFactory factory, INamedTypeSymbol tagHelperTypeSymbol) + Compilation compilation, ISymbol? targetSymbol, DefaultTagHelperDescriptorFactory factory, INamedTypeSymbol tagHelperTypeSymbol) : TagHelperCollector(compilation, targetSymbol) { private readonly DefaultTagHelperDescriptorFactory _factory = factory; diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/EventHandlerTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/EventHandlerTagHelperDescriptorProvider.cs index 7817c7fafa5..f89840fde8b 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/EventHandlerTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/EventHandlerTagHelperDescriptorProvider.cs @@ -1,10 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - -using System; using System.Collections.Generic; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; using Microsoft.AspNetCore.Razor.PooledObjects; @@ -12,18 +10,11 @@ namespace Microsoft.CodeAnalysis.Razor; -internal class EventHandlerTagHelperDescriptorProvider : ITagHelperDescriptorProvider +internal sealed class EventHandlerTagHelperDescriptorProvider : TagHelperDescriptorProviderBase { - public int Order { get; set; } - - public RazorEngine Engine { get; set; } - - public void Execute(TagHelperDescriptorProviderContext context) + public override void Execute(TagHelperDescriptorProviderContext context) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } + ArgHelper.ThrowIfNull(context); var compilation = context.Compilation; @@ -39,7 +30,7 @@ public void Execute(TagHelperDescriptorProviderContext context) collector.Collect(context); } - private class Collector(Compilation compilation, ISymbol targetSymbol, INamedTypeSymbol eventHandlerAttribute) + private class Collector(Compilation compilation, ISymbol? targetSymbol, INamedTypeSymbol eventHandlerAttribute) : TagHelperCollector(compilation, targetSymbol) { private readonly INamedTypeSymbol _eventHandlerAttribute = eventHandlerAttribute; @@ -63,30 +54,63 @@ protected override void Collect(ISymbol symbol, ICollection { if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, _eventHandlerAttribute)) { - var enablePreventDefault = false; - var enableStopPropagation = false; - if (attribute.ConstructorArguments.Length == 4) + if (!AttributeArgs.TryGet(attribute, out var values)) { - enablePreventDefault = (bool)attribute.ConstructorArguments[2].Value; - enableStopPropagation = (bool)attribute.ConstructorArguments[3].Value; + // If this occurs, the EventHandlerAttribute type has been broken. + Assumed.Unreachable(); } var (typeName, namespaceName) = displayNames.GetNames(); - var constructorArguments = attribute.ConstructorArguments; - - results.Add(CreateTagHelper( - typeName, - namespaceName, - type.Name, - (string)constructorArguments[0].Value, - (INamedTypeSymbol)constructorArguments[1].Value, - enablePreventDefault, - enableStopPropagation)); + results.Add(CreateTagHelper(typeName, namespaceName, type.Name, values)); } } } } + private readonly record struct AttributeArgs( + string Attribute, + INamedTypeSymbol EventArgsType, + bool EnableStopPropagation, + bool EnablePreventDefault) + { + public static bool TryGet(AttributeData attribute, out AttributeArgs args) + { + // EventHandlerAttribute has two constructors: + // + // - EventHandlerAttribute(string attributeName, Type eventArgsType); + // - EventHandlerAttribute(string attributeName, Type eventArgsType, bool enableStopPropagation, bool enablePreventDefault); + + args = default; + + var arguments = attribute.ConstructorArguments; + + if (arguments.Length is not (2 or 4)) + { + return false; + } + + if (arguments[0] is not { Value: string attributeName } || + arguments[1] is not { Value: INamedTypeSymbol eventArgsType }) + { + return false; + } + + // TODO: The enablePreventDefault and enableStopPropagation arguments are incorrectly swapped! + // However, they have been that way since the 4-argument constructor variant was introduced + // in https://github.com/dotnet/razor/commit/7635bba6ef2d3e6798d0846ceb96da6d5908e1b0. + // Fixing this is tracked be https://github.com/dotnet/razor/issues/10497 + + if (arguments is not [.., { Value: bool enablePreventDefault }, { Value: bool enableStopPropagation }]) + { + enableStopPropagation = false; + enablePreventDefault = false; + } + + args = new(attributeName, eventArgsType, enableStopPropagation, enablePreventDefault); + return true; + } + } + /// /// Helper to avoid computing various type-based names until necessary. /// @@ -108,11 +132,10 @@ private static TagHelperDescriptor CreateTagHelper( string typeName, string typeNamespace, string typeNameIdentifier, - string attribute, - INamedTypeSymbol eventArgsType, - bool enablePreventDefault, - bool enableStopPropagation) + AttributeArgs args) { + var (attribute, eventArgsType, enableStopPropagation, enablePreventDefault) = args; + var attributeName = "@" + attribute; var eventArgType = eventArgsType.ToDisplayString(); _ = TagHelperDescriptorBuilder.GetPooledInstance( diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/FormNameTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/FormNameTagHelperDescriptorProvider.cs index 208e1ecc038..c04ecadf5fc 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/FormNameTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/FormNameTagHelperDescriptorProvider.cs @@ -3,27 +3,21 @@ using System; using System.Linq; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; using static Microsoft.AspNetCore.Razor.Language.CommonMetadata; namespace Microsoft.CodeAnalysis.Razor; -internal sealed class FormNameTagHelperDescriptorProvider : ITagHelperDescriptorProvider +// Run after the component tag helper provider +internal sealed class FormNameTagHelperDescriptorProvider() : TagHelperDescriptorProviderBase(order: 1000) { private static readonly Lazy s_formNameTagHelper = new(CreateFormNameTagHelper); - // Run after the component tag helper provider - public int Order { get; set; } = 1000; - - public RazorEngine? Engine { get; set; } - - public void Execute(TagHelperDescriptorProviderContext context) + public override void Execute(TagHelperDescriptorProviderContext context) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } + ArgHelper.ThrowIfNull(context); var compilation = context.Compilation; diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/KeyTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/KeyTagHelperDescriptorProvider.cs index 359071fbc3e..0bafbe36bf6 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/KeyTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/KeyTagHelperDescriptorProvider.cs @@ -1,30 +1,22 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - using System; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; using static Microsoft.AspNetCore.Razor.Language.CommonMetadata; namespace Microsoft.CodeAnalysis.Razor; -internal class KeyTagHelperDescriptorProvider : ITagHelperDescriptorProvider +// Run after the component tag helper provider +internal sealed class KeyTagHelperDescriptorProvider() : TagHelperDescriptorProviderBase(order: 1000) { - private static TagHelperDescriptor s_keyTagHelper; - - // Run after the component tag helper provider - public int Order { get; set; } = 1000; + private static readonly Lazy s_keyTagHelper = new(CreateKeyTagHelper); - public RazorEngine Engine { get; set; } - - public void Execute(TagHelperDescriptorProviderContext context) + public override void Execute(TagHelperDescriptorProviderContext context) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } + ArgHelper.ThrowIfNull(context); var compilation = context.Compilation; @@ -41,50 +33,45 @@ public void Execute(TagHelperDescriptorProviderContext context) return; } - context.Results.Add(GetOrCreateKeyTagHelper()); + context.Results.Add(s_keyTagHelper.Value); } - private static TagHelperDescriptor GetOrCreateKeyTagHelper() + private static TagHelperDescriptor CreateKeyTagHelper() { - return s_keyTagHelper ??= CreateKeyTagHelper(); - - static TagHelperDescriptor CreateKeyTagHelper() - { - using var _ = TagHelperDescriptorBuilder.GetPooledInstance( - ComponentMetadata.Key.TagHelperKind, "Key", ComponentsApi.AssemblyName, - out var builder); + using var _ = TagHelperDescriptorBuilder.GetPooledInstance( + ComponentMetadata.Key.TagHelperKind, "Key", ComponentsApi.AssemblyName, + out var builder); - builder.CaseSensitive = true; - builder.SetDocumentation(DocumentationDescriptor.KeyTagHelper); + builder.CaseSensitive = true; + builder.SetDocumentation(DocumentationDescriptor.KeyTagHelper); - builder.SetMetadata( - SpecialKind(ComponentMetadata.Key.TagHelperKind), - MakeTrue(TagHelperMetadata.Common.ClassifyAttributesOnly), - RuntimeName(ComponentMetadata.Key.RuntimeName), - TypeName("Microsoft.AspNetCore.Components.Key")); + builder.SetMetadata( + SpecialKind(ComponentMetadata.Key.TagHelperKind), + MakeTrue(TagHelperMetadata.Common.ClassifyAttributesOnly), + RuntimeName(ComponentMetadata.Key.RuntimeName), + TypeName("Microsoft.AspNetCore.Components.Key")); - builder.TagMatchingRule(rule => + builder.TagMatchingRule(rule => + { + rule.TagName = "*"; + rule.Attribute(attribute => { - rule.TagName = "*"; - rule.Attribute(attribute => - { - attribute.Name = "@key"; - attribute.SetMetadata(Attributes.IsDirectiveAttribute); - }); + attribute.Name = "@key"; + attribute.SetMetadata(Attributes.IsDirectiveAttribute); }); + }); - builder.BindAttribute(attribute => - { - attribute.SetDocumentation(DocumentationDescriptor.KeyTagHelper); - attribute.Name = "@key"; + builder.BindAttribute(attribute => + { + attribute.SetDocumentation(DocumentationDescriptor.KeyTagHelper); + attribute.Name = "@key"; - attribute.TypeName = typeof(object).FullName; - attribute.SetMetadata( - PropertyName("Key"), - IsDirectiveAttribute); - }); + attribute.TypeName = typeof(object).FullName; + attribute.SetMetadata( + PropertyName("Key"), + IsDirectiveAttribute); + }); - return builder.Build(); - } + return builder.Build(); } } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RefTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RefTagHelperDescriptorProvider.cs index 40f50698d20..e6cb16f5489 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RefTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RefTagHelperDescriptorProvider.cs @@ -1,30 +1,22 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - using System; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; using static Microsoft.AspNetCore.Razor.Language.CommonMetadata; namespace Microsoft.CodeAnalysis.Razor; -internal class RefTagHelperDescriptorProvider : ITagHelperDescriptorProvider +// Run after the component tag helper provider, because later we may want component-type-specific variants of this +internal sealed class RefTagHelperDescriptorProvider() : TagHelperDescriptorProviderBase(order: 1000) { - private static TagHelperDescriptor s_refTagHelper; - - // Run after the component tag helper provider, because later we may want component-type-specific variants of this - public int Order { get; set; } = 1000; + private static readonly Lazy s_refTagHelper = new(CreateRefTagHelper); - public RazorEngine Engine { get; set; } - - public void Execute(TagHelperDescriptorProviderContext context) + public override void Execute(TagHelperDescriptorProviderContext context) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } + ArgHelper.ThrowIfNull(context); var compilation = context.Compilation; @@ -41,50 +33,45 @@ public void Execute(TagHelperDescriptorProviderContext context) return; } - context.Results.Add(GetOrCreateRefTagHelper()); + context.Results.Add(s_refTagHelper.Value); } - private static TagHelperDescriptor GetOrCreateRefTagHelper() + private static TagHelperDescriptor CreateRefTagHelper() { - return s_refTagHelper ??= CreateRefTagHelper(); - - static TagHelperDescriptor CreateRefTagHelper() - { - using var _ = TagHelperDescriptorBuilder.GetPooledInstance( - ComponentMetadata.Ref.TagHelperKind, "Ref", ComponentsApi.AssemblyName, - out var builder); + using var _ = TagHelperDescriptorBuilder.GetPooledInstance( + ComponentMetadata.Ref.TagHelperKind, "Ref", ComponentsApi.AssemblyName, + out var builder); - builder.CaseSensitive = true; - builder.SetDocumentation(DocumentationDescriptor.RefTagHelper); + builder.CaseSensitive = true; + builder.SetDocumentation(DocumentationDescriptor.RefTagHelper); - builder.SetMetadata( - SpecialKind(ComponentMetadata.Ref.TagHelperKind), - MakeTrue(TagHelperMetadata.Common.ClassifyAttributesOnly), - RuntimeName(ComponentMetadata.Ref.RuntimeName), - TypeName("Microsoft.AspNetCore.Components.Ref")); + builder.SetMetadata( + SpecialKind(ComponentMetadata.Ref.TagHelperKind), + MakeTrue(TagHelperMetadata.Common.ClassifyAttributesOnly), + RuntimeName(ComponentMetadata.Ref.RuntimeName), + TypeName("Microsoft.AspNetCore.Components.Ref")); - builder.TagMatchingRule(rule => + builder.TagMatchingRule(rule => + { + rule.TagName = "*"; + rule.Attribute(attribute => { - rule.TagName = "*"; - rule.Attribute(attribute => - { - attribute.Name = "@ref"; - attribute.SetMetadata(Attributes.IsDirectiveAttribute); - }); + attribute.Name = "@ref"; + attribute.SetMetadata(Attributes.IsDirectiveAttribute); }); + }); - builder.BindAttribute(attribute => - { - attribute.SetDocumentation(DocumentationDescriptor.RefTagHelper); - attribute.Name = "@ref"; + builder.BindAttribute(attribute => + { + attribute.SetDocumentation(DocumentationDescriptor.RefTagHelper); + attribute.Name = "@ref"; - attribute.TypeName = typeof(object).FullName; - attribute.SetMetadata( - PropertyName("Ref"), - IsDirectiveAttribute); - }); + attribute.TypeName = typeof(object).FullName; + attribute.SetMetadata( + PropertyName("Ref"), + IsDirectiveAttribute); + }); - return builder.Build(); - } + return builder.Build(); } } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RenderModeTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RenderModeTagHelperDescriptorProvider.cs index 8feb1499e26..a18227a82dd 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RenderModeTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/RenderModeTagHelperDescriptorProvider.cs @@ -1,30 +1,22 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable enable - using System; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; using static Microsoft.AspNetCore.Razor.Language.CommonMetadata; namespace Microsoft.CodeAnalysis.Razor; -internal sealed class RenderModeTagHelperDescriptorProvider : ITagHelperDescriptorProvider +// Run after the component tag helper provider +internal sealed class RenderModeTagHelperDescriptorProvider() : TagHelperDescriptorProviderBase(order: 1000) { - private static readonly Lazy s_refTagHelper = new(CreateRenderModeTagHelper); - - // Run after the component tag helper provider - public int Order { get; set; } = 1000; - - public RazorEngine? Engine { get; set; } + private static readonly Lazy s_renderModeTagHelper = new(CreateRenderModeTagHelper); - public void Execute(TagHelperDescriptorProviderContext context) + public override void Execute(TagHelperDescriptorProviderContext context) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } + ArgHelper.ThrowIfNull(context); var compilation = context.Compilation; @@ -41,7 +33,7 @@ public void Execute(TagHelperDescriptorProviderContext context) return; } - context.Results.Add(s_refTagHelper.Value); + context.Results.Add(s_renderModeTagHelper.Value); } private static TagHelperDescriptor CreateRenderModeTagHelper() diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SplatTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SplatTagHelperDescriptorProvider.cs index 5ec98d1eaa5..2db0111c0b7 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SplatTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SplatTagHelperDescriptorProvider.cs @@ -1,30 +1,21 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - using System; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; using static Microsoft.AspNetCore.Razor.Language.CommonMetadata; namespace Microsoft.CodeAnalysis.Razor; -internal class SplatTagHelperDescriptorProvider : ITagHelperDescriptorProvider +internal sealed class SplatTagHelperDescriptorProvider : TagHelperDescriptorProviderBase { - private static TagHelperDescriptor s_splatTagHelper; - - // Order doesn't matter - public int Order { get; set; } + private static readonly Lazy s_splatTagHelper = new(CreateSplatTagHelper); - public RazorEngine Engine { get; set; } - - public void Execute(TagHelperDescriptorProviderContext context) + public override void Execute(TagHelperDescriptorProviderContext context) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } + ArgHelper.ThrowIfNull(context); var compilation = context.Compilation; @@ -41,50 +32,45 @@ public void Execute(TagHelperDescriptorProviderContext context) return; } - context.Results.Add(GetOrCreateSplatTagHelper()); + context.Results.Add(s_splatTagHelper.Value); } - private static TagHelperDescriptor GetOrCreateSplatTagHelper() + private static TagHelperDescriptor CreateSplatTagHelper() { - return s_splatTagHelper ??= CreateSplatTagHelper(); - - static TagHelperDescriptor CreateSplatTagHelper() - { - using var _ = TagHelperDescriptorBuilder.GetPooledInstance( - ComponentMetadata.Splat.TagHelperKind, "Attributes", ComponentsApi.AssemblyName, - out var builder); + using var _ = TagHelperDescriptorBuilder.GetPooledInstance( + ComponentMetadata.Splat.TagHelperKind, "Attributes", ComponentsApi.AssemblyName, + out var builder); - builder.CaseSensitive = true; - builder.SetDocumentation(DocumentationDescriptor.SplatTagHelper); + builder.CaseSensitive = true; + builder.SetDocumentation(DocumentationDescriptor.SplatTagHelper); - builder.SetMetadata( - SpecialKind(ComponentMetadata.Splat.TagHelperKind), - MakeTrue(TagHelperMetadata.Common.ClassifyAttributesOnly), - RuntimeName(ComponentMetadata.Splat.RuntimeName), - TypeName("Microsoft.AspNetCore.Components.Attributes")); + builder.SetMetadata( + SpecialKind(ComponentMetadata.Splat.TagHelperKind), + MakeTrue(TagHelperMetadata.Common.ClassifyAttributesOnly), + RuntimeName(ComponentMetadata.Splat.RuntimeName), + TypeName("Microsoft.AspNetCore.Components.Attributes")); - builder.TagMatchingRule(rule => + builder.TagMatchingRule(rule => + { + rule.TagName = "*"; + rule.Attribute(attribute => { - rule.TagName = "*"; - rule.Attribute(attribute => - { - attribute.Name = "@attributes"; - attribute.SetMetadata(Attributes.IsDirectiveAttribute); - }); + attribute.Name = "@attributes"; + attribute.SetMetadata(Attributes.IsDirectiveAttribute); }); + }); - builder.BindAttribute(attribute => - { - attribute.SetDocumentation(DocumentationDescriptor.SplatTagHelper); - attribute.Name = "@attributes"; + builder.BindAttribute(attribute => + { + attribute.SetDocumentation(DocumentationDescriptor.SplatTagHelper); + attribute.Name = "@attributes"; - attribute.TypeName = typeof(object).FullName; - attribute.SetMetadata( - PropertyName("Attributes"), - IsDirectiveAttribute); - }); + attribute.TypeName = typeof(object).FullName; + attribute.SetMetadata( + PropertyName("Attributes"), + IsDirectiveAttribute); + }); - return builder.Build(); - } + return builder.Build(); } } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SymbolExtensions.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SymbolExtensions.cs index e9bc59e3480..a280e8db8a4 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SymbolExtensions.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/SymbolExtensions.cs @@ -13,6 +13,9 @@ internal static class SymbolExtensions .WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted) .RemoveMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.UseSpecialTypes); + internal static bool HasFullName(this AttributeData attribute, string fullName) + => attribute.AttributeClass is { } attributeClass && attributeClass.HasFullName(fullName); + /// /// Checks if has the same fully qualified name as . /// diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderBase.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderBase.cs new file mode 100644 index 00000000000..0ab7a8355cb --- /dev/null +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDescriptorProviderBase.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Razor.Language; + +public abstract class TagHelperDescriptorProviderBase(int order = 0) : RazorEngineFeatureBase, ITagHelperDescriptorProvider +{ + public int Order { get; } = order; + + public abstract void Execute(TagHelperDescriptorProviderContext context); +} diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version1_X/ViewComponentTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version1_X/ViewComponentTagHelperDescriptorProvider.cs index 70ed5efa619..abddce93827 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version1_X/ViewComponentTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version1_X/ViewComponentTagHelperDescriptorProvider.cs @@ -1,26 +1,19 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - -using System; using System.Collections.Generic; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X; -public sealed class ViewComponentTagHelperDescriptorProvider : RazorEngineFeatureBase, ITagHelperDescriptorProvider +public sealed class ViewComponentTagHelperDescriptorProvider : TagHelperDescriptorProviderBase { - public int Order { get; set; } - - public void Execute(TagHelperDescriptorProviderContext context) + public override void Execute(TagHelperDescriptorProviderContext context) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } + ArgHelper.ThrowIfNull(context); var compilation = context.Compilation; @@ -42,12 +35,12 @@ private class Collector( Compilation compilation, ViewComponentTagHelperDescriptorFactory factory, INamedTypeSymbol vcAttribute, - INamedTypeSymbol nonVCAttribute) + INamedTypeSymbol? nonVCAttribute) : TagHelperCollector(compilation, targetSymbol: null) { private readonly ViewComponentTagHelperDescriptorFactory _factory = factory; private readonly INamedTypeSymbol _vcAttribute = vcAttribute; - private readonly INamedTypeSymbol _nonVCAttribute = nonVCAttribute; + private readonly INamedTypeSymbol? _nonVCAttribute = nonVCAttribute; protected override void Collect(ISymbol symbol, ICollection results) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version1_X/ViewComponentTypeVisitor.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version1_X/ViewComponentTypeVisitor.cs index 2baa96bc20e..610fa47c60b 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version1_X/ViewComponentTypeVisitor.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version1_X/ViewComponentTypeVisitor.cs @@ -1,23 +1,21 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - using System; using System.Collections.Generic; using Microsoft.CodeAnalysis; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X; -internal class ViewComponentTypeVisitor : SymbolVisitor +internal sealed class ViewComponentTypeVisitor : SymbolVisitor { private readonly INamedTypeSymbol _viewComponentAttribute; - private readonly INamedTypeSymbol _nonViewComponentAttribute; + private readonly INamedTypeSymbol? _nonViewComponentAttribute; private readonly List _results; public ViewComponentTypeVisitor( INamedTypeSymbol viewComponentAttribute, - INamedTypeSymbol nonViewComponentAttribute, + INamedTypeSymbol? nonViewComponentAttribute, List results) { _viewComponentAttribute = viewComponentAttribute; @@ -65,7 +63,7 @@ internal bool IsViewComponent(INamedTypeSymbol symbol) AttributeIsDefined(symbol, _viewComponentAttribute); } - private static bool AttributeIsDefined(INamedTypeSymbol type, INamedTypeSymbol queryAttribute) + private static bool AttributeIsDefined(INamedTypeSymbol? type, INamedTypeSymbol? queryAttribute) { if (type == null || queryAttribute == null) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version2_X/ViewComponentTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version2_X/ViewComponentTagHelperDescriptorProvider.cs index a3c6c11d5d9..6058ae7ae52 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version2_X/ViewComponentTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version2_X/ViewComponentTagHelperDescriptorProvider.cs @@ -1,26 +1,19 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - -using System; using System.Collections.Generic; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X; -public sealed class ViewComponentTagHelperDescriptorProvider : RazorEngineFeatureBase, ITagHelperDescriptorProvider +public sealed class ViewComponentTagHelperDescriptorProvider : TagHelperDescriptorProviderBase { - public int Order { get; set; } - - public void Execute(TagHelperDescriptorProviderContext context) + public override void Execute(TagHelperDescriptorProviderContext context) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } + ArgHelper.ThrowIfNull(context); var compilation = context.Compilation; @@ -42,12 +35,12 @@ private class Collector( Compilation compilation, ViewComponentTagHelperDescriptorFactory factory, INamedTypeSymbol vcAttribute, - INamedTypeSymbol nonVCAttribute) + INamedTypeSymbol? nonVCAttribute) : TagHelperCollector(compilation, targetSymbol: null) { private readonly ViewComponentTagHelperDescriptorFactory _factory = factory; private readonly INamedTypeSymbol _vcAttribute = vcAttribute; - private readonly INamedTypeSymbol _nonVCAttribute = nonVCAttribute; + private readonly INamedTypeSymbol? _nonVCAttribute = nonVCAttribute; protected override void Collect(ISymbol symbol, ICollection results) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version2_X/ViewComponentTypeVisitor.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version2_X/ViewComponentTypeVisitor.cs index cb1ff06f5ca..7e2b8240fb5 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version2_X/ViewComponentTypeVisitor.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc.Version2_X/ViewComponentTypeVisitor.cs @@ -1,23 +1,21 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - using System; using System.Collections.Generic; using Microsoft.CodeAnalysis; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X; -internal class ViewComponentTypeVisitor : SymbolVisitor +internal sealed class ViewComponentTypeVisitor : SymbolVisitor { private readonly INamedTypeSymbol _viewComponentAttribute; - private readonly INamedTypeSymbol _nonViewComponentAttribute; + private readonly INamedTypeSymbol? _nonViewComponentAttribute; private readonly List _results; public ViewComponentTypeVisitor( INamedTypeSymbol viewComponentAttribute, - INamedTypeSymbol nonViewComponentAttribute, + INamedTypeSymbol? nonViewComponentAttribute, List results) { _viewComponentAttribute = viewComponentAttribute; @@ -70,7 +68,7 @@ internal bool IsViewComponent(INamedTypeSymbol symbol) AttributeIsDefined(symbol, _viewComponentAttribute); } - private static bool AttributeIsDefined(INamedTypeSymbol type, INamedTypeSymbol queryAttribute) + private static bool AttributeIsDefined(INamedTypeSymbol? type, INamedTypeSymbol? queryAttribute) { if (type == null || queryAttribute == null) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc/ViewComponentTagHelperDescriptorProvider.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc/ViewComponentTagHelperDescriptorProvider.cs index 178508686ac..2159ce7a07b 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc/ViewComponentTagHelperDescriptorProvider.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc/ViewComponentTagHelperDescriptorProvider.cs @@ -1,26 +1,19 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - -using System; using System.Collections.Generic; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions; -public sealed class ViewComponentTagHelperDescriptorProvider : RazorEngineFeatureBase, ITagHelperDescriptorProvider +public sealed class ViewComponentTagHelperDescriptorProvider : TagHelperDescriptorProviderBase { - public int Order { get; set; } - - public void Execute(TagHelperDescriptorProviderContext context) + public override void Execute(TagHelperDescriptorProviderContext context) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } + ArgHelper.ThrowIfNull(context); var compilation = context.Compilation; @@ -42,12 +35,12 @@ private class Collector( Compilation compilation, ViewComponentTagHelperDescriptorFactory factory, INamedTypeSymbol vcAttribute, - INamedTypeSymbol nonVCAttribute) + INamedTypeSymbol? nonVCAttribute) : TagHelperCollector(compilation, targetSymbol: null) { private readonly ViewComponentTagHelperDescriptorFactory _factory = factory; private readonly INamedTypeSymbol _vcAttribute = vcAttribute; - private readonly INamedTypeSymbol _nonVCAttribute = nonVCAttribute; + private readonly INamedTypeSymbol? _nonVCAttribute = nonVCAttribute; protected override void Collect(ISymbol symbol, ICollection results) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc/ViewComponentTypeVisitor.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc/ViewComponentTypeVisitor.cs index d7a48e6494f..96f3982c579 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc/ViewComponentTypeVisitor.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Mvc/ViewComponentTypeVisitor.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - using System; using System.Collections.Generic; using Microsoft.CodeAnalysis; @@ -12,12 +10,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions; internal class ViewComponentTypeVisitor : SymbolVisitor { private readonly INamedTypeSymbol _viewComponentAttribute; - private readonly INamedTypeSymbol _nonViewComponentAttribute; + private readonly INamedTypeSymbol? _nonViewComponentAttribute; private readonly List _results; public ViewComponentTypeVisitor( INamedTypeSymbol viewComponentAttribute, - INamedTypeSymbol nonViewComponentAttribute, + INamedTypeSymbol? nonViewComponentAttribute, List results) { _viewComponentAttribute = viewComponentAttribute; @@ -75,7 +73,7 @@ internal bool IsViewComponent(INamedTypeSymbol symbol) AttributeIsDefined(symbol, _viewComponentAttribute); } - private static bool AttributeIsDefined(INamedTypeSymbol type, INamedTypeSymbol queryAttribute) + private static bool AttributeIsDefined(INamedTypeSymbol? type, INamedTypeSymbol? queryAttribute) { if (type == null || queryAttribute == null) { From 9f6c7b6186f9a30f785ac9c8531bdcfcffde08ac Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Thu, 8 Aug 2024 13:16:01 -0700 Subject: [PATCH 49/53] Clean up CompilationTagHelperResolver --- .../CompilationTagHelperResolver.cs | 63 +++++++------------ .../Telemetry/ITelemetryReporter.cs | 2 +- .../Telemetry/NoOpTelemetryReporter.cs | 2 +- .../Telemetry/TelemetryReporter.cs | 2 +- 4 files changed, 26 insertions(+), 43 deletions(-) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs index 73e1d766d06..05b2edf83cd 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/CompilationTagHelperResolver.cs @@ -1,8 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; -using System.Collections.Generic; +using System.Buffers; using System.Collections.Immutable; using System.Linq; using System.Threading; @@ -15,70 +14,54 @@ namespace Microsoft.AspNetCore.Razor; -internal class CompilationTagHelperResolver(ITelemetryReporter? telemetryReporter) +internal sealed class CompilationTagHelperResolver(ITelemetryReporter telemetryReporter) { - private readonly ITelemetryReporter? _telemetryReporter = telemetryReporter; + private readonly ITelemetryReporter _telemetryReporter = telemetryReporter; public async ValueTask> GetTagHelpersAsync( - Project workspaceProject, + Project project, RazorProjectEngine projectEngine, CancellationToken cancellationToken) { - if (workspaceProject is null) - { - throw new ArgumentNullException(nameof(workspaceProject)); - } - - if (projectEngine is null) - { - throw new ArgumentNullException(nameof(projectEngine)); - } + var providers = projectEngine.Engine.Features + .OfType() + .OrderBy(static f => f.Order) + .ToImmutableArray(); - var providers = projectEngine.Engine.Features.OfType().OrderBy(f => f.Order).ToArray(); - if (providers.Length == 0) + if (providers is []) { return []; } - var compilation = await workspaceProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false); + var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); if (compilation is null || !CompilationTagHelperFeature.IsValidCompilation(compilation)) { return []; } - using var _ = HashSetPool.GetPooledObject(out var results); + using var pooledHashSet = HashSetPool.GetPooledObject(out var results); + using var pooledWatch = StopwatchPool.GetPooledObject(out var watch); + using var pooledSpan = ArrayPool.Shared.GetPooledArraySpan(minimumLength: providers.Length, out var properties); + var context = new TagHelperDescriptorProviderContext(compilation, results) { ExcludeHidden = true, IncludeDocumentation = true }; - ExecuteProviders(providers, context, _telemetryReporter); - - return results.ToImmutableArray(); - - static void ExecuteProviders(ITagHelperDescriptorProvider[] providers, TagHelperDescriptorProviderContext context, ITelemetryReporter? telemetryReporter) + for (var i = 0; i < providers.Length; i++) { - using var _ = StopwatchPool.GetPooledObject(out var watch); + var provider = providers[i]; - Property[]? properties = null; + watch.Restart(); + provider.Execute(context); + watch.Stop(); - for (var i = 0; i < providers.Length; i++) - { - var provider = providers[i]; - watch.Restart(); - provider.Execute(context); - watch.Stop(); + properties[i] = new($"{provider.GetType().Name}.elapsedtimems", watch.ElapsedMilliseconds); + } - if (telemetryReporter is not null) - { - properties ??= new Property[providers.Length]; - var propertyName = $"{provider.GetType().Name}.elapsedtimems"; - properties[i] = new(propertyName, watch.ElapsedMilliseconds); - } - } + _telemetryReporter.ReportEvent("taghelperresolver/gettaghelpers", Severity.Normal, properties); - telemetryReporter?.ReportEvent("taghelperresolver/gettaghelpers", Severity.Normal, properties.AssumeNotNull()); - } + return [.. results]; } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporter.cs index 0530e181e21..7f0814a98b6 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporter.cs @@ -19,7 +19,7 @@ internal interface ITelemetryReporter void ReportEvent(string name, Severity severity, Property property); void ReportEvent(string name, Severity severity, Property property1, Property property2); void ReportEvent(string name, Severity severity, Property property1, Property property2, Property property3); - void ReportEvent(string name, Severity severity, params Property[] properties); + void ReportEvent(string name, Severity severity, params ReadOnlySpan properties); void ReportFault(Exception exception, string? message, params object?[] @params); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/NoOpTelemetryReporter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/NoOpTelemetryReporter.cs index 29dcb3101a7..28a937da055 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/NoOpTelemetryReporter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/NoOpTelemetryReporter.cs @@ -44,7 +44,7 @@ public void ReportEvent(string name, Severity severity, Property property1, Prop { } - public void ReportEvent(string name, Severity severity, params Property[] properties) + public void ReportEvent(string name, Severity severity, params ReadOnlySpan properties) { } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/TelemetryReporter.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/TelemetryReporter.cs index 7542ae4a7b6..f6de565c009 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/TelemetryReporter.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/TelemetryReporter.cs @@ -72,7 +72,7 @@ public void ReportEvent(string name, Severity severity, Property property1, Prop Report(telemetryEvent); } - public void ReportEvent(string name, Severity severity, params Property[] properties) + public void ReportEvent(string name, Severity severity, params ReadOnlySpan properties) { var telemetryEvent = new TelemetryEvent(GetEventName(name), ConvertSeverity(severity)); From 79b2d26a8086d353e2595307a717494302919780 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Fri, 9 Aug 2024 08:46:36 +1000 Subject: [PATCH 50/53] I spent 10 minutes looking up cool Mr Freeze catch phrases for this commit message, and I didn't like any of them. --- .../Diagnostics/RazorTranslateDiagnosticsService.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs index f93731a0c75..9efb5b39ee5 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; +using System.Collections.Frozen; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -36,11 +37,11 @@ internal class RazorTranslateDiagnosticsService(IDocumentMappingService document private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); private readonly IDocumentMappingService _documentMappingService = documentMappingService; - private static readonly HashSet s_cSharpDiagnosticsToIgnore = + private static readonly FrozenSet s_cSharpDiagnosticsToIgnore = new HashSet( [ "RemoveUnnecessaryImportsFixable", "IDE0005_gen", // Using directive is unnecessary - ]; + ]).ToFrozenSet(); /// /// Translates code diagnostics from one representation into another. From 4441e1da03c936bae21e5c983ce6372184c5c98f Mon Sep 17 00:00:00 2001 From: David Wengier Date: Fri, 9 Aug 2024 13:46:11 +1000 Subject: [PATCH 51/53] Unskip rename tests --- .../RenameTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RenameTests.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RenameTests.cs index 7dad7fb8f87..996df573f0e 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RenameTests.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RenameTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests; public class RenameTests(ITestOutputHelper testOutputHelper) : AbstractRazorEditorTest(testOutputHelper) { - [ConditionalSkipIdeFact(Issue = "https://github.com/dotnet/razor/issues/8121")] + [IdeFact] public async Task Rename_ComponentAttribute_FromRazor() { // Open the file @@ -36,7 +36,7 @@ public async Task Rename_ComponentAttribute_FromRazor() await TestServices.Editor.VerifyTextContainsAsync(" Date: Fri, 9 Aug 2024 16:26:30 +1000 Subject: [PATCH 52/53] Try to fix rename tests --- .../InProcess/RazorProjectSystemInProcess.cs | 24 ++++++++++++++++ .../InProcess/SolutionExplorerInProcess.cs | 28 ++++++------------- .../RenameTests.cs | 23 ++++++++------- 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/RazorProjectSystemInProcess.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/RazorProjectSystemInProcess.cs index 168c4c5c0fd..04f8659b0f8 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/RazorProjectSystemInProcess.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/RazorProjectSystemInProcess.cs @@ -12,6 +12,7 @@ using Microsoft.VisualStudio.Razor.LanguageClient; using Microsoft.AspNetCore.Razor.Threading; using System.Collections.Immutable; +using System.Linq; namespace Microsoft.VisualStudio.Extensibility.Testing; @@ -53,6 +54,29 @@ await Helper.RetryAsync(ct => }, TimeSpan.FromMilliseconds(100), cancellationToken); } + public async Task WaitForComponentTagNameAsync(string projectName, string componentName, CancellationToken cancellationToken) + { + var projectFileName = await TestServices.SolutionExplorer.GetProjectFileNameAsync(projectName, cancellationToken); + var projectManager = await TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); + Assert.NotNull(projectManager); + await Helper.RetryAsync(async ct => + { + var projectKeys = projectManager.GetAllProjectKeys(projectFileName); + if (projectKeys.Length == 0) + { + return false; + } + + if (!projectManager.TryGetLoadedProject(projectKeys[0], out var project)) + { + return false; + } + + var tagHelpers = await project.GetTagHelpersAsync(cancellationToken); + return tagHelpers.Any(tagHelper => tagHelper.TagMatchingRules.Any(r => r.TagName.Equals(componentName, StringComparison.Ordinal))); + }, TimeSpan.FromMilliseconds(100), cancellationToken); + } + public async Task WaitForRazorFileInProjectAsync(string projectFilePath, string filePath, CancellationToken cancellationToken) { var projectSnapshotManager = await TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/SolutionExplorerInProcess.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/SolutionExplorerInProcess.cs index c08dad916eb..04e8d3e162d 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/SolutionExplorerInProcess.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/SolutionExplorerInProcess.cs @@ -155,24 +155,6 @@ public async Task AddFileAsync(string projectName, string fileName, string? cont } } - internal async Task WaitForComponentAsync(string projectName, string componentName, CancellationToken cancellationToken) - { - var project = await GetProjectAsync(projectName, cancellationToken); - - var localPath = (string)project.Properties.Item("LocalPath").Value; - var style = "Debug"; - var framework = "net6.0"; - - var razorJsonPath = Path.Combine(localPath, "obj", style, framework, "project.razor.vs.bin"); - - await Helper.RetryAsync(ct => - { - var jsonContents = File.ReadAllText(razorJsonPath); - - return Task.FromResult(jsonContents.Contains($"TypeNameIdentifier\":\"{componentName}\"")); - }, TimeSpan.FromSeconds(1), cancellationToken); - } - /// /// The summary line for the build, which generally looks something like this: /// @@ -291,6 +273,13 @@ private static string ConvertLanguageName(string languageName) } public async Task GetAbsolutePathForProjectRelativeFilePathAsync(string projectName, string relativeFilePath, CancellationToken cancellationToken) + { + var projectFileName = await GetProjectFileNameAsync(projectName, cancellationToken); + var projectPath = Path.GetDirectoryName(projectFileName); + return Path.Combine(projectPath, relativeFilePath); + } + + public async Task GetProjectFileNameAsync(string projectName, CancellationToken cancellationToken) { await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); @@ -306,8 +295,7 @@ public async Task GetAbsolutePathForProjectRelativeFilePathAsync(string } Assert.NotNull(project); - var projectPath = Path.GetDirectoryName(project.FullName); - return Path.Combine(projectPath, relativeFilePath); + return project.FullName; } public async Task GetDirectoryNameAsync(CancellationToken cancellationToken) diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RenameTests.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RenameTests.cs index 996df573f0e..37e533b0cca 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RenameTests.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RenameTests.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System.Threading; using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; @@ -90,7 +89,7 @@ public partial class MyComponent """, open: true, cancellationToken: ControlledHangMitigatingCancellationToken); - await WaitForComponentInitializeAsync(RazorProjectConstants.BlazorProjectName, "MyComponent", ControlledHangMitigatingCancellationToken); + await TestServices.RazorProjectSystem.WaitForComponentTagNameAsync(RazorProjectConstants.BlazorProjectName, "MyComponent", ControlledHangMitigatingCancellationToken); await TestServices.Editor.CloseCodeFileAsync(RazorProjectConstants.BlazorProjectName, MyComponentCSharpPath, saveFile: true, ControlledHangMitigatingCancellationToken); await TestServices.SolutionExplorer.AddFileAsync(RazorProjectConstants.BlazorProjectName, @@ -107,6 +106,10 @@ await TestServices.SolutionExplorer.AddFileAsync(RazorProjectConstants.BlazorPro await TestServices.Editor.PlaceCaretAsync("MyProperty", charsOffset: 0, occurrence: 2, extendSelection: false, selectBlock: false, ControlledHangMitigatingCancellationToken); + await TestServices.RazorProjectSystem.WaitForComponentTagNameAsync(RazorProjectConstants.BlazorProjectName, "MyPage", ControlledHangMitigatingCancellationToken); + + await Task.Delay(500); + // Act await TestServices.Editor.InvokeRenameAsync(ControlledHangMitigatingCancellationToken); TestServices.Input.Send("ZooperDooper{ENTER}"); @@ -116,11 +119,11 @@ await TestServices.SolutionExplorer.AddFileAsync(RazorProjectConstants.BlazorPro await TestServices.Editor.WaitForActiveWindowByFileAsync("MyComponent.razor.cs", ControlledHangMitigatingCancellationToken); await TestServices.Editor.VerifyTextContainsAsync("public string? ZooperDooper { get; set; }", ControlledHangMitigatingCancellationToken); - await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, "MyPage.razor", ControlledHangMitigatingCancellationToken); - await TestServices.Editor.VerifyTextContainsAsync("", ControlledHangMitigatingCancellationToken); } - - private async Task WaitForComponentInitializeAsync(string projectName, string componentName, CancellationToken cancellationToken) - { - // Wait for it to initialize by building - await TestServices.SolutionExplorer.WaitForComponentAsync(projectName, componentName, cancellationToken); - } } From cd1f82be2156e147cd63535f0179e7a91c049749 Mon Sep 17 00:00:00 2001 From: Jared Parsons Date: Fri, 9 Aug 2024 15:26:39 -0700 Subject: [PATCH 53/53] Move to central package pinning (#10716) * Move to central package pinning This should make it much easier for us to respond to CG alerts in the future. All that will need to be done is add an entry in Directory.Packages.props and it will automatically impact all consumers of it. Consider this example in Roslyn for how to respond to a CG issue https://github.com/dotnet/roslyn/pull/74653 --- Directory.Build.props | 1 + Directory.Packages.props | 12 ++++++------ ...soft.AspNetCore.Razor.Language.Legacy.Test.csproj | 3 +++ .../Microsoft.AspNetCore.Razor.Language.Test.csproj | 3 +++ ...AspNetCore.Razor.Microbenchmarks.Generator.csproj | 6 ++++-- ...rosoft.NET.Sdk.Razor.SourceGenerators.Test.csproj | 2 ++ 6 files changed, 19 insertions(+), 8 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index d2e322d1332..69a3cd1524c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -26,6 +26,7 @@ $(MSBuildThisFileDirectory) true true + true $(MSBuildThisFileDirectory)src\Shared\ diff --git a/Directory.Packages.props b/Directory.Packages.props index 4e2bdea802f..86b4aa1bca0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -16,7 +16,7 @@ <_MicrosoftCodeAnalysisAnalyzersPackageVersion>3.11.0-beta1.24170.2 <_MicrosoftVisualStudioLanguageServicesPackageVersion>$(MicrosoftVisualStudioLanguageServicesPackageVersion) <_XunitPackageVersion>2.6.3 - <_MicrosoftBuildPackageVersion>17.3.0-preview-22364-05 + <_MicrosoftBuildPackageVersion>17.11.0-preview-24309-01 @@ -89,7 +89,7 @@ - + @@ -109,13 +109,13 @@ - - + + - + - + diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Microsoft.AspNetCore.Razor.Language.Legacy.Test.csproj b/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Microsoft.AspNetCore.Razor.Language.Legacy.Test.csproj index 7b16714b910..160c21c8ca7 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Microsoft.AspNetCore.Razor.Language.Legacy.Test.csproj +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Microsoft.AspNetCore.Razor.Language.Legacy.Test.csproj @@ -21,6 +21,9 @@ + + + diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Microsoft.AspNetCore.Razor.Language.Test.csproj b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Microsoft.AspNetCore.Razor.Language.Test.csproj index f60fafca607..c0579b84329 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Microsoft.AspNetCore.Razor.Language.Test.csproj +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Microsoft.AspNetCore.Razor.Language.Test.csproj @@ -21,6 +21,9 @@ + + + diff --git a/src/Compiler/perf/Microsoft.AspNetCore.Razor.Microbenchmarks.Generator/Microsoft.AspNetCore.Razor.Microbenchmarks.Generator.csproj b/src/Compiler/perf/Microsoft.AspNetCore.Razor.Microbenchmarks.Generator/Microsoft.AspNetCore.Razor.Microbenchmarks.Generator.csproj index 67034ffdb99..aebe9633fef 100644 --- a/src/Compiler/perf/Microsoft.AspNetCore.Razor.Microbenchmarks.Generator/Microsoft.AspNetCore.Razor.Microbenchmarks.Generator.csproj +++ b/src/Compiler/perf/Microsoft.AspNetCore.Razor.Microbenchmarks.Generator/Microsoft.AspNetCore.Razor.Microbenchmarks.Generator.csproj @@ -21,8 +21,10 @@ - - + + + + diff --git a/src/Compiler/test/Microsoft.NET.Sdk.Razor.SourceGenerators.Tests/Microsoft.NET.Sdk.Razor.SourceGenerators.Test.csproj b/src/Compiler/test/Microsoft.NET.Sdk.Razor.SourceGenerators.Tests/Microsoft.NET.Sdk.Razor.SourceGenerators.Test.csproj index 73ee7b956d3..4d1acf312b7 100644 --- a/src/Compiler/test/Microsoft.NET.Sdk.Razor.SourceGenerators.Tests/Microsoft.NET.Sdk.Razor.SourceGenerators.Test.csproj +++ b/src/Compiler/test/Microsoft.NET.Sdk.Razor.SourceGenerators.Tests/Microsoft.NET.Sdk.Razor.SourceGenerators.Test.csproj @@ -25,6 +25,8 @@ + +