Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deduplicate Types by Assembly Qualified Name #318

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
26 changes: 26 additions & 0 deletions ArchUnitNET/Domain/Extensions/NamingExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,31 @@ 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
{
#if !DEBUG
return source.FirstOrDefault(type =>
type.AssemblyQualifiedName == assemblyQualifiedName
);
#else
var matchingTypes = source
.Where(type => type.AssemblyQualifiedName == assemblyQualifiedName)
.ToList();
if (matchingTypes.Count > 1)
{
throw new MultipleOccurrencesInSequenceException(
$"Assembly qualified name {assemblyQualifiedName} found multiple times in provided types. "
+ "Please use extern alias to reference assemblies that have the same fully-qualified type names."
);
}
return matchingTypes.FirstOrDefault();
#endif
}
}
}
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