Skip to content

Commit edb1236

Browse files
committed
GetProperty.Match
1 parent adce5d7 commit edb1236

2 files changed

Lines changed: 84 additions & 4 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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 GetProperty
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+
internal readonly Types Types;
17+
18+
private GetProperty(InvocationExpressionSyntax invocation, IMethodSymbol target, ReflectedMember member, Name name, Flags flags, Types types)
19+
{
20+
this.Invocation = invocation;
21+
this.Target = target;
22+
this.Member = member;
23+
this.Name = name;
24+
this.Flags = flags;
25+
this.Types = types;
26+
}
27+
28+
internal IPropertySymbol? Single => this.Member.Match == FilterMatch.Single ? (IPropertySymbol)this.Member.Symbol! : null;
29+
30+
/// <summary>
31+
/// Check if <paramref name="candidate"/> is a call to Type.GetField.
32+
/// </summary>
33+
internal static GetProperty? Match(ExpressionSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken)
34+
{
35+
return candidate switch
36+
{
37+
InvocationExpressionSyntax invocation
38+
=> Match(invocation, semanticModel, cancellationToken),
39+
PostfixUnaryExpressionSyntax { RawKind: (int)SyntaxKind.SuppressNullableWarningExpression, Operand: InvocationExpressionSyntax invocation }
40+
=> Match(invocation, semanticModel, cancellationToken),
41+
MemberAccessExpressionSyntax { Expression: { } inner }
42+
=> Match(inner, semanticModel, cancellationToken),
43+
MemberBindingExpressionSyntax { Parent.Parent: ConditionalAccessExpressionSyntax { Expression: InvocationExpressionSyntax invocation } }
44+
=> Match(invocation, semanticModel, cancellationToken),
45+
IdentifierNameSyntax identifierName
46+
when semanticModel.TryGetSymbol(identifierName, cancellationToken, out ILocalSymbol? local) &&
47+
AssignedValue.FindSingle(local, semanticModel, cancellationToken) is { } value
48+
=> Match(value, semanticModel, cancellationToken),
49+
_ => null,
50+
};
51+
}
52+
53+
/// <summary>
54+
/// Check if <paramref name="candidate"/> is a call to Type.GetField.
55+
/// </summary>
56+
internal static GetProperty? Match(InvocationExpressionSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken)
57+
{
58+
if (candidate.TryGetTarget(KnownSymbol.Type.GetProperty, semanticModel, cancellationToken, out var target))
59+
{
60+
if (ReflectedMember.TryGetType(candidate, semanticModel, cancellationToken, out var type, out var typeSource) &&
61+
Name.TryCreate(candidate, target, semanticModel, cancellationToken, out var name) &&
62+
Flags.TryCreate(candidate, target, semanticModel, cancellationToken, out var flags) &&
63+
Types.TryCreate(candidate, target, semanticModel, cancellationToken, out var types))
64+
{
65+
return ReflectedMember.TryCreate(target, candidate, type, typeSource, name, flags.Effective, types, semanticModel.Compilation, out var member)
66+
? new GetProperty(candidate, target, member, name, flags, types)
67+
: null;
68+
}
69+
70+
if (Flags.TryCreate(candidate, target, semanticModel, cancellationToken, out flags) &&
71+
flags.AreInSufficient)
72+
{
73+
_ = Name.TryCreate(candidate, target, semanticModel, cancellationToken, out name);
74+
_ = Types.TryCreate(candidate, target, semanticModel, cancellationToken, out types);
75+
var member = new ReflectedMember(type, typeSource, null, target, candidate, FilterMatch.InSufficientFlags);
76+
return new GetProperty(candidate, target, member, name, flags, types);
77+
}
78+
}
79+
80+
return null;
81+
}
82+
}

ReflectionAnalyzers/Helpers/Reflection/Type.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,9 @@ when GetField.Match(invocation, recursion.SemanticModel, recursion.CancellationT
166166
result = single.Type;
167167
return true;
168168
case MemberAccessExpressionSyntax { Expression: InvocationExpressionSyntax invocation, Name: { Identifier: { ValueText: "PropertyType" } } } memberAccess
169-
when GetX.TryMatchGetProperty(invocation, recursion.SemanticModel, recursion.CancellationToken, out var reflectedMember, out _, out _, out _) &&
170-
reflectedMember.Match == FilterMatch.Single &&
171-
reflectedMember.Symbol is IPropertySymbol field:
169+
when GetProperty.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: "ReturnType" } } } memberAccess
176174
when GetMethod.Match(invocation, recursion.SemanticModel, recursion.CancellationToken) is { Single: { } single }:

0 commit comments

Comments
 (0)