8
8
using System . Linq ;
9
9
using System . Reflection ;
10
10
using CommunityToolkit . Mvvm . SourceGenerators . Extensions ;
11
+ using CommunityToolkit . Mvvm . SourceGenerators . Helpers ;
11
12
using Microsoft . CodeAnalysis ;
12
13
using Microsoft . CodeAnalysis . CSharp ;
13
14
using Microsoft . CodeAnalysis . CSharp . Syntax ;
@@ -23,6 +24,18 @@ partial class TransitiveMembersGenerator<TInfo>
23
24
/// </summary>
24
25
internal static class Execute
25
26
{
27
+ /// <summary>
28
+ /// Checks whether or not nullability attributes are currently available.
29
+ /// </summary>
30
+ /// <param name="compilation">The input <see cref="Compilation"/> instance.</param>
31
+ /// <returns>Whether or not nullability attributes are currently available.</returns>
32
+ public static bool IsNullabilitySupported ( Compilation compilation )
33
+ {
34
+ return
35
+ compilation . HasAccessibleTypeWithMetadataName ( "System.Diagnostics.CodeAnalysis.NotNullAttribute" ) &&
36
+ compilation . HasAccessibleTypeWithMetadataName ( "System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute" ) ;
37
+ }
38
+
26
39
/// <summary>
27
40
/// Loads the source <see cref="ClassDeclarationSyntax"/> instance to get member declarations from.
28
41
/// </summary>
@@ -101,5 +114,67 @@ public static void ProcessMemberDeclarations(
101
114
102
115
nonSealedMemberDeclarations = annotatedMemberDeclarations ;
103
116
}
117
+
118
+ /// <summary>
119
+ /// Adjusts the nullability annotations for generated members, dropping attributes if needed.
120
+ /// </summary>
121
+ /// <param name="memberDeclarations">The input sequence of member declarations to generate.</param>
122
+ /// <param name="isNullabilitySupported">Whether nullability attributes are supported.</param>
123
+ /// <returns>The updated collection of member declarations to generate.</returns>
124
+ public static ImmutableArray < MemberDeclarationSyntax > AdjustMemberDeclarationNullabilityAnnotations (
125
+ ImmutableArray < MemberDeclarationSyntax > memberDeclarations ,
126
+ bool isNullabilitySupported )
127
+ {
128
+ // If nullability attributes are supported, there is nothing else to do
129
+ if ( isNullabilitySupported )
130
+ {
131
+ return memberDeclarations ;
132
+ }
133
+
134
+ using ImmutableArrayBuilder < MemberDeclarationSyntax > builder = ImmutableArrayBuilder < MemberDeclarationSyntax > . Rent ( ) ;
135
+
136
+ NullabilityAdjustmentSyntaxRewriter syntaxRewriter = new ( ) ;
137
+
138
+ // Iterate over all members and adjust the method declarations, if needed
139
+ foreach ( MemberDeclarationSyntax memberDeclaration in memberDeclarations )
140
+ {
141
+ if ( memberDeclaration is MethodDeclarationSyntax methodDeclaration )
142
+ {
143
+ builder . Add ( ( MethodDeclarationSyntax ) syntaxRewriter . Visit ( methodDeclaration ) ) ;
144
+ }
145
+ else
146
+ {
147
+ builder . Add ( memberDeclaration ) ;
148
+ }
149
+ }
150
+
151
+ return builder . ToImmutable ( ) ;
152
+ }
153
+
154
+ /// <summary>
155
+ /// A custom syntax rewriter that removes nullability attributes from method parameters.
156
+ /// </summary>
157
+ private sealed class NullabilityAdjustmentSyntaxRewriter : CSharpSyntaxRewriter
158
+ {
159
+ /// <inheritdoc/>
160
+ public override SyntaxNode ? VisitParameter ( ParameterSyntax node )
161
+ {
162
+ SyntaxNode ? updatedNode = base . VisitParameter ( node ) ;
163
+
164
+ // If the node is a parameter node with a single attribute being either [NotNull] or [NotNullIfNotNull], drop it.
165
+ // This expression will match all parameters with the following format:
166
+ //
167
+ // ([global::<NAMESPACE>.<ATTRIBUTE_NAME>] <TYPE> <PARAMETER_NAME>)
168
+ //
169
+ // Where <ATTRIBUTE_NAME> is either "NotNull" or "NotNullIfNotNull". This relies on parameters following this structure
170
+ // for nullability annotations, but that is fine in this context given the only source files are the embedded ones.
171
+ if ( updatedNode is ParameterSyntax { AttributeLists : [ { Attributes : [ { Name : QualifiedNameSyntax { Right . Identifier . Text : "NotNull" or "NotNullIfNotNull" } } ] } ] } parameterNode )
172
+ {
173
+ return parameterNode . WithAttributeLists ( default ) ;
174
+ }
175
+
176
+ return updatedNode ;
177
+ }
178
+ }
104
179
}
105
180
}
0 commit comments