diff --git a/ArchUnitNET/Domain/GenericParameter.cs b/ArchUnitNET/Domain/GenericParameter.cs index 17bb8b15a..d71391359 100644 --- a/ArchUnitNET/Domain/GenericParameter.cs +++ b/ArchUnitNET/Domain/GenericParameter.cs @@ -8,24 +8,22 @@ namespace ArchUnitNET.Domain { public class GenericParameter : IType { + private readonly string _declarerFullName; internal readonly IEnumerable> TypeInstanceConstraints; public GenericParameter( - ITypeInstance declaringTypeInstance, - [CanBeNull] MethodMemberInstance declaringMethodInstance, - string fullName, + string declarerFullName, string name, GenericParameterVariance variance, IEnumerable> typeConstraints, bool hasReferenceTypeConstraint, bool hasNotNullableValueTypeConstraint, bool hasDefaultConstructorConstraint, - bool isCompilerGenerated + bool isCompilerGenerated, + bool declarerIsMethod ) { - DeclaringTypeInstance = declaringTypeInstance; - DeclaringMethodInstance = declaringMethodInstance; - FullName = fullName; + _declarerFullName = declarerFullName; Name = name; Variance = variance; TypeInstanceConstraints = typeConstraints; @@ -33,17 +31,14 @@ bool isCompilerGenerated HasNotNullableValueTypeConstraint = hasNotNullableValueTypeConstraint; HasDefaultConstructorConstraint = hasDefaultConstructorConstraint; IsCompilerGenerated = isCompilerGenerated; + DeclarerIsMethod = declarerIsMethod; } - public ITypeInstance DeclaringTypeInstance { get; } - public IType DeclaringType => DeclaringTypeInstance.Type; + public IType DeclaringType { get; private set; } [CanBeNull] - public MethodMemberInstance DeclaringMethodInstance { get; } - - [CanBeNull] - public IMember DeclaringMethod => DeclaringMethodInstance?.Member; - public bool DeclarerIsMethod => DeclaringMethodInstance != null; + public IMember DeclaringMethod { get; private set; } + public bool DeclarerIsMethod { get; } public GenericParameterVariance Variance { get; } public IEnumerable TypeConstraints => TypeInstanceConstraints.Select(instance => instance.Type); @@ -58,7 +53,7 @@ bool isCompilerGenerated || TypeConstraints.Any(); public string Name { get; } - public string FullName { get; } + public string FullName => _declarerFullName + "+<" + Name + ">"; public string AssemblyQualifiedName => System.Reflection.Assembly.CreateQualifiedName( DeclaringType.Assembly.FullName, @@ -83,6 +78,27 @@ bool isCompilerGenerated 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)) diff --git a/ArchUnitNET/Loader/LoadTasks/AddGenericParameterDependencies.cs b/ArchUnitNET/Loader/LoadTasks/AddGenericParameterDependencies.cs index 4b12271de..fc9ed1ae4 100644 --- a/ArchUnitNET/Loader/LoadTasks/AddGenericParameterDependencies.cs +++ b/ArchUnitNET/Loader/LoadTasks/AddGenericParameterDependencies.cs @@ -24,6 +24,7 @@ private void AddTypeGenericParameterDependencies() { foreach (var genericParameter in _type.GenericParameters) { + genericParameter.AssignDeclarer(_type); foreach (var typeInstanceConstraint in genericParameter.TypeInstanceConstraints) { var dependency = new TypeGenericParameterTypeConstraintDependency( @@ -41,6 +42,7 @@ private void AddMemberGenericParameterDependencies() { foreach (var genericParameter in member.GenericParameters) { + genericParameter.AssignDeclarer(member); foreach (var typeInstanceConstraint in genericParameter.TypeInstanceConstraints) { var dependency = new MemberGenericParameterTypeConstraintDependency( diff --git a/ArchUnitNET/Loader/TypeFactory.cs b/ArchUnitNET/Loader/TypeFactory.cs index 07c9530f8..0745b7f12 100644 --- a/ArchUnitNET/Loader/TypeFactory.cs +++ b/ArchUnitNET/Loader/TypeFactory.cs @@ -130,31 +130,37 @@ TypeReference typeReference { var genericParameter = (Mono.Cecil.GenericParameter)typeReference; var declarerIsMethod = genericParameter.Type == GenericParameterType.Method; - var declaringType = GetOrCreateStubTypeInstanceFromTypeReference( - declarerIsMethod - ? genericParameter.DeclaringMethod.DeclaringType - : genericParameter.DeclaringType - ); - var declaringMethod = declarerIsMethod - ? GetOrCreateMethodMemberFromMethodReference( - declaringType, - genericParameter.DeclaringMethod - ) - : null; - var declarerFullName = - declaringMethod != null - ? declaringMethod.Member.FullName - : declaringType.Type.FullName; + var declarerFullName = declarerIsMethod + ? genericParameter.DeclaringMethod.BuildFullName() + : genericParameter.DeclaringType.BuildFullName(); + var declaringTypeAssemblyName = declarerIsMethod + ? genericParameter.DeclaringMethod.DeclaringType.Module.Assembly.FullName + : genericParameter.DeclaringType.Module.Assembly.FullName; var assemblyQualifiedName = System.Reflection.Assembly.CreateQualifiedName( - declaringType.Type.Assembly.FullName, + declaringTypeAssemblyName, $"{declarerFullName}+<{genericParameter.Name}>" ); if (_allTypes.TryGetValue(assemblyQualifiedName, out var existingTypeInstance)) { return existingTypeInstance; } + var isCompilerGenerated = genericParameter.IsCompilerGenerated(); + var variance = genericParameter.GetVariance(); + var typeConstraints = genericParameter.Constraints.Select(con => + GetOrCreateStubTypeInstanceFromTypeReference(con.ConstraintType) + ); var result = new TypeInstance( - CreateGenericParameter(genericParameter, declaringType, declaringMethod) + new GenericParameter( + declarerFullName, + genericParameter.Name, + variance, + typeConstraints, + genericParameter.HasReferenceTypeConstraint, + genericParameter.HasNotNullableValueTypeConstraint, + genericParameter.HasDefaultConstructorConstraint, + isCompilerGenerated, + declarerIsMethod + ) ); _allTypes.Add(assemblyQualifiedName, result); return result; @@ -199,7 +205,7 @@ TypeReference typeReference } while (elementType.IsArray); var elementTypeInstance = GetOrCreateStubTypeInstanceFromTypeReference(elementType); var assemblyQualifiedName = System.Reflection.Assembly.CreateQualifiedName( - elementTypeInstance.Type.Assembly.FullName, + elementTypeInstance.Type.Assembly?.FullName ?? "", typeReference.BuildFullName() ); if (_allTypes.TryGetValue(assemblyQualifiedName, out var existingTypeInstance)) @@ -609,35 +615,6 @@ IGenericParameterProvider genericParameterProvider .Cast(); } - private GenericParameter CreateGenericParameter( - Mono.Cecil.GenericParameter genericParameter, - ITypeInstance declaringTypeInstance, - [CanBeNull] MethodMemberInstance declaringMethodInstance - ) - { - var isCompilerGenerated = genericParameter.IsCompilerGenerated(); - var variance = genericParameter.GetVariance(); - var typeConstraints = genericParameter.Constraints.Select(con => - GetOrCreateStubTypeInstanceFromTypeReference(con.ConstraintType) - ); - var declarerFullName = - declaringMethodInstance != null - ? declaringMethodInstance.Member.FullName - : declaringTypeInstance.Type.FullName; - return new GenericParameter( - declaringTypeInstance, - declaringMethodInstance, - $"{declarerFullName}+<{genericParameter.Name}>", - genericParameter.Name, - variance, - typeConstraints, - genericParameter.HasReferenceTypeConstraint, - genericParameter.HasNotNullableValueTypeConstraint, - genericParameter.HasDefaultConstructorConstraint, - isCompilerGenerated - ); - } - internal GenericArgument CreateGenericArgumentFromTypeReference(TypeReference typeReference) { return new GenericArgument(GetOrCreateStubTypeInstanceFromTypeReference(typeReference)); diff --git a/TestAssemblies/DependencyAssembly/TypeDependency.cs b/TestAssemblies/DependencyAssembly/TypeDependency.cs index 748df2d66..49b61f880 100644 --- a/TestAssemblies/DependencyAssembly/TypeDependency.cs +++ b/TestAssemblies/DependencyAssembly/TypeDependency.cs @@ -43,3 +43,18 @@ public class ChildClassOfGeneric : GenericBaseClass { } public class ClassWithoutDependencies { } public class OtherClassWithoutDependencies { } + +// https://github.com/TNG/ArchUnitNET/issues/351 +class Issue351 +{ + public void OuterFunc() + { + LocalFunc(); + + void LocalFunc() + { + var list = new List(); + list.GroupBy(x => x).ToDictionary(g => g.Key, g => (IReadOnlyCollection)g.ToList()); + } + } +}