diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 6edcaa2e2..fda33199b 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -771,5 +771,206 @@ namespace ICSharpCode.Decompiler.CSharp } return eventDecl; } + + #region Convert Type Reference + /// + /// Converts a type reference. + /// + /// The Cecil type reference that should be converted into + /// a type system type reference. + /// Attributes associated with the Cecil type reference. + /// This is used to support the 'dynamic' type. + public static AstType ConvertType(TypeReference type, ICustomAttributeProvider typeAttributes = null, ConvertTypeOptions options = ConvertTypeOptions.None) + { + int typeIndex = 0; + return ConvertType(type, typeAttributes, ref typeIndex, options); + } + + static AstType ConvertType(TypeReference type, ICustomAttributeProvider typeAttributes, ref int typeIndex, ConvertTypeOptions options) + { + while (type is OptionalModifierType || type is RequiredModifierType) { + type = ((TypeSpecification)type).ElementType; + } + if (type == null) { + return AstType.Null; + } + + if (type is Mono.Cecil.ByReferenceType) { + typeIndex++; + // by reference type cannot be represented in C#; so we'll represent it as a pointer instead + return ConvertType((type as Mono.Cecil.ByReferenceType).ElementType, typeAttributes, ref typeIndex, options) + .MakePointerType(); + } else if (type is Mono.Cecil.PointerType) { + typeIndex++; + return ConvertType((type as Mono.Cecil.PointerType).ElementType, typeAttributes, ref typeIndex, options) + .MakePointerType(); + } else if (type is Mono.Cecil.ArrayType) { + typeIndex++; + return ConvertType((type as Mono.Cecil.ArrayType).ElementType, typeAttributes, ref typeIndex, options) + .MakeArrayType((type as Mono.Cecil.ArrayType).Rank); + } else if (type is GenericInstanceType) { + GenericInstanceType gType = (GenericInstanceType)type; + if (gType.ElementType.Namespace == "System" && gType.ElementType.Name == "Nullable`1" && gType.GenericArguments.Count == 1) { + typeIndex++; + return new ComposedType { + BaseType = ConvertType(gType.GenericArguments[0], typeAttributes, ref typeIndex, options), + HasNullableSpecifier = true + }; + } + AstType baseType = ConvertType(gType.ElementType, typeAttributes, ref typeIndex, options & ~ConvertTypeOptions.IncludeTypeParameterDefinitions); + List typeArguments = new List(); + foreach (var typeArgument in gType.GenericArguments) { + typeIndex++; + typeArguments.Add(ConvertType(typeArgument, typeAttributes, ref typeIndex, options)); + } + ApplyTypeArgumentsTo(baseType, typeArguments); + return baseType; + } else if (type is GenericParameter) { + return new SimpleType(type.Name); + } else if (type.IsNested) { + AstType typeRef = ConvertType(type.DeclaringType, typeAttributes, ref typeIndex, options & ~ConvertTypeOptions.IncludeTypeParameterDefinitions); + string namepart = ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name); + MemberType memberType = new MemberType { Target = typeRef, MemberName = namepart }; + memberType.AddAnnotation(type); + if ((options & ConvertTypeOptions.IncludeTypeParameterDefinitions) == ConvertTypeOptions.IncludeTypeParameterDefinitions) { + AddTypeParameterDefininitionsTo(type, memberType); + } + return memberType; + } else { + string ns = type.Namespace ?? string.Empty; + string name = type.Name; + if (name == null) + throw new InvalidOperationException("type.Name returned null. Type: " + type.ToString()); + + if (name == "Object" && ns == "System" && HasDynamicAttribute(typeAttributes, typeIndex)) { + return new Syntax.PrimitiveType("dynamic"); + } else { + if (ns == "System") { + if ((options & ConvertTypeOptions.DoNotUsePrimitiveTypeNames) + != ConvertTypeOptions.DoNotUsePrimitiveTypeNames) { + switch (name) { + case "SByte": + return new Syntax.PrimitiveType("sbyte"); + case "Int16": + return new Syntax.PrimitiveType("short"); + case "Int32": + return new Syntax.PrimitiveType("int"); + case "Int64": + return new Syntax.PrimitiveType("long"); + case "Byte": + return new Syntax.PrimitiveType("byte"); + case "UInt16": + return new Syntax.PrimitiveType("ushort"); + case "UInt32": + return new Syntax.PrimitiveType("uint"); + case "UInt64": + return new Syntax.PrimitiveType("ulong"); + case "String": + return new Syntax.PrimitiveType("string"); + case "Single": + return new Syntax.PrimitiveType("float"); + case "Double": + return new Syntax.PrimitiveType("double"); + case "Decimal": + return new Syntax.PrimitiveType("decimal"); + case "Char": + return new Syntax.PrimitiveType("char"); + case "Boolean": + return new Syntax.PrimitiveType("bool"); + case "Void": + return new Syntax.PrimitiveType("void"); + case "Object": + return new Syntax.PrimitiveType("object"); + } + } + } + + name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(name); + + AstType astType; + if ((options & ConvertTypeOptions.IncludeNamespace) == ConvertTypeOptions.IncludeNamespace && ns.Length > 0) { + string[] parts = ns.Split('.'); + AstType nsType = new SimpleType(parts[0]); + for (int i = 1; i < parts.Length; i++) { + nsType = new MemberType { Target = nsType, MemberName = parts[i] }; + } + astType = new MemberType { Target = nsType, MemberName = name }; + } else { + astType = new SimpleType(name); + } + astType.AddAnnotation(type); + + if ((options & ConvertTypeOptions.IncludeTypeParameterDefinitions) == ConvertTypeOptions.IncludeTypeParameterDefinitions) { + AddTypeParameterDefininitionsTo(type, astType); + } + return astType; + } + } + } + + static void AddTypeParameterDefininitionsTo(TypeReference type, AstType astType) + { + if (type.HasGenericParameters) { + List typeArguments = new List(); + foreach (GenericParameter gp in type.GenericParameters) { + typeArguments.Add(new SimpleType(gp.Name)); + } + ApplyTypeArgumentsTo(astType, typeArguments); + } + } + + static void ApplyTypeArgumentsTo(AstType baseType, List typeArguments) + { + SimpleType st = baseType as SimpleType; + if (st != null) { + st.TypeArguments.AddRange(typeArguments); + } + MemberType mt = baseType as MemberType; + if (mt != null) { + TypeReference type = mt.Annotation(); + if (type != null) { + int typeParameterCount; + ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount); + if (typeParameterCount > typeArguments.Count) + typeParameterCount = typeArguments.Count; + mt.TypeArguments.AddRange(typeArguments.GetRange(typeArguments.Count - typeParameterCount, typeParameterCount)); + typeArguments.RemoveRange(typeArguments.Count - typeParameterCount, typeParameterCount); + if (typeArguments.Count > 0) + ApplyTypeArgumentsTo(mt.Target, typeArguments); + } else { + mt.TypeArguments.AddRange(typeArguments); + } + } + } + + const string DynamicAttributeFullName = "System.Runtime.CompilerServices.DynamicAttribute"; + + static bool HasDynamicAttribute(ICustomAttributeProvider attributeProvider, int typeIndex) + { + if (attributeProvider == null || !attributeProvider.HasCustomAttributes) + return false; + foreach (CustomAttribute a in attributeProvider.CustomAttributes) { + if (a.Constructor.DeclaringType.FullName == DynamicAttributeFullName) { + if (a.ConstructorArguments.Count == 1) { + CustomAttributeArgument[] values = a.ConstructorArguments[0].Value as CustomAttributeArgument[]; + if (values != null && typeIndex < values.Length && values[typeIndex].Value is bool) + return (bool)values[typeIndex].Value; + } + return true; + } + } + return false; + } + #endregion + + } + + [Flags] + public enum ConvertTypeOptions + { + None = 0, + IncludeNamespace = 1, + IncludeTypeParameterDefinitions = 2, + DoNotUsePrimitiveTypeNames = 4 } } diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index 56ffeaae5..5a1651323 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -50,7 +50,7 @@ namespace ICSharpCode.ILSpy bool showAllMembers = false; int transformCount = int.MaxValue; - #if DEBUG +#if DEBUG internal static IEnumerable GetDebugLanguages() { var decompiler = new CSharpDecompiler(ModuleDefinition.CreateModule("Dummy", ModuleKind.Dll), new DecompilerSettings()); @@ -70,20 +70,17 @@ namespace ICSharpCode.ILSpy showAllMembers = true }; } - #endif +#endif - public override string Name - { + public override string Name { get { return name; } } - public override string FileExtension - { + public override string FileExtension { get { return ".cs"; } } - public override string ProjectFileExtension - { + public override string ProjectFileExtension { get { return ".csproj"; } } @@ -95,7 +92,7 @@ namespace ICSharpCode.ILSpy decompiler.AstTransforms.RemoveAt(decompiler.AstTransforms.Count - 1); return decompiler; } - + void WriteCode(ITextOutput output, DecompilerSettings settings, SyntaxTree syntaxTree, IDecompilerTypeSystem typeSystem) { syntaxTree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }); @@ -103,7 +100,7 @@ namespace ICSharpCode.ILSpy var formattingPolicy = settings.CSharpFormattingOptions; syntaxTree.AcceptVisitor(new CSharpOutputVisitor(outputFormatter, formattingPolicy)); } - + public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) { AddReferenceWarningMessage(method.Module.Assembly, output); @@ -117,11 +114,11 @@ namespace ICSharpCode.ILSpy WriteCode(output, options.DecompilerSettings, decompiler.Decompile(method), decompiler.TypeSystem); } } - + class SelectCtorTransform : IAstTransform { readonly IMethod ctor; - + public SelectCtorTransform(IMethod ctor) { this.ctor = ctor; @@ -197,7 +194,7 @@ namespace ICSharpCode.ILSpy sealed class SelectFieldTransform : IAstTransform { readonly IField field; - + public SelectFieldTransform(IField field) { this.field = field; @@ -328,7 +325,7 @@ namespace ICSharpCode.ILSpy output.WriteLine("// Runtime: " + runtimeName); } output.WriteLine(); - + // don't automatically load additional assemblies when an assembly node is selected in the tree view using (options.FullDecompilation ? null : LoadedAssembly.DisableAssemblyLoad()) { CSharpDecompiler decompiler = new CSharpDecompiler(assembly.ModuleDefinition, options.DecompilerSettings); @@ -343,25 +340,25 @@ namespace ICSharpCode.ILSpy } } } - + class ILSpyWholeProjectDecompiler : WholeProjectDecompiler { readonly LoadedAssembly assembly; readonly DecompilationOptions options; - + public ILSpyWholeProjectDecompiler(LoadedAssembly assembly, DecompilationOptions options) { this.assembly = assembly; this.options = options; base.Settings = options.DecompilerSettings; } - + protected override IEnumerable> WriteResourceToFile(string fileName, string resourceName, Stream entryStream) { if (fileName.EndsWith(".resource", StringComparison.OrdinalIgnoreCase)) { using (ResourceReader reader = new ResourceReader(entryStream)) - using (FileStream fs = new FileStream(Path.Combine(targetDirectory, fileName), FileMode.Create, FileAccess.Write)) - using (ResXResourceWriter writer = new ResXResourceWriter(fs)) { + using (FileStream fs = new FileStream(Path.Combine(targetDirectory, fileName), FileMode.Create, FileAccess.Write)) + using (ResXResourceWriter writer = new ResXResourceWriter(fs)) { foreach (DictionaryEntry entry in reader) { writer.AddResource((string)entry.Key, entry.Value); } @@ -395,6 +392,7 @@ namespace ICSharpCode.ILSpy Settings = settings }); } + */ public override string TypeToString(TypeReference type, bool includeNamespace, ICustomAttributeProvider typeAttributes = null) { @@ -407,7 +405,7 @@ namespace ICSharpCode.ILSpy string TypeToString(ConvertTypeOptions options, TypeReference type, ICustomAttributeProvider typeAttributes = null) { - AstType astType = AstBuilder.ConvertType(type, typeAttributes, options); + AstType astType = CSharpDecompiler.ConvertType(type, typeAttributes, options); StringWriter w = new StringWriter(); if (type.IsByReference) { @@ -424,9 +422,9 @@ namespace ICSharpCode.ILSpy astType.AcceptVisitor(new CSharpOutputVisitor(w, TypeToStringFormattingOptions)); return w.ToString(); } + static readonly CSharpFormattingOptions TypeToStringFormattingOptions = FormattingOptionsFactory.CreateEmpty(); - */ - + public override string FormatPropertyName(PropertyDefinition property, bool? isIndexer) { if (property == null) @@ -466,15 +464,14 @@ namespace ICSharpCode.ILSpy return (method.IsConstructor) ? method.DeclaringType.Name : method.Name; } - /* public override string FormatTypeName(TypeDefinition type) { if (type == null) throw new ArgumentNullException("type"); - + return TypeToString(ConvertTypeOptions.DoNotUsePrimitiveTypeNames | ConvertTypeOptions.IncludeTypeParameterDefinitions, type); } - */ + public override bool ShowMember(MemberReference member) { return showAllMembers || !CSharpDecompiler.MemberIsHidden(member, new DecompilationOptions().DecompilerSettings);