1
0
mirror of https://github.com/chylex/.NET-Community-Toolkit.git synced 2025-02-28 00:46:01 +01:00

Generate [DynamicallyAccessedMembers] for __IMessengerExtensions

This commit is contained in:
Sergio Pedri 2022-03-06 19:26:02 +01:00
parent fa9114b3ed
commit e78e9c8250
2 changed files with 57 additions and 28 deletions

View File

@ -67,19 +67,54 @@ public static RecipientInfo GetInfo(INamedTypeSymbol typeSymbol, ImmutableArray<
/// Gets the head <see cref="CompilationUnitSyntax"/> instance.
/// </summary>
/// <returns>The head <see cref="CompilationUnitSyntax"/> instance with the type attributes.</returns>
public static CompilationUnitSyntax GetSyntax()
public static CompilationUnitSyntax GetSyntax(bool isDynamicallyAccessedMembersAttributeAvailable)
{
int numberOfAttributes = 5 + (isDynamicallyAccessedMembersAttributeAvailable ? 1 : 0);
ImmutableArray<AttributeListSyntax>.Builder attributes = ImmutableArray.CreateBuilder<AttributeListSyntax>(numberOfAttributes);
// Prepare the base attributes with are always present:
//
// [global::System.CodeDom.Compiler.GeneratedCode("...", "...")]
// [global::System.Diagnostics.DebuggerNonUserCode]
// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
// [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
// [global::System.Obsolete("This type is not intended to be used directly by user code")]
attributes.Add(
AttributeList(SingletonSeparatedList(
Attribute(IdentifierName($"global::System.CodeDom.Compiler.GeneratedCode")).AddArgumentListArguments(
AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(typeof(IMessengerRegisterAllGenerator).FullName))),
AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(typeof(IMessengerRegisterAllGenerator).Assembly.GetName().Version.ToString())))))));
attributes.Add(AttributeList(SingletonSeparatedList(Attribute(IdentifierName("global::System.Diagnostics.DebuggerNonUserCode")))));
attributes.Add(AttributeList(SingletonSeparatedList(Attribute(IdentifierName("global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage")))));
attributes.Add(
AttributeList(SingletonSeparatedList(
Attribute(IdentifierName("global::System.ComponentModel.EditorBrowsable")).AddArgumentListArguments(
AttributeArgument(ParseExpression("global::System.ComponentModel.EditorBrowsableState.Never"))))));
attributes.Add(
AttributeList(SingletonSeparatedList(
Attribute(IdentifierName("global::System.Obsolete")).AddArgumentListArguments(
AttributeArgument(LiteralExpression(
SyntaxKind.StringLiteralExpression,
Literal("This type is not intended to be used directly by user code")))))));
if (isDynamicallyAccessedMembersAttributeAvailable)
{
// Conditionally add the attribute to inform trimming, if the type is available:
//
// [global::System.CodeDom.Compiler.DynamicallyAccessedMembersAttribute(global::System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)]
attributes.Add(
AttributeList(SingletonSeparatedList(
Attribute(IdentifierName("global::System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute")).AddArgumentListArguments(
AttributeArgument(ParseExpression("global::System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods"))))));
}
// This code produces a compilation unit as follows:
//
// // <auto-generated/>
// #pragma warning disable
// namespace CommunityToolkit.Mvvm.Messaging.__Internals
// {
// [global::System.CodeDom.Compiler.GeneratedCode("...", "...")]
// [global::System.Diagnostics.DebuggerNonUserCode]
// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
// [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
// [global::System.Obsolete("This type is not intended to be used directly by user code")]
// <ATTRIBUTES>
// internal static partial class __IMessengerExtensions
// {
// }
@ -93,21 +128,7 @@ public static CompilationUnitSyntax GetSyntax()
Token(SyntaxKind.InternalKeyword),
Token(SyntaxKind.StaticKeyword),
Token(SyntaxKind.PartialKeyword))
.AddAttributeLists(
AttributeList(SingletonSeparatedList(
Attribute(IdentifierName($"global::System.CodeDom.Compiler.GeneratedCode")).AddArgumentListArguments(
AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(typeof(IMessengerRegisterAllGenerator).FullName))),
AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(typeof(IMessengerRegisterAllGenerator).Assembly.GetName().Version.ToString())))))),
AttributeList(SingletonSeparatedList(Attribute(IdentifierName("global::System.Diagnostics.DebuggerNonUserCode")))),
AttributeList(SingletonSeparatedList(Attribute(IdentifierName("global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage")))),
AttributeList(SingletonSeparatedList(
Attribute(IdentifierName("global::System.ComponentModel.EditorBrowsable")).AddArgumentListArguments(
AttributeArgument(ParseExpression("global::System.ComponentModel.EditorBrowsableState.Never"))))),
AttributeList(SingletonSeparatedList(
Attribute(IdentifierName("global::System.Obsolete")).AddArgumentListArguments(
AttributeArgument(LiteralExpression(
SyntaxKind.StringLiteralExpression,
Literal("This type is not intended to be used directly by user code")))))))))
.AddAttributeLists(attributes.MoveToImmutable().ToArray())))
.NormalizeWhitespace();
}

View File

@ -57,14 +57,22 @@ item.Symbol.DeclaringSyntaxReferences[0] is SyntaxReference syntaxReference &&
.Collect()
.Select(static (item, _) => item.Length > 0);
// Generate the header file with the attributes
context.RegisterConditionalImplementationSourceOutput(isHeaderFileNeeded, static context =>
{
CompilationUnitSyntax compilationUnit = Execute.GetSyntax();
// Check whether [DynamicallyAccessedMembers] is available
IncrementalValueProvider<bool> isDynamicallyAccessedMembersAttributeAvailable =
context.CompilationProvider
.Select(static (item, _) => item.GetTypeByMetadataName("System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute") is { DeclaredAccessibility: Accessibility.Public });
context.AddSource(
hintName: "__IMessengerExtensions.cs",
sourceText: SourceText.From(compilationUnit.ToFullString(), Encoding.UTF8));
// Generate the header file with the attributes
context.RegisterImplementationSourceOutput(isHeaderFileNeeded.Combine(isDynamicallyAccessedMembersAttributeAvailable), static (context, item) =>
{
if (item.Left)
{
CompilationUnitSyntax compilationUnit = Execute.GetSyntax(item.Right);
context.AddSource(
hintName: "__IMessengerExtensions.cs",
sourceText: SourceText.From(compilationUnit.ToFullString(), Encoding.UTF8));
}
});
// Generate the class with all registration methods