Skip to content

Commit c150d20

Browse files
authored
Allow for weird Uris as file paths (#12155)
Part of fixing https://github.com/dotnet/razor/issues/10437 along with dotnet/roslyn#80068
2 parents aaefcae + 2bc3bdd commit c150d20

File tree

4 files changed

+70
-9
lines changed

4 files changed

+70
-9
lines changed

src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.AspNetCore.Razor;
99
using Microsoft.AspNetCore.Razor.Language;
1010
using Microsoft.AspNetCore.Razor.PooledObjects;
11+
using Microsoft.AspNetCore.Razor.Utilities;
1112
using Microsoft.CodeAnalysis;
1213
using Microsoft.CodeAnalysis.CSharp;
1314

@@ -54,7 +55,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
5455
.ReportDiagnostics(context);
5556

5657
var sourceItems = additionalTexts
57-
.Where(static (file) => file.Path.EndsWith(".razor", StringComparison.OrdinalIgnoreCase) || file.Path.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase))
58+
.Where(static (file) => FileUtilities.IsAnyRazorFilePath(file.Path, StringComparison.OrdinalIgnoreCase))
5859
.Combine(analyzerConfigOptions)
5960
.Select(ComputeProjectItems)
6061
.ReportDiagnostics(context);
@@ -79,7 +80,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
7980
return false;
8081
});
8182

82-
var componentFiles = sourceItems.Where(static file => file.FilePath.EndsWith(".razor", StringComparison.OrdinalIgnoreCase));
83+
var componentFiles = sourceItems.Where(static file => FileUtilities.IsRazorComponentFilePath(file.FilePath, StringComparison.OrdinalIgnoreCase));
8384

8485
var generatedDeclarationText = componentFiles
8586
.Combine(importFiles.Collect())

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/StringExtensions.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,17 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using Microsoft.AspNetCore.Razor;
5+
using Microsoft.AspNetCore.Razor.Utilities;
56

67
namespace Microsoft.CodeAnalysis.Razor;
78

89
internal static class StringExtensions
910
{
10-
private const string RazorExtension = ".razor";
11-
private const string CSHtmlExtension = ".cshtml";
12-
1311
public static bool IsRazorFilePath(this string filePath)
1412
{
1513
var comparison = PathUtilities.OSSpecificPathComparison;
1614

17-
return filePath.EndsWith(RazorExtension, comparison) ||
18-
filePath.EndsWith(CSHtmlExtension, comparison);
15+
return FileUtilities.IsAnyRazorFilePath(filePath, comparison);
1916
}
2017

2118
public static int? GetFirstNonWhitespaceOffset(this string line)

src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostFoldingRangeEndpointTest.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,30 @@ namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
1717

1818
public class CohostFoldingRangeEndpointTest(ITestOutputHelper testOutputHelper) : CohostEndpointTestBase(testOutputHelper)
1919
{
20+
[Fact]
21+
public Task BadLooseFileUri()
22+
=> VerifyFoldingRangesAsync("""
23+
<div>
24+
@if (true) {[|
25+
<div>
26+
Hello World
27+
</div>
28+
}
29+
|]</div>
30+
31+
@if (true) {[|
32+
<div>
33+
Hello World
34+
</div>
35+
}
36+
|]
37+
@if (true) {[|
38+
}|]
39+
""",
40+
fileKind: RazorFileKind.Legacy,
41+
miscellaneousFile: true,
42+
razorFilePath: "git:/c:/Users/dawengie/source/repos/razor01/Pages/Index.cshtml?%7B%22path%22:%22c:%5C%5CUsers%5C%5Cdawengie%5C%5Csource%5C%5Crepos%5C%5Crazor01%5C%5CPages%5C%5CIndex.cshtml%22,%22ref%22:%22~%22%7D");
43+
2044
[Theory]
2145
[CombinatorialData]
2246
public Task IfStatements(bool miscellaneousFile)
@@ -215,10 +239,10 @@ public void M() {[|
215239
}|]
216240
""");
217241

218-
private async Task VerifyFoldingRangesAsync(string input, RazorFileKind? fileKind = null, bool miscellaneousFile = false)
242+
private async Task VerifyFoldingRangesAsync(string input, RazorFileKind? fileKind = null, bool miscellaneousFile = false, string? razorFilePath = null)
219243
{
220244
TestFileMarkupParser.GetSpans(input, out var source, out ImmutableDictionary<string, ImmutableArray<TextSpan>> spans);
221-
var document = CreateProjectAndRazorDocument(source, fileKind, miscellaneousFile: miscellaneousFile);
245+
var document = CreateProjectAndRazorDocument(source, fileKind, miscellaneousFile: miscellaneousFile, documentFilePath: razorFilePath);
222246
var inputText = await document.GetTextAsync(DisposalToken);
223247

224248
var htmlSpans = spans.GetValueOrDefault("html").NullToEmpty();

src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/FileUtilities.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,52 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
45
using System.Globalization;
56
using System.IO;
67

78
namespace Microsoft.AspNetCore.Razor.Utilities;
89

910
internal static class FileUtilities
1011
{
12+
private const string RazorExtension = ".razor";
13+
private const string CSHtmlExtension = ".cshtml";
14+
15+
public static bool IsAnyRazorFilePath(ReadOnlySpan<char> filePath, StringComparison comparison)
16+
{
17+
return IsRazorComponentFilePath(filePath, comparison) ||
18+
IsMvcFilePath(filePath, comparison);
19+
}
20+
21+
public static bool IsRazorComponentFilePath(ReadOnlySpan<char> filePath, StringComparison comparison)
22+
{
23+
return AdjustToUsableFilePath(filePath).EndsWith(RazorExtension, comparison);
24+
}
25+
26+
public static bool IsMvcFilePath(ReadOnlySpan<char> filePath, StringComparison comparison)
27+
{
28+
return AdjustToUsableFilePath(filePath).EndsWith(CSHtmlExtension, comparison);
29+
}
30+
31+
private static ReadOnlySpan<char> AdjustToUsableFilePath(ReadOnlySpan<char> filePath)
32+
{
33+
// In VS Code we sometimes get odd uris with query string components as the file path, for example on the left side of
34+
// a diff view. In those cases Roslyn will create a document and the file path will be set to the full raw Uri send via
35+
// VS Code. When trying to find out the file extension for those Uris, we need to strip off the query string.
36+
//
37+
// For example we get:
38+
// git:/c:/Users/dawengie/source/repos/razor01/Pages/Index.cshtml?%7B%22path%22:%22c:%5C%5CUsers%5C%5Cdawengie%5C%5Csource%5C%5Crepos%5C%5Crazor01%5C%5CPages%5C%5CIndex.cshtml%22,%22ref%22:%22~%22%7D
39+
//
40+
// Given colons and question marks are unlikely, or illegal, file path characters the risk of false positives here is hopefully low.
41+
if (filePath.IndexOf(":/") > 0 &&
42+
filePath.IndexOf('?') is int realPathEnd and > 0)
43+
{
44+
return filePath[..realPathEnd];
45+
}
46+
47+
return filePath;
48+
}
49+
1150
/// <summary>
1251
/// Generate a file path adjacent to the input path that has the
1352
/// specified file extension, using numbers to differentiate for

0 commit comments

Comments
 (0)