Skip to content

Commit 60bf37c

Browse files
Merge pull request #312 from TNG/fix/correctly-resolve-assemblies
Correctly Resolve Assemblies for Types
2 parents bba7065 + e75fe2b commit 60bf37c

File tree

7 files changed

+208
-28
lines changed

7 files changed

+208
-28
lines changed

ArchUnitNET/Domain/FunctionPointer.cs

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright 2019 Florian Gather <[email protected]>
2+
// Copyright 2019 Fritz Brandhuber <[email protected]>
3+
// Copyright 2020 Pavel Fischer <[email protected]>
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using ArchUnitNET.Domain.Dependencies;
10+
11+
namespace ArchUnitNET.Domain
12+
{
13+
public class FunctionPointer : IType
14+
{
15+
private readonly IType _type;
16+
17+
public FunctionPointer(
18+
IType type,
19+
ITypeInstance<IType> returnTypeInstance,
20+
List<ITypeInstance<IType>> parameterTypeInstances
21+
)
22+
{
23+
_type = type;
24+
ReturnTypeInstance = returnTypeInstance;
25+
ParameterTypeInstances = parameterTypeInstances;
26+
}
27+
28+
public Namespace Namespace => _type.Namespace;
29+
public Assembly Assembly => _type.Assembly;
30+
public MemberList Members => _type.Members;
31+
public IEnumerable<IType> ImplementedInterfaces => _type.ImplementedInterfaces;
32+
public bool IsNested => _type.IsNested;
33+
public bool IsStub => _type.IsStub;
34+
public bool IsGenericParameter => _type.IsGenericParameter;
35+
public string Name => _type.Name;
36+
public string FullName => _type.FullName;
37+
public Visibility Visibility => _type.Visibility;
38+
public bool IsGeneric => _type.IsGeneric;
39+
public List<GenericParameter> GenericParameters => _type.GenericParameters;
40+
public bool IsCompilerGenerated => _type.IsCompilerGenerated;
41+
public List<ITypeDependency> Dependencies => _type.Dependencies;
42+
public List<ITypeDependency> BackwardsDependencies => _type.BackwardsDependencies;
43+
public IEnumerable<Attribute> Attributes => _type.Attributes;
44+
public List<AttributeInstance> AttributeInstances => _type.AttributeInstances;
45+
public ITypeInstance<IType> ReturnTypeInstance { get; }
46+
public List<ITypeInstance<IType>> ParameterTypeInstances { get; }
47+
48+
public bool Equals(FunctionPointer other)
49+
{
50+
if (ReferenceEquals(null, other))
51+
{
52+
return false;
53+
}
54+
if (ReferenceEquals(this, other))
55+
{
56+
return true;
57+
}
58+
return Equals(_type, other._type)
59+
&& Equals(ReturnTypeInstance, other.ReturnTypeInstance)
60+
&& ParameterTypeInstances.SequenceEqual(other.ParameterTypeInstances);
61+
}
62+
63+
public override bool Equals(object obj)
64+
{
65+
if (ReferenceEquals(null, obj))
66+
{
67+
return false;
68+
}
69+
if (ReferenceEquals(this, obj))
70+
{
71+
return true;
72+
}
73+
return obj.GetType() == GetType() && Equals((FunctionPointer)obj);
74+
}
75+
76+
public override int GetHashCode()
77+
{
78+
unchecked
79+
{
80+
var hashCode = _type.GetHashCode();
81+
hashCode =
82+
(hashCode * 397)
83+
^ (ReturnTypeInstance != null ? ReturnTypeInstance.GetHashCode() : 0);
84+
hashCode = ParameterTypeInstances.Aggregate(
85+
hashCode,
86+
(current, typeInstance) =>
87+
(current * 397) ^ (typeInstance != null ? typeInstance.GetHashCode() : 0)
88+
);
89+
return hashCode;
90+
}
91+
}
92+
}
93+
}
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2019 Florian Gather <[email protected]>
2+
// Copyright 2019 Fritz Brandhuber <[email protected]>
3+
// Copyright 2020 Pavel Fischer <[email protected]>
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
7+
namespace ArchUnitNET.Loader
8+
{
9+
public class ArchLoaderException : System.Exception
10+
{
11+
public ArchLoaderException(string message)
12+
: base(message) { }
13+
14+
public ArchLoaderException(string message, System.Exception innerException)
15+
: base(message, innerException) { }
16+
}
17+
}

ArchUnitNET/Loader/TypeFactory.cs

+59-27
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//
55
// SPDX-License-Identifier: Apache-2.0
66

7+
using System;
78
using System.Collections.Generic;
89
using System.Linq;
910
using System.Runtime.CompilerServices;
@@ -199,18 +200,40 @@ bool isStub
199200
}
200201
}
201202

203+
if (
204+
typeReference.IsByReference
205+
|| typeReference.IsPointer
206+
|| typeReference.IsPinned
207+
|| typeReference.IsRequiredModifier
208+
)
209+
{
210+
return CreateTypeFromTypeReference(typeReference.GetElementType(), isStub);
211+
}
212+
213+
if (typeReference is FunctionPointerType functionPointerType)
214+
{
215+
return GetOrCreateTypeInstance(functionPointerType);
216+
}
217+
202218
TypeDefinition typeDefinition;
203219
try
204220
{
205221
typeDefinition = typeReference.Resolve();
206222
}
207-
catch (AssemblyResolutionException)
223+
catch (AssemblyResolutionException e)
224+
{
225+
throw new ArchLoaderException(
226+
$"Could not resolve type {typeReference.FullName}",
227+
e
228+
);
229+
}
230+
if (typeDefinition == null)
208231
{
209-
typeDefinition = null;
232+
throw new ArchLoaderException($"Could not resolve type {typeReference.FullName}");
210233
}
211234

212-
var typeName = typeReference.BuildFullName();
213-
var declaringTypeReference = typeReference;
235+
var typeName = typeDefinition.BuildFullName();
236+
var declaringTypeReference = typeDefinition;
214237
while (declaringTypeReference.IsNested)
215238
{
216239
declaringTypeReference = declaringTypeReference.DeclaringType;
@@ -220,8 +243,8 @@ bool isStub
220243
declaringTypeReference.Namespace
221244
);
222245
var currentAssembly = _assemblyRegistry.GetOrCreateAssembly(
223-
typeReference.Module.Assembly.Name.FullName,
224-
typeReference.Module.Assembly.FullName,
246+
typeDefinition.Module.Assembly.Name.FullName,
247+
typeDefinition.Module.Assembly.FullName,
225248
true,
226249
null
227250
);
@@ -231,26 +254,6 @@ bool isStub
231254
isNested,
232255
isGeneric;
233256

234-
if (typeDefinition == null)
235-
{
236-
isCompilerGenerated = typeReference.IsCompilerGenerated();
237-
isNested = typeReference.IsNested;
238-
isGeneric = typeReference.HasGenericParameters;
239-
type = new Type(
240-
typeName,
241-
typeReference.Name,
242-
currentAssembly,
243-
currentNamespace,
244-
NotAccessible,
245-
isNested,
246-
isGeneric,
247-
true,
248-
isCompilerGenerated
249-
);
250-
251-
return new TypeInstance<IType>(type);
252-
}
253-
254257
const string fixedElementField = "FixedElementField";
255258

256259
if (
@@ -312,7 +315,7 @@ bool isStub
312315
isGeneric = typeDefinition.HasGenericParameters;
313316
type = new Type(
314317
typeName,
315-
typeReference.Name,
318+
typeDefinition.Name,
316319
currentAssembly,
317320
currentNamespace,
318321
visibility,
@@ -373,6 +376,35 @@ bool isStub
373376
return createdTypeInstance;
374377
}
375378

379+
[NotNull]
380+
private ITypeInstance<FunctionPointer> GetOrCreateTypeInstance(
381+
FunctionPointerType functionPointerType
382+
)
383+
{
384+
var type = new Type(
385+
functionPointerType.FullName,
386+
functionPointerType.Name,
387+
null,
388+
null,
389+
Public,
390+
false,
391+
false,
392+
false,
393+
false
394+
);
395+
var returnTypeInstance = GetOrCreateStubTypeInstanceFromTypeReference(
396+
functionPointerType.ReturnType
397+
);
398+
var parameterTypeInstances = functionPointerType
399+
.Parameters.Select(parameter =>
400+
GetOrCreateStubTypeInstanceFromTypeReference(parameter.ParameterType)
401+
)
402+
.ToList();
403+
return new TypeInstance<FunctionPointer>(
404+
new FunctionPointer(type, returnTypeInstance, parameterTypeInstances)
405+
);
406+
}
407+
376408
[NotNull]
377409
private MethodMemberInstance CreateMethodMemberFromMethodReference(
378410
[NotNull] ITypeInstance<IType> typeInstance,

ArchUnitNETTests/Domain/Dependencies/Members/MethodCallDependencyTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ MethodCallDependency expectedDependency
6464
Assert.Contains(expectedDependency, originMember.GetMethodCallDependencies());
6565
}
6666

67-
[Theory]
67+
[SkipInReleaseBuildTheory]
6868
[ClassData(typeof(MethodDependencyTestBuild.MethodCallDependencyInAsyncMethodTestData))]
6969
public void MethodCallDependenciesAreFoundInAsyncMethod(
7070
IMember originMember,

ArchUnitNETTests/Loader/ArchLoaderTests.cs

+16
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66

77
using System.Linq;
88
using ArchUnitNET.Loader;
9+
using ArchUnitNET.xUnit;
910
using ArchUnitNETTests.Domain.Dependencies.Members;
1011
using Xunit;
12+
using static ArchUnitNET.Fluent.ArchRuleDefinition;
1113
using static ArchUnitNETTests.StaticTestArchitectures;
1214

1315
namespace ArchUnitNETTests.Loader
@@ -82,5 +84,19 @@ public void LoadAssembliesRecursively_NestedDependencyOnly()
8284

8385
Assert.Single(architecture.Assemblies);
8486
}
87+
88+
[Fact]
89+
public void TypesAreAssignedToCorrectAssemblies()
90+
{
91+
// https://github.com/TNG/ArchUnitNET/issues/302
92+
var architecture = FullArchUnitNETArchitecture;
93+
Types()
94+
.That()
95+
.ResideInAssembly(architecture.GetType().Assembly)
96+
.Should()
97+
.NotDependOnAnyTypesThat()
98+
.ResideInAssembly(GetType().Assembly)
99+
.Check(architecture);
100+
}
85101
}
86102
}

ArchUnitNETTests/Loader/TypeTests.cs

+12
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//
55
// SPDX-License-Identifier: Apache-2.0
66

7+
using System.Linq;
78
using ArchUnitNET.Domain;
89
using ArchUnitNET.Domain.Dependencies;
910
using ArchUnitNET.Domain.Extensions;
@@ -122,6 +123,17 @@ public void NotAssignableToNull()
122123
{
123124
Assert.False(_type.IsAssignableTo(null));
124125
}
126+
127+
[Fact]
128+
public void TypesAreNotLoadedFromMultipleAssemblies()
129+
{
130+
var booleanType = _architecture
131+
.Types.Concat(_architecture.ReferencedTypes)
132+
.Where(type => type.FullName == "System.Boolean")
133+
.ToList();
134+
Assert.Single(booleanType);
135+
Assert.False(booleanType.First().Assembly.Name.StartsWith("ArchUnitNET"));
136+
}
125137
}
126138

127139
[Example]

ArchUnitNETTests/SkipInReleaseBuild.cs

+10
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ public SkipInReleaseBuild()
1515
{
1616
#if !DEBUG
1717
Skip = "This test only works in debug build";
18+
#endif
19+
}
20+
}
21+
22+
public sealed class SkipInReleaseBuildTheory : TheoryAttribute
23+
{
24+
public SkipInReleaseBuildTheory()
25+
{
26+
#if !DEBUG
27+
Skip = "This test only works in debug build";
1828
#endif
1929
}
2030
}

0 commit comments

Comments
 (0)