Skip to content

Commit 0d69e61

Browse files
committed
Use GetMethod.Match
1 parent 54e2846 commit 0d69e61

3 files changed

Lines changed: 93 additions & 2 deletions

File tree

ReflectionAnalyzers.Tests/REFL001CastReturnValueTests/Diagnostics.MethodInfoInvoke.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace ReflectionAnalyzers.Tests.REFL001CastReturnValueTests
1+
namespace ReflectionAnalyzers.Tests.REFL001CastReturnValueTests
22
{
33
using Gu.Roslyn.Asserts;
44
using NUnit.Framework;
@@ -10,6 +10,26 @@ public static class MethodInfoInvoke
1010
private static readonly InvokeAnalyzer Analyzer = new();
1111
private static readonly ExpectedDiagnostic ExpectedDiagnostic = ExpectedDiagnostic.Create(Descriptors.REFL001CastReturnValue);
1212

13+
[Test]
14+
public static void Simple()
15+
{
16+
var code = @"
17+
namespace N
18+
{
19+
public class C
20+
{
21+
public C()
22+
{
23+
var value = ↓typeof(C).GetMethod(nameof(M)).Invoke(null, null);
24+
}
25+
26+
public static int M() => 0;
27+
}
28+
}";
29+
30+
RoslynAssert.Diagnostics(Analyzer, ExpectedDiagnostic, code);
31+
}
32+
1333
[Test]
1434
public static void Walk()
1535
{
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
namespace ReflectionAnalyzers;
2+
3+
using System.Threading;
4+
5+
using Gu.Roslyn.AnalyzerExtensions;
6+
7+
using Microsoft.CodeAnalysis;
8+
using Microsoft.CodeAnalysis.CSharp;
9+
using Microsoft.CodeAnalysis.CSharp.Syntax;
10+
11+
internal readonly struct GetMethod
12+
{
13+
internal readonly InvocationExpressionSyntax Invocation;
14+
internal readonly IMethodSymbol Target;
15+
internal readonly ReflectedMember Member;
16+
internal readonly Name Name;
17+
internal readonly Flags Flags;
18+
internal readonly Types Types;
19+
20+
private GetMethod(InvocationExpressionSyntax invocation, IMethodSymbol target, ReflectedMember member, Name name, Flags flags, Types types)
21+
{
22+
this.Invocation = invocation;
23+
this.Target = target;
24+
this.Member = member;
25+
this.Name = name;
26+
this.Flags = flags;
27+
this.Types = types;
28+
}
29+
30+
internal IMethodSymbol? SingleMatch => this.Member.Match == FilterMatch.Single ? (IMethodSymbol)this.Member.Symbol! : null;
31+
32+
internal static GetMethod? Match(ExpressionSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken)
33+
{
34+
return candidate switch
35+
{
36+
InvocationExpressionSyntax invocation
37+
=> Match(invocation, semanticModel, cancellationToken),
38+
PostfixUnaryExpressionSyntax { RawKind: (int)SyntaxKind.SuppressNullableWarningExpression, Operand: InvocationExpressionSyntax invocation }
39+
=> Match(invocation, semanticModel, cancellationToken),
40+
MemberAccessExpressionSyntax { Expression: { } inner }
41+
=> Match(inner, semanticModel, cancellationToken),
42+
IdentifierNameSyntax identifierName
43+
when semanticModel.TryGetSymbol(identifierName, cancellationToken, out ILocalSymbol? local) &&
44+
AssignedValue.FindSingle(local, semanticModel, cancellationToken) is { } value
45+
=> Match(value, semanticModel, cancellationToken),
46+
_ => null,
47+
};
48+
}
49+
50+
internal static GetMethod? Match(InvocationExpressionSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken)
51+
{
52+
if (candidate.TryGetTarget(KnownSymbol.Type.GetMethod, semanticModel, cancellationToken, out var target) &&
53+
Flags.TryCreate(candidate, target, semanticModel, cancellationToken, out var flags) &&
54+
ReflectedMember.TryGetType(candidate, semanticModel, cancellationToken, out var type, out var typeSource))
55+
{
56+
_ = Name.TryCreate(candidate, target, semanticModel, cancellationToken, out var name);
57+
_ = Types.TryCreate(candidate, target, semanticModel, cancellationToken, out var types);
58+
if (flags.AreInSufficient)
59+
{
60+
return new GetMethod(candidate, target, new ReflectedMember(type, typeSource, null, target, candidate, FilterMatch.InSufficientFlags), name, flags, types);
61+
}
62+
63+
if (ReflectedMember.TryCreate(target, candidate, type, typeSource, name, flags.Effective, types, semanticModel.Compilation, out var member))
64+
{
65+
return new GetMethod(candidate, target, member, name, flags, types);
66+
}
67+
}
68+
69+
return null;
70+
}
71+
}

ReflectionAnalyzers/NodeAnalzers/InvokeAnalyzer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ type is IArrayTypeSymbol arrayType &&
4949
context.ReportDiagnostic(Diagnostic.Create(Descriptors.REFL024PreferNullOverEmptyArray, parametersArg.GetLocation()));
5050
}
5151

52-
if (GetX.TryGetMethodInfo(memberAccess, context.SemanticModel, context.CancellationToken, out var method))
52+
if (GetMethod.Match(invocation.Expression, context.SemanticModel, context.CancellationToken) is { SingleMatch: { } method })
5353
{
5454
if (!method.ReturnsVoid &&
5555
ReturnValue.ShouldCast(invocation, method.ReturnType, context.SemanticModel))

0 commit comments

Comments
 (0)