Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
<InternalsVisibleTo Include="Microsoft.VisualStudio.LegacyEditor.Razor.Test" Key="$(RazorKey)" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.RazorExtension" Key="$(RazorKey)" />
<InternalsVisibleTo Include="Microsoft.VisualStudioCode.RazorExtension" Key="$(RazorKey)" />
<InternalsVisibleTo Include="Microsoft.VisualStudioCode.RazorExtension.Test" Key="$(RazorKey)" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ private static (SourceGeneratorProjectItem?, Diagnostic?) ComputeProjectItems((A
var (additionalText, globalOptions) = pair;
var options = globalOptions.GetOptions(additionalText);

globalOptions.GlobalOptions.TryGetValue("build_property.MSBuildProjectDirectory", out var projectPath);
Comment thread
davidwengier marked this conversation as resolved.
Outdated

string relativePath;
if (options.TryGetValue("build_metadata.AdditionalFiles.TargetPath", out var encodedRelativePath))
{
Expand All @@ -92,10 +94,19 @@ private static (SourceGeneratorProjectItem?, Diagnostic?) ComputeProjectItems((A

relativePath = Encoding.UTF8.GetString(Convert.FromBase64String(encodedRelativePath));
}
else if (projectPath is { Length: > 0 } &&
additionalText.Path.StartsWith(projectPath, StringComparison.OrdinalIgnoreCase))
{
// Fallback, when TargetPath isn't specified but we know about the project directory, we can do our own calulation of
// the project relative path, and use that as the target path. This is an easy way for a project that isn't using the
// Razor SDK to still get TargetPath functionality without the complexity of specifying metadata on every item.
relativePath = additionalText.Path[projectPath.Length..].TrimStart(['/', '\\']);
}
else
{
// If the TargetPath is not provided, we effectively assume its in the root of the project.
relativePath = Path.GetFileName(additionalText.Path);
// If the TargetPath is not provided, it could be a Misc Files situation, or just a project that isn't using the
// Web or Razor SDK. In this case, we just use the physical path.
relativePath = additionalText.Path;
}

options.TryGetValue("build_metadata.AdditionalFiles.CssScope", out var cssScope);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,7 @@ protected virtual TRequest CreateHtmlParams(Uri uri)

protected static Task<SourceGeneratedDocument?> TryGetGeneratedDocumentAsync(TextDocument razorDocument, CancellationToken cancellationToken)
{
if (!razorDocument.TryComputeHintNameFromRazorDocument(out var hintName))
{
return SpecializedTasks.Null<SourceGeneratedDocument>();
}

return razorDocument.Project.TryGetSourceGeneratedDocumentFromHintNameAsync(hintName, cancellationToken);
return razorDocument.Project.TryGetSourceGeneratedDocumentForRazorDocumentAsync(razorDocument, cancellationToken);
}

private async Task<LspDiagnostic[]> GetCSharpDiagnosticsAsync(TextDocument razorDocument, Guid correletionId, CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.AspNetCore.Razor.Threading;
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Telemetry;
using Microsoft.NET.Sdk.Razor.SourceGenerators;

namespace Microsoft.CodeAnalysis;

Expand Down Expand Up @@ -103,6 +105,76 @@ private static ImmutableArray<ITagHelperDescriptorProvider> GetTagHelperDescript
return generatedDocuments.SingleOrDefault(d => d.HintName == hintName);
}

/// <summary>
/// Finds source generated documents by iterating through all of them. In OOP there are better options!
/// </summary>
public static async Task<SourceGeneratedDocument?> TryGetSourceGeneratedDocumentForRazorDocumentAsync(this Project project, TextDocument razorDocument, CancellationToken cancellationToken)
{
if (razorDocument.FilePath is null)
{
return null;
}

var generatedDocuments = await project.GetSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false);

// For misc files, and projects that don't have a globalconfig file (eg, non Razor SDK projects), the hint name will be based
// on the full path of the file.
var fullPathHintName = RazorSourceGenerator.GetIdentifierFromPath(razorDocument.FilePath);
// For normal Razor SDK projects, the hint name will be based on the project-relative path of the file.
var projectRelativeHintName = GetProjectRelativeHintName(razorDocument);

SourceGeneratedDocument? candidateDoc = null;
foreach (var doc in generatedDocuments)
{
if (!doc.IsRazorSourceGeneratedDocument())
{
continue;
}

if (doc.HintName == fullPathHintName)
{
// If the full path matches, we've found it for sure
return doc;
}
else if (doc.HintName == projectRelativeHintName)
{
if (candidateDoc is not null)
{
// Multiple documents with the same hint name found, can't be sure which one to return
// This can happen as a result of a bug in the source generator: https://github.com/dotnet/razor/issues/11578
candidateDoc = null;
break;
}

candidateDoc = doc;
}
}

return candidateDoc;

static string? GetProjectRelativeHintName(TextDocument razorDocument)
{
var filePath = razorDocument.FilePath.AsSpanOrDefault();
if (string.IsNullOrEmpty(razorDocument.Project.FilePath))
{
// Misc file - no project info to get a relative path
return null;
}

var projectFilePath = razorDocument.Project.FilePath.AsSpanOrDefault();
var projectBasePath = PathUtilities.GetDirectoryName(projectFilePath);
if (filePath.Length <= projectBasePath.Length)
{
// File must be from outside the project directory
return null;
}

var relativeDocumentPath = filePath[projectBasePath.Length..].TrimStart(['/', '\\']);

return RazorSourceGenerator.GetIdentifierFromPath(relativeDocumentPath);
}
}

/// <summary>
/// Finds source generated documents by iterating through all of them. In OOP there are better options!
/// </summary>
Expand Down

This file was deleted.

Loading