Skip to content

Commit

Permalink
[17.6] Revert "Perf/generator (#8212)" (#8742)
Browse files Browse the repository at this point in the history
* Revert "Perf/generator (#8212)"

This reverts commit 4ab512e.

* Add more tests
  • Loading branch information
jjonescz authored May 22, 2023
1 parent 37f2727 commit a6a61fd
Show file tree
Hide file tree
Showing 22 changed files with 711 additions and 601 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal sealed class DefaultRazorTagHelperContextDiscoveryPhase : RazorEnginePh
{
protected override void ExecuteCore(RazorCodeDocument codeDocument)
{
var syntaxTree = codeDocument.GetPreTagHelperSyntaxTree() ?? codeDocument.GetSyntaxTree();
var syntaxTree = codeDocument.GetSyntaxTree();
ThrowForMissingDocumentDependency(syntaxTree);

var descriptors = codeDocument.GetTagHelpers();
Expand Down Expand Up @@ -69,6 +69,7 @@ protected override void ExecuteCore(RazorCodeDocument codeDocument)

var context = TagHelperDocumentContext.Create(tagHelperPrefix, descriptors);
codeDocument.SetTagHelperContext(context);
codeDocument.SetPreTagHelperSyntaxTree(syntaxTree);
}

private static bool MatchesDirective(TagHelperDescriptor descriptor, string typePattern, string assemblyName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,24 @@
// The .NET Foundation licenses this file to you under the MIT license.
#nullable enable

using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Language.Legacy;

namespace Microsoft.AspNetCore.Razor.Language;
internal sealed class DefaultRazorTagHelperRewritePhase : RazorEnginePhaseBase
{
protected override void ExecuteCore(RazorCodeDocument codeDocument)
{
var syntaxTree = codeDocument.GetPreTagHelperSyntaxTree() ?? codeDocument.GetSyntaxTree();
ThrowForMissingDocumentDependency(syntaxTree);

var syntaxTree = codeDocument.GetPreTagHelperSyntaxTree();
var context = codeDocument.GetTagHelperContext();
if (context?.TagHelpers.Count > 0)
{
var rewrittenSyntaxTree = TagHelperParseTreeRewriter.Rewrite(syntaxTree, context.Prefix, context.TagHelpers, out var usedHelpers);
codeDocument.SetSyntaxTree(rewrittenSyntaxTree);
codeDocument.SetReferencedTagHelpers(usedHelpers);
}
else
if (syntaxTree is null || context.TagHelpers.Count == 0)
{
codeDocument.SetReferencedTagHelpers(new HashSet<TagHelperDescriptor>());
// No descriptors, no-op.
return;
}

var rewrittenSyntaxTree = TagHelperParseTreeRewriter.Rewrite(syntaxTree, context.Prefix, context.TagHelpers, out var usedHelpers);

codeDocument.SetReferencedTagHelpers(usedHelpers);
codeDocument.SetSyntaxTree(rewrittenSyntaxTree);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\Shared\Microsoft.AspNetCore.Razor.Utilities.Shared\Microsoft.AspNetCore.Razor.Utilities.Shared.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.Mvc.Razor.Extensions\src\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.Razor.Language\src\Microsoft.AspNetCore.Razor.Language.csproj" />
<ProjectReference Include="..\Microsoft.CodeAnalysis.Razor\src\Microsoft.CodeAnalysis.Razor.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ private static RazorProjectEngine GetDiscoveryProjectEngine(
return discoveryProjectEngine;
}

private static SourceGeneratorProjectEngine GetGenerationProjectEngine(
private static RazorProjectEngine GetGenerationProjectEngine(
IReadOnlyList<TagHelperDescriptor> tagHelpers,
SourceGeneratorProjectItem item,
IEnumerable<SourceGeneratorProjectItem> imports,
RazorSourceGenerationOptions razorSourceGeneratorOptions)
Expand All @@ -95,7 +96,7 @@ private static SourceGeneratorProjectEngine GetGenerationProjectEngine(
fileSystem.Add(import);
}

var projectEngine = (DefaultRazorProjectEngine)RazorProjectEngine.Create(razorSourceGeneratorOptions.Configuration, fileSystem, b =>
var projectEngine = RazorProjectEngine.Create(razorSourceGeneratorOptions.Configuration, fileSystem, b =>
{
b.Features.Add(new DefaultTypeNameFeature());
b.SetRootNamespace(razorSourceGeneratorOptions.RootNamespace);
Expand All @@ -106,13 +107,16 @@ private static SourceGeneratorProjectEngine GetGenerationProjectEngine(
options.SupportLocalizedComponentNames = razorSourceGeneratorOptions.SupportLocalizedComponentNames;
}));

b.Features.Add(new StaticTagHelperFeature { TagHelpers = tagHelpers });
b.Features.Add(new DefaultTagHelperDescriptorProvider());

CompilerFeatures.Register(b);
RazorExtensions.Register(b);

b.SetCSharpLanguageVersion(razorSourceGeneratorOptions.CSharpLanguageVersion);
});

return new SourceGeneratorProjectEngine(projectEngine);
return projectEngine;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace Microsoft.NET.Sdk.Razor.SourceGenerators
{
Expand Down Expand Up @@ -68,82 +66,69 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
var generatedDeclarationCode = componentFiles
.Combine(importFiles.Collect())
.Combine(razorSourceGeneratorOptions)
.WithLambdaComparer((old, @new) => (old.Right.Equals(@new.Right) && old.Left.Left.Equals(@new.Left.Left) && old.Left.Right.SequenceEqual(@new.Left.Right)), (a) => a.GetHashCode())
.Select(static (pair, _) =>
{

var ((sourceItem, importFiles), razorSourceGeneratorOptions) = pair;
RazorSourceGeneratorEventSource.Log.GenerateDeclarationCodeStart(sourceItem.RelativePhysicalPath);
RazorSourceGeneratorEventSource.Log.GenerateDeclarationCodeStart(sourceItem.FilePath);

var projectEngine = GetDeclarationProjectEngine(sourceItem, importFiles, razorSourceGeneratorOptions);

var codeGen = projectEngine.Process(sourceItem);

var result = codeGen.GetCSharpDocument().GeneratedCode;

RazorSourceGeneratorEventSource.Log.GenerateDeclarationCodeStop(sourceItem.RelativePhysicalPath);
RazorSourceGeneratorEventSource.Log.GenerateDeclarationCodeStop(sourceItem.FilePath);

return (result, sourceItem.RelativePhysicalPath);
return result;
});

var generatedDeclarationSyntaxTrees = generatedDeclarationCode
.Combine(parseOptions)
.Select(static (pair, ct) =>
.Select(static (pair, _) =>
{
var ((generatedDeclarationCode, filePath), parseOptions) = pair;
return CSharpSyntaxTree.ParseText(generatedDeclarationCode, (CSharpParseOptions)parseOptions, filePath, cancellationToken: ct);
var (generatedDeclarationCode, parseOptions) = pair;
return CSharpSyntaxTree.ParseText(generatedDeclarationCode, (CSharpParseOptions)parseOptions);
});

var tagHelpersFromComponents = generatedDeclarationSyntaxTrees
.Combine(compilation)
var tagHelpersFromCompilation = compilation
.Combine(generatedDeclarationSyntaxTrees.Collect())
.Combine(razorSourceGeneratorOptions)
.SelectMany(static (pair, ct) =>
.Select(static (pair, _) =>
{
RazorSourceGeneratorEventSource.Log.DiscoverTagHelpersFromCompilationStart();

var ((generatedDeclarationSyntaxTree, compilation), razorSourceGeneratorOptions) = pair;
RazorSourceGeneratorEventSource.Log.DiscoverTagHelpersFromComponentStart(generatedDeclarationSyntaxTree.FilePath);
var ((compilation, generatedDeclarationSyntaxTrees), razorSourceGeneratorOptions) = pair;

var tagHelperFeature = new StaticCompilationTagHelperFeature();
var discoveryProjectEngine = GetDiscoveryProjectEngine(compilation.References.ToImmutableArray(), tagHelperFeature);

var compilationWithDeclarations = compilation.AddSyntaxTrees(generatedDeclarationSyntaxTree);

// 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;
var root = generatedDeclarationSyntaxTree.GetRoot(ct);
if (root is CompilationUnitSyntax { Members: [NamespaceDeclarationSyntax { Members: [ClassDeclarationSyntax classSyntax, ..] }, ..] })
{
var declaredClass = compilationWithDeclarations.GetSemanticModel(generatedDeclarationSyntaxTree).GetDeclaredSymbol(classSyntax, ct);
Debug.Assert(declaredClass is null || declaredClass is { AllInterfaces: [{ Name: "IComponent" }, ..] });
targetSymbol = declaredClass ?? targetSymbol;
}
var compilationWithDeclarations = compilation.AddSyntaxTrees(generatedDeclarationSyntaxTrees);

tagHelperFeature.Compilation = compilationWithDeclarations;
tagHelperFeature.TargetSymbol = targetSymbol;
tagHelperFeature.TargetSymbol = compilationWithDeclarations.Assembly;

var result = tagHelperFeature.GetDescriptors();
RazorSourceGeneratorEventSource.Log.DiscoverTagHelpersFromComponentStop(generatedDeclarationSyntaxTree.FilePath);
var result = (IList<TagHelperDescriptor>)tagHelperFeature.GetDescriptors();
RazorSourceGeneratorEventSource.Log.DiscoverTagHelpersFromCompilationStop();
return result;
});

var tagHelpersFromCompilation = compilation
.Combine(razorSourceGeneratorOptions)
.Select(static (pair, _) =>
})
.WithLambdaComparer(static (a, b) =>
{
RazorSourceGeneratorEventSource.Log.DiscoverTagHelpersFromCompilationStart();

var (compilation, razorSourceGeneratorOptions) = pair;

var tagHelperFeature = new StaticCompilationTagHelperFeature();
var discoveryProjectEngine = GetDiscoveryProjectEngine(compilation.References.ToImmutableArray(), tagHelperFeature);
if (a.Count != b.Count)
{
return false;
}

tagHelperFeature.Compilation = compilation;
tagHelperFeature.TargetSymbol = compilation.Assembly;
for (var i = 0; i < a.Count; i++)
{
if (!a[i].Equals(b[i]))
{
return false;
}
}

var result = tagHelperFeature.GetDescriptors();
RazorSourceGeneratorEventSource.Log.DiscoverTagHelpersFromCompilationStop();
return result;
});
return true;
}, getHashCode: static a => a.Count);

var tagHelpersFromReferences = compilation
.Combine(razorSourceGeneratorOptions)
Expand Down Expand Up @@ -186,7 +171,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
var tagHelperFeature = new StaticCompilationTagHelperFeature();
var discoveryProjectEngine = GetDiscoveryProjectEngine(compilation.References.ToImmutableArray(), tagHelperFeature);

using var pool = ArrayBuilderPool<TagHelperDescriptor>.GetPooledObject(out var descriptors);
List<TagHelperDescriptor> descriptors = new();
tagHelperFeature.Compilation = compilation;
foreach (var reference in compilation.References)
{
Expand All @@ -198,84 +183,47 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
}

RazorSourceGeneratorEventSource.Log.DiscoverTagHelpersFromReferencesStop();
return descriptors.ToImmutable();
return (ICollection<TagHelperDescriptor>)descriptors;
});

var allTagHelpers = tagHelpersFromComponents.Collect()
.Combine(tagHelpersFromCompilation)
var allTagHelpers = tagHelpersFromCompilation
.Combine(tagHelpersFromReferences)
.Select(static (pair, _) =>
{
var ((tagHelpersFromComponents, tagHelpersFromCompilation), tagHelpersFromReferences) = pair;
var count = tagHelpersFromCompilation.Length + tagHelpersFromReferences.Length + tagHelpersFromComponents.Length;
var (tagHelpersFromCompilation, tagHelpersFromReferences) = pair;
var count = tagHelpersFromCompilation.Count + tagHelpersFromReferences.Count;
if (count == 0)
{
return ImmutableArray<TagHelperDescriptor>.Empty;
return Array.Empty<TagHelperDescriptor>();
}

using var pool = ArrayBuilderPool<TagHelperDescriptor>.GetPooledObject(out var allTagHelpers);
allTagHelpers.AddRange(tagHelpersFromCompilation);
allTagHelpers.AddRange(tagHelpersFromReferences);
allTagHelpers.AddRange(tagHelpersFromComponents);
var allTagHelpers = new TagHelperDescriptor[count];
tagHelpersFromCompilation.CopyTo(allTagHelpers, 0);
tagHelpersFromReferences.CopyTo(allTagHelpers, tagHelpersFromCompilation.Count);

return allTagHelpers.ToImmutable();
return allTagHelpers;
});

var generatedOutput = sourceItems
.Combine(importFiles.Collect())
.WithLambdaComparer((old, @new) => old.Left.Equals(@new.Left) && old.Right.SequenceEqual(@new.Right), (a) => a.GetHashCode())
.Combine(allTagHelpers)
.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;
RazorSourceGeneratorEventSource.Log.RewriteTagHelpersStart(filePath);
var (((sourceItem, imports), allTagHelpers), razorSourceGeneratorOptions) = pair;

codeDocument = projectEngine.ProcessTagHelpers(codeDocument, allTagHelpers, checkForIdempotency: false);
RazorSourceGeneratorEventSource.Log.RazorCodeGenerateStart(sourceItem.FilePath);

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, _) =>
{
// Add a generated suffix so tools, such as coverlet, consider the file to be generated
var hintName = GetIdentifierFromPath(sourceItem.RelativePhysicalPath) + ".g.cs";

var ((projectEngine, filePath, document), allTagHelpers) = pair;
RazorSourceGeneratorEventSource.Log.CheckAndRewriteTagHelpersStart(filePath);
var projectEngine = GetGenerationProjectEngine(allTagHelpers, sourceItem, imports, razorSourceGeneratorOptions);

document = projectEngine.ProcessTagHelpers(document, allTagHelpers, checkForIdempotency: true);
var codeDocument = projectEngine.Process(sourceItem);
var csharpDocument = codeDocument.GetCSharpDocument();

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

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

RazorSourceGeneratorEventSource.Log.RazorCodeGenerateStop(filePath);
return (filePath, csharpDocument);
RazorSourceGeneratorEventSource.Log.RazorCodeGenerateStop(sourceItem.FilePath);
return (hintName, csharpDocument);
})
.WithLambdaComparer(static (a, b) =>
{
Expand All @@ -290,11 +238,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)

context.RegisterSourceOutput(generatedOutput, static (context, pair) =>
{
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";

var (hintName, csharpDocument) = pair;
RazorSourceGeneratorEventSource.Log.AddSyntaxTrees(hintName);
for (var i = 0; i < csharpDocument.Diagnostics.Count; i++)
{
Expand Down
Loading

0 comments on commit a6a61fd

Please sign in to comment.