Skip to content

Commit a5a1313

Browse files
committed
Add tests for GetNestedType when generic. Fix #92.
1 parent dfb38a1 commit a5a1313

File tree

5 files changed

+127
-15
lines changed

5 files changed

+127
-15
lines changed

ReflectionAnalyzers.Tests/REFL003MemberDoesNotExistTests/Diagnostics.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,5 +140,30 @@ public Foo()
140140

141141
AnalyzerAssert.Valid(Analyzer, ExpectedDiagnostic, exception, code);
142142
}
143+
144+
[TestCase("GetNestedType(\"Generic\", BindingFlags.Public)")]
145+
[TestCase("GetNestedType(nameof(Generic<int>), BindingFlags.Public)")]
146+
[TestCase("GetNestedType(\"Generic`2\", BindingFlags.Public)")]
147+
public void GetNestedType(string call)
148+
{
149+
var code = @"
150+
namespace RoslynSandbox
151+
{
152+
using System.Reflection;
153+
154+
class Foo
155+
{
156+
public Foo()
157+
{
158+
var methodInfo = typeof(Foo).GetNestedType(nameof(Generic<int>), BindingFlags.Public);
159+
}
160+
161+
public class Generic<T>
162+
{
163+
}
164+
}
165+
}".AssertReplace("GetNestedType(nameof(Generic<int>), BindingFlags.Public)", call);
166+
AnalyzerAssert.Valid(Analyzer, ExpectedDiagnostic, code);
167+
}
143168
}
144169
}

ReflectionAnalyzers.Tests/REFL003MemberDoesNotExistTests/ValidCode.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,48 @@ public Foo()
6262

6363
AnalyzerAssert.Valid(Analyzer, ExpectedDiagnostic, exception, code);
6464
}
65+
66+
[TestCase("GetNestedType(nameof(PublicStatic), BindingFlags.Public)")]
67+
[TestCase("GetNestedType(\"Generic`1\", BindingFlags.Public)")]
68+
[TestCase("GetNestedType(nameof(Public), BindingFlags.Public)")]
69+
[TestCase("GetNestedType(nameof(PrivateStatic), BindingFlags.NonPublic)")]
70+
[TestCase("GetNestedType(nameof(Private), BindingFlags.NonPublic)")]
71+
public void GetNestedType(string call)
72+
{
73+
var code = @"
74+
namespace RoslynSandbox
75+
{
76+
using System.Reflection;
77+
78+
class Foo
79+
{
80+
public Foo()
81+
{
82+
var methodInfo = typeof(Foo).GetNestedType(nameof(Public), BindingFlags.Public);
83+
}
84+
85+
public static class PublicStatic
86+
{
87+
}
88+
89+
public class Generic<T>
90+
{
91+
}
92+
93+
public class Public
94+
{
95+
}
96+
97+
private static class PrivateStatic
98+
{
99+
}
100+
101+
private class Private
102+
{
103+
}
104+
}
105+
}".AssertReplace("GetNestedType(nameof(Public), BindingFlags.Public)", call);
106+
AnalyzerAssert.Valid(Analyzer, ExpectedDiagnostic, code);
107+
}
65108
}
66109
}

ReflectionAnalyzers.Tests/REFL016UseNameofTests/ValidCode.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,29 @@ public MethodInfo Bar<T>()
103103
AnalyzerAssert.Valid(Analyzer, ExpectedDiagnostic, code);
104104
}
105105

106+
[TestCase("GetNestedType(\"Generic`1\", BindingFlags.Public)")]
107+
public void GetNestedGenericType(string call)
108+
{
109+
var code = @"
110+
namespace RoslynSandbox
111+
{
112+
using System.Reflection;
113+
114+
class Foo
115+
{
116+
public Foo()
117+
{
118+
var methodInfo = typeof(Foo).GetNestedType(""Generic`1"", BindingFlags.Public);
119+
}
120+
121+
public class Generic<T>
122+
{
123+
}
124+
}
125+
}".AssertReplace("GetNestedType(\"Generic`1\", BindingFlags.Public)", call);
126+
AnalyzerAssert.Valid(Analyzer, ExpectedDiagnostic, code);
127+
}
128+
106129
[Test]
107130
public void WhenThrowingArgumentException()
108131
{

ReflectionAnalyzers/Helpers/GetX.cs

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
namespace ReflectionAnalyzers
22
{
33
using System.Linq;
4-
using System.Threading;
54
using Gu.Roslyn.AnalyzerExtensions;
65
using Microsoft.CodeAnalysis;
76
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -130,26 +129,27 @@ internal static bool TryGetTargetType(InvocationExpressionSyntax getX, SyntaxNod
130129
TryGetTargetType(memberAccess.Expression, context, null, out result, out instance);
131130
}
132131

133-
internal static GetXResult TryGetTarget(IMethodSymbol getX, ITypeSymbol targetType, string targetName, BindingFlags effectiveFlags, SyntaxNodeAnalysisContext context, out ISymbol target)
132+
internal static GetXResult TryGetTarget(IMethodSymbol getX, ITypeSymbol targetType, string targetMetadataName, BindingFlags effectiveFlags, SyntaxNodeAnalysisContext context, out ISymbol target)
134133
{
134+
var name = TrimName();
135135
target = null;
136136
if (targetType is ITypeParameterSymbol typeParameter)
137137
{
138138
if (typeParameter.ConstraintTypes.Length == 0)
139139
{
140-
return TryGetTarget(getX, context.Compilation.GetSpecialType(SpecialType.System_Object), targetName, effectiveFlags, context, out target);
140+
return TryGetTarget(getX, context.Compilation.GetSpecialType(SpecialType.System_Object), name, effectiveFlags, context, out target);
141141
}
142142

143143
foreach (var constraintType in typeParameter.ConstraintTypes)
144144
{
145-
var result = TryGetTarget(getX, constraintType, targetName, effectiveFlags, context, out target);
145+
var result = TryGetTarget(getX, constraintType, name, effectiveFlags, context, out target);
146146
if (result != GetXResult.NoMatch)
147147
{
148148
return result;
149149
}
150150
}
151151

152-
return TryGetTarget(getX, context.Compilation.GetSpecialType(SpecialType.System_Object), targetName, effectiveFlags, context, out target);
152+
return TryGetTarget(getX, context.Compilation.GetSpecialType(SpecialType.System_Object), name, effectiveFlags, context, out target);
153153
}
154154

155155
if (getX == KnownSymbol.Type.GetNestedType ||
@@ -158,9 +158,9 @@ internal static GetXResult TryGetTarget(IMethodSymbol getX, ITypeSymbol targetTy
158158
!effectiveFlags.HasFlagFast(BindingFlags.Instance) &&
159159
!effectiveFlags.HasFlagFast(BindingFlags.FlattenHierarchy)))
160160
{
161-
foreach (var member in targetType.GetMembers(targetName))
161+
foreach (var member in targetType.GetMembers(name))
162162
{
163-
if (!MatchesFlags(member, effectiveFlags))
163+
if (!MatchesFilter(member, targetMetadataName, effectiveFlags))
164164
{
165165
continue;
166166
}
@@ -180,7 +180,7 @@ internal static GetXResult TryGetTarget(IMethodSymbol getX, ITypeSymbol targetTy
180180
return GetXResult.Single;
181181
}
182182

183-
if (targetType.TryFindFirstMemberRecursive(targetName, out target))
183+
if (targetType.TryFindFirstMemberRecursive(name, out target))
184184
{
185185
if (getX == KnownSymbol.Type.GetNestedType &&
186186
!targetType.Equals(target.ContainingType))
@@ -214,9 +214,9 @@ internal static GetXResult TryGetTarget(IMethodSymbol getX, ITypeSymbol targetTy
214214
var current = targetType;
215215
while (current != null)
216216
{
217-
foreach (var member in current.GetMembers(targetName))
217+
foreach (var member in current.GetMembers(name))
218218
{
219-
if (!MatchesFlags(member, effectiveFlags))
219+
if (!MatchesFilter(member, targetMetadataName, effectiveFlags))
220220
{
221221
continue;
222222
}
@@ -258,7 +258,7 @@ internal static GetXResult TryGetTarget(IMethodSymbol getX, ITypeSymbol targetTy
258258

259259
if (target == null)
260260
{
261-
if (targetType.TryFindFirstMemberRecursive(targetName, out target))
261+
if (targetType.TryFindFirstMemberRecursive(name, out target))
262262
{
263263
return GetXResult.WrongFlags;
264264
}
@@ -332,7 +332,7 @@ bool IsExplicitImplementation( out ISymbol result)
332332
{
333333
foreach (var @interface in targetType.AllInterfaces)
334334
{
335-
if (@interface.TryFindFirstMemberRecursive(targetName, out result))
335+
if (@interface.TryFindFirstMemberRecursive(name, out result))
336336
{
337337
return true;
338338
}
@@ -341,6 +341,17 @@ bool IsExplicitImplementation( out ISymbol result)
341341
result = null;
342342
return false;
343343
}
344+
345+
string TrimName()
346+
{
347+
var index = targetMetadataName.IndexOf('`');
348+
if (index > 0)
349+
{
350+
return targetMetadataName.Substring(0, index);
351+
}
352+
353+
return targetMetadataName;
354+
}
344355
}
345356

346357
internal static bool TryGetDefaultFlags(QualifiedMethod getX, out BindingFlags defaultFlags)
@@ -409,8 +420,13 @@ private static bool TryGetFlags(InvocationExpressionSyntax invocation, IMethodSy
409420
context.SemanticModel.TryGetConstantValue(argument.Expression, context.CancellationToken, out bindingFlags);
410421
}
411422

412-
private static bool MatchesFlags(ISymbol candidate, BindingFlags filter)
423+
private static bool MatchesFilter(ISymbol candidate, string metadataName, BindingFlags filter)
413424
{
425+
if (candidate.MetadataName != metadataName)
426+
{
427+
return false;
428+
}
429+
414430
if (candidate.DeclaredAccessibility == Accessibility.Public &&
415431
!filter.HasFlagFast(BindingFlags.Public))
416432
{
@@ -498,7 +514,7 @@ private static bool TryGetTargetType(ExpressionSyntax expression, SyntaxNodeAnal
498514
}
499515

500516
return context.SemanticModel.TryGetType(typeAccess.Expression, context.CancellationToken, out result);
501-
case IdentifierNameSyntax identifierName when expression.TryFirstAncestor(out TypeDeclarationSyntax containingType):
517+
case IdentifierNameSyntax _ when expression.TryFirstAncestor(out TypeDeclarationSyntax containingType):
502518
return context.SemanticModel.TryGetSymbol(containingType, context.CancellationToken, out result);
503519
}
504520
}

ValidCode/GenericMember.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@ public class GenericMember
66
{
77
public GenericMember()
88
{
9-
_ = typeof(GenericMember).GetMethod(nameof(GenericMember.Id), BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
9+
_ = typeof(GenericMember).GetMethod(nameof(this.Id), BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
10+
_ = typeof(GenericMember).GetNestedType("Bar`1", BindingFlags.Public);
1011
}
1112

1213
public T Id<T>(T value) => value;
14+
15+
public class Bar<T>
16+
{
17+
}
1318
}
1419
}

0 commit comments

Comments
 (0)