Skip to content

Commit 0605ee9

Browse files
committed
[feat] New assembly resolving pipeline + some nuget resolving heuristics
1 parent f6dda79 commit 0605ee9

12 files changed

+423
-79
lines changed

VSharp.API/VSharp.cs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ private static Statistics StartExploration(List<MethodBase> methods, string resu
9292

9393
void HandleInternalFail(MethodBase method, Exception exception)
9494
{
95-
Console.WriteLine($"EXCEPTION | {method.DeclaringType}.{method.Name} | {exception.GetType().Name} {exception.Message}");
95+
Logger.printLogString(Logger.Error, $"Internal exception | {method.DeclaringType}.{method.Name} | {exception.GetType().Name} {exception.Message}");
9696
}
9797

9898
foreach (var method in methods)
@@ -172,18 +172,52 @@ public static Statistics Cover(Type type, int timeout = -1, string outputDirecto
172172
public static Statistics Cover(Assembly assembly, int timeout = -1, string outputDirectory = "")
173173
{
174174
AssemblyManager.Load(assembly);
175-
List<MethodBase> methods;
176175
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public |
177176
BindingFlags.DeclaredOnly;
178-
methods = new List<MethodBase>();
179177

180-
foreach (var t in assembly.GetTypes())
178+
var methods = new List<MethodBase>();
179+
var types = new List<Type>();
180+
181+
try
182+
{
183+
types.AddRange(assembly.GetTypes());
184+
}
185+
catch (ReflectionTypeLoadException e)
186+
{
187+
foreach (var loaderException in e.LoaderExceptions)
188+
{
189+
Logger.printLogString(Logger.Error, $"Cannot load type: {loaderException?.Message}");
190+
}
191+
192+
foreach (var type in e.Types)
193+
{
194+
if (type is not null)
195+
{
196+
types.Add(type);
197+
}
198+
}
199+
}
200+
201+
foreach (var t in types)
181202
{
182-
if (t.IsPublic)
203+
if (t.IsPublic || t.IsNestedPublic)
183204
{
184205
foreach (var m in t.GetMethods(bindingFlags))
185206
{
186-
if (m.GetMethodBody() != null)
207+
global::System.Reflection.MethodBody methodBody = null;
208+
var hasByRefLikes = true;
209+
210+
try
211+
{
212+
methodBody = m.GetMethodBody();
213+
hasByRefLikes = Reflection.hasByRefLikes(m);
214+
}
215+
catch (Exception e)
216+
{
217+
Logger.printLogString(Logger.Error, $"Cannot get method info: {e.Message}");
218+
}
219+
220+
if (methodBody is not null && !hasByRefLikes)
187221
methods.Add(m);
188222
}
189223
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using System;
2+
using System.IO;
3+
using System.Linq;
4+
using System.Reflection;
5+
6+
namespace VSharp.CSharpUtils.AssemblyResolving
7+
{
8+
public static class AssemblyResolverUtils
9+
{
10+
public static string FindAssemblyWithName(DirectoryInfo directory, AssemblyName targetName)
11+
{
12+
bool IsTargetAssembly(FileInfo assemblyFile)
13+
{
14+
try
15+
{
16+
var foundName = AssemblyName.GetAssemblyName(assemblyFile.FullName);
17+
return foundName.Name == targetName.Name &&
18+
foundName.Version == targetName.Version &&
19+
foundName.ContentType == targetName.ContentType;
20+
}
21+
catch (Exception)
22+
{
23+
return false;
24+
}
25+
}
26+
27+
var found = directory.EnumerateFiles("*.dll").FirstOrDefault(IsTargetAssembly);
28+
29+
if (found is not null)
30+
{
31+
return found.FullName;
32+
}
33+
34+
foreach (var subDir in directory.EnumerateDirectories())
35+
{
36+
var foundInSubDir = FindAssemblyWithName(subDir, targetName);
37+
if (foundInSubDir is not null)
38+
{
39+
return foundInSubDir;
40+
}
41+
}
42+
43+
return null;
44+
}
45+
46+
public static string GetBaseNuGetDirectory()
47+
{
48+
var baseDirectory = Environment.GetEnvironmentVariable("NUGET_PACKAGES");
49+
50+
if (!string.IsNullOrEmpty(baseDirectory))
51+
{
52+
return baseDirectory;
53+
}
54+
55+
if (OperatingSystem.IsWindows())
56+
{
57+
baseDirectory = Environment.GetEnvironmentVariable("USERPROFILE");
58+
}
59+
else
60+
{
61+
baseDirectory = Environment.GetEnvironmentVariable("HOME");
62+
}
63+
64+
if (string.IsNullOrEmpty(baseDirectory))
65+
{
66+
return null;
67+
}
68+
69+
return Path.Combine(baseDirectory, ".nuget", "packages");
70+
}
71+
}
72+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System.Collections.Generic;
2+
using System.Reflection;
3+
4+
namespace VSharp.CSharpUtils.AssemblyResolving
5+
{
6+
public class CompositeAssemblyResolver : IAssemblyResolver
7+
{
8+
private readonly List<IAssemblyResolver> _resolvers = new();
9+
10+
public CompositeAssemblyResolver(params IAssemblyResolver[] resolvers)
11+
{
12+
_resolvers.AddRange(resolvers);
13+
}
14+
15+
public string Resolve(AssemblyName assemblyName)
16+
{
17+
foreach (var resolver in _resolvers)
18+
{
19+
var resolved = resolver.Resolve(assemblyName);
20+
if (resolved is not null)
21+
{
22+
return resolved;
23+
}
24+
}
25+
26+
return null;
27+
}
28+
}
29+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.IO;
2+
using System.Reflection;
3+
4+
namespace VSharp.CSharpUtils.AssemblyResolving
5+
{
6+
public class CurrentDirectoryAssemblyResolver : IAssemblyResolver
7+
{
8+
private readonly string _directoryPath;
9+
10+
public CurrentDirectoryAssemblyResolver(string directoryPath)
11+
{
12+
_directoryPath = directoryPath;
13+
}
14+
15+
public string Resolve(AssemblyName assemblyName)
16+
{
17+
var dllPath = Path.Combine(_directoryPath, $"{assemblyName.Name}.dll");
18+
19+
if (File.Exists(dllPath))
20+
{
21+
return dllPath;
22+
}
23+
24+
return null;
25+
}
26+
}
27+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.Reflection;
2+
3+
namespace VSharp.CSharpUtils.AssemblyResolving
4+
{
5+
public interface IAssemblyResolver
6+
{
7+
string Resolve(AssemblyName assemblyName);
8+
}
9+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
using Microsoft.Extensions.DependencyModel;
6+
using Microsoft.Extensions.DependencyModel.Resolution;
7+
8+
namespace VSharp.CSharpUtils.AssemblyResolving
9+
{
10+
public class MicrosoftDependencyModelAssemblyResolver : IAssemblyResolver
11+
{
12+
private readonly List<ICompilationAssemblyResolver> _resolvers = new();
13+
private readonly DependencyContext _context;
14+
15+
public MicrosoftDependencyModelAssemblyResolver(DependencyContext context, params ICompilationAssemblyResolver[] resolvers)
16+
{
17+
_resolvers.AddRange(resolvers);
18+
_context = context;
19+
}
20+
21+
public string Resolve(AssemblyName assemblyName)
22+
{
23+
if (_context is null)
24+
{
25+
return null;
26+
}
27+
28+
var compilationLibrary = _context.CompileLibraries.FirstOrDefault(l =>
29+
l.Name.Equals(assemblyName.Name, StringComparison.OrdinalIgnoreCase));
30+
31+
if (compilationLibrary is null)
32+
{
33+
var runtimeLibrary = _context.RuntimeLibraries.FirstOrDefault(l =>
34+
l.Name.Equals(assemblyName.Name, StringComparison.OrdinalIgnoreCase));
35+
36+
if (runtimeLibrary is not null)
37+
{
38+
compilationLibrary = new CompilationLibrary(
39+
runtimeLibrary.Type,
40+
runtimeLibrary.Name,
41+
runtimeLibrary.Version,
42+
runtimeLibrary.Hash,
43+
runtimeLibrary.RuntimeAssemblyGroups.SelectMany(g => g.AssetPaths),
44+
runtimeLibrary.Dependencies,
45+
runtimeLibrary.Serviceable
46+
);
47+
}
48+
}
49+
50+
if (compilationLibrary is null)
51+
{
52+
return null;
53+
}
54+
55+
var assemblies = new List<string>();
56+
57+
foreach (ICompilationAssemblyResolver resolver in _resolvers)
58+
{
59+
try
60+
{
61+
if (resolver.TryResolveAssemblyPaths(compilationLibrary, assemblies))
62+
{
63+
return assemblies[0];
64+
}
65+
}
66+
catch { }
67+
}
68+
69+
return null;
70+
}
71+
}
72+
}

0 commit comments

Comments
 (0)