Skip to content

Commit cac8018

Browse files
authored
Merge pull request #8 from brandhuf/bugfix/MissingDependenciesToGenericStaticMethods
fixed another occurrence where MethodCallDependencies to generic static methods where not assigned correctly
2 parents 72ea288 + d22325a commit cac8018

File tree

7 files changed

+87
-25
lines changed

7 files changed

+87
-25
lines changed

ArchUnitNET/Core/LoadTasks/AddMembers.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using JetBrains.Annotations;
1313
using Mono.Cecil;
1414
using static ArchUnitNET.Domain.Visibility;
15+
using GenericParameter = ArchUnitNET.Domain.GenericParameter;
1516

1617
namespace ArchUnitNET.Core.LoadTasks
1718
{
@@ -127,9 +128,11 @@ private MethodMember CreateMethodMember(MethodDefinition methodDefinition)
127128
var methodForm = methodDefinition.GetMethodForm();
128129
var methodName = methodDefinition.BuildMethodMemberName();
129130
var methodDefinitionFullName = methodDefinition.GetFullName();
131+
var genericParameters =
132+
methodDefinition.GenericParameters.Select(parameter => new GenericParameter(parameter.Name)).ToList();
130133

131134
return new MethodMember(methodName, methodDefinitionFullName, _type, visibility,
132-
parameters, returnType, methodDefinition.IsVirtual, methodForm);
135+
parameters, returnType, methodDefinition.IsVirtual, methodForm, genericParameters);
133136
}
134137
}
135138
}

ArchUnitNET/Core/LoadTasks/AddMethodDependencies.cs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -167,24 +167,16 @@ private void HandlePropertyBackingFieldDependencies(MethodBody methodBody)
167167
private IEnumerable<MethodCallDependency> CreateMethodCallDependenciesFromBody(MethodMember methodMember,
168168
MethodBody methodBody)
169169
{
170-
var operands = methodBody.Instructions
171-
.Select(instruction => instruction.Operand).ToList();
172-
173-
return operands.OfType<MethodReference>()
170+
return methodBody.Instructions
171+
.Select(instruction => instruction.Operand)
172+
.OfType<MethodReference>()
174173
.Select(methodReference =>
175174
{
176175
var calledType =
177176
_typeFactory.GetOrCreateStubTypeFromTypeReference(methodReference.DeclaringType);
178177

179-
return calledType.GetMethodMemberWithFullName(methodReference.FullName);
178+
return calledType.GetMethodMemberWithMethodReference(methodReference);
180179
})
181-
.Concat(operands.OfType<GenericInstanceMethod>()
182-
.Select(genericMethod =>
183-
{
184-
var calledType = _typeFactory.GetOrCreateStubTypeFromTypeReference(genericMethod.DeclaringType);
185-
186-
return calledType.GetMethodMemberWithFullName(genericMethod.GetFullName());
187-
}))
188180
.Where(calledMethodMember => calledMethodMember != null)
189181
.Select(calledMethodMember => new MethodCallDependency(methodMember, calledMethodMember));
190182
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2019 Florian Gather <florian.gather@tngtech.com>
2+
// Copyright 2019 Paula Ruiz <paularuiz22@gmail.com>
3+
// Copyright 2019 Fritz Brandhuber <fritz.brandhuber@tngtech.com>
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
7+
namespace ArchUnitNET.Domain
8+
{
9+
public class GenericParameter
10+
{
11+
public GenericParameter(string name)
12+
{
13+
Name = name;
14+
}
15+
16+
public string Name { get; }
17+
}
18+
}

ArchUnitNET/Domain/MethodMember.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ namespace ArchUnitNET.Domain
1313
public class MethodMember : IMember
1414
{
1515
public MethodMember(string name, string fullName, IType declaringType, Visibility visibility,
16-
List<IType> parameters, IType returnType, bool isVirtual, MethodForm methodForm)
16+
List<IType> parameters, IType returnType, bool isVirtual, MethodForm methodForm,
17+
List<GenericParameter> genericParameters)
1718
{
1819
Name = name;
1920
FullName = fullName;
@@ -23,12 +24,14 @@ public MethodMember(string name, string fullName, IType declaringType, Visibilit
2324
ReturnType = returnType;
2425
IsVirtual = isVirtual;
2526
MethodForm = methodForm;
27+
GenericParameters = genericParameters;
2628
}
2729

2830
public bool IsVirtual { get; }
2931
public MethodForm MethodForm { get; }
3032
public List<IType> Parameters { get; }
3133
public IType ReturnType { get; }
34+
public List<GenericParameter> GenericParameters { get; }
3235
public Visibility Visibility { get; }
3336
public List<Attribute> Attributes { get; } = new List<Attribute>();
3437
public List<IMemberTypeDependency> MemberDependencies { get; } = new List<IMemberTypeDependency>();

ArchUnitNET/Fluent/Extensions/MonoCecilMemberExtensions.cs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using JetBrains.Annotations;
1414
using Mono.Cecil;
1515
using static ArchUnitNET.Domain.Visibility;
16+
using GenericParameter = ArchUnitNET.Domain.GenericParameter;
1617

1718
namespace ArchUnitNET.Fluent.Extensions
1819
{
@@ -60,11 +61,13 @@ internal static MethodMember CreateStubMethodMemberFromMethodReference(this Type
6061
var typeReference = methodReference.ReturnType;
6162
var returnType = typeFactory.GetOrCreateStubTypeFromTypeReference(typeReference);
6263
var parameters = methodReference.GetParameters(typeFactory).ToList();
64+
var genericParameters = methodReference.GenericParameters
65+
.Select(parameter => new GenericParameter(parameter.Name)).ToList();
6366

6467
var methodForm = methodReference.HasConstructorName() ? MethodForm.Constructor : MethodForm.Normal;
6568

6669
return new MethodMember(methodReference.BuildMethodMemberName(), methodReference.FullName, type,
67-
Public, parameters, returnType, false, methodForm);
70+
Public, parameters, returnType, false, methodForm, genericParameters);
6871
}
6972

7073
[NotNull]
@@ -203,17 +206,10 @@ public static Visibility GetVisibility(this MethodDefinition methodDefinition)
203206
throw new ArgumentException("The method definition seems to have no visibility.");
204207
}
205208

206-
public static string GetFullName(this MethodDefinition methodDefinition)
209+
public static string GetFullName(this MethodReference methodReference)
207210
{
208-
return methodDefinition.FullName + methodDefinition.GenericParameters.Aggregate(string.Empty,
211+
return methodReference.FullName + methodReference.GenericParameters.Aggregate(string.Empty,
209212
(current, newElement) => current + "<" + newElement.Name + ">");
210213
}
211-
212-
public static string GetFullName(this GenericInstanceMethod genericInstanceMethod)
213-
{
214-
return genericInstanceMethod.GetElementMethod().FullName + genericInstanceMethod.GetElementMethod()
215-
.GenericParameters.Aggregate(string.Empty,
216-
(current, newElement) => current + "<" + newElement.Name + ">");
217-
}
218214
}
219215
}

ArchUnitNET/Fluent/Extensions/TypeExtensions.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@
77
using System.Collections.Generic;
88
using System.Linq;
99
using System.Text.RegularExpressions;
10+
using ArchUnitNET.ArchitectureExceptions;
1011
using ArchUnitNET.Domain;
1112
using ArchUnitNET.Domain.Dependencies.Members;
1213
using ArchUnitNET.Domain.Dependencies.Types;
14+
using JetBrains.Annotations;
15+
using Mono.Cecil;
16+
using GenericParameter = ArchUnitNET.Domain.GenericParameter;
1317

1418
namespace ArchUnitNET.Fluent.Extensions
1519
{
@@ -105,6 +109,52 @@ public static MethodMember GetMethodMemberWithFullName(this IType type, string f
105109
return type.GetMethodMembers().WhereFullNameIs(fullName);
106110
}
107111

112+
[CanBeNull]
113+
public static MethodMember GetMethodMemberWithMethodReference(this IType type, MethodReference methodReference)
114+
{
115+
var matchingMethods = type.GetMethodMembers().Where(member => member.MatchesGeneric(methodReference))
116+
.ToList();
117+
if (matchingMethods.Count > 1)
118+
{
119+
throw new MultipleOccurrencesInSequenceException(
120+
$"Multiple Methods matching {methodReference.FullName} found in provided type.");
121+
}
122+
123+
return matchingMethods.FirstOrDefault();
124+
}
125+
126+
private static bool MatchesGeneric(this MethodMember methodMember, MethodReference methodReference)
127+
{
128+
var referenceFullName = methodReference.GetElementMethod().GetFullName();
129+
var memberFullName = methodMember.FullName;
130+
var count = methodReference.GetElementMethod().GenericParameters.Count;
131+
if (methodMember.GenericParameters.Count != count)
132+
{
133+
return false;
134+
}
135+
136+
var parameters = new List<GenericParameter[]>();
137+
for (var i = 0; i < count; i++)
138+
{
139+
parameters.Add(new[]
140+
{
141+
new GenericParameter(methodReference.GetElementMethod().GenericParameters[i].Name),
142+
methodMember.GenericParameters[i]
143+
});
144+
}
145+
146+
parameters = parameters.OrderByDescending(genericParameters => genericParameters[0].Name.Length).ToList();
147+
148+
foreach (var genericParameters in parameters.Where(genericParameters => genericParameters[0] != null)
149+
)
150+
{
151+
referenceFullName = referenceFullName.Replace(genericParameters[0].Name, genericParameters[1].Name);
152+
memberFullName = memberFullName.Replace(genericParameters[0].Name, genericParameters[1].Name);
153+
}
154+
155+
return memberFullName.Equals(referenceFullName);
156+
}
157+
108158
public static bool HasMethodMemberWithFullName(this IType type, string fullname)
109159
{
110160
return type.GetMethodMemberWithFullName(fullname) != null;

ArchUnitNETTests/Fluent/Extensions/BuildMocksExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public static MethodMember CreateStubMethodMember(this MethodBase methodBase)
134134
}
135135

136136
return new MethodMember(methodBase.BuildMockMethodName(), fullName, declaringType, visibility, parameters,
137-
returnType, methodBase.IsVirtual, methodForm);
137+
returnType, methodBase.IsVirtual, methodForm, new List<GenericParameter>());
138138
}
139139

140140
private static string BuildMockMethodName(this MethodBase methodBase)

0 commit comments

Comments
 (0)