#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

468 lines
16 KiB

// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Mono.Cecil;
using AssemblyName = System.Reflection.AssemblyName;
namespace ICSharpCode.SharpDevelop.Dom
{
public static class CecilReader
{
public static ReflectionProjectContent LoadAssembly(string fileName, ProjectContentRegistry registry)
{
if (fileName == null)
throw new ArgumentNullException("fileName");
if (registry == null)
throw new ArgumentNullException("registry");
LoggingService.Info("Cecil: Load from " + fileName);
AssemblyDefinition asm = AssemblyFactory.GetAssembly(fileName);
List<DomAssemblyName> referencedAssemblies = new List<DomAssemblyName>();
foreach (ModuleDefinition module in asm.Modules) {
foreach (AssemblyNameReference anr in module.AssemblyReferences) {
referencedAssemblies.Add(new DomAssemblyName(anr.FullName));
}
}
return new CecilProjectContent(asm.Name.FullName, fileName, referencedAssemblies.ToArray(), asm, registry);
}
static void AddAttributes(IProjectContent pc, IList<IAttribute> list, CustomAttributeCollection attributes)
{
foreach (CustomAttribute att in attributes) {
DefaultAttribute a = new DefaultAttribute(CreateType(pc, null, att.Constructor.DeclaringType));
foreach (object o in att.ConstructorParameters) {
a.PositionalArguments.Add(o);
}
foreach (DictionaryEntry entry in att.Properties) {
a.NamedArguments.Add(entry.Key.ToString(), entry.Value);
}
list.Add(a);
}
}
static void AddConstraintsFromType(ITypeParameter tp, GenericParameter g)
{
foreach (TypeReference constraint in g.Constraints) {
if (tp.Method != null) {
tp.Constraints.Add(CreateType(tp.Class.ProjectContent, tp.Method, constraint));
} else {
tp.Constraints.Add(CreateType(tp.Class.ProjectContent, tp.Class, constraint));
}
}
}
/// <summary>
/// Create a SharpDevelop return type from a Cecil type reference.
/// </summary>
internal static IReturnType CreateType(IProjectContent pc, IDecoration member, TypeReference type)
{
while (type is ModType) {
type = (type as ModType).ElementType;
}
if (type == null) {
LoggingService.Warn("CecilReader: Null type for: " + member);
return VoidReturnType.Instance;
}
if (type is ReferenceType) {
// TODO: Use ByRefRefReturnType
return CreateType(pc, member, (type as ReferenceType).ElementType);
} else if (type is ArrayType) {
return new ArrayReturnType(pc, CreateType(pc, member, (type as ArrayType).ElementType), (type as ArrayType).Rank);
} else if (type is GenericInstanceType) {
GenericInstanceType gType = (GenericInstanceType)type;
IReturnType[] para = new IReturnType[gType.GenericArguments.Count];
for (int i = 0; i < para.Length; ++i) {
para[i] = CreateType(pc, member, gType.GenericArguments[i]);
}
return new ConstructedReturnType(CreateType(pc, member, gType.ElementType), para);
} else if (type is GenericParameter) {
GenericParameter typeGP = type as GenericParameter;
if (typeGP.Owner is MethodDefinition) {
IMethod method = member as IMethod;
if (method != null) {
if (typeGP.Position < method.TypeParameters.Count) {
return new GenericReturnType(method.TypeParameters[typeGP.Position]);
}
}
return new GenericReturnType(new DefaultTypeParameter(method, typeGP.Name, typeGP.Position));
} else {
IClass c = (member is IClass) ? (IClass)member : (member is IMember) ? ((IMember)member).DeclaringType : null;
if (c != null && typeGP.Position < c.TypeParameters.Count) {
if (c.TypeParameters[typeGP.Position].Name == type.Name) {
return new GenericReturnType(c.TypeParameters[typeGP.Position]);
}
}
return new GenericReturnType(new DefaultTypeParameter(c, typeGP.Name, typeGP.Position));
}
} else {
string name = type.FullName;
if (name == null)
throw new ApplicationException("type.FullName returned null. Type: " + type.ToString());
if (name.IndexOf('/') > 0) {
name = name.Replace('/', '.');
}
int typeParameterCount = 0;
if (name.Length > 2 && name[name.Length - 2] == '`') {
typeParameterCount = name[name.Length - 1] - '0';
name = name.Substring(0, name.Length - 2);
}
IClass c = pc.GetClass(name, typeParameterCount);
if (c != null) {
return c.DefaultReturnType;
} else {
// example where name is not found: pointers like System.Char*
// or when the class is in a assembly that is not referenced
return new GetClassReturnType(pc, name, typeParameterCount);
}
}
}
private sealed class CecilProjectContent : ReflectionProjectContent
{
public CecilProjectContent(string fullName, string fileName, DomAssemblyName[] referencedAssemblies,
AssemblyDefinition assembly, ProjectContentRegistry registry)
: base(fullName, fileName, referencedAssemblies, registry)
{
AddAttributes(this, this.AssemblyCompilationUnit.Attributes, assembly.CustomAttributes);
foreach (ModuleDefinition module in assembly.Modules) {
AddTypes(module.Types);
}
InitializeSpecialClasses();
}
void AddTypes(TypeDefinitionCollection types)
{
foreach (TypeDefinition td in types) {
if ((td.Attributes & TypeAttributes.Public) == TypeAttributes.Public) {
if ((td.Attributes & TypeAttributes.NestedAssembly) == TypeAttributes.NestedAssembly
|| (td.Attributes & TypeAttributes.NestedPrivate) == TypeAttributes.NestedPrivate
|| (td.Attributes & TypeAttributes.NestedFamANDAssem) == TypeAttributes.NestedFamANDAssem)
{
continue;
}
string name = td.FullName;
if (name.Length == 0 || name[0] == '<')
continue;
if (name.Length > 2 && name[name.Length - 2] == '`')
name = name.Substring(0, name.Length - 2);
AddClassToNamespaceListInternal(new CecilClass(this.AssemblyCompilationUnit, null, td, name));
}
}
}
}
private sealed class CecilClass : DefaultClass
{
public static bool IsDelegate(TypeDefinition type)
{
if (type.BaseType == null)
return false;
else
return type.BaseType.FullName == "System.Delegate"
|| type.BaseType.FullName == "System.MulticastDelegate";
}
public CecilClass(ICompilationUnit compilationUnit, IClass declaringType,
TypeDefinition td, string fullName)
: base(compilationUnit, declaringType)
{
this.FullyQualifiedName = fullName;
this.UseInheritanceCache = true;
AddAttributes(compilationUnit.ProjectContent, this.Attributes, td.CustomAttributes);
// set classtype
if (td.IsInterface) {
this.ClassType = ClassType.Interface;
} else if (td.IsEnum) {
this.ClassType = ClassType.Enum;
} else if (td.IsValueType) {
this.ClassType = ClassType.Struct;
} else if (IsDelegate(td)) {
this.ClassType = ClassType.Delegate;
} else {
this.ClassType = ClassType.Class;
}
if (td.GenericParameters.Count > 0) {
foreach (GenericParameter g in td.GenericParameters) {
this.TypeParameters.Add(new DefaultTypeParameter(this, g.Name, g.Position));
}
int i = 0;
foreach (GenericParameter g in td.GenericParameters) {
AddConstraintsFromType(this.TypeParameters[i++], g);
}
}
ModifierEnum modifiers = ModifierEnum.None;
if (td.IsSealed) {
modifiers |= ModifierEnum.Sealed;
}
if (td.IsAbstract) {
modifiers |= ModifierEnum.Abstract;
}
if ((td.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic) {
modifiers |= ModifierEnum.Public;
} else if ((td.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily) {
modifiers |= ModifierEnum.Protected;
} else if ((td.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
modifiers |= ModifierEnum.Protected;
} else {
modifiers |= ModifierEnum.Public;
}
this.Modifiers = modifiers;
// set base classes
if (td.BaseType != null) {
BaseTypes.Add(CreateType(this.ProjectContent, this, td.BaseType));
}
foreach (TypeReference iface in td.Interfaces) {
BaseTypes.Add(CreateType(this.ProjectContent, this, iface));
}
ReflectionLayer.ReflectionClass.ApplySpecialsFromAttributes(this);
InitMembers(td);
}
void InitMembers(TypeDefinition type)
{
string defaultMemberName = null;
foreach (CustomAttribute att in type.CustomAttributes) {
if (att.Constructor.DeclaringType.FullName == "System.Reflection.DefaultMemberAttribute"
&& att.ConstructorParameters.Count == 1)
{
defaultMemberName = att.ConstructorParameters[0] as string;
}
}
foreach (TypeDefinition nestedType in type.NestedTypes) {
TypeAttributes visibility = nestedType.Attributes & TypeAttributes.VisibilityMask;
if (visibility == TypeAttributes.NestedPublic || visibility == TypeAttributes.NestedFamily
|| visibility == TypeAttributes.NestedFamORAssem)
{
string name = nestedType.Name;
int pos = name.LastIndexOf('/');
if (pos > 0)
name = name.Substring(pos + 1);
if (name.Length == 0 || name[0] == '<')
continue;
if (name.Length > 2 && name[name.Length - 2] == '`')
name = name.Substring(0, name.Length - 2);
name = this.FullyQualifiedName + "." + name;
InnerClasses.Add(new CecilClass(this.CompilationUnit, this, nestedType, name));
}
}
foreach (FieldDefinition field in type.Fields) {
if (IsVisible(field.Attributes) && !field.IsSpecialName) {
DefaultField f = new DefaultField(this, field.Name);
f.Modifiers = TranslateModifiers(field);
f.ReturnType = CreateType(this.ProjectContent, this, field.FieldType);
AddAttributes(CompilationUnit.ProjectContent, f.Attributes, field.CustomAttributes);
Fields.Add(f);
}
}
foreach (PropertyDefinition property in type.Properties) {
if ((property.GetMethod != null && IsVisible(property.GetMethod.Attributes))
|| (property.SetMethod != null && IsVisible(property.SetMethod.Attributes)))
{
DefaultProperty p = new DefaultProperty(this, property.Name);
if (this.ClassType == ClassType.Interface) {
p.Modifiers = ModifierEnum.Public | ModifierEnum.Abstract;
} else {
p.Modifiers = TranslateModifiers(property);
}
p.ReturnType = CreateType(this.ProjectContent, this, property.PropertyType);
p.CanGet = property.GetMethod != null;
p.CanSet = property.SetMethod != null;
if (p.Name == defaultMemberName) {
p.IsIndexer = true;
}
AddParameters(p, property.Parameters);
AddAttributes(CompilationUnit.ProjectContent, p.Attributes, property.CustomAttributes);
Properties.Add(p);
}
}
foreach (EventDefinition eventDef in type.Events) {
if (eventDef.AddMethod != null && IsVisible(eventDef.AddMethod.Attributes)) {
DefaultEvent e = new DefaultEvent(this, eventDef.Name);
if (this.ClassType == ClassType.Interface) {
e.Modifiers = ModifierEnum.Public | ModifierEnum.Abstract;
} else {
e.Modifiers = TranslateModifiers(eventDef);
}
e.ReturnType = CreateType(this.ProjectContent, this, eventDef.EventType);
AddAttributes(CompilationUnit.ProjectContent, e.Attributes, eventDef.CustomAttributes);
Events.Add(e);
}
}
foreach (MethodDefinition method in type.Constructors) {
AddMethod(method);
}
foreach (MethodDefinition method in type.Methods) {
if (!method.IsSpecialName) {
AddMethod(method);
}
}
}
void AddMethod(MethodDefinition method)
{
if (IsVisible(method.Attributes)) {
DefaultMethod m = new DefaultMethod(this, method.IsConstructor ? "#ctor" : method.Name);
if (method.GenericParameters.Count > 0) {
foreach (GenericParameter g in method.GenericParameters) {
m.TypeParameters.Add(new DefaultTypeParameter(m, g.Name, g.Position));
}
int i = 0;
foreach (GenericParameter g in method.GenericParameters) {
AddConstraintsFromType(m.TypeParameters[i++], g);
}
}
m.ReturnType = CreateType(this.ProjectContent, m, method.ReturnType.ReturnType);
AddAttributes(CompilationUnit.ProjectContent, m.Attributes, method.CustomAttributes);
if (this.ClassType == ClassType.Interface) {
m.Modifiers = ModifierEnum.Public | ModifierEnum.Abstract;
} else {
m.Modifiers = TranslateModifiers(method);
}
AddParameters(m, method.Parameters);
AddExplicitInterfaceImplementations(method.Overrides, m);
ReflectionLayer.ReflectionMethod.ApplySpecialsFromAttributes(m);
Methods.Add(m);
}
}
void AddExplicitInterfaceImplementations(OverrideCollection overrides, IMember targetMember)
{
foreach (MethodReference overrideRef in overrides) {
if (overrideRef.Name == targetMember.Name && targetMember.IsPublic) {
continue; // is like implicit interface implementation / normal override
}
targetMember.InterfaceImplementations.Add(new ExplicitInterfaceImplementation(
CreateType(this.ProjectContent, targetMember, overrideRef.DeclaringType),
overrideRef.Name
));
}
}
void AddParameters(IMethodOrProperty target, ParameterDefinitionCollection plist)
{
foreach (ParameterDefinition par in plist) {
IReturnType pReturnType = CreateType(this.ProjectContent, target, par.ParameterType);
DefaultParameter p = new DefaultParameter(par.Name, pReturnType, DomRegion.Empty);
if (par.ParameterType is ReferenceType) {
if ((par.Attributes & ParameterAttributes.Out) == ParameterAttributes.Out) {
p.Modifiers = ParameterModifiers.Out;
} else {
p.Modifiers = ParameterModifiers.Ref;
}
} else {
p.Modifiers = ParameterModifiers.In;
}
if ((par.Attributes & ParameterAttributes.Optional) == ParameterAttributes.Optional) {
p.Modifiers |= ParameterModifiers.Optional;
}
if (p.ReturnType.IsArrayReturnType) {
foreach (CustomAttribute att in par.CustomAttributes) {
if (att.Constructor.DeclaringType.FullName == typeof(ParamArrayAttribute).FullName) {
p.Modifiers |= ParameterModifiers.Params;
}
}
}
target.Parameters.Add(p);
}
}
static bool IsVisible(MethodAttributes att)
{
return ((att & MethodAttributes.Public) == MethodAttributes.Public)
|| ((att & MethodAttributes.Family) == MethodAttributes.Family)
|| ((att & MethodAttributes.FamORAssem) == MethodAttributes.FamORAssem);
}
static bool IsVisible(FieldAttributes att)
{
return ((att & FieldAttributes.Public) == FieldAttributes.Public)
|| ((att & FieldAttributes.Family) == FieldAttributes.Family)
|| ((att & FieldAttributes.FamORAssem) == FieldAttributes.FamORAssem);
}
static ModifierEnum TranslateModifiers(MethodDefinition method)
{
ModifierEnum m = ModifierEnum.None;
if (method.IsStatic)
m |= ModifierEnum.Static;
if (method.IsAbstract) {
m |= ModifierEnum.Abstract;
} else if (method.Overrides.Count > 0) {
if (method.IsFinal) {
m |= ModifierEnum.Sealed;
} else {
m |= ModifierEnum.Override;
}
} else if (method.IsVirtual) {
m |= ModifierEnum.Virtual;
}
if ((method.Attributes & MethodAttributes.Public) == MethodAttributes.Public)
m |= ModifierEnum.Public;
else
m |= ModifierEnum.Protected;
return m;
}
static ModifierEnum TranslateModifiers(PropertyDefinition property)
{
return TranslateModifiers(property.GetMethod ?? property.SetMethod);
}
static ModifierEnum TranslateModifiers(EventDefinition @event)
{
return TranslateModifiers(@event.AddMethod);
}
static ModifierEnum TranslateModifiers(FieldDefinition field)
{
ModifierEnum m = ModifierEnum.None;
if (field.IsStatic)
m |= ModifierEnum.Static;
if (field.IsLiteral)
m |= ModifierEnum.Const;
else if (field.IsInitOnly)
m |= ModifierEnum.Readonly;
if ((field.Attributes & FieldAttributes.Public) == FieldAttributes.Public)
m |= ModifierEnum.Public;
else
m |= ModifierEnum.Protected;
return m;
}
}
}
}