1
+ using System ;
2
+ using System . Linq ;
3
+ using System . Text . RegularExpressions ;
4
+ using Mono . Cecil ;
5
+ using Mono . Cecil . Rocks ;
6
+
7
+ namespace ModTekSimpleInjector ;
8
+
9
+ internal class SimpleInjection
10
+ {
11
+ private readonly TypeDefinition _typeDefinition ;
12
+ private readonly ModuleDefinition _moduleDefinition ;
13
+ private readonly CustomAttribute _customAttribute ;
14
+
15
+ public SimpleInjection (
16
+ string sourceFile ,
17
+ IAssemblyResolver resolver ,
18
+ Addition addition
19
+ ) {
20
+ Console . WriteLine ( $ "Processing { addition } ") ;
21
+ var assemblyName = new AssemblyNameReference ( addition . InAssembly , null ) ;
22
+
23
+ var assemblyDefinition = resolver . Resolve ( assemblyName )
24
+ ?? throw new ArgumentException ( $ "Unable to resolve assembly { addition . InAssembly } ") ;
25
+ _typeDefinition = assemblyDefinition . MainModule . GetType ( addition . ToType )
26
+ ?? throw new ArgumentException ( $ "Unable to resolve type { addition . ToType } in assembly { addition . InAssembly } ") ;
27
+ _moduleDefinition = assemblyDefinition . MainModule ;
28
+
29
+ _customAttribute = CreateCustomAttribute ( _moduleDefinition , "ModTekSimpleInjector" , "InjectedAttribute" , [
30
+ new ParameterInfo < string > ( "source" , sourceFile ) ,
31
+ new ParameterInfo < string > ( "comment" , addition . Comment )
32
+ ] ) ;
33
+ }
34
+
35
+ internal void InjectField ( AddField fieldAddition )
36
+ {
37
+ var fieldType = ResolveType ( fieldAddition . OfType ) ;
38
+ var fieldTypeReference = _moduleDefinition . ImportReference ( fieldType ) ;
39
+ var fieldDefinition = new FieldDefinition ( fieldAddition . Name , fieldAddition . Attributes , fieldTypeReference ) ;
40
+ fieldDefinition . CustomAttributes . Add ( _customAttribute ) ;
41
+ _typeDefinition . Fields . Add ( fieldDefinition ) ;
42
+ }
43
+
44
+ internal void InjectEnumConstant ( AddEnumConstant enumConstant )
45
+ {
46
+ const FieldAttributes EnumFieldAttributes =
47
+ FieldAttributes . Static
48
+ | FieldAttributes . Literal
49
+ | FieldAttributes . Public
50
+ | FieldAttributes . HasDefault ;
51
+ var fieldDefinition = new FieldDefinition ( enumConstant . Name , EnumFieldAttributes , _typeDefinition )
52
+ {
53
+ Constant = enumConstant . Value
54
+ } ;
55
+ fieldDefinition . CustomAttributes . Add ( _customAttribute ) ;
56
+ _typeDefinition . Fields . Add ( fieldDefinition ) ;
57
+ }
58
+
59
+ private static CustomAttribute CreateCustomAttribute (
60
+ ModuleDefinition moduleDefinition ,
61
+ string @namespace ,
62
+ string name ,
63
+ IParameterInfo [ ] parameters
64
+ ) {
65
+ var attributeTypeDefinition = moduleDefinition . GetType ( @namespace , name ) ;
66
+ if ( attributeTypeDefinition == null )
67
+ {
68
+ var baseType = moduleDefinition . ImportReference ( typeof ( Attribute ) ) ;
69
+ attributeTypeDefinition = new TypeDefinition (
70
+ @namespace ,
71
+ name ,
72
+ TypeAttributes . NotPublic | TypeAttributes . Sealed ,
73
+ baseType
74
+ ) ;
75
+ const MethodAttributes CtorAttributes =
76
+ MethodAttributes . Public
77
+ | MethodAttributes . HideBySig
78
+ | MethodAttributes . SpecialName
79
+ | MethodAttributes . RTSpecialName ;
80
+ var methodDefinition = new MethodDefinition ( ".ctor" , CtorAttributes , moduleDefinition . TypeSystem . Void ) ;
81
+ // if not wanting CustomAttributeNamedArgument, one can use:
82
+ // foreach (var parameter in parameters)
83
+ // {
84
+ // var parameterDefinition = new ParameterDefinition(
85
+ // parameter.name,
86
+ // ParameterAttributes.None,
87
+ // moduleDefinition.ImportReference(parameter.type)
88
+ // );
89
+ // methodDefinition.Parameters.Add(parameterDefinition);
90
+ // }
91
+ attributeTypeDefinition . Methods . Add ( methodDefinition ) ;
92
+ moduleDefinition . Types . Add ( attributeTypeDefinition ) ;
93
+ }
94
+ var attributeConstructor = attributeTypeDefinition . GetConstructors ( ) . First ( ) ;
95
+ var attribute = new CustomAttribute ( attributeConstructor ) ;
96
+ foreach ( var parameter in parameters )
97
+ {
98
+ if ( parameter . Value is null )
99
+ {
100
+ continue ;
101
+ }
102
+ var attributeArgument = new CustomAttributeArgument (
103
+ moduleDefinition . ImportReference ( parameter . Type ) ,
104
+ parameter . Value
105
+ ) ;
106
+ var attributeNamedArgument = new CustomAttributeNamedArgument ( parameter . Name , attributeArgument ) ;
107
+ attribute . Fields . Add ( attributeNamedArgument ) ;
108
+ }
109
+ return attribute ;
110
+ }
111
+ private record ParameterInfo < T > ( string Name , T value ) : IParameterInfo
112
+ {
113
+ public Type Type => typeof ( T ) ;
114
+ public object Value => value ;
115
+ }
116
+ private interface IParameterInfo
117
+ {
118
+ string Name { get ; }
119
+ object Value { get ; }
120
+ Type Type { get ; }
121
+ }
122
+
123
+ private static Type ResolveType ( string typeName )
124
+ {
125
+ var isArray = typeName . EndsWith ( "[]" ) ;
126
+ if ( isArray )
127
+ {
128
+ typeName = typeName [ ..^ 2 ] ;
129
+ }
130
+
131
+ var genericArgumentsRegex = new Regex ( "^(.+?)<(.+)>$" ) ;
132
+ var genericArgumentsMatch = genericArgumentsRegex . Match ( typeName ) ;
133
+ Type [ ] genericArgumentsTypes ;
134
+ if ( genericArgumentsMatch . Success )
135
+ {
136
+ var genericArgumentsString = genericArgumentsMatch . Groups [ 2 ] . Value ;
137
+ var genericArgumentsStrings = genericArgumentsString . Split ( ',' ) ;
138
+ typeName = genericArgumentsMatch . Groups [ 1 ] . Value ;
139
+ typeName += "`" + genericArgumentsStrings . Length ;
140
+ genericArgumentsTypes = new Type [ genericArgumentsStrings . Length ] ;
141
+ for ( var i = 0 ; i < genericArgumentsTypes . Length ; i ++ )
142
+ {
143
+ genericArgumentsTypes [ i ] = ResolveType ( genericArgumentsStrings [ i ] ) ;
144
+ }
145
+ }
146
+ else
147
+ {
148
+ genericArgumentsTypes = null ;
149
+ }
150
+
151
+ // TODO fix msbuild and unity mono supporting different classes in mscorlib!
152
+ // we only support mscorlib classes for now
153
+ var fieldType = typeof ( int ) . Assembly . GetType ( typeName ) ;
154
+
155
+ if ( genericArgumentsTypes != null )
156
+ {
157
+ fieldType = fieldType . MakeGenericType ( genericArgumentsTypes ) ;
158
+ }
159
+ if ( isArray )
160
+ {
161
+ fieldType = fieldType . MakeArrayType ( ) ;
162
+ }
163
+ return fieldType ;
164
+ }
165
+ }
0 commit comments