Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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,25 +77,37 @@ private static (SourceGeneratorProjectItem?, Diagnostic?) ComputeProjectItems((A
var (additionalText, globalOptions) = pair;
var options = globalOptions.GetOptions(additionalText);

string relativePath;
if (options.TryGetValue("build_metadata.AdditionalFiles.TargetPath", out var encodedRelativePath))
string? relativePath = null;
var hasTargetPath = options.TryGetValue("build_metadata.AdditionalFiles.TargetPath", out var encodedRelativePath);
if (hasTargetPath && !string.IsNullOrWhiteSpace(encodedRelativePath))
{
// TargetPath is optional, but must have a value if provided.
if (string.IsNullOrWhiteSpace(encodedRelativePath))
{
var diagnostic = Diagnostic.Create(
RazorDiagnostics.TargetPathNotProvided,
Location.None,
additionalText.Path);
return (null, diagnostic);
}

relativePath = Encoding.UTF8.GetString(Convert.FromBase64String(encodedRelativePath));
}
else
else if (globalOptions.GlobalOptions.TryGetValue("build_property.MSBuildProjectDirectory", out var projectPath) &&
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 (!hasTargetPath)
{
// 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;
}

if (relativePath is null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine leaving this the way it is for now, but I actually think given that we have the project file anyway, we should just ditch the target path calculation in MSBuild and just do it here always.

My suspicion for why it was done like this is that the old pre-SG way of compiling had logic in MSBuild for target path calculation, and the authors didn't want to have a duplicate that could get out of sync.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed #12390

{
// If we had a TargetPath but it was empty or whitespace, and we couldn't fall back to computing it from the project path
// that's an error.
var diagnostic = Diagnostic.Create(
RazorDiagnostics.TargetPathNotProvided,
Location.None,
additionalText.Path);
return (null, diagnostic);
}

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
Loading