-
-
Notifications
You must be signed in to change notification settings - Fork 61
/
Copy pathModuleWeaver.cs
120 lines (98 loc) · 3.31 KB
/
ModuleWeaver.cs
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
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Rocks;
using Mono.Cecil.Cil;
using Fody;
#region ModuleWeaver
public class ModuleWeaver :
BaseModuleWeaver
{
#region Execute
public override void Execute()
{
var ns = GetNamespace();
var type = new TypeDefinition(ns, "Hello", TypeAttributes.Public, TypeSystem.ObjectReference);
AddConstructor(type);
AddHelloWorld(type);
ModuleDefinition.Types.Add(type);
WriteInfo("Added type 'Hello' with method 'World'.");
}
#endregion
#region GetAssembliesForScanning
public override IEnumerable<string> GetAssembliesForScanning()
{
yield return "netstandard";
yield return "mscorlib";
}
#endregion
string GetNamespace()
{
var namespaceFromConfig = GetNamespaceFromConfig();
var namespaceFromAttribute = GetNamespaceFromAttribute();
if (namespaceFromConfig != null && namespaceFromAttribute != null)
{
throw new WeavingException("Configuring namespace from both Config and Attribute is not supported.");
}
if (namespaceFromAttribute != null)
{
return namespaceFromAttribute;
}
return namespaceFromConfig;
}
string GetNamespaceFromConfig()
{
var attribute = Config?.Attribute("Namespace");
if (attribute == null)
{
return null;
}
var value = attribute.Value;
ValidateNamespace(value);
return value;
}
string GetNamespaceFromAttribute()
{
var attributes = ModuleDefinition.Assembly.CustomAttributes;
var namespaceAttribute = attributes
.SingleOrDefault(x => x.AttributeType.FullName == "NamespaceAttribute");
if (namespaceAttribute == null)
{
return null;
}
attributes.Remove(namespaceAttribute);
var value = (string)namespaceAttribute.ConstructorArguments.First().Value;
ValidateNamespace(value);
return value;
}
static void ValidateNamespace(string value)
{
if (value is null || string.IsNullOrWhiteSpace(value))
{
throw new WeavingException("Invalid namespace");
}
}
void AddConstructor(TypeDefinition newType)
{
var attributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName;
var method = new MethodDefinition(".ctor", attributes, TypeSystem.VoidReference);
var objectConstructor = ModuleDefinition.ImportReference(TypeSystem.ObjectDefinition.GetConstructors().First());
var processor = method.Body.GetILProcessor();
processor.Emit(OpCodes.Ldarg_0);
processor.Emit(OpCodes.Call, objectConstructor);
processor.Emit(OpCodes.Ret);
newType.Methods.Add(method);
}
void AddHelloWorld(TypeDefinition newType)
{
var method = new MethodDefinition("World", MethodAttributes.Public, TypeSystem.StringReference);
var processor = method.Body.GetILProcessor();
processor.Emit(OpCodes.Ldstr, "Hello World");
processor.Emit(OpCodes.Ret);
newType.Methods.Add(method);
}
#region ShouldCleanReference
public override bool ShouldCleanReference => true;
#endregion
}
#endregion