Skip to content

Commit 7368089

Browse files
committed
GetField
1 parent ca97abc commit 7368089

3 files changed

Lines changed: 80 additions & 6 deletions

File tree

ReflectionAnalyzers/Helpers/Reflection/FieldInfo.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ internal FieldInfo(INamedTypeSymbol reflectedType, IFieldSymbol field)
2424
return expression switch
2525
{
2626
InvocationExpressionSyntax invocation
27-
when GetX.TryMatchGetField(invocation, semanticModel, cancellationToken, out var member, out _, out _) &&
28-
member is { ReflectedType: { } reflectedType, Symbol: IFieldSymbol field }
27+
when GetField.Match(invocation, semanticModel, cancellationToken) is { Member: { ReflectedType: { } reflectedType, Symbol: IFieldSymbol field } }
2928
=> new FieldInfo(reflectedType, field),
3029
IdentifierNameSyntax identifierName => FindAssigned(identifierName),
3130
MemberAccessExpressionSyntax memberAccess => FindAssigned(memberAccess),
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
namespace ReflectionAnalyzers;
2+
3+
using System.Threading;
4+
using Gu.Roslyn.AnalyzerExtensions;
5+
using Microsoft.CodeAnalysis;
6+
using Microsoft.CodeAnalysis.CSharp;
7+
using Microsoft.CodeAnalysis.CSharp.Syntax;
8+
9+
internal readonly struct GetField
10+
{
11+
internal readonly InvocationExpressionSyntax Invocation;
12+
internal readonly IMethodSymbol Target;
13+
internal readonly ReflectedMember Member;
14+
internal readonly Name Name;
15+
internal readonly Flags Flags;
16+
17+
private GetField(InvocationExpressionSyntax invocation, IMethodSymbol target, ReflectedMember member, Name name, Flags flags)
18+
{
19+
this.Invocation = invocation;
20+
this.Target = target;
21+
this.Member = member;
22+
this.Name = name;
23+
this.Flags = flags;
24+
}
25+
26+
internal IFieldSymbol? Single => this.Member.Match == FilterMatch.Single ? (IFieldSymbol)this.Member.Symbol! : null;
27+
28+
/// <summary>
29+
/// Check if <paramref name="candidate"/> is a call to Type.GetField.
30+
/// </summary>
31+
internal static GetField? Match(ExpressionSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken)
32+
{
33+
return candidate switch
34+
{
35+
InvocationExpressionSyntax invocation
36+
=> Match(invocation, semanticModel, cancellationToken),
37+
PostfixUnaryExpressionSyntax { RawKind: (int)SyntaxKind.SuppressNullableWarningExpression, Operand: InvocationExpressionSyntax invocation }
38+
=> Match(invocation, semanticModel, cancellationToken),
39+
MemberAccessExpressionSyntax { Expression: { } inner }
40+
=> Match(inner, semanticModel, cancellationToken),
41+
MemberBindingExpressionSyntax { Parent.Parent: ConditionalAccessExpressionSyntax { Expression: InvocationExpressionSyntax invocation } }
42+
=> Match(invocation, semanticModel, cancellationToken),
43+
IdentifierNameSyntax identifierName
44+
when semanticModel.TryGetSymbol(identifierName, cancellationToken, out ILocalSymbol? local) &&
45+
AssignedValue.FindSingle(local, semanticModel, cancellationToken) is { } value
46+
=> Match(value, semanticModel, cancellationToken),
47+
_ => null,
48+
};
49+
}
50+
51+
/// <summary>
52+
/// Check if <paramref name="candidate"/> is a call to Type.GetField.
53+
/// </summary>
54+
internal static GetField? Match(InvocationExpressionSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken)
55+
{
56+
if (candidate.TryGetTarget(KnownSymbol.Type.GetField, semanticModel, cancellationToken, out var target))
57+
{
58+
if (ReflectedMember.TryGetType(candidate, semanticModel, cancellationToken, out var type, out var typeSource) &&
59+
Name.TryCreate(candidate, target, semanticModel, cancellationToken, out var name) &&
60+
Flags.TryCreate(candidate, target, semanticModel, cancellationToken, out var flags) &&
61+
ReflectedMember.TryCreate(target, candidate, type, typeSource, name, flags.Effective, Types.Any, semanticModel.Compilation, out var member))
62+
{
63+
return new GetField(candidate, target, member, name, flags);
64+
}
65+
66+
if (Flags.TryCreate(candidate, target, semanticModel, cancellationToken, out flags) &&
67+
flags.AreInSufficient)
68+
{
69+
_ = Name.TryCreate(candidate, target, semanticModel, cancellationToken, out name);
70+
member = new ReflectedMember(type, typeSource, null, target, candidate, FilterMatch.InSufficientFlags);
71+
return new GetField(candidate, target, member, name, flags);
72+
}
73+
}
74+
75+
return null;
76+
}
77+
}

ReflectionAnalyzers/Helpers/Reflection/Type.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,9 @@ when GetMethod.Match(invocation, recursion.SemanticModel, recursion.Cancellation
166166
result = single.ReturnType;
167167
return true;
168168
case MemberAccessExpressionSyntax { Expression: InvocationExpressionSyntax invocation, Name: { Identifier: { ValueText: "FieldType" } } } memberAccess
169-
when GetX.TryMatchGetField(invocation, recursion.SemanticModel, recursion.CancellationToken, out var reflectedMember, out _, out _) &&
170-
reflectedMember.Match == FilterMatch.Single &&
171-
reflectedMember.Symbol is IFieldSymbol field:
169+
when GetField.Match(invocation, recursion.SemanticModel, recursion.CancellationToken) is { Single:{} single }:
172170
source = memberAccess;
173-
result = field.Type;
171+
result = single.Type;
174172
return true;
175173
case MemberAccessExpressionSyntax { Expression: InvocationExpressionSyntax invocation, Name: { Identifier: { ValueText: "PropertyType" } } } memberAccess
176174
when GetX.TryMatchGetProperty(invocation, recursion.SemanticModel, recursion.CancellationToken, out var reflectedMember, out _, out _, out _) &&

0 commit comments

Comments
 (0)