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
39 changes: 28 additions & 11 deletions ArchUnitNET/Loader/DotNetCoreAssemblyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,42 @@ public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters p
throw new ArgumentNullException(nameof(name));
}

if (
_libraries.TryGetValue(name.FullName, out var assemblyDefinition)
|| string.IsNullOrEmpty(AssemblyPath)
)
if (_libraries.TryGetValue(name.FullName, out var assemblyDefinition))
{
return assemblyDefinition;
}

var file = Directory
.EnumerateFiles(AssemblyPath, $"{name.Name}.dll", SearchOption.AllDirectories)
.FirstOrDefault();
if (!string.IsNullOrEmpty(AssemblyPath))
{
var file = Directory
.EnumerateFiles(AssemblyPath, $"{name.Name}.dll", SearchOption.AllDirectories)
.FirstOrDefault();

if (file != null)
{
assemblyDefinition = AssemblyDefinition.ReadAssembly(file, parameters);
_libraries.Add(name.FullName, assemblyDefinition);
return assemblyDefinition;
}
}

if (file == null)
// Fall back to DefaultAssemblyResolver for framework assemblies not found in
// AssemblyPath. Pass the original parameters so the loaded assembly keeps using
// this resolver (which returns null for unresolvable references) instead of the
// DefaultAssemblyResolver (which throws).
try
{
assemblyDefinition = _defaultAssemblyResolver.Resolve(name, parameters);
}
catch (AssemblyResolutionException)
{
return null;
}

assemblyDefinition = AssemblyDefinition.ReadAssembly(file, parameters);
_libraries.Add(name.FullName, assemblyDefinition);
if (assemblyDefinition != null)
{
_libraries.Add(name.FullName, assemblyDefinition);
}

return assemblyDefinition;
}
Expand Down Expand Up @@ -84,7 +101,7 @@ [NotNull] AssemblyDefinition moduleAssembly

public void AddLib(AssemblyNameReference name)
{
var assembly = Resolve(name) ?? _defaultAssemblyResolver.Resolve(name);
var assembly = Resolve(name);
AddLib(name, assembly ?? throw new AssemblyResolutionException(name));
}

Expand Down
2 changes: 1 addition & 1 deletion ArchUnitNET/Loader/InstructionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ [NotNull] this Instruction methodCallInstruction
&& methodCallAssignment.Operand is FieldReference fieldReference
)
{
return fieldReference.Resolve();
return fieldReference.TryResolve();
}

return null;
Expand Down
5 changes: 3 additions & 2 deletions ArchUnitNET/Loader/MonoCecilMemberExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,9 @@ internal static bool IsCompilerGenerated(this MemberReference memberReference)
{
return true;
}
var declaringType =
memberReference.Resolve()?.DeclaringType ?? memberReference.DeclaringType;

var resolvedType = memberReference.TryResolve();
var declaringType = resolvedType?.DeclaringType ?? memberReference.DeclaringType;
return declaringType != null && declaringType.Name.HasCompilerGeneratedName();
}

Expand Down
67 changes: 67 additions & 0 deletions ArchUnitNET/Loader/MonoCecilResolveExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using JetBrains.Annotations;
using Mono.Cecil;

namespace ArchUnitNET.Loader
{
/// <summary>
/// Resolve extensions that return <c>null</c> instead of throwing
/// <see cref="AssemblyResolutionException" /> when an assembly cannot be located.
/// </summary>
internal static class MonoCecilResolveExtensions
{
[CanBeNull]
public static TypeDefinition TryResolve([CanBeNull] this TypeReference typeReference)
{
if (typeReference == null)
{
return null;
}

try
{
return typeReference.Resolve();
}
catch (AssemblyResolutionException)
{
return null;
}
}

[CanBeNull]
public static FieldDefinition TryResolve([CanBeNull] this FieldReference fieldReference)
{
if (fieldReference == null)
{
return null;
}

try
{
return fieldReference.Resolve();
}
catch (AssemblyResolutionException)
{
return null;
}
}

[CanBeNull]
public static IMemberDefinition TryResolve([CanBeNull] this MemberReference memberReference)
{
if (memberReference == null)
{
return null;
}

try
{
return memberReference.Resolve();
}
catch (AssemblyResolutionException)
{
return null;
}
}
}
}
9 changes: 7 additions & 2 deletions ArchUnitNET/Loader/MonoCecilTypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,13 @@ internal static bool IsAttribute([CanBeNull] this TypeDefinition typeDefinition)
{
if (typeDefinition?.BaseType != null)
{
return typeDefinition.BaseType.FullName == "System.Attribute"
|| IsAttribute(typeDefinition.BaseType.Resolve());
if (typeDefinition.BaseType.FullName == "System.Attribute")
{
return true;
}

var resolvedBaseType = typeDefinition.BaseType.TryResolve();
return resolvedBaseType != null && IsAttribute(resolvedBaseType);
}

return false;
Expand Down
15 changes: 5 additions & 10 deletions ArchUnitNET/Loader/TypeProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -797,15 +797,10 @@ var calledMethodReference in calledMethodReferences.Except(visitedMethodReferenc

if (calledMethodReference.IsCompilerGenerated())
{
MethodDefinition calledMethodDefinition;
try
{
calledMethodDefinition = calledMethodReference.Resolve();
}
catch (AssemblyResolutionException)
{
calledMethodDefinition = null;
}
// Here an AssemblyResolutionException would only occur if the method is from a referenced assembly that is not available.
// However, since we are only resolving compiler-generated methods here, we can safely assume that the method is from an
// available assembly and don't need to handle the exception.
var calledMethodDefinition = calledMethodReference.Resolve();

if (calledMethodDefinition?.Body == null)
{
Expand Down Expand Up @@ -1071,7 +1066,7 @@ private static IEnumerable<TypeReference> GetInterfacesImplementedByClass(
TypeDefinition typeDefinition
)
{
var baseType = typeDefinition.BaseType?.Resolve();
var baseType = typeDefinition.BaseType.TryResolve();
var baseInterfaces =
baseType != null
? GetInterfacesImplementedByClass(baseType)
Expand Down
2 changes: 1 addition & 1 deletion ArchUnitNETTests/Loader/ArchLoaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ public void UnavailableTypeTest()
System.IO.SearchOption.AllDirectories
)
.Build();
Assert.Equal(3, architecture.Types.Count());
Assert.Equal(4, architecture.Types.Count());
var loggerType = architecture.ReferencedTypes.WhereFullNameIs("Serilog.ILogger");
Assert.NotNull(loggerType);
Assert.True(loggerType is UnavailableType);
Expand Down
Loading
Loading