From 3779381796e327191b5702d8afc44cd1ca286153 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 21 May 2011 21:57:53 +0200 Subject: [PATCH] Add support for type forwarding declarations ([TypeForwardedToAttribute]). Closes #190. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 68 ++++++++++++++++++- .../Ast/AstMethodBodyBuilder.cs | 31 +-------- .../Disassembler/ReflectionDisassembler.cs | 15 ++++ 3 files changed, 81 insertions(+), 33 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 7a489d07e..397b82030 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -128,6 +128,7 @@ namespace ICSharpCode.Decompiler.Ast ConvertCustomAttributes(astCompileUnit, assemblyDefinition, "assembly"); ConvertSecurityAttributes(astCompileUnit, assemblyDefinition, "assembly"); ConvertCustomAttributes(astCompileUnit, assemblyDefinition.MainModule, "module"); + AddTypeForwarderAttributes(astCompileUnit, assemblyDefinition.MainModule, "assembly"); if (!onlyAssemblyLevel) { foreach (TypeDefinition typeDef in assemblyDefinition.MainModule.Types) { @@ -142,6 +143,30 @@ namespace ICSharpCode.Decompiler.Ast } } + void AddTypeForwarderAttributes(CompilationUnit astCompileUnit, ModuleDefinition module, string target) + { + if (!module.HasExportedTypes) + return; + foreach (ExportedType type in module.ExportedTypes) { + if (type.IsForwarder) { + var forwardedType = CreateTypeOfExpression(new TypeReference(type.Namespace, type.Name, module, type.Scope)); + astCompileUnit.AddChild( + new AttributeSection { + AttributeTarget = target, + Attributes = { + new NRefactory.CSharp.Attribute { + Type = new SimpleType("TypeForwardedTo") + .WithAnnotation(new TypeReference( + "System.Runtime.CompilerServices", "TypeForwardedToAttribute", + module, module.TypeSystem.Corlib)), + Arguments = { forwardedType } + } + } + }, AttributedNode.AttributeRole); + } + } + } + NamespaceDeclaration GetCodeNamespace(string name) { if (string.IsNullOrEmpty(name)) { @@ -306,6 +331,45 @@ namespace ICSharpCode.Decompiler.Ast return name; } + #region Create TypeOf Expression + /// + /// Creates a typeof-expression for the specified type. + /// + public static TypeOfExpression CreateTypeOfExpression(TypeReference type) + { + return new TypeOfExpression(AddEmptyTypeArgumentsForUnboundGenerics(ConvertType(type))); + } + + static AstType AddEmptyTypeArgumentsForUnboundGenerics(AstType type) + { + TypeReference typeRef = type.Annotation(); + if (typeRef == null) + return type; + TypeDefinition typeDef = typeRef.Resolve(); // need to resolve to figure out the number of type parameters + if (typeDef == null || !typeDef.HasGenericParameters) + return type; + SimpleType sType = type as SimpleType; + MemberType mType = type as MemberType; + if (sType != null) { + while (typeDef.GenericParameters.Count > sType.TypeArguments.Count) { + sType.TypeArguments.Add(new SimpleType("")); + } + } + + if (mType != null) { + AddEmptyTypeArgumentsForUnboundGenerics(mType.Target); + + int outerTypeParamCount = typeDef.DeclaringType == null ? 0 : typeDef.DeclaringType.GenericParameters.Count; + + while (typeDef.GenericParameters.Count - outerTypeParamCount > mType.TypeArguments.Count) { + mType.TypeArguments.Add(new SimpleType("")); + } + } + + return type; + } + #endregion + #region Convert Type Reference /// /// Converts a type reference. @@ -1378,9 +1442,7 @@ namespace ICSharpCode.Decompiler.Ast if (type != null && type.IsEnum) { return MakePrimitive(Convert.ToInt64(argument.Value), type); } else if (argument.Value is TypeReference) { - return new TypeOfExpression() { - Type = ConvertType((TypeReference)argument.Value), - }; + return CreateTypeOfExpression((TypeReference)argument.Value); } else { return new PrimitiveExpression(argument.Value); } diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index c8666b73a..b82101562 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -601,7 +601,7 @@ namespace ICSharpCode.Decompiler.Ast case ILCode.Ldstr: return new Ast.PrimitiveExpression(operand); case ILCode.Ldtoken: if (operand is Cecil.TypeReference) { - return new Ast.TypeOfExpression { Type = AddEmptyTypeArgumentsForUnboundGenerics(operandAsTypeRef) }.Member("TypeHandle"); + return AstBuilder.CreateTypeOfExpression((TypeReference)operand).Member("TypeHandle"); } else { return InlineAssembly(byteCode, args); } @@ -749,35 +749,6 @@ namespace ICSharpCode.Decompiler.Ast } } - AstType AddEmptyTypeArgumentsForUnboundGenerics(AstType type) - { - TypeReference typeRef = type.Annotation(); - if (typeRef == null) - return type; - TypeDefinition typeDef = typeRef.Resolve(); // need to resolve to figure out the number of type parameters - if (typeDef == null || !typeDef.HasGenericParameters) - return type; - SimpleType sType = type as SimpleType; - MemberType mType = type as MemberType; - if (sType != null) { - while (typeDef.GenericParameters.Count > sType.TypeArguments.Count) { - sType.TypeArguments.Add(new SimpleType("")); - } - } - - if (mType != null) { - AddEmptyTypeArgumentsForUnboundGenerics(mType.Target); - - int outerTypeParamCount = typeDef.DeclaringType == null ? 0 : typeDef.DeclaringType.GenericParameters.Count; - - while (typeDef.GenericParameters.Count - outerTypeParamCount > mType.TypeArguments.Count) { - mType.TypeArguments.Add(new SimpleType("")); - } - } - - return type; - } - static readonly AstNode objectInitializerPattern = new AssignmentExpression( new MemberReferenceExpression { Target = new InitializedObjectExpression() diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index be00da59a..f4f8dac8a 100644 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -1096,6 +1096,21 @@ namespace ICSharpCode.Decompiler.Disassembler public void WriteModuleHeader(ModuleDefinition module) { + if (module.HasExportedTypes) { + foreach (ExportedType exportedType in module.ExportedTypes) { + output.Write(".class extern "); + if (exportedType.IsForwarder) + output.Write("forwarder "); + output.Write(exportedType.DeclaringType != null ? exportedType.Name : exportedType.FullName); + OpenBlock(false); + if (exportedType.DeclaringType != null) + output.WriteLine(".class extern {0}", DisassemblerHelpers.Escape(exportedType.DeclaringType.FullName)); + else + output.WriteLine(".assembly extern {0}", DisassemblerHelpers.Escape(exportedType.Scope.Name)); + CloseBlock(); + } + } + output.WriteLine(".module {0}", module.Name); output.WriteLine("// MVID: {0}", module.Mvid.ToString("B").ToUpperInvariant()); // TODO: imagebase, file alignment, stackreserve, subsystem