Skip to content

Commit

Permalink
Merge pull request #318 from TNG/fix/multiple-instances-of-same-type
Browse files Browse the repository at this point in the history
Deduplicate Types by Assembly Qualified Name
  • Loading branch information
alexanderlinne authored Jan 24, 2025
2 parents 9a8486f + 0a880cc commit 2cbfd10
Show file tree
Hide file tree
Showing 31 changed files with 519 additions and 478 deletions.
1 change: 1 addition & 0 deletions ArchUnitNET/Domain/Class.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public Class(Class @class)
public bool IsCompilerGenerated => Type.IsCompilerGenerated;
public string Name => Type.Name;
public string FullName => Type.FullName;
public string AssemblyQualifiedName => Type.AssemblyQualifiedName;

public Namespace Namespace => Type.Namespace;
public Assembly Assembly => Type.Assembly;
Expand Down
1 change: 1 addition & 0 deletions ArchUnitNET/Domain/Enum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public Enum(IType type)
public IType Type { get; }
public string Name => Type.Name;
public string FullName => Type.FullName;
public string AssemblyQualifiedName => Type.AssemblyQualifiedName;

[CanBeNull]
public Class BaseClass =>
Expand Down
100 changes: 32 additions & 68 deletions ArchUnitNET/Domain/Extensions/ArchitectureExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,16 @@ [NotNull] Type type
return architecture.GetInterfaceOfType(type);
}

try
var foundType = AllTypes(architecture)
.WhereAssemblyQualifiedNameIs(type.AssemblyQualifiedName);
if (foundType != null)
{
var foundType = AllTypes(architecture).WhereFullNameIs(type.FullName);
if (foundType != null)
{
return foundType;
}

throw new TypeDoesNotExistInArchitecture(
$"Type {type.FullName} does not exist in provided architecture."
);
}
catch (MultipleOccurrencesInSequenceException)
{
throw new NotSupportedException(
$"Type {type.FullName} found multiple times in provided architecture. Please use extern "
+ "alias to reference assemblies that have the same fully-qualified type names."
);
return foundType;
}

throw new TypeDoesNotExistInArchitecture(
$"Type {type.FullName} does not exist in provided architecture."
);
}

[NotNull]
Expand All @@ -77,25 +68,16 @@ public static Class GetClassOfType(
[NotNull] Type type
)
{
try
var cls = AllClasses(architecture)
.WhereAssemblyQualifiedNameIs(type.AssemblyQualifiedName);
if (cls != null)
{
var cls = AllClasses(architecture).WhereFullNameIs(type.FullName);
if (cls != null)
{
return cls;
}

throw new TypeDoesNotExistInArchitecture(
$"Type {type.FullName} does not exist in provided architecture or is no class."
);
}
catch (MultipleOccurrencesInSequenceException)
{
throw new NotSupportedException(
$"Type {type.FullName} found multiple times in provided architecture. Please use extern "
+ "alias to reference assemblies that have the same fully-qualified type names."
);
return cls;
}

throw new TypeDoesNotExistInArchitecture(
$"Type {type.FullName} does not exist in provided architecture or is no class."
);
}

[NotNull]
Expand All @@ -104,25 +86,16 @@ public static Interface GetInterfaceOfType(
[NotNull] Type type
)
{
try
var intf = AllInterfaces(architecture)
.WhereAssemblyQualifiedNameIs(type.AssemblyQualifiedName);
if (intf != null)
{
var intf = AllInterfaces(architecture).WhereFullNameIs(type.FullName);
if (intf != null)
{
return intf;
}

throw new TypeDoesNotExistInArchitecture(
$"Type {type.FullName} does not exist in provided architecture or is no interface."
);
}
catch (MultipleOccurrencesInSequenceException)
{
throw new NotSupportedException(
$"Type {type.FullName} found multiple times in provided architecture. Please use extern "
+ "alias to reference assemblies that have the same fully-qualified type names."
);
return intf;
}

throw new TypeDoesNotExistInArchitecture(
$"Type {type.FullName} does not exist in provided architecture or is no interface."
);
}

[NotNull]
Expand All @@ -131,25 +104,16 @@ public static Attribute GetAttributeOfType(
[NotNull] Type type
)
{
try
var attribute = AllAttributes(architecture)
.WhereAssemblyQualifiedNameIs(type.AssemblyQualifiedName);
if (attribute != null)
{
var attribute = AllAttributes(architecture).WhereFullNameIs(type.FullName);
if (attribute != null)
{
return attribute;
}

throw new TypeDoesNotExistInArchitecture(
$"Type {type.FullName} does not exist in provided architecture or is no attribute."
);
}
catch (MultipleOccurrencesInSequenceException)
{
throw new NotSupportedException(
$"Type {type.FullName} found multiple times in provided architecture. Please use extern "
+ "alias to reference assemblies that have the same fully-qualified type names."
);
return attribute;
}

throw new TypeDoesNotExistInArchitecture(
$"Type {type.FullName} does not exist in provided architecture or is no attribute."
);
}

[NotNull]
Expand Down
12 changes: 12 additions & 0 deletions ArchUnitNET/Domain/Extensions/NamingExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,17 @@ public static TType WhereFullNameIs<TType>(this IEnumerable<TType> source, strin

return withFullName.FirstOrDefault();
}

[CanBeNull]
public static TType WhereAssemblyQualifiedNameIs<TType>(
this IEnumerable<TType> source,
string assemblyQualifiedName
)
where TType : IHasAssemblyQualifiedName
{
return source.FirstOrDefault(type =>
type.AssemblyQualifiedName == assemblyQualifiedName
);
}
}
}
8 changes: 7 additions & 1 deletion ArchUnitNET/Domain/FieldMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,24 @@ Writability writability
DeclaringType = declaringType;
Name = name;
FullName = fullName;
AssemblyQualifiedName = System.Reflection.Assembly.CreateQualifiedName(
declaringType.Assembly.FullName,
fullName
);
Visibility = visibility;
IsCompilerGenerated = isCompilerGenerated;
_typeInstance = typeInstance;
IsStatic = isStatic;
Writability = writability;
}

public Assembly Assembly => DeclaringType.Assembly;
public Namespace Namespace => DeclaringType.Namespace;
public Visibility Visibility { get; }

public IType DeclaringType { get; }
public string Name { get; }
public string FullName { get; }
public string AssemblyQualifiedName { get; }

public bool IsCompilerGenerated { get; }
public bool? IsStatic { get; }
Expand Down
1 change: 1 addition & 0 deletions ArchUnitNET/Domain/FunctionPointer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ List<ITypeInstance<IType>> parameterTypeInstances
public bool IsGenericParameter => _type.IsGenericParameter;
public string Name => _type.Name;
public string FullName => _type.FullName;
public string AssemblyQualifiedName => _type.AssemblyQualifiedName;
public Visibility Visibility => _type.Visibility;
public bool IsGeneric => _type.IsGeneric;
public List<GenericParameter> GenericParameters => _type.GenericParameters;
Expand Down
51 changes: 20 additions & 31 deletions ArchUnitNET/Domain/GenericParameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,42 @@ namespace ArchUnitNET.Domain
{
public class GenericParameter : IType
{
private readonly string _declarerFullName;
internal readonly IEnumerable<ITypeInstance<IType>> TypeInstanceConstraints;

public GenericParameter(
string declarerFullName,
ITypeInstance<IType> declaringTypeInstance,
[CanBeNull] MethodMemberInstance declaringMethodInstance,
string fullName,
string name,
GenericParameterVariance variance,
IEnumerable<ITypeInstance<IType>> typeConstraints,
bool hasReferenceTypeConstraint,
bool hasNotNullableValueTypeConstraint,
bool hasDefaultConstructorConstraint,
bool isCompilerGenerated,
bool declarerIsMethod
bool isCompilerGenerated
)
{
_declarerFullName = declarerFullName;
DeclaringTypeInstance = declaringTypeInstance;
DeclaringMethodInstance = declaringMethodInstance;
FullName = fullName;
Name = name;
Variance = variance;
TypeInstanceConstraints = typeConstraints;
HasReferenceTypeConstraint = hasReferenceTypeConstraint;
HasNotNullableValueTypeConstraint = hasNotNullableValueTypeConstraint;
HasDefaultConstructorConstraint = hasDefaultConstructorConstraint;
IsCompilerGenerated = isCompilerGenerated;
DeclarerIsMethod = declarerIsMethod;
}

public IType DeclaringType { get; private set; }
public ITypeInstance<IType> DeclaringTypeInstance { get; }
public IType DeclaringType => DeclaringTypeInstance.Type;

[CanBeNull]
public IMember DeclaringMethod { get; private set; }
public bool DeclarerIsMethod { get; }
public MethodMemberInstance DeclaringMethodInstance { get; }

[CanBeNull]
public IMember DeclaringMethod => DeclaringMethodInstance?.Member;
public bool DeclarerIsMethod => DeclaringMethodInstance != null;
public GenericParameterVariance Variance { get; }
public IEnumerable<IType> TypeConstraints =>
TypeInstanceConstraints.Select(instance => instance.Type);
Expand All @@ -59,7 +64,12 @@ bool declarerIsMethod
|| TypeConstraints.Any();

public string Name { get; }
public string FullName => _declarerFullName + "+<" + Name + ">";
public string FullName { get; }
public string AssemblyQualifiedName =>
System.Reflection.Assembly.CreateQualifiedName(
DeclaringType.Assembly.FullName,
FullName
);
public bool IsCompilerGenerated { get; }
public IEnumerable<Attribute> Attributes =>
AttributeInstances.Select(instance => instance.Type);
Expand All @@ -79,27 +89,6 @@ bool declarerIsMethod
public bool IsNested => true;
public bool IsStub => true;

internal void AssignDeclarer(IMember declaringMethod)
{
if (!declaringMethod.FullName.Equals(_declarerFullName))
{
throw new InvalidOperationException("Full name of declaring member doesn't match.");
}

DeclaringType = declaringMethod.DeclaringType;
DeclaringMethod = declaringMethod;
}

internal void AssignDeclarer(IType declaringType)
{
if (!declaringType.FullName.Equals(_declarerFullName))
{
throw new InvalidOperationException("Full name of declaring type doesn't match.");
}

DeclaringType = declaringType;
}

public bool Equals(GenericParameter other)
{
if (ReferenceEquals(null, other))
Expand Down
3 changes: 2 additions & 1 deletion ArchUnitNET/Domain/ICanBeAnalyzed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
namespace ArchUnitNET.Domain
{
public interface ICanBeAnalyzed
: IHasName,
: IHasAssemblyQualifiedName,
IResidesInNamespace,
IHasDependencies,
IHasAttributes,
IHasVisibility,
Expand Down
13 changes: 13 additions & 0 deletions ArchUnitNET/Domain/IHasAssemblyQualifiedName.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2019 Florian Gather <[email protected]>
// Copyright 2019 Fritz Brandhuber <[email protected]>
// Copyright 2020 Pavel Fischer <[email protected]>
//
// SPDX-License-Identifier: Apache-2.0

namespace ArchUnitNET.Domain
{
public interface IHasAssemblyQualifiedName : IHasName, IResidesInAssembly
{
string AssemblyQualifiedName { get; }
}
}
13 changes: 13 additions & 0 deletions ArchUnitNET/Domain/IResidesInAssembly.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2019 Florian Gather <[email protected]>
// Copyright 2019 Fritz Brandhuber <[email protected]>
// Copyright 2020 Pavel Fischer <[email protected]>
//
// SPDX-License-Identifier: Apache-2.0

namespace ArchUnitNET.Domain
{
public interface IResidesInAssembly
{
Assembly Assembly { get; }
}
}
13 changes: 13 additions & 0 deletions ArchUnitNET/Domain/IResidesInNamespace.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2019 Florian Gather <[email protected]>
// Copyright 2019 Fritz Brandhuber <[email protected]>
// Copyright 2020 Pavel Fischer <[email protected]>
//
// SPDX-License-Identifier: Apache-2.0

namespace ArchUnitNET.Domain
{
public interface IResidesInNamespace
{
Namespace Namespace { get; }
}
}
2 changes: 0 additions & 2 deletions ArchUnitNET/Domain/IType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ namespace ArchUnitNET.Domain
{
public interface IType : ICanBeAnalyzed
{
Namespace Namespace { get; }
Assembly Assembly { get; }
MemberList Members { get; }
IEnumerable<IType> ImplementedInterfaces { get; }
bool IsNested { get; }
Expand Down
1 change: 1 addition & 0 deletions ArchUnitNET/Domain/Interface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public Interface(IType type)
public IType Type { get; }
public string Name => Type.Name;
public string FullName => Type.FullName;
public string AssemblyQualifiedName => Type.AssemblyQualifiedName;

public Visibility Visibility => Type.Visibility;
public bool IsNested => Type.IsNested;
Expand Down
Loading

0 comments on commit 2cbfd10

Please sign in to comment.