Skip to content

Commit 807dbca

Browse files
committed
Switch NullabilityAttributesGenerator to incremental
1 parent a3bafc6 commit 807dbca

File tree

1 file changed

+43
-23
lines changed

1 file changed

+43
-23
lines changed

CommunityToolkit.Mvvm.SourceGenerators/Attributes/NullabilityAttributesGenerator.cs

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,53 +5,73 @@
55
using System.IO;
66
using System.Linq;
77
using System.Reflection;
8-
using System.Text;
98
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
109
using Microsoft.CodeAnalysis;
11-
using Microsoft.CodeAnalysis.Text;
1210

1311
namespace CommunityToolkit.Mvvm.SourceGenerators;
1412

1513
/// <summary>
1614
/// A source generator for necessary nullability attributes.
1715
/// </summary>
18-
[Generator]
19-
public sealed class NullabilityAttributesGenerator : ISourceGenerator
16+
[Generator(LanguageNames.CSharp)]
17+
public sealed class NullabilityAttributesGenerator : IIncrementalGenerator
2018
{
21-
/// <inheritdoc/>
22-
public void Initialize(GeneratorInitializationContext context)
23-
{
24-
}
25-
26-
/// <inheritdoc/>
27-
public void Execute(GeneratorExecutionContext context)
28-
{
29-
AddSourceCodeIfTypeIsNotPresent(context, "System.Diagnostics.CodeAnalysis.NotNullAttribute");
30-
AddSourceCodeIfTypeIsNotPresent(context, "System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute");
31-
}
19+
/// <summary>
20+
/// The <c>System.Diagnostics.CodeAnalysis.NotNullAttribute</c> metadata name.
21+
/// </summary>
22+
private const string NotNullAttributeMetadataName = "System.Diagnostics.CodeAnalysis.NotNullAttribute";
3223

3324
/// <summary>
34-
/// Adds the source for a given attribute type if it's not present already in the compilation.
25+
/// The <c>System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute</c> metadata name.
3526
/// </summary>
36-
private void AddSourceCodeIfTypeIsNotPresent(GeneratorExecutionContext context, string typeFullName)
27+
private const string NotNullIfNotNullAttributeMetadataName = "System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute";
28+
29+
/// <inheritdoc/>
30+
public void Initialize(IncrementalGeneratorInitializationContext context)
3731
{
3832
// Check that the target attributes are not available in the consuming project. To ensure that
3933
// this works fine both in .NET (Core) and .NET Standard implementations, we also need to check
4034
// that the target types are declared as public (we assume that in this case those types are from the BCL).
4135
// This avoids issues on .NET Standard with Roslyn also seeing internal types from referenced assemblies.
42-
if (context.Compilation.HasAccessibleTypeWithMetadataName(typeFullName))
36+
37+
// Check whether [NotNull] is available
38+
IncrementalValueProvider<bool> isNotNullAttributeAvailable =
39+
context.CompilationProvider
40+
.Select(static (item, _) => item.HasAccessibleTypeWithMetadataName(NotNullAttributeMetadataName));
41+
42+
// Generate the [NotNull] type
43+
context.RegisterConditionalSourceOutput(isNotNullAttributeAvailable, static context =>
44+
{
45+
string source = LoadAttributeSourceWithMetadataName(NotNullAttributeMetadataName);
46+
47+
context.AddSource(NotNullAttributeMetadataName, source);
48+
});
49+
50+
// Check whether [NotNullIfNotNull] is available
51+
IncrementalValueProvider<bool> isNotNullIfNotNullAttributeAvailable =
52+
context.CompilationProvider
53+
.Select(static (item, _) => item.HasAccessibleTypeWithMetadataName(NotNullIfNotNullAttributeMetadataName));
54+
55+
// Generate the [NotNullIfNotNull] type
56+
context.RegisterConditionalSourceOutput(isNotNullIfNotNullAttributeAvailable, static context =>
4357
{
44-
return;
45-
}
58+
string source = LoadAttributeSourceWithMetadataName(NotNullIfNotNullAttributeMetadataName);
4659

60+
context.AddSource(NotNullIfNotNullAttributeMetadataName, source);
61+
});
62+
}
63+
64+
/// <summary>
65+
/// Gets the generated source for a specified attribute.
66+
/// </summary>
67+
private static string LoadAttributeSourceWithMetadataName(string typeFullName)
68+
{
4769
string typeName = typeFullName.Split('.').Last();
4870
string filename = $"CommunityToolkit.Mvvm.SourceGenerators.EmbeddedResources.{typeName}.cs";
4971

5072
Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(filename);
5173
StreamReader reader = new(stream);
5274

53-
string source = reader.ReadToEnd();
54-
55-
context.AddSource($"{typeFullName}.cs", SourceText.From(source, Encoding.UTF8));
75+
return reader.ReadToEnd();
5676
}
5777
}

0 commit comments

Comments
 (0)