Skip to content

Commit da5d0d6

Browse files
committed
Record method call generic argument types as dependencies
Signed-off-by: Pete Forrest <petemforrest@gmail.com>
1 parent cb83e98 commit da5d0d6

10 files changed

Lines changed: 154 additions & 88 deletions

ArchUnitNET/Loader/LoadTasks/AddMethodDependencies.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ MethodMember methodMember
164164

165165
bodyTypes.AddRange(methodDefinition.GetBodyTypes(_typeFactory).ToList());
166166

167+
var genericArgumentTypes = methodDefinition.GetGenericArguments(_typeFactory).ToList();
168+
167169
var castTypes = methodDefinition.GetCastTypes(_typeFactory).ToList();
168170

169171
var typeCheckTypes = methodDefinition.GetTypeCheckTypes(_typeFactory).ToList();
@@ -177,6 +179,7 @@ MethodMember methodMember
177179
var calledMethodMembers = CreateMethodBodyDependenciesRecursive(
178180
methodBody,
179181
visitedMethodReferences,
182+
genericArgumentTypes,
180183
bodyTypes,
181184
castTypes,
182185
typeCheckTypes,
@@ -193,6 +196,15 @@ var calledMethodMember in calledMethodMembers
193196
yield return new MethodCallDependency(methodMember, calledMethodMember);
194197
}
195198

199+
foreach (
200+
var genericArgument in genericArgumentTypes
201+
.Where(instance => !instance.Type.IsCompilerGenerated)
202+
.Distinct()
203+
)
204+
{
205+
yield return new MethodSignatureDependency(methodMember, genericArgument);
206+
}
207+
196208
foreach (
197209
var bodyType in bodyTypes
198210
.Where(instance => !instance.Type.IsCompilerGenerated)
@@ -242,6 +254,7 @@ var fieldMember in accessedFieldMembers
242254
private IEnumerable<MethodMemberInstance> CreateMethodBodyDependenciesRecursive(
243255
MethodBody methodBody,
244256
ICollection<MethodReference> visitedMethodReferences,
257+
List<ITypeInstance<IType>> genericArgumentTypes,
245258
List<ITypeInstance<IType>> bodyTypes,
246259
List<ITypeInstance<IType>> castTypes,
247260
List<ITypeInstance<IType>> typeCheckTypes,
@@ -258,6 +271,9 @@ var calledMethodReference in calledMethodReferences.Except(visitedMethodReferenc
258271
)
259272
{
260273
visitedMethodReferences.Add(calledMethodReference);
274+
genericArgumentTypes.AddRange(
275+
calledMethodReference.GetGenericArguments(_typeFactory)
276+
);
261277

262278
if (calledMethodReference.IsCompilerGenerated())
263279
{
@@ -301,6 +317,7 @@ var calledMethodReference in calledMethodReferences.Except(visitedMethodReferenc
301317
var dep in CreateMethodBodyDependenciesRecursive(
302318
calledMethodBody,
303319
visitedMethodReferences,
320+
genericArgumentTypes,
304321
bodyTypes,
305322
castTypes,
306323
typeCheckTypes,

ArchUnitNET/Loader/MonoCecilMemberExtensions.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,25 @@ TypeFactory typeFactory
152152
.Distinct();
153153
}
154154

155+
[NotNull]
156+
internal static IEnumerable<ITypeInstance<IType>> GetGenericArguments(
157+
this MethodReference method,
158+
TypeFactory typeFactory
159+
)
160+
{
161+
return method is GenericInstanceMethod genericInstanceMethod
162+
? genericInstanceMethod
163+
.GenericArguments.Select(argument =>
164+
{
165+
var typeReference = argument.GetElementType();
166+
return typeFactory.GetOrCreateStubTypeInstanceFromTypeReference(
167+
typeReference
168+
);
169+
})
170+
.Distinct()
171+
: Enumerable.Empty<ITypeInstance<IType>>();
172+
}
173+
155174
[NotNull]
156175
internal static IEnumerable<ITypeInstance<IType>> GetBodyTypes(
157176
this MethodDefinition methodDefinition,

ArchUnitNETTests/AssemblyTestHelper/DependencyAssemblyTestHelpers.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ public class DependencyAssemblyTestHelper : AssemblyTestHelper
5757
public Class OtherClassWithoutDependencies;
5858
public Type OtherClassWithoutDependenciesSystemType = typeof(OtherClassWithoutDependencies);
5959

60+
public Class ClassWithGenericMethodCallDependency;
61+
public Type ClassWithGenericMethodCallDependencySystemType = typeof(ClassWithGenericMethodCall);
62+
6063
public MethodMember MethodWithSingleDependency;
6164

6265
public MethodMember CalledMethod;
@@ -93,6 +96,9 @@ public DependencyAssemblyTestHelper()
9396
GenericBaseClass = Architecture.GetClassOfType(typeof(GenericBaseClass<>));
9497
ChildClassOfGeneric = Architecture.GetClassOfType(typeof(ChildClassOfGeneric));
9598
ClassWithoutDependencies = Architecture.GetClassOfType(typeof(ClassWithoutDependencies));
99+
ClassWithGenericMethodCallDependency = Architecture.GetClassOfType(
100+
typeof(ClassWithGenericMethodCall)
101+
);
96102
OtherClassWithoutDependencies = Architecture.GetClassOfType(
97103
typeof(OtherClassWithoutDependencies)
98104
);

ArchUnitNETTests/Fluent/Syntax/Elements/ObjectSyntaxElementsTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,8 @@ public async Task DependOnAnyTest()
363363
should.DependOnAny(Classes().That().Are(helper.BaseClass)).AssertNoViolations(helper);
364364
should.DependOnAny(new List<IType> { helper.BaseClass }).AssertNoViolations(helper);
365365
should.DependOnAny(new List<System.Type> { helper.BaseClassSystemType }).AssertNoViolations(helper);
366+
Types().That().Are(helper.ClassWithGenericMethodCallDependency).Should().DependOnAny(helper.ClassWithoutDependencies).AssertNoViolations(helper);
367+
Types().That().Are(helper.ClassWithGenericMethodCallDependency).Should().DependOnAny(helper.OtherClassWithoutDependencies).AssertNoViolations(helper);
366368

367369
helper.AddSnapshotSubHeader("Predicates");
368370
should.Be(Types().That().DependOnAny(helper.BaseClass)).AssertNoViolations(helper);

ArchUnitNETTests/Fluent/Syntax/Elements/Snapshots/ObjectSyntaxElementsTests.DependOnAnyTest.verified.txt

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,18 @@ Description: TypeDependencyNamespace.ChildClass passed
3232
Message:
3333
All Evaluations passed
3434

35+
Query: Types that are "TypeDependencyNamespace.ClassWithGenericMethodCall" should depend on "TypeDependencyNamespace.ClassWithoutDependencies"
36+
Result: True
37+
Description: TypeDependencyNamespace.ClassWithGenericMethodCall passed
38+
Message:
39+
All Evaluations passed
40+
41+
Query: Types that are "TypeDependencyNamespace.ClassWithGenericMethodCall" should depend on "TypeDependencyNamespace.OtherClassWithoutDependencies"
42+
Result: True
43+
Description: TypeDependencyNamespace.ClassWithGenericMethodCall passed
44+
Message:
45+
All Evaluations passed
46+
3547
----- Predicates -----
3648

3749
Query: Types that are "TypeDependencyNamespace.ChildClass" should be Types that depend on "TypeDependencyNamespace.BaseClass"
@@ -196,46 +208,46 @@ Message:
196208

197209
Query: Types that have full name "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on "TypeDependencyNamespace.ClassWithoutDependencies"
198210
Result: False
199-
Description: TypeDependencyNamespace.ClassWithMultipleDependencies does exist
211+
Description: TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ClassWithGenericMethodCall"
200212
Message:
201213
"Types that have full name "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on "TypeDependencyNamespace.ClassWithoutDependencies"" failed:
202-
TypeDependencyNamespace.ClassWithMultipleDependencies does exist
214+
TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ClassWithGenericMethodCall"
203215

204216

205217

206218
Query: Types that have full name "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on "TypeDependencyNamespace.ClassWithoutDependencies"
207219
Result: False
208-
Description: TypeDependencyNamespace.ClassWithMultipleDependencies does exist
220+
Description: TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ClassWithGenericMethodCall"
209221
Message:
210222
"Types that have full name "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on "TypeDependencyNamespace.ClassWithoutDependencies"" failed:
211-
TypeDependencyNamespace.ClassWithMultipleDependencies does exist
223+
TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ClassWithGenericMethodCall"
212224

213225

214226

215227
Query: Types that have full name "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on any Classes that are "TypeDependencyNamespace.ClassWithoutDependencies"
216228
Result: False
217-
Description: TypeDependencyNamespace.ClassWithMultipleDependencies does exist
229+
Description: TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ClassWithGenericMethodCall"
218230
Message:
219231
"Types that have full name "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on any Classes that are "TypeDependencyNamespace.ClassWithoutDependencies"" failed:
220-
TypeDependencyNamespace.ClassWithMultipleDependencies does exist
232+
TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ClassWithGenericMethodCall"
221233

222234

223235

224236
Query: Types that have full name "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on "TypeDependencyNamespace.ClassWithoutDependencies"
225237
Result: False
226-
Description: TypeDependencyNamespace.ClassWithMultipleDependencies does exist
238+
Description: TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ClassWithGenericMethodCall"
227239
Message:
228240
"Types that have full name "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on "TypeDependencyNamespace.ClassWithoutDependencies"" failed:
229-
TypeDependencyNamespace.ClassWithMultipleDependencies does exist
241+
TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ClassWithGenericMethodCall"
230242

231243

232244

233245
Query: Types that have full name "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on "TypeDependencyNamespace.ClassWithoutDependencies"
234246
Result: False
235-
Description: TypeDependencyNamespace.ClassWithMultipleDependencies does exist
247+
Description: TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ClassWithGenericMethodCall"
236248
Message:
237249
"Types that have full name "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on "TypeDependencyNamespace.ClassWithoutDependencies"" failed:
238-
TypeDependencyNamespace.ClassWithMultipleDependencies does exist
250+
TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ClassWithGenericMethodCall"
239251

240252

241253

@@ -454,37 +466,37 @@ Message:
454466

455467
Query: Types that are "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on any "TypeDependencyNamespace.ClassWithoutDependencies" or "TypeDependencyNamespace.BaseClass"
456468
Result: False
457-
Description: TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass"
469+
Description: TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass" or "TypeDependencyNamespace.ClassWithGenericMethodCall"
458470
Message:
459471
"Types that are "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on any "TypeDependencyNamespace.ClassWithoutDependencies" or "TypeDependencyNamespace.BaseClass"" failed:
460-
TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass"
472+
TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass" or "TypeDependencyNamespace.ClassWithGenericMethodCall"
461473

462474

463475

464476
Query: Types that are "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on any "TypeDependencyNamespace.ClassWithoutDependencies" or "TypeDependencyNamespace.BaseClass"
465477
Result: False
466-
Description: TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass"
478+
Description: TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass" or "TypeDependencyNamespace.ClassWithGenericMethodCall"
467479
Message:
468480
"Types that are "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on any "TypeDependencyNamespace.ClassWithoutDependencies" or "TypeDependencyNamespace.BaseClass"" failed:
469-
TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass"
481+
TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass" or "TypeDependencyNamespace.ClassWithGenericMethodCall"
470482

471483

472484

473485
Query: Types that are "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on any "TypeDependencyNamespace.ClassWithoutDependencies" or "TypeDependencyNamespace.BaseClass"
474486
Result: False
475-
Description: TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass"
487+
Description: TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass" or "TypeDependencyNamespace.ClassWithGenericMethodCall"
476488
Message:
477489
"Types that are "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on any "TypeDependencyNamespace.ClassWithoutDependencies" or "TypeDependencyNamespace.BaseClass"" failed:
478-
TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass"
490+
TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass" or "TypeDependencyNamespace.ClassWithGenericMethodCall"
479491

480492

481493

482494
Query: Types that are "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on any "TypeDependencyNamespace.ClassWithoutDependencies" or "TypeDependencyNamespace.BaseClass"
483495
Result: False
484-
Description: TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass"
496+
Description: TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass" or "TypeDependencyNamespace.ClassWithGenericMethodCall"
485497
Message:
486498
"Types that are "TypeDependencyNamespace.ClassWithMultipleDependencies" should be types that depend on any "TypeDependencyNamespace.ClassWithoutDependencies" or "TypeDependencyNamespace.BaseClass"" failed:
487-
TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass"
499+
TypeDependencyNamespace.ClassWithMultipleDependencies is not "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.OtherChildClass" or "TypeDependencyNamespace.ClassWithGenericMethodCall"
488500

489501

490502

@@ -581,13 +593,13 @@ All Evaluations passed
581593

582594
Query: Types that are "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.BaseClass" should be types that depend on "TypeDependencyNamespace.ClassWithoutDependencies"
583595
Result: False
584-
Description: TypeDependencyNamespace.BaseClass does exist
596+
Description: TypeDependencyNamespace.BaseClass is not "TypeDependencyNamespace.ClassWithGenericMethodCall"
585597
Result: False
586-
Description: TypeDependencyNamespace.ChildClass does exist
598+
Description: TypeDependencyNamespace.ChildClass is not "TypeDependencyNamespace.ClassWithGenericMethodCall"
587599
Message:
588600
"Types that are "TypeDependencyNamespace.ChildClass" or "TypeDependencyNamespace.BaseClass" should be types that depend on "TypeDependencyNamespace.ClassWithoutDependencies"" failed:
589-
TypeDependencyNamespace.BaseClass does exist
590-
TypeDependencyNamespace.ChildClass does exist
601+
TypeDependencyNamespace.BaseClass is not "TypeDependencyNamespace.ClassWithGenericMethodCall"
602+
TypeDependencyNamespace.ChildClass is not "TypeDependencyNamespace.ClassWithGenericMethodCall"
591603

592604

593605

0 commit comments

Comments
 (0)