@@ -71,7 +71,7 @@ static bool IsCandidateField(SyntaxNode node, out TypeDeclarationSyntax? contain
71
71
/// <param name="node">The <see cref="MemberDeclarationSyntax"/> instance to process.</param>
72
72
/// <param name="semanticModel">The <see cref="SemanticModel"/> instance for the current run.</param>
73
73
/// <returns>Whether <paramref name="node"/> is valid.</returns>
74
- public static bool IsCandidateValidForCompilation ( SyntaxNode node , SemanticModel semanticModel )
74
+ public static bool IsCandidateValidForCompilation ( MemberDeclarationSyntax node , SemanticModel semanticModel )
75
75
{
76
76
// At least C# 8 is always required
77
77
if ( ! semanticModel . Compilation . HasLanguageVersionAtLeastEqualTo ( LanguageVersion . CSharp8 ) )
@@ -90,6 +90,35 @@ public static bool IsCandidateValidForCompilation(SyntaxNode node, SemanticModel
90
90
return true ;
91
91
}
92
92
93
+ /// <summary>
94
+ /// Performs additional checks before running the core generation logic.
95
+ /// </summary>
96
+ /// <param name="memberSymbol">The input <see cref="ISymbol"/> instance to process.</param>
97
+ /// <returns>Whether <paramref name="memberSymbol"/> is valid.</returns>
98
+ public static bool IsCandidateSymbolValid ( ISymbol memberSymbol )
99
+ {
100
+ #if ROSLYN_4_12_0_OR_GREATER
101
+ // We only need additional checks for properties (Roslyn already validates things for fields in our scenarios)
102
+ if ( memberSymbol is IPropertySymbol propertySymbol )
103
+ {
104
+ // Ensure that the property declaration is a partial definition with no implementation
105
+ if ( propertySymbol is not { IsPartialDefinition : true , PartialImplementationPart : null } )
106
+ {
107
+ return false ;
108
+ }
109
+
110
+ // Also ignore all properties that have an invalid declaration
111
+ if ( propertySymbol . ReturnsByRef || propertySymbol . ReturnsByRefReadonly || propertySymbol . Type . IsRefLikeType )
112
+ {
113
+ return false ;
114
+ }
115
+ }
116
+ #endif
117
+
118
+ // We assume all other cases are supported (other failure cases will be detected later)
119
+ return true ;
120
+ }
121
+
93
122
/// <summary>
94
123
/// Gets the candidate <see cref="MemberDeclarationSyntax"/> after the initial filtering.
95
124
/// </summary>
@@ -140,13 +169,11 @@ public static bool TryGetInfo(
140
169
return false ;
141
170
}
142
171
143
- using ImmutableArrayBuilder < DiagnosticInfo > builder = ImmutableArrayBuilder < DiagnosticInfo > . Rent ( ) ;
144
-
145
172
// Validate the target type
146
173
if ( ! IsTargetTypeValid ( memberSymbol , out bool shouldInvokeOnPropertyChanging ) )
147
174
{
148
175
propertyInfo = null ;
149
- diagnostics = builder . ToImmutable ( ) ;
176
+ diagnostics = ImmutableArray < DiagnosticInfo > . Empty ;
150
177
151
178
return false ;
152
179
}
@@ -168,7 +195,7 @@ public static bool TryGetInfo(
168
195
if ( fieldName == propertyName && memberSyntax . IsKind ( SyntaxKind . FieldDeclaration ) )
169
196
{
170
197
propertyInfo = null ;
171
- diagnostics = builder . ToImmutable ( ) ;
198
+ diagnostics = ImmutableArray < DiagnosticInfo > . Empty ;
172
199
173
200
// If the generated property would collide, skip generating it entirely. This makes sure that
174
201
// users only get the helpful diagnostic about the collision, and not the normal compiler error
@@ -182,7 +209,7 @@ public static bool TryGetInfo(
182
209
if ( IsGeneratedPropertyInvalid ( propertyName , GetPropertyType ( memberSymbol ) ) )
183
210
{
184
211
propertyInfo = null ;
185
- diagnostics = builder . ToImmutable ( ) ;
212
+ diagnostics = ImmutableArray < DiagnosticInfo > . Empty ;
186
213
187
214
return false ;
188
215
}
@@ -232,6 +259,8 @@ public static bool TryGetInfo(
232
259
233
260
token . ThrowIfCancellationRequested ( ) ;
234
261
262
+ using ImmutableArrayBuilder < DiagnosticInfo > builder = ImmutableArrayBuilder < DiagnosticInfo > . Rent ( ) ;
263
+
235
264
// Gather attributes info
236
265
foreach ( AttributeData attributeData in memberSymbol . GetAttributes ( ) )
237
266
{
0 commit comments