Skip to content

Commit 59b8145

Browse files
authored
Improve caching in RazorSourceGenerator (#18985) (#19128)
* Cache tag helpers when the declaration build of razor files does not change * Cache generated output invariant of other non _Import files
1 parent cb42857 commit 59b8145

7 files changed

+172
-129
lines changed

src/RazorSdk/SourceGenerators/IncrementalValueProviderExtensions.cs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,9 @@ namespace Microsoft.NET.Sdk.Razor.SourceGenerators
1010
{
1111
internal static class IncrementalValuesProviderExtensions
1212
{
13-
internal static IncrementalValuesProvider<T> WithLambdaComparer<T>(this IncrementalValuesProvider<T> source, Func<T?, T?, bool> equal)
13+
internal static IncrementalValueProvider<T> WithLambdaComparer<T>(this IncrementalValueProvider<T> source, Func<T, T, bool> equal, Func<T, int> getHashCode)
1414
{
15-
var comparer = new LambdaComparer<T>(equal);
16-
return source.WithComparer(comparer);
17-
}
18-
19-
internal static IncrementalValueProvider<T> WithLambdaComparer<T>(this IncrementalValueProvider<T> source, Func<T?, T?, bool> equal)
20-
{
21-
var comparer = new LambdaComparer<T>(equal);
15+
var comparer = new LambdaComparer<T>(equal, getHashCode);
2216
return source.WithComparer(comparer);
2317
}
2418

@@ -53,15 +47,17 @@ internal static IncrementalValueProvider<TSource> ReportDiagnostics<TSource>(thi
5347

5448
internal class LambdaComparer<T> : IEqualityComparer<T>
5549
{
56-
private readonly Func<T?, T?, bool> _equal;
50+
private readonly Func<T, T, bool> _equal;
51+
private readonly Func<T, int> _getHashCode;
5752

58-
public LambdaComparer(Func<T?, T?, bool> equal)
53+
public LambdaComparer(Func<T, T, bool> equal, Func<T, int> getHashCode)
5954
{
6055
_equal = equal;
56+
_getHashCode = getHashCode;
6157
}
6258

63-
public bool Equals(T? x, T? y) => _equal(x, y);
59+
public bool Equals(T x, T y) => _equal(x, y);
6460

65-
public int GetHashCode(T obj) => EqualityComparer<T>.Default.GetHashCode(obj);
61+
public int GetHashCode(T obj) => _getHashCode(obj);
6662
}
67-
}
63+
}

src/RazorSdk/SourceGenerators/RazorSourceGenerationOptions.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
// Copyright (c) .NET Foundation. All rights reserved.
33
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
44

5+
using System;
56
using Microsoft.AspNetCore.Razor.Language;
67
using Microsoft.CodeAnalysis.CSharp;
78

89
namespace Microsoft.NET.Sdk.Razor.SourceGenerators
910
{
10-
internal class RazorSourceGenerationOptions
11+
internal class RazorSourceGenerationOptions : IEquatable<RazorSourceGenerationOptions>
1112
{
1213
public string RootNamespace { get; set; } = "ASP";
1314

@@ -40,6 +41,19 @@ internal class RazorSourceGenerationOptions
4041
/// <summary>
4142
/// Gets the CSharp language version currently used by the compilation.
4243
/// </summary>
43-
public LanguageVersion CSharpLanguageVersion { get; set; } = LanguageVersion.Preview;
44+
public LanguageVersion CSharpLanguageVersion { get; set; } = LanguageVersion.CSharp10;
45+
46+
public bool Equals(RazorSourceGenerationOptions other)
47+
{
48+
return RootNamespace == other.RootNamespace &&
49+
Configuration == other.Configuration &&
50+
GenerateMetadataSourceChecksumAttributes == other.GenerateMetadataSourceChecksumAttributes &&
51+
SuppressRazorSourceGenerator == other.SuppressRazorSourceGenerator &&
52+
CSharpLanguageVersion == other.CSharpLanguageVersion;
53+
}
54+
55+
public override bool Equals(object obj) => obj is RazorSourceGenerationOptions other && Equals(other);
56+
57+
public override int GetHashCode() => Configuration.GetHashCode();
4458
}
45-
}
59+
}

src/RazorSdk/SourceGenerators/RazorSourceGenerator.Helpers.cs

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,10 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System.Collections.Generic;
5-
using System.Diagnostics;
6-
using System.Linq;
75
using System.Text;
8-
using System.Threading;
96
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
107
using Microsoft.AspNetCore.Razor.Language;
118
using Microsoft.CodeAnalysis;
12-
using Microsoft.CodeAnalysis.CSharp;
139
using Microsoft.CodeAnalysis.Razor;
1410

1511
namespace Microsoft.NET.Sdk.Razor.SourceGenerators
@@ -37,7 +33,9 @@ private static string GetIdentifierFromPath(string filePath)
3733
return builder.ToString();
3834
}
3935

40-
private static RazorProjectEngine GetDiscoveryProjectEngine(StaticCompilationTagHelperFeature tagHelperFeature, IEnumerable<MetadataReference> references, IEnumerable<SourceGeneratorProjectItem> items, RazorSourceGenerationOptions razorSourceGeneratorOptions)
36+
private static RazorProjectEngine GetDeclarationProjectEngine(
37+
IEnumerable<SourceGeneratorProjectItem> items,
38+
RazorSourceGenerationOptions razorSourceGeneratorOptions)
4139
{
4240
var fileSystem = new VirtualRazorProjectFileSystem();
4341
foreach (var item in items)
@@ -56,26 +54,43 @@ private static RazorProjectEngine GetDiscoveryProjectEngine(StaticCompilationTag
5654

5755
b.SetRootNamespace(razorSourceGeneratorOptions.RootNamespace);
5856

59-
b.Features.Add(new DefaultMetadataReferenceFeature { References = references.ToList() });
57+
CompilerFeatures.Register(b);
58+
RazorExtensions.Register(b);
59+
60+
b.SetCSharpLanguageVersion(razorSourceGeneratorOptions.CSharpLanguageVersion);
61+
});
6062

63+
return discoveryProjectEngine;
64+
}
65+
66+
private static RazorProjectEngine GetDiscoveryProjectEngine(
67+
IReadOnlyList<MetadataReference> references,
68+
StaticCompilationTagHelperFeature tagHelperFeature)
69+
{
70+
var discoveryProjectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, new VirtualRazorProjectFileSystem(), b =>
71+
{
72+
b.Features.Add(new DefaultMetadataReferenceFeature { References = references });
6173
b.Features.Add(tagHelperFeature);
6274
b.Features.Add(new DefaultTagHelperDescriptorProvider());
6375

6476
CompilerFeatures.Register(b);
6577
RazorExtensions.Register(b);
66-
67-
b.SetCSharpLanguageVersion(razorSourceGeneratorOptions.CSharpLanguageVersion);
6878
});
6979

7080
return discoveryProjectEngine;
7181
}
7282

73-
private static RazorProjectEngine GetGenerationProjectEngine(IReadOnlyList<TagHelperDescriptor> tagHelpers, IEnumerable<SourceGeneratorProjectItem> items, RazorSourceGenerationOptions razorSourceGeneratorOptions)
83+
private static RazorProjectEngine GetGenerationProjectEngine(
84+
IReadOnlyList<TagHelperDescriptor> tagHelpers,
85+
SourceGeneratorProjectItem item,
86+
IEnumerable<SourceGeneratorProjectItem> imports,
87+
RazorSourceGenerationOptions razorSourceGeneratorOptions)
7488
{
7589
var fileSystem = new VirtualRazorProjectFileSystem();
76-
foreach (var item in items)
90+
fileSystem.Add(item);
91+
foreach (var import in imports)
7792
{
78-
fileSystem.Add(item);
93+
fileSystem.Add(import);
7994
}
8095

8196
var projectEngine = RazorProjectEngine.Create(razorSourceGeneratorOptions.Configuration, fileSystem, b =>
@@ -99,19 +114,5 @@ private static RazorProjectEngine GetGenerationProjectEngine(IReadOnlyList<TagHe
99114

100115
return projectEngine;
101116
}
102-
103-
private static TFeature? GetFeature<TFeature>(RazorProjectEngine engine)
104-
{
105-
var count = engine.EngineFeatures.Count;
106-
for (var i = 0; i < count; i++)
107-
{
108-
if (engine.EngineFeatures[i] is TFeature feature)
109-
{
110-
return feature;
111-
}
112-
}
113-
114-
return default;
115-
}
116117
}
117118
}

src/RazorSdk/SourceGenerators/RazorSourceGenerator.RazorProviders.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ private static (RazorSourceGenerationOptions?, Diagnostic?) ComputeRazorSourceGe
4040

4141
var razorSourceGenerationOptions = new RazorSourceGenerationOptions()
4242
{
43+
Configuration = razorConfiguration,
4344
WaitForDebugger = waitForDebugger == "true",
4445
SuppressRazorSourceGenerator = suppressRazorSourceGenerator == "true",
4546
GenerateMetadataSourceChecksumAttributes = generateMetadataSourceChecksumAttributes == "true",
4647
RootNamespace = rootNamespace ?? "ASP",
47-
Configuration = razorConfiguration,
4848
CSharpLanguageVersion = ((CSharpParseOptions)parseOptions).LanguageVersion,
4949
};
5050

@@ -80,4 +80,4 @@ private static (SourceGeneratorProjectItem?, Diagnostic?) ComputeProjectItems((A
8080
return (projectItem, null);
8181
}
8282
}
83-
}
83+
}

src/RazorSdk/SourceGenerators/RazorSourceGenerator.TagHelpers.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ private IReadOnlyList<TagHelperDescriptor> GetTagHelpers(IEnumerable<MetadataRef
2424
return descriptors;
2525
}
2626

27-
private IReadOnlyList<TagHelperDescriptor> GetTagHelpersFromCompilation(Compilation compilation, StaticCompilationTagHelperFeature tagHelperFeature, SyntaxTree syntaxTrees)
27+
private static IReadOnlyList<TagHelperDescriptor> GetTagHelpersFromCompilation(Compilation compilation, StaticCompilationTagHelperFeature tagHelperFeature, SyntaxTree syntaxTrees)
2828
{
2929
var compilationWithDeclarations = compilation.AddSyntaxTrees(syntaxTrees);
3030

@@ -34,4 +34,4 @@ private IReadOnlyList<TagHelperDescriptor> GetTagHelpersFromCompilation(Compilat
3434
return tagHelperFeature.GetDescriptors();
3535
}
3636
}
37-
}
37+
}

0 commit comments

Comments
 (0)