diff --git a/ArchUnitNET/Loader/LoadTasks/AddMethodDependencies.cs b/ArchUnitNET/Loader/LoadTasks/AddMethodDependencies.cs index fd2734cd4..5878c6d28 100644 --- a/ArchUnitNET/Loader/LoadTasks/AddMethodDependencies.cs +++ b/ArchUnitNET/Loader/LoadTasks/AddMethodDependencies.cs @@ -119,8 +119,11 @@ private IEnumerable CreateMethodSignatureDependencies MethodMember methodMember ) { - return methodReference - .GetSignatureTypes(_typeFactory) + var returnType = methodReference.GetReturnType(_typeFactory); + return (returnType != null ? new[] { returnType } : Array.Empty>()) + .Concat(methodReference.GetParameters(_typeFactory)) + .Concat(methodReference.GetGenericParameters(_typeFactory)) + .Distinct() .Select(signatureType => new MethodSignatureDependency( methodMember, signatureType diff --git a/ArchUnitNET/Loader/MonoCecilMemberExtensions.cs b/ArchUnitNET/Loader/MonoCecilMemberExtensions.cs index 2adca2969..20379af43 100644 --- a/ArchUnitNET/Loader/MonoCecilMemberExtensions.cs +++ b/ArchUnitNET/Loader/MonoCecilMemberExtensions.cs @@ -82,75 +82,33 @@ this MethodDefinition methodDefinition .Concat(methodDefinition.MethodReturnType.CustomAttributes); } - [NotNull] - internal static IEnumerable> GetSignatureTypes( - this MethodReference methodReference, - TypeFactory typeFactory - ) - { - var parameters = GetAllParameters(methodReference, typeFactory).ToList(); - var returnType = GetReturnType(methodReference, typeFactory); - if (returnType != null) - { - parameters.Insert(0, returnType); - } - - return parameters; - } - - private static ITypeInstance GetReturnType( + internal static ITypeInstance GetReturnType( this MethodReference methodReference, TypeFactory typeFactory - ) - { - return ReturnsVoid(methodReference) + ) => + ReturnsVoid(methodReference) ? null : typeFactory.GetOrCreateStubTypeInstanceFromTypeReference( methodReference.MethodReturnType.ReturnType ); - } - - [NotNull] - private static IEnumerable> GetAllParameters( - this MethodReference methodReference, - TypeFactory typeFactory - ) - { - var parameters = methodReference.GetParameters(typeFactory).ToList(); - var genericParameters = methodReference.GetGenericParameters(typeFactory).ToList(); - parameters.AddRange(genericParameters); - return parameters; - } [NotNull] internal static IEnumerable> GetParameters( this MethodReference method, TypeFactory typeFactory - ) - { - return method - .Parameters.Select(parameter => - { - var typeReference = parameter.ParameterType; - return typeFactory.GetOrCreateStubTypeInstanceFromTypeReference(typeReference); - }) - .Distinct(); - } + ) => + method.Parameters.Select(parameter => + typeFactory.GetOrCreateStubTypeInstanceFromTypeReference(parameter.ParameterType) + ); [NotNull] - private static IEnumerable> GetGenericParameters( + internal static IEnumerable> GetGenericParameters( this MethodReference method, TypeFactory typeFactory - ) - { - return method - .GenericParameters.Select(parameter => - { - var typeReference = parameter.GetElementType(); - return typeFactory.GetOrCreateStubTypeInstanceFromTypeReference(typeReference); - }) - .Distinct(); - } + ) => + method.GenericParameters.Select( + typeFactory.GetOrCreateStubTypeInstanceFromTypeReference + ); [NotNull] internal static IEnumerable> GetBodyTypes( diff --git a/ArchUnitNETTests/Loader/MonoCecilMemberExtensionsTests.cs b/ArchUnitNETTests/Loader/MonoCecilMemberExtensionsTests.cs new file mode 100644 index 000000000..2026599c8 --- /dev/null +++ b/ArchUnitNETTests/Loader/MonoCecilMemberExtensionsTests.cs @@ -0,0 +1,104 @@ +using System.Linq; +using ArchUnitNET.Domain; +using ArchUnitNET.Domain.Extensions; +using Xunit; +using static ArchUnitNETTests.StaticTestArchitectures; + +namespace ArchUnitNETTests.Loader +{ + public class MonoCecilMemberExtensionsTests + { + private static readonly Architecture LoaderTestArchitecture = + StaticTestArchitectures.LoaderTestArchitecture; + + [Fact] + public void GetParameters_PreservesDuplicateParameterTypes() + { + var @class = LoaderTestArchitecture + .Types.OfType() + .FirstOrDefault(c => c.Name == "ClassWithDuplicateParameters"); + + Assert.NotNull(@class); + + var method = @class + .GetMethodMembers() + .First(m => m.FullName.Contains("MethodWithSameParameterType")); + + Assert.Equal(2, method.ParameterInstances.Count); + Assert.All( + method.ParameterInstances, + p => Assert.Equal("System.String", p.Type.FullName) + ); + } + + [Fact] + public void GetParameters_PreservesMultipleDuplicateParameterTypes() + { + var @class = LoaderTestArchitecture + .Types.OfType() + .FirstOrDefault(c => c.Name == "ClassWithDuplicateParameters"); + + Assert.NotNull(@class); + + var method = @class + .GetMethodMembers() + .First(m => m.FullName.Contains("MethodWithTripleDuplicate")); + + Assert.Equal(3, method.ParameterInstances.Count); + Assert.All( + method.ParameterInstances, + p => Assert.Equal("System.Int32", p.Type.FullName) + ); + } + + [Fact] + public void GetParameters_MixedTypeWithDuplicates() + { + var @class = LoaderTestArchitecture + .Types.OfType() + .FirstOrDefault(c => c.Name == "ClassWithDuplicateParameters"); + + Assert.NotNull(@class); + + var method = @class + .GetMethodMembers() + .First(m => m.FullName.Contains("MethodWithMixedParamTypes")); + + Assert.Equal(5, method.ParameterInstances.Count); + + var stringParameters = method.ParameterInstances.Count(p => + p.Type.FullName == "System.String" + ); + var intParameters = method.ParameterInstances.Count(p => + p.Type.FullName == "System.Int32" + ); + var boolParameters = method.ParameterInstances.Count(p => + p.Type.FullName == "System.Boolean" + ); + + Assert.Equal(3, stringParameters); + Assert.Equal(1, intParameters); + Assert.Equal(1, boolParameters); + } + + [Fact] + public void GetParameters_CustomTypeDuplicates() + { + var @class = LoaderTestArchitecture + .Types.OfType() + .FirstOrDefault(c => c.Name == "ClassWithDuplicateParameters"); + + Assert.NotNull(@class); + + var method = @class + .GetMethodMembers() + .First(m => m.FullName.Contains("MethodWithCustomTypeDuplicates")); + + Assert.Equal(2, method.ParameterInstances.Count); + Assert.All( + method.ParameterInstances, + p => Assert.Contains("CustomType", p.Type.FullName) + ); + } + } +} diff --git a/TestAssemblies/LoaderTestAssembly/LoaderTestAssembly.cs b/TestAssemblies/LoaderTestAssembly/LoaderTestAssembly.cs index 9de88db39..d78500f17 100644 --- a/TestAssemblies/LoaderTestAssembly/LoaderTestAssembly.cs +++ b/TestAssemblies/LoaderTestAssembly/LoaderTestAssembly.cs @@ -1,3 +1,16 @@ namespace LoaderTestAssembly; public class LoaderTestAssembly { } + +public class ClassWithDuplicateParameters +{ + public void MethodWithSameParameterType(string param1, string param2) { } + + public void MethodWithTripleDuplicate(int a, int b, int c) { } + + public void MethodWithMixedParamTypes(string s1, int i, string s2, bool b, string s3) { } + + public void MethodWithCustomTypeDuplicates(CustomType a, CustomType b) { } +} + +public class CustomType { }