Skip to content

Commit 850064c

Browse files
Merge pull request #363 from TNG/351-getting-stub-instead-of-real-type-in-followcustomcondition
Break Recursion in Resolving Generic Arguments of Nested Functions
2 parents 230adff + 2217ce0 commit 850064c

File tree

4 files changed

+72
-62
lines changed

4 files changed

+72
-62
lines changed

ArchUnitNET/Domain/GenericParameter.cs

+31-15
Original file line numberDiff line numberDiff line change
@@ -8,42 +8,37 @@ namespace ArchUnitNET.Domain
88
{
99
public class GenericParameter : IType
1010
{
11+
private readonly string _declarerFullName;
1112
internal readonly IEnumerable<ITypeInstance<IType>> TypeInstanceConstraints;
1213

1314
public GenericParameter(
14-
ITypeInstance<IType> declaringTypeInstance,
15-
[CanBeNull] MethodMemberInstance declaringMethodInstance,
16-
string fullName,
15+
string declarerFullName,
1716
string name,
1817
GenericParameterVariance variance,
1918
IEnumerable<ITypeInstance<IType>> typeConstraints,
2019
bool hasReferenceTypeConstraint,
2120
bool hasNotNullableValueTypeConstraint,
2221
bool hasDefaultConstructorConstraint,
23-
bool isCompilerGenerated
22+
bool isCompilerGenerated,
23+
bool declarerIsMethod
2424
)
2525
{
26-
DeclaringTypeInstance = declaringTypeInstance;
27-
DeclaringMethodInstance = declaringMethodInstance;
28-
FullName = fullName;
26+
_declarerFullName = declarerFullName;
2927
Name = name;
3028
Variance = variance;
3129
TypeInstanceConstraints = typeConstraints;
3230
HasReferenceTypeConstraint = hasReferenceTypeConstraint;
3331
HasNotNullableValueTypeConstraint = hasNotNullableValueTypeConstraint;
3432
HasDefaultConstructorConstraint = hasDefaultConstructorConstraint;
3533
IsCompilerGenerated = isCompilerGenerated;
34+
DeclarerIsMethod = declarerIsMethod;
3635
}
3736

38-
public ITypeInstance<IType> DeclaringTypeInstance { get; }
39-
public IType DeclaringType => DeclaringTypeInstance.Type;
37+
public IType DeclaringType { get; private set; }
4038

4139
[CanBeNull]
42-
public MethodMemberInstance DeclaringMethodInstance { get; }
43-
44-
[CanBeNull]
45-
public IMember DeclaringMethod => DeclaringMethodInstance?.Member;
46-
public bool DeclarerIsMethod => DeclaringMethodInstance != null;
40+
public IMember DeclaringMethod { get; private set; }
41+
public bool DeclarerIsMethod { get; }
4742
public GenericParameterVariance Variance { get; }
4843
public IEnumerable<IType> TypeConstraints =>
4944
TypeInstanceConstraints.Select(instance => instance.Type);
@@ -58,7 +53,7 @@ bool isCompilerGenerated
5853
|| TypeConstraints.Any();
5954

6055
public string Name { get; }
61-
public string FullName { get; }
56+
public string FullName => _declarerFullName + "+<" + Name + ">";
6257
public string AssemblyQualifiedName =>
6358
System.Reflection.Assembly.CreateQualifiedName(
6459
DeclaringType.Assembly.FullName,
@@ -83,6 +78,27 @@ bool isCompilerGenerated
8378
public bool IsNested => true;
8479
public bool IsStub => true;
8580

81+
internal void AssignDeclarer(IMember declaringMethod)
82+
{
83+
if (!declaringMethod.FullName.Equals(_declarerFullName))
84+
{
85+
throw new InvalidOperationException("Full name of declaring member doesn't match.");
86+
}
87+
88+
DeclaringType = declaringMethod.DeclaringType;
89+
DeclaringMethod = declaringMethod;
90+
}
91+
92+
internal void AssignDeclarer(IType declaringType)
93+
{
94+
if (!declaringType.FullName.Equals(_declarerFullName))
95+
{
96+
throw new InvalidOperationException("Full name of declaring type doesn't match.");
97+
}
98+
99+
DeclaringType = declaringType;
100+
}
101+
86102
public bool Equals(GenericParameter other)
87103
{
88104
if (ReferenceEquals(null, other))

ArchUnitNET/Loader/LoadTasks/AddGenericParameterDependencies.cs

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ private void AddTypeGenericParameterDependencies()
2424
{
2525
foreach (var genericParameter in _type.GenericParameters)
2626
{
27+
genericParameter.AssignDeclarer(_type);
2728
foreach (var typeInstanceConstraint in genericParameter.TypeInstanceConstraints)
2829
{
2930
var dependency = new TypeGenericParameterTypeConstraintDependency(
@@ -41,6 +42,7 @@ private void AddMemberGenericParameterDependencies()
4142
{
4243
foreach (var genericParameter in member.GenericParameters)
4344
{
45+
genericParameter.AssignDeclarer(member);
4446
foreach (var typeInstanceConstraint in genericParameter.TypeInstanceConstraints)
4547
{
4648
var dependency = new MemberGenericParameterTypeConstraintDependency(

ArchUnitNET/Loader/TypeFactory.cs

+24-47
Original file line numberDiff line numberDiff line change
@@ -130,31 +130,37 @@ TypeReference typeReference
130130
{
131131
var genericParameter = (Mono.Cecil.GenericParameter)typeReference;
132132
var declarerIsMethod = genericParameter.Type == GenericParameterType.Method;
133-
var declaringType = GetOrCreateStubTypeInstanceFromTypeReference(
134-
declarerIsMethod
135-
? genericParameter.DeclaringMethod.DeclaringType
136-
: genericParameter.DeclaringType
137-
);
138-
var declaringMethod = declarerIsMethod
139-
? GetOrCreateMethodMemberFromMethodReference(
140-
declaringType,
141-
genericParameter.DeclaringMethod
142-
)
143-
: null;
144-
var declarerFullName =
145-
declaringMethod != null
146-
? declaringMethod.Member.FullName
147-
: declaringType.Type.FullName;
133+
var declarerFullName = declarerIsMethod
134+
? genericParameter.DeclaringMethod.BuildFullName()
135+
: genericParameter.DeclaringType.BuildFullName();
136+
var declaringTypeAssemblyName = declarerIsMethod
137+
? genericParameter.DeclaringMethod.DeclaringType.Module.Assembly.FullName
138+
: genericParameter.DeclaringType.Module.Assembly.FullName;
148139
var assemblyQualifiedName = System.Reflection.Assembly.CreateQualifiedName(
149-
declaringType.Type.Assembly.FullName,
140+
declaringTypeAssemblyName,
150141
$"{declarerFullName}+<{genericParameter.Name}>"
151142
);
152143
if (_allTypes.TryGetValue(assemblyQualifiedName, out var existingTypeInstance))
153144
{
154145
return existingTypeInstance;
155146
}
147+
var isCompilerGenerated = genericParameter.IsCompilerGenerated();
148+
var variance = genericParameter.GetVariance();
149+
var typeConstraints = genericParameter.Constraints.Select(con =>
150+
GetOrCreateStubTypeInstanceFromTypeReference(con.ConstraintType)
151+
);
156152
var result = new TypeInstance<GenericParameter>(
157-
CreateGenericParameter(genericParameter, declaringType, declaringMethod)
153+
new GenericParameter(
154+
declarerFullName,
155+
genericParameter.Name,
156+
variance,
157+
typeConstraints,
158+
genericParameter.HasReferenceTypeConstraint,
159+
genericParameter.HasNotNullableValueTypeConstraint,
160+
genericParameter.HasDefaultConstructorConstraint,
161+
isCompilerGenerated,
162+
declarerIsMethod
163+
)
158164
);
159165
_allTypes.Add(assemblyQualifiedName, result);
160166
return result;
@@ -199,7 +205,7 @@ TypeReference typeReference
199205
} while (elementType.IsArray);
200206
var elementTypeInstance = GetOrCreateStubTypeInstanceFromTypeReference(elementType);
201207
var assemblyQualifiedName = System.Reflection.Assembly.CreateQualifiedName(
202-
elementTypeInstance.Type.Assembly.FullName,
208+
elementTypeInstance.Type.Assembly?.FullName ?? "",
203209
typeReference.BuildFullName()
204210
);
205211
if (_allTypes.TryGetValue(assemblyQualifiedName, out var existingTypeInstance))
@@ -609,35 +615,6 @@ IGenericParameterProvider genericParameterProvider
609615
.Cast<GenericParameter>();
610616
}
611617

612-
private GenericParameter CreateGenericParameter(
613-
Mono.Cecil.GenericParameter genericParameter,
614-
ITypeInstance<IType> declaringTypeInstance,
615-
[CanBeNull] MethodMemberInstance declaringMethodInstance
616-
)
617-
{
618-
var isCompilerGenerated = genericParameter.IsCompilerGenerated();
619-
var variance = genericParameter.GetVariance();
620-
var typeConstraints = genericParameter.Constraints.Select(con =>
621-
GetOrCreateStubTypeInstanceFromTypeReference(con.ConstraintType)
622-
);
623-
var declarerFullName =
624-
declaringMethodInstance != null
625-
? declaringMethodInstance.Member.FullName
626-
: declaringTypeInstance.Type.FullName;
627-
return new GenericParameter(
628-
declaringTypeInstance,
629-
declaringMethodInstance,
630-
$"{declarerFullName}+<{genericParameter.Name}>",
631-
genericParameter.Name,
632-
variance,
633-
typeConstraints,
634-
genericParameter.HasReferenceTypeConstraint,
635-
genericParameter.HasNotNullableValueTypeConstraint,
636-
genericParameter.HasDefaultConstructorConstraint,
637-
isCompilerGenerated
638-
);
639-
}
640-
641618
internal GenericArgument CreateGenericArgumentFromTypeReference(TypeReference typeReference)
642619
{
643620
return new GenericArgument(GetOrCreateStubTypeInstanceFromTypeReference(typeReference));

TestAssemblies/DependencyAssembly/TypeDependency.cs

+15
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,18 @@ public class ChildClassOfGeneric : GenericBaseClass<ChildClassOfGeneric> { }
4343
public class ClassWithoutDependencies { }
4444

4545
public class OtherClassWithoutDependencies { }
46+
47+
// https://github.com/TNG/ArchUnitNET/issues/351
48+
class Issue351
49+
{
50+
public void OuterFunc()
51+
{
52+
LocalFunc<string>();
53+
54+
void LocalFunc<T>()
55+
{
56+
var list = new List<string>();
57+
list.GroupBy(x => x).ToDictionary(g => g.Key, g => (IReadOnlyCollection<T>)g.ToList());
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)