-
Notifications
You must be signed in to change notification settings - Fork 153
Expand file tree
/
Copy pathAddInternalsVisibleToForAllUserAssembliesPostProcess.cs
More file actions
144 lines (120 loc) · 5 KB
/
AddInternalsVisibleToForAllUserAssembliesPostProcess.cs
File metadata and controls
144 lines (120 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Mono.Cecil;
using UnityEditor;
using UnityEngine;
namespace FastScriptReload.Editor.AssemblyPostProcess
{
[InitializeOnLoad]
public static class AddInternalsVisibleToForAllUserAssembliesPostProcess
{
public static readonly DirectoryInfo AdjustedAssemblyRoot;
static AddInternalsVisibleToForAllUserAssembliesPostProcess()
{
AdjustedAssemblyRoot = new DirectoryInfo(Path.Combine(Application.dataPath, "..", "Temp", "Fast Script Reload", "AdjustedDlls"));
}
public static string CreateAssemblyWithInternalsContentsVisibleTo(Assembly changedAssembly, string visibleToAssemblyName)
{
if (!AdjustedAssemblyRoot.Exists)
AdjustedAssemblyRoot.Create();
var assemblyResolver = new UnityMonoEditorAssemblyResolver(changedAssembly.Location);
using (var assembly = AssemblyDefinition.ReadAssembly(changedAssembly.Location, new ReaderParameters { ReadWrite = false, AssemblyResolver = assemblyResolver }))
{
var mainModule = assembly.MainModule;
var attributeCtor = mainModule.ImportReference(
typeof(System.Runtime.CompilerServices.InternalsVisibleToAttribute).GetConstructor(new[] { typeof(string) })
);
var attribute = new CustomAttribute(attributeCtor);
attribute.ConstructorArguments.Add(
new CustomAttributeArgument(mainModule.TypeSystem.String, visibleToAssemblyName)
);
assembly.CustomAttributes.Add(attribute);
var newAssemblyPath = new FileInfo(Path.Combine(AdjustedAssemblyRoot.FullName, assembly.Name.Name) + ".dll").FullName;
assembly.Write(newAssemblyPath);
return newAssemblyPath;
}
}
}
class UnityMonoEditorAssemblyResolver : IAssemblyResolver
{
static readonly HashSet<string> s_unityEditorSearchDirs;
static UnityMonoEditorAssemblyResolver()
{
// s_unityEditorSearchDirs will be populated on each domain reload
s_unityEditorSearchDirs = new();
foreach (var loadedAssembly in AppDomain.CurrentDomain.GetAssemblies())
{
if (loadedAssembly.IsDynamic) continue;
if (!File.Exists(loadedAssembly.Location)) continue;
var assemblyDir = Path.GetDirectoryName(loadedAssembly.Location);
s_unityEditorSearchDirs.Add(assemblyDir);
}
}
private Dictionary<string, AssemblyDefinition> cache;
private string majorSearchDir;
public UnityMonoEditorAssemblyResolver(string targetAssemblyPath)
{
cache = new();
majorSearchDir = Path.GetDirectoryName(targetAssemblyPath);
}
private AssemblyDefinition GetAssembly(string file, ReaderParameters parameters)
{
parameters.AssemblyResolver ??= this;
return ModuleDefinition.ReadModule(file, parameters).Assembly;
}
private bool TryResolveAssemblyInDirectory(string directory, ReaderParameters parameters, AssemblyNameReference name, out AssemblyDefinition assembly)
{
const string AssemblyExtension = ".dll";
var filepath = Path.Combine(directory, name.Name + AssemblyExtension);
assembly = null;
if (File.Exists(filepath))
{
try
{
assembly = GetAssembly(filepath, parameters);
return true;
}
catch { }
}
return false;
}
private AssemblyDefinition ResolveInternalCacheLess(AssemblyNameReference name, ReaderParameters parameters)
{
if (TryResolveAssemblyInDirectory(majorSearchDir, parameters, name, out var assembly))
{
return assembly;
}
foreach (var dir in s_unityEditorSearchDirs)
{
if (TryResolveAssemblyInDirectory(dir, parameters, name, out assembly))
{
return assembly;
}
}
throw new AssemblyResolutionException(name);
}
public AssemblyDefinition Resolve(AssemblyNameReference name)
{
return Resolve(name, new ReaderParameters());
}
public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
if (!cache.TryGetValue(name.FullName, out var value))
{
cache[name.FullName] = value = ResolveInternalCacheLess(name, parameters);
}
return value;
}
public void Dispose()
{
foreach (var (path, assembly) in cache)
{
assembly.Dispose();
}
cache.Clear();
}
}
}