Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace Microsoft.NET.Sdk.Razor.SourceGenerators
{
Expand Down Expand Up @@ -106,10 +107,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context)

var compilationWithDeclarations = compilation.AddSyntaxTrees(generatedDeclarationSyntaxTree);

// try and find the specific class this component is declaring, falling back to the assembly if for any reason we can't
// try and find the specific root class this component is declaring, falling back to the assembly if for any reason the code is not in the shape we expect
ISymbol targetSymbol = compilationWithDeclarations.Assembly;
Copy link
Member Author

Choose a reason for hiding this comment

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

We need to look at the whole compilation with the component added (as it might reference stuff from csharp), but there's no need to actually discover anything else from the compilation, so only search the component itself.

var classSyntax = generatedDeclarationSyntaxTree.GetRoot(ct).DescendantNodes().SingleOrDefault(n => n.IsKind(CodeAnalysis.CSharp.SyntaxKind.ClassDeclaration));
if (classSyntax is not null)
var root = generatedDeclarationSyntaxTree.GetRoot(ct);
if (root is CompilationUnitSyntax { Members: [ NamespaceDeclarationSyntax { Members : [ ClassDeclarationSyntax classSyntax, ..] }, .. ] })
{
targetSymbol = compilationWithDeclarations.GetSemanticModel(generatedDeclarationSyntaxTree).GetDeclaredSymbol(classSyntax, ct) ?? targetSymbol;
}
Expand Down Expand Up @@ -203,7 +204,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.Select(static (pair, _) =>
{
var ((tagHelpersFromComponents, tagHelpersFromCompilation), tagHelpersFromReferences) = pair;
var count = tagHelpersFromCompilation.Count + tagHelpersFromReferences.Count+ tagHelpersFromComponents.Length;
var count = tagHelpersFromCompilation.Count + tagHelpersFromReferences.Count + tagHelpersFromComponents.Length;
if (count == 0)
{
return Array.Empty<TagHelperDescriptor>();
Expand All @@ -219,60 +220,61 @@ public void Initialize(IncrementalGeneratorInitializationContext context)

var generatedOutput = sourceItems
.Combine(importFiles.Collect())
.WithLambdaComparer((old, @new) => old.Left.Equals(@new.Left) && old.Right.SequenceEqual(@new.Right), (a) => GetHashCode())
.WithLambdaComparer((old, @new) => old.Left.Equals(@new.Left) && old.Right.SequenceEqual(@new.Right), (a) => a.GetHashCode())
.Combine(razorSourceGeneratorOptions)
.Select(static (pair, _) =>
{
var ((sourceItem, imports), razorSourceGeneratorOptions) = pair;

RazorSourceGeneratorEventSource.Log.ParseRazorDocumentStart(sourceItem.RelativePhysicalPath);

var projectEngine = GetGenerationProjectEngine(sourceItem, imports, razorSourceGeneratorOptions);

var document = projectEngine.ProcessInitialParse(sourceItem);

RazorSourceGeneratorEventSource.Log.ParseRazorDocumentStop(sourceItem.RelativePhysicalPath);
return (projectEngine, sourceItem.RelativePhysicalPath, document);
})

// Add the tag helpers in, but ignore if they've changed or not, only reprocessing the actual document changed
.Combine(allTagHelpers)
.WithLambdaComparer((old, @new) => old.Left.Equals(@new.Left), (item) => item.GetHashCode())
.Select((pair, _) =>
{
var ((projectEngine, filePath, codeDocument), allTagHelpers) = pair;
return (projectEngine, sourceItem.RelativePhysicalPath, document);
})

// Add the tag helpers in, but ignore if they've changed or not, only reprocessing the actual document changed
.Combine(allTagHelpers)
.WithLambdaComparer((old, @new) => old.Left.Equals(@new.Left), (item) => item.GetHashCode())
.Select((pair, _) =>
{
var ((projectEngine, filePath, codeDocument), allTagHelpers) = pair;
RazorSourceGeneratorEventSource.Log.RewriteTagHelpersStart(filePath);

codeDocument = projectEngine.ProcessTagHelpers(codeDocument, allTagHelpers, checkForIdempotency: false);
codeDocument = projectEngine.ProcessTagHelpers(codeDocument, allTagHelpers, checkForIdempotency: false);

RazorSourceGeneratorEventSource.Log.RewriteTagHelpersStop(filePath);
return (projectEngine, filePath, codeDocument);
})
RazorSourceGeneratorEventSource.Log.RewriteTagHelpersStop(filePath);
return (projectEngine, filePath, codeDocument);
})

// next we do a second parse, along with the helpers, but check for idempotency. If the tag helpers used on the previous parse match, the compiler can skip re-computing them
.Combine(allTagHelpers)
.Select((pair, _) => {
// next we do a second parse, along with the helpers, but check for idempotency. If the tag helpers used on the previous parse match, the compiler can skip re-computing them
.Combine(allTagHelpers)
.Select((pair, _) =>
{

var ((projectEngine, filePath, document), allTagHelpers) = pair;
RazorSourceGeneratorEventSource.Log.CheckAndRewriteTagHelpersStart(filePath);
var ((projectEngine, filePath, document), allTagHelpers) = pair;
RazorSourceGeneratorEventSource.Log.CheckAndRewriteTagHelpersStart(filePath);

document = projectEngine.ProcessTagHelpers(document, allTagHelpers, checkForIdempotency: true);

document = projectEngine.ProcessTagHelpers(document, allTagHelpers, checkForIdempotency: true);

RazorSourceGeneratorEventSource.Log.CheckAndRewriteTagHelpersStop(filePath);
return (projectEngine, filePath, document);
})
return (projectEngine, filePath, document);
})

.Select((pair, _) =>
{
var (projectEngine, filePath, document) = pair;
RazorSourceGeneratorEventSource.Log.RazorCodeGenerateStart(filePath);
.Select((pair, _) =>
{
var (projectEngine, filePath, document) = pair;
RazorSourceGeneratorEventSource.Log.RazorCodeGenerateStart(filePath);
document = projectEngine.ProcessRemaining(document);
var csharpDocument = document.CodeDocument.GetCSharpDocument();
var csharpDocument = document.CodeDocument.GetCSharpDocument();

RazorSourceGeneratorEventSource.Log.RazorCodeGenerateStop(filePath);
return (filePath, csharpDocument);
})
.WithLambdaComparer(static (a, b) =>
})
.WithLambdaComparer(static (a, b) =>
{
if (a.csharpDocument.Diagnostics.Count > 0 || b.csharpDocument.Diagnostics.Count > 0)
{
Expand All @@ -287,10 +289,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
{
var (filePath, csharpDocument) = pair;

// Add a generated suffix so tools, such as coverlet, consider the file to be generated
var hintName = GetIdentifierFromPath(filePath) + ".g.cs";
// Add a generated suffix so tools, such as coverlet, consider the file to be generated
var hintName = GetIdentifierFromPath(filePath) + ".g.cs";

RazorSourceGeneratorEventSource.Log.AddSyntaxTrees(hintName);
RazorSourceGeneratorEventSource.Log.AddSyntaxTrees(hintName);
for (var i = 0; i < csharpDocument.Diagnostics.Count; i++)
{
var razorDiagnostic = csharpDocument.Diagnostics[i];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,28 +68,28 @@ private RazorSourceGeneratorEventSource() { }
[Event(DiscoverTagHelpersFromComponentStopId, Level = EventLevel.Informational)]
public void DiscoverTagHelpersFromComponentStop(string filePath) => WriteEvent(DiscoverTagHelpersFromComponentStopId, filePath);

private const int ParseRazorDocumentStartId = 17;
[Event(ParseRazorDocumentStartId, Level = EventLevel.Informational)]
public void ParseRazorDocumentStart(string file) => WriteEvent(ParseRazorDocumentStartId, file);

private const int ParseRazorDocumentStopId = 18;
[Event(ParseRazorDocumentStopId, Level = EventLevel.Informational)]
public void ParseRazorDocumentStop(string file) => WriteEvent(ParseRazorDocumentStopId, file);

private const int RewriteTagHelpersStartId = 19;
[Event(RewriteTagHelpersStartId, Level = EventLevel.Informational)]
public void RewriteTagHelpersStart(string file) => WriteEvent(RewriteTagHelpersStartId, file);

private const int RewriteTagHelpersStopId = 20;
[Event(RewriteTagHelpersStopId, Level = EventLevel.Informational)]
public void RewriteTagHelpersStop(string file) => WriteEvent(RewriteTagHelpersStopId, file);

private const int CheckAndRewriteTagHelpersStartId = 21;
[Event(CheckAndRewriteTagHelpersStartId, Level = EventLevel.Informational)]
public void CheckAndRewriteTagHelpersStart(string file) => WriteEvent(CheckAndRewriteTagHelpersStartId, file);

private const int CheckAndRewriteTagHelpersStopId = 22;
[Event(CheckAndRewriteTagHelpersStopId, Level = EventLevel.Informational)]
public void CheckAndRewriteTagHelpersStop(string file) => WriteEvent(CheckAndRewriteTagHelpersStopId, file);
}
private const int ParseRazorDocumentStartId = 17;
[Event(ParseRazorDocumentStartId, Level = EventLevel.Informational)]
public void ParseRazorDocumentStart(string file) => WriteEvent(ParseRazorDocumentStartId, file);

private const int ParseRazorDocumentStopId = 18;
[Event(ParseRazorDocumentStopId, Level = EventLevel.Informational)]
public void ParseRazorDocumentStop(string file) => WriteEvent(ParseRazorDocumentStopId, file);

private const int RewriteTagHelpersStartId = 19;
[Event(RewriteTagHelpersStartId, Level = EventLevel.Informational)]
public void RewriteTagHelpersStart(string file) => WriteEvent(RewriteTagHelpersStartId, file);

private const int RewriteTagHelpersStopId = 20;
[Event(RewriteTagHelpersStopId, Level = EventLevel.Informational)]
public void RewriteTagHelpersStop(string file) => WriteEvent(RewriteTagHelpersStopId, file);

private const int CheckAndRewriteTagHelpersStartId = 21;
[Event(CheckAndRewriteTagHelpersStartId, Level = EventLevel.Informational)]
public void CheckAndRewriteTagHelpersStart(string file) => WriteEvent(CheckAndRewriteTagHelpersStartId, file);

private const int CheckAndRewriteTagHelpersStopId = 22;
[Event(CheckAndRewriteTagHelpersStopId, Level = EventLevel.Informational)]
public void CheckAndRewriteTagHelpersStop(string file) => WriteEvent(CheckAndRewriteTagHelpersStopId, file);
}
}
Loading