Skip to content

Commit 2cbfd10

Browse files
Merge pull request #318 from TNG/fix/multiple-instances-of-same-type
Deduplicate Types by Assembly Qualified Name
2 parents 9a8486f + 0a880cc commit 2cbfd10

31 files changed

+519
-478
lines changed

ArchUnitNET/Domain/Class.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public Class(Class @class)
6969
public bool IsCompilerGenerated => Type.IsCompilerGenerated;
7070
public string Name => Type.Name;
7171
public string FullName => Type.FullName;
72+
public string AssemblyQualifiedName => Type.AssemblyQualifiedName;
7273

7374
public Namespace Namespace => Type.Namespace;
7475
public Assembly Assembly => Type.Assembly;

ArchUnitNET/Domain/Enum.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public Enum(IType type)
2222
public IType Type { get; }
2323
public string Name => Type.Name;
2424
public string FullName => Type.FullName;
25+
public string AssemblyQualifiedName => Type.AssemblyQualifiedName;
2526

2627
[CanBeNull]
2728
public Class BaseClass =>

ArchUnitNET/Domain/Extensions/ArchitectureExtensions.cs

Lines changed: 32 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -50,25 +50,16 @@ [NotNull] Type type
5050
return architecture.GetInterfaceOfType(type);
5151
}
5252

53-
try
53+
var foundType = AllTypes(architecture)
54+
.WhereAssemblyQualifiedNameIs(type.AssemblyQualifiedName);
55+
if (foundType != null)
5456
{
55-
var foundType = AllTypes(architecture).WhereFullNameIs(type.FullName);
56-
if (foundType != null)
57-
{
58-
return foundType;
59-
}
60-
61-
throw new TypeDoesNotExistInArchitecture(
62-
$"Type {type.FullName} does not exist in provided architecture."
63-
);
64-
}
65-
catch (MultipleOccurrencesInSequenceException)
66-
{
67-
throw new NotSupportedException(
68-
$"Type {type.FullName} found multiple times in provided architecture. Please use extern "
69-
+ "alias to reference assemblies that have the same fully-qualified type names."
70-
);
57+
return foundType;
7158
}
59+
60+
throw new TypeDoesNotExistInArchitecture(
61+
$"Type {type.FullName} does not exist in provided architecture."
62+
);
7263
}
7364

7465
[NotNull]
@@ -77,25 +68,16 @@ public static Class GetClassOfType(
7768
[NotNull] Type type
7869
)
7970
{
80-
try
71+
var cls = AllClasses(architecture)
72+
.WhereAssemblyQualifiedNameIs(type.AssemblyQualifiedName);
73+
if (cls != null)
8174
{
82-
var cls = AllClasses(architecture).WhereFullNameIs(type.FullName);
83-
if (cls != null)
84-
{
85-
return cls;
86-
}
87-
88-
throw new TypeDoesNotExistInArchitecture(
89-
$"Type {type.FullName} does not exist in provided architecture or is no class."
90-
);
91-
}
92-
catch (MultipleOccurrencesInSequenceException)
93-
{
94-
throw new NotSupportedException(
95-
$"Type {type.FullName} found multiple times in provided architecture. Please use extern "
96-
+ "alias to reference assemblies that have the same fully-qualified type names."
97-
);
75+
return cls;
9876
}
77+
78+
throw new TypeDoesNotExistInArchitecture(
79+
$"Type {type.FullName} does not exist in provided architecture or is no class."
80+
);
9981
}
10082

10183
[NotNull]
@@ -104,25 +86,16 @@ public static Interface GetInterfaceOfType(
10486
[NotNull] Type type
10587
)
10688
{
107-
try
89+
var intf = AllInterfaces(architecture)
90+
.WhereAssemblyQualifiedNameIs(type.AssemblyQualifiedName);
91+
if (intf != null)
10892
{
109-
var intf = AllInterfaces(architecture).WhereFullNameIs(type.FullName);
110-
if (intf != null)
111-
{
112-
return intf;
113-
}
114-
115-
throw new TypeDoesNotExistInArchitecture(
116-
$"Type {type.FullName} does not exist in provided architecture or is no interface."
117-
);
118-
}
119-
catch (MultipleOccurrencesInSequenceException)
120-
{
121-
throw new NotSupportedException(
122-
$"Type {type.FullName} found multiple times in provided architecture. Please use extern "
123-
+ "alias to reference assemblies that have the same fully-qualified type names."
124-
);
93+
return intf;
12594
}
95+
96+
throw new TypeDoesNotExistInArchitecture(
97+
$"Type {type.FullName} does not exist in provided architecture or is no interface."
98+
);
12699
}
127100

128101
[NotNull]
@@ -131,25 +104,16 @@ public static Attribute GetAttributeOfType(
131104
[NotNull] Type type
132105
)
133106
{
134-
try
107+
var attribute = AllAttributes(architecture)
108+
.WhereAssemblyQualifiedNameIs(type.AssemblyQualifiedName);
109+
if (attribute != null)
135110
{
136-
var attribute = AllAttributes(architecture).WhereFullNameIs(type.FullName);
137-
if (attribute != null)
138-
{
139-
return attribute;
140-
}
141-
142-
throw new TypeDoesNotExistInArchitecture(
143-
$"Type {type.FullName} does not exist in provided architecture or is no attribute."
144-
);
145-
}
146-
catch (MultipleOccurrencesInSequenceException)
147-
{
148-
throw new NotSupportedException(
149-
$"Type {type.FullName} found multiple times in provided architecture. Please use extern "
150-
+ "alias to reference assemblies that have the same fully-qualified type names."
151-
);
111+
return attribute;
152112
}
113+
114+
throw new TypeDoesNotExistInArchitecture(
115+
$"Type {type.FullName} does not exist in provided architecture or is no attribute."
116+
);
153117
}
154118

155119
[NotNull]

ArchUnitNET/Domain/Extensions/NamingExtensions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,5 +102,17 @@ public static TType WhereFullNameIs<TType>(this IEnumerable<TType> source, strin
102102

103103
return withFullName.FirstOrDefault();
104104
}
105+
106+
[CanBeNull]
107+
public static TType WhereAssemblyQualifiedNameIs<TType>(
108+
this IEnumerable<TType> source,
109+
string assemblyQualifiedName
110+
)
111+
where TType : IHasAssemblyQualifiedName
112+
{
113+
return source.FirstOrDefault(type =>
114+
type.AssemblyQualifiedName == assemblyQualifiedName
115+
);
116+
}
105117
}
106118
}

ArchUnitNET/Domain/FieldMember.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,24 @@ Writability writability
2828
DeclaringType = declaringType;
2929
Name = name;
3030
FullName = fullName;
31+
AssemblyQualifiedName = System.Reflection.Assembly.CreateQualifiedName(
32+
declaringType.Assembly.FullName,
33+
fullName
34+
);
3135
Visibility = visibility;
3236
IsCompilerGenerated = isCompilerGenerated;
3337
_typeInstance = typeInstance;
3438
IsStatic = isStatic;
3539
Writability = writability;
3640
}
3741

42+
public Assembly Assembly => DeclaringType.Assembly;
43+
public Namespace Namespace => DeclaringType.Namespace;
3844
public Visibility Visibility { get; }
39-
4045
public IType DeclaringType { get; }
4146
public string Name { get; }
4247
public string FullName { get; }
48+
public string AssemblyQualifiedName { get; }
4349

4450
public bool IsCompilerGenerated { get; }
4551
public bool? IsStatic { get; }

ArchUnitNET/Domain/FunctionPointer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ List<ITypeInstance<IType>> parameterTypeInstances
3434
public bool IsGenericParameter => _type.IsGenericParameter;
3535
public string Name => _type.Name;
3636
public string FullName => _type.FullName;
37+
public string AssemblyQualifiedName => _type.AssemblyQualifiedName;
3738
public Visibility Visibility => _type.Visibility;
3839
public bool IsGeneric => _type.IsGeneric;
3940
public List<GenericParameter> GenericParameters => _type.GenericParameters;

ArchUnitNET/Domain/GenericParameter.cs

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,42 @@ namespace ArchUnitNET.Domain
1414
{
1515
public class GenericParameter : IType
1616
{
17-
private readonly string _declarerFullName;
1817
internal readonly IEnumerable<ITypeInstance<IType>> TypeInstanceConstraints;
1918

2019
public GenericParameter(
21-
string declarerFullName,
20+
ITypeInstance<IType> declaringTypeInstance,
21+
[CanBeNull] MethodMemberInstance declaringMethodInstance,
22+
string fullName,
2223
string name,
2324
GenericParameterVariance variance,
2425
IEnumerable<ITypeInstance<IType>> typeConstraints,
2526
bool hasReferenceTypeConstraint,
2627
bool hasNotNullableValueTypeConstraint,
2728
bool hasDefaultConstructorConstraint,
28-
bool isCompilerGenerated,
29-
bool declarerIsMethod
29+
bool isCompilerGenerated
3030
)
3131
{
32-
_declarerFullName = declarerFullName;
32+
DeclaringTypeInstance = declaringTypeInstance;
33+
DeclaringMethodInstance = declaringMethodInstance;
34+
FullName = fullName;
3335
Name = name;
3436
Variance = variance;
3537
TypeInstanceConstraints = typeConstraints;
3638
HasReferenceTypeConstraint = hasReferenceTypeConstraint;
3739
HasNotNullableValueTypeConstraint = hasNotNullableValueTypeConstraint;
3840
HasDefaultConstructorConstraint = hasDefaultConstructorConstraint;
3941
IsCompilerGenerated = isCompilerGenerated;
40-
DeclarerIsMethod = declarerIsMethod;
4142
}
4243

43-
public IType DeclaringType { get; private set; }
44+
public ITypeInstance<IType> DeclaringTypeInstance { get; }
45+
public IType DeclaringType => DeclaringTypeInstance.Type;
4446

4547
[CanBeNull]
46-
public IMember DeclaringMethod { get; private set; }
47-
public bool DeclarerIsMethod { get; }
48+
public MethodMemberInstance DeclaringMethodInstance { get; }
49+
50+
[CanBeNull]
51+
public IMember DeclaringMethod => DeclaringMethodInstance?.Member;
52+
public bool DeclarerIsMethod => DeclaringMethodInstance != null;
4853
public GenericParameterVariance Variance { get; }
4954
public IEnumerable<IType> TypeConstraints =>
5055
TypeInstanceConstraints.Select(instance => instance.Type);
@@ -59,7 +64,12 @@ bool declarerIsMethod
5964
|| TypeConstraints.Any();
6065

6166
public string Name { get; }
62-
public string FullName => _declarerFullName + "+<" + Name + ">";
67+
public string FullName { get; }
68+
public string AssemblyQualifiedName =>
69+
System.Reflection.Assembly.CreateQualifiedName(
70+
DeclaringType.Assembly.FullName,
71+
FullName
72+
);
6373
public bool IsCompilerGenerated { get; }
6474
public IEnumerable<Attribute> Attributes =>
6575
AttributeInstances.Select(instance => instance.Type);
@@ -79,27 +89,6 @@ bool declarerIsMethod
7989
public bool IsNested => true;
8090
public bool IsStub => true;
8191

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

ArchUnitNET/Domain/ICanBeAnalyzed.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
namespace ArchUnitNET.Domain
88
{
99
public interface ICanBeAnalyzed
10-
: IHasName,
10+
: IHasAssemblyQualifiedName,
11+
IResidesInNamespace,
1112
IHasDependencies,
1213
IHasAttributes,
1314
IHasVisibility,
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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.Domain
8+
{
9+
public interface IHasAssemblyQualifiedName : IHasName, IResidesInAssembly
10+
{
11+
string AssemblyQualifiedName { get; }
12+
}
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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.Domain
8+
{
9+
public interface IResidesInAssembly
10+
{
11+
Assembly Assembly { get; }
12+
}
13+
}

0 commit comments

Comments
 (0)