Skip to content
Merged
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
11 changes: 11 additions & 0 deletions ArchUnitNET/Loader/TypeProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,17 @@ var calledMethodReference in calledMethodReferences.Except(visitedMethodReferenc
);
}

if (calledMethodDefinition.IsAsync())
{
HandleAsync(
out calledMethodDefinition,
ref calledMethodBody,
bodyTypes,
visitedMethodReferences,
domainResolver
);
}

var calledScan = calledMethodDefinition.ScanMethodBody(domainResolver);
bodyTypes.AddRange(calledScan.BodyTypes);
castTypes.AddRange(calledScan.CastTypes);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Linq;
using System;
using System.Linq;
using System.Threading.Tasks;
using ArchUnitNET.Domain;
using ArchUnitNET.Domain.Dependencies;
using ArchUnitNET.Domain.Extensions;
Expand Down Expand Up @@ -107,6 +109,17 @@ MethodCallDependency expectedDependency
Assert.Contains(expectedDependency, originMember.GetMethodCallDependencies());
}

[Theory]
[ClassData(typeof(MethodDependencyTestBuild.MethodCallDependencyInAsyncLambdaTestData))]
public void MethodCallDependenciesAreFoundInAsyncLambdas(
IMember originMember,
MethodCallDependency expectedDependency
)
{
Assert.True(originMember.HasMemberDependency(expectedDependency));
Assert.Contains(expectedDependency, originMember.GetMethodCallDependencies());
}

[Theory]
[ClassData(
typeof(MethodDependencyTestBuild.MethodCallGenericConstructorArgumentsDependencyTestData)
Expand Down Expand Up @@ -173,6 +186,88 @@ public static async void MethodAAsync()
}
}

public class ClassWithAsyncLambdas
{
public static void MethodWithAsyncLambda()
{
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
Func<Task> asyncLambda = async () =>
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
var classWithMethodB = new ClassWithMethodB();
ClassWithMethodB.MethodB();
};
}
}

public class ClassWithAsyncLambdaVariants
{
public static void MethodWithCapturingAsyncLambda()
{
var capturedValue = 0;
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
Func<Task> asyncLambda = async () =>
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
capturedValue++;
var classWithMethodB = new ClassWithMethodB();
ClassWithMethodB.MethodB();
};
}

public static void MethodWithAsyncLocalFunction()
{
_ = LocalFunctionAsync();

#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
async Task LocalFunctionAsync()
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
var classWithMethodB = new ClassWithMethodB();
ClassWithMethodB.MethodB();
}
}

public static void MethodWithNestedAsyncLambda()
{
Func<Task> outerAsyncLambda = async () =>
{
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
Func<Task> innerAsyncLambda = async () =>
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
var classWithMethodB = new ClassWithMethodB();
ClassWithMethodB.MethodB();
};
await innerAsyncLambda();
};
}

public static async Task AsyncMethodWithAsyncLambda()
{
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
Func<Task> asyncLambda = async () =>
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
var classWithMethodB = new ClassWithMethodB();
ClassWithMethodB.MethodB();
};
await asyncLambda();
}

public static void GenericMethodWithAsyncLambda<T>()
{
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
Func<Task<T>> asyncLambda = async () =>
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
var classWithMethodB = new ClassWithMethodB();
ClassWithMethodB.MethodB();
return default;
};
}
}

public class ClassWithMethodWithGenericConstructorArguments
{
public static void Method()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,105 @@ IEnumerator IEnumerable.GetEnumerator()
}
}

public class MethodCallDependencyInAsyncLambdaTestData : IEnumerable<object[]>
{
private readonly List<object[]> _methodCallDependencyData = new List<object[]>
{
BuildMethodCallDependencyTestData(
typeof(ClassWithAsyncLambdas),
nameof(ClassWithAsyncLambdas.MethodWithAsyncLambda).BuildMethodMemberName(),
typeof(ClassWithMethodB),
StaticConstants.ConstructorNameBase.BuildMethodMemberName()
),
BuildMethodCallDependencyTestData(
typeof(ClassWithAsyncLambdas),
nameof(ClassWithAsyncLambdas.MethodWithAsyncLambda).BuildMethodMemberName(),
typeof(ClassWithMethodB),
nameof(ClassWithMethodB.MethodB).BuildMethodMemberName()
),
BuildMethodCallDependencyTestData(
typeof(ClassWithAsyncLambdaVariants),
nameof(ClassWithAsyncLambdaVariants.MethodWithCapturingAsyncLambda)
.BuildMethodMemberName(),
typeof(ClassWithMethodB),
StaticConstants.ConstructorNameBase.BuildMethodMemberName()
),
BuildMethodCallDependencyTestData(
typeof(ClassWithAsyncLambdaVariants),
nameof(ClassWithAsyncLambdaVariants.MethodWithCapturingAsyncLambda)
.BuildMethodMemberName(),
typeof(ClassWithMethodB),
nameof(ClassWithMethodB.MethodB).BuildMethodMemberName()
),
BuildMethodCallDependencyTestData(
typeof(ClassWithAsyncLambdaVariants),
nameof(ClassWithAsyncLambdaVariants.MethodWithAsyncLocalFunction)
.BuildMethodMemberName(),
typeof(ClassWithMethodB),
StaticConstants.ConstructorNameBase.BuildMethodMemberName()
),
BuildMethodCallDependencyTestData(
typeof(ClassWithAsyncLambdaVariants),
nameof(ClassWithAsyncLambdaVariants.MethodWithAsyncLocalFunction)
.BuildMethodMemberName(),
typeof(ClassWithMethodB),
nameof(ClassWithMethodB.MethodB).BuildMethodMemberName()
),
BuildMethodCallDependencyTestData(
typeof(ClassWithAsyncLambdaVariants),
nameof(ClassWithAsyncLambdaVariants.MethodWithNestedAsyncLambda)
.BuildMethodMemberName(),
typeof(ClassWithMethodB),
StaticConstants.ConstructorNameBase.BuildMethodMemberName()
),
BuildMethodCallDependencyTestData(
typeof(ClassWithAsyncLambdaVariants),
nameof(ClassWithAsyncLambdaVariants.MethodWithNestedAsyncLambda)
.BuildMethodMemberName(),
typeof(ClassWithMethodB),
nameof(ClassWithMethodB.MethodB).BuildMethodMemberName()
),
BuildMethodCallDependencyTestData(
typeof(ClassWithAsyncLambdaVariants),
nameof(ClassWithAsyncLambdaVariants.AsyncMethodWithAsyncLambda)
.BuildMethodMemberName(),
typeof(ClassWithMethodB),
StaticConstants.ConstructorNameBase.BuildMethodMemberName()
),
BuildMethodCallDependencyTestData(
typeof(ClassWithAsyncLambdaVariants),
nameof(ClassWithAsyncLambdaVariants.AsyncMethodWithAsyncLambda)
.BuildMethodMemberName(),
typeof(ClassWithMethodB),
nameof(ClassWithMethodB.MethodB).BuildMethodMemberName()
),
BuildMethodCallDependencyTestData(
typeof(ClassWithAsyncLambdaVariants),
nameof(ClassWithAsyncLambdaVariants.GenericMethodWithAsyncLambda)
.BuildMethodMemberName(),
typeof(ClassWithMethodB),
StaticConstants.ConstructorNameBase.BuildMethodMemberName()
),
BuildMethodCallDependencyTestData(
typeof(ClassWithAsyncLambdaVariants),
nameof(ClassWithAsyncLambdaVariants.GenericMethodWithAsyncLambda)
.BuildMethodMemberName(),
typeof(ClassWithMethodB),
nameof(ClassWithMethodB.MethodB).BuildMethodMemberName()
),
};

public IEnumerator<object[]> GetEnumerator()
{
return _methodCallDependencyData.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}

public class MethodSignatureDependencyTestData : IEnumerable<object[]>
{
private readonly List<object[]> _methodSignatureDependencyData = new List<object[]>
Expand Down
Loading