4
// Lluis Sanchez Gual <lluis@novell.com>
6
// Copyright (c) 2007 Novell, Inc (http://www.novell.com)
8
// Permission is hereby granted, free of charge, to any person obtaining a copy
9
// of this software and associated documentation files (the "Software"), to deal
10
// in the Software without restriction, including without limitation the rights
11
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
// copies of the Software, and to permit persons to whom the Software is
13
// furnished to do so, subject to the following conditions:
15
// The above copyright notice and this permission notice shall be included in
16
// all copies or substantial portions of the Software.
18
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
using System.Collections;
30
using System.Reflection;
32
using Mono.Addins.Database;
34
using CustomAttribute = Mono.Cecil.CustomAttribute;
35
using MA = Mono.Addins.Database;
36
using System.Collections.Generic;
38
namespace Mono.Addins.CecilReflector
40
public class Reflector: IAssemblyReflector
42
IAssemblyLocator locator;
43
Hashtable cachedAssemblies = new Hashtable ();
45
public void Initialize (IAssemblyLocator locator)
47
this.locator = locator;
50
public object[] GetCustomAttributes (object obj, Type type, bool inherit)
52
Mono.Cecil.ICustomAttributeProvider aprov = obj as Mono.Cecil.ICustomAttributeProvider;
54
return new object [0];
56
ArrayList atts = new ArrayList ();
57
foreach (CustomAttribute att in aprov.CustomAttributes) {
58
object catt = ConvertAttribute (att, type);
62
if (inherit && (obj is TypeDefinition)) {
63
TypeDefinition td = (TypeDefinition) obj;
64
if (td.BaseType != null && td.BaseType.FullName != "System.Object") {
65
TypeDefinition bt = FindTypeDefinition (td.Module.Assembly, td.BaseType);
67
atts.AddRange (GetCustomAttributes (bt, type, true));
70
return atts.ToArray ();
73
object ConvertAttribute (CustomAttribute att, Type expectedType)
75
Type attype = typeof(IAssemblyReflector).Assembly.GetType (att.Constructor.DeclaringType.FullName);
77
if (attype == null || !expectedType.IsAssignableFrom (attype))
82
if (att.ConstructorArguments.Count > 0) {
83
object[] cargs = new object [att.ConstructorArguments.Count];
84
ArrayList typeParameters = null;
86
// Constructor parameters of type System.Type can't be set because types from the assembly
87
// can't be loaded. The parameter value will be set later using a type name property.
88
for (int n=0; n<cargs.Length; n++) {
89
cargs [n] = att.ConstructorArguments [n].Value;
90
string atype = att.Constructor.Parameters[n].ParameterType.FullName;
91
if (atype == "System.Type") {
92
if (typeParameters == null)
93
typeParameters = new ArrayList ();
94
cargs [n] = typeof(object);
95
typeParameters.Add (n);
98
ob = Activator.CreateInstance (attype, cargs);
100
// If there are arguments of type System.Type, set them using the property
101
if (typeParameters != null) {
102
Type[] ptypes = new Type [cargs.Length];
103
for (int n=0; n<cargs.Length; n++) {
104
ptypes [n] = cargs [n].GetType ();
106
ConstructorInfo ci = attype.GetConstructor (ptypes);
107
ParameterInfo[] ciParams = ci.GetParameters ();
109
for (int n=0; n<typeParameters.Count; n++) {
110
int ip = (int) typeParameters [n];
111
string propName = ciParams[ip].Name;
112
propName = char.ToUpper (propName [0]) + propName.Substring (1) + "Name";
113
PropertyInfo pi = attype.GetProperty (propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
116
throw new InvalidOperationException ("Property '" + propName + "' not found in type '" + attype + "'.");
118
pi.SetValue (ob, ((TypeReference) att.ConstructorArguments [ip].Value).FullName, null);
122
ob = Activator.CreateInstance (attype);
125
foreach (Mono.Cecil.CustomAttributeNamedArgument namedArgument in att.Properties) {
126
string pname = namedArgument.Name;
127
PropertyInfo prop = attype.GetProperty (pname);
129
if (prop.PropertyType == typeof(System.Type)) {
130
// We can't load the type. We have to use the typeName property instead.
132
prop = attype.GetProperty (pname, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
135
throw new InvalidOperationException ("Property '" + pname + "' not found in type '" + attype + "'.");
137
prop.SetValue (ob, ((TypeReference) namedArgument.Argument.Value).FullName, null);
139
prop.SetValue (ob, namedArgument.Argument.Value, null);
145
public List<MA.CustomAttribute> GetRawCustomAttributes (object obj, Type type, bool inherit)
147
List<MA.CustomAttribute> atts = new List<MA.CustomAttribute> ();
148
Mono.Cecil.ICustomAttributeProvider aprov = obj as Mono.Cecil.ICustomAttributeProvider;
152
foreach (CustomAttribute att in aprov.CustomAttributes) {
153
MA.CustomAttribute catt = ConvertToRawAttribute (att, type.FullName);
157
if (inherit && (obj is TypeDefinition)) {
158
TypeDefinition td = (TypeDefinition) obj;
159
if (td.BaseType != null && td.BaseType.FullName != "System.Object") {
160
TypeDefinition bt = FindTypeDefinition (td.Module.Assembly, td.BaseType);
162
atts.AddRange (GetRawCustomAttributes (bt, type, true));
168
MA.CustomAttribute ConvertToRawAttribute (CustomAttribute att, string expectedType)
170
TypeDefinition attType = FindTypeDefinition (att.Constructor.DeclaringType.Module.Assembly, att.Constructor.DeclaringType);
172
if (attType == null || !TypeIsAssignableFrom (expectedType, attType))
175
MA.CustomAttribute mat = new MA.CustomAttribute ();
176
mat.TypeName = att.Constructor.DeclaringType.FullName;
178
if (att.ConstructorArguments.Count > 0) {
179
var arguments = att.ConstructorArguments;
181
MethodReference constructor = FindConstructor (att);
182
if (constructor == null)
183
throw new InvalidOperationException ("Custom attribute constructor not found");
185
for (int n=0; n<arguments.Count; n++) {
186
ParameterDefinition par = constructor.Parameters[n];
187
object val = arguments [n].Value;
189
string name = par.Name;
190
NodeAttributeAttribute bat = (NodeAttributeAttribute) GetCustomAttribute (par, typeof(NodeAttributeAttribute), false);
193
mat.Add (name, Convert.ToString (val, System.Globalization.CultureInfo.InvariantCulture));
198
foreach (Mono.Cecil.CustomAttributeNamedArgument namedArgument in att.Properties) {
199
string pname = namedArgument.Name;
200
object val = namedArgument.Argument.Value;
204
foreach (TypeDefinition td in GetInheritanceChain (attType)) {
205
PropertyDefinition prop = GetMember (td.Properties, pname);
209
NodeAttributeAttribute bat = (NodeAttributeAttribute) GetCustomAttribute (prop, typeof(NodeAttributeAttribute), false);
211
string name = string.IsNullOrEmpty (bat.Name) ? prop.Name : bat.Name;
212
mat.Add (name, Convert.ToString (val, System.Globalization.CultureInfo.InvariantCulture));
217
foreach (Mono.Cecil.CustomAttributeNamedArgument namedArgument in att.Fields) {
218
string pname = namedArgument.Name;
219
object val = namedArgument.Argument.Value;
223
foreach (TypeDefinition td in GetInheritanceChain (attType)) {
224
FieldDefinition field = GetMember (td.Fields, pname);
226
NodeAttributeAttribute bat = (NodeAttributeAttribute) GetCustomAttribute (field, typeof(NodeAttributeAttribute), false);
228
string name = string.IsNullOrEmpty (bat.Name) ? field.Name : bat.Name;
229
mat.Add (name, Convert.ToString (val, System.Globalization.CultureInfo.InvariantCulture));
238
static TMember GetMember<TMember> (ICollection<TMember> members, string name) where TMember : class, IMemberDefinition
240
foreach (var member in members)
241
if (member.Name == name)
247
IEnumerable<TypeDefinition> GetInheritanceChain (TypeDefinition td)
250
while (td != null && td.BaseType != null && td.BaseType.FullName != "System.Object") {
251
td = FindTypeDefinition (td.Module.Assembly, td.BaseType);
257
MethodReference FindConstructor (CustomAttribute att)
259
// The constructor provided by CustomAttribute.Constructor is lacking some information, such as the parameter
260
// name and custom attributes. Since we need the full info, we have to look it up in the declaring type.
262
TypeDefinition atd = FindTypeDefinition (att.Constructor.DeclaringType.Module.Assembly, att.Constructor.DeclaringType);
263
foreach (MethodReference met in atd.Methods) {
264
if (met.Name != ".ctor")
267
if (met.Parameters.Count == att.Constructor.Parameters.Count) {
268
for (int n = met.Parameters.Count - 1; n >= 0; n--) {
269
if (met.Parameters[n].ParameterType.FullName != att.Constructor.Parameters[n].ParameterType.FullName)
279
public object LoadAssembly (string file)
281
return LoadAssembly (file, false);
284
public AssemblyDefinition LoadAssembly (string file, bool cache)
286
AssemblyDefinition adef = (AssemblyDefinition) cachedAssemblies [file];
289
adef = AssemblyDefinition.ReadAssembly (file);
290
if (adef != null && cache)
291
cachedAssemblies [file] = adef;
295
public string[] GetResourceNames (object asm)
297
AssemblyDefinition adef = (AssemblyDefinition) asm;
298
List<string> names = new List<string> (adef.MainModule.Resources.Count);
299
foreach (Resource res in adef.MainModule.Resources) {
300
if (res is EmbeddedResource)
301
names.Add (res.Name);
303
return names.ToArray ();
306
public System.IO.Stream GetResourceStream (object asm, string resourceName)
308
AssemblyDefinition adef = (AssemblyDefinition) asm;
309
foreach (Resource res in adef.MainModule.Resources) {
310
EmbeddedResource r = res as EmbeddedResource;
311
if (r != null && r.Name == resourceName)
312
return r.GetResourceStream ();
314
throw new InvalidOperationException ("Resource not found: " + resourceName);
317
public object LoadAssemblyFromReference (object asmReference)
319
AssemblyNameReference aref = (AssemblyNameReference) asmReference;
320
string loc = locator.GetAssemblyLocation (aref.FullName);
322
return LoadAssembly (loc);
327
public System.Collections.IEnumerable GetAssemblyTypes (object asm)
329
return ((AssemblyDefinition)asm).MainModule.Types;
332
public System.Collections.IEnumerable GetAssemblyReferences (object asm)
334
return ((AssemblyDefinition)asm).MainModule.AssemblyReferences;
337
public object GetType (object asm, string typeName)
339
if (typeName.IndexOf ('`') != -1) {
340
foreach (TypeDefinition td in ((AssemblyDefinition)asm).MainModule.Types) {
341
if (td.FullName == typeName) {
346
TypeDefinition t = ((AssemblyDefinition)asm).MainModule.GetType (typeName);
354
public object GetCustomAttribute (object obj, Type type, bool inherit)
356
foreach (object att in GetCustomAttributes (obj, type, inherit))
357
if (type.IsInstanceOfType (att))
362
public string GetTypeName (object type)
364
return ((TypeDefinition)type).Name;
367
public string GetTypeFullName (object type)
369
return ((TypeDefinition)type).FullName;
372
public string GetTypeAssemblyQualifiedName (object type)
374
AssemblyDefinition asm = GetAssemblyDefinition ((TypeDefinition)type);
375
return ((TypeDefinition)type).FullName + ", " + asm.Name.FullName;
378
AssemblyDefinition GetAssemblyDefinition (TypeDefinition t)
380
return t.Module.Assembly;
383
public System.Collections.IEnumerable GetBaseTypeFullNameList (object type)
385
TypeDefinition t = (TypeDefinition) type;
386
AssemblyDefinition asm = GetAssemblyDefinition (t);
388
ArrayList list = new ArrayList ();
389
Hashtable visited = new Hashtable ();
390
GetBaseTypeFullNameList (visited, list, asm, t);
391
list.Remove (t.FullName);
395
void GetBaseTypeFullNameList (Hashtable visited, ArrayList list, AssemblyDefinition asm, TypeReference tr)
397
if (tr.FullName == "System.Object" || visited.Contains (tr.FullName))
400
visited [tr.FullName] = tr;
401
list.Add (tr.FullName);
403
TypeDefinition type = FindTypeDefinition (asm, tr);
407
asm = GetAssemblyDefinition (type);
409
if (type.BaseType != null)
410
GetBaseTypeFullNameList (visited, list, asm, type.BaseType);
412
foreach (TypeReference interf in type.Interfaces)
413
GetBaseTypeFullNameList (visited, list, asm, interf);
416
TypeDefinition FindTypeDefinition (AssemblyDefinition referencer, TypeReference rt)
418
if (rt is TypeDefinition)
419
return (TypeDefinition) rt;
421
string name = rt.FullName;
422
TypeDefinition td = GetType (referencer, name) as TypeDefinition;
425
int i = name.IndexOf ('<');
427
name = name.Substring (0, i);
428
td = GetType (referencer, name) as TypeDefinition;
433
foreach (AssemblyNameReference aref in referencer.MainModule.AssemblyReferences) {
434
string loc = locator.GetAssemblyLocation (aref.FullName);
437
AssemblyDefinition asm = LoadAssembly (loc, true);
438
td = GetType (asm, name) as TypeDefinition;
445
public bool TypeIsAssignableFrom (object baseType, object type)
447
string baseName = ((TypeDefinition)baseType).FullName;
448
foreach (string bt in GetBaseTypeFullNameList (type))
454
public bool TypeIsAssignableFrom (string baseTypeName, object type)
456
foreach (string bt in GetBaseTypeFullNameList (type))
457
if (bt == baseTypeName)
462
public IEnumerable GetFields (object type)
464
return ((TypeDefinition)type).Fields;
467
public string GetFieldName (object field)
469
return ((FieldDefinition)field).Name;
472
public string GetFieldTypeFullName (object field)
474
return ((FieldDefinition)field).FieldType.FullName;