diff --git a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs index 28e4dad7d..11ac6e648 100644 --- a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs +++ b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs @@ -36,7 +36,6 @@ using ICSharpCode.Decompiler.TypeSystem; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CSharp; -using Mono.Cecil; using NUnit.Framework; namespace ICSharpCode.Decompiler.Tests.Helpers @@ -114,7 +113,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers using (var writer = new StreamWriter(outputFile)) { //module.Name = Path.GetFileNameWithoutExtension(outputFile); var output = new PlainTextOutput(writer); - ReflectionDisassembler rd = new ReflectionDisassembler(output, module.GetMetadataReader(), CancellationToken.None); + ReflectionDisassembler rd = new ReflectionDisassembler(output, CancellationToken.None); rd.DetectControlStructure = false; //rd.WriteAssemblyReferences(module); /*if (module.Assembly != null) diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 731c7c964..ddf597b73 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -178,7 +178,7 @@ namespace ICSharpCode.Decompiler.CSharp } public CSharpDecompiler(string fileName, DecompilerSettings settings) - : this(UniversalAssemblyResolver.LoadMainModule(fileName, settings.ThrowOnAssemblyResolveErrors, settings.LoadInMemory), settings) + //: this(UniversalAssemblyResolver.LoadMainModule(fileName, settings.ThrowOnAssemblyResolveErrors, settings.LoadInMemory), settings) { } @@ -1158,7 +1158,7 @@ namespace ICSharpCode.Decompiler.CSharp /// /// This only works correctly when the nodes in the syntax tree have line/column information. /// - public Dictionary> CreateSequencePoints(SyntaxTree syntaxTree) + public Dictionary> CreateSequencePoints(SyntaxTree syntaxTree) { SequencePointBuilder spb = new SequencePointBuilder(); syntaxTree.AcceptVisitor(spb); diff --git a/ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs b/ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs index 0daf76ab6..05798e909 100644 --- a/ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs @@ -56,7 +56,7 @@ namespace ICSharpCode.Decompiler.CSharp } } - readonly List<(ILFunction, SequencePoint)> sequencePoints = new List<(ILFunction, SequencePoint)>(); + readonly List<(ILFunction, Dom.SequencePoint)> sequencePoints = new List<(ILFunction, Dom.SequencePoint)>(); readonly HashSet mappedInstructions = new HashSet(); // Stack holding information for outer statements. @@ -219,7 +219,7 @@ namespace ICSharpCode.Decompiler.CSharp // use LongSet to deduplicate and merge the intervals var longSet = new LongSet(current.Intervals.Select(i => new LongInterval(i.Start, i.End))); Debug.Assert(!longSet.IsEmpty); - sequencePoints.Add((current.Function, new SequencePoint { + sequencePoints.Add((current.Function, new Dom.SequencePoint { Offset = (int)longSet.Intervals[0].Start, EndOffset = (int)longSet.Intervals[0].End, StartLine = startLocation.Line, @@ -277,18 +277,18 @@ namespace ICSharpCode.Decompiler.CSharp /// /// Called after the visitor is done to return the results. /// - internal Dictionary> GetSequencePoints() + internal Dictionary> GetSequencePoints() { - var dict = new Dictionary>(); + var dict = new Dictionary>(); foreach (var (function, sequencePoint) in this.sequencePoints) { if (!dict.TryGetValue(function, out var list)) { - dict.Add(function, list = new List()); + dict.Add(function, list = new List()); } list.Add(sequencePoint); } foreach (var (function, list) in dict.ToList()) { // For each function, sort sequence points and fix overlaps+gaps - var newList = new List(); + var newList = new List(); int pos = 0; foreach (var sequencePoint in list.OrderBy(sp => sp.Offset).ThenBy(sp => sp.EndOffset)) { if (sequencePoint.Offset < pos) { @@ -305,7 +305,7 @@ namespace ICSharpCode.Decompiler.CSharp } } else if (sequencePoint.Offset > pos) { // insert hidden sequence point in the gap. - var hidden = new SequencePoint(); + var hidden = new Dom.SequencePoint(); hidden.Offset = pos; hidden.EndOffset = sequencePoint.Offset; hidden.SetHidden(); @@ -315,7 +315,7 @@ namespace ICSharpCode.Decompiler.CSharp pos = sequencePoint.EndOffset; } if (pos < function.CecilMethod.Body.CodeSize) { - var hidden = new SequencePoint(); + var hidden = new Dom.SequencePoint(); hidden.Offset = pos; hidden.EndOffset = function.CecilMethod.Body.CodeSize; hidden.SetHidden(); diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs index b612716f1..5bfa3bd9d 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs @@ -25,6 +25,7 @@ using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching; using ICSharpCode.Decompiler.CSharp.TypeSystem; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Semantics; +using Mono.Cecil; namespace ICSharpCode.Decompiler.CSharp.Transforms { diff --git a/ICSharpCode.Decompiler/Disassembler/BlobDecoder.cs b/ICSharpCode.Decompiler/Disassembler/BlobDecoder.cs new file mode 100644 index 000000000..98477da8a --- /dev/null +++ b/ICSharpCode.Decompiler/Disassembler/BlobDecoder.cs @@ -0,0 +1,223 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using ICSharpCode.Decompiler.Semantics; +using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.TypeSystem.Implementation; +using SRM = System.Reflection.Metadata; + +namespace ICSharpCode.Decompiler.Disassembler +{ + sealed class BlobDecoder + { + SRM.BlobReader blob; + static readonly ITypeResolveContext context = new SimpleTypeResolveContext(MinimalCorlib.Instance.CreateCompilation()); + + public BlobDecoder(SRM.BlobReader blob) + { + this.blob = blob; + } + + public int Offset => blob.Offset; + + public ResolveResult ReadFixedArg(IType argType) + { + if (argType.Kind == TypeKind.Array) { + if (((ArrayType)argType).Dimensions != 1) { + // Only single-dimensional arrays are supported + return ErrorResolveResult.UnknownError; + } + IType elementType = ((ArrayType)argType).ElementType; + uint numElem = blob.ReadUInt32(); + if (numElem == 0xffffffff) { + // null reference + return new ConstantResolveResult(argType, null); + } else { + ResolveResult[] elements = new ResolveResult[numElem]; + for (int i = 0; i < elements.Length; i++) { + elements[i] = ReadElem(elementType); + // Stop decoding when encountering an error: + if (elements[i].IsError) + return ErrorResolveResult.UnknownError; + } + IType int32 = context.Compilation.FindType(KnownTypeCode.Int32); + ResolveResult[] sizeArgs = { new ConstantResolveResult(int32, elements.Length) }; + return new ArrayCreateResolveResult(argType, sizeArgs, elements); + } + } else { + return ReadElem(argType); + } + } + + public ResolveResult ReadElem(IType elementType) + { + ITypeDefinition underlyingType; + if (elementType.Kind == TypeKind.Enum) { + underlyingType = elementType.GetDefinition().EnumUnderlyingType.GetDefinition(); + } else { + underlyingType = elementType.GetDefinition(); + } + if (underlyingType == null) + return ErrorResolveResult.UnknownError; + KnownTypeCode typeCode = underlyingType.KnownTypeCode; + if (typeCode == KnownTypeCode.Object) { + // boxed value type + IType boxedTyped = ReadCustomAttributeFieldOrPropType(); + ResolveResult elem = ReadFixedArg(boxedTyped); + if (elem.IsCompileTimeConstant && elem.ConstantValue == null) + return new ConstantResolveResult(elementType, null); + else + return new ConversionResolveResult(elementType, elem, Conversion.BoxingConversion); + } else if (typeCode == KnownTypeCode.Type) { + var type = ReadType(); + if (type != null) { + return new TypeOfResolveResult(underlyingType, type); + } else { + return new ConstantResolveResult(underlyingType, null); + } + } else { + return new ConstantResolveResult(elementType, ReadElemValue(typeCode)); + } + } + + object ReadElemValue(KnownTypeCode typeCode) + { + switch (typeCode) { + case KnownTypeCode.Boolean: + return blob.ReadBoolean(); + case KnownTypeCode.Char: + return blob.ReadChar(); + case KnownTypeCode.SByte: + return blob.ReadSByte(); + case KnownTypeCode.Byte: + return blob.ReadByte(); + case KnownTypeCode.Int16: + return blob.ReadInt16(); + case KnownTypeCode.UInt16: + return blob.ReadUInt16(); + case KnownTypeCode.Int32: + return blob.ReadInt32(); + case KnownTypeCode.UInt32: + return blob.ReadUInt32(); + case KnownTypeCode.Int64: + return blob.ReadInt64(); + case KnownTypeCode.UInt64: + return blob.ReadUInt64(); + case KnownTypeCode.Single: + return blob.ReadSingle(); + case KnownTypeCode.Double: + return blob.ReadDouble(); + case KnownTypeCode.String: + return blob.ReadSerializedString(); + default: + throw new NotSupportedException(); + } + } + + public KeyValuePair ReadNamedArg() + { + SymbolKind memberType; + var b = blob.ReadByte(); + switch (b) { + case 0x53: + memberType = SymbolKind.Field; + break; + case 0x54: + memberType = SymbolKind.Property; + break; + default: + throw new NotSupportedException(string.Format("Custom member type 0x{0:x} is not supported.", b)); + } + IType type = ReadCustomAttributeFieldOrPropType(); + string name = blob.ReadSerializedString(); + ResolveResult val = ReadFixedArg(type); + return new KeyValuePair(name, val); + } + + IType ReadCustomAttributeFieldOrPropType() + { + ICompilation compilation = context.Compilation; + var b = blob.ReadByte(); + switch (b) { + case 0x02: + return compilation.FindType(KnownTypeCode.Boolean); + case 0x03: + return compilation.FindType(KnownTypeCode.Char); + case 0x04: + return compilation.FindType(KnownTypeCode.SByte); + case 0x05: + return compilation.FindType(KnownTypeCode.Byte); + case 0x06: + return compilation.FindType(KnownTypeCode.Int16); + case 0x07: + return compilation.FindType(KnownTypeCode.UInt16); + case 0x08: + return compilation.FindType(KnownTypeCode.Int32); + case 0x09: + return compilation.FindType(KnownTypeCode.UInt32); + case 0x0a: + return compilation.FindType(KnownTypeCode.Int64); + case 0x0b: + return compilation.FindType(KnownTypeCode.UInt64); + case 0x0c: + return compilation.FindType(KnownTypeCode.Single); + case 0x0d: + return compilation.FindType(KnownTypeCode.Double); + case 0x0e: + return compilation.FindType(KnownTypeCode.String); + case 0x1d: + return new ArrayType(compilation, ReadCustomAttributeFieldOrPropType()); + case 0x50: + return compilation.FindType(KnownTypeCode.Type); + case 0x51: // boxed value type + return compilation.FindType(KnownTypeCode.Object); + case 0x55: // enum + var type = ReadType(); + if (type == null) { + throw new NotSupportedException("Enum type should not be null."); + } + return type; + default: + throw new NotSupportedException(string.Format("Custom attribute type 0x{0:x} is not supported.", b)); + } + } + + IType ReadType() + { + string typeName = blob.ReadSerializedString(); + if (typeName == null) { + return null; + } + ITypeReference typeReference = ReflectionHelper.ParseReflectionName(typeName); + IType typeInCurrentAssembly = typeReference.Resolve(context); + if (typeInCurrentAssembly.Kind != TypeKind.Unknown) + return typeInCurrentAssembly; + + // look for the type in mscorlib + ITypeDefinition systemObject = context.Compilation.FindType(KnownTypeCode.Object).GetDefinition(); + if (systemObject != null) { + return typeReference.Resolve(new SimpleTypeResolveContext(systemObject.ParentAssembly)); + } else { + // couldn't find corlib - return the unknown IType for the current assembly + return typeInCurrentAssembly; + } + } + } +} \ No newline at end of file diff --git a/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs b/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs index 0a54cc6d4..9754edce7 100644 --- a/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs +++ b/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs @@ -18,9 +18,11 @@ using System; using System.Collections.Generic; -using Mono.Cecil; -using Mono.Cecil.Cil; +using System.Linq; +using System.Reflection.Metadata; using System.Text; +using ICSharpCode.Decompiler.Dom; +using ICSharpCode.Decompiler.Util; using SRM = System.Reflection.Metadata; namespace ICSharpCode.Decompiler.Disassembler @@ -57,62 +59,35 @@ namespace ICSharpCode.Decompiler.Disassembler return string.Format("IL_{0:x4}", offset); } - public static void WriteOffsetReference(ITextOutput writer, Instruction instruction) + public static void WriteOffsetReference(ITextOutput writer, int? offset) { - if (instruction == null) + if (offset == null) writer.Write("null"); else - writer.WriteReference(OffsetToString(instruction.Offset), instruction); + writer.WriteReference(OffsetToString(offset.Value), offset); } - public static void WriteTo(this ExceptionHandler exceptionHandler, ITextOutput writer) + public static void WriteTo(this SRM.ExceptionRegion exceptionHandler, Dom.MethodDefinition method, ITextOutput writer) { writer.Write(".try "); - WriteOffsetReference(writer, exceptionHandler.TryStart); + WriteOffsetReference(writer, exceptionHandler.TryOffset); writer.Write('-'); - WriteOffsetReference(writer, exceptionHandler.TryEnd); + WriteOffsetReference(writer, exceptionHandler.TryOffset + exceptionHandler.TryLength); writer.Write(' '); - writer.Write(exceptionHandler.HandlerType.ToString().ToLowerInvariant()); - if (exceptionHandler.FilterStart != null) { + writer.Write(exceptionHandler.Kind.ToString().ToLowerInvariant()); + if (exceptionHandler.FilterOffset != -1) { writer.Write(' '); - WriteOffsetReference(writer, exceptionHandler.FilterStart); + WriteOffsetReference(writer, exceptionHandler.FilterOffset); writer.Write(" handler "); } - if (exceptionHandler.CatchType != null) { + if (!exceptionHandler.CatchType.IsNil) { writer.Write(' '); - exceptionHandler.CatchType.WriteTo(writer); + exceptionHandler.CatchType.CoerceTypeReference(method.Module).WriteTo(writer, new GenericContext(method)); } writer.Write(' '); - WriteOffsetReference(writer, exceptionHandler.HandlerStart); + WriteOffsetReference(writer, exceptionHandler.HandlerOffset); writer.Write('-'); - WriteOffsetReference(writer, exceptionHandler.HandlerEnd); - } - - public static void WriteTo(this Instruction instruction, ITextOutput writer) - { - writer.WriteDefinition(OffsetToString(instruction.Offset), instruction); - writer.Write(": "); - writer.WriteReference(instruction.OpCode.Name, instruction.OpCode); - if (instruction.Operand != null) { - writer.Write(' '); - if (instruction.OpCode == OpCodes.Ldtoken) { - if (instruction.Operand is MethodReference) - writer.Write("method "); - else if (instruction.Operand is FieldReference) - writer.Write("field "); - } - WriteOperand(writer, instruction.Operand); - } - } - - static void WriteLabelList(ITextOutput writer, Instruction[] instructions) - { - writer.Write("("); - for (int i = 0; i < instructions.Length; i++) { - if (i != 0) writer.Write(", "); - WriteOffsetReference(writer, instructions[i]); - } - writer.Write(")"); + WriteOffsetReference(writer, exceptionHandler.HandlerOffset + exceptionHandler.HandlerLength); } static string ToInvariantCultureString(object value) @@ -123,57 +98,6 @@ namespace ICSharpCode.Decompiler.Disassembler : value.ToString(); } - public static void WriteTo(this MethodReference method, ITextOutput writer) - { - if (method.ExplicitThis) { - writer.Write("instance explicit "); - } else if (method.HasThis) { - writer.Write("instance "); - } - if (method.CallingConvention == MethodCallingConvention.VarArg) { - writer.Write("vararg "); - } - method.ReturnType.WriteTo(writer, ILNameSyntax.SignatureNoNamedTypeParameters); - writer.Write(' '); - if (method.DeclaringType != null) { - method.DeclaringType.WriteTo(writer, ILNameSyntax.TypeName); - writer.Write("::"); - } - MethodDefinition md = method as MethodDefinition; - if (md != null && md.IsCompilerControlled) { - writer.WriteReference(Escape(method.Name + "$PST" + method.MetadataToken.ToInt32().ToString("X8")), method); - } else { - writer.WriteReference(Escape(method.Name), method); - } - GenericInstanceMethod gim = method as GenericInstanceMethod; - if (gim != null) { - writer.Write('<'); - for (int i = 0; i < gim.GenericArguments.Count; i++) { - if (i > 0) - writer.Write(", "); - gim.GenericArguments[i].WriteTo(writer); - } - writer.Write('>'); - } - writer.Write("("); - var parameters = method.Parameters; - for (int i = 0; i < parameters.Count; ++i) { - if (i > 0) - writer.Write(", "); - parameters[i].ParameterType.WriteTo(writer, ILNameSyntax.SignatureNoNamedTypeParameters); - } - writer.Write(")"); - } - - static void WriteTo(this FieldReference field, ITextOutput writer) - { - field.FieldType.WriteTo(writer, ILNameSyntax.SignatureNoNamedTypeParameters); - writer.Write(' '); - field.DeclaringType.WriteTo(writer, ILNameSyntax.TypeName); - writer.Write("::"); - writer.WriteReference(Escape(field.Name), field); - } - static bool IsValidIdentifierCharacter(char c) { return c == '_' || c == '$' || c == '@' || c == '?' || c == '`'; @@ -194,48 +118,9 @@ namespace ICSharpCode.Decompiler.Disassembler return true; } - static readonly HashSet ilKeywords = BuildKeywordList( - "abstract", "algorithm", "alignment", "ansi", "any", "arglist", - "array", "as", "assembly", "assert", "at", "auto", "autochar", "beforefieldinit", - "blob", "blob_object", "bool", "brnull", "brnull.s", "brzero", "brzero.s", "bstr", - "bytearray", "byvalstr", "callmostderived", "carray", "catch", "cdecl", "cf", - "char", "cil", "class", "clsid", "const", "currency", "custom", "date", "decimal", - "default", "demand", "deny", "endmac", "enum", "error", "explicit", "extends", "extern", - "false", "famandassem", "family", "famorassem", "fastcall", "fault", "field", "filetime", - "filter", "final", "finally", "fixed", "float", "float32", "float64", "forwardref", - "fromunmanaged", "handler", "hidebysig", "hresult", "idispatch", "il", "illegal", - "implements", "implicitcom", "implicitres", "import", "in", "inheritcheck", "init", - "initonly", "instance", "int", "int16", "int32", "int64", "int8", "interface", "internalcall", - "iunknown", "lasterr", "lcid", "linkcheck", "literal", "localloc", "lpstr", "lpstruct", "lptstr", - "lpvoid", "lpwstr", "managed", "marshal", "method", "modopt", "modreq", "native", "nested", - "newslot", "noappdomain", "noinlining", "nomachine", "nomangle", "nometadata", "noncasdemand", - "noncasinheritance", "noncaslinkdemand", "noprocess", "not", "not_in_gc_heap", "notremotable", - "notserialized", "null", "nullref", "object", "objectref", "opt", "optil", "out", - "permitonly", "pinned", "pinvokeimpl", "prefix1", "prefix2", "prefix3", "prefix4", "prefix5", "prefix6", - "prefix7", "prefixref", "prejitdeny", "prejitgrant", "preservesig", "private", "privatescope", "protected", - "public", "record", "refany", "reqmin", "reqopt", "reqrefuse", "reqsecobj", "request", "retval", - "rtspecialname", "runtime", "safearray", "sealed", "sequential", "serializable", "special", "specialname", - "static", "stdcall", "storage", "stored_object", "stream", "streamed_object", "string", "struct", - "synchronized", "syschar", "sysstring", "tbstr", "thiscall", "tls", "to", "true", "typedref", - "unicode", "unmanaged", "unmanagedexp", "unsigned", "unused", "userdefined", "value", "valuetype", - "vararg", "variant", "vector", "virtual", "void", "wchar", "winapi", "with", "wrapper", - - // These are not listed as keywords in spec, but ILAsm treats them as such - "property", "type", "flags", "callconv", "strict" - ); - - static HashSet BuildKeywordList(params string[] keywords) - { - HashSet s = new HashSet(keywords); - foreach (var field in typeof(OpCodes).GetFields()) { - s.Add(((OpCode)field.GetValue(null)).Name); - } - return s; - } - public static string Escape(string identifier) { - if (IsValidIdentifier(identifier) && !ilKeywords.Contains(identifier)) { + if (IsValidIdentifier(identifier) && !IL.ILOpCodeExtensions.ILKeywords.Contains(identifier)) { return identifier; } else { // The ECMA specification says that ' inside SQString should be ecaped using an octal escape sequence, @@ -244,112 +129,34 @@ namespace ICSharpCode.Decompiler.Disassembler } } - public static void WriteTo(this TypeReference type, ITextOutput writer, ILNameSyntax syntax = ILNameSyntax.Signature) + public static void WriteParameterReference(ITextOutput writer, Dom.MethodDefinition method, int sequence) { - ILNameSyntax syntaxForElementTypes = syntax == ILNameSyntax.SignatureNoNamedTypeParameters ? syntax : ILNameSyntax.Signature; - if (type is PinnedType) { - ((PinnedType)type).ElementType.WriteTo(writer, syntaxForElementTypes); - writer.Write(" pinned"); - } else if (type is ArrayType) { - ArrayType at = (ArrayType)type; - at.ElementType.WriteTo(writer, syntaxForElementTypes); - writer.Write('['); - writer.Write(string.Join(", ", at.Dimensions)); - writer.Write(']'); - } else if (type is GenericParameter) { - writer.Write('!'); - if (((GenericParameter)type).Owner.GenericParameterType == GenericParameterType.Method) - writer.Write('!'); - if (string.IsNullOrEmpty(type.Name) || type.Name[0] == '!' || syntax == ILNameSyntax.SignatureNoNamedTypeParameters) - writer.Write(((GenericParameter)type).Position.ToString()); - else - writer.Write(Escape(type.Name)); - } else if (type is ByReferenceType) { - ((ByReferenceType)type).ElementType.WriteTo(writer, syntaxForElementTypes); - writer.Write('&'); - } else if (type is PointerType) { - ((PointerType)type).ElementType.WriteTo(writer, syntaxForElementTypes); - writer.Write('*'); - } else if (type is GenericInstanceType) { - type.GetElementType().WriteTo(writer, syntaxForElementTypes); - writer.Write('<'); - var arguments = ((GenericInstanceType)type).GenericArguments; - for (int i = 0; i < arguments.Count; i++) { - if (i > 0) - writer.Write(", "); - arguments[i].WriteTo(writer, syntaxForElementTypes); - } - writer.Write('>'); - } else if (type is OptionalModifierType) { - ((OptionalModifierType)type).ElementType.WriteTo(writer, syntax); - writer.Write(" modopt("); - ((OptionalModifierType)type).ModifierType.WriteTo(writer, ILNameSyntax.TypeName); - writer.Write(") "); - } else if (type is RequiredModifierType) { - ((RequiredModifierType)type).ElementType.WriteTo(writer, syntax); - writer.Write(" modreq("); - ((RequiredModifierType)type).ModifierType.WriteTo(writer, ILNameSyntax.TypeName); - writer.Write(") "); - } else if (type is FunctionPointerType fpt) { - writer.Write("method "); - fpt.ReturnType.WriteTo(writer, syntax); - writer.Write(" *("); - bool first = true; - foreach (var p in fpt.Parameters) { - if (first) - first = false; - else - writer.Write(", "); - p.ParameterType.WriteTo(writer, syntax); - } - writer.Write(')'); - } else if (type is SentinelType) { - writer.Write("..., "); - ((SentinelType)type).ElementType.WriteTo(writer, syntax); + var metadata = method.Module.GetMetadataReader(); + var signatureHeader = method.DecodeSignature(new FullTypeNameSignatureDecoder(metadata), default(Unit)).Header; + int index = signatureHeader.IsInstance && !signatureHeader.HasExplicitThis ? sequence - 1 : sequence; + if (index < 0 || index >= method.Parameters.Count) { + writer.Write(sequence.ToString()); } else { - string name = PrimitiveTypeName(type.FullName); - if (syntax == ILNameSyntax.ShortTypeName) { - if (name != null) - writer.Write(name); - else - writer.WriteReference(Escape(type.Name), type); - } else if ((syntax == ILNameSyntax.Signature || syntax == ILNameSyntax.SignatureNoNamedTypeParameters) && name != null) { - writer.Write(name); + var param = metadata.GetParameter(method.Parameters.ElementAt(index)); + if (param.Name.IsNil) { + writer.Write(sequence.ToString()); } else { - if (syntax == ILNameSyntax.Signature || syntax == ILNameSyntax.SignatureNoNamedTypeParameters) - writer.Write(type.IsValueType ? "valuetype " : "class "); - - if (type.DeclaringType != null) { - type.DeclaringType.WriteTo(writer, ILNameSyntax.TypeName); - writer.Write('/'); - writer.WriteReference(Escape(type.Name), type); - } else { - if (!type.IsDefinition && type.Scope != null && !(type is TypeSpecification)) - writer.Write("[{0}]", Escape(type.Scope.Name)); - writer.WriteReference(Escape(type.FullName), type); - } + writer.Write(Escape(metadata.GetString(param.Name))); } } } + public static void WriteVariableReference(ITextOutput writer, Dom.MethodDefinition method, int index) + { + writer.Write(index.ToString()); + } + public static void WriteOperand(ITextOutput writer, object operand) { if (operand == null) throw new ArgumentNullException(nameof(operand)); - Instruction targetInstruction = operand as Instruction; - if (targetInstruction != null) { - WriteOffsetReference(writer, targetInstruction); - return; - } - - Instruction[] targetInstructions = operand as Instruction[]; - if (targetInstructions != null) { - WriteLabelList(writer, targetInstructions); - return; - } - - VariableReference variableRef = operand as VariableReference; + /*VariableReference variableRef = operand as VariableReference; if (variableRef != null) { writer.WriteReference(variableRef.Index.ToString(), variableRef); return; @@ -363,25 +170,7 @@ namespace ICSharpCode.Decompiler.Disassembler } else writer.WriteReference(Escape(paramRef.Name), paramRef); return; - } - - MethodReference methodRef = operand as MethodReference; - if (methodRef != null) { - methodRef.WriteTo(writer); - return; - } - - TypeReference typeRef = operand as TypeReference; - if (typeRef != null) { - typeRef.WriteTo(writer, ILNameSyntax.TypeName); - return; - } - - FieldReference fieldRef = operand as FieldReference; - if (fieldRef != null) { - fieldRef.WriteTo(writer); - return; - } + }*/ string s = operand as string; if (s != null) { diff --git a/ICSharpCode.Decompiler/Disassembler/DomExtensions.cs b/ICSharpCode.Decompiler/Disassembler/DomExtensions.cs new file mode 100644 index 000000000..79115cbab --- /dev/null +++ b/ICSharpCode.Decompiler/Disassembler/DomExtensions.cs @@ -0,0 +1,373 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Immutable; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using ICSharpCode.Decompiler.Dom; +using ICSharpCode.Decompiler.Util; + +namespace ICSharpCode.Decompiler.Disassembler +{ + public static class DomExtensions + { + public static void WriteTo(this Dom.FieldDefinition field, ITextOutput output) + { + var signature = field.DecodeSignature(new DisassemblerSignatureProvider(field.Module, output), new GenericContext(field.DeclaringType)); + signature(ILNameSyntax.SignatureNoNamedTypeParameters); + output.Write(' '); + field.DeclaringType.WriteTo(output, ILNameSyntax.TypeName); + output.Write("::"); + output.Write(DisassemblerHelpers.Escape(field.Name)); + } + + public static void WriteTo(this IMemberReference member, ITextOutput output, GenericContext genericContext, ILNameSyntax syntax = ILNameSyntax.Signature) + { + void WriteParent(EntityHandle parentHandle) + { + var metadata = member.Module.GetMetadataReader(); + switch (parentHandle.Kind) { + case HandleKind.MethodDefinition: + new Dom.MethodDefinition(member.Module, (MethodDefinitionHandle)parentHandle).WriteTo(output, genericContext, syntax); + break; + case HandleKind.ModuleReference: + output.Write('['); + var moduleRef = metadata.GetModuleReference((ModuleReferenceHandle)parentHandle); + output.Write(metadata.GetString(moduleRef.Name)); + output.Write(']'); + break; + case HandleKind.TypeDefinition: + new Dom.TypeDefinition(member.Module, (TypeDefinitionHandle)parentHandle).WriteTo(output, syntax); + break; + case HandleKind.TypeReference: + new Dom.TypeReference(member.Module, (TypeReferenceHandle)parentHandle).WriteTo(output, syntax); + break; + case HandleKind.TypeSpecification: + new Dom.TypeSpecification(member.Module, (TypeSpecificationHandle)parentHandle).WriteTo(output, genericContext, syntax); + break; + } + } + + MethodSignature> signature; + switch (member) { + case Dom.MethodDefinition md: + md.WriteTo(output); + break; + case Dom.MemberReference mr: + switch (mr.Kind) { + case MemberReferenceKind.Method: + signature = mr.DecodeMethodSignature(new DisassemblerSignatureProvider(member.Module, output), genericContext); + if (signature.Header.HasExplicitThis) { + output.Write("instance explicit "); + } else if (signature.Header.IsInstance) { + output.Write("instance "); + } + if (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs) { + output.Write("vararg "); + } + signature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters); + output.Write(' '); + WriteParent(mr.Parent); + output.Write("::"); + output.Write(DisassemblerHelpers.Escape(mr.Name)); + output.Write("("); + for (int i = 0; i < signature.ParameterTypes.Length; ++i) { + if (i > 0) + output.Write(", "); + signature.ParameterTypes[i](ILNameSyntax.SignatureNoNamedTypeParameters); + } + output.Write(")"); + break; + case MemberReferenceKind.Field: + var fieldSignature = mr.DecodeFieldSignature(new DisassemblerSignatureProvider(member.Module, output), genericContext); + fieldSignature(ILNameSyntax.SignatureNoNamedTypeParameters); + output.Write(' '); + WriteParent(mr.Parent); + output.Write("::"); + output.Write(DisassemblerHelpers.Escape(mr.Name)); + break; + } + break; + case Dom.MethodSpecification ms: + var substitution = ms.DecodeSignature(new DisassemblerSignatureProvider(ms.Module, output), genericContext); + switch (ms.Method) { + case Dom.MethodDefinition method: + var metadata = method.Module.GetMetadataReader(); + signature = method.DecodeSignature(new DisassemblerSignatureProvider(method.Module, output), new GenericContext(method)); + if (signature.Header.HasExplicitThis) { + output.Write("instance explicit "); + } else if (signature.Header.IsInstance) { + output.Write("instance "); + } + if (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs) { + output.Write("vararg "); + } + signature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters); + output.Write(' '); + if (!method.DeclaringType.IsNil) { + method.DeclaringType.WriteTo(output, ILNameSyntax.TypeName); + output.Write("::"); + } + bool isCompilerControlled = (method.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.PrivateScope; + if (isCompilerControlled) { + output.Write(DisassemblerHelpers.Escape(method.Name + "$PST" + MetadataTokens.GetToken(method.Handle).ToString("X8"))); + } else { + output.Write(DisassemblerHelpers.Escape(method.Name)); + } + output.Write('<'); + for (int i = 0; i < substitution.Length; i++) { + if (i > 0) + output.Write(", "); + substitution[i](syntax); + } + output.Write('>'); + output.Write("("); + for (int i = 0; i < signature.ParameterTypes.Length; ++i) { + if (i > 0) + output.Write(", "); + signature.ParameterTypes[i](ILNameSyntax.SignatureNoNamedTypeParameters); + } + output.Write(")"); + break; + case Dom.MemberReference mr: + signature = mr.DecodeMethodSignature(new DisassemblerSignatureProvider(member.Module, output), genericContext); + if (signature.Header.HasExplicitThis) { + output.Write("instance explicit "); + } else if (signature.Header.IsInstance) { + output.Write("instance "); + } + if (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs) { + output.Write("vararg "); + } + signature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters); + output.Write(' '); + WriteParent(mr.Parent); + output.Write("::"); + output.Write(DisassemblerHelpers.Escape(mr.Name)); + output.Write('<'); + for (int i = 0; i < substitution.Length; i++) { + if (i > 0) + output.Write(", "); + substitution[i](syntax); + } + output.Write('>'); + output.Write("("); + for (int i = 0; i < signature.ParameterTypes.Length; ++i) { + if (i > 0) + output.Write(", "); + signature.ParameterTypes[i](ILNameSyntax.SignatureNoNamedTypeParameters); + } + output.Write(")"); + break; + } + break; + } + } + + public static void WriteTo(this Dom.TypeReference typeRef, ITextOutput output, ILNameSyntax syntax = ILNameSyntax.Signature) + { + var metadata = typeRef.Module.GetMetadataReader(); + if (!typeRef.ResolutionScope.IsNil) { + output.Write("["); + var currentTypeRef = typeRef; + while (currentTypeRef.ResolutionScope.Kind == HandleKind.TypeReference) { + currentTypeRef = new Dom.TypeReference(currentTypeRef.Module, (TypeReferenceHandle)currentTypeRef.ResolutionScope); + } + switch (currentTypeRef.ResolutionScope.Kind) { + case HandleKind.ModuleReference: + break; + case HandleKind.AssemblyReference: + var asmRef = metadata.GetAssemblyReference((AssemblyReferenceHandle)currentTypeRef.ResolutionScope); + output.Write(DisassemblerHelpers.Escape(metadata.GetString(asmRef.Name))); + break; + } + output.Write("]"); + } + output.WriteReference(typeRef.FullName.ToILNameString(), typeRef); + } + + public static void WriteTo(this Dom.TypeDefinition typeDefinition, ITextOutput output, ILNameSyntax syntax = ILNameSyntax.Signature) + { + output.WriteReference(typeDefinition.FullName.ToILNameString(), typeDefinition); + } + + public static void WriteTo(this Dom.TypeSpecification typeSpecification, ITextOutput output, GenericContext genericContext, ILNameSyntax syntax = ILNameSyntax.Signature) + { + var signature = typeSpecification.DecodeSignature(new DisassemblerSignatureProvider(typeSpecification.Module, output), genericContext); + signature(syntax); + } + + public static void WriteTo(this ITypeReference type, ITextOutput output, GenericContext genericContext, ILNameSyntax syntax = ILNameSyntax.Signature) + { + switch (type) { + case Dom.TypeDefinition td: + td.WriteTo(output, syntax); + break; + case Dom.TypeReference tr: + tr.WriteTo(output, syntax); + break; + case Dom.TypeSpecification ts: + ts.WriteTo(output, genericContext, syntax); + break; + } + } + + public static void WriteTo(this Dom.MethodDefinition method, ITextOutput output) + { + var metadata = method.Module.GetMetadataReader(); + var signature = method.DecodeSignature(new DisassemblerSignatureProvider(method.Module, output), new GenericContext(method)); + if (signature.Header.HasExplicitThis) { + output.Write("instance explicit "); + } else if (signature.Header.IsInstance) { + output.Write("instance "); + } + if (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs) { + output.Write("vararg "); + } + signature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters); + output.Write(' '); + if (!method.DeclaringType.IsNil) { + method.DeclaringType.WriteTo(output, ILNameSyntax.TypeName); + output.Write("::"); + } + bool isCompilerControlled = (method.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.PrivateScope; + if (isCompilerControlled) { + output.Write(DisassemblerHelpers.Escape(method.Name + "$PST" + MetadataTokens.GetToken(method.Handle).ToString("X8"))); + } else { + output.Write(DisassemblerHelpers.Escape(method.Name)); + } + var genericParameters = method.GenericParameters; + if (genericParameters.Count > 0) { + output.Write('<'); + for (int i = 0; i < genericParameters.Count; i++) { + if (i > 0) + output.Write(", "); + var gp = metadata.GetGenericParameter(genericParameters[i]); + if ((gp.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == GenericParameterAttributes.ReferenceTypeConstraint) { + output.Write("class "); + } else if ((gp.Attributes & GenericParameterAttributes.NotNullableValueTypeConstraint) == GenericParameterAttributes.NotNullableValueTypeConstraint) { + output.Write("valuetype "); + } + if ((gp.Attributes & GenericParameterAttributes.DefaultConstructorConstraint) == GenericParameterAttributes.DefaultConstructorConstraint) { + output.Write(".ctor "); + } + var constraints = gp.GetConstraints(); + if (constraints.Count > 0) { + output.Write('('); + for (int j = 0; j < constraints.Count; j++) { + if (j > 0) + output.Write(", "); + var constraint = metadata.GetGenericParameterConstraint(constraints[j]); + constraint.Type.CoerceTypeReference(method.Module).WriteTo(output, new GenericContext(method), ILNameSyntax.TypeName); + } + output.Write(") "); + } + if ((gp.Attributes & GenericParameterAttributes.Contravariant) == GenericParameterAttributes.Contravariant) { + output.Write('-'); + } else if ((gp.Attributes & GenericParameterAttributes.Covariant) == GenericParameterAttributes.Covariant) { + output.Write('+'); + } + output.Write(DisassemblerHelpers.Escape(metadata.GetString(gp.Name))); + } + output.Write('>'); + } + output.Write("("); + for (int i = 0; i < signature.ParameterTypes.Length; ++i) { + if (i > 0) + output.Write(", "); + signature.ParameterTypes[i](ILNameSyntax.SignatureNoNamedTypeParameters); + } + output.Write(")"); + } + + public static bool IsBaseTypeOf(this ITypeReference baseType, ITypeReference derivedType) + { + var derivedTypeDefinition = derivedType.GetDefinition(); + while (!derivedTypeDefinition.IsNil) { + if (derivedTypeDefinition.FullName == baseType.FullName) + return true; + derivedTypeDefinition = derivedTypeDefinition.BaseType.GetDefinition(); + } + return false; + } + } + + public class TypeUsedInSignature : ISignatureTypeProvider + { + readonly PEFile module; + readonly Dom.TypeDefinition type; + + public TypeUsedInSignature(ITypeReference type) + { + this.module = type.Module; + this.type = type.GetDefinition(); + } + + public bool GetArrayType(bool elementType, ArrayShape shape) => elementType; + + public bool GetByReferenceType(bool elementType) => elementType; + + public bool GetFunctionPointerType(MethodSignature signature) + { + throw new NotImplementedException(); + } + + public bool GetGenericInstantiation(bool genericType, ImmutableArray typeArguments) + { + throw new NotImplementedException(); + } + + public bool GetGenericMethodParameter(Unit genericContext, int index) => false; + + public bool GetGenericTypeParameter(Unit genericContext, int index) => false; + + public bool GetModifiedType(bool modifier, bool unmodifiedType, bool isRequired) + { + throw new NotImplementedException(); + } + + public bool GetPinnedType(bool elementType) => elementType; + + public bool GetPointerType(bool elementType) => elementType; + + public bool GetPrimitiveType(PrimitiveTypeCode typeCode) + { + throw new NotImplementedException(); + } + + public bool GetSZArrayType(bool elementType) => elementType; + + public bool GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) + { + return module == type.Module && handle == type.Handle; + } + + public bool GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) + { + return new Dom.TypeReference(module, handle).GetDefinition() == type; + } + + public bool GetTypeFromSpecification(MetadataReader reader, Unit genericContext, TypeSpecificationHandle handle, byte rawTypeKind) + { + return new Dom.TypeSpecification(module, handle).GetDefinition() == type; + } + } +} \ No newline at end of file diff --git a/ICSharpCode.Decompiler/Disassembler/ILStructure.cs b/ICSharpCode.Decompiler/Disassembler/ILStructure.cs index a8d0c159d..a30be6d7c 100644 --- a/ICSharpCode.Decompiler/Disassembler/ILStructure.cs +++ b/ICSharpCode.Decompiler/Disassembler/ILStructure.cs @@ -19,7 +19,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using Mono.Cecil.Cil; +using System.Reflection.Metadata; +using ICSharpCode.Decompiler.IL; +using ICSharpCode.Decompiler.Util; namespace ICSharpCode.Decompiler.Disassembler { @@ -55,6 +57,7 @@ namespace ICSharpCode.Decompiler.Disassembler /// public class ILStructure { + public readonly Dom.MethodDefinition Method; public readonly ILStructureType Type; /// @@ -70,82 +73,83 @@ namespace ICSharpCode.Decompiler.Disassembler /// /// The exception handler associated with the Try, Filter or Handler block. /// - public readonly ExceptionHandler ExceptionHandler; + public readonly ExceptionRegion ExceptionHandler; /// /// The loop's entry point. /// - public readonly Instruction LoopEntryPoint; + public readonly int LoopEntryPointOffset; /// /// The list of child structures. /// public readonly List Children = new List(); - public ILStructure(MethodBody body) - : this(ILStructureType.Root, 0, body.CodeSize) + public ILStructure(Dom.MethodDefinition method, MethodBodyBlock body) + : this(method, ILStructureType.Root, 0, body.GetILReader().Length) { // Build the tree of exception structures: - for (int i = 0; i < body.ExceptionHandlers.Count; i++) { - ExceptionHandler eh = body.ExceptionHandlers[i]; - if (!body.ExceptionHandlers.Take(i).Any(oldEh => oldEh.TryStart == eh.TryStart && oldEh.TryEnd == eh.TryEnd)) - AddNestedStructure(new ILStructure(ILStructureType.Try, eh.TryStart.Offset, eh.TryEnd.Offset, eh)); - if (eh.HandlerType == ExceptionHandlerType.Filter) - AddNestedStructure(new ILStructure(ILStructureType.Filter, eh.FilterStart.Offset, eh.HandlerStart.Offset, eh)); - AddNestedStructure(new ILStructure(ILStructureType.Handler, eh.HandlerStart.Offset, eh.HandlerEnd == null ? body.CodeSize : eh.HandlerEnd.Offset, eh)); + for (int i = 0; i < body.ExceptionRegions.Length; i++) { + ExceptionRegion eh = body.ExceptionRegions[i]; + if (!body.ExceptionRegions.Take(i).Any(oldEh => oldEh.TryOffset == eh.TryOffset && oldEh.TryLength == eh.TryLength)) + AddNestedStructure(new ILStructure(method, ILStructureType.Try, eh.TryOffset, eh.TryOffset + eh.TryLength, eh)); + if (eh.Kind == ExceptionRegionKind.Filter) + AddNestedStructure(new ILStructure(method, ILStructureType.Filter, eh.FilterOffset, eh.HandlerOffset, eh)); + AddNestedStructure(new ILStructure(method, ILStructureType.Handler, eh.HandlerOffset, eh.HandlerOffset + eh.HandlerLength, eh)); } // Very simple loop detection: look for backward branches - List> allBranches = FindAllBranches(body); + (var allBranches, var isAfterConditionalBranch) = FindAllBranches(body.GetILReader()); // We go through the branches in reverse so that we find the biggest possible loop boundary first (think loops with "continue;") for (int i = allBranches.Count - 1; i >= 0; i--) { - int loopEnd = allBranches[i].Key.GetEndOffset(); - int loopStart = allBranches[i].Value.Offset; + int loopEnd = allBranches[i].Source.End; + int loopStart = allBranches[i].Target; if (loopStart < loopEnd) { // We found a backward branch. This is a potential loop. // Check that is has only one entry point: - Instruction entryPoint = null; + int entryPoint = -1; // entry point is first instruction in loop if prev inst isn't an unconditional branch - Instruction prev = allBranches[i].Value.Previous; - if (prev != null && !prev.OpCode.IsUnconditionalBranch()) - entryPoint = allBranches[i].Value; + if (!isAfterConditionalBranch[loopStart]) + entryPoint = allBranches[i].Target; bool multipleEntryPoints = false; - foreach (var pair in allBranches) { - if (pair.Key.Offset < loopStart || pair.Key.Offset >= loopEnd) { - if (loopStart <= pair.Value.Offset && pair.Value.Offset < loopEnd) { + foreach (var branch in allBranches) { + if (branch.Source.Start < loopStart || branch.Source.Start >= loopEnd) { + if (loopStart <= branch.Target && branch.Target < loopEnd) { // jump from outside the loop into the loop - if (entryPoint == null) - entryPoint = pair.Value; - else if (pair.Value != entryPoint) + if (entryPoint < 0) + entryPoint = branch.Target; + else if (branch.Target != entryPoint) multipleEntryPoints = true; } } } if (!multipleEntryPoints) { - AddNestedStructure(new ILStructure(ILStructureType.Loop, loopStart, loopEnd, entryPoint)); + AddNestedStructure(new ILStructure(method, ILStructureType.Loop, loopStart, loopEnd, entryPoint)); } } } SortChildren(); } - public ILStructure(ILStructureType type, int startOffset, int endOffset, ExceptionHandler handler = null) + public ILStructure(Dom.MethodDefinition method, ILStructureType type, int startOffset, int endOffset, ExceptionRegion handler = default(ExceptionRegion)) { Debug.Assert(startOffset < endOffset); + this.Method = method; this.Type = type; this.StartOffset = startOffset; this.EndOffset = endOffset; this.ExceptionHandler = handler; } - public ILStructure(ILStructureType type, int startOffset, int endOffset, Instruction loopEntryPoint) + public ILStructure(Dom.MethodDefinition method, ILStructureType type, int startOffset, int endOffset, int loopEntryPoint) { Debug.Assert(startOffset < endOffset); + this.Method = method; this.Type = type; this.StartOffset = startOffset; this.EndOffset = endOffset; - this.LoopEntryPoint = loopEntryPoint; + this.LoopEntryPointOffset = loopEntryPoint; } bool AddNestedStructure(ILStructure newStructure) @@ -180,29 +184,68 @@ namespace ICSharpCode.Decompiler.Disassembler return true; } + struct Branch + { + public Interval Source; + public int Target; + + public Branch(int start, int end, int target) + { + this.Source = new Interval(start, end); + this.Target = target; + } + + public override string ToString() + { + return $"[Branch Source={Source}, Target={Target}]"; + } + } + /// /// Finds all branches. Returns list of source offset->target offset mapping. /// Multiple entries for the same source offset are possible (switch statements). /// The result is sorted by source offset. /// - List> FindAllBranches(MethodBody body) + (List Branches, BitSet IsAfterUnconditionalBranch) FindAllBranches(BlobReader body) { - var result = new List>(); - foreach (Instruction inst in body.Instructions) { - switch (inst.OpCode.OperandType) { - case OperandType.InlineBrTarget: - case OperandType.ShortInlineBrTarget: - result.Add(new KeyValuePair(inst, (Instruction)inst.Operand)); + var result = new List(); + var bitset = new BitSet(body.Length); + body.Reset(); + int target; + while (body.RemainingBytes > 0) { + var offset = body.Offset; + int endOffset; + var thisOpCode = ILParser.DecodeOpCode(ref body); + switch (thisOpCode.GetOperandType()) { + case OperandType.BrTarget: + case OperandType.ShortBrTarget: + endOffset = body.Offset + thisOpCode.GetBranchOperandSize(); + target = ILParser.DecodeBranchTarget(ref body, thisOpCode); + result.Add(new Branch(offset, endOffset, target)); + bitset[endOffset] = IsUnconditionalBranch(thisOpCode); + break; + case OperandType.Switch: + var targets = ILParser.DecodeSwitchTargets(ref body); + foreach (int t in targets) + result.Add(new Branch(offset, offset + 4 * (targets.Length + 1), t)); break; - case OperandType.InlineSwitch: - foreach (Instruction target in (Instruction[])inst.Operand) - result.Add(new KeyValuePair(inst, target)); + default: + ILParser.SkipOperand(ref body, thisOpCode); break; } } - // ignore the branches where Cecil doesn't decode the target - result.RemoveAll(x => x.Value == null); - return result; + return (result, bitset); + } + + static bool IsUnconditionalBranch(ILOpCode opCode) + { + switch (opCode) { + case ILOpCode.Br: + case ILOpCode.Br_s: + return true; + default: + return false; + } } void SortChildren() diff --git a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs index 7b2ced187..af2e9b1ce 100644 --- a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs @@ -20,9 +20,10 @@ using System; using System.Collections.Generic; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; -using System.Reflection.PortableExecutable; using System.Threading; +using ICSharpCode.Decompiler.IL; + namespace ICSharpCode.Decompiler.Disassembler { /// @@ -31,8 +32,6 @@ namespace ICSharpCode.Decompiler.Disassembler public class MethodBodyDisassembler { readonly ITextOutput output; - readonly MetadataReader metadata; - readonly PEReader reader; readonly CancellationToken cancellationToken; /// @@ -45,1085 +44,60 @@ namespace ICSharpCode.Decompiler.Disassembler /// public bool ShowSequencePoints { get; set; } - IList sequencePoints; + IList sequencePoints; int nextSequencePointIndex; - public MethodBodyDisassembler(ITextOutput output, PEReader reader, CancellationToken cancellationToken) + public MethodBodyDisassembler(ITextOutput output, CancellationToken cancellationToken) { this.output = output ?? throw new ArgumentNullException(nameof(output)); this.cancellationToken = cancellationToken; - this.reader = reader; - this.metadata = reader.GetMetadataReader(); } - public unsafe virtual void Disassemble(MethodDefinitionHandle handle) + public unsafe virtual void Disassemble(Dom.MethodDefinition method) { // start writing IL code - MethodDefinition method = metadata.GetMethodDefinition(handle); - output.WriteLine("// Method begins at RVA 0x{0:x4}", method.RelativeVirtualAddress); - if (method.RelativeVirtualAddress == 0) { + output.WriteLine("// Method begins at RVA 0x{0:x4}", method.RVA); + if (method.RVA == 0) { output.WriteLine("// Code size {0} (0x{0:x})", 0); output.WriteLine(".maxstack {0}", 0); output.WriteLine(); return; } - var body = reader.GetMethodBody(method.RelativeVirtualAddress); - output.WriteLine("// Code size {0} (0x{0:x})", body.Size); // wrong + var body = method.Body; + var blob = body.GetILReader(); + output.WriteLine("// Code size {0} (0x{0:x})", blob.Length); output.WriteLine(".maxstack {0}", body.MaxStack); - ulong address = (ulong)reader.PEHeaders.PEHeader.AddressOfEntryPoint; - output.WriteLine($"// Entrypoint: 0x{address:x}"); - int token = MetadataTokens.GetToken(handle); - var entrypointHandle = MetadataTokens.MethodDefinitionHandle(reader.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress); - if (handle == entrypointHandle) + var entrypointHandle = MetadataTokens.MethodDefinitionHandle(method.Module.Reader.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress); + if (method.Handle == entrypointHandle) output.WriteLine(".entrypoint"); - DisassembleLocalsBlock(handle, body); + DisassembleLocalsBlock(method, body); output.WriteLine(); - WriteInstructions(body.GetILReader()); + var metadata = method.Module.GetMetadataReader(); - /* - sequencePoints = method.DebugInformation?.SequencePoints; + sequencePoints = method.GetSequencePoints(); nextSequencePointIndex = 0; - if (DetectControlStructure && body.Instructions.Count > 0) { - Instruction inst = body.Instructions[0]; - HashSet branchTargets = GetBranchTargets(body.Instructions); - WriteStructureBody(new ILStructure(body), branchTargets, ref inst, method.Body.CodeSize); + if (DetectControlStructure && blob.Length > 0) { + blob.Reset(); + HashSet branchTargets = GetBranchTargets(blob); + blob.Reset(); + WriteStructureBody(new ILStructure(method, body), branchTargets, ref blob); } else { - foreach (var inst in method.Body.Instructions) { - WriteInstruction(output, inst); - output.WriteLine(); + while (blob.RemainingBytes > 0) { + WriteInstruction(output, method, ref blob); } - WriteExceptionHandlers(body); + WriteExceptionHandlers(method, body); } - sequencePoints = null;*/ + sequencePoints = null; } - void WriteInstructions(BlobReader blob) + void DisassembleLocalsBlock(Dom.MethodDefinition method, MethodBodyBlock body) { - while (blob.RemainingBytes > 0) { - WriteInstruction(blob.Offset, blob.ReadByte(), ref blob); - } - } - - void WriteInstruction(int offset, byte instructionByte, ref BlobReader blob) - { - output.WriteDefinition(DisassemblerHelpers.OffsetToString(offset), offset); - output.Write(": "); - if (instructionByte == 0xFE) { - instructionByte = blob.ReadByte(); - switch (instructionByte) { - case 0x00: - output.WriteReference("arglist", new OpCodeInfo(0xFE00, "arglist")); - output.WriteLine(); - break; - case 0x01: - output.WriteReference("ceq", new OpCodeInfo(0xFE01, "ceq")); - output.WriteLine(); - break; - case 0x02: - output.WriteReference("cgt", new OpCodeInfo(0xFE02, "cgt")); - output.WriteLine(); - break; - case 0x03: - output.WriteReference("cgt.un", new OpCodeInfo(0xFE03, "cgt.un")); - output.WriteLine(); - break; - case 0x04: - output.WriteReference("clt", new OpCodeInfo(0xFE04, "clt")); - output.WriteLine(); - break; - case 0x05: - output.WriteReference("clt.un", new OpCodeInfo(0xFE05, "clt.un")); - output.WriteLine(); - break; - case 0x06: - var token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("ldftn", new OpCodeInfo(0xFE06, "ldftn")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x07: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("ldvirtftn", new OpCodeInfo(0xFE07, "ldvirtftn")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x09: - ushort arg = blob.ReadUInt16(); - output.WriteReference("ldarg", new OpCodeInfo(0xFE09, "ldarg")); - output.WriteLine($" {arg}"); - break; - case 0x0A: - arg = blob.ReadUInt16(); - output.WriteReference("ldarga", new OpCodeInfo(0xFE0A, "ldarga")); - output.WriteLine($" {arg}"); - break; - case 0x0B: - arg = blob.ReadUInt16(); - output.WriteReference("starg", new OpCodeInfo(0xFE0B, "starg")); - output.WriteLine($" {arg}"); - break; - case 0x0C: - arg = blob.ReadUInt16(); - output.WriteReference("ldloc", new OpCodeInfo(0xFE0C, "ldloc")); - output.WriteLine($" {arg}"); - break; - case 0x0D: - arg = blob.ReadUInt16(); - output.WriteReference("ldloca", new OpCodeInfo(0xFE0D, "ldloca")); - output.WriteLine($" {arg}"); - break; - case 0x0E: - arg = blob.ReadUInt16(); - output.WriteReference("stloc", new OpCodeInfo(0xFE0E, "stloc")); - output.WriteLine($" {arg}"); - break; - case 0x0F: - output.WriteReference("localloc", new OpCodeInfo(0xFE0F, "localloc")); - output.WriteLine(); - break; - case 0x11: - output.WriteReference("endfilter", new OpCodeInfo(0xFE11, "endfilter")); - output.WriteLine(); - break; - case 0x12: - var alignment = blob.ReadByte(); - output.WriteReference("unaligned.", new OpCodeInfo(0xFE12, "unaligned.")); - output.WriteLine($" {alignment}"); - break; - case 0x13: - output.WriteReference("volatile.", new OpCodeInfo(0xFE13, "volatile.")); - output.WriteLine(); - break; - case 0x14: - output.WriteReference("tail.", new OpCodeInfo(0xFE14, "tail.")); - output.WriteLine(); - break; - case 0x15: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("initobj", new OpCodeInfo(0xFE15, "initobj")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x16: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("constrained.", new OpCodeInfo(0xFE16, "constrained.")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x17: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("cpblk", new OpCodeInfo(0xFE17, "cpblk")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x18: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("initblk", new OpCodeInfo(0xFE18, "initblk")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x19: - var type = blob.ReadByte(); - output.WriteReference("no.", new OpCodeInfo(0xFE19, "no.")); - if ((type & 1) == 1) - output.Write(" typecheck"); - if ((type & 2) == 2) - output.Write(" rangecheck"); - if ((type & 4) == 4) - output.Write(" nullcheck"); - output.WriteLine(); - break; - case 0x1A: - output.WriteReference("rethrow", new OpCodeInfo(0xFE1A, "rethrow")); - output.WriteLine(); - break; - case 0x1C: - output.WriteReference("sizeof", new OpCodeInfo(0xFE1C, "sizeof")); - output.WriteLine(); - break; - case 0x1D: - output.WriteReference("refanytype", new OpCodeInfo(0xFE1D, "refanytype")); - output.WriteLine(); - break; - case 0x1E: - output.WriteReference("readonly.", new OpCodeInfo(0xFE1E, "readonly.")); - output.WriteLine(); - break; - default: - output.WriteLine($".emitbyte 0xfe"); - output.WriteLine($".emitbyte 0x{instructionByte:x2}"); - break; - } - } else { - switch (instructionByte) { - case 0x00: - output.WriteReference("nop", new OpCodeInfo(0x0, "nop")); - output.WriteLine(); - break; - case 0x01: - output.WriteReference("break", new OpCodeInfo(0x1, "break")); - output.WriteLine(); - break; - case 0x02: - case 0x03: - case 0x04: - case 0x05: - output.WriteReference($"ldarg.{instructionByte - 0x2}", new OpCodeInfo(instructionByte, $"ldarg.{instructionByte - 0x2}")); - output.WriteLine(); - break; - case 0x06: - case 0x07: - case 0x08: - case 0x09: - output.WriteReference($"ldloc.{instructionByte - 0x6}", new OpCodeInfo(instructionByte, $"ldloc.{instructionByte - 0x6}")); - output.WriteLine(); - break; - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - output.WriteReference($"stloc.{instructionByte - 0xA}", new OpCodeInfo(instructionByte, $"stloc.{instructionByte - 0xA}")); - output.WriteLine(); - break; - case 0x0E: - byte arg = blob.ReadByte(); - output.WriteReference("ldarg.s", new OpCodeInfo(instructionByte, "ldarg.s")); - output.WriteLine(" {0}", arg); - break; - case 0x0F: - arg = blob.ReadByte(); - output.WriteReference("ldarga.s", new OpCodeInfo(instructionByte, "ldarga.s")); - output.WriteLine(" {0}", arg); - break; - case 0x10: - arg = blob.ReadByte(); - output.WriteReference("starg.s", new OpCodeInfo(instructionByte, "starg.s")); - output.WriteLine(" {0}", arg); - break; - case 0x11: - arg = blob.ReadByte(); - output.WriteReference("ldloc.s", new OpCodeInfo(instructionByte, "ldloc.s")); - output.WriteLine(" {0}", arg); - break; - case 0x12: - arg = blob.ReadByte(); - output.WriteReference("ldloca.s", new OpCodeInfo(instructionByte, "ldloca.s")); - output.WriteLine(" {0}", arg); - break; - case 0x13: - arg = blob.ReadByte(); - output.WriteReference("stloc.s", new OpCodeInfo(instructionByte, "stloc.s")); - output.WriteLine(" {0}", arg); - break; - case 0x14: - output.WriteReference("ldnull", new OpCodeInfo(instructionByte, "ldnull")); - output.WriteLine(); - break; - case 0x15: - output.WriteReference("ldc.i4.m1", new OpCodeInfo(instructionByte, "ldc.i4.m1")); - output.WriteLine(); - break; - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - output.WriteReference($"ldc.i4.{instructionByte - 0x16}", new OpCodeInfo(instructionByte, $"ldc.i4.{instructionByte - 0x16}")); - output.WriteLine(); - break; - case 0x1F: - sbyte sbarg = blob.ReadSByte(); - output.WriteReference("ldc.i4.s", new OpCodeInfo(instructionByte, "ldc.i4.s")); - output.WriteLine(" {0}", sbarg); - break; - case 0x20: - int intarg = blob.ReadInt32(); - output.WriteReference("ldc.i4", new OpCodeInfo(instructionByte, "ldc.i4")); - output.WriteLine(" {0}", intarg); - break; - case 0x21: - long longarg = blob.ReadInt64(); - output.WriteReference("ldc.i8", new OpCodeInfo(instructionByte, "ldc.i8")); - output.WriteLine(" {0}", longarg); - break; - case 0x22: - float farg = blob.ReadSingle(); - output.WriteReference("ldc.r4", new OpCodeInfo(instructionByte, "ldc.r4")); - output.WriteLine(" {0}", farg); - break; - case 0x23: - double darg = blob.ReadDouble(); - output.WriteReference("ldc.r8", new OpCodeInfo(instructionByte, "ldc.r8")); - output.WriteLine(" {0}", darg); - break; - case 0x25: - output.WriteReference("dup", new OpCodeInfo(instructionByte, "dup")); - output.WriteLine(); - break; - case 0x26: - output.WriteReference("pop", new OpCodeInfo(instructionByte, "pop")); - output.WriteLine(); - break; - case 0x27: - var token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("jmp", new OpCodeInfo(instructionByte, "jmp")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x28: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("call", new OpCodeInfo(instructionByte, "call")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x29: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("calli", new OpCodeInfo(instructionByte, "calli")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x2A: - output.WriteReference("ret", new OpCodeInfo(instructionByte, "ret")); - output.WriteLine(); - break; - case 0x2B: - int targetOffset = blob.ReadByte() + blob.Offset; - output.WriteReference("br.s", new OpCodeInfo(instructionByte, "br.s")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x2C: - targetOffset = blob.ReadByte() + blob.Offset; - output.WriteReference("brfalse.s", new OpCodeInfo(instructionByte, "brfalse.s")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x2D: - targetOffset = blob.ReadByte() + blob.Offset; - output.WriteReference("brtrue.s", new OpCodeInfo(instructionByte, "brtrue.s")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x2E: - targetOffset = blob.ReadByte() + blob.Offset; - output.WriteReference("beq.s", new OpCodeInfo(instructionByte, "beq.s")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x2F: - targetOffset = blob.ReadByte() + blob.Offset; - output.WriteReference("bge.s", new OpCodeInfo(instructionByte, "bge.s")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x30: - targetOffset = blob.ReadByte() + blob.Offset; - output.WriteReference("bgt.s", new OpCodeInfo(instructionByte, "bgt.s")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x31: - targetOffset = blob.ReadByte() + blob.Offset; - output.WriteReference("ble.s", new OpCodeInfo(instructionByte, "ble.s")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x32: - targetOffset = blob.ReadByte() + blob.Offset; - output.WriteReference("blt.s", new OpCodeInfo(instructionByte, "blt.s")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x33: - targetOffset = blob.ReadByte() + blob.Offset; - output.WriteReference("bne.un.s", new OpCodeInfo(instructionByte, "bne.un.s")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x34: - targetOffset = blob.ReadByte() + blob.Offset; - output.WriteReference("bge.un.s", new OpCodeInfo(instructionByte, "bge.un.s")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x35: - targetOffset = blob.ReadByte() + blob.Offset; - output.WriteReference("bgt.un.s", new OpCodeInfo(instructionByte, "bgt.un.s")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x36: - targetOffset = blob.ReadByte() + blob.Offset; - output.WriteReference("ble.un.s", new OpCodeInfo(instructionByte, "ble.un.s")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x37: - targetOffset = blob.ReadByte() + blob.Offset; - output.WriteReference("blt.un.s", new OpCodeInfo(instructionByte, "blt.un.s")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x38: - targetOffset = blob.ReadInt32() + blob.Offset; - output.WriteReference("br", new OpCodeInfo(instructionByte, "br")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x39: - targetOffset = blob.ReadInt32() + blob.Offset; - output.WriteReference("brfalse", new OpCodeInfo(instructionByte, "brfalse")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x3A: - targetOffset = blob.ReadInt32() + blob.Offset; - output.WriteReference("brtrue", new OpCodeInfo(instructionByte, "brtrue")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x3B: - targetOffset = blob.ReadInt32() + blob.Offset; - output.WriteReference("beq", new OpCodeInfo(instructionByte, "beq")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x3C: - targetOffset = blob.ReadInt32() + blob.Offset; - output.WriteReference("bge", new OpCodeInfo(instructionByte, "bge")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x3D: - targetOffset = blob.ReadInt32() + blob.Offset; - output.WriteReference("bgt", new OpCodeInfo(instructionByte, "bgt")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x3E: - targetOffset = blob.ReadInt32() + blob.Offset; - output.WriteReference("ble", new OpCodeInfo(instructionByte, "ble")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x3F: - targetOffset = blob.ReadInt32() + blob.Offset; - output.WriteReference("blt", new OpCodeInfo(instructionByte, "blt")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x40: - targetOffset = blob.ReadInt32() + blob.Offset; - output.WriteReference("bne.un", new OpCodeInfo(instructionByte, "bne.un")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x41: - targetOffset = blob.ReadInt32() + blob.Offset; - output.WriteReference("bge.un", new OpCodeInfo(instructionByte, "bge.un")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x42: - targetOffset = blob.ReadInt32() + blob.Offset; - output.WriteReference("bgt.un", new OpCodeInfo(instructionByte, "bgt.un")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x43: - targetOffset = blob.ReadInt32() + blob.Offset; - output.WriteReference("ble.un", new OpCodeInfo(instructionByte, "ble.un")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x44: - targetOffset = blob.ReadInt32() + blob.Offset; - output.WriteReference("blt.un", new OpCodeInfo(instructionByte, "blt.un")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0x45: - uint count = blob.ReadUInt32(); - int[] targetOffsets = new int[count]; - for (int i = 0; i < count; i++) { - targetOffsets[i] = blob.ReadInt32(); - } - output.WriteReference("switch", new OpCodeInfo(instructionByte, "switch")); - output.Write(" ("); - for (int i = 0; i < count; i++) { - if (i > 0) - output.Write(", "); - targetOffset = targetOffsets[i] + blob.Offset; - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - } - output.WriteLine(")"); - break; - case 0x46: - output.WriteReference("ldind.i1", new OpCodeInfo(instructionByte, "ldind.i1")); - output.WriteLine(); - break; - case 0x47: - output.WriteReference("ldind.u1", new OpCodeInfo(instructionByte, "ldind.u1")); - output.WriteLine(); - break; - case 0x48: - output.WriteReference("ldind.i2", new OpCodeInfo(instructionByte, "ldind.i2")); - output.WriteLine(); - break; - case 0x49: - output.WriteReference("ldind.u2", new OpCodeInfo(instructionByte, "ldind.u2")); - output.WriteLine(); - break; - case 0x4A: - output.WriteReference("ldind.i4", new OpCodeInfo(instructionByte, "ldind.i4")); - output.WriteLine(); - break; - case 0x4B: - output.WriteReference("ldind.u4", new OpCodeInfo(instructionByte, "ldind.u4")); - output.WriteLine(); - break; - case 0x4C: - output.WriteReference("ldind.i8", new OpCodeInfo(instructionByte, "ldind.i8")); - output.WriteLine(); - break; - case 0x4D: - output.WriteReference("ldind.i", new OpCodeInfo(instructionByte, "ldind.i")); - output.WriteLine(); - break; - case 0x4E: - output.WriteReference("ldind.r4", new OpCodeInfo(instructionByte, "ldind.r4")); - output.WriteLine(); - break; - case 0x4F: - output.WriteReference("ldind.r8", new OpCodeInfo(instructionByte, "ldind.r8")); - output.WriteLine(); - break; - case 0x50: - output.WriteReference("ldind.ref", new OpCodeInfo(instructionByte, "ldind.ref")); - output.WriteLine(); - break; - case 0x51: - output.WriteReference("stind.ref", new OpCodeInfo(instructionByte, "stind.ref")); - output.WriteLine(); - break; - case 0x52: - output.WriteReference("stind.i1", new OpCodeInfo(instructionByte, "stind.i1")); - output.WriteLine(); - break; - case 0x53: - output.WriteReference("stind.i2", new OpCodeInfo(instructionByte, "stind.i2")); - output.WriteLine(); - break; - case 0x54: - output.WriteReference("stind.i4", new OpCodeInfo(instructionByte, "stind.i4")); - output.WriteLine(); - break; - case 0x55: - output.WriteReference("stind.i8", new OpCodeInfo(instructionByte, "stind.i8")); - output.WriteLine(); - break; - case 0x56: - output.WriteReference("stind.r4", new OpCodeInfo(instructionByte, "stind.r4")); - output.WriteLine(); - break; - case 0x57: - output.WriteReference("stind.r8", new OpCodeInfo(instructionByte, "stind.r8")); - output.WriteLine(); - break; - case 0x58: - output.WriteReference("add", new OpCodeInfo(instructionByte, "add")); - output.WriteLine(); - break; - case 0x59: - output.WriteReference("sub", new OpCodeInfo(instructionByte, "sub")); - output.WriteLine(); - break; - case 0x5A: - output.WriteReference("mul", new OpCodeInfo(instructionByte, "mul")); - output.WriteLine(); - break; - case 0x5B: - output.WriteReference("div", new OpCodeInfo(instructionByte, "div")); - output.WriteLine(); - break; - case 0x5C: - output.WriteReference("div.un", new OpCodeInfo(instructionByte, "div.un")); - output.WriteLine(); - break; - case 0x5D: - output.WriteReference("rem", new OpCodeInfo(instructionByte, "rem")); - output.WriteLine(); - break; - case 0x5E: - output.WriteReference("rem.un", new OpCodeInfo(instructionByte, "rem.un")); - output.WriteLine(); - break; - case 0x5F: - output.WriteReference("and", new OpCodeInfo(instructionByte, "and")); - output.WriteLine(); - break; - case 0x60: - output.WriteReference("or", new OpCodeInfo(instructionByte, "or")); - output.WriteLine(); - break; - case 0x61: - output.WriteReference("xor", new OpCodeInfo(instructionByte, "xor")); - output.WriteLine(); - break; - case 0x62: - output.WriteReference("shl", new OpCodeInfo(instructionByte, "shl")); - output.WriteLine(); - break; - case 0x63: - output.WriteReference("shr", new OpCodeInfo(instructionByte, "shr")); - output.WriteLine(); - break; - case 0x64: - output.WriteReference("shr.un", new OpCodeInfo(instructionByte, "shr.un")); - output.WriteLine(); - break; - case 0x65: - output.WriteReference("neg", new OpCodeInfo(instructionByte, "neg")); - output.WriteLine(); - break; - case 0x66: - output.WriteReference("not", new OpCodeInfo(instructionByte, "not")); - output.WriteLine(); - break; - case 0x67: - output.WriteReference("conv.i1", new OpCodeInfo(instructionByte, "conv.i1")); - output.WriteLine(); - break; - case 0x68: - output.WriteReference("conv.i2", new OpCodeInfo(instructionByte, "conv.i2")); - output.WriteLine(); - break; - case 0x69: - output.WriteReference("conv.i4", new OpCodeInfo(instructionByte, "conv.i4")); - output.WriteLine(); - break; - case 0x6A: - output.WriteReference("conv.i8", new OpCodeInfo(instructionByte, "conv.i8")); - output.WriteLine(); - break; - case 0x6B: - output.WriteReference("conv.r4", new OpCodeInfo(instructionByte, "conv.r4")); - output.WriteLine(); - break; - case 0x6C: - output.WriteReference("conv.r8", new OpCodeInfo(instructionByte, "conv.r8")); - output.WriteLine(); - break; - case 0x6D: - output.WriteReference("conv.u4", new OpCodeInfo(instructionByte, "conv.u4")); - output.WriteLine(); - break; - case 0x6E: - output.WriteReference("conv.u8", new OpCodeInfo(instructionByte, "conv.u8")); - output.WriteLine(); - break; - case 0x6F: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("callvirt", new OpCodeInfo(instructionByte, "callvirt")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x70: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("cpobj", new OpCodeInfo(instructionByte, "cpobj")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x71: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("ldobj", new OpCodeInfo(instructionByte, "ldobj")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x72: - var str = metadata.GetUserString(MetadataTokens.UserStringHandle(blob.ReadInt32())); - output.WriteReference("ldstr", new OpCodeInfo(instructionByte, "ldstr")); - output.WriteLine($" \"{DisassemblerHelpers.EscapeString(str)}\""); - break; - case 0x73: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("newobj", new OpCodeInfo(instructionByte, "newobj")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x74: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("castclass", new OpCodeInfo(instructionByte, "castclass")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x75: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("isinst", new OpCodeInfo(instructionByte, "isinst")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x76: - output.WriteReference("conv.r.un", new OpCodeInfo(instructionByte, "conv.r.un")); - output.WriteLine(); - break; - case 0x79: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("unbox", new OpCodeInfo(instructionByte, "unbox")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x7A: - output.WriteReference("throw", new OpCodeInfo(instructionByte, "throw")); - output.WriteLine(); - break; - case 0x7B: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("ldfld", new OpCodeInfo(instructionByte, "ldfld")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x7C: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("ldflda", new OpCodeInfo(instructionByte, "ldflda")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x7D: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("stfld", new OpCodeInfo(instructionByte, "stfld")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x7E: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("ldsfld", new OpCodeInfo(instructionByte, "ldsfld")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x7F: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("ldsflda", new OpCodeInfo(instructionByte, "ldsflda")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x80: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("stsfld", new OpCodeInfo(instructionByte, "stsfld")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x81: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("stobj", new OpCodeInfo(instructionByte, "stobj")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x82: - output.WriteReference("conv.ovf.i1.un", new OpCodeInfo(instructionByte, "conv.ovf.i1.un")); - output.WriteLine(); - break; - case 0x83: - output.WriteReference("conv.ovf.i2.un", new OpCodeInfo(instructionByte, "conv.ovf.i2.un")); - output.WriteLine(); - break; - case 0x84: - output.WriteReference("conv.ovf.i4.un", new OpCodeInfo(instructionByte, "conv.ovf.i4.un")); - output.WriteLine(); - break; - case 0x85: - output.WriteReference("conv.ovf.i8.un", new OpCodeInfo(instructionByte, "conv.ovf.i8.un")); - output.WriteLine(); - break; - case 0x86: - output.WriteReference("conv.ovf.u1.un", new OpCodeInfo(instructionByte, "conv.ovf.u1.un")); - output.WriteLine(); - break; - case 0x87: - output.WriteReference("conv.ovf.u2.un", new OpCodeInfo(instructionByte, "conv.ovf.u2.un")); - output.WriteLine(); - break; - case 0x88: - output.WriteReference("conv.ovf.u4.un", new OpCodeInfo(instructionByte, "conv.ovf.u4.un")); - output.WriteLine(); - break; - case 0x89: - output.WriteReference("conv.ovf.u8.un", new OpCodeInfo(instructionByte, "conv.ovf.u8.un")); - output.WriteLine(); - break; - case 0x8A: - output.WriteReference("conv.ovf.i.un", new OpCodeInfo(instructionByte, "conv.ovf.i.un")); - output.WriteLine(); - break; - case 0x8B: - output.WriteReference("conv.ovf.u.un", new OpCodeInfo(instructionByte, "conv.ovf.u.un")); - output.WriteLine(); - break; - case 0x8C: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("box", new OpCodeInfo(instructionByte, "box")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x8D: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("newarr", new OpCodeInfo(instructionByte, "newarr")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x8E: - output.WriteReference("ldlen", new OpCodeInfo(instructionByte, "ldlen")); - output.WriteLine(); - break; - case 0x8F: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("ldelema", new OpCodeInfo(instructionByte, "ldelema")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0x90: - output.WriteReference("ldelem.i1", new OpCodeInfo(instructionByte, "ldelem.i1")); - output.WriteLine(); - break; - case 0x91: - output.WriteReference("ldelem.u1", new OpCodeInfo(instructionByte, "ldelem.u1")); - output.WriteLine(); - break; - case 0x92: - output.WriteReference("ldelem.i2", new OpCodeInfo(instructionByte, "ldelem.i2")); - output.WriteLine(); - break; - case 0x93: - output.WriteReference("ldelem.u2", new OpCodeInfo(instructionByte, "ldelem.u2")); - output.WriteLine(); - break; - case 0x94: - output.WriteReference("ldelem.i4", new OpCodeInfo(instructionByte, "ldelem.i4")); - output.WriteLine(); - break; - case 0x95: - output.WriteReference("ldelem.u4", new OpCodeInfo(instructionByte, "ldelem.u4")); - output.WriteLine(); - break; - case 0x96: - output.WriteReference("ldelem.i8", new OpCodeInfo(instructionByte, "ldelem.i8")); - output.WriteLine(); - break; - case 0x97: - output.WriteReference("ldelem.i", new OpCodeInfo(instructionByte, "ldelem.i")); - output.WriteLine(); - break; - case 0x98: - output.WriteReference("ldelem.r4", new OpCodeInfo(instructionByte, "ldelem.r4")); - output.WriteLine(); - break; - case 0x99: - output.WriteReference("ldelem.r8", new OpCodeInfo(instructionByte, "ldelem.r8")); - output.WriteLine(); - break; - case 0x9A: - output.WriteReference("ldelem.ref", new OpCodeInfo(instructionByte, "ldelem.ref")); - output.WriteLine(); - break; - case 0x9B: - output.WriteReference("stelem.i", new OpCodeInfo(instructionByte, "stelem.i")); - output.WriteLine(); - break; - case 0x9C: - output.WriteReference("stelem.i1", new OpCodeInfo(instructionByte, "stelem.i1")); - output.WriteLine(); - break; - case 0x9D: - output.WriteReference("stelem.i2", new OpCodeInfo(instructionByte, "stelem.i2")); - output.WriteLine(); - break; - case 0x9E: - output.WriteReference("stelem.i4", new OpCodeInfo(instructionByte, "stelem.i4")); - output.WriteLine(); - break; - case 0x9F: - output.WriteReference("stelem.i8", new OpCodeInfo(instructionByte, "stelem.i8")); - output.WriteLine(); - break; - case 0xA0: - output.WriteReference("stelem.r4", new OpCodeInfo(instructionByte, "stelem.r4")); - output.WriteLine(); - break; - case 0xA1: - output.WriteReference("stelem.r8", new OpCodeInfo(instructionByte, "stelem.r8")); - output.WriteLine(); - break; - case 0xA2: - output.WriteReference("stelem.ref", new OpCodeInfo(instructionByte, "stelem.ref")); - output.WriteLine(); - break; - case 0xA3: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("ldelem", new OpCodeInfo(instructionByte, "ldelem")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0xA4: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("stelem", new OpCodeInfo(instructionByte, "stelem")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0xC3: - output.WriteReference("ckfinite", new OpCodeInfo(instructionByte, "ckfinite")); - output.WriteLine(); - break; - case 0xD0: - token = MetadataTokens.EntityHandle(blob.ReadInt32()); - output.WriteReference("ldtoken", new OpCodeInfo(instructionByte, "ldtoken")); - output.Write(" "); - token.WriteTo(metadata, output); - output.WriteLine(); - break; - case 0xD1: - output.WriteReference("conv.u2", new OpCodeInfo(instructionByte, "conv.u2")); - output.WriteLine(); - break; - case 0xD2: - output.WriteReference("conv.u1", new OpCodeInfo(instructionByte, "conv.u1")); - output.WriteLine(); - break; - case 0xD3: - output.WriteReference("conv.i", new OpCodeInfo(instructionByte, "conv.i")); - output.WriteLine(); - break; - case 0xD4: - output.WriteReference("conv.ovf.i", new OpCodeInfo(instructionByte, "conv.ovf.i")); - output.WriteLine(); - break; - case 0xD5: - output.WriteReference("conv.ovf.u", new OpCodeInfo(instructionByte, "conv.ovf.u")); - output.WriteLine(); - break; - case 0xD6: - output.WriteReference("add.ovf", new OpCodeInfo(instructionByte, "add.ovf")); - output.WriteLine(); - break; - case 0xD7: - output.WriteReference("add.ovf.un", new OpCodeInfo(instructionByte, "add.ovf.un")); - output.WriteLine(); - break; - case 0xD8: - output.WriteReference("mul.ovf", new OpCodeInfo(instructionByte, "mul.ovf")); - output.WriteLine(); - break; - case 0xD9: - output.WriteReference("mul.ovf.un", new OpCodeInfo(instructionByte, "mul.ovf.un")); - output.WriteLine(); - break; - case 0xDA: - output.WriteReference("sub.ovf", new OpCodeInfo(instructionByte, "sub.ovf")); - output.WriteLine(); - break; - case 0xDB: - output.WriteReference("sub.ovf.un", new OpCodeInfo(instructionByte, "sub.ovf.un")); - output.WriteLine(); - break; - case 0xDC: - output.WriteReference("endfinally", new OpCodeInfo(instructionByte, "endfinally")); - output.WriteLine(); - break; - case 0xDD: - targetOffset = blob.ReadInt32() + blob.Offset; - output.WriteReference("leave", new OpCodeInfo(instructionByte, "leave")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0xDE: - targetOffset = blob.ReadByte() + blob.Offset; - output.WriteReference("leave.s", new OpCodeInfo(instructionByte, "leave.s")); - output.Write(" "); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); - output.WriteLine(); - break; - case 0xDF: - output.WriteReference("stind.i", new OpCodeInfo(instructionByte, "stind.i")); - output.WriteLine(); - break; - case 0xE0: - output.WriteReference("conv.u", new OpCodeInfo(instructionByte, "conv.u")); - output.WriteLine(); - break; - default: - output.WriteLine($".emitbyte 0x{instructionByte:x2}"); - break; - } - } - } - - void DisassembleLocalsBlock(MethodDefinitionHandle handle, MethodBodyBlock body) - { - MethodDefinition method = metadata.GetMethodDefinition(handle); - var declaringType = metadata.GetTypeDefinition(method.GetDeclaringType()); if (body.LocalSignature.IsNil) return; - var signature = metadata.GetStandaloneSignature(body.LocalSignature).DecodeLocalSignature(new MethodSignatureProvider(metadata, output), (declaringType.GetGenericParameters(), method.GetGenericParameters())); + var metadata = method.Module.GetMetadataReader(); + var signature = metadata.GetStandaloneSignature(body.LocalSignature).DecodeLocalSignature(new DisassemblerSignatureProvider(method.Module, output), new Dom.GenericContext(method)); if (!signature.IsEmpty) { output.Write(".locals "); if (body.LocalVariablesInitialized) @@ -1144,28 +118,30 @@ namespace ICSharpCode.Decompiler.Disassembler } } - internal void WriteExceptionHandlers(Mono.Cecil.Cil.MethodBody body) + internal void WriteExceptionHandlers(Dom.MethodDefinition method, MethodBodyBlock body) { - if (body.HasExceptionHandlers) { + var handlers = body.ExceptionRegions; + if (!handlers.IsEmpty) { output.WriteLine(); - foreach (var eh in body.ExceptionHandlers) { - eh.WriteTo(output); + foreach (var eh in handlers) { + eh.WriteTo(method, output); output.WriteLine(); } } } - HashSet GetBranchTargets(IEnumerable instructions) + HashSet GetBranchTargets(BlobReader blob) { HashSet branchTargets = new HashSet(); - foreach (var inst in instructions) { - var target = inst.Operand as Mono.Cecil.Cil.Instruction; - if (target != null) - branchTargets.Add(target.Offset); - var targets = inst.Operand as Mono.Cecil.Cil.Instruction[]; - if (targets != null) - foreach (var t in targets) - branchTargets.Add(t.Offset); + while (blob.RemainingBytes > 0) { + var opCode = ILParser.DecodeOpCode(ref blob); + if (opCode == ILOpCode.Switch) { + branchTargets.UnionWith(ILParser.DecodeSwitchTargets(ref blob)); + } else if (opCode.IsBranch()) { + branchTargets.Add(ILParser.DecodeBranchTarget(ref blob, opCode)); + } else { + ILParser.SkipOperand(ref blob, opCode); + } } return branchTargets; } @@ -1175,9 +151,9 @@ namespace ICSharpCode.Decompiler.Disassembler switch (s.Type) { case ILStructureType.Loop: output.Write("// loop start"); - if (s.LoopEntryPoint != null) { + if (s.LoopEntryPointOffset >= 0) { output.Write(" (head: "); - DisassemblerHelpers.WriteOffsetReference(output, s.LoopEntryPoint); + DisassemblerHelpers.WriteOffsetReference(output, s.LoopEntryPointOffset); output.Write(')'); } output.WriteLine(); @@ -1187,20 +163,20 @@ namespace ICSharpCode.Decompiler.Disassembler output.WriteLine("{"); break; case ILStructureType.Handler: - switch (s.ExceptionHandler.HandlerType) { - case Mono.Cecil.Cil.ExceptionHandlerType.Catch: - case Mono.Cecil.Cil.ExceptionHandlerType.Filter: + switch (s.ExceptionHandler.Kind) { + case ExceptionRegionKind.Catch: + case ExceptionRegionKind.Filter: output.Write("catch"); - if (s.ExceptionHandler.CatchType != null) { + if (!s.ExceptionHandler.CatchType.IsNil) { output.Write(' '); - s.ExceptionHandler.CatchType.WriteTo(output, ILNameSyntax.TypeName); + s.ExceptionHandler.CatchType.CoerceTypeReference(s.Method.Module).WriteTo(output, new Dom.GenericContext(s.Method), ILNameSyntax.TypeName); } output.WriteLine(); break; - case Mono.Cecil.Cil.ExceptionHandlerType.Finally: + case ExceptionRegionKind.Finally: output.WriteLine("finally"); break; - case Mono.Cecil.Cil.ExceptionHandlerType.Fault: + case ExceptionRegionKind.Fault: output.WriteLine("fault"); break; default: @@ -1218,31 +194,29 @@ namespace ICSharpCode.Decompiler.Disassembler output.Indent(); } - void WriteStructureBody(ILStructure s, HashSet branchTargets, ref Mono.Cecil.Cil.Instruction inst, int codeSize) + void WriteStructureBody(ILStructure s, HashSet branchTargets, ref BlobReader body) { bool isFirstInstructionInStructure = true; bool prevInstructionWasBranch = false; int childIndex = 0; - while (inst != null && inst.Offset < s.EndOffset) { - int offset = inst.Offset; + while (body.RemainingBytes > 0 && body.Offset < s.EndOffset) { + int offset = body.Offset; if (childIndex < s.Children.Count && s.Children[childIndex].StartOffset <= offset && offset < s.Children[childIndex].EndOffset) { ILStructure child = s.Children[childIndex++]; WriteStructureHeader(child); - WriteStructureBody(child, branchTargets, ref inst, codeSize); + WriteStructureBody(child, branchTargets, ref body); WriteStructureFooter(child); } else { if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) { - output.WriteLine(); // put an empty line after branches, and in front of branch targets + output.WriteLine(); // put an empty line after branches, and in front of branch targets } - WriteInstruction(output, inst); - output.WriteLine(); - - prevInstructionWasBranch = inst.OpCode.FlowControl == Mono.Cecil.Cil.FlowControl.Branch - || inst.OpCode.FlowControl == Mono.Cecil.Cil.FlowControl.Cond_Branch - || inst.OpCode.FlowControl == Mono.Cecil.Cil.FlowControl.Return - || inst.OpCode.FlowControl == Mono.Cecil.Cil.FlowControl.Throw; - - inst = inst.Next; + var currentOpCode = ILParser.DecodeOpCode(ref body); + body.Offset = offset; // reset IL stream + WriteInstruction(output, s.Method, ref body); + prevInstructionWasBranch = currentOpCode.IsBranch() + || currentOpCode.IsReturn() + || currentOpCode == ILOpCode.Throw + || currentOpCode == ILOpCode.Rethrow; } isFirstInstructionInStructure = false; } @@ -1269,24 +243,150 @@ namespace ICSharpCode.Decompiler.Disassembler } } - protected virtual void WriteInstruction(ITextOutput output, Mono.Cecil.Cil.Instruction instruction) + protected virtual void WriteInstruction(ITextOutput output, Dom.MethodDefinition method, ref BlobReader blob) { - /*if (ShowSequencePoints && nextSequencePointIndex < sequencePoints?.Count) { - SequencePoint sp = sequencePoints[nextSequencePointIndex]; - if (sp.Offset <= instruction.Offset) { + var metadata = method.Module.GetMetadataReader(); + int offset = blob.Offset; + if (ShowSequencePoints && nextSequencePointIndex < sequencePoints?.Count) { + Dom.SequencePoint sp = sequencePoints[nextSequencePointIndex]; + if (sp.Offset <= offset) { output.Write("// sequence point: "); - if (sp.Offset != instruction.Offset) { + if (sp.Offset != offset) { output.Write("!! at " + DisassemblerHelpers.OffsetToString(sp.Offset) + " !!"); } if (sp.IsHidden) { output.WriteLine("hidden"); } else { - output.WriteLine($"(line {sp.StartLine}, col {sp.StartColumn}) to (line {sp.EndLine}, col {sp.EndColumn}) in {sp.Document?.Url}"); + output.WriteLine($"(line {sp.StartLine}, col {sp.StartColumn}) to (line {sp.EndLine}, col {sp.EndColumn}) in {sp.Document.Url}"); } nextSequencePointIndex++; } - }*/ - instruction.WriteTo(output); + } + ILOpCode opCode = ILParser.DecodeOpCode(ref blob); + output.WriteDefinition(DisassemblerHelpers.OffsetToString(offset), offset); + output.Write(": "); + if (opCode.IsDefined()) { + output.WriteReference(opCode.GetDisplayName(), new OpCodeInfo(opCode, opCode.GetDisplayName())); + switch (opCode.GetOperandType()) { + case OperandType.BrTarget: + case OperandType.ShortBrTarget: + output.Write(' '); + int targetOffset = ILParser.DecodeBranchTarget(ref blob, opCode); + output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); + break; + case OperandType.Field: + case OperandType.Method: + case OperandType.Sig: + case OperandType.Type: + output.Write(' '); + var handle = MetadataTokens.EntityHandle(blob.ReadInt32()); + WriteEntityHandle(handle, method.Module, new Dom.GenericContext(method), output); + break; + case OperandType.Tok: + output.Write(' '); + handle = MetadataTokens.EntityHandle(blob.ReadInt32()); + switch (handle.Kind) { + case HandleKind.MemberReference: + switch (method.Module.GetMetadataReader().GetMemberReference((MemberReferenceHandle)handle).GetKind()) { + case MemberReferenceKind.Method: + output.Write("method "); + break; + case MemberReferenceKind.Field: + output.Write("field "); + break; + } + break; + case HandleKind.FieldDefinition: + output.Write("field "); + break; + } + WriteEntityHandle(handle, method.Module, new Dom.GenericContext(method), output); + break; + case OperandType.ShortI: + output.Write(' '); + DisassemblerHelpers.WriteOperand(output, blob.ReadSByte()); + break; + case OperandType.I: + output.Write(' '); + DisassemblerHelpers.WriteOperand(output, blob.ReadInt32()); + break; + case OperandType.I8: + output.Write(' '); + DisassemblerHelpers.WriteOperand(output, blob.ReadInt64()); + break; + case OperandType.ShortR: + output.Write(' '); + DisassemblerHelpers.WriteOperand(output, blob.ReadSingle()); + break; + case OperandType.R: + output.Write(' '); + DisassemblerHelpers.WriteOperand(output, blob.ReadDouble()); + break; + case OperandType.String: + var userString = metadata.GetUserString(MetadataTokens.UserStringHandle(blob.ReadInt32())); + output.Write(' '); + DisassemblerHelpers.WriteOperand(output, userString); + break; + case OperandType.Switch: + int[] targets = ILParser.DecodeSwitchTargets(ref blob); + output.Write(" ("); + for (int i = 0; i < targets.Length; i++) { + if (i > 0) + output.Write(", "); + output.WriteReference($"IL_{targets[i]:x4}", targets[i], true); + } + output.WriteLine(")"); + break; + case OperandType.Variable: + output.Write(' '); + int index = blob.ReadUInt16(); + if (opCode == ILOpCode.Ldloc || opCode == ILOpCode.Ldloca || opCode == ILOpCode.Stloc) { + DisassemblerHelpers.WriteVariableReference(output, method, index); + } else { + DisassemblerHelpers.WriteParameterReference(output, method, index); + } + break; + case OperandType.ShortVariable: + output.Write(' '); + index = blob.ReadByte(); + if (opCode == ILOpCode.Ldloc_s || opCode == ILOpCode.Ldloca_s || opCode == ILOpCode.Stloc_s) { + DisassemblerHelpers.WriteVariableReference(output, method, index); + } else { + DisassemblerHelpers.WriteParameterReference(output, method, index); + } + break; + } + } else { + output.Write($".emitbyte 0x{opCode:x}"); + } + output.WriteLine(); + } + + void WriteEntityHandle(EntityHandle entity, Dom.PEFile module, Dom.GenericContext context, ITextOutput output) + { + switch (entity.Kind) { + case HandleKind.TypeReference: + new Dom.TypeReference(module, (TypeReferenceHandle)entity).WriteTo(output); + break; + case HandleKind.TypeDefinition: + new Dom.TypeDefinition(module, (TypeDefinitionHandle)entity).WriteTo(output); + break; + case HandleKind.FieldDefinition: + new Dom.FieldDefinition(module, (FieldDefinitionHandle)entity).WriteTo(output); + break; + case HandleKind.MethodDefinition: + new Dom.MethodDefinition(module, (MethodDefinitionHandle)entity).WriteTo(output); + break; + case HandleKind.MemberReference: + new Dom.MemberReference(module, (MemberReferenceHandle)entity).WriteTo(output, context); + break; + case HandleKind.TypeSpecification: + new Dom.TypeSpecification(module, (TypeSpecificationHandle)entity).WriteTo(output, context); + break; + case HandleKind.MethodSpecification: + new Dom.MethodSpecification(module, (MethodSpecificationHandle)entity).WriteTo(output, context); + break; + } } } } diff --git a/ICSharpCode.Decompiler/Disassembler/OpCodeInfo.cs b/ICSharpCode.Decompiler/Disassembler/OpCodeInfo.cs index e57ac3534..50b7624f3 100644 --- a/ICSharpCode.Decompiler/Disassembler/OpCodeInfo.cs +++ b/ICSharpCode.Decompiler/Disassembler/OpCodeInfo.cs @@ -19,22 +19,25 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Text; using System.Threading.Tasks; +using ICSharpCode.Decompiler.IL; namespace ICSharpCode.Decompiler.Disassembler { public struct OpCodeInfo : IEquatable { - public readonly int Code; + public readonly ILOpCode Code; public readonly string Name; string encodedName; - public OpCodeInfo(int code, string name) + public OpCodeInfo(ILOpCode code, string name) { this.Code = code; - this.Name = name; + this.Name = name ?? ""; this.encodedName = null; } @@ -46,6 +49,18 @@ namespace ICSharpCode.Decompiler.Disassembler public static bool operator ==(OpCodeInfo lhs, OpCodeInfo rhs) => lhs.Equals(rhs); public static bool operator !=(OpCodeInfo lhs, OpCodeInfo rhs) => !(lhs == rhs); + public override bool Equals(object obj) + { + if (obj is OpCodeInfo opCode) + return Equals(opCode); + return false; + } + + public override int GetHashCode() + { + return unchecked(982451629 * Code.GetHashCode() + 982451653 * Name.GetHashCode()); + } + public string Link => "http://msdn.microsoft.com/library/system.reflection.emit.opcodes." + EncodedName.ToLowerInvariant() + ".aspx"; public string EncodedName { get { @@ -89,4 +104,98 @@ namespace ICSharpCode.Decompiler.Disassembler } } } + + public static class ILParser + { + public static ILOpCode DecodeOpCode(ref BlobReader blob) + { + byte opCodeByte = blob.ReadByte(); + return (ILOpCode)(opCodeByte == 0xFE ? 0xFE00 + blob.ReadByte() : opCodeByte); + } + + public static void SkipOperand(ref BlobReader blob, ILOpCode opCode) + { + switch (opCode.GetOperandType()) { + // 64-bit + case OperandType.I8: + case OperandType.R: + blob.Offset += 8; + break; + // 32-bit + case OperandType.BrTarget: + case OperandType.Field: + case OperandType.Method: + case OperandType.I: + case OperandType.Sig: + case OperandType.String: + case OperandType.Tok: + case OperandType.Type: + case OperandType.ShortR: + blob.Offset += 4; + break; + // (n + 1) * 32-bit + case OperandType.Switch: + uint n = blob.ReadUInt32(); + blob.Offset += (int)(n * 4); + break; + // 16-bit + case OperandType.Variable: + blob.Offset += 2; + break; + // 8-bit + case OperandType.ShortVariable: + case OperandType.ShortBrTarget: + case OperandType.ShortI: + blob.Offset++; + break; + } + } + + public static int DecodeBranchTarget(ref BlobReader blob, ILOpCode opCode) + { + return (opCode.GetBranchOperandSize() == 4 ? blob.ReadInt32() : blob.ReadSByte()) + blob.Offset; + } + + public static int[] DecodeSwitchTargets(ref BlobReader blob) + { + int[] targets = new int[blob.ReadUInt32()]; + int offset = blob.Offset + 4 * targets.Length; + for (int i = 0; i < targets.Length; i++) + targets[i] = blob.ReadInt32() + offset; + return targets; + } + + public static string DecodeUserString(ref BlobReader blob, Dom.PEFile module) + { + return module.GetMetadataReader().GetUserString(MetadataTokens.UserStringHandle(blob.ReadInt32())); + } + + public static Dom.IMemberReference DecodeMemberToken(ref BlobReader blob, Dom.PEFile module) + { + var handle = MetadataTokens.EntityHandle(blob.ReadInt32()); + switch (handle.Kind) { + case HandleKind.TypeDefinition: + return new Dom.TypeDefinition(module, (TypeDefinitionHandle)handle); + case HandleKind.TypeReference: + return new Dom.TypeReference(module, (TypeReferenceHandle)handle); + case HandleKind.TypeSpecification: + return new Dom.TypeSpecification(module, (TypeSpecificationHandle)handle); + case HandleKind.MethodDefinition: + return new Dom.MethodDefinition(module, (MethodDefinitionHandle)handle); + case HandleKind.MethodSpecification: + return new Dom.MethodSpecification(module, (MethodSpecificationHandle)handle); + case HandleKind.FieldDefinition: + return new Dom.FieldDefinition(module, (FieldDefinitionHandle)handle); + case HandleKind.MemberReference: + return new Dom.MemberReference(module, (MemberReferenceHandle)handle); + default: + throw new NotSupportedException(); + } + } + + public static bool IsReturn(this ILOpCode opCode) + { + return opCode == ILOpCode.Ret || opCode == ILOpCode.Endfilter || opCode == ILOpCode.Endfinally; + } + } } diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index 6156e51f8..97a8e1328 100644 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -19,12 +19,15 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; -using System.Reflection.PortableExecutable; using System.Threading; +using ICSharpCode.Decompiler.Dom; +using ICSharpCode.Decompiler.IL; + namespace ICSharpCode.Decompiler.Disassembler { /// @@ -36,8 +39,6 @@ namespace ICSharpCode.Decompiler.Disassembler CancellationToken cancellationToken; bool isInType; // whether we are currently disassembling a whole type (-> defaultCollapsed for foldings) MethodBodyDisassembler methodBodyDisassembler; - MetadataReader metadata; - PEReader reader; public bool DetectControlStructure { get => methodBodyDisassembler.DetectControlStructure; @@ -49,20 +50,18 @@ namespace ICSharpCode.Decompiler.Disassembler set => methodBodyDisassembler.ShowSequencePoints = value; } - public ReflectionDisassembler(ITextOutput output, PEReader reader, CancellationToken cancellationToken) - : this(output, reader, new MethodBodyDisassembler(output, reader, cancellationToken), cancellationToken) + public ReflectionDisassembler(ITextOutput output, CancellationToken cancellationToken) + : this(output, new MethodBodyDisassembler(output, cancellationToken), cancellationToken) { } - public ReflectionDisassembler(ITextOutput output, PEReader reader, MethodBodyDisassembler methodBodyDisassembler, CancellationToken cancellationToken) + public ReflectionDisassembler(ITextOutput output, MethodBodyDisassembler methodBodyDisassembler, CancellationToken cancellationToken) { if (output == null) throw new ArgumentNullException(nameof(output)); this.output = output; this.cancellationToken = cancellationToken; this.methodBodyDisassembler = methodBodyDisassembler; - this.reader = reader; - this.metadata = reader.GetMetadataReader(); } #region Disassemble Method @@ -116,25 +115,25 @@ namespace ICSharpCode.Decompiler.Disassembler { MethodImplAttributes.ForwardRef, "forwardref" }, }; - public void DisassembleMethod(MethodDefinitionHandle method) + public void DisassembleMethod(Dom.MethodDefinition method) { DisassembleMethodHeader(method); DisassembleMethodBlock(method); } - public void DisassembleMethodHeader(MethodDefinitionHandle method) + public void DisassembleMethodHeader(Dom.MethodDefinition method) { // write method header output.WriteDefinition(".method ", method); DisassembleMethodHeaderInternal(method); } - void DisassembleMethodHeaderInternal(MethodDefinitionHandle handle) + void DisassembleMethodHeaderInternal(Dom.MethodDefinition method) { + var metadata = method.Module.GetMetadataReader(); // .method public hidebysig specialname // instance default class [mscorlib]System.IO.TextWriter get_BaseWriter () cil managed // - var method = metadata.GetMethodDefinition(handle); //emit flags WriteEnum(method.Attributes & MethodAttributes.MemberAccessMask, methodVisibility); WriteFlags(method.Attributes & ~MethodAttributes.MemberAccessMask, methodAttributeFlags); @@ -144,12 +143,12 @@ namespace ICSharpCode.Decompiler.Disassembler if ((method.Attributes & MethodAttributes.PinvokeImpl) == MethodAttributes.PinvokeImpl) { output.Write("pinvokeimpl"); - var info = method.GetImport(); + var info = method.Import; if (!info.Module.IsNil) { var moduleRef = metadata.GetModuleReference(info.Module); output.Write("(\"" + DisassemblerHelpers.EscapeString(metadata.GetString(moduleRef.Name)) + "\""); - if (!info.Name.IsNil && info.Name != method.Name) + if (!info.Name.IsNil && metadata.GetString(info.Name) != method.Name) output.Write(" as \"" + DisassemblerHelpers.EscapeString(metadata.GetString(info.Name)) + "\""); if ((info.Attributes & MethodImportAttributes.ExactSpelling) == MethodImportAttributes.ExactSpelling) @@ -195,9 +194,8 @@ namespace ICSharpCode.Decompiler.Disassembler output.WriteLine(); output.Indent(); - var declaringType = metadata.GetTypeDefinition(method.GetDeclaringType()); - var reader = metadata.GetBlobReader(method.Signature); - var signature = method.DecodeSignature(new MethodSignatureProvider(metadata, output), (declaringType.GetGenericParameters(), method.GetGenericParameters())); + var declaringType = method.DeclaringType; + var signature = method.DecodeSignature(new DisassemblerSignatureProvider(method.Module, output), new GenericContext(method)); if (signature.Header.HasExplicitThis) { output.Write("instance explicit "); } else if (signature.Header.IsInstance) { @@ -211,7 +209,7 @@ namespace ICSharpCode.Decompiler.Disassembler signature.ReturnType(ILNameSyntax.Signature); output.Write(' '); - var parameters = method.GetParameters().ToImmutableArray(); + var parameters = method.Parameters.ToImmutableArray(); if (parameters.Length > 0) { var marshallingDesc = metadata.GetParameter(parameters[0]).GetMarshallingDescriptor(); @@ -221,19 +219,19 @@ namespace ICSharpCode.Decompiler.Disassembler } if (isCompilerControlled) { - output.Write(DisassemblerHelpers.Escape(metadata.GetString(method.Name) + "$PST" + MetadataTokens.GetToken(handle).ToString("X8"))); + output.Write(DisassemblerHelpers.Escape(method.Name + "$PST" + MetadataTokens.GetToken(method.Handle).ToString("X8"))); } else { - output.Write(DisassemblerHelpers.Escape(metadata.GetString(method.Name))); + output.Write(DisassemblerHelpers.Escape(method.Name)); } - WriteTypeParameters(output, method.GetGenericParameters()); + WriteTypeParameters(output, method.Module, new GenericContext(method), method.GenericParameters); //( params ) output.Write(" ("); if (signature.ParameterTypes.Length > 0) { output.WriteLine(); output.Indent(); - WriteParameters(parameters, signature); + WriteParameters(metadata, parameters, signature); output.Unindent(); } output.Write(") "); @@ -248,44 +246,38 @@ namespace ICSharpCode.Decompiler.Disassembler output.Unindent(); } - void DisassembleMethodBlock(MethodDefinitionHandle handle) + void DisassembleMethodBlock(Dom.MethodDefinition method) { - var method = metadata.GetMethodDefinition(handle); OpenBlock(defaultCollapsed: isInType); - WriteAttributes(method.GetCustomAttributes()); - // TODO: implement cache? - for (int row = 1; row <= metadata.GetTableRowCount(TableIndex.MethodImpl); row++) { - var impl = metadata.GetMethodImplementation(MetadataTokens.MethodImplementationHandle(row)); - if (impl.MethodBody != handle) continue; + WriteAttributes(method); + + var metadata = method.Module.GetMetadataReader(); + + foreach (var h in method.GetMethodImplementations()) { + var impl = metadata.GetMethodImplementation(h); output.Write(".override method "); - impl.MethodDeclaration.WriteTo(metadata, output); + var memberRef = impl.MethodDeclaration.CoerceMemberReference(method.Module); + memberRef.WriteTo(output, new GenericContext(method)); output.WriteLine(); } - foreach (var p in method.GetParameters()) { - WriteParameterAttributes(p); + foreach (var p in method.Parameters) { + WriteParameterAttributes(method.Module, p); } - //WriteSecurityDeclarations(method); + WriteSecurityDeclarations(method.Module, method.DeclarativeSecurityAttributes); - bool hasBody = (method.Attributes & MethodAttributes.Abstract) == 0 && - (method.Attributes & MethodAttributes.PinvokeImpl) == 0 && - (method.ImplAttributes & MethodImplAttributes.InternalCall) == 0 && - (method.ImplAttributes & MethodImplAttributes.Native) == 0 && - (method.ImplAttributes & MethodImplAttributes.Unmanaged) == 0 && - (method.ImplAttributes & MethodImplAttributes.Runtime) == 0; - - if (hasBody) { - methodBodyDisassembler.Disassemble(handle); + if (method.HasBody) { + methodBodyDisassembler.Disassemble(method); } - var td = metadata.GetTypeDefinition(method.GetDeclaringType()); - CloseBlock("end of method " + DisassemblerHelpers.Escape(metadata.GetString(td.Name)) + "::" + DisassemblerHelpers.Escape(metadata.GetString(method.Name))); + CloseBlock("end of method " + DisassemblerHelpers.Escape(method.DeclaringType.Name) + "::" + DisassemblerHelpers.Escape(method.Name)); } #region Write Security Declarations - void WriteSecurityDeclarations(DeclarativeSecurityAttributeHandleCollection secDeclProvider) + void WriteSecurityDeclarations(PEFile module, DeclarativeSecurityAttributeHandleCollection secDeclProvider) { if (secDeclProvider.Count == 0) - return;/* + return; + var metadata = module.GetMetadataReader(); foreach (var h in secDeclProvider) { output.Write(".permissionset "); var secdecl = metadata.GetDeclarativeSecurityAttribute(h); @@ -341,29 +333,27 @@ namespace ICSharpCode.Decompiler.Disassembler } output.WriteLine(" = {"); output.Indent(); - - for (int i = 0; i < secdecl.SecurityAttributes.Count; i++) { - SecurityAttribute sa = secdecl.SecurityAttributes[i]; - if (sa.AttributeType.Scope == sa.AttributeType.Module) { + var blob = metadata.GetBlobReader(secdecl.PermissionSet); + if ((char)blob.ReadByte() != '.') throw new InvalidOperationException("sanity check!"); + int count = blob.ReadCompressedInteger(); + for (int i = 0; i < count; i++) { + var typeName = blob.ReadSerializedString(); + if (secdecl.Parent == EntityHandle.AssemblyDefinition) { output.Write("class "); - output.Write(DisassemblerHelpers.Escape(GetAssemblyQualifiedName(sa.AttributeType))); + output.Write(DisassemblerHelpers.Escape(typeName)); } else { - sa.AttributeType.WriteTo(output, ILNameSyntax.TypeName); + throw new NotImplementedException(); + //sa.AttributeType.WriteTo(output, ILNameSyntax.TypeName); } output.Write(" = {"); - if (sa.HasFields || sa.HasProperties) { + blob.ReadByte(); + int argCount = blob.ReadByte(); + if (argCount > 0) { output.WriteLine(); output.Indent(); - foreach (CustomAttributeNamedArgument na in sa.Fields) { - output.Write("field "); - WriteSecurityDeclarationArgument(na); - output.WriteLine(); - } - - foreach (CustomAttributeNamedArgument na in sa.Properties) { - output.Write("property "); - WriteSecurityDeclarationArgument(na); + for (int j = 0; j < argCount; j++) { + WriteSecurityDeclarationArgument(ref blob); output.WriteLine(); } @@ -371,55 +361,52 @@ namespace ICSharpCode.Decompiler.Disassembler } output.Write('}'); - if (i + 1 < secdecl.SecurityAttributes.Count) + if (i + 1 < count) output.Write(','); output.WriteLine(); } output.Unindent(); output.WriteLine("}"); - }*/ + } } - /* - void WriteSecurityDeclarationArgument(CustomAttributeNamedArgument na) + + void WriteSecurityDeclarationArgument(ref BlobReader blob) { - TypeReference type = na.Argument.Type; - if (type.MetadataType == MetadataType.Class || type.MetadataType == MetadataType.ValueType) { - output.Write("enum "); - if (type.Scope != type.Module) { - output.Write("class "); - output.Write(DisassemblerHelpers.Escape(GetAssemblyQualifiedName(type))); - } else { - type.WriteTo(output, ILNameSyntax.TypeName); - } + var decoder = new BlobDecoder(blob); + var namedArg = decoder.ReadNamedArg(); + switch (blob.ReadByte()) { + case 0x53: + output.Write("field "); + break; + case 0x54: + output.Write("property "); + break; + } + blob.Offset = decoder.Offset; + var value = namedArg.Value.ConstantValue; + string typeName = DisassemblerHelpers.PrimitiveTypeName(value.GetType().FullName); + if (typeName != null) { + output.Write(typeName); } else { - type.WriteTo(output); + namedArg.Value.Type.WriteTo(output); } output.Write(' '); - output.Write(DisassemblerHelpers.Escape(na.Name)); + output.Write(DisassemblerHelpers.Escape(namedArg.Key)); output.Write(" = "); - if (na.Argument.Value is string) { + if (value is string) { // secdecls use special syntax for strings - output.Write("string('{0}')", DisassemblerHelpers.EscapeString((string)na.Argument.Value).Replace("'", "\'")); + output.Write("string('{0}')", DisassemblerHelpers.EscapeString((string)value).Replace("'", "\'")); } else { - WriteConstant(na.Argument.Value); - } - } - - string GetAssemblyQualifiedName(TypeReference type) - { - AssemblyNameReference anr = type.Scope as AssemblyNameReference; - if (anr == null) { - ModuleDefinition md = type.Scope as ModuleDefinition; - if (md != null) { - anr = md.Assembly.Name; + if (typeName != null) { + output.Write(typeName); + } else { + namedArg.Value.Type.WriteTo(output); } + output.Write('('); + DisassemblerHelpers.WriteOperand(output, value); + output.Write(')'); } - if (anr != null) { - return type.FullName + ", " + anr.FullName; - } else { - return type.FullName; - } - }*/ + } #endregion #region WriteMarshalInfo @@ -642,7 +629,7 @@ namespace ICSharpCode.Decompiler.Disassembler } #endregion - void WriteParameters(ImmutableArray parameters, MethodSignature> signature) + void WriteParameters(MetadataReader metadata, ImmutableArray parameters, MethodSignature> signature) { int parameterOffset = parameters.Length > signature.ParameterTypes.Length ? 1 : 0; for (int i = 0; i < signature.ParameterTypes.Length; i++) { @@ -666,21 +653,22 @@ namespace ICSharpCode.Decompiler.Disassembler } } - void WriteParameterAttributes(ParameterHandle handle) + void WriteParameterAttributes(PEFile module, ParameterHandle handle) { + var metadata = module.GetMetadataReader(); var p = metadata.GetParameter(handle); if (p.GetDefaultValue().IsNil && p.GetCustomAttributes().Count == 0) return; output.Write(".param [{0}]", p.SequenceNumber); if (!p.GetDefaultValue().IsNil) { output.Write(" = "); - WriteConstant(metadata.GetConstant(p.GetDefaultValue())); + WriteConstant(metadata, metadata.GetConstant(p.GetDefaultValue())); } output.WriteLine(); - WriteAttributes(p.GetCustomAttributes()); + WriteAttributes(module, p.GetCustomAttributes()); } - void WriteConstant(Constant constant) + void WriteConstant(MetadataReader metadata, Constant constant) { var blob = metadata.GetBlobReader(constant.Value); switch (constant.TypeCode) { @@ -730,11 +718,11 @@ namespace ICSharpCode.Decompiler.Disassembler { FieldAttributes.NotSerialized, "notserialized" }, }; - public void DisassembleField(FieldDefinitionHandle handle) + public void DisassembleField(Dom.FieldDefinition field) { - var field = metadata.GetFieldDefinition(handle); + var metadata = field.Module.GetMetadataReader(); output.WriteDefinition(".field ", field); - int offset = field.GetOffset(); + int offset = field.Offset; if (offset > -1) { output.Write("[" + offset + "] "); } @@ -742,27 +730,25 @@ namespace ICSharpCode.Decompiler.Disassembler const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA; WriteFlags(field.Attributes & ~(FieldAttributes.FieldAccessMask | hasXAttributes), fieldAttributes); - var declaringType = metadata.GetTypeDefinition(field.GetDeclaringType()); - var reader = metadata.GetBlobReader(field.Signature); - var signature = field.DecodeSignature(new MethodSignatureProvider(metadata, output), (declaringType.GetGenericParameters(), default(GenericParameterHandleCollection))); + var signature = field.DecodeSignature(new DisassemblerSignatureProvider(field.Module, output), new GenericContext(field.DeclaringType)); if (!field.GetMarshallingDescriptor().IsNil) { WriteMarshalInfo(metadata.GetBlobReader(field.GetMarshallingDescriptor())); } signature(ILNameSyntax.Signature); output.Write(' '); - output.Write(DisassemblerHelpers.Escape(metadata.GetString(field.Name))); - if ((field.Attributes & FieldAttributes.HasFieldRVA) == FieldAttributes.HasFieldRVA) { - output.Write(" at I_{0:x8}", field.GetRelativeVirtualAddress()); + output.Write(DisassemblerHelpers.Escape(field.Name)); + if (field.HasFlag(FieldAttributes.HasFieldRVA)) { + output.Write(" at I_{0:x8}", field.RVA); } if (!field.GetDefaultValue().IsNil) { output.Write(" = "); - WriteConstant(metadata.GetConstant(field.GetDefaultValue())); + WriteConstant(metadata, metadata.GetConstant(field.GetDefaultValue())); } output.WriteLine(); - if (field.GetCustomAttributes().Count > 0) { + if (field.CustomAttributes.Count > 0) { output.MarkFoldStart(); - WriteAttributes(field.GetCustomAttributes()); + WriteAttributes(field); output.MarkFoldEnd(); } } @@ -775,47 +761,46 @@ namespace ICSharpCode.Decompiler.Disassembler { PropertyAttributes.HasDefault, "hasdefault" }, }; - public void DisassembleProperty(PropertyDefinitionHandle handle) + public void DisassembleProperty(Dom.PropertyDefinition property) { - var property = metadata.GetPropertyDefinition(handle); + var metadata = property.Module.GetMetadataReader(); output.WriteDefinition(".property ", property); WriteFlags(property.Attributes, propertyAttributes); - var declaringType = metadata.GetTypeDefinition(FindDeclaringTypeForProperty(handle)); - var reader = metadata.GetBlobReader(property.Signature); - var signature = property.DecodeSignature(new MethodSignatureProvider(metadata, output), (declaringType.GetGenericParameters(), default(GenericParameterHandleCollection))); + var declaringType = property.DeclaringType; + var signature = property.DecodeSignature(new DisassemblerSignatureProvider(property.Module, output), new GenericContext(declaringType)); if (signature.Header.IsInstance) output.Write("instance "); signature.ReturnType(ILNameSyntax.Signature); output.Write(' '); - output.Write(DisassemblerHelpers.Escape(metadata.GetString(property.Name))); + output.Write(DisassemblerHelpers.Escape(property.Name)); output.Write("("); - var parameters = metadata.GetMethodDefinition(property.GetAccessors().Getter).GetParameters(); + var parameters = property.GetAccessors().First().Method.Parameters; if (parameters.Count > 0) { output.WriteLine(); output.Indent(); - WriteParameters(parameters.ToImmutableArray(), signature); + WriteParameters(metadata, parameters.ToImmutableArray(), signature); output.Unindent(); } output.Write(")"); OpenBlock(false); - WriteAttributes(property.GetCustomAttributes()); - WriteNestedMethod(".get", property.GetAccessors().Getter); - WriteNestedMethod(".set", property.GetAccessors().Setter); + WriteAttributes(property); + WriteNestedMethod(".get", property.GetMethod); + WriteNestedMethod(".set", property.SetMethod); CloseBlock(); } - void WriteNestedMethod(string keyword, MethodDefinitionHandle handle) + void WriteNestedMethod(string keyword, Dom.MethodDefinition method) { - if (handle.IsNil) + if (method.IsNil) return; output.Write(keyword); output.Write(' '); - handle.WriteTo(metadata, output); + method.WriteTo(output); output.WriteLine(); } #endregion @@ -826,22 +811,23 @@ namespace ICSharpCode.Decompiler.Disassembler { EventAttributes.RTSpecialName, "rtspecialname" }, }; - public void DisassembleEvent(EventDefinitionHandle handle) + public void DisassembleEvent(Dom.EventDefinition ev) { - var ev = metadata.GetEventDefinition(handle); + var metadata = ev.Module.GetMetadataReader(); output.WriteDefinition(".event ", ev); WriteFlags(ev.Attributes, eventAttributes); - ev.Type.WriteTo(metadata, output, ILNameSyntax.TypeName); + var signature = ev.DecodeSignature(new DisassemblerSignatureProvider(ev.Module, output), new GenericContext(ev.DeclaringType)); + signature(ILNameSyntax.TypeName); output.Write(' '); - output.Write(DisassemblerHelpers.Escape(metadata.GetString(ev.Name))); + output.Write(DisassemblerHelpers.Escape(ev.Name)); OpenBlock(false); - WriteAttributes(ev.GetCustomAttributes()); - WriteNestedMethod(".addon", ev.GetAccessors().Adder); - WriteNestedMethod(".removeon", ev.GetAccessors().Remover); - WriteNestedMethod(".fire", ev.GetAccessors().Raiser); - /*foreach (var method in ev.OtherMethods) { + WriteAttributes(ev); + WriteNestedMethod(".addon", ev.AddMethod); + WriteNestedMethod(".removeon", ev.RemoveMethod); + WriteNestedMethod(".fire", ev.InvokeMethod); + foreach (var method in ev.OtherMethods) { WriteNestedMethod(".other", method); - }*/ + } CloseBlock(); } #endregion @@ -881,9 +867,9 @@ namespace ICSharpCode.Decompiler.Disassembler { TypeAttributes.HasSecurity, null }, }; - public void DisassembleType(TypeDefinitionHandle handle) + public void DisassembleType(Dom.TypeDefinition type) { - var type = metadata.GetTypeDefinition(handle); + var metadata = type.Module.GetMetadataReader(); output.WriteDefinition(".class ", type); if ((type.Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface) @@ -894,16 +880,15 @@ namespace ICSharpCode.Decompiler.Disassembler const TypeAttributes masks = TypeAttributes.ClassSemanticsMask | TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.StringFormatMask; WriteFlags(type.Attributes & ~masks, typeAttributes); - string typeName = !type.GetDeclaringType().IsNil ? metadata.GetString(type.Name) : metadata.GetString(type.Namespace) + "." + metadata.GetString(type.Name); - output.Write(DisassemblerHelpers.Escape(typeName)); - WriteTypeParameters(output, type.GetGenericParameters()); + output.Write(type.DeclaringType.IsNil ? type.FullName.ToILNameString() : DisassemblerHelpers.Escape(type.Name)); + WriteTypeParameters(output, type.Module, new GenericContext(type), type.GenericParameters); output.MarkFoldStart(defaultCollapsed: isInType); output.WriteLine(); if (type.BaseType != null) { output.Indent(); output.Write("extends "); - type.BaseType.WriteTo(metadata, output, ILNameSyntax.TypeName); + type.BaseType.WriteTo(output, new GenericContext(type), ILNameSyntax.TypeName); output.WriteLine(); output.Unindent(); } @@ -920,8 +905,9 @@ namespace ICSharpCode.Decompiler.Disassembler output.Write(" "); first = false; var iface = metadata.GetInterfaceImplementation(i); - WriteAttributes(iface.GetCustomAttributes()); - iface.Interface.WriteTo(metadata, output, ILNameSyntax.TypeName); + WriteAttributes(type.Module, iface.GetCustomAttributes()); + var ifaceRef = iface.Interface.CoerceTypeReference(type.Module); + ifaceRef.WriteTo(output, new GenericContext(type), ILNameSyntax.TypeName); } output.WriteLine(); output.Unindent(); @@ -931,64 +917,65 @@ namespace ICSharpCode.Decompiler.Disassembler output.Indent(); bool oldIsInType = isInType; isInType = true; - WriteAttributes(type.GetCustomAttributes()); - //WriteSecurityDeclarations(type); + WriteAttributes(type); + WriteSecurityDeclarations(type.Module, type.DeclarativeSecurityAttributes); var layout = type.GetLayout(); if (!layout.IsDefault) { output.WriteLine(".pack {0}", layout.PackingSize); output.WriteLine(".size {0}", layout.Size); output.WriteLine(); } - if (!type.GetNestedTypes().IsEmpty) { + if (!type.NestedTypes.IsEmpty) { output.WriteLine("// Nested Types"); - foreach (var nestedType in type.GetNestedTypes()) { + foreach (var nestedType in type.NestedTypes) { cancellationToken.ThrowIfCancellationRequested(); DisassembleType(nestedType); output.WriteLine(); } output.WriteLine(); } - if (type.GetFields().Count > 0) { + if (!type.Fields.IsEmpty) { output.WriteLine("// Fields"); - foreach (var field in type.GetFields()) { + foreach (var field in type.Fields) { cancellationToken.ThrowIfCancellationRequested(); DisassembleField(field); } output.WriteLine(); } - if (type.GetMethods().Count > 0) { + if (!type.Methods.IsEmpty) { output.WriteLine("// Methods"); - foreach (var m in type.GetMethods()) { + foreach (var m in type.Methods) { cancellationToken.ThrowIfCancellationRequested(); DisassembleMethod(m); output.WriteLine(); } } - if (type.GetEvents().Count > 0) { + if (!type.Events.IsEmpty) { output.WriteLine("// Events"); - foreach (var ev in type.GetEvents()) { + foreach (var ev in type.Events) { cancellationToken.ThrowIfCancellationRequested(); DisassembleEvent(ev); output.WriteLine(); } output.WriteLine(); } - if (type.GetProperties().Count > 0) { + if (!type.Properties.IsEmpty) { output.WriteLine("// Properties"); - foreach (var prop in type.GetProperties()) { + foreach (var prop in type.Properties) { cancellationToken.ThrowIfCancellationRequested(); DisassembleProperty(prop); } output.WriteLine(); } - CloseBlock("end of class " + typeName); + CloseBlock("end of class " + (!type.DeclaringType.IsNil ? type.Name : type.FullName.ToString())); isInType = oldIsInType; } - void WriteTypeParameters(ITextOutput output, GenericParameterHandleCollection p) + void WriteTypeParameters(ITextOutput output, PEFile module, GenericContext context, GenericParameterHandleCollection p) { if (p.Count > 0) { output.Write('<'); + var metadata = module.GetMetadataReader(); for (int i = 0; i < p.Count; i++) { if (i > 0) output.Write(", "); @@ -1008,7 +995,7 @@ namespace ICSharpCode.Decompiler.Disassembler if (j > 0) output.Write(", "); var constraint = metadata.GetGenericParameterConstraint(constraints[j]); - constraint.Type.WriteTo(metadata, output, ILNameSyntax.TypeName); + constraint.Type.CoerceTypeReference(module).WriteTo(output, context, ILNameSyntax.TypeName); } output.Write(") "); } @@ -1025,12 +1012,18 @@ namespace ICSharpCode.Decompiler.Disassembler #endregion #region Helper methods - void WriteAttributes(CustomAttributeHandleCollection attributes) + void WriteAttributes(Dom.ICustomAttributeProvider attributes) { + WriteAttributes(attributes.Module, attributes.CustomAttributes); + } + + void WriteAttributes(PEFile module, CustomAttributeHandleCollection attributes) + { + var metadata = module.GetMetadataReader(); foreach (CustomAttributeHandle a in attributes) { output.Write(".custom "); var attr = metadata.GetCustomAttribute(a); - attr.Constructor.WriteTo(metadata, output); + attr.Constructor.CoerceMemberReference(module).WriteTo(output, GenericContext.Empty); byte[] blob = metadata.GetBlobBytes(attr.Value); if (blob.Length > 0) { output.Write(" = "); @@ -1132,7 +1125,7 @@ namespace ICSharpCode.Decompiler.Disassembler } #endregion - public void DisassembleNamespace(string nameSpace, IEnumerable types) + public void DisassembleNamespace(string nameSpace, IEnumerable types) { if (!string.IsNullOrEmpty(nameSpace)) { output.Write(".namespace " + DisassemblerHelpers.Escape(nameSpace)); @@ -1140,7 +1133,7 @@ namespace ICSharpCode.Decompiler.Disassembler } bool oldIsInType = isInType; isInType = true; - foreach (TypeDefinitionHandle td in types) { + foreach (var td in types) { cancellationToken.ThrowIfCancellationRequested(); DisassembleType(td); output.WriteLine(); @@ -1151,16 +1144,18 @@ namespace ICSharpCode.Decompiler.Disassembler } } - public void WriteAssemblyHeader() + public void WriteAssemblyHeader(PEFile module) { - var asm = metadata.GetAssemblyDefinition(); + var metadata = module.GetMetadataReader(); + if (!metadata.IsAssembly) return; output.Write(".assembly "); + var asm = metadata.GetAssemblyDefinition(); if ((asm.Flags & AssemblyFlags.WindowsRuntime) == AssemblyFlags.WindowsRuntime) output.Write("windowsruntime "); output.Write(DisassemblerHelpers.Escape(metadata.GetString(asm.Name))); OpenBlock(false); - WriteAttributes(asm.GetCustomAttributes()); - //WriteSecurityDeclarations(asm); + WriteAttributes(module, asm.GetCustomAttributes()); + WriteSecurityDeclarations(module, asm.GetDeclarativeSecurityAttributes()); var publicKey = metadata.GetBlobBytes(asm.PublicKey); if (publicKey.Length > 0) { output.Write(".publickey = "); @@ -1180,14 +1175,15 @@ namespace ICSharpCode.Decompiler.Disassembler CloseBlock(); } - public void WriteAssemblyReferences() + public void WriteAssemblyReferences(PEFile module) { - for (int row = 0; row < metadata.GetTableRowCount(TableIndex.ModuleRef); row++) { - var mref = metadata.GetModuleReference(MetadataTokens.ModuleReferenceHandle(row)); + var metadata = module.GetMetadataReader(); + foreach (var m in module.ModuleReferences) { + var mref = metadata.GetModuleReference(m); output.WriteLine(".module extern {0}", DisassemblerHelpers.Escape(metadata.GetString(mref.Name))); } - foreach (var a in metadata.AssemblyReferences) { - var aref = metadata.GetAssemblyReference(a); + foreach (var a in module.AssemblyReferences) { + var aref = metadata.GetAssemblyReference(a.Handle); output.Write(".assembly extern "); if ((aref.Flags & AssemblyFlags.WindowsRuntime) == AssemblyFlags.WindowsRuntime) output.Write("windowsruntime "); @@ -1205,9 +1201,9 @@ namespace ICSharpCode.Decompiler.Disassembler } } - public void WriteModuleHeader() + public void WriteModuleHeader(PEFile module) { - var module = metadata.GetModuleDefinition(); + var metadata = module.GetMetadataReader(); foreach (var et in metadata.ExportedTypes) { var exportedType = metadata.GetExportedType(et); output.Write(".class extern "); @@ -1222,252 +1218,36 @@ namespace ICSharpCode.Decompiler.Disassembler output.WriteLine(".assembly extern {0}", DisassemblerHelpers.Escape(exportedType.Scope.Name)); CloseBlock();*/ } + var moduleDefinition = metadata.GetModuleDefinition(); - output.WriteLine(".module {0}", metadata.GetString(module.Name)); - output.WriteLine("// MVID: {0}", metadata.GetGuid(module.Mvid).ToString("B").ToUpperInvariant()); + output.WriteLine(".module {0}", metadata.GetString(moduleDefinition.Name)); + output.WriteLine("// MVID: {0}", metadata.GetGuid(moduleDefinition.Mvid).ToString("B").ToUpperInvariant()); // TODO: imagebase, file alignment, stackreserve, subsystem //output.WriteLine(".corflags 0x{0:x} // {1}", module., module.Attributes.ToString()); - //WriteAttributes(metadata.GetCustomAttributes(metadata.getmod)); + WriteAttributes(module, metadata.GetCustomAttributes(EntityHandle.ModuleDefinition)); } - public void WriteModuleContents(ModuleDefinition module) + public void WriteModuleContents(PEFile module) { - foreach (var handle in metadata.TypeDefinitions) { + foreach (var handle in module.TypeDefinitions) { DisassembleType(handle); output.WriteLine(); } } - - unsafe TypeDefinitionHandle FindDeclaringTypeForProperty(PropertyDefinitionHandle handle) - { - byte* startPointer = metadata.MetadataPointer; - int offset = metadata.GetTableMetadataOffset(TableIndex.PropertyMap); - int rowSize = metadata.GetTableRowSize(TableIndex.PropertyMap); - int rowCount = metadata.GetTableRowCount(TableIndex.PropertyMap); - int token = metadata.GetToken(handle); - for (int row = rowCount - 1; row >= 0; row--) { - byte* ptr = startPointer + offset + rowSize * row; - ushort parentToken = *ptr; - ushort list = *(ptr + 2); - if (token > list) - return MetadataTokens.TypeDefinitionHandle(parentToken); - } - return default(TypeDefinitionHandle); - } - } - - public static class MetadataReaderExtensions - { - public static void WriteTo(this EntityHandle handle, MetadataReader metadata, ITextOutput output, ILNameSyntax syntax = ILNameSyntax.Signature) - { - if (handle.IsNil) return; - switch (handle.Kind) { - case HandleKind.TypeReference: - ((TypeReferenceHandle)handle).WriteTo(metadata, output, syntax); - break; - case HandleKind.TypeDefinition: - ((TypeDefinitionHandle)handle).WriteTo(metadata, output); - break; - case HandleKind.TypeSpecification: - ((TypeSpecificationHandle)handle).WriteTo(metadata, output); - break; - case HandleKind.AssemblyReference: - var ar = metadata.GetAssemblyReference((AssemblyReferenceHandle)handle); - output.Write(metadata.GetString(ar.Name)); - break; - case HandleKind.MethodDefinition: - ((MethodDefinitionHandle)handle).WriteTo(metadata, output); - break; - case HandleKind.MemberReference: - ((MemberReferenceHandle)handle).WriteTo(metadata, output); - break; - case HandleKind.MethodSpecification: - ((MethodSpecificationHandle)handle).WriteTo(metadata, output); - break; - case HandleKind.FieldDefinition: - ((FieldDefinitionHandle)handle).WriteTo(metadata, output); - break; - default: - throw new NotImplementedException(handle.Kind.ToString()); - } - } - - public static void WriteTo(this TypeSpecificationHandle handle, MetadataReader metadata, ITextOutput output, ILNameSyntax syntax = ILNameSyntax.Signature) - { - var ts = metadata.GetTypeSpecification(handle); - var signature = ts.DecodeSignature(new MethodSignatureProvider(metadata, output), (default(GenericParameterHandleCollection), default(GenericParameterHandleCollection))); - signature(syntax); - } - - public static void WriteTo(this FieldDefinitionHandle handle, MetadataReader metadata, ITextOutput output, ILNameSyntax syntax = ILNameSyntax.Signature) - { - var fd = metadata.GetFieldDefinition(handle); - var signature = fd.DecodeSignature(new MethodSignatureProvider(metadata, output), (default(GenericParameterHandleCollection), default(GenericParameterHandleCollection))); - var name = metadata.GetString(fd.Name); - signature(syntax); - output.Write(' '); - fd.GetDeclaringType().WriteTo(metadata, output); - output.Write("::"); - output.Write(DisassemblerHelpers.Escape(name)); - } - - public static void WriteTo(this MethodSpecificationHandle handle, MetadataReader metadata, ITextOutput output, ILNameSyntax syntax = ILNameSyntax.Signature) - { - var ms = metadata.GetMethodSpecification(handle); - var signature = ms.DecodeSignature(new MethodSignatureProvider(metadata, output), (default(GenericParameterHandleCollection), default(GenericParameterHandleCollection))); - ms.Method.WriteTo(metadata, output); - } - - public static void WriteTo(this MemberReferenceHandle handle, MetadataReader metadata, ITextOutput output, ILNameSyntax syntax = ILNameSyntax.Signature) - { - var mr = metadata.GetMemberReference(handle); - switch (mr.GetKind()) { - case MemberReferenceKind.Method: - var signature = mr.DecodeMethodSignature(new MethodSignatureProvider(metadata, output), (default(GenericParameterHandleCollection), default(GenericParameterHandleCollection))); - if (signature.Header.HasExplicitThis) { - output.Write("instance explicit "); - } else if (signature.Header.IsInstance) { - output.Write("instance "); - } - if (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs) { - output.Write("vararg "); - } - signature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters); - output.Write(' '); - mr.Parent.WriteTo(metadata, output, syntax); - output.Write("::"); - output.Write(DisassemblerHelpers.Escape(metadata.GetString(mr.Name))); - output.Write("("); - for (int i = 0; i < signature.ParameterTypes.Length; ++i) { - if (i > 0) - output.Write(", "); - signature.ParameterTypes[i](ILNameSyntax.SignatureNoNamedTypeParameters); - } - output.Write(")"); - break; - case MemberReferenceKind.Field: - var fieldSignature = mr.DecodeFieldSignature(new MethodSignatureProvider(metadata, output), (default(GenericParameterHandleCollection), default(GenericParameterHandleCollection))); - fieldSignature(ILNameSyntax.TypeName); - output.Write(' '); - mr.Parent.WriteTo(metadata, output, syntax); - output.Write("::"); - output.Write(DisassemblerHelpers.Escape(metadata.GetString(mr.Name))); - break; - } - } - - public static void WriteTo(this TypeReferenceHandle handle, MetadataReader metadata, ITextOutput output, ILNameSyntax syntax = ILNameSyntax.Signature) - { - var tr = metadata.GetTypeReference(handle); - output.Write("["); - tr.ResolutionScope.WriteTo(metadata, output); - output.Write("]"); - string fullName = ""; - if (!tr.Namespace.IsNil) - fullName += DisassemblerHelpers.Escape(metadata.GetString(tr.Namespace)) + "."; - fullName += DisassemblerHelpers.Escape(metadata.GetString(tr.Name)); - output.WriteReference(fullName, tr); - } - - public static void WriteTo(this TypeDefinitionHandle handle, MetadataReader metadata, ITextOutput output, ILNameSyntax syntax = ILNameSyntax.Signature) - { - var td = metadata.GetTypeDefinition(handle); - output.WriteReference(GetFullName(td, metadata), td); - } - - static string GetFullName(TypeDefinition td, MetadataReader metadata) - { - var declaringType = td.GetDeclaringType(); - string fullName = ""; - if (!td.Namespace.IsNil) - fullName += DisassemblerHelpers.Escape(metadata.GetString(td.Namespace)) + "."; - if (!declaringType.IsNil) - fullName += GetFullName(metadata.GetTypeDefinition(declaringType), metadata) + "/"; - fullName += DisassemblerHelpers.Escape(metadata.GetString(td.Name)); - return fullName; - } - - public static void WriteTo(this MethodDefinitionHandle handle, MetadataReader metadata, ITextOutput output) - { - var method = metadata.GetMethodDefinition(handle); - bool isCompilerControlled = (method.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.PrivateScope; - var declaringType = metadata.GetTypeDefinition(method.GetDeclaringType()); - var reader = metadata.GetBlobReader(method.Signature); - var signature = method.DecodeSignature(new MethodSignatureProvider(metadata, output), (declaringType.GetGenericParameters(), method.GetGenericParameters())); - if (signature.Header.HasExplicitThis) { - output.Write("instance explicit "); - } else if (signature.Header.IsInstance) { - output.Write("instance "); - } - if (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs) { - output.Write("vararg "); - } - signature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters); - output.Write(' '); - if (!method.GetDeclaringType().IsNil) { - method.GetDeclaringType().WriteTo(metadata, output, ILNameSyntax.TypeName); - output.Write("::"); - } - if (isCompilerControlled) { - output.Write(DisassemblerHelpers.Escape(metadata.GetString(method.Name) + "$PST" + MetadataTokens.GetToken(handle).ToString("X8"))); - } else { - output.Write(DisassemblerHelpers.Escape(metadata.GetString(method.Name))); - } - var genericParameters = method.GetGenericParameters(); - if (genericParameters.Count > 0) { - output.Write('<'); - for (int i = 0; i < genericParameters.Count; i++) { - if (i > 0) - output.Write(", "); - var gp = metadata.GetGenericParameter(genericParameters[i]); - if ((gp.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == GenericParameterAttributes.ReferenceTypeConstraint) { - output.Write("class "); - } else if ((gp.Attributes & GenericParameterAttributes.NotNullableValueTypeConstraint) == GenericParameterAttributes.NotNullableValueTypeConstraint) { - output.Write("valuetype "); - } - if ((gp.Attributes & GenericParameterAttributes.DefaultConstructorConstraint) == GenericParameterAttributes.DefaultConstructorConstraint) { - output.Write(".ctor "); - } - var constraints = gp.GetConstraints(); - if (constraints.Count > 0) { - output.Write('('); - for (int j = 0; j < constraints.Count; j++) { - if (j > 0) - output.Write(", "); - var constraint = metadata.GetGenericParameterConstraint(constraints[j]); - constraint.Type.WriteTo(metadata, output, ILNameSyntax.TypeName); - } - output.Write(") "); - } - if ((gp.Attributes & GenericParameterAttributes.Contravariant) == GenericParameterAttributes.Contravariant) { - output.Write('-'); - } else if ((gp.Attributes & GenericParameterAttributes.Covariant) == GenericParameterAttributes.Covariant) { - output.Write('+'); - } - output.Write(DisassemblerHelpers.Escape(metadata.GetString(gp.Name))); - } - output.Write('>'); - } - output.Write("("); - for (int i = 0; i < signature.ParameterTypes.Length; ++i) { - if (i > 0) - output.Write(", "); - signature.ParameterTypes[i](ILNameSyntax.SignatureNoNamedTypeParameters); - } - output.Write(")"); - } } - class MethodSignatureProvider : ISignatureTypeProvider, (GenericParameterHandleCollection TypeParameters, GenericParameterHandleCollection MethodTypeParameters)> + class DisassemblerSignatureProvider : ISignatureTypeProvider, GenericContext> { + readonly PEFile module; readonly MetadataReader metadata; readonly ITextOutput output; - public MethodSignatureProvider(MetadataReader metadata, ITextOutput output) + public DisassemblerSignatureProvider(PEFile module, ITextOutput output) { - this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); + this.module = module ?? throw new ArgumentNullException(nameof(module)); this.output = output ?? throw new ArgumentNullException(nameof(output)); + this.metadata = module.GetMetadataReader(); } public Action GetArrayType(Action elementType, ArrayShape shape) @@ -1533,21 +1313,19 @@ namespace ICSharpCode.Decompiler.Disassembler }; } - public Action GetGenericMethodParameter((GenericParameterHandleCollection TypeParameters, GenericParameterHandleCollection MethodTypeParameters) genericContext, int index) + public Action GetGenericMethodParameter(GenericContext genericContext, int index) { return syntax => { output.Write("!!"); - var param = genericContext.MethodTypeParameters.Count > index ? genericContext.MethodTypeParameters[index] : MetadataTokens.GenericParameterHandle(0); - WriteTypeParameter(param, index, syntax); + WriteTypeParameter(genericContext.GetGenericMethodTypeParameterHandleOrNull(index), index, syntax); }; } - public Action GetGenericTypeParameter((GenericParameterHandleCollection TypeParameters, GenericParameterHandleCollection MethodTypeParameters) genericContext, int index) + public Action GetGenericTypeParameter(GenericContext genericContext, int index) { return syntax => { output.Write("!"); - var param = genericContext.TypeParameters.Count > index ? genericContext.TypeParameters[index] : MetadataTokens.GenericParameterHandle(0); - WriteTypeParameter(param, index, syntax); + WriteTypeParameter(genericContext.GetGenericTypeParameterHandleOrNull(index), index, syntax); }; } @@ -1650,11 +1428,19 @@ namespace ICSharpCode.Decompiler.Disassembler { return syntax => { switch (rawTypeKind) { + case 0x00: + break; case 0x11: output.Write("valuetype "); break; + case 0x12: + output.Write("class "); + break; + default: + throw new NotSupportedException($"rawTypeKind: {rawTypeKind} (0x{rawTypeKind:x})"); } - handle.WriteTo(reader, output, syntax); + var td = new Dom.TypeDefinition(module, handle); + td.WriteTo(output); }; } @@ -1673,13 +1459,14 @@ namespace ICSharpCode.Decompiler.Disassembler default: throw new NotSupportedException($"rawTypeKind: {rawTypeKind} (0x{rawTypeKind:x})"); } - handle.WriteTo(reader, output, syntax); + var typeRef = new Dom.TypeReference(module, handle); + typeRef.WriteTo(output); }; } - public Action GetTypeFromSpecification(MetadataReader reader, (GenericParameterHandleCollection TypeParameters, GenericParameterHandleCollection MethodTypeParameters) genericContext, TypeSpecificationHandle handle, byte rawTypeKind) + public Action GetTypeFromSpecification(MetadataReader reader, GenericContext genericContext, TypeSpecificationHandle handle, byte rawTypeKind) { - throw new NotImplementedException(); + return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext); } } } \ No newline at end of file diff --git a/ICSharpCode.Decompiler/Dom/Dom.cs b/ICSharpCode.Decompiler/Dom/Dom.cs new file mode 100644 index 000000000..8df5b0487 --- /dev/null +++ b/ICSharpCode.Decompiler/Dom/Dom.cs @@ -0,0 +1,1231 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; +using System.Security.Cryptography; +using System.Text; +using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.Util; + +namespace ICSharpCode.Decompiler.Dom +{ + using SRMMemberRef = System.Reflection.Metadata.MemberReference; + using SRMMethod = System.Reflection.Metadata.MethodDefinition; + using SRMMethodSpec = System.Reflection.Metadata.MethodSpecification; + using SRMProperty = System.Reflection.Metadata.PropertyDefinition; + using SRMEvent = System.Reflection.Metadata.EventDefinition; + using SRMField = System.Reflection.Metadata.FieldDefinition; + using SRMTypeDef = System.Reflection.Metadata.TypeDefinition; + using SRMTypeRef = System.Reflection.Metadata.TypeReference; + using SRMTypeSpec = System.Reflection.Metadata.TypeSpecification; + using SRMAssemblyReference = System.Reflection.Metadata.AssemblyReference; + + public sealed class AssemblyResolutionException : FileNotFoundException + { + public IAssemblyReference Reference { get; } + + public AssemblyResolutionException(IAssemblyReference reference) + : this(reference, null) + { + } + + public AssemblyResolutionException(IAssemblyReference reference, Exception innerException) + : base($"Failed to resolve assembly: '{reference}'", innerException) + { + this.Reference = reference; + } + } + + public interface ICustomAttributeProvider + { + PEFile Module { get; } + CustomAttributeHandleCollection CustomAttributes { get; } + } + + public interface IAssemblyResolver + { + PEFile Resolve(IAssemblyReference reference); + } + + public interface IAssemblyReference + { + string Name { get; } + string FullName { get; } + Version Version { get; } + string Culture { get; } + byte[] PublicKeyToken { get; } + + bool IsWindowsRuntime { get; } + bool IsRetargetable { get; } + } + + public interface IAssemblyDocumentationResolver + { + } + + public struct Variable { } + + public interface IDebugInfoProvider + { + IList GetSequencePoints(MethodDefinition method); + IList GetVariables(MethodDefinition method); + } + + public interface IMemberReference + { + PEFile Module { get; } + string Name { get; } + IMemberDefinition GetDefinition(); + ITypeReference DeclaringType { get; } + } + + public interface IMemberDefinition : IMemberReference, ICustomAttributeProvider + { + new TypeDefinition DeclaringType { get; } + } + + public interface IMethodReference : IMemberReference + { + } + + public interface ITypeReference : IMemberReference + { + PEFile Module { get; } + FullTypeName FullName { get; } + string Namespace { get; } + new TypeDefinition GetDefinition(); + } + + public interface ITypeDefinition : ITypeReference, IMemberDefinition + { + new PEFile Module { get; } + TypeDefinitionHandle Handle { get; } + } + + public class PEFile + { + public string FileName { get; } + public PEReader Reader { get; } + public IAssemblyResolver AssemblyResolver { get; } + public IAssemblyDocumentationResolver DocumentationResolver { get; set; } + public IDebugInfoProvider DebugInfo { get; set; } + + public PEFile(string fileName, PEReader reader, IAssemblyResolver resolver) + { + this.FileName = fileName; + this.Reader = reader; + this.AssemblyResolver = resolver; + } + + public bool IsAssembly => GetMetadataReader().IsAssembly; + public string Name => GetName(); + public string FullName => IsAssembly ? GetMetadataReader().GetFullAssemblyName() : Name; + + public MetadataReader GetMetadataReader() => Reader.GetMetadataReader(); + + string GetName() + { + var metadata = GetMetadataReader(); + if (metadata.IsAssembly) + return metadata.GetString(metadata.GetAssemblyDefinition().Name) + " (" + metadata.GetAssemblyDefinition().Version + ")"; + return metadata.GetString(metadata.GetModuleDefinition().Name); + } + + public ImmutableArray AssemblyReferences => GetMetadataReader().AssemblyReferences.Select(r => new AssemblyReference(this, r)).ToImmutableArray(); + public ImmutableArray ModuleReferences => GetModuleReferences().ToImmutableArray(); + public ImmutableArray TypeDefinitions => Reader.GetMetadataReader().GetTopLevelTypeDefinitions().Select(t => new TypeDefinition(this, t)).ToImmutableArray(); + public ImmutableArray TypeReferences => Reader.GetMetadataReader().TypeReferences.Select(t => new TypeReference(this, t)).ToImmutableArray(); + public ImmutableArray Resources => GetResources().ToImmutableArray(); + + IEnumerable GetModuleReferences() + { + var rowCount = GetMetadataReader().GetTableRowCount(TableIndex.ModuleRef); + for (int row = 0; row < rowCount; row++) { + yield return MetadataTokens.ModuleReferenceHandle(row); + } + } + + IEnumerable GetResources() + { + var metadata = GetMetadataReader(); + foreach (var h in metadata.ManifestResources) { + yield return new Resource(this, h); + } + } + } + + public enum ResourceType + { + Linked, + Embedded, + AssemblyLinked, + } + + public struct Resource + { + public PEFile Module { get; } + public ManifestResourceHandle Handle { get; } + public bool IsNil => Handle.IsNil; + + public Resource(PEFile module, ManifestResourceHandle handle) : this() + { + this.Module = module ?? throw new ArgumentNullException(nameof(module)); + this.Handle = handle; + } + + ManifestResource This() => Module.GetMetadataReader().GetManifestResource(Handle); + + public string Name => Module.GetMetadataReader().GetString(This().Name); + + public ManifestResourceAttributes Attributes => This().Attributes; + public bool HasFlag(ManifestResourceAttributes flag) => (Attributes & flag) == flag; + public ResourceType ResourceType => GetResourceType(); + + ResourceType GetResourceType() + { + if (This().Implementation.IsNil) + return ResourceType.Embedded; + if (This().Implementation.Kind == HandleKind.AssemblyReference) + return ResourceType.AssemblyLinked; + return ResourceType.Linked; + } + + public unsafe Stream TryOpenStream() + { + if (ResourceType != ResourceType.Embedded) + return null; + var headers = Module.Reader.PEHeaders; + var resources = headers.CorHeader.ResourcesDirectory; + int index = headers.GetContainingSectionIndex(resources.RelativeVirtualAddress); + if (index < 0) throw new NotSupportedException(); + var sectionHeader = headers.SectionHeaders[index]; + var sectionData = Module.Reader.GetEntireImage(); + int totalOffset = resources.RelativeVirtualAddress + sectionHeader.PointerToRawData - sectionHeader.VirtualAddress; + var reader = sectionData.GetReader(); + reader.Offset += totalOffset; + reader.Offset += (int)This().Offset; + int length = reader.ReadInt32(); + return new MemoryStream(reader.ReadBytes(length)); + } + } + + public class AssemblyNameReference : IAssemblyReference + { + string fullName; + + public string Name { get; private set; } + + public string FullName { + get { + if (fullName != null) + return fullName; + + const string sep = ", "; + + var builder = new StringBuilder(); + builder.Append(Name); + builder.Append(sep); + builder.Append("Version="); + builder.Append(Version.ToString(fieldCount: 4)); + builder.Append(sep); + builder.Append("Culture="); + builder.Append(string.IsNullOrEmpty(Culture) ? "neutral" : Culture); + builder.Append(sep); + builder.Append("PublicKeyToken="); + + var pk_token = PublicKeyToken; + if (pk_token != null && pk_token.Length > 0) { + for (int i = 0; i < pk_token.Length; i++) { + builder.Append(pk_token[i].ToString("x2")); + } + } else + builder.Append("null"); + + if (IsRetargetable) { + builder.Append(sep); + builder.Append("Retargetable=Yes"); + } + + return fullName = builder.ToString(); + } + } + + public Version Version { get; private set; } + + public string Culture { get; private set; } + + public byte[] PublicKeyToken { get; private set; } + + public bool IsWindowsRuntime { get; private set; } + + public bool IsRetargetable { get; private set; } + + public static AssemblyNameReference Parse(string fullName) + { + if (fullName == null) + throw new ArgumentNullException("fullName"); + if (fullName.Length == 0) + throw new ArgumentException("Name can not be empty"); + + var name = new AssemblyNameReference(); + var tokens = fullName.Split(','); + for (int i = 0; i < tokens.Length; i++) { + var token = tokens[i].Trim(); + + if (i == 0) { + name.Name = token; + continue; + } + + var parts = token.Split('='); + if (parts.Length != 2) + throw new ArgumentException("Malformed name"); + + switch (parts[0].ToLowerInvariant()) { + case "version": + name.Version = new Version(parts[1]); + break; + case "culture": + name.Culture = parts[1] == "neutral" ? "" : parts[1]; + break; + case "publickeytoken": + var pk_token = parts[1]; + if (pk_token == "null") + break; + + name.PublicKeyToken = new byte[pk_token.Length / 2]; + for (int j = 0; j < name.PublicKeyToken.Length; j++) + name.PublicKeyToken[j] = Byte.Parse(pk_token.Substring(j * 2, 2), System.Globalization.NumberStyles.HexNumber); + + break; + } + } + + return name; + } + } + + public struct AssemblyReference : IAssemblyReference + { + static readonly SHA1 sha1 = SHA1.Create(); + + public PEFile Module { get; } + public AssemblyReferenceHandle Handle { get; } + public bool IsNil => Handle.IsNil; + + SRMAssemblyReference This() => Module.GetMetadataReader().GetAssemblyReference(Handle); + + public bool IsWindowsRuntime => (This().Flags & AssemblyFlags.WindowsRuntime) != 0; + public bool IsRetargetable => (This().Flags & AssemblyFlags.Retargetable) != 0; + + public string Name => Module.GetMetadataReader().GetString(This().Name); + public string FullName => This().GetFullAssemblyName(Module.GetMetadataReader()); + public Version Version => This().Version; + public string Culture => Module.GetMetadataReader().GetString(This().Culture); + byte[] IAssemblyReference.PublicKeyToken => GetPublicKeyToken(); + + public byte[] GetPublicKeyToken() + { + var inst = This(); + if (inst.PublicKeyOrToken.IsNil) + return Empty.Array; + var bytes = Module.GetMetadataReader().GetBlobBytes(inst.PublicKeyOrToken); + if ((inst.Flags & AssemblyFlags.PublicKey) != 0) { + return sha1.ComputeHash(bytes).Skip(12).ToArray(); + } + return bytes; + } + + public AssemblyReference(PEFile module, AssemblyReferenceHandle handle) + { + Module = module; + Handle = handle; + } + } + + public struct MethodDefinition : IEquatable, IMethodReference, IMemberDefinition + { + public PEFile Module { get; } + public MethodDefinitionHandle Handle { get; } + public bool IsNil => Handle.IsNil; + + public MethodDefinition(PEFile module, MethodDefinitionHandle handle) : this() + { + this.Module = module ?? throw new ArgumentNullException(nameof(module)); + this.Handle = handle; + } + + SRMMethod This() => Module.GetMetadataReader().GetMethodDefinition(Handle); + + public bool Equals(MethodDefinition other) + { + return Module == other.Module && Handle == other.Handle; + } + + public override bool Equals(object obj) + { + if (obj is MethodDefinition md) + return Equals(md); + return false; + } + + public override int GetHashCode() + { + return unchecked(982451629 * Module.GetHashCode() + 982451653 * MetadataTokens.GetToken(Handle)); + } + + public static bool operator ==(MethodDefinition lhs, MethodDefinition rhs) => lhs.Equals(rhs); + public static bool operator !=(MethodDefinition lhs, MethodDefinition rhs) => !lhs.Equals(rhs); + + public string Name { + get { + var reader = Module.GetMetadataReader(); + return reader.GetString(reader.GetMethodDefinition(Handle).Name); + } + } + + public TypeDefinition DeclaringType => new TypeDefinition(Module, This().GetDeclaringType()); + ITypeReference IMemberReference.DeclaringType => DeclaringType; + + public MethodAttributes Attributes => This().Attributes; + public MethodImplAttributes ImplAttributes => This().ImplAttributes; + public CustomAttributeHandleCollection CustomAttributes => This().GetCustomAttributes(); + public DeclarativeSecurityAttributeHandleCollection DeclarativeSecurityAttributes => This().GetDeclarativeSecurityAttributes(); + public bool HasFlag(MethodAttributes attribute) => (This().Attributes & attribute) == attribute; + public bool HasPInvokeInfo => !This().GetImport().Module.IsNil || HasFlag(MethodAttributes.PinvokeImpl); + public bool IsConstructor => This().IsConstructor(Module.GetMetadataReader()); + public bool HasParameters => This().GetParameters().Count > 0; + public bool HasBody => (Attributes & MethodAttributes.Abstract) == 0 && + (Attributes & MethodAttributes.PinvokeImpl) == 0 && + (ImplAttributes & MethodImplAttributes.InternalCall) == 0 && + (ImplAttributes & MethodImplAttributes.Native) == 0 && + (ImplAttributes & MethodImplAttributes.Unmanaged) == 0 && + (ImplAttributes & MethodImplAttributes.Runtime) == 0; + public int RVA => This().RelativeVirtualAddress; + public MethodBodyBlock Body => Module.Reader.GetMethodBody(RVA); + public MethodImport Import => This().GetImport(); + public GenericParameterHandleCollection GenericParameters => This().GetGenericParameters(); + public ParameterHandleCollection Parameters => This().GetParameters(); + + public bool IsExtensionMethod { + get { + if (!HasFlag(MethodAttributes.Static)) { + var metadata = Module.GetMetadataReader(); + foreach (var attribute in This().GetCustomAttributes()) { + string typeName = metadata.GetCustomAttribute(attribute).GetAttributeType(Module).FullName.ToString(); + if (typeName == "System.Runtime.CompilerServices.ExtensionAttribute") + return true; + } + } + return false; + } + } + + public unsafe MethodSemanticsAttributes GetMethodSemanticsAttributes() + { + var reader = Module.GetMetadataReader(); + byte* startPointer = reader.MetadataPointer; + int offset = reader.GetTableMetadataOffset(TableIndex.MethodSemantics); + int rowSize = reader.GetTableRowSize(TableIndex.MethodSemantics); + int rowCount = reader.GetTableRowCount(TableIndex.MethodSemantics); + var small = reader.IsSmallReference(TableIndex.MethodDef); + + int methodRowNo = reader.GetRowNumber(Handle); + for (int row = rowCount - 1; row >= 0; row--) { + byte* ptr = startPointer + offset + rowSize * row; + uint rowNo = small ? *(ushort*)(ptr + 2) : *(uint*)(ptr + 2); + if (methodRowNo == rowNo) { + return (MethodSemanticsAttributes)(*(ushort*)ptr); + } + } + return 0; + } + + public unsafe ImmutableArray GetMethodImplementations() + { + var reader = Module.GetMetadataReader(); + byte* startPointer = reader.MetadataPointer; + int offset = reader.GetTableMetadataOffset(TableIndex.MethodImpl); + int rowSize = reader.GetTableRowSize(TableIndex.MethodImpl); + int rowCount = reader.GetTableRowCount(TableIndex.MethodImpl); + var methodDefSize = reader.GetReferenceSize(TableIndex.MethodDef); + var typeDefSize = reader.GetReferenceSize(TableIndex.TypeDef); + + var containingTypeRow = reader.GetRowNumber(This().GetDeclaringType()); + var methodDefRow = reader.GetRowNumber(Handle); + + var list = new List(); + + // TODO : if sorted -> binary search? + for (int row = 0; row < reader.GetTableRowCount(TableIndex.MethodImpl); row++) { + byte* ptr = startPointer + offset + rowSize * row; + uint currentTypeRow = typeDefSize == 2 ? *(ushort*)ptr : *(uint*)ptr; + if (currentTypeRow != containingTypeRow) continue; + uint currentMethodRowCoded = methodDefSize == 2 ? *(ushort*)(ptr + typeDefSize) : *(uint*)(ptr + typeDefSize); + if ((currentMethodRowCoded >> 1) != methodDefRow) continue; + list.Add(MetadataTokens.MethodImplementationHandle(row + 1)); + } + + return list.ToImmutableArray(); + } + + public IList GetSequencePoints() + { + return Module.DebugInfo?.GetSequencePoints(this); + } + + public IList GetVariables() + { + return Module.DebugInfo?.GetVariables(this); + } + + public MethodSignature DecodeSignature(ISignatureTypeProvider provider, TGenericContext genericContext) + { + return This().DecodeSignature(provider, genericContext); + } + + IMemberDefinition IMemberReference.GetDefinition() => this; + } + + public struct PropertyDefinition : IEquatable, IMemberDefinition, ICustomAttributeProvider + { + public PEFile Module { get; } + public PropertyDefinitionHandle Handle { get; } + public bool IsNil => Handle.IsNil; + + public PropertyDefinition(PEFile module, PropertyDefinitionHandle handle) : this() + { + this.Module = module ?? throw new ArgumentNullException(nameof(module)); + this.Handle = handle; + } + + SRMProperty This() => Module.GetMetadataReader().GetPropertyDefinition(Handle); + + public bool Equals(PropertyDefinition other) + { + return Module == other.Module && Handle == other.Handle; + } + + public override bool Equals(object obj) + { + if (obj is PropertyDefinition pd) + return Equals(pd); + return false; + } + + public override int GetHashCode() + { + return unchecked(982451629 * Module.GetHashCode() + 982451653 * MetadataTokens.GetToken(Handle)); + } + + public static bool operator ==(PropertyDefinition lhs, PropertyDefinition rhs) => lhs.Equals(rhs); + public static bool operator !=(PropertyDefinition lhs, PropertyDefinition rhs) => !lhs.Equals(rhs); + + public string Name { + get { + var reader = Module.GetMetadataReader(); + return reader.GetString(reader.GetPropertyDefinition(Handle).Name); + } + } + + public TypeDefinition DeclaringType => GetAccessors().First().Method.DeclaringType; + ITypeReference IMemberReference.DeclaringType => DeclaringType; + + public MethodDefinition GetMethod => GetAccessors().FirstOrDefault(m => m.Kind == MethodSemanticsAttributes.Getter).Method; + public MethodDefinition SetMethod => GetAccessors().FirstOrDefault(m => m.Kind == MethodSemanticsAttributes.Setter).Method; + public ImmutableArray OtherMethods => GetAccessors().Where(a => a.Kind == MethodSemanticsAttributes.Other).Select(a => a.Method).ToImmutableArray(); + + public PropertyAttributes Attributes => This().Attributes; + public bool HasFlag(PropertyAttributes attribute) => (This().Attributes & attribute) == attribute; + public bool HasParameters => Handle.HasParameters(Module.GetMetadataReader()); + public CustomAttributeHandleCollection CustomAttributes => This().GetCustomAttributes(); + + public bool IsIndexer => HasMatchingDefaultMemberAttribute(out var attr); + + public bool HasMatchingDefaultMemberAttribute(out CustomAttributeHandle defaultMemberAttribute) + { + var metadata = Module.GetMetadataReader(); + defaultMemberAttribute = default(CustomAttributeHandle); + if (HasParameters) { + var accessor = GetAccessors().First(a => a.Kind != MethodSemanticsAttributes.Other).Method; + PropertyDefinition basePropDef = this; + var firstOverrideHandle = accessor.GetMethodImplementations().FirstOrDefault(); + if (!firstOverrideHandle.IsNil) { + // if the property is explicitly implementing an interface, look up the property in the interface: + var firstOverride = metadata.GetMethodImplementation(firstOverrideHandle); + var baseAccessor = firstOverride.MethodDeclaration.CoerceMemberReference(Module).GetDefinition() as MethodDefinition?; + if (baseAccessor != null) { + foreach (PropertyDefinition baseProp in baseAccessor?.DeclaringType.Properties) { + if (baseProp.GetMethod == baseAccessor || baseProp.SetMethod == baseAccessor) { + basePropDef = baseProp; + break; + } + } + } else + return false; + } + var defaultMemberName = basePropDef.DeclaringType.Handle.GetDefaultMemberName(metadata, out var attr); + if (defaultMemberName == basePropDef.Name) { + defaultMemberAttribute = attr; + return true; + } + } + return false; + } + + public unsafe ImmutableArray<(MethodSemanticsAttributes Kind, MethodDefinition Method)> GetAccessors() + { + var reader = Module.GetMetadataReader(); + byte* startPointer = reader.MetadataPointer; + int offset = reader.GetTableMetadataOffset(TableIndex.MethodSemantics); + + uint encodedTag = (uint)(MetadataTokens.GetRowNumber(Handle) << 1) | 1; + var methodDefRefSize = reader.GetReferenceSize(TableIndex.MethodDef); + (int startRow, int endRow) = reader.BinarySearchRange(TableIndex.MethodSemantics, 2 + methodDefRefSize, encodedTag, reader.IsSmallReference(TableIndex.MethodSemantics)); + if (startRow == -1) + return ImmutableArray<(MethodSemanticsAttributes Kind, MethodDefinition Method)>.Empty; + var methods = new(MethodSemanticsAttributes Kind, MethodDefinition Method)[endRow - startRow + 1]; + int rowSize = reader.GetTableRowSize(TableIndex.MethodSemantics); + for (int row = startRow; row <= endRow; row++) { + int rowOffset = row * rowSize; + byte* ptr = startPointer + offset + rowOffset; + var kind = (MethodSemanticsAttributes)(*(ushort*)ptr); + var handle = MetadataTokens.MethodDefinitionHandle(*(ushort*)(ptr + 2)); + methods[row - startRow] = (kind, new MethodDefinition(Module, handle)); + } + return methods.ToImmutableArray(); + } + + public MethodSignature DecodeSignature(ISignatureTypeProvider provider, TGenericContext genericContext) + { + return This().DecodeSignature(provider, genericContext); + } + + IMemberDefinition IMemberReference.GetDefinition() => this; + } + + public struct FieldDefinition : IEquatable, IMemberDefinition, ICustomAttributeProvider + { + public PEFile Module { get; } + public FieldDefinitionHandle Handle { get; } + public bool IsNil => Handle.IsNil; + + public FieldDefinition(PEFile module, FieldDefinitionHandle handle) : this() + { + this.Module = module ?? throw new ArgumentNullException(nameof(module)); + this.Handle = handle; + } + + SRMField This() => Module.GetMetadataReader().GetFieldDefinition(Handle); + + public bool Equals(FieldDefinition other) + { + return Module == other.Module && Handle == other.Handle; + } + + public override bool Equals(object obj) + { + if (obj is FieldDefinition fd) + return Equals(fd); + return false; + } + + public override int GetHashCode() + { + return unchecked(982451629 * Module.GetHashCode() + 982451653 * MetadataTokens.GetToken(Handle)); + } + + public static bool operator ==(FieldDefinition lhs, FieldDefinition rhs) => lhs.Equals(rhs); + public static bool operator !=(FieldDefinition lhs, FieldDefinition rhs) => !lhs.Equals(rhs); + + public string Name { + get { + var reader = Module.GetMetadataReader(); + return reader.GetString(reader.GetFieldDefinition(Handle).Name); + } + } + + public TypeDefinition DeclaringType => new TypeDefinition(Module, This().GetDeclaringType()); + ITypeReference IMemberReference.DeclaringType => DeclaringType; + + public FieldAttributes Attributes => This().Attributes; + public bool HasFlag(FieldAttributes attribute) => (This().Attributes & attribute) == attribute; + public CustomAttributeHandleCollection CustomAttributes => This().GetCustomAttributes(); + public int RVA => This().GetRelativeVirtualAddress(); + public int Offset => This().GetOffset(); + + public BlobHandle GetMarshallingDescriptor() => This().GetMarshallingDescriptor(); + public ConstantHandle GetDefaultValue() => This().GetDefaultValue(); + + public TType DecodeSignature(ISignatureTypeProvider provider, TGenericContext genericContext) + { + return This().DecodeSignature(provider, genericContext); + } + + public object DecodeConstant() + { + var metadata = Module.GetMetadataReader(); + var constant = metadata.GetConstant(GetDefaultValue()); + var blob = metadata.GetBlobReader(constant.Value); + switch (constant.TypeCode) { + case ConstantTypeCode.Boolean: + return blob.ReadBoolean(); + case ConstantTypeCode.Char: + return blob.ReadChar(); + case ConstantTypeCode.SByte: + return blob.ReadSByte(); + case ConstantTypeCode.Byte: + return blob.ReadByte(); + case ConstantTypeCode.Int16: + return blob.ReadInt16(); + case ConstantTypeCode.UInt16: + return blob.ReadUInt16(); + case ConstantTypeCode.Int32: + return blob.ReadInt32(); + case ConstantTypeCode.UInt32: + return blob.ReadUInt32(); + case ConstantTypeCode.Int64: + return blob.ReadInt64(); + case ConstantTypeCode.UInt64: + return blob.ReadUInt64(); + case ConstantTypeCode.Single: + return blob.ReadSingle(); + case ConstantTypeCode.Double: + return blob.ReadDouble(); + case ConstantTypeCode.String: + return blob.ReadSerializedString(); + case ConstantTypeCode.NullReference: + return null; + default: + throw new NotSupportedException(); + } + } + + IMemberDefinition IMemberReference.GetDefinition() => this; + } + + public struct EventDefinition : IEquatable, IMemberDefinition, ICustomAttributeProvider + { + public PEFile Module { get; } + public EventDefinitionHandle Handle { get; } + public bool IsNil => Handle.IsNil; + + public EventDefinition(PEFile module, EventDefinitionHandle handle) + { + this.Module = module ?? throw new ArgumentNullException(nameof(module)); + this.Handle = handle; + } + + SRMEvent This() => Module.GetMetadataReader().GetEventDefinition(Handle); + + public bool Equals(EventDefinition other) + { + return Module == other.Module && Handle == other.Handle; + } + + public override bool Equals(object obj) + { + if (obj is EventDefinition ed) + return Equals(ed); + return false; + } + + public override int GetHashCode() + { + return unchecked(982451629 * Module.GetHashCode() + 982451653 * MetadataTokens.GetToken(Handle)); + } + + public static bool operator ==(EventDefinition lhs, EventDefinition rhs) => lhs.Equals(rhs); + public static bool operator !=(EventDefinition lhs, EventDefinition rhs) => !lhs.Equals(rhs); + + public string Name { + get { + var reader = Module.GetMetadataReader(); + return reader.GetString(reader.GetEventDefinition(Handle).Name); + } + } + + public TypeDefinition DeclaringType => GetAccessors().First().Method.DeclaringType; + ITypeReference IMemberReference.DeclaringType => DeclaringType; + + public EventAttributes Attributes => This().Attributes; + public bool HasFlag(EventAttributes attribute) => (This().Attributes & attribute) == attribute; + public CustomAttributeHandleCollection CustomAttributes => This().GetCustomAttributes(); + + public MethodDefinition AddMethod => GetAccessors().FirstOrDefault(m => m.Kind == MethodSemanticsAttributes.Adder).Method; + public MethodDefinition RemoveMethod => GetAccessors().FirstOrDefault(m => m.Kind == MethodSemanticsAttributes.Remover).Method; + public MethodDefinition InvokeMethod => GetAccessors().FirstOrDefault(m => m.Kind == MethodSemanticsAttributes.Raiser).Method; + public ImmutableArray OtherMethods => GetAccessors().Where(a => a.Kind == MethodSemanticsAttributes.Other).Select(a => a.Method).ToImmutableArray(); + + public unsafe ImmutableArray<(MethodSemanticsAttributes Kind, MethodDefinition Method)> GetAccessors() + { + var reader = Module.GetMetadataReader(); + byte* startPointer = reader.MetadataPointer; + int offset = reader.GetTableMetadataOffset(TableIndex.MethodSemantics); + + uint encodedTag = (uint)(MetadataTokens.GetRowNumber(Handle) << 1) | 0; + var methodDefRefSize = reader.GetReferenceSize(TableIndex.MethodDef); + (int startRow, int endRow) = reader.BinarySearchRange(TableIndex.MethodSemantics, 2 + methodDefRefSize, encodedTag, reader.IsSmallReference(TableIndex.MethodSemantics)); + if (startRow == -1) + return ImmutableArray<(MethodSemanticsAttributes Kind, MethodDefinition Method)>.Empty; + var methods = new(MethodSemanticsAttributes Kind, MethodDefinition Method)[endRow - startRow + 1]; + int rowSize = reader.GetTableRowSize(TableIndex.MethodSemantics); + for (int row = startRow; row <= endRow; row++) { + int rowOffset = row * rowSize; + byte* ptr = startPointer + offset + rowOffset; + var kind = (MethodSemanticsAttributes)(*(ushort*)ptr); + var handle = MetadataTokens.MethodDefinitionHandle(*(ushort*)(ptr + 2)); + methods[row - startRow] = (kind, new MethodDefinition(Module, handle)); + } + return methods.ToImmutableArray(); + } + + public TType DecodeSignature(ISignatureTypeProvider provider, TGenericContext genericContext) + { + var type = This().Type; + var reader = Module.GetMetadataReader(); + switch (type.Kind) { + case HandleKind.TypeDefinition: + return provider.GetTypeFromDefinition(reader, (TypeDefinitionHandle)type, 0); + case HandleKind.TypeReference: + return provider.GetTypeFromReference(reader, (TypeReferenceHandle)type, 0); + case HandleKind.TypeSpecification: + return provider.GetTypeFromSpecification(reader, genericContext, (TypeSpecificationHandle)type, 0); + default: + throw new NotSupportedException(); + } + } + + IMemberDefinition IMemberReference.GetDefinition() => this; + } + + public struct TypeDefinition : IEquatable, ITypeDefinition, ICustomAttributeProvider + { + public PEFile Module { get; } + public TypeDefinitionHandle Handle { get; } + public bool IsNil => Handle.IsNil; + + public TypeDefinition(PEFile module, TypeDefinitionHandle handle) + { + this.Module = module ?? throw new ArgumentNullException(nameof(module)); + this.Handle = handle; + } + + internal SRMTypeDef This() => Module.GetMetadataReader().GetTypeDefinition(Handle); + + public bool Equals(TypeDefinition other) + { + return Module == other.Module && Handle == other.Handle; + } + + public override bool Equals(object obj) + { + if (obj is TypeDefinition td) + return Equals(td); + return false; + } + + public override int GetHashCode() + { + return unchecked(982451629 * Module.GetHashCode() + 982451653 * MetadataTokens.GetToken(Handle)); + } + + public static bool operator ==(TypeDefinition lhs, TypeDefinition rhs) => lhs.Equals(rhs); + public static bool operator !=(TypeDefinition lhs, TypeDefinition rhs) => !lhs.Equals(rhs); + + public string Name => Module.GetMetadataReader().GetString(This().Name); + public string Namespace => Module.GetMetadataReader().GetString(This().Namespace); + public FullTypeName FullName => This().GetFullTypeName(Module.GetMetadataReader()); + public TypeAttributes Attributes => This().Attributes; + public bool HasFlag(TypeAttributes attribute) => (This().Attributes & attribute) == attribute; + public TypeDefinition DeclaringType => new TypeDefinition(Module, This().GetDeclaringType()); + ITypeReference IMemberReference.DeclaringType => DeclaringType; + public GenericParameterHandleCollection GenericParameters => This().GetGenericParameters(); + public CustomAttributeHandleCollection CustomAttributes => This().GetCustomAttributes(); + public DeclarativeSecurityAttributeHandleCollection DeclarativeSecurityAttributes => This().GetDeclarativeSecurityAttributes(); + public TypeLayout GetLayout() => This().GetLayout(); + + public ITypeReference BaseType { + get { + var baseType = This().BaseType; + return CreateTypeReference(baseType); + } + } + + ITypeReference CreateTypeReference(EntityHandle baseType) + { + if (baseType.IsNil) + return null; + switch (baseType.Kind) { + case HandleKind.TypeDefinition: + return new TypeDefinition(Module, (TypeDefinitionHandle)baseType); + case HandleKind.TypeReference: + return new TypeReference(Module, (TypeReferenceHandle)baseType); + case HandleKind.TypeSpecification: + return new TypeSpecification(Module, (TypeSpecificationHandle)baseType); + default: + throw new NotSupportedException(); + } + } + + public bool HasInterfaces => This().GetInterfaceImplementations().Count > 0; + + public ImmutableArray Interfaces => GetInterfaces().ToImmutableArray(); + + IEnumerable GetInterfaces() + { + var reader = Module.GetMetadataReader(); + foreach (var h in This().GetInterfaceImplementations()) { + var interfaceImpl = reader.GetInterfaceImplementation(h); + yield return CreateTypeReference(interfaceImpl.Interface); + } + } + + public bool IsValueType => This().IsValueType(Module.GetMetadataReader()); + public bool IsEnum => This().IsEnum(Module.GetMetadataReader()); + public bool IsInterface => (This().Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface; + public bool IsClass => (This().Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Class; + public bool IsNotPublic => (This().Attributes & TypeAttributes.VisibilityMask) == 0; + public bool IsDelegate { + get { + var baseType = This().BaseType; + return !baseType.IsNil && baseType.GetFullTypeName(Module.GetMetadataReader()).ToString() == typeof(MulticastDelegate).FullName; + } + } + + public ImmutableArray NestedTypes { + get { + var module = Module; + return This().GetNestedTypes().Select(nt => new TypeDefinition(module, nt)).ToImmutableArray(); + } + } + public ImmutableArray Fields { + get { + var module = Module; + return This().GetFields().Select(f => new FieldDefinition(module, f)).ToImmutableArray(); + } + } + public ImmutableArray Properties { + get { + var module = Module; + return This().GetProperties().Select(p => new PropertyDefinition(module, p)).ToImmutableArray(); + } + } + public ImmutableArray Events { + get { + var module = Module; + return This().GetEvents().Select(e => new EventDefinition(module, e)).ToImmutableArray(); + } + } + public ImmutableArray Methods { + get { + var module = Module; + return This().GetMethods().Select(m => new MethodDefinition(module, m)).ToImmutableArray(); + } + } + + TypeDefinition ITypeReference.GetDefinition() => this; + + public InterfaceImplementationHandleCollection GetInterfaceImplementations() => This().GetInterfaceImplementations(); + + IMemberDefinition IMemberReference.GetDefinition() => this; + } + + public struct TypeReference : ITypeReference + { + public PEFile Module { get; } + public TypeReferenceHandle Handle { get; } + public bool IsNil => Handle.IsNil; + + public TypeReference(PEFile module, TypeReferenceHandle handle) + { + this.Module = module ?? throw new ArgumentNullException(nameof(module)); + this.Handle = handle; + } + + SRMTypeRef This() => Module.GetMetadataReader().GetTypeReference(Handle); + + public string Name { + get { + var reader = Module.GetMetadataReader(); + return reader.GetString(This().Name); + } + } + + public FullTypeName FullName { + get { + return Handle.GetFullTypeName(Module.GetMetadataReader()); + } + } + + public string Namespace => throw new NotImplementedException(); + + public EntityHandle ResolutionScope => This().ResolutionScope; + + public TypeDefinition GetDefinition() + { + return MetadataResolver.Resolve(Handle, new SimpleMetadataResolveContext(Module)); + } + + IMemberDefinition IMemberReference.GetDefinition() => GetDefinition(); + ITypeReference IMemberReference.DeclaringType => new TypeReference(Module, This().GetDeclaringType()); + } + + public struct TypeSpecification : ITypeReference + { + public PEFile Module { get; } + public TypeSpecificationHandle Handle { get; } + public bool IsNil => Handle.IsNil; + + public TypeSpecification(PEFile module, TypeSpecificationHandle handle) + { + this.Module = module ?? throw new ArgumentNullException(nameof(module)); + this.Handle = handle; + } + + SRMTypeSpec This() => Module.GetMetadataReader().GetTypeSpecification(Handle); + + public FullTypeName FullName { + get { + return DecodeSignature(new FullTypeNameSignatureDecoder(Module.GetMetadataReader()), default(Unit)); + } + } + + public string Name => FullName.Name; + + public string Namespace => FullName.TopLevelTypeName.Namespace; + + public ITypeReference DeclaringType => GetDefinition().DeclaringType; + + public TypeDefinition GetDefinition() + { + return MetadataResolver.Resolve(Handle, new SimpleMetadataResolveContext(Module)); + } + + IMemberDefinition IMemberReference.GetDefinition() + { + return GetDefinition(); + } + + public TType DecodeSignature(ISignatureTypeProvider provider, TGenericContext genericContext) + { + return This().DecodeSignature(provider, genericContext); + } + } + + public struct MethodSpecification : IMethodReference + { + public PEFile Module { get; } + public MethodSpecificationHandle Handle { get; } + public bool IsNil => Handle.IsNil; + + public string Name => This().Method.CoerceMemberReference(Module).Name; + + public MethodSpecification(PEFile module, MethodSpecificationHandle handle) + { + this.Module = module ?? throw new ArgumentNullException(nameof(module)); + this.Handle = handle; + } + + SRMMethodSpec This() => Module.GetMetadataReader().GetMethodSpecification(Handle); + + public ImmutableArray DecodeSignature(ISignatureTypeProvider provider, TGenericContext genericContext) + { + return This().DecodeSignature(provider, genericContext); + } + + public IMemberDefinition GetDefinition() + { + return Method.GetDefinition(); + } + + public ITypeReference DeclaringType => Method.DeclaringType; + + public IMemberReference Method => This().Method.CoerceMemberReference(Module); + } + + public struct MemberReference : IMemberReference + { + public PEFile Module { get; } + public MemberReferenceHandle Handle { get; } + public bool IsNil => Handle.IsNil; + + SRMMemberRef This() => Module.GetMetadataReader().GetMemberReference(Handle); + + public MemberReference(PEFile module, MemberReferenceHandle handle) + { + this.Module = module ?? throw new ArgumentNullException(nameof(module)); + this.Handle = handle; + } + + public string Name { + get { + var reader = Module.GetMetadataReader(); + return reader.GetString(reader.GetMemberReference(Handle).Name); + } + } + + public MemberReferenceKind Kind => This().GetKind(); + + /// + /// MethodDef, ModuleRef,TypeDef, TypeRef, or TypeSpec handle. + /// + public EntityHandle Parent => This().Parent; + + public MethodSignature DecodeMethodSignature(ISignatureTypeProvider provider, TGenericContext genericContext) + { + return This().DecodeMethodSignature(provider, genericContext); + } + + public TType DecodeFieldSignature(ISignatureTypeProvider provider, TGenericContext genericContext) + { + return This().DecodeFieldSignature(provider, genericContext); + } + + public IMemberDefinition GetDefinition() + { + return MetadataResolver.Resolve(Handle, new SimpleMetadataResolveContext(Module)); + } + + public TypeDefinition DeclaringType => GetDefinition().DeclaringType; + + ITypeReference IMemberReference.DeclaringType => DeclaringType; + } + + class FullTypeNameSignatureDecoder : ISignatureTypeProvider + { + readonly MetadataReader metadata; + + public FullTypeNameSignatureDecoder(MetadataReader metadata) + { + this.metadata = metadata; + } + + public FullTypeName GetArrayType(FullTypeName elementType, ArrayShape shape) + { + return elementType; + } + + public FullTypeName GetByReferenceType(FullTypeName elementType) + { + return elementType; + } + + public FullTypeName GetFunctionPointerType(MethodSignature signature) + { + throw new NotSupportedException(); + } + + public FullTypeName GetGenericInstantiation(FullTypeName genericType, ImmutableArray typeArguments) + { + return genericType; + } + + public FullTypeName GetGenericMethodParameter(Unit genericContext, int index) + { + return default(FullTypeName); + } + + public FullTypeName GetGenericTypeParameter(Unit genericContext, int index) + { + return default(FullTypeName); + } + + public FullTypeName GetModifiedType(FullTypeName modifier, FullTypeName unmodifiedType, bool isRequired) + { + return unmodifiedType; + } + + public FullTypeName GetPinnedType(FullTypeName elementType) + { + return elementType; + } + + public FullTypeName GetPointerType(FullTypeName elementType) + { + return elementType; + } + + public FullTypeName GetPrimitiveType(PrimitiveTypeCode typeCode) + { + return new FullTypeName($"System.{typeCode}"); + } + + public FullTypeName GetSZArrayType(FullTypeName elementType) + { + return elementType; + } + + public FullTypeName GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) + { + return handle.GetFullTypeName(reader); + } + + public FullTypeName GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) + { + return handle.GetFullTypeName(reader, omitGenericParamCount: true); + } + + public FullTypeName GetTypeFromSpecification(MetadataReader reader, Unit genericContext, TypeSpecificationHandle handle, byte rawTypeKind) + { + return reader.GetTypeSpecification(handle).DecodeSignature(new FullTypeNameSignatureDecoder(metadata), default(Unit)); + } + } + + public class GenericContext + { + readonly MethodDefinition method; + readonly TypeDefinition declaringType; + readonly MetadataReader metadata; + + public static readonly GenericContext Empty = new GenericContext(); + + private GenericContext() { } + + public GenericContext(MethodDefinition method) + { + this.method = method; + this.declaringType = method.DeclaringType; + this.metadata = method.Module.GetMetadataReader(); + } + + public GenericContext(TypeDefinition declaringType) + { + this.declaringType = declaringType; + this.metadata = declaringType.Module.GetMetadataReader(); + } + + public string GetGenericTypeParameterName(int index) + { + if (declaringType.IsNil || index < 0 || index >= declaringType.GenericParameters.Count) + return index.ToString(); + return metadata.GetString(metadata.GetGenericParameter(declaringType.GenericParameters[index]).Name); + } + + public string GetGenericMethodTypeParameterName(int index) + { + if (method.IsNil || index < 0 || index >= method.GenericParameters.Count) + return index.ToString(); + return metadata.GetString(metadata.GetGenericParameter(method.GenericParameters[index]).Name); + } + + public GenericParameterHandle GetGenericTypeParameterHandleOrNull(int index) + { + if (declaringType.IsNil || index < 0 || index >= declaringType.GenericParameters.Count) + return MetadataTokens.GenericParameterHandle(0); + return declaringType.GenericParameters[index]; + } + + public GenericParameterHandle GetGenericMethodTypeParameterHandleOrNull(int index) + { + if (method.IsNil || index < 0 || index >= method.GenericParameters.Count) + return MetadataTokens.GenericParameterHandle(0); + return method.GenericParameters[index]; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/MetadataExtensions.cs b/ICSharpCode.Decompiler/Dom/MetadataExtensions.cs similarity index 52% rename from ICSharpCode.Decompiler/TypeSystem/MetadataExtensions.cs rename to ICSharpCode.Decompiler/Dom/MetadataExtensions.cs index 7c6a17c34..38b115d3a 100644 --- a/ICSharpCode.Decompiler/TypeSystem/MetadataExtensions.cs +++ b/ICSharpCode.Decompiler/Dom/MetadataExtensions.cs @@ -1,17 +1,57 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; +using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.TypeSystem.Implementation; +using ICSharpCode.Decompiler.Util; -namespace ICSharpCode.Decompiler.TypeSystem +namespace ICSharpCode.Decompiler { - static class MetadataExtensions + public static class MetadataExtensions { + public static Dom.ITypeReference CoerceTypeReference(this EntityHandle handle, Dom.PEFile module) + { + if (handle.IsNil) + return null; + switch (handle.Kind) { + case HandleKind.TypeDefinition: + return new Dom.TypeDefinition(module, (TypeDefinitionHandle)handle); + case HandleKind.TypeReference: + return new Dom.TypeReference(module, (TypeReferenceHandle)handle); + case HandleKind.TypeSpecification: + return new Dom.TypeSpecification(module, (TypeSpecificationHandle)handle); + default: + throw new ArgumentException("must be either TypeDef, TypeRef or TypeSpec!", nameof(handle)); + } + } + + public static Dom.IMemberReference CoerceMemberReference(this EntityHandle handle, Dom.PEFile module) + { + if (handle.IsNil) + return null; + switch (handle.Kind) { + case HandleKind.MemberReference: + return new Dom.MemberReference(module, (MemberReferenceHandle)handle); + case HandleKind.MethodDefinition: + return new Dom.MethodDefinition(module, (MethodDefinitionHandle)handle); + default: + throw new ArgumentException("must be either MethodDef or MemberRef!", nameof(handle)); + } + } + + public static bool IsNil(this Dom.IAssemblyReference reference) + { + return reference == null || (reference is Dom.AssemblyReference ar && ar.IsNil); + } + public static string GetFullAssemblyName(this MetadataReader reader) { if (!reader.IsAssembly) @@ -26,6 +66,20 @@ namespace ICSharpCode.Decompiler.TypeSystem return $"{reader.GetString(asm.Name)}, Version={asm.Version}, Culture={reader.GetString(asm.Culture)}, PublicKeyToken={publicKey}"; } + public static string GetFullAssemblyName(this AssemblyReference reference, MetadataReader reader) + { + string publicKey = "null"; + if (!reference.PublicKeyOrToken.IsNil && (reference.Flags & AssemblyFlags.PublicKey) != 0) { + SHA1 sha1 = SHA1.Create(); + var publicKeyTokenBytes = sha1.ComputeHash(reader.GetBlobBytes(reference.PublicKeyOrToken)).Skip(12).ToArray(); + publicKey = publicKeyTokenBytes.ToHexString(); + } + string properties = ""; + if ((reference.Flags & AssemblyFlags.Retargetable) != 0) + properties = ", Retargetable=true"; + return $"{reader.GetString(reference.Name)}, Version={reference.Version}, Culture={reader.GetString(reference.Culture)}, PublicKeyToken={publicKey}{properties}"; + } + static string ToHexString(this byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.Length * 2); @@ -37,7 +91,24 @@ namespace ICSharpCode.Decompiler.TypeSystem /// /// Gets the type of the attribute. /// - /// Either , , + public static Dom.ITypeReference GetAttributeType(this CustomAttribute attribute, Dom.PEFile module) + { + var reader = module.GetMetadataReader(); + switch (attribute.Constructor.Kind) { + case HandleKind.MethodDefinition: + var md = reader.GetMethodDefinition((MethodDefinitionHandle)attribute.Constructor); + return new Dom.TypeDefinition(module, md.GetDeclaringType()); + case HandleKind.MemberReference: + var mr = reader.GetMemberReference((MemberReferenceHandle)attribute.Constructor); + return mr.Parent.CoerceTypeReference(module); + default: + throw new NotSupportedException(); + } + } + + /// + /// Gets the type of the attribute. + /// public static EntityHandle GetAttributeType(this CustomAttribute attribute, MetadataReader reader) { switch (attribute.Constructor.Kind) { @@ -52,32 +123,61 @@ namespace ICSharpCode.Decompiler.TypeSystem } } + public static IEnumerable GetTopLevelTypeDefinitions(this MetadataReader reader) + { + var queue = new Queue(); + queue.Enqueue(reader.GetNamespaceDefinitionRoot()); + while (queue.Count > 0) { + var ns = queue.Dequeue(); + foreach (var td in ns.TypeDefinitions) + yield return td; + foreach (var nestedNS in ns.NamespaceDefinitions) + queue.Enqueue(reader.GetNamespaceDefinition(nestedNS)); + } + } + public static FullTypeName GetFullTypeName(this EntityHandle handle, MetadataReader reader) { + if (handle.IsNil) + throw new ArgumentNullException(nameof(handle)); switch (handle.Kind) { case HandleKind.TypeDefinition: return ((TypeDefinitionHandle)handle).GetFullTypeName(reader); case HandleKind.TypeReference: return ((TypeReferenceHandle)handle).GetFullTypeName(reader); + case HandleKind.TypeSpecification: + return ((TypeSpecificationHandle)handle).GetFullTypeName(reader); default: throw new NotSupportedException(); } } - public static FullTypeName GetFullTypeName(this TypeReferenceHandle handle, MetadataReader reader) + public static FullTypeName GetFullTypeName(this TypeSpecificationHandle handle, MetadataReader reader, bool omitGenericParamCount = false) + { + if (handle.IsNil) + throw new ArgumentNullException(nameof(handle)); + var ts = reader.GetTypeSpecification(handle); + return ts.DecodeSignature(new Dom.FullTypeNameSignatureDecoder(reader), default(Unit)); + } + + public static FullTypeName GetFullTypeName(this TypeReferenceHandle handle, MetadataReader reader, bool omitGenericParamCount = false) { + if (handle.IsNil) + throw new ArgumentNullException(nameof(handle)); var tr = reader.GetTypeReference(handle); TypeReferenceHandle declaringTypeHandle; if ((declaringTypeHandle = tr.GetDeclaringType()).IsNil) { string @namespace = tr.Namespace.IsNil ? "" : reader.GetString(tr.Namespace); return new FullTypeName(new TopLevelTypeName(@namespace, reader.GetString(tr.Name))); } else { - return declaringTypeHandle.GetFullTypeName(reader).NestedType(reader.GetString(tr.Name), 0); + return declaringTypeHandle.GetFullTypeName(reader, omitGenericParamCount).NestedType(reader.GetString(tr.Name), 0); } } public static FullTypeName GetFullTypeName(this TypeDefinitionHandle handle, MetadataReader reader) { + if (handle.IsNil) + throw new ArgumentNullException(nameof(handle)); return reader.GetTypeDefinition(handle).GetFullTypeName(reader); } @@ -86,9 +186,21 @@ namespace ICSharpCode.Decompiler.TypeSystem TypeDefinitionHandle declaringTypeHandle; if ((declaringTypeHandle = td.GetDeclaringType()).IsNil) { string @namespace = td.Namespace.IsNil ? "" : reader.GetString(td.Namespace); - return new FullTypeName(new TopLevelTypeName(@namespace, reader.GetString(td.Name), td.GetGenericParameters().Count)); + return new FullTypeName(new TopLevelTypeName(@namespace, reader.GetString(td.Name))); } else { - return declaringTypeHandle.GetFullTypeName(reader).NestedType(reader.GetString(td.Name), td.GetGenericParameters().Count); + return declaringTypeHandle.GetFullTypeName(reader).NestedType(reader.GetString(td.Name), 0); + } + } + + public static string ToILNameString(this FullTypeName typeName) + { + var escapedName = Disassembler.DisassemblerHelpers.Escape(typeName.Name); + if (typeName.IsNested) { + return $"{typeName.GetDeclaringType().ToILNameString()}/{escapedName}"; + } else if (!string.IsNullOrEmpty(typeName.TopLevelTypeName.Namespace)) { + return $"{typeName.TopLevelTypeName.Namespace}.{escapedName}"; + } else { + return $"{escapedName}"; } } @@ -115,23 +227,6 @@ namespace ICSharpCode.Decompiler.TypeSystem } } - public unsafe static MethodSemanticsAttributes GetMethodSemanticsAttributes(this MethodDefinitionHandle handle, MetadataReader reader) - { - byte* startPointer = reader.MetadataPointer; - int offset = reader.GetTableMetadataOffset(TableIndex.MethodSemantics); - int rowSize = reader.GetTableRowSize(TableIndex.MethodSemantics); - int rowCount = reader.GetTableRowCount(TableIndex.MethodSemantics); - int token = reader.GetToken(handle); - for (int row = rowCount - 1; row >= 0; row--) { - byte* ptr = startPointer + offset + rowSize * row; - ushort methodToken = *(ptr + 2); - if (token == methodToken) { - return (MethodSemanticsAttributes)(*ptr); - } - } - return 0; - } - public static bool IsValueType(this TypeDefinition typeDefinition, MetadataReader reader) { if (typeDefinition.BaseType.IsNil) @@ -157,6 +252,32 @@ namespace ICSharpCode.Decompiler.TypeSystem return typeDefinition.BaseType.GetFullTypeName(reader).ToString() == "System.Enum"; } + public static string GetDefaultMemberName(this TypeDefinitionHandle type, MetadataReader reader) + { + return type.GetDefaultMemberName(reader, out var attr); + } + + static readonly ITypeResolveContext minimalCorlibContext = new SimpleTypeResolveContext(MinimalCorlib.Instance.CreateCompilation()); + + public static string GetDefaultMemberName(this TypeDefinitionHandle type, MetadataReader reader, out CustomAttributeHandle defaultMemberAttribute) + { + var td = reader.GetTypeDefinition(type); + + foreach (var h in td.GetCustomAttributes()) { + var ca = reader.GetCustomAttribute(h); + if (ca.GetAttributeType(reader).ToString() == "System.Reflection.DefaultMemberAttribute") { + var decodedValues = ca.DecodeValue(new TypeSystemAttributeTypeProvider(minimalCorlibContext)); + if (decodedValues.FixedArguments.Length == 1 && decodedValues.FixedArguments[0].Value is string value) { + defaultMemberAttribute = h; + return value; + } + } + } + + defaultMemberAttribute = default(CustomAttributeHandle); + return null; + } + public static bool HasOverrides(this MethodDefinitionHandle handle, MetadataReader reader) { for (int row = 1; row <= reader.GetTableRowCount(TableIndex.MethodImpl); row++) { @@ -267,5 +388,75 @@ namespace ICSharpCode.Decompiler.TypeSystem return KnownTypeCode.None; } } + + public static bool IsSmallReference(this MetadataReader reader, TableIndex table) + { + // TODO detect whether #JTD is present (EnC) + return reader.GetTableRowCount(table) <= ushort.MaxValue; + } + + public static int GetReferenceSize(this MetadataReader reader, TableIndex table) + { + return IsSmallReference(reader, table) ? 2 : 4; + } + + public static unsafe (int startRow, int endRow) BinarySearchRange(this MetadataReader reader, TableIndex table, int valueOffset, uint referenceValue, bool small) + { + int offset = reader.GetTableMetadataOffset(table); + int rowSize = reader.GetTableRowSize(table); + int rowCount = reader.GetTableRowCount(table); + int tableLength = rowSize * rowCount; + byte* startPointer = reader.MetadataPointer; + + int result = BinarySearch(); + if (result == -1) + return (-1, -1); + + int start = result; + + while (start > 0 && GetValue(start - 1) == referenceValue) + start--; + + int end = result; + + while (end + 1 < tableLength && GetValue(end + 1) == referenceValue) + end++; + + return (start, end); + + uint GetValue(int row) + { + if (small) + return *(ushort*)(startPointer + offset + row * rowSize + valueOffset); + else + return *(uint*)(startPointer + offset + row * rowSize + valueOffset); + } + + int BinarySearch() + { + int startRow = 0; + int endRow = rowCount - 1; + while (startRow <= endRow) { + int row = (startRow + endRow) / 2; + uint currentValue = GetValue(row); + if (referenceValue > currentValue) { + startRow = row + 1; + } else if (referenceValue < currentValue) { + endRow = row - 1; + } else { + return row; + } + } + return -1; + } + } + + public static AssemblyDefinition? GetAssemblyDefinition(this PEReader reader) + { + var metadata = reader.GetMetadataReader(); + if (metadata.IsAssembly) + return metadata.GetAssemblyDefinition(); + return null; + } } } diff --git a/ICSharpCode.Decompiler/Dom/MetadataResolver.cs b/ICSharpCode.Decompiler/Dom/MetadataResolver.cs new file mode 100644 index 000000000..63ae1c246 --- /dev/null +++ b/ICSharpCode.Decompiler/Dom/MetadataResolver.cs @@ -0,0 +1,230 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; +using System.Text; +using System.Threading.Tasks; +using ICSharpCode.Decompiler.Util; + +namespace ICSharpCode.Decompiler.Dom +{ + public interface IMetadataResolveContext + { + PEFile CurrentModule { get; } + PEFile ResolveAssembly(IAssemblyReference reference); + } + + public class SimpleMetadataResolveContext : IMetadataResolveContext + { + readonly PEFile mainModule; + readonly IAssemblyResolver assemblyResolver; + readonly Dictionary loadedModules = new Dictionary(); + + public SimpleMetadataResolveContext(PEFile mainModule) + { + this.mainModule = mainModule; + this.assemblyResolver = mainModule.AssemblyResolver; + } + + public PEFile CurrentModule => mainModule; + + public PEFile ResolveAssembly(IAssemblyReference reference) + { + if (loadedModules.TryGetValue(reference, out var module)) + return module; + var resolved = assemblyResolver.Resolve(reference); + loadedModules.Add(reference, resolved); + return resolved; + } + } + + public static class MetadataResolver + { + /// + /// Implements resolving of TypeReferences to TypeDefinitions as decribed in II.7.3 of ECMA-335 6th edition. + /// + public static TypeDefinition Resolve(TypeReferenceHandle handle, IMetadataResolveContext context) + { + var metadata = context.CurrentModule.GetMetadataReader(); + var tr = metadata.GetTypeReference(handle); + if (tr.ResolutionScope.IsNil) { + foreach (var h in metadata.ExportedTypes) { + var exportedType = metadata.GetExportedType(h); + if (exportedType.Name == tr.Name && exportedType.Namespace == tr.Namespace) { + // TODO + } + } + } + switch (tr.ResolutionScope.Kind) { + case HandleKind.TypeReference: + //return Resolve((TypeReferenceHandle)tr.ResolutionScope, context).GetNestedType(new ); + break; + case HandleKind.ModuleReference: + break; + case HandleKind.AssemblyReference: + var module = context.ResolveAssembly(new AssemblyReference(context.CurrentModule, (AssemblyReferenceHandle)tr.ResolutionScope)); + var moduleMetadata = module.GetMetadataReader(); + var @namespace = ResolveNamespace(moduleMetadata, metadata.GetString(tr.Namespace).Split('.')); + if (@namespace == null) + throw new NotSupportedException(); + var type = FindTypeInNamespace(moduleMetadata, @namespace.Value, metadata.GetString(tr.Name)); + if (type.IsNil) + throw new NotSupportedException(); + return new TypeDefinition(module, type); + } + throw new NotSupportedException(); + } + + static NamespaceDefinition? ResolveNamespace(MetadataReader metadata, string[] namespaceParts) + { + var currentNamespace = metadata.GetNamespaceDefinitionRoot(); + for (int i = 0; i < namespaceParts.Length; i++) { + string identifier = namespaceParts[i]; + var next = currentNamespace.NamespaceDefinitions.FirstOrDefault(ns => metadata.GetString(metadata.GetNamespaceDefinition(ns).Name) == identifier); + if (next.IsNil) + return null; + currentNamespace = metadata.GetNamespaceDefinition(next); + } + return currentNamespace; + } + + static TypeDefinitionHandle FindTypeInNamespace(MetadataReader metadata, NamespaceDefinition @namespace, string name) + { + foreach (var type in @namespace.TypeDefinitions) { + var typeName = metadata.GetString(metadata.GetTypeDefinition(type).Name); + if (name == typeName) + return type; + } + return default(TypeDefinitionHandle); + } + + public static IMemberDefinition Resolve(MemberReferenceHandle handle, IMetadataResolveContext context) + { + var metadata = context.CurrentModule.GetMetadataReader(); + var mr = metadata.GetMemberReference(handle); + TypeDefinition declaringType; + switch (mr.Parent.Kind) { + case HandleKind.TypeDefinition: + declaringType = new TypeDefinition(context.CurrentModule, (TypeDefinitionHandle)mr.Parent); + break; + case HandleKind.TypeReference: + declaringType = Resolve((TypeReferenceHandle)mr.Parent, context); + break; + case HandleKind.TypeSpecification: + case HandleKind.MethodDefinition: + case HandleKind.ModuleReference: + throw new NotImplementedException(); + default: + throw new NotSupportedException(); + } + var name = metadata.GetString(mr.Name); + switch (mr.GetKind()) { + case MemberReferenceKind.Field: + return declaringType.Fields.FirstOrDefault(fd => fd.Name == name); + case MemberReferenceKind.Method: + var signature = mr.DecodeMethodSignature(new TypeSystem.Implementation.TypeReferenceSignatureDecoder(), default(Unit)); + return declaringType.Methods.SingleOrDefault(md => MatchMethodDefinition(name, signature, md)); + } + throw new NotSupportedException(); + } + + static bool MatchMethodDefinition(string name, MethodSignature signature, MethodDefinition md) + { + if (name != md.Name || md.GenericParameters.Count != signature.GenericParameterCount || signature.RequiredParameterCount != md.Parameters.Count) + return false; + // TODO overload resolution... OMG + return true; + } + + public static TypeDefinition Resolve(TypeSpecificationHandle handle, IMetadataResolveContext context) + { + var metadata = context.CurrentModule.GetMetadataReader(); + var ts = metadata.GetTypeSpecification(handle); + var unspecialized = ts.DecodeSignature(new Unspecializer(), default(Unit)); + switch (unspecialized.Kind) { + case HandleKind.TypeDefinition: + return new TypeDefinition(context.CurrentModule, (TypeDefinitionHandle)unspecialized); + case HandleKind.TypeReference: + return Resolve((TypeReferenceHandle)unspecialized, context); + default: + throw new NotImplementedException(); + } + } + + class Unspecializer : ISignatureTypeProvider + { + public EntityHandle GetArrayType(EntityHandle elementType, ArrayShape shape) + { + return elementType; + } + + public EntityHandle GetByReferenceType(EntityHandle elementType) + { + return elementType; + } + + public EntityHandle GetFunctionPointerType(MethodSignature signature) + { + throw new NotImplementedException(); + } + + public EntityHandle GetGenericInstantiation(EntityHandle genericType, ImmutableArray typeArguments) + { + return genericType; + } + + public EntityHandle GetGenericMethodParameter(Unit genericContext, int index) + { + return MetadataTokens.EntityHandle(0); + } + + public EntityHandle GetGenericTypeParameter(Unit genericContext, int index) + { + return MetadataTokens.EntityHandle(0); + } + + public EntityHandle GetModifiedType(EntityHandle modifier, EntityHandle unmodifiedType, bool isRequired) + { + return unmodifiedType; + } + + public EntityHandle GetPinnedType(EntityHandle elementType) + { + return elementType; + } + + public EntityHandle GetPointerType(EntityHandle elementType) + { + return elementType; + } + + public EntityHandle GetPrimitiveType(PrimitiveTypeCode typeCode) + { + throw new NotImplementedException(); + } + + public EntityHandle GetSZArrayType(EntityHandle elementType) + { + throw new NotImplementedException(); + } + + public EntityHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) + { + return handle; + } + + public EntityHandle GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) + { + return handle; + } + + public EntityHandle GetTypeFromSpecification(MetadataReader reader, Unit genericContext, TypeSpecificationHandle handle, byte rawTypeKind) + { + return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext); + } + } + } +} diff --git a/ICSharpCode.Decompiler/Dom/SequencePoint.cs b/ICSharpCode.Decompiler/Dom/SequencePoint.cs new file mode 100644 index 000000000..d1a4e7923 --- /dev/null +++ b/ICSharpCode.Decompiler/Dom/SequencePoint.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Text; + +namespace ICSharpCode.Decompiler.Dom +{ + using SRMDocument = System.Reflection.Metadata.Document; + + /// + /// A sequence point read from a PDB file or produced by the decompiler. + /// + public struct SequencePoint + { + /// + /// IL start offset. + /// + public int Offset { get; set; } + + /// + /// IL end offset. + /// + /// + /// This does not get stored in debug information; + /// it is used internally to create hidden sequence points + /// for the IL fragments not covered by any sequence point. + /// + public int EndOffset { get; set; } + + public int StartLine { get; set; } + public int StartColumn { get; set; } + public int EndLine { get; set; } + public int EndColumn { get; set; } + + public bool IsHidden { + get { return StartLine == 0xfeefee && StartLine == EndLine; } + } + + public Document Document { get; set; } + + internal void SetHidden() + { + StartLine = EndLine = 0xfeefee; + } + } + + public struct Document : IEquatable + { + public PEFile Module { get; } + public DocumentHandle Handle { get; } + public bool IsNil => Handle.IsNil; + + public Document(PEFile module, DocumentHandle handle) : this() + { + this.Module = module ?? throw new ArgumentNullException(nameof(module)); + this.Handle = handle; + } + + SRMDocument This() => Module.GetMetadataReader().GetDocument(Handle); + + public bool Equals(Document other) + { + return Module == other.Module && Handle == other.Handle; + } + + public override bool Equals(object obj) + { + if (obj is Document md) + return Equals(md); + return false; + } + + public override int GetHashCode() + { + return unchecked(982451629 * Module.GetHashCode() + 982451653 * MetadataTokens.GetToken(Handle)); + } + + public static bool operator ==(Document lhs, Document rhs) => lhs.Equals(rhs); + public static bool operator !=(Document lhs, Document rhs) => !lhs.Equals(rhs); + + public string Url { + get { + if (Handle.IsNil) + return null; + var h = This().Name; + if (h.IsNil) return null; + return Module.GetMetadataReader().GetString(h); + } + } + } +} diff --git a/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs b/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs index 8ff093c1d..270f05f1b 100644 --- a/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs +++ b/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs @@ -5,8 +5,8 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; +using ICSharpCode.Decompiler.Dom; using LightJson.Serialization; -using Mono.Cecil; namespace ICSharpCode.Decompiler { @@ -70,7 +70,7 @@ namespace ICSharpCode.Decompiler } } - public string TryResolveDotNetCore(AssemblyNameReference name) + public string TryResolveDotNetCore(IAssemblyReference name) { foreach (var basePath in packageBasePaths) { if (File.Exists(Path.Combine(basePath, name.Name + ".dll"))) { @@ -106,7 +106,7 @@ namespace ICSharpCode.Decompiler } } - string FallbackToDotNetSharedDirectory(AssemblyNameReference name, Version version) + string FallbackToDotNetSharedDirectory(IAssemblyReference name, Version version) { if (dotnetBasePath == null) return null; var basePath = Path.Combine(dotnetBasePath, "shared", "Microsoft.NETCore.App"); diff --git a/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs b/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs index 7fb8f2561..0d66dd570 100644 --- a/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs +++ b/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs @@ -1,26 +1,28 @@ using System; using System.Collections.Generic; using System.Linq; -using ICSharpCode.Decompiler.TypeSystem.Implementation; -using Mono.Cecil; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; namespace ICSharpCode.Decompiler { public static class DotNetCorePathFinderExtensions { - public static string DetectTargetFrameworkId(this AssemblyDefinition assembly) + public static string DetectTargetFrameworkId(this PEReader assembly) { if (assembly == null) throw new ArgumentNullException(nameof(assembly)); const string TargetFrameworkAttributeName = "System.Runtime.Versioning.TargetFrameworkAttribute"; + var reader = assembly.GetMetadataReader(); - foreach (var attribute in assembly.CustomAttributes) { - if (attribute.AttributeType.FullName != TargetFrameworkAttributeName) + foreach (var h in reader.GetCustomAttributes(Handle.AssemblyDefinition)) { + var attribute = reader.GetCustomAttribute(h); + if (attribute.GetAttributeType(reader).ToString() != TargetFrameworkAttributeName) continue; - var blobReader = new BlobReader(attribute.GetBlob(), null); + var blobReader = reader.GetBlobReader(attribute.Value); if (blobReader.ReadUInt16() == 0x0001) { - return blobReader.ReadSerString(); + return blobReader.ReadSerializedString(); } } diff --git a/ICSharpCode.Decompiler/DotNetCore/UniversalAssemblyResolver.cs b/ICSharpCode.Decompiler/DotNetCore/UniversalAssemblyResolver.cs index a1d70d762..bcf7c4732 100644 --- a/ICSharpCode.Decompiler/DotNetCore/UniversalAssemblyResolver.cs +++ b/ICSharpCode.Decompiler/DotNetCore/UniversalAssemblyResolver.cs @@ -1,9 +1,10 @@ using System; using System.Collections.Generic; using System.IO; +using System.Reflection.PortableExecutable; using System.Text; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.Decompiler.Util; -using Mono.Cecil; namespace ICSharpCode.Decompiler { @@ -58,26 +59,18 @@ namespace ICSharpCode.Decompiler AddSearchDirectory(baseDirectory); } - public static ModuleDefinition LoadMainModule(string mainAssemblyFileName, bool throwOnError = true, bool inMemory = false) + public static PEFile LoadMainModule(string mainAssemblyFileName, bool throwOnError = true, bool inMemory = false) { var resolver = new UniversalAssemblyResolver(mainAssemblyFileName, throwOnError); - var module = ModuleDefinition.ReadModule(mainAssemblyFileName, new ReaderParameters { - AssemblyResolver = resolver, - InMemory = inMemory - }); + var module = new PEReader(new FileStream(mainAssemblyFileName, FileMode.Open)); - resolver.TargetFramework = module.Assembly.DetectTargetFrameworkId(); + resolver.TargetFramework = module.DetectTargetFrameworkId(); - return module; + return new PEFile(mainAssemblyFileName, module, resolver); } - public AssemblyDefinition Resolve(AssemblyNameReference name) - { - return Resolve(name, new ReaderParameters()); - } - - public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters) + public PEFile Resolve(IAssemblyReference name) { var file = FindAssemblyFile(name); if (file == null) { @@ -85,10 +78,10 @@ namespace ICSharpCode.Decompiler throw new AssemblyResolutionException(name); return null; } - return GetAssembly(file, parameters); + return new PEFile(file, GetAssembly(file), this); } - public string FindAssemblyFile(AssemblyNameReference name) + public string FindAssemblyFile(IAssemblyReference name) { var targetFramework = TargetFramework.Split(new[] { ",Version=v" }, StringSplitOptions.None); string file = null; @@ -110,28 +103,21 @@ namespace ICSharpCode.Decompiler } } - string ResolveInternal(AssemblyNameReference name) + string ResolveInternal(IAssemblyReference name) { - if (name == null) + if (name.IsNil()) throw new ArgumentNullException(nameof(name)); var assembly = SearchDirectory(name, directories); if (assembly != null) return assembly; - if (name.IsRetargetable) { - // if the reference is retargetable, zero it - name = new AssemblyNameReference(name.Name, ZeroVersion) { - PublicKeyToken = Empty.Array, - }; - } - var framework_dir = Path.GetDirectoryName(typeof(object).Module.FullyQualifiedName); var framework_dirs = DetectMono() ? new[] { framework_dir, Path.Combine(framework_dir, "Facades") } : new[] { framework_dir }; - if (IsZero(name.Version)) { + if (IsZeroVersionOrRetargetable(name)) { assembly = SearchDirectory(name, framework_dirs); if (assembly != null) return assembly; @@ -157,7 +143,7 @@ namespace ICSharpCode.Decompiler } #region .NET / mono GAC handling - string SearchDirectory(AssemblyNameReference name, IEnumerable directories) + string SearchDirectory(IAssemblyReference name, IEnumerable directories) { var extensions = name.IsWindowsRuntime ? new[] { ".winmd", ".dll" } : new[] { ".exe", ".dll" }; foreach (var directory in directories) { @@ -176,19 +162,22 @@ namespace ICSharpCode.Decompiler return null; } + static bool IsZeroVersionOrRetargetable(IAssemblyReference reference) + { + return IsZero(reference.Version) || reference.IsRetargetable; + } + static bool IsZero(Version version) { return version.Major == 0 && version.Minor == 0 && version.Build == 0 && version.Revision == 0; } - static Version ZeroVersion = new Version(0, 0, 0, 0); - - string GetCorlib(AssemblyNameReference reference) + string GetCorlib(IAssemblyReference reference) { var version = reference.Version; var corlib = typeof(object).Assembly.GetName(); - if (corlib.Version == version || IsZero(version)) + if (corlib.Version == version || IsZeroVersionOrRetargetable(reference)) return typeof(object).Module.FullyQualifiedName; var path = Directory.GetParent( @@ -286,15 +275,12 @@ namespace ICSharpCode.Decompiler "gac"); } - AssemblyDefinition GetAssembly(string file, ReaderParameters parameters) + PEReader GetAssembly(string file) { - if (parameters.AssemblyResolver == null) - parameters.AssemblyResolver = this; - - return ModuleDefinition.ReadModule(file, parameters).Assembly; + return new PEReader(new FileStream(file, FileMode.Open)); } - string GetAssemblyInGac(AssemblyNameReference reference) + string GetAssemblyInGac(IAssemblyReference reference) { if (reference.PublicKeyToken == null || reference.PublicKeyToken.Length == 0) return null; @@ -305,7 +291,7 @@ namespace ICSharpCode.Decompiler return GetAssemblyInNetGac(reference); } - string GetAssemblyInMonoGac(AssemblyNameReference reference) + string GetAssemblyInMonoGac(IAssemblyReference reference) { for (int i = 0; i < gac_paths.Count; i++) { var gac_path = gac_paths[i]; @@ -317,7 +303,7 @@ namespace ICSharpCode.Decompiler return null; } - string GetAssemblyInNetGac(AssemblyNameReference reference) + string GetAssemblyInNetGac(IAssemblyReference reference) { var gacs = new[] { "GAC_MSIL", "GAC_32", "GAC_64", "GAC" }; var prefixes = new[] { string.Empty, "v4.0_" }; @@ -334,7 +320,7 @@ namespace ICSharpCode.Decompiler return null; } - static string GetAssemblyFile(AssemblyNameReference reference, string prefix, string gac) + static string GetAssemblyFile(IAssemblyReference reference, string prefix, string gac) { var gac_folder = new StringBuilder() .Append(prefix) diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 00f22d083..b6307ff1e 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -268,6 +268,8 @@ + + @@ -275,6 +277,8 @@ + + @@ -292,7 +296,7 @@ - + @@ -326,7 +330,7 @@ - + diff --git a/ICSharpCode.Decompiler/IL/ILOpCodes.cs b/ICSharpCode.Decompiler/IL/ILOpCodes.cs index c7f772e91..d16adb34c 100644 --- a/ICSharpCode.Decompiler/IL/ILOpCodes.cs +++ b/ICSharpCode.Decompiler/IL/ILOpCodes.cs @@ -17,247 +17,120 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Reflection.Emit; +using System.Collections.Generic; +using System.Reflection.Metadata; namespace ICSharpCode.Decompiler.IL { - enum ILOpCode : ushort + /// Describes the operand type of Microsoft intermediate language (MSIL) instruction. + public enum OperandType { - Nop = 0x00, - Break = 0x01, - Ldarg_0 = 0x02, - Ldarg_1 = 0x03, - Ldarg_2 = 0x04, - Ldarg_3 = 0x05, - Ldloc_0 = 0x06, - Ldloc_1 = 0x07, - Ldloc_2 = 0x08, - Ldloc_3 = 0x09, - Stloc_0 = 0x0a, - Stloc_1 = 0x0b, - Stloc_2 = 0x0c, - Stloc_3 = 0x0d, - Ldarg_S = 0x0e, - Ldarga_S = 0x0f, - Starg_S = 0x10, - Ldloc_S = 0x11, - Ldloca_S = 0x12, - Stloc_S = 0x13, - Ldnull = 0x14, - Ldc_I4_M1 = 0x15, - Ldc_I4_0 = 0x16, - Ldc_I4_1 = 0x17, - Ldc_I4_2 = 0x18, - Ldc_I4_3 = 0x19, - Ldc_I4_4 = 0x1a, - Ldc_I4_5 = 0x1b, - Ldc_I4_6 = 0x1c, - Ldc_I4_7 = 0x1d, - Ldc_I4_8 = 0x1e, - Ldc_I4_S = 0x1f, - Ldc_I4 = 0x20, - Ldc_I8 = 0x21, - Ldc_R4 = 0x22, - Ldc_R8 = 0x23, - Dup = 0x25, - Pop = 0x26, - Jmp = 0x27, - Call = 0x28, - Calli = 0x29, - Ret = 0x2a, - Br_S = 0x2b, - Brfalse_S = 0x2c, - Brtrue_S = 0x2d, - Beq_S = 0x2e, - Bge_S = 0x2f, - Bgt_S = 0x30, - Ble_S = 0x31, - Blt_S = 0x32, - Bne_Un_S = 0x33, - Bge_Un_S = 0x34, - Bgt_Un_S = 0x35, - Ble_Un_S = 0x36, - Blt_Un_S = 0x37, - Br = 0x38, - Brfalse = 0x39, - Brtrue = 0x3a, - Beq = 0x3b, - Bge = 0x3c, - Bgt = 0x3d, - Ble = 0x3e, - Blt = 0x3f, - Bne_Un = 0x40, - Bge_Un = 0x41, - Bgt_Un = 0x42, - Ble_Un = 0x43, - Blt_Un = 0x44, - Switch = 0x45, - Ldind_I1 = 0x46, - Ldind_U1 = 0x47, - Ldind_I2 = 0x48, - Ldind_U2 = 0x49, - Ldind_I4 = 0x4a, - Ldind_U4 = 0x4b, - Ldind_I8 = 0x4c, - Ldind_I = 0x4d, - Ldind_R4 = 0x4e, - Ldind_R8 = 0x4f, - Ldind_Ref = 0x50, - Stind_Ref = 0x51, - Stind_I1 = 0x52, - Stind_I2 = 0x53, - Stind_I4 = 0x54, - Stind_I8 = 0x55, - Stind_R4 = 0x56, - Stind_R8 = 0x57, - Add = 0x58, - Sub = 0x59, - Mul = 0x5a, - Div = 0x5b, - Div_Un = 0x5c, - Rem = 0x5d, - Rem_Un = 0x5e, - And = 0x5f, - Or = 0x60, - Xor = 0x61, - Shl = 0x62, - Shr = 0x63, - Shr_Un = 0x64, - Neg = 0x65, - Not = 0x66, - Conv_I1 = 0x67, - Conv_I2 = 0x68, - Conv_I4 = 0x69, - Conv_I8 = 0x6a, - Conv_R4 = 0x6b, - Conv_R8 = 0x6c, - Conv_U4 = 0x6d, - Conv_U8 = 0x6e, - Callvirt = 0x6f, - Cpobj = 0x70, - Ldobj = 0x71, - Ldstr = 0x72, - Newobj = 0x73, - Castclass = 0x74, - Isinst = 0x75, - Conv_R_Un = 0x76, - Unbox = 0x79, - Throw = 0x7a, - Ldfld = 0x7b, - Ldflda = 0x7c, - Stfld = 0x7d, - Ldsfld = 0x7e, - Ldsflda = 0x7f, - Stsfld = 0x80, - Stobj = 0x81, - Conv_Ovf_I1_Un = 0x82, - Conv_Ovf_I2_Un = 0x83, - Conv_Ovf_I4_Un = 0x84, - Conv_Ovf_I8_Un = 0x85, - Conv_Ovf_U1_Un = 0x86, - Conv_Ovf_U2_Un = 0x87, - Conv_Ovf_U4_Un = 0x88, - Conv_Ovf_U8_Un = 0x89, - Conv_Ovf_I_Un = 0x8a, - Conv_Ovf_U_Un = 0x8b, - Box = 0x8c, - Newarr = 0x8d, - Ldlen = 0x8e, - Ldelema = 0x8f, - Ldelem_I1 = 0x90, - Ldelem_U1 = 0x91, - Ldelem_I2 = 0x92, - Ldelem_U2 = 0x93, - Ldelem_I4 = 0x94, - Ldelem_U4 = 0x95, - Ldelem_I8 = 0x96, - Ldelem_I = 0x97, - Ldelem_R4 = 0x98, - Ldelem_R8 = 0x99, - Ldelem_Ref = 0x9a, - Stelem_I = 0x9b, - Stelem_I1 = 0x9c, - Stelem_I2 = 0x9d, - Stelem_I4 = 0x9e, - Stelem_I8 = 0x9f, - Stelem_R4 = 0xa0, - Stelem_R8 = 0xa1, - Stelem_Ref = 0xa2, - Ldelem = 0xa3, - Stelem = 0xa4, - Unbox_Any = 0xa5, - Conv_Ovf_I1 = 0xb3, - Conv_Ovf_U1 = 0xb4, - Conv_Ovf_I2 = 0xb5, - Conv_Ovf_U2 = 0xb6, - Conv_Ovf_I4 = 0xb7, - Conv_Ovf_U4 = 0xb8, - Conv_Ovf_I8 = 0xb9, - Conv_Ovf_U8 = 0xba, - Refanyval = 0xc2, - Ckfinite = 0xc3, - Mkrefany = 0xc6, - Ldtoken = 0xd0, - Conv_U2 = 0xd1, - Conv_U1 = 0xd2, - Conv_I = 0xd3, - Conv_Ovf_I = 0xd4, - Conv_Ovf_U = 0xd5, - Add_Ovf = 0xd6, - Add_Ovf_Un = 0xd7, - Mul_Ovf = 0xd8, - Mul_Ovf_Un = 0xd9, - Sub_Ovf = 0xda, - Sub_Ovf_Un = 0xdb, - Endfinally = 0xdc, - Leave = 0xdd, - Leave_S = 0xde, - Stind_I = 0xdf, - Conv_U = 0xe0, - Prefix7 = 0xf8, - Prefix6 = 0xf9, - Prefix5 = 0xfa, - Prefix4 = 0xfb, - Prefix3 = 0xfc, - Prefix2 = 0xfd, - Prefix1 = 0xfe, - Prefixref = 0xff, - Arglist = 0x100, - Ceq = 0x101, - Cgt = 0x102, - Cgt_Un = 0x103, - Clt = 0x104, - Clt_Un = 0x105, - Ldftn = 0x106, - Ldvirtftn = 0x107, - Ldarg = 0x109, - Ldarga = 0x10a, - Starg = 0x10b, - Ldloc = 0x10c, - Ldloca = 0x10d, - Stloc = 0x10e, - Localloc = 0x10f, - Endfilter = 0x111, - Unaligned = 0x112, - Volatile = 0x113, - Tailcall = 0x114, - Initobj = 0x115, - Constrained = 0x116, - Cpblk = 0x117, - Initblk = 0x118, - Rethrow = 0x11a, - Sizeof = 0x11c, - Refanytype = 0x11d, - Readonly = 0x11e, + /// The operand is a 32-bit integer branch target. + BrTarget, + /// The operand is a 32-bit metadata token. + Field, + /// The operand is a 32-bit integer. + I, + /// The operand is a 64-bit integer. + I8, + /// The operand is a 32-bit metadata token. + Method, + /// No operand. + None, + /// The operand is reserved and should not be used. + [Obsolete("This API has been deprecated. http://go.microsoft.com/fwlink/?linkid=14202")] + Phi, + /// The operand is a 64-bit IEEE floating point number. + R, + /// The operand is a 32-bit metadata signature token. + Sig = 9, + /// The operand is a 32-bit metadata string token. + String, + /// The operand is the 32-bit integer argument to a switch instruction. + Switch, + /// The operand is a , , or token. + Tok, + /// The operand is a 32-bit metadata token. + Type, + /// The operand is 16-bit integer containing the ordinal of a local variable or an argument. + Variable, + /// The operand is an 8-bit integer branch target. + ShortBrTarget, + /// The operand is an 8-bit integer. + ShortI, + /// The operand is a 32-bit IEEE floating point number. + ShortR, + /// The operand is an 8-bit integer containing the ordinal of a local variable or an argumenta. + ShortVariable } - static class ILOpCodeExtensions + + public static class ILOpCodeExtensions { // We use a byte array instead of an enum array because it can be initialized more efficiently - static readonly byte[] operandTypes = { (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.ShortVariable, (byte)OperandType.ShortVariable, (byte)OperandType.ShortVariable, (byte)OperandType.ShortVariable, (byte)OperandType.ShortVariable, (byte)OperandType.ShortVariable, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.ShortI, (byte)OperandType.I, (byte)OperandType.I8, (byte)OperandType.ShortR, (byte)OperandType.R, (byte)OperandType.BrTarget, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.Method, (byte)OperandType.Method, (byte)OperandType.Sig, (byte)OperandType.None, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.Switch, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.Method, (byte)OperandType.Type, (byte)OperandType.Type, (byte)OperandType.String, (byte)OperandType.Method, (byte)OperandType.Type, (byte)OperandType.Type, (byte)OperandType.None, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.Type, (byte)OperandType.None, (byte)OperandType.Field, (byte)OperandType.Field, (byte)OperandType.Field, (byte)OperandType.Field, (byte)OperandType.Field, (byte)OperandType.Field, (byte)OperandType.Type, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.Type, (byte)OperandType.Type, (byte)OperandType.None, (byte)OperandType.Type, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.Type, (byte)OperandType.Type, (byte)OperandType.Type, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.Type, (byte)OperandType.None, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.Type, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.Tok, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.BrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.Method, (byte)OperandType.Method, (byte)OperandType.BrTarget, (byte)OperandType.Variable, (byte)OperandType.Variable, (byte)OperandType.Variable, (byte)OperandType.Variable, (byte)OperandType.Variable, (byte)OperandType.Variable, (byte)OperandType.None, (byte)OperandType.BrTarget, (byte)OperandType.None, (byte)OperandType.ShortI, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.Type, (byte)OperandType.Type, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.BrTarget, (byte)OperandType.None, (byte)OperandType.BrTarget, (byte)OperandType.Type, (byte)OperandType.None, (byte)OperandType.None, }; + static readonly byte[] operandTypes = { (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.ShortVariable, (byte)OperandType.ShortVariable, (byte)OperandType.ShortVariable, (byte)OperandType.ShortVariable, (byte)OperandType.ShortVariable, (byte)OperandType.ShortVariable, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.ShortI, (byte)OperandType.I, (byte)OperandType.I8, (byte)OperandType.ShortR, (byte)OperandType.R, 255, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.Method, (byte)OperandType.Method, (byte)OperandType.Sig, (byte)OperandType.None, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.BrTarget, (byte)OperandType.Switch, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.Method, (byte)OperandType.Type, (byte)OperandType.Type, (byte)OperandType.String, (byte)OperandType.Method, (byte)OperandType.Type, (byte)OperandType.Type, (byte)OperandType.None, 255, 255, (byte)OperandType.Type, (byte)OperandType.None, (byte)OperandType.Field, (byte)OperandType.Field, (byte)OperandType.Field, (byte)OperandType.Field, (byte)OperandType.Field, (byte)OperandType.Field, (byte)OperandType.Type, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.Type, (byte)OperandType.Type, (byte)OperandType.None, (byte)OperandType.Type, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.Type, (byte)OperandType.Type, (byte)OperandType.Type, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, 255, 255, 255, 255, 255, 255, 255, (byte)OperandType.Type, (byte)OperandType.None, 255, 255, (byte)OperandType.Type, 255, 255, 255, 255, 255, 255, 255, 255, 255, (byte)OperandType.Tok, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.BrTarget, (byte)OperandType.ShortBrTarget, (byte)OperandType.None, (byte)OperandType.None, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.Method, (byte)OperandType.Method, 255, (byte)OperandType.Variable, (byte)OperandType.Variable, (byte)OperandType.Variable, (byte)OperandType.Variable, (byte)OperandType.Variable, (byte)OperandType.Variable, (byte)OperandType.None, 255, (byte)OperandType.None, (byte)OperandType.ShortI, (byte)OperandType.None, (byte)OperandType.None, (byte)OperandType.Type, (byte)OperandType.Type, (byte)OperandType.None, (byte)OperandType.None, 255, (byte)OperandType.None, 255, (byte)OperandType.Type, (byte)OperandType.None, (byte)OperandType.None, }; + + static readonly string[] operandNames = { "nop", "break", "ldarg.0", "ldarg.1", "ldarg.2", "ldarg.3", "ldloc.0", "ldloc.1", "ldloc.2", "ldloc.3", "stloc.0", "stloc.1", "stloc.2", "stloc.3", "ldarg.s", "ldarga.s", "starg.s", "ldloc.s", "ldloca.s", "stloc.s", "ldnull", "ldc.i4.m1", "ldc.i4.0", "ldc.i4.1", "ldc.i4.2", "ldc.i4.3", "ldc.i4.4", "ldc.i4.5", "ldc.i4.6", "ldc.i4.7", "ldc.i4.8", "ldc.i4.s", "ldc.i4", "ldc.i8", "ldc.r4", "ldc.r8", "", "dup", "pop", "jmp", "call", "calli", "ret", "br.s", "brfalse.s", "brtrue.s", "beq.s", "bge.s", "bgt.s", "ble.s", "blt.s", "bne.un.s", "bge.un.s", "bgt.un.s", "ble.un.s", "blt.un.s", "br", "brfalse", "brtrue", "beq", "bge", "bgt", "ble", "blt", "bne.un", "bge.un", "bgt.un", "ble.un", "blt.un", "switch", "ldind.i1", "ldind.u1", "ldind.i2", "ldind.u2", "ldind.i4", "ldind.u4", "ldind.i8", "ldind.i", "ldind.r4", "ldind.r8", "ldind.ref", "stind.ref", "stind.i1", "stind.i2", "stind.i4", "stind.i8", "stind.r4", "stind.r8", "add", "sub", "mul", "div", "div.un", "rem", "rem.un", "and", "or", "xor", "shl", "shr", "shr.un", "neg", "not", "conv.i1", "conv.i2", "conv.i4", "conv.i8", "conv.r4", "conv.r8", "conv.u4", "conv.u8", "callvirt", "cpobj", "ldobj", "ldstr", "newobj", "castclass", "isinst", "conv.r.un", "", "", "unbox", "throw", "ldfld", "ldflda", "stfld", "ldsfld", "ldsflda", "stsfld", "stobj", "conv.ovf.i1.un", "conv.ovf.i2.un", "conv.ovf.i4.un", "conv.ovf.i8.un", "conv.ovf.u1.un", "conv.ovf.u2.un", "conv.ovf.u4.un", "conv.ovf.u8.un", "conv.ovf.i.un", "conv.ovf.u.un", "box", "newarr", "ldlen", "ldelema", "ldelem.i1", "ldelem.u1", "ldelem.i2", "ldelem.u2", "ldelem.i4", "ldelem.u4", "ldelem.i8", "ldelem.i", "ldelem.r4", "ldelem.r8", "ldelem.ref", "stelem.i", "stelem.i1", "stelem.i2", "stelem.i4", "stelem.i8", "stelem.r4", "stelem.r8", "stelem.ref", "ldelem", "stelem", "unbox.any", "", "", "", "", "", "", "", "", "", "", "", "", "", "conv.ovf.i1", "conv.ovf.u1", "conv.ovf.i2", "conv.ovf.u2", "conv.ovf.i4", "conv.ovf.u4", "conv.ovf.i8", "conv.ovf.u8", "", "", "", "", "", "", "", "refanyval", "ckfinite", "", "", "mkrefany", "", "", "", "", "", "", "", "", "", "ldtoken", "conv.u2", "conv.u1", "conv.i", "conv.ovf.i", "conv.ovf.u", "add.ovf", "add.ovf.un", "mul.ovf", "mul.ovf.un", "sub.ovf", "sub.ovf.un", "endfinally", "leave", "leave.s", "stind.i", "conv.u", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "prefix7", "prefix6", "prefix5", "prefix4", "prefix3", "prefix2", "prefix1", "prefixref", "arglist", "ceq", "cgt", "cgt.un", "clt", "clt.un", "ldftn", "ldvirtftn", "", "ldarg", "ldarga", "starg", "ldloc", "ldloca", "stloc", "localloc", "", "endfilter", "unaligned.", "volatile.", "tail.", "initobj", "constrained.", "cpblk", "initblk", "", "rethrow", "", "sizeof", "refanytype", "readonly.", }; public static OperandType GetOperandType(this ILOpCode opCode) { - return (OperandType)operandTypes[(ushort)opCode]; + ushort index = (ushort)((((int)opCode & 0x200) >> 1) | ((int)opCode & 0xff)); + if (index >= operandTypes.Length) + return (OperandType)255; + return (OperandType)operandTypes[index]; + } + + public static string GetDisplayName(this ILOpCode opCode) + { + ushort index = (ushort)((((int)opCode & 0x200) >> 1) | ((int)opCode & 0xff)); + if (index >= operandNames.Length) + return ""; + return operandNames[index]; + } + + public static bool IsDefined(this ILOpCode opCode) + { + return !string.IsNullOrEmpty(GetDisplayName(opCode)); + } + + public static readonly HashSet ILKeywords = BuildKeywordList( + "abstract", "algorithm", "alignment", "ansi", "any", "arglist", + "array", "as", "assembly", "assert", "at", "auto", "autochar", "beforefieldinit", + "blob", "blob_object", "bool", "brnull", "brnull.s", "brzero", "brzero.s", "bstr", + "bytearray", "byvalstr", "callmostderived", "carray", "catch", "cdecl", "cf", + "char", "cil", "class", "clsid", "const", "currency", "custom", "date", "decimal", + "default", "demand", "deny", "endmac", "enum", "error", "explicit", "extends", "extern", + "false", "famandassem", "family", "famorassem", "fastcall", "fault", "field", "filetime", + "filter", "final", "finally", "fixed", "float", "float32", "float64", "forwardref", + "fromunmanaged", "handler", "hidebysig", "hresult", "idispatch", "il", "illegal", + "implements", "implicitcom", "implicitres", "import", "in", "inheritcheck", "init", + "initonly", "instance", "int", "int16", "int32", "int64", "int8", "interface", "internalcall", + "iunknown", "lasterr", "lcid", "linkcheck", "literal", "localloc", "lpstr", "lpstruct", "lptstr", + "lpvoid", "lpwstr", "managed", "marshal", "method", "modopt", "modreq", "native", "nested", + "newslot", "noappdomain", "noinlining", "nomachine", "nomangle", "nometadata", "noncasdemand", + "noncasinheritance", "noncaslinkdemand", "noprocess", "not", "not_in_gc_heap", "notremotable", + "notserialized", "null", "nullref", "object", "objectref", "opt", "optil", "out", + "permitonly", "pinned", "pinvokeimpl", "prefix1", "prefix2", "prefix3", "prefix4", "prefix5", "prefix6", + "prefix7", "prefixref", "prejitdeny", "prejitgrant", "preservesig", "private", "privatescope", "protected", + "public", "record", "refany", "reqmin", "reqopt", "reqrefuse", "reqsecobj", "request", "retval", + "rtspecialname", "runtime", "safearray", "sealed", "sequential", "serializable", "special", "specialname", + "static", "stdcall", "storage", "stored_object", "stream", "streamed_object", "string", "struct", + "synchronized", "syschar", "sysstring", "tbstr", "thiscall", "tls", "to", "true", "typedref", + "unicode", "unmanaged", "unmanagedexp", "unsigned", "unused", "userdefined", "value", "valuetype", + "vararg", "variant", "vector", "virtual", "void", "wchar", "winapi", "with", "wrapper", + + // These are not listed as keywords in spec, but ILAsm treats them as such + "property", "type", "flags", "callconv", "strict" + ); + + static HashSet BuildKeywordList(params string[] keywords) + { + HashSet s = new HashSet(keywords); + foreach (var inst in operandNames) { + if (string.IsNullOrEmpty(inst)) + continue; + s.Add(inst); + } + return s; } } } diff --git a/ICSharpCode.Decompiler/IL/ILOpCodes.tt b/ICSharpCode.Decompiler/IL/ILOpCodes.tt index 9dc485b87..50e7e3dfd 100644 --- a/ICSharpCode.Decompiler/IL/ILOpCodes.tt +++ b/ICSharpCode.Decompiler/IL/ILOpCodes.tt @@ -21,40 +21,148 @@ <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.Reflection.Metadata" #> <#@ import namespace="System.Reflection.Emit" #> <#@ output extension=".cs" #> using System; -using System.Reflection.Emit; +using System.Collections.Generic; +using System.Reflection.Metadata; <# - var operandTypes = new OperandType[0x11f]; - + var operandTypes = Enumerable.Repeat((OperandType)0xff, 0x11f).ToArray(); + var operandNames = new string[0x11f]; #> namespace ICSharpCode.Decompiler.IL { - enum ILOpCode : ushort + /// Describes the operand type of Microsoft intermediate language (MSIL) instruction. + public enum OperandType { -<# foreach (var field in typeof(OpCodes).GetFields()) { - var opCode = (OpCode)field.GetValue(null); - ushort val = (ushort)(((opCode.Value & 0x200) >> 1) | (opCode.Value & 0xff)); - operandTypes[val] = opCode.OperandType; -#> - <#=field.Name#> = 0x<#=val.ToString("x2")#>, -<# } // end foreach #> + /// The operand is a 32-bit integer branch target. + BrTarget, + /// The operand is a 32-bit metadata token. + Field, + /// The operand is a 32-bit integer. + I, + /// The operand is a 64-bit integer. + I8, + /// The operand is a 32-bit metadata token. + Method, + /// No operand. + None, + /// The operand is reserved and should not be used. + [Obsolete("This API has been deprecated. http://go.microsoft.com/fwlink/?linkid=14202")] + Phi, + /// The operand is a 64-bit IEEE floating point number. + R, + /// The operand is a 32-bit metadata signature token. + Sig = 9, + /// The operand is a 32-bit metadata string token. + String, + /// The operand is the 32-bit integer argument to a switch instruction. + Switch, + /// The operand is a , , or token. + Tok, + /// The operand is a 32-bit metadata token. + Type, + /// The operand is 16-bit integer containing the ordinal of a local variable or an argument. + Variable, + /// The operand is an 8-bit integer branch target. + ShortBrTarget, + /// The operand is an 8-bit integer. + ShortI, + /// The operand is a 32-bit IEEE floating point number. + ShortR, + /// The operand is an 8-bit integer containing the ordinal of a local variable or an argumenta. + ShortVariable } +<# + foreach (var field in typeof(OpCodes).GetFields()) { + var opCode = (OpCode)field.GetValue(null); + ushort index = (ushort)(((opCode.Value & 0x200) >> 1) | (opCode.Value & 0xff)); + operandTypes[index] = opCode.OperandType; + operandNames[index] = opCode.Name; + } #> + static class ILOpCodeExtensions { // We use a byte array instead of an enum array because it can be initialized more efficiently static readonly byte[] operandTypes = { <# foreach (var operandType in operandTypes) { - string operandTypeName = operandType.ToString().Replace("Inline", "").Replace("Var", "Variable"); - Write("(byte)OperandType." + operandTypeName + ", "); + if ((byte)operandType == 255) { + Write("255, "); + } else { + string operandTypeName = operandType.ToString().Replace("Inline", "").Replace("Var", "Variable"); + Write("(byte)OperandType." + operandTypeName + ", "); + } + } + #> }; + + static readonly string[] operandNames = { <# + foreach (var operandName in operandNames) { + Write("\"" + operandName + "\", "); } #> }; public static OperandType GetOperandType(this ILOpCode opCode) { - return (OperandType)operandTypes[(ushort)opCode]; + ushort index = (ushort)((((int)opCode & 0x200) >> 1) | ((int)opCode & 0xff)); + if (index >= operandTypes.Length) + return (OperandType)255; + return (OperandType)operandTypes[index]; + } + + public static string GetDisplayName(this ILOpCode opCode) + { + ushort index = (ushort)((((int)opCode & 0x200) >> 1) | ((int)opCode & 0xff)); + if (index >= operandNames.Length) + return ""; + return operandNames[index]; + } + + public static bool IsDefined(this ILOpCode opCode) + { + return !string.IsNullOrEmpty(GetDisplayName(opCode)); + } + + public static readonly HashSet ILKeywords = BuildKeywordList( + "abstract", "algorithm", "alignment", "ansi", "any", "arglist", + "array", "as", "assembly", "assert", "at", "auto", "autochar", "beforefieldinit", + "blob", "blob_object", "bool", "brnull", "brnull.s", "brzero", "brzero.s", "bstr", + "bytearray", "byvalstr", "callmostderived", "carray", "catch", "cdecl", "cf", + "char", "cil", "class", "clsid", "const", "currency", "custom", "date", "decimal", + "default", "demand", "deny", "endmac", "enum", "error", "explicit", "extends", "extern", + "false", "famandassem", "family", "famorassem", "fastcall", "fault", "field", "filetime", + "filter", "final", "finally", "fixed", "float", "float32", "float64", "forwardref", + "fromunmanaged", "handler", "hidebysig", "hresult", "idispatch", "il", "illegal", + "implements", "implicitcom", "implicitres", "import", "in", "inheritcheck", "init", + "initonly", "instance", "int", "int16", "int32", "int64", "int8", "interface", "internalcall", + "iunknown", "lasterr", "lcid", "linkcheck", "literal", "localloc", "lpstr", "lpstruct", "lptstr", + "lpvoid", "lpwstr", "managed", "marshal", "method", "modopt", "modreq", "native", "nested", + "newslot", "noappdomain", "noinlining", "nomachine", "nomangle", "nometadata", "noncasdemand", + "noncasinheritance", "noncaslinkdemand", "noprocess", "not", "not_in_gc_heap", "notremotable", + "notserialized", "null", "nullref", "object", "objectref", "opt", "optil", "out", + "permitonly", "pinned", "pinvokeimpl", "prefix1", "prefix2", "prefix3", "prefix4", "prefix5", "prefix6", + "prefix7", "prefixref", "prejitdeny", "prejitgrant", "preservesig", "private", "privatescope", "protected", + "public", "record", "refany", "reqmin", "reqopt", "reqrefuse", "reqsecobj", "request", "retval", + "rtspecialname", "runtime", "safearray", "sealed", "sequential", "serializable", "special", "specialname", + "static", "stdcall", "storage", "stored_object", "stream", "streamed_object", "string", "struct", + "synchronized", "syschar", "sysstring", "tbstr", "thiscall", "tls", "to", "true", "typedref", + "unicode", "unmanaged", "unmanagedexp", "unsigned", "unused", "userdefined", "value", "valuetype", + "vararg", "variant", "vector", "virtual", "void", "wchar", "winapi", "with", "wrapper", + + // These are not listed as keywords in spec, but ILAsm treats them as such + "property", "type", "flags", "callconv", "strict" + ); + + static HashSet BuildKeywordList(params string[] keywords) + { + HashSet s = new HashSet(keywords); + foreach (var inst in operandNames) { + if (string.IsNullOrEmpty(inst)) + continue; + s.Add(inst); + } + return s; } } } diff --git a/ICSharpCode.Decompiler/IL/SequencePoint.cs b/ICSharpCode.Decompiler/IL/SequencePoint.cs deleted file mode 100644 index d313fa73d..000000000 --- a/ICSharpCode.Decompiler/IL/SequencePoint.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ICSharpCode.Decompiler.IL -{ - /// - /// A sequence point produced by the decompiler. - /// - public struct SequencePoint - { - /// - /// IL start offset. - /// - public int Offset { get; set; } - - /// - /// IL end offset. - /// - /// - /// This does not get stored in debug information; - /// it is used internally to create hidden sequence points - /// for the IL fragments not covered by any sequence point. - /// - public int EndOffset { get; set; } - - public int StartLine { get; set; } - public int StartColumn { get; set; } - public int EndLine { get; set; } - public int EndColumn { get; set; } - - public bool IsHidden { - get { return StartLine == 0xfeefee && StartLine == EndLine; } - } - - internal void SetHidden() - { - StartLine = EndLine = 0xfeefee; - } - } -} diff --git a/ICSharpCode.Decompiler/TypeSystem/CecilLoader.cs b/ICSharpCode.Decompiler/TypeSystem/CecilLoader.cs index 6c1a73ee8..4aa6d1ba8 100644 --- a/ICSharpCode.Decompiler/TypeSystem/CecilLoader.cs +++ b/ICSharpCode.Decompiler/TypeSystem/CecilLoader.cs @@ -227,7 +227,7 @@ namespace ICSharpCode.Decompiler.TypeSystem InitTypeDefinition(cecilTypeDefs[i], typeDefs[i]); } - AddToTypeSystemTranslationTable(this.currentAssembly, assemblyDefinition); + //AddToTypeSystemTranslationTable(this.currentAssembly, assemblyDefinition); // Freezing the assembly here is important: // otherwise it will be frozen when a compilation is first created // from it. But freezing has the effect of changing some collection instances @@ -911,7 +911,7 @@ namespace ICSharpCode.Decompiler.TypeSystem { foreach (MethodDefinitionHandle h in typeDefinition.GetMethods()) { var method = currentModule.GetMethodDefinition(h); - if (IsVisible(method.Attributes) && !IsAccessor(h.GetMethodSemanticsAttributes(currentModule))) { + /*if (IsVisible(method.Attributes) && !IsAccessor(h.GetMethodSemanticsAttributes(currentModule))) { SymbolKind type = SymbolKind.Method; if ((method.Attributes & MethodAttributes.SpecialName) != 0) { if (method.IsConstructor(currentModule)) @@ -920,7 +920,7 @@ namespace ICSharpCode.Decompiler.TypeSystem type = SymbolKind.Operator; } members.Add(ReadMethod(h, td, type)); - } + }*/ } foreach (FieldDefinitionHandle h in typeDefinition.GetFields()) { var field = currentModule.GetFieldDefinition(h); @@ -1714,39 +1714,45 @@ namespace ICSharpCode.Decompiler.TypeSystem public AssemblyDefinition GetCecilObject (IUnresolvedAssembly content) { - return InternalGetCecilObject (content); + throw new NotImplementedException(); + //return InternalGetCecilObject (content); } - + public TypeDefinition GetCecilObject (IUnresolvedTypeDefinition type) { if (type == null) throw new ArgumentNullException ("type"); - return InternalGetCecilObject (type); + throw new NotImplementedException(); + //return InternalGetCecilObject (type); } - + public MethodDefinition GetCecilObject (IUnresolvedMethod method) { - return InternalGetCecilObject (method); + throw new NotImplementedException(); + //return InternalGetCecilObject (method); } - + public FieldDefinition GetCecilObject (IUnresolvedField field) { - return InternalGetCecilObject (field); + throw new NotImplementedException(); + //return InternalGetCecilObject (field); } - + public EventDefinition GetCecilObject (IUnresolvedEvent evt) { - return InternalGetCecilObject (evt); + throw new NotImplementedException(); + //return InternalGetCecilObject (evt); } - + public PropertyDefinition GetCecilObject (IUnresolvedProperty property) { - return InternalGetCecilObject (property); + throw new NotImplementedException(); + //return InternalGetCecilObject (property); } #endregion } diff --git a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs index 4eb15a280..557645d45 100644 --- a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs +++ b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs @@ -41,7 +41,7 @@ namespace ICSharpCode.Decompiler.TypeSystem if (moduleDefinition == null) throw new ArgumentNullException(nameof(moduleDefinition)); this.moduleDefinition = moduleDefinition; - MetadataLoader cecilLoader = new MetadataLoader { IncludeInternalMembers = true, LazyLoad = true, OnEntityLoaded = StoreMemberReference, ShortenInterfaceImplNames = false }; + /*MetadataLoader cecilLoader = new MetadataLoader { IncludeInternalMembers = true, LazyLoad = true, OnEntityLoaded = StoreMemberReference, ShortenInterfaceImplNames = false }; typeReferenceCecilLoader.SetCurrentModule(moduleDefinition); IUnresolvedAssembly mainAssembly = cecilLoader.LoadModule(moduleDefinition); // Load referenced assemblies and type-forwarder references. @@ -69,7 +69,7 @@ namespace ICSharpCode.Decompiler.TypeSystem referencedAssemblies.Add(MinimalCorlib.Instance); compilation = new SimpleCompilation(mainAssembly, referencedAssemblies); } - context = new SimpleTypeResolveContext(compilation.MainAssembly); + context = new SimpleTypeResolveContext(compilation.MainAssembly);*/ } public ICompilation Compilation { @@ -130,6 +130,8 @@ namespace ICSharpCode.Decompiler.TypeSystem #region Resolve Type public IType Resolve(TypeReference typeReference) { + throw new NotImplementedException(); +#if false if (typeReference == null) return SpecialType.UnknownType; // We need to skip SentinelType and PinnedType. @@ -137,15 +139,16 @@ namespace ICSharpCode.Decompiler.TypeSystem while (typeReference is OptionalModifierType || typeReference is RequiredModifierType) { typeReference = ((TypeSpecification)typeReference).ElementType; } - if (typeReference is SentinelType || typeReference is PinnedType) { + if (typeReference is SentinelType || typeReference is Mono.Cecil.PinnedType) { typeReference = ((TypeSpecification)typeReference).ElementType; } ITypeReference typeRef; lock (typeReferenceCecilLoader) typeRef = typeReferenceCecilLoader.ReadTypeReference(typeReference); return typeRef.Resolve(context); +#endif } - #endregion +#endregion #region Resolve Field public IField Resolve(FieldReference fieldReference) @@ -180,6 +183,8 @@ namespace ICSharpCode.Decompiler.TypeSystem IField CreateFakeField(FieldReference fieldReference) { + throw new NotImplementedException(); +#if false var declaringType = Resolve(fieldReference.DeclaringType); var f = new DefaultUnresolvedField(); f.Name = fieldReference.Name; @@ -187,6 +192,7 @@ namespace ICSharpCode.Decompiler.TypeSystem f.ReturnType = typeReferenceCecilLoader.ReadTypeReference(fieldReference.FieldType); } return new ResolvedFakeField(f, context.WithCurrentTypeDefinition(declaringType.GetDefinition()), declaringType); +#endif } class ResolvedFakeField : DefaultResolvedField @@ -204,7 +210,7 @@ namespace ICSharpCode.Decompiler.TypeSystem get { return declaringType; } } } - #endregion +#endregion #region Resolve Method public IMethod Resolve(MethodReference methodReference) @@ -306,6 +312,8 @@ namespace ICSharpCode.Decompiler.TypeSystem /// IMethod CreateFakeMethod(MethodReference methodReference) { + throw new NotImplementedException(); +#if false var m = new DefaultUnresolvedMethod(); ITypeReference declaringTypeReference; lock (typeReferenceCecilLoader) { @@ -324,6 +332,7 @@ namespace ICSharpCode.Decompiler.TypeSystem } var type = declaringTypeReference.Resolve(context); return new ResolvedFakeMethod(m, context.WithCurrentTypeDefinition(type.GetDefinition()), type); +#endif } class ResolvedFakeMethod : DefaultResolvedMethod @@ -343,7 +352,7 @@ namespace ICSharpCode.Decompiler.TypeSystem } #endregion - #region Resolve Property +#region Resolve Property public IProperty Resolve(PropertyReference propertyReference) { if (propertyReference == null) @@ -378,9 +387,9 @@ namespace ICSharpCode.Decompiler.TypeSystem } return null; } - #endregion +#endregion - #region Resolve Event +#region Resolve Event public IEvent Resolve(EventReference eventReference) { if (eventReference == null) @@ -412,6 +421,6 @@ namespace ICSharpCode.Decompiler.TypeSystem } return null; } - #endregion +#endregion } } diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/TypeSpecification.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/TypeSpecification.cs index 9266b0aa1..28ea11f71 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/TypeSpecification.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/TypeSpecification.cs @@ -105,8 +105,6 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation } } - public struct Unit { } - class TypeReferenceSignatureDecoder : ISignatureTypeProvider { public ITypeReference GetArrayType(ITypeReference elementType, ArrayShape shape) @@ -184,10 +182,12 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation } } - class TypeSystemAttributeTypeProvider : ICustomAttributeTypeProvider + public class TypeSystemAttributeTypeProvider : ICustomAttributeTypeProvider { readonly ITypeResolveContext context; + public static TypeSystemAttributeTypeProvider CreateDefault() => new TypeSystemAttributeTypeProvider(new SimpleTypeResolveContext(MinimalCorlib.Instance.CreateCompilation())); + public TypeSystemAttributeTypeProvider(ITypeResolveContext context) { this.context = context; diff --git a/ICSharpCode.Decompiler/Util/EmptyList.cs b/ICSharpCode.Decompiler/Util/EmptyList.cs index d98a1f309..6fdef375b 100644 --- a/ICSharpCode.Decompiler/Util/EmptyList.cs +++ b/ICSharpCode.Decompiler/Util/EmptyList.cs @@ -116,4 +116,6 @@ namespace ICSharpCode.Decompiler.Util { public static readonly T[] Array = new T[0]; } + + public struct Unit { } } diff --git a/ILSpy.AddIn/ILSpy.AddIn.csproj b/ILSpy.AddIn/ILSpy.AddIn.csproj index 208d762d3..c985dc06c 100644 --- a/ILSpy.AddIn/ILSpy.AddIn.csproj +++ b/ILSpy.AddIn/ILSpy.AddIn.csproj @@ -49,7 +49,6 @@ - diff --git a/ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj b/ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj index 6c4636f92..e549810b4 100644 --- a/ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj +++ b/ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj @@ -40,7 +40,6 @@ - diff --git a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs index dc93117cf..20fab5471 100644 --- a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs +++ b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs @@ -10,11 +10,11 @@ using System.Threading.Tasks; using System.Xml.Linq; using ICSharpCode.AvalonEdit.Highlighting; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.Decompiler.Util; using ICSharpCode.ILSpy; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; -using Mono.Cecil; using Ricciolo.StylesExplorer.MarkupReflection; namespace ILSpy.BamlDecompiler @@ -50,16 +50,16 @@ namespace ILSpy.BamlDecompiler { var asm = this.Ancestors().OfType().FirstOrDefault().LoadedAssembly; Data.Position = 0; - XDocument xamlDocument = LoadIntoDocument(asm.GetAssemblyResolver(), asm.GetAssemblyDefinitionAsync().Result, Data, cancellationToken); + XDocument xamlDocument = LoadIntoDocument(asm.GetAssemblyResolver(), asm.GetPEFileOrNull(), Data, cancellationToken); output.Write(xamlDocument.ToString()); return true; } - internal static XDocument LoadIntoDocument(IAssemblyResolver resolver, AssemblyDefinition asm, Stream stream, CancellationToken cancellationToken) + internal static XDocument LoadIntoDocument(PEFile module, Stream stream, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); XDocument xamlDocument; - using (XmlBamlReader reader = new XmlBamlReader(stream, new CecilTypeResolver(resolver, asm))) { + using (XmlBamlReader reader = new XmlBamlReader(stream, new NRTypeResolver(resolver, asm))) { xamlDocument = XDocument.Load(reader); ConvertConnectionIds(xamlDocument, asm, cancellationToken); ConvertToEmptyElements(xamlDocument.Root); diff --git a/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs b/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs index 4128a002e..178e8cb39 100644 --- a/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs +++ b/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs @@ -7,13 +7,14 @@ using System.IO; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy; +using ICSharpCode.Decompiler.Dom; namespace ILSpy.BamlDecompiler { [Export(typeof(IResourceNodeFactory))] public sealed class BamlResourceNodeFactory : IResourceNodeFactory { - public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) + public ILSpyTreeNode CreateNode(Resource resource) { return null; } @@ -35,7 +36,7 @@ namespace ILSpy.BamlDecompiler public string WriteResourceToFile(LoadedAssembly assembly, string fileName, Stream stream, DecompilationOptions options) { - var document = BamlResourceEntryNode.LoadIntoDocument(assembly.GetAssemblyResolver(), assembly.GetAssemblyDefinitionAsync().Result, stream, options.CancellationToken); + var document = BamlResourceEntryNode.LoadIntoDocument(assembly.GetAssemblyResolver(), assembly.GetPEFileOrNull(), stream, options.CancellationToken); fileName = Path.ChangeExtension(fileName, ".xaml"); document.Save(Path.Combine(options.SaveAsProjectDirectory, fileName)); return fileName; diff --git a/ILSpy.BamlDecompiler/CecilDependencyPropertyDescriptor.cs b/ILSpy.BamlDecompiler/CecilDependencyPropertyDescriptor.cs deleted file mode 100644 index 7e014b033..000000000 --- a/ILSpy.BamlDecompiler/CecilDependencyPropertyDescriptor.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team -// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt) - -using System; -using System.Linq; -using Mono.Cecil; -using Ricciolo.StylesExplorer.MarkupReflection; - -namespace ILSpy.BamlDecompiler -{ - public class CecilDependencyPropertyDescriptor : IDependencyPropertyDescriptor - { - string member; - TypeDefinition type; - - public CecilDependencyPropertyDescriptor(string member, TypeDefinition type) - { - if (type == null) - throw new ArgumentNullException("type"); - this.member = member; - this.type = type; - } - - public bool IsAttached { - get { - return type.Methods.Any(m => m.Name == "Get" + member); - } - } - - public override string ToString() - { - return string.Format("[CecilDependencyPropertyDescriptor Member={0}, Type={1}]", member, type); - } - } -} diff --git a/ILSpy.BamlDecompiler/CecilType.cs b/ILSpy.BamlDecompiler/CecilType.cs index 383e8da4a..18d877eb9 100644 --- a/ILSpy.BamlDecompiler/CecilType.cs +++ b/ILSpy.BamlDecompiler/CecilType.cs @@ -2,68 +2,49 @@ // This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt) using System; +using System.Linq; +using ICSharpCode.Decompiler.TypeSystem; using Mono.Cecil; using Ricciolo.StylesExplorer.MarkupReflection; namespace ILSpy.BamlDecompiler { - public class CecilType : IType + public class NRType : IDotNetType { - internal readonly TypeDefinition type; + readonly ITypeDefinition type; + + public ITypeDefinition Type => type; - public CecilType(TypeDefinition type) + public NRType(ITypeDefinition type) { - if (type == null) - throw new ArgumentNullException("type"); - this.type = type; + this.type = type ?? throw new ArgumentNullException(nameof(type)); } public string AssemblyQualifiedName { get { return type.FullName + - ", " + type.Module.Assembly.FullName; + ", " + type.ParentAssembly.FullAssemblyName; } } - public bool IsSubclassOf(IType type) + public bool IsSubclassOf(IDotNetType type) { if (type == null) - throw new ArgumentNullException("type"); - if (!(type is CecilType)) + throw new ArgumentNullException(nameof(type)); + if (!(type is NRType baseType)) return false; - - CecilType ct = (CecilType)type; - - var t = this.type; - - if (t == ct.type) - return false; - - while (t != null) { - if (t == ct.type) - return true; - foreach (var @interface in t.Interfaces) { - var resolved = @interface.InterfaceType.Resolve(); - if (resolved == ct.type) - return true; - } - if (t.BaseType == null) - break; - - t = t.BaseType.Resolve(); - } - - return false; + + return this.type.GetAllBaseTypeDefinitions().Any(t => t.Equals(baseType.type)); } - public bool Equals(IType type) + public bool Equals(IDotNetType type) { if (type == null) throw new ArgumentNullException("type"); - if (!(type is CecilType)) + if (!(type is NRType)) return false; - return this.type == ((CecilType)type).type; + return this.type.Equals(((NRType)type).type); } public override string ToString() @@ -71,13 +52,14 @@ namespace ILSpy.BamlDecompiler return string.Format("[CecilType Type={0}]", type); } - public IType BaseType { + public IDotNetType BaseType { get { - TypeDefinition td = type.BaseType.Resolve(); + var t = type.DirectBaseTypes.First(); + var td = t.GetDefinition(); if (td == null) - throw new Exception("could not resolve '" + type.BaseType.FullName + "'!"); + throw new Exception($"Could not resolve '{t.FullName}'!"); - return new CecilType(td); + return new NRType(td); } } } diff --git a/ILSpy.BamlDecompiler/CecilTypeResolver.cs b/ILSpy.BamlDecompiler/CecilTypeResolver.cs index ff2d677d8..cafe37d60 100644 --- a/ILSpy.BamlDecompiler/CecilTypeResolver.cs +++ b/ILSpy.BamlDecompiler/CecilTypeResolver.cs @@ -2,6 +2,7 @@ // This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt) using System; +using ICSharpCode.Decompiler.TypeSystem; using Mono.Cecil; using Ricciolo.StylesExplorer.MarkupReflection; @@ -10,20 +11,18 @@ namespace ILSpy.BamlDecompiler /// /// Description of CecilTypeResolver. /// - public class CecilTypeResolver : ITypeResolver + public class NRTypeResolver : IDotNetTypeResolver { - IAssemblyResolver resolver; - AssemblyDefinition thisAssembly; - - public CecilTypeResolver(IAssemblyResolver resolver, AssemblyDefinition asm) + readonly ICompilation compilation; + + public NRTypeResolver(ICompilation compilation) { - this.resolver = resolver; - this.thisAssembly = asm; + this.compilation = compilation; } public bool IsLocalAssembly(string name) { - return MakeShort(name) == this.thisAssembly.Name.Name; + return MakeShort(name) == compilation.MainAssembly.AssemblyName; } string MakeShort(string name) @@ -35,7 +34,7 @@ namespace ILSpy.BamlDecompiler return name.Substring(0, endOffset); } - public IType GetTypeByAssemblyQualifiedName(string name) + public IDotNetType GetTypeByAssemblyQualifiedName(string name) { int bracket = name.LastIndexOf(']'); int comma = bracket > -1 ? name.IndexOf(',', bracket) : name.IndexOf(','); @@ -45,48 +44,22 @@ namespace ILSpy.BamlDecompiler string fullName = bracket > -1 ? name.Substring(0, name.IndexOf('[')) : name.Substring(0, comma); string assemblyName = name.Substring(comma + 1).Trim(); - - var type = thisAssembly.MainModule.GetType(fullName); - - if (type == null) { - type = TryFindInExportedTypes(fullName, thisAssembly); - } - - if (type == null) { - var otherAssembly = resolver.Resolve(AssemblyNameReference.Parse(assemblyName)); - if (otherAssembly == null) - return new UnresolvableType(name); - type = otherAssembly.MainModule.GetType(fullName.Replace('+', '/')); - - if (type == null) { - type = TryFindInExportedTypes(fullName, otherAssembly); - } - } + + var type = compilation.FindType(new FullTypeName(fullName)).GetDefinition(); if (type == null) return new UnresolvableType(name); - return new CecilType(type); - } - - TypeDefinition TryFindInExportedTypes(string fullName, AssemblyDefinition asm) - { - foreach (var exportedType in asm.MainModule.ExportedTypes) { - if (exportedType.IsForwarder && exportedType.FullName == fullName) { - return exportedType.Resolve(); - } - } - - return null; + return new NRType(type); } - public IDependencyPropertyDescriptor GetDependencyPropertyDescriptor(string name, IType ownerType, IType targetType) + public IDependencyPropertyDescriptor GetDependencyPropertyDescriptor(string name, IDotNetType ownerType, IDotNetType targetType) { if (ownerType == null) throw new ArgumentNullException("ownerType"); - if (ownerType is CecilType) - return new CecilDependencyPropertyDescriptor(name, ((CecilType)ownerType).type); + if (ownerType is NRType) + return new NRTypeDependencyPropertyDescriptor(((NRType)ownerType).Type, name); if (ownerType is UnresolvableType) return new UnresolvableDependencyPropertyDescriptor(); @@ -95,7 +68,8 @@ namespace ILSpy.BamlDecompiler public string RuntimeVersion { get { - return thisAssembly.MainModule.Runtime.ToString(); + throw new NotImplementedException(); + //return thisAssembly.MainModule.Runtime.ToString(); } } } diff --git a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj index 7372b21fd..a9aafae32 100644 --- a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj +++ b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj @@ -54,7 +54,7 @@ - + diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/IType.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/IType.cs index 5d580354e..ecaf34bfa 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/IType.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/IType.cs @@ -7,41 +7,31 @@ namespace Ricciolo.StylesExplorer.MarkupReflection /// /// Interface representing a DotNet type /// - public interface IType + public interface IDotNetType { - IType BaseType { get; } + IDotNetType BaseType { get; } string AssemblyQualifiedName { get; } - bool IsSubclassOf(IType type); - bool Equals(IType type); + bool IsSubclassOf(IDotNetType type); + bool Equals(IDotNetType type); } - - public class UnresolvableType : IType + + public class UnresolvableType : IDotNetType { - string assemblyQualifiedName; - public UnresolvableType(string assemblyQualifiedName) { - this.assemblyQualifiedName = assemblyQualifiedName; - } - - public IType BaseType { - get { - return null; - } + this.AssemblyQualifiedName = assemblyQualifiedName; } - - public string AssemblyQualifiedName { - get { - return assemblyQualifiedName; - } - } - - public bool IsSubclassOf(IType type) + + public IDotNetType BaseType => null; + + public string AssemblyQualifiedName { get; } + + public bool IsSubclassOf(IDotNetType type) { return Equals(type); } - - public bool Equals(IType type) + + public bool Equals(IDotNetType type) { return type is UnresolvableType && type.AssemblyQualifiedName == AssemblyQualifiedName; } diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/ITypeResolver.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/ITypeResolver.cs index 950469315..edce5c931 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/ITypeResolver.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/ITypeResolver.cs @@ -4,11 +4,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection { - public interface ITypeResolver + public interface IDotNetTypeResolver { string RuntimeVersion { get; } bool IsLocalAssembly(string name); - IType GetTypeByAssemblyQualifiedName(string name); - IDependencyPropertyDescriptor GetDependencyPropertyDescriptor(string name, IType ownerType, IType targetType); + IDotNetType GetTypeByAssemblyQualifiedName(string name); + IDependencyPropertyDescriptor GetDependencyPropertyDescriptor(string name, IDotNetType ownerType, IDotNetType targetType); } } diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KnownInfo.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KnownInfo.cs index 54e81e3a4..807f69743 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KnownInfo.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KnownInfo.cs @@ -31,7 +31,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection { } - public KnownInfo(ITypeResolver resolver) + public KnownInfo(IDotNetTypeResolver resolver) { switch (resolver.RuntimeVersion) { case "Net_2_0": diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs index 6454fe1ed..f14800c6b 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs @@ -9,33 +9,33 @@ namespace Ricciolo.StylesExplorer.MarkupReflection { readonly XmlBamlReader reader; readonly bool _isExtension; - IType _type; + IDotNetType _type; bool _typeLoaded; - readonly ITypeResolver resolver; + readonly IDotNetTypeResolver resolver; - protected TypeDeclaration(ITypeResolver resolver) + protected TypeDeclaration(IDotNetTypeResolver resolver) { this.resolver = resolver; } - public TypeDeclaration(ITypeResolver resolver, string name, string namespaceName, short assemblyId) + public TypeDeclaration(IDotNetTypeResolver resolver, string name, string namespaceName, short assemblyId) : this(null, resolver, name, namespaceName, assemblyId) { } - public TypeDeclaration(ITypeResolver resolver, string name, string enclosingTypeName, string namespaceName, short assemblyId) + public TypeDeclaration(IDotNetTypeResolver resolver, string name, string enclosingTypeName, string namespaceName, short assemblyId) : this(null, resolver, name, namespaceName, assemblyId) { this.EnclosingTypeName = enclosingTypeName; } - public TypeDeclaration(ITypeResolver resolver, string name, string namespaceName, short assemblyId, bool isExtension) + public TypeDeclaration(IDotNetTypeResolver resolver, string name, string namespaceName, short assemblyId, bool isExtension) : this(null, resolver, name, namespaceName, assemblyId) { _isExtension = isExtension; } - public TypeDeclaration(XmlBamlReader reader, ITypeResolver resolver, string name, string namespaceName, short assemblyId) + public TypeDeclaration(XmlBamlReader reader, IDotNetTypeResolver resolver, string name, string namespaceName, short assemblyId) { this.reader = reader; this.resolver = resolver; @@ -73,7 +73,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection public virtual string Name { get; protected set; } - public IType Type { + public IDotNetType Type { get { if (!_typeLoaded) { if (this.Name.Length > 0) @@ -119,7 +119,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection protected set { throw new NotSupportedException(); } } - public ResolverTypeDeclaration(ITypeResolver resolver, string assemblyQualifiedName) + public ResolverTypeDeclaration(IDotNetTypeResolver resolver, string assemblyQualifiedName) : base(resolver) { string name, @namespace, assembly; diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs index fe025943b..0e5e864d7 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs @@ -22,7 +22,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection Dictionary typeTable = new Dictionary(); Dictionary propertyTable = new Dictionary(); - readonly ITypeResolver _resolver; + readonly IDotNetTypeResolver _resolver; BamlRecordType currentType; @@ -99,7 +99,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection public ISet XmlnsDefinitions { get; } = new HashSet(); - public XmlBamlReader(Stream stream, ITypeResolver resolver) + public XmlBamlReader(Stream stream, IDotNetTypeResolver resolver) { if (stream == null) throw new ArgumentNullException(nameof(stream)); @@ -1626,7 +1626,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection /// /// Returns object used to resolve types /// - public ITypeResolver Resolver + public IDotNetTypeResolver Resolver { get { return _resolver; } } diff --git a/ILSpy.BamlDecompiler/SRMDependencyPropertyDescriptor.cs b/ILSpy.BamlDecompiler/SRMDependencyPropertyDescriptor.cs new file mode 100644 index 000000000..de2117509 --- /dev/null +++ b/ILSpy.BamlDecompiler/SRMDependencyPropertyDescriptor.cs @@ -0,0 +1,33 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt) + +using System; +using System.Linq; +using ICSharpCode.Decompiler.TypeSystem; +using Ricciolo.StylesExplorer.MarkupReflection; + +namespace ILSpy.BamlDecompiler +{ + public class NRTypeDependencyPropertyDescriptor : IDependencyPropertyDescriptor + { + readonly ITypeDefinition typeDefinition; + readonly string member; + + public NRTypeDependencyPropertyDescriptor(ITypeDefinition type, string name) + { + this.typeDefinition = type; + this.member = name; + } + + public bool IsAttached { + get { + return typeDefinition.GetMethods(m => m.Name == "Get" + member, GetMemberOptions.IgnoreInheritedMembers).Any(); + } + } + + public override string ToString() + { + return string.Format("[CecilDependencyPropertyDescriptor Member={0}, Type={1}]", member, typeDefinition); + } + } +} diff --git a/ILSpy.sln b/ILSpy.sln index 7c164b62d..4e035c102 100644 --- a/ILSpy.sln +++ b/ILSpy.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26730.12 +VisualStudioVersion = 15.0.27130.2026 MinimumVisualStudioVersion = 15.0 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}" ProjectSection(SolutionItems) = preProject @@ -24,10 +24,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestPlugin", "TestPlugin\Te EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Pdb", "cecil\symbols\pdb\Mono.Cecil.Pdb.csproj", "{63E6915C-7EA4-4D76-AB28-0D7191EEA626}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILSpy.BamlDecompiler", "ILSpy.BamlDecompiler\ILSpy.BamlDecompiler.csproj", "{A6BAD2BA-76BA-461C-8B6D-418607591247}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILSpy.BamlDecompiler.Tests", "ILSpy.BamlDecompiler.Tests\ILSpy.BamlDecompiler.Tests.csproj", "{1169E6D1-1899-43D4-A500-07CE4235B388}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILSpy.AddIn", "ILSpy.AddIn\ILSpy.AddIn.csproj", "{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0A344E19-D1FC-4F4C-8883-0844AC669113}" @@ -69,14 +65,6 @@ Global {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|Any CPU.Build.0 = net_4_0_Release|Any CPU - {A6BAD2BA-76BA-461C-8B6D-418607591247}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A6BAD2BA-76BA-461C-8B6D-418607591247}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A6BAD2BA-76BA-461C-8B6D-418607591247}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A6BAD2BA-76BA-461C-8B6D-418607591247}.Release|Any CPU.Build.0 = Release|Any CPU - {1169E6D1-1899-43D4-A500-07CE4235B388}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1169E6D1-1899-43D4-A500-07CE4235B388}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1169E6D1-1899-43D4-A500-07CE4235B388}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1169E6D1-1899-43D4-A500-07CE4235B388}.Release|Any CPU.Build.0 = Release|Any CPU {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Debug|Any CPU.Build.0 = Debug|Any CPU {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/ILSpy/AnalyzerTreeView.cs b/ILSpy/AnalyzerTreeView.cs index ce40cd198..c0181b577 100644 --- a/ILSpy/AnalyzerTreeView.cs +++ b/ILSpy/AnalyzerTreeView.cs @@ -119,4 +119,4 @@ namespace ICSharpCode.ILSpy } } } -} \ No newline at end of file +} diff --git a/ILSpy/Commands/DecompileAllCommand.cs b/ILSpy/Commands/DecompileAllCommand.cs index 2de1c24ef..ce4b0e03c 100644 --- a/ILSpy/Commands/DecompileAllCommand.cs +++ b/ILSpy/Commands/DecompileAllCommand.cs @@ -16,7 +16,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -#if DEBUG +#if false && DEBUG using System; using System.Diagnostics; diff --git a/ILSpy/DebugSteps.xaml.cs b/ILSpy/DebugSteps.xaml.cs index f3c3b7a7f..c2e4de4e3 100644 --- a/ILSpy/DebugSteps.xaml.cs +++ b/ILSpy/DebugSteps.xaml.cs @@ -20,7 +20,7 @@ namespace ICSharpCode.ILSpy public static ILAstWritingOptions Options => writingOptions; -#if DEBUG +#if false && DEBUG ILAstLanguage language; #endif @@ -28,7 +28,7 @@ namespace ICSharpCode.ILSpy { InitializeComponent(); -#if DEBUG +#if false && DEBUG MainWindow.Instance.SessionSettings.FilterSettings.PropertyChanged += FilterSettings_PropertyChanged; MainWindow.Instance.SelectionChanged += SelectionChanged; writingOptions.PropertyChanged += WritingOptions_PropertyChanged; @@ -56,7 +56,7 @@ namespace ICSharpCode.ILSpy private void FilterSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { -#if DEBUG +#if false && DEBUG if (e.PropertyName == "Language") { if (language != null) { language.StepperUpdated -= ILAstStepperUpdated; @@ -72,7 +72,7 @@ namespace ICSharpCode.ILSpy private void ILAstStepperUpdated(object sender, EventArgs e) { -#if DEBUG +#if false && DEBUG if (language == null) return; Dispatcher.Invoke(() => { tree.ItemsSource = language.Stepper.Steps; @@ -88,7 +88,7 @@ namespace ICSharpCode.ILSpy void IPane.Closed() { -#if DEBUG +#if false && DEBUG MainWindow.Instance.SessionSettings.FilterSettings.PropertyChanged -= FilterSettings_PropertyChanged; MainWindow.Instance.SelectionChanged -= SelectionChanged; writingOptions.PropertyChanged -= WritingOptions_PropertyChanged; diff --git a/ILSpy/ExtensionMethods.cs b/ILSpy/ExtensionMethods.cs index c83d09f4e..6defc0728 100644 --- a/ILSpy/ExtensionMethods.cs +++ b/ILSpy/ExtensionMethods.cs @@ -101,13 +101,45 @@ namespace ICSharpCode.ILSpy } return false; } - - public static string ToSuffixString(this MetadataToken token) + + public static string ToSuffixString(this System.Reflection.Metadata.MethodDefinitionHandle token) + { + if (!DisplaySettingsPanel.CurrentDisplaySettings.ShowMetadataTokens) + return string.Empty; + + return " @" + System.Reflection.Metadata.Ecma335.MetadataTokens.GetToken(token).ToString("x8"); + } + + public static string ToSuffixString(this System.Reflection.Metadata.PropertyDefinitionHandle token) + { + if (!DisplaySettingsPanel.CurrentDisplaySettings.ShowMetadataTokens) + return string.Empty; + + return " @" + System.Reflection.Metadata.Ecma335.MetadataTokens.GetToken(token).ToString("x8"); + } + + public static string ToSuffixString(this System.Reflection.Metadata.EventDefinitionHandle token) { if (!DisplaySettingsPanel.CurrentDisplaySettings.ShowMetadataTokens) return string.Empty; - - return " @" + token.ToInt32().ToString("x8"); + + return " @" + System.Reflection.Metadata.Ecma335.MetadataTokens.GetToken(token).ToString("x8"); + } + + public static string ToSuffixString(this System.Reflection.Metadata.FieldDefinitionHandle token) + { + if (!DisplaySettingsPanel.CurrentDisplaySettings.ShowMetadataTokens) + return string.Empty; + + return " @" + System.Reflection.Metadata.Ecma335.MetadataTokens.GetToken(token).ToString("x8"); + } + + public static string ToSuffixString(this System.Reflection.Metadata.TypeDefinitionHandle token) + { + if (!DisplaySettingsPanel.CurrentDisplaySettings.ShowMetadataTokens) + return string.Empty; + + return " @" + System.Reflection.Metadata.Ecma335.MetadataTokens.GetToken(token).ToString("x8"); } /// diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 08303a247..702f2607f 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -76,7 +76,6 @@ - @@ -127,6 +126,7 @@ + @@ -181,28 +181,8 @@ - - - - - - - - - - - - - - - - - - - - - + @@ -213,12 +193,12 @@ - + + - - + LGPL.txt @@ -264,13 +244,6 @@ - - - - - - - @@ -284,9 +257,7 @@ - - diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index 0a71362d0..4c72be361 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -23,23 +23,21 @@ using System.ComponentModel.Composition; using System.IO; using System.Linq; using System.Resources; - +using System.Windows; +using System.Windows.Controls; using ICSharpCode.Decompiler; -using ICSharpCode.ILSpy.Options; -using Mono.Cecil; using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp.OutputVisitor; using ICSharpCode.Decompiler.CSharp.Syntax; +using ICSharpCode.Decompiler.CSharp.Transforms; using ICSharpCode.Decompiler.TypeSystem; -using System.Windows; -using System.Windows.Controls; +using ICSharpCode.ILSpy.Options; using ICSharpCode.ILSpy.TreeNodes; -using ICSharpCode.Decompiler.CSharp.Transforms; -using ICSharpCode.AvalonEdit.Highlighting; -using System.Windows.Media; +using Mono.Cecil; namespace ICSharpCode.ILSpy { +#if false /// /// C# decompiler integration into ILSpy. /// Note: if you're interested in using the decompiler without the ILSpy UI, @@ -252,40 +250,6 @@ namespace ICSharpCode.ILSpy WriteCode(output, options.DecompilerSettings, decompiler.Decompile(type), decompiler.TypeSystem); } - public static string GetPlatformDisplayName(ModuleDefinition module) - { - switch (module.Architecture) { - case TargetArchitecture.I386: - if ((module.Attributes & ModuleAttributes.Preferred32Bit) == ModuleAttributes.Preferred32Bit) - return "AnyCPU (32-bit preferred)"; - else if ((module.Attributes & ModuleAttributes.Required32Bit) == ModuleAttributes.Required32Bit) - return "x86"; - else - return "AnyCPU (64-bit preferred)"; - case TargetArchitecture.AMD64: - return "x64"; - case TargetArchitecture.IA64: - return "Itanium"; - default: - return module.Architecture.ToString(); - } - } - - public static string GetRuntimeDisplayName(ModuleDefinition module) - { - switch (module.Runtime) { - case TargetRuntime.Net_1_0: - return ".NET 1.0"; - case TargetRuntime.Net_1_1: - return ".NET 1.1"; - case TargetRuntime.Net_2_0: - return ".NET 2.0"; - case TargetRuntime.Net_4_0: - return ".NET 4.0"; - } - return null; - } - void AddReferenceWarningMessage(AssemblyDefinition assembly, ITextOutput output) { var loadedAssembly = MainWindow.Instance.CurrentAssemblyList.GetAssemblies().FirstOrDefault(la => la.GetAssemblyDefinitionOrNull() == assembly); @@ -519,4 +483,5 @@ namespace ICSharpCode.ILSpy return new CSharpAmbience() { ConversionFlags = flags }.ConvertSymbol(symbol); } } +#endif } diff --git a/ILSpy/Languages/ILAstLanguage.cs b/ILSpy/Languages/ILAstLanguage.cs index ccc79c0db..9f7b190da 100644 --- a/ILSpy/Languages/ILAstLanguage.cs +++ b/ILSpy/Languages/ILAstLanguage.cs @@ -23,14 +23,14 @@ using System.Linq; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.TypeSystem; -using Mono.Cecil; namespace ICSharpCode.ILSpy { -#if DEBUG +#if false && DEBUG /// /// Represents the ILAst "language" used for debugging purposes. /// diff --git a/ILSpy/Languages/ILLanguage.cs b/ILSpy/Languages/ILLanguage.cs index bce17aad3..afd1b67e0 100644 --- a/ILSpy/Languages/ILLanguage.cs +++ b/ILSpy/Languages/ILLanguage.cs @@ -25,6 +25,7 @@ using System.Reflection.Metadata; using System.IO; using System.Reflection.Metadata.Ecma335; using System.Linq; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy { @@ -48,114 +49,99 @@ namespace ICSharpCode.ILSpy get { return ".il"; } } - protected virtual ReflectionDisassembler CreateDisassembler(ITextOutput output, PEReader reader, DecompilationOptions options) + protected virtual ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options) { - return new ReflectionDisassembler(output, reader, options.CancellationToken) { + return new ReflectionDisassembler(output, options.CancellationToken) { DetectControlStructure = detectControlStructure, ShowSequencePoints = options.DecompilerSettings.ShowDebugInfo }; } - public override void DecompileMethod(Mono.Cecil.MethodDefinition method, ITextOutput output, DecompilationOptions options) + public override void DecompileMethod(Decompiler.Dom.MethodDefinition method, ITextOutput output, DecompilationOptions options) { - using (var reader = new PEReader(new FileStream(method.Module.FileName, FileMode.Open, FileAccess.Read))) { - var dis = CreateDisassembler(output, reader, options); - dis.DisassembleMethod(MetadataTokens.MethodDefinitionHandle(method.MetadataToken.ToInt32())); - } + var dis = CreateDisassembler(output, options); + dis.DisassembleMethod(method); } - public override void DecompileField(Mono.Cecil.FieldDefinition field, ITextOutput output, DecompilationOptions options) + public override void DecompileField(Decompiler.Dom.FieldDefinition field, ITextOutput output, DecompilationOptions options) { - using (var reader = new PEReader(new FileStream(field.Module.FileName, FileMode.Open, FileAccess.Read))) { - var dis = CreateDisassembler(output, reader, options); - dis.DisassembleField(MetadataTokens.FieldDefinitionHandle(field.MetadataToken.ToInt32())); - } + var dis = CreateDisassembler(output, options); + dis.DisassembleField(field); } - public override void DecompileProperty(Mono.Cecil.PropertyDefinition property, ITextOutput output, DecompilationOptions options) + public override void DecompileProperty(Decompiler.Dom.PropertyDefinition property, ITextOutput output, DecompilationOptions options) { - using (var reader = new PEReader(new FileStream(property.Module.FileName, FileMode.Open, FileAccess.Read))) { - var dis = CreateDisassembler(output, reader, options); - dis.DisassembleProperty(MetadataTokens.PropertyDefinitionHandle(property.MetadataToken.ToInt32())); + var dis = CreateDisassembler(output, options); + dis.DisassembleProperty(property); - if (property.GetMethod != null) { - output.WriteLine(); - dis.DisassembleMethod(MetadataTokens.MethodDefinitionHandle(property.GetMethod.MetadataToken.ToInt32())); - } - if (property.SetMethod != null) { - output.WriteLine(); - dis.DisassembleMethod(MetadataTokens.MethodDefinitionHandle(property.SetMethod.MetadataToken.ToInt32())); - } - foreach (var m in property.OtherMethods) { - output.WriteLine(); - dis.DisassembleMethod(MetadataTokens.MethodDefinitionHandle(m.MetadataToken.ToInt32())); - } + if (!property.GetMethod.IsNil) { + output.WriteLine(); + dis.DisassembleMethod(property.GetMethod); + } + if (!property.SetMethod.IsNil) { + output.WriteLine(); + dis.DisassembleMethod(property.SetMethod); + } + foreach (var m in property.OtherMethods) { + output.WriteLine(); + dis.DisassembleMethod(m); } } - public override void DecompileEvent(Mono.Cecil.EventDefinition ev, ITextOutput output, DecompilationOptions options) + public override void DecompileEvent(Decompiler.Dom.EventDefinition ev, ITextOutput output, DecompilationOptions options) { - using (var reader = new PEReader(new FileStream(ev.Module.FileName, FileMode.Open, FileAccess.Read))) { - var dis = CreateDisassembler(output, reader, options); - dis.DisassembleEvent(MetadataTokens.EventDefinitionHandle(ev.MetadataToken.ToInt32())); - if (ev.AddMethod != null) { - output.WriteLine(); - dis.DisassembleMethod(MetadataTokens.MethodDefinitionHandle(ev.AddMethod.MetadataToken.ToInt32())); - } - if (ev.RemoveMethod != null) { - output.WriteLine(); - dis.DisassembleMethod(MetadataTokens.MethodDefinitionHandle(ev.RemoveMethod.MetadataToken.ToInt32())); - } - foreach (var m in ev.OtherMethods) { - output.WriteLine(); - dis.DisassembleMethod(MetadataTokens.MethodDefinitionHandle(m.MetadataToken.ToInt32())); - } + var dis = CreateDisassembler(output, options); + dis.DisassembleEvent(ev); + if (!ev.AddMethod.IsNil) { + output.WriteLine(); + dis.DisassembleMethod(ev.AddMethod); + } + if (!ev.RemoveMethod.IsNil) { + output.WriteLine(); + dis.DisassembleMethod(ev.RemoveMethod); + } + foreach (var m in ev.OtherMethods) { + output.WriteLine(); + dis.DisassembleMethod(m); } } - public override void DecompileType(Mono.Cecil.TypeDefinition type, ITextOutput output, DecompilationOptions options) + public override void DecompileType(Decompiler.Dom.TypeDefinition type, ITextOutput output, DecompilationOptions options) { - using (var reader = new PEReader(new FileStream(type.Module.FileName, FileMode.Open, FileAccess.Read))) { - var dis = CreateDisassembler(output, reader, options); - dis.DisassembleType(MetadataTokens.TypeDefinitionHandle(type.MetadataToken.ToInt32())); - } + var dis = CreateDisassembler(output, options); + dis.DisassembleType(type); } - public override void DecompileNamespace(string nameSpace, IEnumerable types, ITextOutput output, DecompilationOptions options) + public override void DecompileNamespace(string nameSpace, IEnumerable types, ITextOutput output, DecompilationOptions options) { - if (!types.Any()) - return; - using (var reader = new PEReader(new FileStream(types.First().Module.FileName, FileMode.Open, FileAccess.Read))) { - var dis = CreateDisassembler(output, reader, options); - dis.DisassembleNamespace(nameSpace, types.Select(t => MetadataTokens.TypeDefinitionHandle(t.MetadataToken.ToInt32()))); - } + var dis = CreateDisassembler(output, options); + dis.DisassembleNamespace(nameSpace, types); } public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) { output.WriteLine("// " + assembly.FileName); output.WriteLine(); - using (var reader = new PEReader(new FileStream(assembly.FileName, FileMode.Open, FileAccess.Read))) { - var dis = CreateDisassembler(output, reader, options); - var module = assembly.GetModuleDefinitionAsync().Result; - if (options.FullDecompilation) - dis.WriteAssemblyReferences(); - if (module.Assembly != null) - dis.WriteAssemblyHeader(); + var module = assembly.GetPEFileOrNull(); + var metadata = module.GetMetadataReader(); + var dis = CreateDisassembler(output, options); + if (options.FullDecompilation) + dis.WriteAssemblyReferences(module); + if (metadata.IsAssembly) + dis.WriteAssemblyHeader(module); + output.WriteLine(); + dis.WriteModuleHeader(module); + if (options.FullDecompilation) { + output.WriteLine(); output.WriteLine(); - dis.WriteModuleHeader(); - if (options.FullDecompilation) { - output.WriteLine(); - output.WriteLine(); - dis.WriteModuleContents(reader.GetMetadataReader().GetModuleDefinition()); - } + dis.WriteModuleContents(module); } } - public override string TypeToString(Mono.Cecil.TypeReference type, bool includeNamespace, Mono.Cecil.ICustomAttributeProvider typeAttributes = null) + public override string TypeToString(Decompiler.Dom.ITypeReference type, bool includeNamespace, Decompiler.Dom.ICustomAttributeProvider typeAttributes = null) { PlainTextOutput output = new PlainTextOutput(); - type.WriteTo(output, includeNamespace ? ILNameSyntax.TypeName : ILNameSyntax.ShortTypeName); + type.WriteTo(output, GenericContext.Empty, includeNamespace ? ILNameSyntax.TypeName : ILNameSyntax.ShortTypeName); return output.ToString(); } } diff --git a/ILSpy/Languages/ITypeProvider.cs b/ILSpy/Languages/ITypeProvider.cs new file mode 100644 index 000000000..3bee791f8 --- /dev/null +++ b/ILSpy/Languages/ITypeProvider.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Reflection.Metadata; +using System.Text; +using System.Threading.Tasks; +using ICSharpCode.Decompiler.Dom; + +namespace ICSharpCode.ILSpy +{ + + + public sealed class CSharpSignatureTypeProvider : ISignatureTypeProvider + { + public string GetArrayType(string elementType, ArrayShape shape) + { + throw new NotImplementedException(); + } + + public string GetByReferenceType(string elementType) + { + throw new NotImplementedException(); + } + + public string GetFunctionPointerType(MethodSignature signature) + { + throw new NotImplementedException(); + } + + public string GetGenericInstantiation(string genericType, ImmutableArray typeArguments) + { + throw new NotImplementedException(); + } + + public string GetGenericMethodParameter(GenericContext genericContext, int index) + { + throw new NotImplementedException(); + } + + public string GetGenericTypeParameter(GenericContext genericContext, int index) + { + throw new NotImplementedException(); + } + + public string GetModifiedType(string modifier, string unmodifiedType, bool isRequired) + { + throw new NotImplementedException(); + } + + public string GetPinnedType(string elementType) + { + throw new NotImplementedException(); + } + + public string GetPointerType(string elementType) + { + throw new NotImplementedException(); + } + + public string GetPrimitiveType(PrimitiveTypeCode typeCode) + { + throw new NotImplementedException(); + } + + public string GetSZArrayType(string elementType) + { + throw new NotImplementedException(); + } + + public string GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) + { + throw new NotImplementedException(); + } + + public string GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) + { + throw new NotImplementedException(); + } + + public string GetTypeFromSpecification(MetadataReader reader, GenericContext genericContext, TypeSpecificationHandle handle, byte rawTypeKind) + { + throw new NotImplementedException(); + } + } +} diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs index 7440f84b8..b3601f4e0 100644 --- a/ILSpy/Languages/Language.cs +++ b/ILSpy/Languages/Language.cs @@ -18,8 +18,13 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Reflection.PortableExecutable; using ICSharpCode.Decompiler; -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; + +using static System.Reflection.Metadata.PEReaderExtensions; +using SRM = System.Reflection.Metadata; namespace ICSharpCode.ILSpy { @@ -87,16 +92,18 @@ namespace ICSharpCode.ILSpy public virtual void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) { WriteCommentLine(output, assembly.FileName); - var asm = assembly.GetAssemblyDefinitionOrNull(); - if (asm != null) { - var name = asm.Name; - if (name.IsWindowsRuntime) { + var asm = assembly.GetPEFileOrNull(); + if (asm == null) return; + var reader = asm.GetMetadataReader(); + if (reader.IsAssembly) { + var name = reader.GetAssemblyDefinition(); + if ((name.Flags & System.Reflection.AssemblyFlags.WindowsRuntime) != 0) { WriteCommentLine(output, name.Name + " [WinRT]"); } else { - WriteCommentLine(output, name.FullName); + WriteCommentLine(output, reader.GetFullAssemblyName()); } } else { - WriteCommentLine(output, assembly.GetModuleDefinitionAsync().Result.Name); + WriteCommentLine(output, reader.GetString(reader.GetModuleDefinition().Name)); } } @@ -108,57 +115,69 @@ namespace ICSharpCode.ILSpy /// /// Converts a type reference into a string. This method is used by the member tree node for parameter and return types. /// - public virtual string TypeToString(TypeReference type, bool includeNamespace, ICustomAttributeProvider typeAttributes = null) + public virtual string TypeToString(ITypeReference type, bool includeNamespace, ICustomAttributeProvider typeAttributes = null) { if (includeNamespace) - return type.FullName; + return type.FullName.ToString(); else return type.Name; } + public virtual SRM.ISignatureTypeProvider CreateSignatureTypeProvider(bool includeNamespace) + { + return new ILSignatureProvider(includeNamespace); + } + /// /// Converts a member signature to a string. /// This is used for displaying the tooltip on a member reference. /// - public virtual string GetTooltip(MemberReference member) + public virtual string GetTooltip(IMemberReference member) { - if (member is TypeReference) - return TypeToString((TypeReference)member, true); - else - return member.ToString(); + return member.Name; } + /// + /// Converts a member signature to a string. + /// This is used for displaying the tooltip on a member reference. + /// + public virtual string GetTooltip(ITypeReference type) + { + return TypeToString(type, true); + } + + public virtual string FormatFieldName(FieldDefinition field) { - if (field == null) + if (field.Handle.IsNil) throw new ArgumentNullException(nameof(field)); return field.Name; } public virtual string FormatPropertyName(PropertyDefinition property, bool? isIndexer = null) { - if (property == null) + if (property.Handle.IsNil) throw new ArgumentNullException(nameof(property)); return property.Name; } public virtual string FormatMethodName(MethodDefinition method) { - if (method == null) + if (method.Handle.IsNil) throw new ArgumentNullException(nameof(method)); return method.Name; } public virtual string FormatEventName(EventDefinition @event) { - if (@event == null) + if (@event.Handle.IsNil) throw new ArgumentNullException(nameof(@event)); return @event.Name; } public virtual string FormatTypeName(TypeDefinition type) { - if (type == null) + if (type.Handle.IsNil) throw new ArgumentNullException(nameof(type)); return type.Name; } @@ -171,7 +190,7 @@ namespace ICSharpCode.ILSpy return Name; } - public virtual bool ShowMember(MemberReference member) + public virtual bool ShowMember(IMemberReference member) { return true; } @@ -179,9 +198,190 @@ namespace ICSharpCode.ILSpy /// /// Used by the analyzer to map compiler generated code back to the original code's location /// - public virtual MemberReference GetOriginalCodeLocation(MemberReference member) + public virtual IMemberReference GetOriginalCodeLocation(IMemberReference member) { return member; } + + public static string GetPlatformDisplayName(PEFile module) + { + var architecture = module.Reader.PEHeaders.CoffHeader.Machine; + var flags = module.Reader.PEHeaders.CorHeader.Flags; + switch (architecture) { + case Machine.I386: + if ((flags & CorFlags.Prefers32Bit) != 0) + return "AnyCPU (32-bit preferred)"; + else if ((flags & CorFlags.Requires32Bit) != 0) + return "x86"; + else + return "AnyCPU (64-bit preferred)"; + case Machine.Amd64: + return "x64"; + case Machine.IA64: + return "Itanium"; + default: + return architecture.ToString(); + } + } + + public static string GetRuntimeDisplayName(PEFile module) + { + string version = module.GetMetadataReader().MetadataVersion; + switch (version[1]) { + case '1': + if (version[3] == 1) + return ".NET 1.1"; + else + return ".NET 1.0"; + case '2': + return ".NET 2.0"; + case '4': + return ".NET 4.0"; + } + return null; + } + } + + class ILSignatureProvider : SRM.ISignatureTypeProvider + { + bool includeNamespace; + + public ILSignatureProvider(bool includeNamespace) + { + this.includeNamespace = includeNamespace; + } + + public string GetArrayType(string elementType, SRM.ArrayShape shape) + { + string printedShape = ""; + for (int i = 0; i < shape.Rank; i++) { + if (i > 0) + printedShape += ", "; + if (i < shape.LowerBounds.Length || i < shape.Sizes.Length) { + int lower = 0; + if (i < shape.LowerBounds.Length) { + lower = shape.LowerBounds[i]; + printedShape += lower.ToString(); + } + printedShape += "..."; + if (i < shape.Sizes.Length) + printedShape += (lower + shape.Sizes[i] - 1).ToString(); + } + } + return $"{elementType}[{printedShape}]"; + } + + public string GetByReferenceType(string elementType) + { + return elementType + "&"; + } + + public string GetFunctionPointerType(SRM.MethodSignature signature) + { + throw new NotImplementedException(); + } + + public string GetGenericInstantiation(string genericType, ImmutableArray typeArguments) + { + return genericType + "<" + string.Join(", ", typeArguments) + ">"; + } + + public string GetGenericMethodParameter(GenericContext genericContext, int index) + { + return "!!" + genericContext.GetGenericMethodTypeParameterName(index); + } + + public string GetGenericTypeParameter(GenericContext genericContext, int index) + { + return "!" + genericContext.GetGenericTypeParameterName(index); + } + + public string GetModifiedType(string modifier, string unmodifiedType, bool isRequired) + { + throw new NotImplementedException(); + } + + public string GetPinnedType(string elementType) + { + throw new NotImplementedException(); + } + + public string GetPointerType(string elementType) + { + return elementType + "*"; + } + + public string GetPrimitiveType(SRM.PrimitiveTypeCode typeCode) + { + switch (typeCode) { + case SRM.PrimitiveTypeCode.Boolean: + return "bool"; + case SRM.PrimitiveTypeCode.Byte: + return "uint8"; + case SRM.PrimitiveTypeCode.SByte: + return "int8"; + case SRM.PrimitiveTypeCode.Char: + return "char"; + case SRM.PrimitiveTypeCode.Int16: + return "int16"; + case SRM.PrimitiveTypeCode.UInt16: + return "uint16"; + case SRM.PrimitiveTypeCode.Int32: + return "int32"; + case SRM.PrimitiveTypeCode.UInt32: + return "uint32"; + case SRM.PrimitiveTypeCode.Int64: + return "int64"; + case SRM.PrimitiveTypeCode.UInt64: + return "uint64"; + case SRM.PrimitiveTypeCode.Single: + return "float32"; + case SRM.PrimitiveTypeCode.Double: + return "float64"; + case SRM.PrimitiveTypeCode.IntPtr: + return "native int"; + case SRM.PrimitiveTypeCode.UIntPtr: + break; + case SRM.PrimitiveTypeCode.Object: + return "object"; + case SRM.PrimitiveTypeCode.String: + return "string"; + case SRM.PrimitiveTypeCode.TypedReference: + break; + case SRM.PrimitiveTypeCode.Void: + return "void"; + default: + break; + } + throw new NotImplementedException(); + } + + public string GetSZArrayType(string elementType) + { + return elementType + "[]"; + } + + public string GetTypeFromDefinition(SRM.MetadataReader reader, SRM.TypeDefinitionHandle handle, byte rawTypeKind) + { + if (!includeNamespace) { + return Decompiler.Disassembler.DisassemblerHelpers.Escape(handle.GetFullTypeName(reader).Name); + } + + return handle.GetFullTypeName(reader).ToILNameString(); + } + + public string GetTypeFromReference(SRM.MetadataReader reader, SRM.TypeReferenceHandle handle, byte rawTypeKind) + { + if (!includeNamespace) { + return Decompiler.Disassembler.DisassemblerHelpers.Escape(handle.GetFullTypeName(reader).Name); + } + + return handle.GetFullTypeName(reader).ToILNameString(); + } + + public string GetTypeFromSpecification(SRM.MetadataReader reader, GenericContext genericContext, SRM.TypeSpecificationHandle handle, byte rawTypeKind) + { + return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext); + } } } diff --git a/ILSpy/Languages/Languages.cs b/ILSpy/Languages/Languages.cs index 2312f7ec5..7c10e3ff1 100644 --- a/ILSpy/Languages/Languages.cs +++ b/ILSpy/Languages/Languages.cs @@ -45,8 +45,8 @@ namespace ICSharpCode.ILSpy languages.AddRange(composition.GetExportedValues()); languages.Sort((a, b) => a.Name.CompareTo(b.Name)); #if DEBUG - languages.AddRange(ILAstLanguage.GetDebugLanguages()); - languages.AddRange(CSharpLanguage.GetDebugLanguages()); + //languages.AddRange(ILAstLanguage.GetDebugLanguages()); + //languages.AddRange(CSharpLanguage.GetDebugLanguages()); #endif allLanguages = languages.AsReadOnly(); } diff --git a/ILSpy/LoadedAssembly.cs b/ILSpy/LoadedAssembly.cs index fd856d8c8..424f68904 100644 --- a/ILSpy/LoadedAssembly.cs +++ b/ILSpy/LoadedAssembly.cs @@ -19,13 +19,14 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; +using System.Reflection.PortableExecutable; using System.Threading; using System.Threading.Tasks; -using System.Windows.Threading; using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.ILSpy.Options; -using Mono.Cecil; + +using static System.Reflection.Metadata.PEReaderExtensions; namespace ICSharpCode.ILSpy { @@ -34,21 +35,17 @@ namespace ICSharpCode.ILSpy /// public sealed class LoadedAssembly { - readonly Task assemblyTask; + readonly Task assemblyTask; readonly AssemblyList assemblyList; readonly string fileName; readonly string shortName; public LoadedAssembly(AssemblyList assemblyList, string fileName, Stream stream = null) { - if (assemblyList == null) - throw new ArgumentNullException(nameof(assemblyList)); - if (fileName == null) - throw new ArgumentNullException(nameof(fileName)); - this.assemblyList = assemblyList; - this.fileName = fileName; + this.assemblyList = assemblyList ?? throw new ArgumentNullException(nameof(assemblyList)); + this.fileName = fileName ?? throw new ArgumentNullException(nameof(fileName)); - this.assemblyTask = Task.Factory.StartNew(LoadAssembly, stream); // requires that this.fileName is set + this.assemblyTask = Task.Factory.StartNew(LoadAssembly, stream); // requires that this.fileName is set this.shortName = Path.GetFileNameWithoutExtension(fileName); } @@ -58,8 +55,8 @@ namespace ICSharpCode.ILSpy /// public async Task GetTargetFrameworkIdAsync() { - var assembly = await GetAssemblyDefinitionAsync().ConfigureAwait(false); - return assembly?.DetectTargetFrameworkId() ?? string.Empty; + var assembly = await GetPEFileAsync().ConfigureAwait(false); + return assembly.Reader.DetectTargetFrameworkId() ?? string.Empty; } public ReferenceLoadInfo LoadedAssemblyReferencesInfo { get; } = new ReferenceLoadInfo(); @@ -67,7 +64,7 @@ namespace ICSharpCode.ILSpy /// /// Gets the Cecil ModuleDefinition. /// - public Task GetModuleDefinitionAsync() + public Task GetPEFileAsync() { return assemblyTask; } @@ -76,33 +73,10 @@ namespace ICSharpCode.ILSpy /// Gets the Cecil ModuleDefinition. /// Returns null in case of load errors. /// - public ModuleDefinition GetModuleDefinitionOrNull() - { - try { - return GetModuleDefinitionAsync().Result; - } catch (Exception ex) { - System.Diagnostics.Trace.TraceError(ex.ToString()); - return null; - } - } - - /// - /// Gets the Cecil AssemblyDefinition. - /// - public async Task GetAssemblyDefinitionAsync() - { - var module = await assemblyTask.ConfigureAwait(false); - return module != null ? module.Assembly : null; - } - - /// - /// Gets the Cecil AssemblyDefinition. - /// Returns null when there was a load error; or when opening a netmodule. - /// - public AssemblyDefinition GetAssemblyDefinitionOrNull() + public PEFile GetPEFileOrNull() { try { - return GetAssemblyDefinitionAsync().Result; + return GetPEFileAsync().Result; } catch (Exception ex) { System.Diagnostics.Trace.TraceError(ex.ToString()); return null; @@ -118,7 +92,7 @@ namespace ICSharpCode.ILSpy public string Text { get { if (IsLoaded && !HasLoadError) { - string version = GetAssemblyDefinitionOrNull()?.Name.Version.ToString(); + string version = GetPEFileOrNull()?.Reader.GetAssemblyDefinition()?.Version.ToString(); if (version == null) return ShortName; return String.Format("{0} ({1})", ShortName, version); @@ -134,25 +108,26 @@ namespace ICSharpCode.ILSpy public bool IsAutoLoaded { get; set; } - ModuleDefinition LoadAssembly(object state) + PEFile LoadAssembly(object state) { var stream = state as Stream; - ModuleDefinition module; + PEReader module; // runs on background thread - ReaderParameters p = new ReaderParameters(); - p.AssemblyResolver = new MyAssemblyResolver(this); - p.InMemory = true; - if (stream != null) { // Read the module from a precrafted stream - module = ModuleDefinition.ReadModule(stream, p); + module = new PEReader(stream); } else { // Read the module from disk (by default) - module = ModuleDefinition.ReadModule(fileName, p); + using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { + var ms = new MemoryStream(); + fs.CopyTo(ms); + ms.Position = 0; + module = new PEReader(ms, PEStreamOptions.PrefetchEntireImage); + } } if (DecompilerSettingsPanel.CurrentDecompilerSettings.UseDebugSymbols) { @@ -164,17 +139,18 @@ namespace ICSharpCode.ILSpy // ignore any errors during symbol loading } } - return module; + return new PEFile(fileName, module, new MyAssemblyResolver(this)); } - private void LoadSymbols(ModuleDefinition module) + private void LoadSymbols(PEReader reader) { - if (!module.HasDebugHeader) { + /*string pdbDirectory = Path.GetDirectoryName(fileName); + if (!reader.TryOpenAssociatedPortablePdb(pdbDirectory, OpenStream, out var provider, out var pdbFileName) { return; } // search for pdb in same directory as dll - string pdbName = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName) + ".pdb"); + string pdbName = Path.Combine(, Path.GetFileNameWithoutExtension(fileName) + ".pdb"); if (File.Exists(pdbName)) { using (Stream s = File.OpenRead(pdbName)) { module.ReadSymbols(new Mono.Cecil.Pdb.PdbReaderProvider().GetSymbolReader(module, s)); @@ -183,6 +159,11 @@ namespace ICSharpCode.ILSpy } // TODO: use symbol cache, get symbols from microsoft + + Stream OpenStream(string pdbFileName) + { + + }*/ } [ThreadStatic] @@ -218,18 +199,9 @@ namespace ICSharpCode.ILSpy this.parent = parent; } - public AssemblyDefinition Resolve(AssemblyNameReference name) - { - return parent.LookupReferencedAssembly(name)?.GetAssemblyDefinitionOrNull(); - } - - public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters) - { - return parent.LookupReferencedAssembly(name)?.GetAssemblyDefinitionOrNull(); - } - - public void Dispose() + public PEFile Resolve(IAssemblyReference reference) { + return parent.LookupReferencedAssembly(reference)?.GetPEFileOrNull(); } } @@ -238,14 +210,12 @@ namespace ICSharpCode.ILSpy return new MyAssemblyResolver(this); } - public LoadedAssembly LookupReferencedAssembly(AssemblyNameReference name) + public LoadedAssembly LookupReferencedAssembly(IAssemblyReference reference) { - if (name == null) - throw new ArgumentNullException(nameof(name)); - if (name.IsWindowsRuntime) { - return assemblyList.assemblyLookupCache.GetOrAdd((name.Name, true), LookupReferencedAssemblyInternal); + if (reference.IsWindowsRuntime) { + return assemblyList.assemblyLookupCache.GetOrAdd((reference.Name, true), LookupReferencedAssemblyInternal); } else { - return assemblyList.assemblyLookupCache.GetOrAdd((name.FullName, false), LookupReferencedAssemblyInternal); + return assemblyList.assemblyLookupCache.GetOrAdd((reference.FullName, false), LookupReferencedAssemblyInternal); } } @@ -265,8 +235,10 @@ namespace ICSharpCode.ILSpy LoadedAssembly asm; lock (loadingAssemblies) { foreach (LoadedAssembly loaded in assemblyList.GetAssemblies()) { - var asmDef = loaded.GetAssemblyDefinitionOrNull(); - if (asmDef != null && data.fullName.Equals(data.isWinRT ? asmDef.Name.Name : asmDef.FullName, StringComparison.OrdinalIgnoreCase)) { + var reader = loaded.GetPEFileOrNull()?.GetMetadataReader(); + if (reader == null || !reader.IsAssembly) continue; + var asmDef = reader.GetAssemblyDefinition(); + if (data.fullName.Equals(data.isWinRT ? reader.GetString(asmDef.Name) : reader.GetFullAssemblyName(), StringComparison.OrdinalIgnoreCase)) { LoadedAssemblyReferencesInfo.AddMessageOnce(data.fullName, MessageKind.Info, "Success - Found in Assembly List"); return loaded; } @@ -312,7 +284,7 @@ namespace ICSharpCode.ILSpy return asm; } - public Task ContinueWhenLoaded(Action> onAssemblyLoaded, TaskScheduler taskScheduler) + public Task ContinueWhenLoaded(Action> onAssemblyLoaded, TaskScheduler taskScheduler) { return this.assemblyTask.ContinueWith(onAssemblyLoaded, default(CancellationToken), TaskContinuationOptions.RunContinuationsAsynchronously, taskScheduler); } diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 490b10a65..8e1da8396 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -38,7 +38,6 @@ using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.TreeView; using Microsoft.Win32; -using Mono.Cecil; namespace ICSharpCode.ILSpy { @@ -273,14 +272,14 @@ namespace ICSharpCode.ILSpy } } else { foreach (LoadedAssembly asm in commandLineLoadedAssemblies) { - ModuleDefinition def = asm.GetModuleDefinitionOrNull(); + var def = asm.GetPEFileOrNull(); if (def != null) { - MemberReference mr = XmlDocKeyProvider.FindMemberByKey(def, args.NavigateTo); + /*MemberReference mr = XmlDocKeyProvider.FindMemberByKey(def, args.NavigateTo); if (mr != null) { found = true; JumpToReference(mr); break; - } + }*/ } } } @@ -292,7 +291,7 @@ namespace ICSharpCode.ILSpy } else if (commandLineLoadedAssemblies.Count == 1) { // NavigateTo == null and an assembly was given on the command-line: // Select the newly loaded assembly - JumpToReference(commandLineLoadedAssemblies[0].GetModuleDefinitionOrNull()); + JumpToReference(commandLineLoadedAssemblies[0].GetPEFileOrNull()); } if (args.Search != null) { @@ -577,7 +576,7 @@ namespace ICSharpCode.ILSpy public ILSpyTreeNode FindTreeNode(object reference) { - if (reference is TypeReference) + /*if (reference is TypeReference) { return assemblyListTreeNode.FindTypeNode(((TypeReference)reference).Resolve()); } @@ -597,7 +596,7 @@ namespace ICSharpCode.ILSpy { return assemblyListTreeNode.FindEventNode(((EventReference)reference).Resolve()); } - else if (reference is AssemblyDefinition) + else if (reference is PEFile) { return assemblyListTreeNode.FindAssemblyNode((AssemblyDefinition)reference); } @@ -607,12 +606,14 @@ namespace ICSharpCode.ILSpy } else if (reference is Resource) { - return assemblyListTreeNode.FindResourceNode((Resource)reference); + return null; + //return assemblyListTreeNode.FindResourceNode((Resource)reference); } else { return null; - } + }*/ + return null; } public void JumpToReference(object reference) diff --git a/ILSpy/SearchPane.cs b/ILSpy/SearchPane.cs index 364fe3fe3..eb5f55f45 100644 --- a/ILSpy/SearchPane.cs +++ b/ILSpy/SearchPane.cs @@ -26,7 +26,7 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; - +using ICSharpCode.Decompiler.Dom; using ICSharpCode.ILSpy.TreeNodes; using Mono.Cecil; @@ -216,12 +216,12 @@ namespace ICSharpCode.ILSpy try { var searcher = GetSearchStrategy(searchMode, searchTerm); foreach (var loadedAssembly in assemblies) { - ModuleDefinition module = loadedAssembly.GetModuleDefinitionOrNull(); + var module = loadedAssembly.GetPEFileOrNull(); if (module == null) continue; CancellationToken cancellationToken = cts.Token; - foreach (TypeDefinition type in module.Types) { + foreach (var type in module.TypeDefinitions) { cancellationToken.ThrowIfCancellationRequested(); searcher.Search(type, language, AddResult); } @@ -333,7 +333,7 @@ namespace ICSharpCode.ILSpy public static readonly System.Collections.Generic.IComparer Comparer = new SearchResultComparer(); - public MemberReference Member { get; set; } + public IMemberReference Member { get; set; } public float Fitness { get; set; } public string Location { get; set; } diff --git a/ILSpy/SearchStrategies.cs b/ILSpy/SearchStrategies.cs index 46385006d..10ef8bdfd 100644 --- a/ILSpy/SearchStrategies.cs +++ b/ILSpy/SearchStrategies.cs @@ -3,11 +3,12 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Windows.Media; -using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Util; using ICSharpCode.ILSpy.TreeNodes; -using Mono.Cecil; -using Code = Mono.Cecil.Cil.Code; +using ICSharpCode.Decompiler.Dom; +using System.Reflection; +using ICSharpCode.Decompiler.Disassembler; +using ILOpCode = System.Reflection.Metadata.ILOpCode; namespace ICSharpCode.ILSpy { @@ -37,7 +38,7 @@ namespace ICSharpCode.ILSpy searchTerm = terms; } - protected float CalculateFitness(MemberReference member) + protected float CalculateFitness(IMemberReference member) { string text = member.Name; @@ -49,11 +50,11 @@ namespace ICSharpCode.ILSpy // Constructors always have the same name in IL: // Use type name instead if (text == ".cctor" || text == ".ctor") { - text = member.DeclaringType.Name; + //text = member.DeclaringType.Name; } // Ignore generic arguments, it not possible to search based on them either - text = ReflectionHelper.SplitTypeParameterCountFromReflectionName(text); + text = Decompiler.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(text); return 1.0f / text.Length; } @@ -139,7 +140,7 @@ namespace ICSharpCode.ILSpy } } - void Add(IEnumerable items, TypeDefinition type, Language language, Action addResult, Func matcher, Func image) where T : MemberReference + void Add(IEnumerable items, TypeDefinition type, Language language, Action addResult, Func matcher, Func image) where T : IMemberReference { foreach (var item in items) { if (matcher(item, language)) { @@ -170,12 +171,12 @@ namespace ICSharpCode.ILSpy bool NotSpecialMethod(MethodDefinition arg) { - return (arg.SemanticsAttributes & ( + return (arg.GetMethodSemanticsAttributes() & ( MethodSemanticsAttributes.Setter | MethodSemanticsAttributes.Getter - | MethodSemanticsAttributes.AddOn - | MethodSemanticsAttributes.RemoveOn - | MethodSemanticsAttributes.Fire)) == 0; + | MethodSemanticsAttributes.Adder + | MethodSemanticsAttributes.Remover + | MethodSemanticsAttributes.Raiser)) == 0; } Regex SafeNewRegex(string unsafePattern) @@ -227,7 +228,7 @@ namespace ICSharpCode.ILSpy protected override bool IsMatch(FieldDefinition field, Language language) { - return IsLiteralMatch(field.Constant); + return IsLiteralMatch(field.DecodeConstant()); } protected override bool IsMatch(PropertyDefinition property, Language language) @@ -268,91 +269,115 @@ namespace ICSharpCode.ILSpy bool MethodIsLiteralMatch(MethodDefinition m) { - if (m == null) - return false; - var body = m.Body; - if (body == null) + if (m == null || !m.HasBody) return false; + var blob = m.Body.GetILReader(); if (searchTermLiteralType == TypeCode.Int64) { long val = (long)searchTermLiteralValue; - foreach (var inst in body.Instructions) { - switch (inst.OpCode.Code) { - case Code.Ldc_I8: - if (val == (long)inst.Operand) - return true; - break; - case Code.Ldc_I4: - if (val == (int)inst.Operand) - return true; - break; - case Code.Ldc_I4_S: - if (val == (sbyte)inst.Operand) - return true; - break; - case Code.Ldc_I4_M1: - if (val == -1) - return true; - break; - case Code.Ldc_I4_0: - if (val == 0) - return true; - break; - case Code.Ldc_I4_1: - if (val == 1) - return true; - break; - case Code.Ldc_I4_2: - if (val == 2) - return true; - break; - case Code.Ldc_I4_3: - if (val == 3) - return true; - break; - case Code.Ldc_I4_4: - if (val == 4) - return true; - break; - case Code.Ldc_I4_5: - if (val == 5) - return true; - break; - case Code.Ldc_I4_6: - if (val == 6) - return true; - break; - case Code.Ldc_I4_7: - if (val == 7) - return true; - break; - case Code.Ldc_I4_8: - if (val == 8) - return true; - break; + while (blob.RemainingBytes > 0) { + ILOpCode code; + switch (code = ILParser.DecodeOpCode(ref blob)) { + case ILOpCode.Ldc_i8: + if (val == blob.ReadInt64()) + return true; + break; + case ILOpCode.Ldc_i4: + if (val == blob.ReadInt32()) + return true; + break; + case ILOpCode.Ldc_i4_s: + if (val == blob.ReadSByte()) + return true; + break; + case ILOpCode.Ldc_i4_m1: + if (val == -1) + return true; + break; + case ILOpCode.Ldc_i4_0: + if (val == 0) + return true; + break; + case ILOpCode.Ldc_i4_1: + if (val == 1) + return true; + break; + case ILOpCode.Ldc_i4_2: + if (val == 2) + return true; + break; + case ILOpCode.Ldc_i4_3: + if (val == 3) + return true; + break; + case ILOpCode.Ldc_i4_4: + if (val == 4) + return true; + break; + case ILOpCode.Ldc_i4_5: + if (val == 5) + return true; + break; + case ILOpCode.Ldc_i4_6: + if (val == 6) + return true; + break; + case ILOpCode.Ldc_i4_7: + if (val == 7) + return true; + break; + case ILOpCode.Ldc_i4_8: + if (val == 8) + return true; + break; + default: + ILParser.SkipOperand(ref blob, code); + break; } } } else if (searchTermLiteralType != TypeCode.Empty) { - Code expectedCode; + ILOpCode expectedCode; switch (searchTermLiteralType) { - case TypeCode.Single: - expectedCode = Code.Ldc_R4; - break; - case TypeCode.Double: - expectedCode = Code.Ldc_R8; - break; - case TypeCode.String: - expectedCode = Code.Ldstr; - break; - default: - throw new InvalidOperationException(); + case TypeCode.Single: + expectedCode = ILOpCode.Ldc_r4; + break; + case TypeCode.Double: + expectedCode = ILOpCode.Ldc_r8; + break; + case TypeCode.String: + expectedCode = ILOpCode.Ldstr; + break; + default: + throw new InvalidOperationException(); } - foreach (var inst in body.Instructions) { - if (inst.OpCode.Code == expectedCode && searchTermLiteralValue.Equals(inst.Operand)) - return true; + while (blob.RemainingBytes > 0) { + var code = ILParser.DecodeOpCode(ref blob); + if (code != expectedCode) { + ILParser.SkipOperand(ref blob, code); + continue; + } + switch (code) { + case ILOpCode.Ldc_r4: + if ((float)searchTermLiteralValue == blob.ReadSingle()) + return true; + break; + case ILOpCode.Ldc_r8: + if ((double)searchTermLiteralValue == blob.ReadDouble()) + return true; + break; + case ILOpCode.Ldstr: + if ((string)searchTermLiteralValue == ILParser.DecodeUserString(ref blob, m.Module)) + return true; + break; + } } } else { - foreach (var inst in body.Instructions) { - if (inst.OpCode.Code == Code.Ldstr && IsMatch(t => (string)inst.Operand)) + while (blob.RemainingBytes > 0) { + var code = ILParser.DecodeOpCode(ref blob); + if (code != ILOpCode.Ldstr) { + ILParser.SkipOperand(ref blob, code); + continue; + } + if (IsMatch(t => ILParser.DecodeUserString(ref blob, m.Module))) return true; } } @@ -450,8 +475,8 @@ namespace ICSharpCode.ILSpy Image = TypeTreeNode.GetIcon(type), Fitness = CalculateFitness(type), Name = name, - LocationImage = type.DeclaringType != null ? TypeTreeNode.GetIcon(type.DeclaringType) : Images.Namespace, - Location = type.DeclaringType != null ? language.TypeToString(type.DeclaringType, includeNamespace: true) : type.Namespace + LocationImage = !type.DeclaringType.IsNil ? TypeTreeNode.GetIcon(type.DeclaringType) : Images.Namespace, + Location = !type.DeclaringType.IsNil ? language.TypeToString(type.DeclaringType, includeNamespace: true) : type.Namespace }); } diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index a56020dd6..bb1e98a20 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -200,12 +200,12 @@ namespace ICSharpCode.ILSpy.TextView string documentation = docProvider.GetDocumentation("F:System.Reflection.Emit.OpCodes." + code.EncodedName); if (documentation != null) { XmlDocRenderer renderer = new XmlDocRenderer(); - renderer.AppendText($"{code.Name} (0x{code.Code:x2}) - "); + renderer.AppendText($"{code.Name} (0x{code.Code:x}) - "); renderer.AddXmlDocumentation(documentation); return renderer.CreateTextBlock(); } } - return $"{code.Name} (0x{code.Code:x2})"; + return $"{code.Name} (0x{code.Code:x})"; } else if (segment.Reference is MemberReference) { MemberReference mr = (MemberReference)segment.Reference; // if possible, resolve the reference @@ -215,7 +215,7 @@ namespace ICSharpCode.ILSpy.TextView mr = ((MethodReference)mr).Resolve() ?? mr; } XmlDocRenderer renderer = new XmlDocRenderer(); - renderer.AppendText(MainWindow.Instance.CurrentLanguage.GetTooltip(mr)); + //renderer.AppendText(MainWindow.Instance.CurrentLanguage.GetTooltip(mr)); try { XmlDocumentationProvider docProvider = XmlDocLoader.LoadDocumentation(mr.Module); if (docProvider != null) { diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs b/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs index d11922724..e28593e31 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs @@ -17,7 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System.Linq; -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -62,32 +62,31 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer } } - public static void Analyze(MemberReference member) + public static void Analyze(IMemberReference member) { - if (member is TypeReference) { - TypeDefinition type = ((TypeReference)member).Resolve(); - if (type != null) - AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedTypeTreeNode(type)); - } - else if (member is FieldReference) { - FieldDefinition field = ((FieldReference)member).Resolve(); - if (field != null) - AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedFieldTreeNode(field)); - } - else if (member is MethodReference) { - MethodDefinition method = ((MethodReference)member).Resolve(); - if (method != null) - AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedMethodTreeNode(method)); - } - else if (member is PropertyReference) { - PropertyDefinition property = ((PropertyReference)member).Resolve(); - if (property != null) - AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedPropertyTreeNode(property)); - } - else if (member is EventReference) { - EventDefinition @event = ((EventReference)member).Resolve(); - if (@event != null) - AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedEventTreeNode(@event)); + var definition = member.GetDefinition(); + if (definition == null) return; + switch (definition) { + case TypeDefinition td: + if (!td.IsNil) + AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedTypeTreeNode(td)); + break; + case FieldDefinition fd: + if (!fd.IsNil) + AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedFieldTreeNode(fd)); + break; + case MethodDefinition md: + if (!md.IsNil) + AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedMethodTreeNode(md)); + break; + case PropertyDefinition pd: + if (!pd.IsNil) + AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedPropertyTreeNode(pd)); + break; + case EventDefinition ed: + if (!ed.IsNil) + AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedEventTreeNode(ed)); + break; } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedAssemblyTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedAssemblyTreeNode.cs index c5c893263..1dc07921a 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedAssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedAssemblyTreeNode.cs @@ -17,15 +17,15 @@ // DEALINGS IN THE SOFTWARE. using System; -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { internal class AnalyzedAssemblyTreeNode : AnalyzerEntityTreeNode { - private readonly ModuleDefinition analyzedAssembly; + private readonly PEFile analyzedAssembly; - public AnalyzedAssemblyTreeNode(ModuleDefinition analyzedAssembly) + public AnalyzedAssemblyTreeNode(PEFile analyzedAssembly) { if (analyzedAssembly == null) throw new ArgumentNullException(nameof(analyzedAssembly)); @@ -33,27 +33,15 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer //this.LazyLoading = true; } - public override object Icon - { - get { return Images.Assembly; } - } + public override object Icon => Images.Assembly; - public override object Text - { - get - { - return analyzedAssembly.Name; - } - } + public override object Text => analyzedAssembly.Name; protected override void LoadChildren() { //this.Children.Add(new AnalyzedAssemblyReferencedByTreeNode(analyzedAssembly)); } - public override MemberReference Member - { - get { return null; } - } + public override IMemberReference Member => null; } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedAttributeAppliedToTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedAttributeAppliedToTreeNode.cs index a5211f757..df134f000 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedAttributeAppliedToTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedAttributeAppliedToTreeNode.cs @@ -20,9 +20,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading; -using Mono.Cecil; using System.Collections.Concurrent; using ICSharpCode.Decompiler.Util; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -43,7 +43,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public AnalyzedAttributeAppliedToTreeNode(TypeDefinition analyzedType) { - if (analyzedType == null) + if (analyzedType.IsNil) throw new ArgumentNullException(nameof(analyzedType)); this.analyzedType = analyzedType; @@ -103,7 +103,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer #region standard custom attributes - private IEnumerable FindReferencesInAssembly(ModuleDefinition module, TypeReference tr, CancellationToken ct) + private IEnumerable FindReferencesInAssembly(PEFile module, TypeReference tr, CancellationToken ct) { //since we do not display modules as separate entities, coalesce the assembly and module searches bool foundInAssyOrModule = false; diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorTreeNode.cs index 7d06191d0..e6f59f60b 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorTreeNode.cs @@ -16,7 +16,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs index e3be33a6f..853cbf580 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs @@ -19,9 +19,10 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Threading; -using ICSharpCode.Decompiler.TypeSystem; -using Mono.Cecil; +using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -31,7 +32,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public AnalyzedEventOverridesTreeNode(EventDefinition analyzedEvent) { - if (analyzedEvent == null) + if (analyzedEvent.IsNil) throw new ArgumentNullException(nameof(analyzedEvent)); this.analyzedEvent = analyzedEvent; @@ -50,7 +51,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer private IEnumerable FindReferencesInType(TypeDefinition type) { - if (!TypesHierarchyHelpers.IsBaseType(analyzedEvent.DeclaringType, type, resolveTypeArguments: false)) + if (!analyzedEvent.DeclaringType.IsBaseTypeOf(type)) yield break; foreach (EventDefinition eventDef in type.Events) { @@ -66,8 +67,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public static bool CanShow(EventDefinition property) { - var accessor = property.AddMethod ?? property.RemoveMethod; - return accessor.IsVirtual && !accessor.IsFinal && !accessor.DeclaringType.IsInterface; + var accessor = property.GetAccessors().First().Method; + return accessor.HasFlag(MethodAttributes.Virtual) && !accessor.HasFlag(MethodAttributes.Final) && !accessor.DeclaringType.IsInterface; } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs index e8d25079e..7bfe4a43c 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs @@ -17,7 +17,8 @@ // DEALINGS IN THE SOFTWARE. using System; -using Mono.Cecil; +using System.Linq; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -35,9 +36,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer this.LazyLoading = true; } - public override MemberReference Member { - get { return analyzedEvent; } - } + public override IMemberReference Member => analyzedEvent; public override object Icon { @@ -82,13 +81,12 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return null; } - public static bool CanShow(MemberReference member) + public static bool CanShow(IMemberReference member) { - var eventDef = member as EventDefinition; - if (eventDef == null) + if (!(member is EventDefinition eventDef)) return false; - return !MainWindow.Instance.CurrentLanguage.ShowMember(eventDef.AddMethod ?? eventDef.RemoveMethod) + return !MainWindow.Instance.CurrentLanguage.ShowMember(eventDef.GetAccessors().First().Method) || AnalyzedEventOverridesTreeNode.CanShow(eventDef); } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs index cc4a9aadd..4891e8d12 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs @@ -21,8 +21,10 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading; -using Mono.Cecil; -using Mono.Cecil.Cil; +using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.Dom; + +using ILOpCode = System.Reflection.Metadata.ILOpCode; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -35,7 +37,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public AnalyzedFieldAccessTreeNode(FieldDefinition analyzedField, bool showWrites) { - if (analyzedField == null) + if (analyzedField.IsNil) throw new ArgumentNullException(nameof(analyzedField)); this.analyzedField = analyzedField; @@ -67,24 +69,27 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer bool found = false; if (!method.HasBody) continue; - foreach (Instruction instr in method.Body.Instructions) { - if (CanBeReference(instr.OpCode.Code)) { - FieldReference fr = instr.Operand as FieldReference; - if (fr != null && fr.Name == name && - Helpers.IsReferencedBy(analyzedField.DeclaringType, fr.DeclaringType) && - fr.Resolve() == analyzedField) { - found = true; - break; - } + var blob = method.Body.GetILReader(); + while (blob.RemainingBytes > 0) { + var opCode = ILParser.DecodeOpCode(ref blob); + if (!CanBeReference(opCode)) { + ILParser.SkipOperand(ref blob, opCode); + continue; } + var field = ILParser.DecodeMemberToken(ref blob, method.Module); + if (field == null || field.Name != name) + continue; + var definition = field.GetDefinition() as FieldDefinition?; + if (definition?.DeclaringType.FullName != analyzedField.DeclaringType.FullName) + continue; + found = true; + break; } - method.Body = null; - if (found) { - MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition; - if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) { - var node = new AnalyzedMethodTreeNode(codeLocation); + MethodDefinition? codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition?; + if (codeLocation != null && !HasAlreadyBeenFound(codeLocation.Value)) { + var node = new AnalyzedMethodTreeNode(codeLocation.Value); node.Language = this.Language; yield return node; } @@ -92,17 +97,17 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer } } - private bool CanBeReference(Code code) + private bool CanBeReference(ILOpCode code) { switch (code) { - case Code.Ldfld: - case Code.Ldsfld: + case ILOpCode.Ldfld: + case ILOpCode.Ldsfld: return !showWrites; - case Code.Stfld: - case Code.Stsfld: + case ILOpCode.Stfld: + case ILOpCode.Stsfld: return showWrites; - case Code.Ldflda: - case Code.Ldsflda: + case ILOpCode.Ldflda: + case ILOpCode.Ldsflda: return true; // always show address-loading default: return false; diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedFieldTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedFieldTreeNode.cs index 3c8a94dc8..a14d51435 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedFieldTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedFieldTreeNode.cs @@ -17,7 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -27,16 +27,13 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public AnalyzedFieldTreeNode(FieldDefinition analyzedField) { - if (analyzedField == null) + if (analyzedField.IsNil) throw new ArgumentNullException(nameof(analyzedField)); this.analyzedField = analyzedField; this.LazyLoading = true; } - public override object Icon - { - get { return FieldTreeNode.GetIcon(analyzedField); } - } + public override object Icon => FieldTreeNode.GetIcon(analyzedField); public override object Text { @@ -54,8 +51,6 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer this.Children.Add(new AnalyzedFieldAccessTreeNode(analyzedField, true)); } - public override MemberReference Member { - get { return analyzedField; } - } + public override IMemberReference Member => analyzedField; } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs index 42804b0de..d12c808a3 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs @@ -17,7 +17,8 @@ // DEALINGS IN THE SOFTWARE. using System; -using Mono.Cecil; +using System.Reflection; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -28,7 +29,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public AnalyzedMethodTreeNode(MethodDefinition analyzedMethod, string prefix = "") { - if (analyzedMethod == null) + if (analyzedMethod.IsNil) throw new ArgumentNullException(nameof(analyzedMethod)); this.analyzedMethod = analyzedMethod; this.prefix = prefix; @@ -53,7 +54,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer if (analyzedMethod.HasBody) this.Children.Add(new AnalyzedMethodUsesTreeNode(analyzedMethod)); - if (analyzedMethod.IsVirtual && !(analyzedMethod.IsNewSlot && analyzedMethod.IsFinal)) + if (analyzedMethod.HasFlag(MethodAttributes.Virtual) && !(analyzedMethod.HasFlag(MethodAttributes.NewSlot) && analyzedMethod.HasFlag(MethodAttributes.Final))) this.Children.Add(new AnalyzedVirtualMethodUsedByTreeNode(analyzedMethod)); else this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedMethod)); @@ -65,8 +66,6 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer this.Children.Add(new AnalyzedInterfaceMethodImplementedByTreeNode(analyzedMethod)); } - public override MemberReference Member { - get { return analyzedMethod; } - } + public override IMemberReference Member => analyzedMethod; } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs index 0cb82941a..ff776fc8e 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs @@ -66,7 +66,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer foreach (Instruction instr in method.Body.Instructions) { MethodReference mr = instr.Operand as MethodReference; if (mr != null && mr.Name == name && - Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) && + Helpers.IsSameType(analyzedMethod.DeclaringType, mr.DeclaringType) && mr.Resolve() == analyzedMethod) { found = true; break; diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs index 7efed4032..5f2b3c9ad 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs @@ -20,8 +20,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading; -using Mono.Cecil; -using Mono.Cecil.Cil; +using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.Dom; +using ICSharpCode.Decompiler.IL; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -34,7 +35,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public AnalyzedMethodUsesTreeNode(MethodDefinition analyzedMethod) { - if (analyzedMethod == null) + if (analyzedMethod.IsNil) throw new ArgumentNullException(nameof(analyzedMethod)); this.analyzedMethod = analyzedMethod; @@ -61,24 +62,42 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer private IEnumerable GetUsedMethods() { - foreach (Instruction instr in analyzedMethod.Body.Instructions) { - MethodReference mr = instr.Operand as MethodReference; - if (mr != null) { - MethodDefinition def = mr.Resolve(); - if (def != null) - yield return def; + if (!analyzedMethod.HasBody) yield break; + var blob = analyzedMethod.Body.GetILReader(); + while (blob.RemainingBytes > 0) { + var opCode = ILParser.DecodeOpCode(ref blob); + switch (opCode.GetOperandType()) { + case OperandType.Method: + case OperandType.Sig: + case OperandType.Tok: + var member = ILParser.DecodeMemberToken(ref blob, analyzedMethod.Module).GetDefinition(); + if (member is MethodDefinition md) + yield return md; + break; + default: + ILParser.SkipOperand(ref blob, opCode); + break; } } } - private IEnumerable GetUsedFields() + IEnumerable GetUsedFields() { - foreach (Instruction instr in analyzedMethod.Body.Instructions) { - FieldReference fr = instr.Operand as FieldReference; - if (fr != null) { - FieldDefinition def = fr.Resolve(); - if (def != null) - yield return def; + if (!analyzedMethod.HasBody) yield break; + var blob = analyzedMethod.Body.GetILReader(); + while (blob.RemainingBytes > 0) { + var opCode = ILParser.DecodeOpCode(ref blob); + switch (opCode.GetOperandType()) { + case OperandType.Field: + case OperandType.Sig: + case OperandType.Tok: + var member = ILParser.DecodeMemberToken(ref blob, analyzedMethod.Module).GetDefinition(); + if (member is FieldDefinition fd) + yield return fd; + break; + default: + ILParser.SkipOperand(ref blob, opCode); + break; } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs index 5ce4956e6..7865c7d48 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs @@ -16,7 +16,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs index 69db2bcc6..6a76dbe14 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs @@ -19,9 +19,10 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Threading; -using ICSharpCode.Decompiler.TypeSystem; -using Mono.Cecil; +using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -50,11 +51,11 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer private IEnumerable FindReferencesInType(TypeDefinition type) { - if (!TypesHierarchyHelpers.IsBaseType(analyzedProperty.DeclaringType, type, resolveTypeArguments: false)) + if (!analyzedProperty.DeclaringType.IsBaseTypeOf(type)) yield break; foreach (PropertyDefinition property in type.Properties) { - + analyzedProperty. if (TypesHierarchyHelpers.IsBaseProperty(analyzedProperty, property)) { MethodDefinition anyAccessor = property.GetMethod ?? property.SetMethod; bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot; @@ -67,8 +68,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public static bool CanShow(PropertyDefinition property) { - var accessor = property.GetMethod ?? property.SetMethod; - return accessor.IsVirtual && !accessor.IsFinal && !accessor.DeclaringType.IsInterface; + var accessor = property.GetAccessors().First().Method; + return accessor.HasFlag(MethodAttributes.Virtual) && !accessor.HasFlag(MethodAttributes.Final) && !accessor.DeclaringType.IsInterface; } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs index 536670d77..9caaa4b22 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs @@ -18,7 +18,7 @@ using System; using ICSharpCode.Decompiler; -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -32,7 +32,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { if (analyzedProperty == null) throw new ArgumentNullException(nameof(analyzedProperty)); - this.isIndexer = analyzedProperty.IsIndexer(); + this.isIndexer = analyzedProperty.IsIndexer; this.analyzedProperty = analyzedProperty; this.prefix = prefix; this.LazyLoading = true; @@ -54,9 +54,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer protected override void LoadChildren() { - if (analyzedProperty.GetMethod != null) + if (!analyzedProperty.GetMethod.IsNil) this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.GetMethod, "get")); - if (analyzedProperty.SetMethod != null) + if (!analyzedProperty.SetMethod.IsNil) this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.SetMethod, "set")); foreach (var accessor in analyzedProperty.OtherMethods) this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null)); @@ -67,26 +67,23 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer this.Children.Add(new AnalyzedInterfacePropertyImplementedByTreeNode(analyzedProperty)); } - public static AnalyzerTreeNode TryCreateAnalyzer(MemberReference member) + public static AnalyzerTreeNode TryCreateAnalyzer(IMemberReference member) { if (CanShow(member)) - return new AnalyzedPropertyTreeNode(member as PropertyDefinition); + return new AnalyzedPropertyTreeNode((PropertyDefinition)member); else return null; } - public static bool CanShow(MemberReference member) + public static bool CanShow(IMemberReference member) { - var property = member as PropertyDefinition; - if (property == null) + if (!(member is PropertyDefinition property)) return false; - return !MainWindow.Instance.CurrentLanguage.ShowMember(property.GetMethod ?? property.SetMethod) + return !MainWindow.Instance.CurrentLanguage.ShowMember(property.GetMethod.IsNil ? property.SetMethod : property.GetMethod) || AnalyzedPropertyOverridesTreeNode.CanShow(property); } - - public override MemberReference Member { - get { return analyzedProperty; } - } + + public override IMemberReference Member => analyzedProperty; } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs index 1da7b9bcf..ffb6e5bd2 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs @@ -19,8 +19,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Threading; -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -30,7 +31,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public AnalyzedTypeExposedByTreeNode(TypeDefinition analyzedType) { - if (analyzedType == null) + if (analyzedType.IsNil) throw new ArgumentNullException(nameof(analyzedType)); this.analyzedType = analyzedType; @@ -135,7 +136,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer // exclude methods with 'semantics'. for example, property getters & setters. // HACK: this is a potentially fragile implementation, as the MethodSemantics may be extended to other uses at a later date. - if (method.SemanticsAttributes != MethodSemanticsAttributes.None) + if (method.GetMethodSemanticsAttributes() != 0) return false; if (method.ReturnType.Resolve() == analyzedType) @@ -153,8 +154,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer private static bool IsPrivate(PropertyDefinition property) { - bool isGetterPublic = (property.GetMethod != null && !property.GetMethod.IsPrivate); - bool isSetterPublic = (property.SetMethod != null && !property.SetMethod.IsPrivate); + bool isGetterPublic = (!property.GetMethod.IsNil && !property.GetMethod.IsPrivate); + bool isSetterPublic = (!property.SetMethod.IsNil && !property.SetMethod.IsPrivate); return !(isGetterPublic || isSetterPublic); } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs index 43b20c722..e69097345 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs @@ -19,10 +19,11 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Threading; -using ICSharpCode.Decompiler.TypeSystem; -using Mono.Cecil; -using Mono.Cecil.Cil; +using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.Dom; +using ICSharpCode.Decompiler.IL; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -33,12 +34,12 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public AnalyzedTypeInstantiationsTreeNode(TypeDefinition analyzedType) { - if (analyzedType == null) + if (analyzedType.IsNil) throw new ArgumentNullException(nameof(analyzedType)); this.analyzedType = analyzedType; - this.isSystemObject = (analyzedType.FullName == "System.Object"); + this.isSystemObject = (analyzedType.FullName.ToString() == "System.Object"); } public override object Text @@ -61,22 +62,30 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer // ignore chained constructors // (since object is the root of everything, we can short circuit the test in this case) - if (method.Name == ".ctor" && - (isSystemObject || analyzedType == type || TypesHierarchyHelpers.IsBaseType(analyzedType, type, false))) + if (method.IsConstructor && (isSystemObject || analyzedType == type || analyzedType.IsBaseTypeOf(type))) continue; - foreach (Instruction instr in method.Body.Instructions) { - MethodReference mr = instr.Operand as MethodReference; - if (mr != null && mr.Name == ".ctor") { - if (Helpers.IsReferencedBy(analyzedType, mr.DeclaringType)) { - found = true; + var blob = method.Body.GetILReader(); + + while (!found && blob.RemainingBytes > 0) { + var opCode = ILParser.DecodeOpCode(ref blob); + switch (opCode.GetOperandType()) { + case OperandType.Method: + case OperandType.Sig: + case OperandType.Tok: + var member = ILParser.DecodeMemberToken(ref blob, method.Module); + if (member.Name == ".ctor") { + if (member.DeclaringType.FullName == analyzedType.FullName) { + found = true; + } + } + break; + default: + ILParser.SkipOperand(ref blob, opCode); break; - } } } - method.Body = null; - if (found) { var node = new AnalyzedMethodTreeNode(method); node.Language = this.Language; @@ -87,7 +96,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public static bool CanShow(TypeDefinition type) { - return (type.IsClass && !(type.IsAbstract && type.IsSealed) && !type.IsEnum); + return (type.IsClass && !(type.HasFlag(TypeAttributes.Abstract) && type.HasFlag(TypeAttributes.Sealed)) && !type.IsEnum); } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs index aff0135ee..7e94f8b1f 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs @@ -17,7 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public AnalyzedTypeTreeNode(TypeDefinition analyzedType) { - if (analyzedType == null) + if (analyzedType.IsNil) throw new ArgumentNullException(nameof(analyzedType)); this.analyzedType = analyzedType; this.LazyLoading = true; @@ -64,8 +64,6 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer this.Children.Add(new AnalyzedTypeExtensionMethodsTreeNode(analyzedType)); } - public override MemberReference Member { - get { return analyzedType; } - } + public override IMemberReference Member => analyzedType; } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs index a3aca579a..b87d4a3cd 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs @@ -20,7 +20,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading; -using Mono.Cecil; +using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.Dom; +using ICSharpCode.Decompiler.Util; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -30,7 +32,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public AnalyzedTypeUsedByTreeNode(TypeDefinition analyzedType) { - if (analyzedType == null) + if (analyzedType.IsNil) throw new ArgumentNullException(nameof(analyzedType)); this.analyzedType = analyzedType; @@ -46,7 +48,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer var analyzer = new ScopedWhereUsedAnalyzer(analyzedType, FindTypeUsage); return analyzer.PerformAnalysis(ct) .Cast() - .Where(n => n.Member.DeclaringType != analyzedType) + .Where(n => n.Member.DeclaringType.FullName != analyzedType.FullName) .Distinct(new AnalyzerEntityTreeNodeComparer()) .OrderBy(n => n.Text); } @@ -59,7 +61,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer if (IsUsedInTypeDefinition(type)) yield return new AnalyzedTypeTreeNode(type) { Language = Language }; - foreach (var field in type.Fields.Where(IsUsedInFieldReference)) + foreach (var field in type.Fields.Where(IsUsedInField)) yield return new AnalyzedFieldTreeNode(field) { Language = Language }; foreach (var method in type.Methods.Where(IsUsedInMethodDefinition)) @@ -80,7 +82,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return types.Any(IsUsedInTypeReference); } - private bool IsUsedInTypeReference(TypeReference type) + private bool IsUsedInTypeReference(ITypeReference type) { if (type == null) return false; @@ -96,16 +98,14 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer || IsUsedInTypeReferences(type.Interfaces.Select(i => i.InterfaceType)); } - private bool IsUsedInFieldReference(FieldReference field) + private bool IsUsedInField(FieldDefinition field) { - if (field == null) - return false; + if (field.IsNil) return false; - return TypeMatches(field.DeclaringType) - || TypeMatches(field.FieldType); + return TypeMatches(field.DeclaringType) || field.DecodeSignature(new TypeUsedInSignature(analyzedType), default(Unit)); } - private bool IsUsedInMethodReference(MethodReference method) + private bool IsUsedInMethod(MethodDefinition method) { if (method == null) return false; @@ -161,10 +161,10 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return TypeMatches(parameter.ParameterType); } - private bool TypeMatches(TypeReference tref) + private bool TypeMatches(ITypeReference tref) { if (tref != null && tref.Name == analyzedType.Name) { - var tdef = tref.Resolve(); + var tdef = tref.GetDefinition(); if (tdef != null) { return (tdef == analyzedType); } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs index 266f1460a..cb67b61e3 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs @@ -97,7 +97,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer if (mr != null && mr.Name == name) { // explicit call to the requested method if (instr.OpCode.Code == Code.Call - && Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) + && Helpers.IsSameType(analyzedMethod.DeclaringType, mr.DeclaringType) && mr.Resolve() == analyzedMethod) { found = true; prefix = "(as base) "; diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzerEntityTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzerEntityTreeNode.cs index 5f7b3d0b9..9e911c381 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzerEntityTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzerEntityTreeNode.cs @@ -17,8 +17,8 @@ // DEALINGS IN THE SOFTWARE. using System.Collections.Generic; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.TreeView; -using Mono.Cecil; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer /// public abstract class AnalyzerEntityTreeNode : AnalyzerTreeNode, IMemberTreeNode { - public abstract MemberReference Member { get; } + public abstract IMemberReference Member { get; } public override void ActivateItem(System.Windows.RoutedEventArgs e) { @@ -38,7 +38,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public override bool HandleAssemblyListChanged(ICollection removedAssemblies, ICollection addedAssemblies) { foreach (LoadedAssembly asm in removedAssemblies) { - if (this.Member.Module == asm.GetModuleDefinitionOrNull()) + if (this.Member.Module == asm.GetPEFileOrNull()) return false; // remove this node } this.Children.RemoveAll( diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs index cf0a40e5e..053946bf6 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs @@ -16,8 +16,12 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System; using System.Collections.Generic; +using System.Reflection.Metadata; using System.Threading; +using ICSharpCode.Decompiler.Disassembler; +using Dom = ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { diff --git a/ILSpy/TreeNodes/Analyzer/Helpers.cs b/ILSpy/TreeNodes/Analyzer/Helpers.cs index 449d82102..162095a54 100644 --- a/ILSpy/TreeNodes/Analyzer/Helpers.cs +++ b/ILSpy/TreeNodes/Analyzer/Helpers.cs @@ -26,7 +26,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { internal static class Helpers { - public static bool IsReferencedBy(TypeDefinition type, TypeReference typeRef) + public static bool IsSameType(TypeDefinition type, TypeReference typeRef) { // TODO: move it to a better place after adding support for more cases. if (type == null) @@ -44,7 +44,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer if (type.DeclaringType != null || typeRef.DeclaringType != null) { if (type.DeclaringType == null || typeRef.DeclaringType == null) return false; - if (!IsReferencedBy(type.DeclaringType, typeRef.DeclaringType)) + if (!IsSameType(type.DeclaringType, typeRef.DeclaringType)) return false; } @@ -105,7 +105,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer foreach (Instruction instr in method.Body.Instructions) { MethodReference mr = instr.Operand as MethodReference; if (mr != null && mr.Name == name && - IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) && + IsSameType(analyzedMethod.DeclaringType, mr.DeclaringType) && mr.Resolve() == analyzedMethod) { found = true; break; diff --git a/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs b/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs index ad7112334..c85821bae 100644 --- a/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs +++ b/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs @@ -19,9 +19,12 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Threading; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Dom; +using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.Util; -using Mono.Cecil; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -30,8 +33,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer /// internal class ScopedWhereUsedAnalyzer { - private readonly AssemblyDefinition assemblyScope; + private readonly PEFile assemblyScope; private TypeDefinition typeScope; + private static readonly TypeSystemAttributeTypeProvider typeProvider = TypeSystemAttributeTypeProvider.CreateDefault(); private readonly Accessibility memberAccessibility = Accessibility.Public; private Accessibility typeAccessibility = Accessibility.Public; @@ -40,7 +44,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public ScopedWhereUsedAnalyzer(TypeDefinition type, Func> typeAnalysisFunction) { this.typeScope = type; - this.assemblyScope = type.Module.Assembly; + this.assemblyScope = type.Module; this.typeAnalysisFunction = typeAnalysisFunction; } @@ -53,8 +57,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public ScopedWhereUsedAnalyzer(PropertyDefinition property, Func> typeAnalysisFunction) : this(property.DeclaringType, typeAnalysisFunction) { - Accessibility getterAccessibility = (property.GetMethod == null) ? Accessibility.Private : GetMethodAccessibility(property.GetMethod); - Accessibility setterAccessibility = (property.SetMethod == null) ? Accessibility.Private : GetMethodAccessibility(property.SetMethod); + Accessibility getterAccessibility = (property.GetMethod.IsNil) ? Accessibility.Private : GetMethodAccessibility(property.GetMethod); + Accessibility setterAccessibility = (property.SetMethod.IsNil) ? Accessibility.Private : GetMethodAccessibility(property.SetMethod); this.memberAccessibility = (Accessibility)Math.Max((int)getterAccessibility, (int)setterAccessibility); } @@ -142,7 +146,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer private void DetermineTypeAccessibility() { - while (typeScope.IsNested) { + while (!typeScope.DeclaringType.IsNil) { Accessibility accessibility = GetNestedTypeAccessibility(typeScope); if ((int)typeAccessibility > (int)accessibility) { typeAccessibility = accessibility; @@ -215,9 +219,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return assemblies.AsParallel().WithCancellation(ct).SelectMany(asm => FindReferencesInAssembly(asm, ct)); } - private IEnumerable FindReferencesInAssembly(AssemblyDefinition asm, CancellationToken ct) + private IEnumerable FindReferencesInAssembly(PEFile asm, CancellationToken ct) { - foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.MainModule.Types, t => t.NestedTypes)) { + foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.TypeDefinitions, t => t.NestedTypes)) { ct.ThrowIfCancellationRequested(); foreach (var result in typeAnalysisFunction(type)) { ct.ThrowIfCancellationRequested(); @@ -248,67 +252,66 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer } } - private IEnumerable GetReferencingAssemblies(AssemblyDefinition asm, CancellationToken ct) + private IEnumerable GetReferencingAssemblies(PEFile asm, CancellationToken ct) { yield return asm; string requiredAssemblyFullName = asm.FullName; - IEnumerable assemblies = MainWindow.Instance.CurrentAssemblyList.GetAssemblies().Where(assy => assy.GetAssemblyDefinitionOrNull() != null); + IEnumerable assemblies = MainWindow.Instance.CurrentAssemblyList.GetAssemblies().Where(assy => assy.GetPEFileOrNull()?.IsAssembly == true); foreach (var assembly in assemblies) { ct.ThrowIfCancellationRequested(); bool found = false; - var module = assembly.GetModuleDefinitionOrNull(); + var module = assembly.GetPEFileOrNull(); if (module == null) continue; + var metadata = module.GetMetadataReader(); foreach (var reference in module.AssemblyReferences) { if (requiredAssemblyFullName == reference.FullName) { found = true; break; } } - if (found && AssemblyReferencesScopeType(module.Assembly)) - yield return module.Assembly; + if (found && AssemblyReferencesScopeType(module)) + yield return module; } } - private IEnumerable GetAssemblyAndAnyFriends(AssemblyDefinition asm, CancellationToken ct) + private IEnumerable GetAssemblyAndAnyFriends(PEFile asm, CancellationToken ct) { yield return asm; + var reader = asm.GetMetadataReader(); + + var attributes = reader.CustomAttributes.Select(h => reader.GetCustomAttribute(h)).Where(ca => ca.GetAttributeType(asm).FullName.ToString() == "System.Runtime.CompilerServices.InternalsVisibleToAttribute"); + var friendAssemblies = new HashSet(); + foreach (var attribute in attributes) { + string assemblyName = attribute.DecodeValue(typeProvider).FixedArguments[0].Value as string; + assemblyName = assemblyName.Split(',')[0]; // strip off any public key info + friendAssemblies.Add(assemblyName); + } - if (asm.HasCustomAttributes) { - var attributes = asm.CustomAttributes - .Where(attr => attr.AttributeType.FullName == "System.Runtime.CompilerServices.InternalsVisibleToAttribute"); - var friendAssemblies = new HashSet(); - foreach (var attribute in attributes) { - string assemblyName = attribute.ConstructorArguments[0].Value as string; - assemblyName = assemblyName.Split(',')[0]; // strip off any public key info - friendAssemblies.Add(assemblyName); - } + if (friendAssemblies.Count > 0) { + IEnumerable assemblies = MainWindow.Instance.CurrentAssemblyList.GetAssemblies(); - if (friendAssemblies.Count > 0) { - IEnumerable assemblies = MainWindow.Instance.CurrentAssemblyList.GetAssemblies(); - - foreach (var assembly in assemblies) { - ct.ThrowIfCancellationRequested(); - if (friendAssemblies.Contains(assembly.ShortName)) { - var module = assembly.GetModuleDefinitionOrNull(); - if (module == null) - continue; - if (AssemblyReferencesScopeType(module.Assembly)) - yield return module.Assembly; - } + foreach (var assembly in assemblies) { + ct.ThrowIfCancellationRequested(); + if (friendAssemblies.Contains(assembly.ShortName)) { + var module = assembly.GetPEFileOrNull(); + if (module == null) + continue; + if (AssemblyReferencesScopeType(module)) + yield return module; } } } } - private bool AssemblyReferencesScopeType(AssemblyDefinition asm) + private bool AssemblyReferencesScopeType(PEFile asm) { bool hasRef = false; - foreach (var typeref in asm.MainModule.GetTypeReferences()) { - if (typeref.Name == typeScope.Name && typeref.Namespace == typeScope.Namespace) { + foreach (var typeRef in asm.TypeReferences) { + if (typeRef.Name == typeScope.Name && typeRef.Namespace == typeScope.Namespace) { hasRef = true; break; } diff --git a/ILSpy/TreeNodes/AssemblyListTreeNode.cs b/ILSpy/TreeNodes/AssemblyListTreeNode.cs index 602fb4614..54964d397 100644 --- a/ILSpy/TreeNodes/AssemblyListTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyListTreeNode.cs @@ -22,10 +22,11 @@ using System.Collections.ObjectModel; using System.Collections.Specialized; using System.IO; using System.Linq; +using System.Reflection.PortableExecutable; using System.Windows; using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.TreeView; -using Mono.Cecil; namespace ICSharpCode.ILSpy.TreeNodes { @@ -153,7 +154,7 @@ namespace ICSharpCode.ILSpy.TreeNodes } #region Find*Node - + /* public ILSpyTreeNode FindResourceNode(Resource resource) { if (resource == null) @@ -177,27 +178,15 @@ namespace ICSharpCode.ILSpy.TreeNodes } return null; } + */ - - public AssemblyTreeNode FindAssemblyNode(ModuleDefinition module) + public AssemblyTreeNode FindAssemblyNode(PEFile module) { if (module == null) return null; App.Current.Dispatcher.VerifyAccess(); foreach (AssemblyTreeNode node in this.Children) { - if (node.LoadedAssembly.IsLoaded && node.LoadedAssembly.GetModuleDefinitionOrNull() == module) - return node; - } - return null; - } - - public AssemblyTreeNode FindAssemblyNode(AssemblyDefinition asm) - { - if (asm == null) - return null; - App.Current.Dispatcher.VerifyAccess(); - foreach (AssemblyTreeNode node in this.Children) { - if (node.LoadedAssembly.IsLoaded && node.LoadedAssembly.GetAssemblyDefinitionOrNull() == asm) + if (node.LoadedAssembly.IsLoaded && node.LoadedAssembly.GetPEFileOrNull() == module) return node; } return null; @@ -221,16 +210,14 @@ namespace ICSharpCode.ILSpy.TreeNodes /// public TypeTreeNode FindTypeNode(TypeDefinition def) { - if (def == null) - return null; - if (def.DeclaringType != null) { + if (!def.DeclaringType.IsNil) { TypeTreeNode decl = FindTypeNode(def.DeclaringType); if (decl != null) { decl.EnsureLazyChildren(); return decl.Children.OfType().FirstOrDefault(t => t.TypeDefinition == def && !t.IsHidden); } } else { - AssemblyTreeNode asm = FindAssemblyNode(def.Module.Assembly); + AssemblyTreeNode asm = FindAssemblyNode(def.Module); if (asm != null) { return asm.FindTypeNode(def); } @@ -244,8 +231,6 @@ namespace ICSharpCode.ILSpy.TreeNodes /// public ILSpyTreeNode FindMethodNode(MethodDefinition def) { - if (def == null) - return null; TypeTreeNode typeNode = FindTypeNode(def.DeclaringType); if (typeNode == null) return null; @@ -281,8 +266,6 @@ namespace ICSharpCode.ILSpy.TreeNodes /// public FieldTreeNode FindFieldNode(FieldDefinition def) { - if (def == null) - return null; TypeTreeNode typeNode = FindTypeNode(def.DeclaringType); if (typeNode == null) return null; @@ -296,8 +279,6 @@ namespace ICSharpCode.ILSpy.TreeNodes /// public PropertyTreeNode FindPropertyNode(PropertyDefinition def) { - if (def == null) - return null; TypeTreeNode typeNode = FindTypeNode(def.DeclaringType); if (typeNode == null) return null; @@ -311,8 +292,6 @@ namespace ICSharpCode.ILSpy.TreeNodes /// public EventTreeNode FindEventNode(EventDefinition def) { - if (def == null) - return null; TypeTreeNode typeNode = FindTypeNode(def.DeclaringType); if (typeNode == null) return null; diff --git a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs index fa8a9b243..d666e49b9 100644 --- a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs @@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy.TreeNodes /// /// Node within assembly reference list. /// - public sealed class AssemblyReferenceTreeNode : ILSpyTreeNode + /*public sealed class AssemblyReferenceTreeNode : ILSpyTreeNode { readonly AssemblyNameReference r; readonly AssemblyTreeNode parentAssembly; @@ -77,7 +77,7 @@ namespace ICSharpCode.ILSpy.TreeNodes if (assemblyListNode != null) { var refNode = assemblyListNode.FindAssemblyNode(parentAssembly.LoadedAssembly.LookupReferencedAssembly(r)); if (refNode != null) { - ModuleDefinition module = refNode.LoadedAssembly.GetModuleDefinitionOrNull(); + ModuleDefinition module = refNode.LoadedAssembly.GetPEFileOrNull(); if (module != null) { foreach (var childRef in module.AssemblyReferences) this.Children.Add(new AssemblyReferenceTreeNode(childRef, refNode)); @@ -106,5 +106,5 @@ namespace ICSharpCode.ILSpy.TreeNodes output.WriteLine(); } } - } + }*/ } diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs index fe10213c1..ffd8c53fe 100644 --- a/ILSpy/TreeNodes/AssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs @@ -20,15 +20,19 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection.PortableExecutable; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.ILSpy.TextView; using ICSharpCode.TreeView; using Microsoft.Win32; -using Mono.Cecil; + +using SRM = System.Reflection.Metadata; +using static System.Reflection.Metadata.PEReaderExtensions; namespace ICSharpCode.ILSpy.TreeNodes { @@ -97,18 +101,19 @@ namespace ICSharpCode.ILSpy.TreeNodes if (tooltip == null && assembly.IsLoaded) { tooltip = new TextBlock(); - var module = assembly.GetModuleDefinitionOrNull(); - if (module.Assembly != null) { + var module = assembly.GetPEFileOrNull(); + var metadata = module?.GetMetadataReader(); + if (metadata?.IsAssembly == true) { tooltip.Inlines.Add(new Bold(new Run("Name: "))); - tooltip.Inlines.Add(new Run(module.Assembly.FullName)); + tooltip.Inlines.Add(new Run(metadata.GetFullAssemblyName())); tooltip.Inlines.Add(new LineBreak()); } tooltip.Inlines.Add(new Bold(new Run("Location: "))); tooltip.Inlines.Add(new Run(assembly.FileName)); tooltip.Inlines.Add(new LineBreak()); tooltip.Inlines.Add(new Bold(new Run("Architecture: "))); - tooltip.Inlines.Add(new Run(CSharpLanguage.GetPlatformDisplayName(module))); - string runtimeName = CSharpLanguage.GetRuntimeDisplayName(module); + tooltip.Inlines.Add(new Run(Language.GetPlatformDisplayName(module))); + string runtimeName = Language.GetRuntimeDisplayName(module); if (runtimeName != null) { tooltip.Inlines.Add(new LineBreak()); tooltip.Inlines.Add(new Bold(new Run("Runtime: "))); @@ -125,7 +130,7 @@ namespace ICSharpCode.ILSpy.TreeNodes get { return !assembly.HasLoadError; } } - void OnAssemblyLoaded(Task moduleTask) + void OnAssemblyLoaded(Task moduleTask) { // change from "Loading" icon to final icon RaisePropertyChanged("Icon"); @@ -145,19 +150,20 @@ namespace ICSharpCode.ILSpy.TreeNodes protected override void LoadChildren() { - ModuleDefinition moduleDefinition = assembly.GetModuleDefinitionOrNull(); - if (moduleDefinition == null) { + var module = assembly.GetPEFileOrNull(); + if (module == null) { // if we crashed on loading, then we don't have any children return; } + var metadata = module.GetMetadataReader(); - this.Children.Add(new ReferenceFolderTreeNode(moduleDefinition, this)); - if (moduleDefinition.HasResources) - this.Children.Add(new ResourceListTreeNode(moduleDefinition)); + this.Children.Add(new ReferenceFolderTreeNode(metadata, this)); + if (module.Resources.Any()) + this.Children.Add(new ResourceListTreeNode(module)); foreach (NamespaceTreeNode ns in namespaces.Values) { ns.Children.Clear(); } - foreach (TypeDefinition type in moduleDefinition.Types.OrderBy(t => t.FullName, NaturalStringComparer.Instance)) { + foreach (TypeDefinition type in metadata.GetTopLevelTypeDefinitions().Select(td => new TypeDefinition(module, td)).OrderBy(t => t.FullName.ToString(), NaturalStringComparer.Instance)) { NamespaceTreeNode ns; if (!namespaces.TryGetValue(type.Namespace, out ns)) { ns = new NamespaceTreeNode(type.Namespace); @@ -172,10 +178,8 @@ namespace ICSharpCode.ILSpy.TreeNodes this.Children.Add(ns); } } - - public override bool CanExpandRecursively { - get { return true; } - } + + public override bool CanExpandRecursively => true; /// /// Finds the node for a top-level type. @@ -396,10 +400,11 @@ namespace ICSharpCode.ILSpy.TreeNodes return; foreach (var node in context.SelectedTreeNodes) { var la = ((AssemblyTreeNode)node).LoadedAssembly; - var module = la.GetModuleDefinitionOrNull(); + var module = la.GetPEFileOrNull(); if (module != null) { - foreach (var assyRef in module.AssemblyReferences) { - la.LookupReferencedAssembly(assyRef); + var metadata = module.GetMetadataReader(); + foreach (var assyRef in metadata.AssemblyReferences) { + la.LookupReferencedAssembly(new AssemblyReference(module, assyRef)); } } } diff --git a/ILSpy/TreeNodes/BaseTypesEntryNode.cs b/ILSpy/TreeNodes/BaseTypesEntryNode.cs index 988587933..69da339d1 100644 --- a/ILSpy/TreeNodes/BaseTypesEntryNode.cs +++ b/ILSpy/TreeNodes/BaseTypesEntryNode.cs @@ -19,35 +19,33 @@ using System; using System.Linq; using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.TreeView; -using Mono.Cecil; namespace ICSharpCode.ILSpy.TreeNodes { sealed class BaseTypesEntryNode : ILSpyTreeNode, IMemberTreeNode { - private readonly TypeReference tr; + private readonly ITypeReference tr; private TypeDefinition def; private readonly bool isInterface; - public BaseTypesEntryNode(TypeReference tr, bool isInterface) + public BaseTypesEntryNode(ITypeReference tr, bool isInterface) { - if (tr == null) - throw new ArgumentNullException(nameof(tr)); - this.tr = tr; - this.def = tr.Resolve(); + this.tr = tr ?? throw new ArgumentNullException(nameof(tr)); + this.def = tr.GetDefinition(); this.isInterface = isInterface; this.LazyLoading = true; } public override bool ShowExpander { - get { return def != null && (def.BaseType != null || def.HasInterfaces); } + get { return !def.IsNil && (def.BaseType != null || def.HasInterfaces); } } public override object Text { - get { return this.Language.TypeToString(tr, true) + tr.MetadataToken.ToSuffixString(); } + get { return def.FullName + def.Handle.ToSuffixString(); } } public override object Icon @@ -71,7 +69,7 @@ namespace ICSharpCode.ILSpy.TreeNodes { // on item activation, try to resolve once again (maybe the user loaded the assembly in the meantime) if (def == null) { - def = tr.Resolve(); + def = tr.GetDefinition(); if (def != null) this.LazyLoading = true; // re-load children @@ -96,9 +94,6 @@ namespace ICSharpCode.ILSpy.TreeNodes language.WriteCommentLine(output, language.TypeToString(tr, true)); } - MemberReference IMemberTreeNode.Member - { - get { return tr; } - } + IMemberReference IMemberTreeNode.Member => tr; } } diff --git a/ILSpy/TreeNodes/BaseTypesTreeNode.cs b/ILSpy/TreeNodes/BaseTypesTreeNode.cs index 7de1839a3..e6be43cac 100644 --- a/ILSpy/TreeNodes/BaseTypesTreeNode.cs +++ b/ILSpy/TreeNodes/BaseTypesTreeNode.cs @@ -19,8 +19,8 @@ using System; using System.Windows.Threading; using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.TreeView; -using Mono.Cecil; namespace ICSharpCode.ILSpy.TreeNodes { @@ -37,15 +37,9 @@ namespace ICSharpCode.ILSpy.TreeNodes this.LazyLoading = true; } - public override object Text - { - get { return "Base Types"; } - } + public override object Text => "Base Types"; - public override object Icon - { - get { return Images.SuperTypes; } - } + public override object Icon => Images.SuperTypes; protected override void LoadChildren() { @@ -57,7 +51,7 @@ namespace ICSharpCode.ILSpy.TreeNodes if (type.BaseType != null) children.Add(new BaseTypesEntryNode(type.BaseType, false)); foreach (var i in type.Interfaces) { - children.Add(new BaseTypesEntryNode(i.InterfaceType, true)); + children.Add(new BaseTypesEntryNode(i, true)); } } diff --git a/ILSpy/TreeNodes/CopyFullyQualifiedNameContextMenuEntry.cs b/ILSpy/TreeNodes/CopyFullyQualifiedNameContextMenuEntry.cs index 7320b8e5a..94ff1815c 100644 --- a/ILSpy/TreeNodes/CopyFullyQualifiedNameContextMenuEntry.cs +++ b/ILSpy/TreeNodes/CopyFullyQualifiedNameContextMenuEntry.cs @@ -15,9 +15,9 @@ namespace ICSharpCode.ILSpy.TreeNodes public void Execute(TextViewContext context) { - var member = GetMemberNodeFromContext(context)?.Member; + /*var member = GetMemberNodeFromContext(context)?.Member; if (member == null) return; - Clipboard.SetText(GetFullyQualifiedName(member)); + Clipboard.SetText(GetFullyQualifiedName(member));*/ } private IMemberTreeNode GetMemberNodeFromContext(TextViewContext context) diff --git a/ILSpy/TreeNodes/DerivedTypesEntryNode.cs b/ILSpy/TreeNodes/DerivedTypesEntryNode.cs index 72df6c2ff..bdc2a9d22 100644 --- a/ILSpy/TreeNodes/DerivedTypesEntryNode.cs +++ b/ILSpy/TreeNodes/DerivedTypesEntryNode.cs @@ -17,19 +17,21 @@ // DEALINGS IN THE SOFTWARE. using System.Collections.Generic; +using System.Reflection; +using System.Reflection.PortableExecutable; using System.Threading; using ICSharpCode.Decompiler; -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes { class DerivedTypesEntryNode : ILSpyTreeNode, IMemberTreeNode { private readonly TypeDefinition type; - private readonly ModuleDefinition[] assemblies; + private readonly PEFile[] assemblies; private readonly ThreadingSupport threading; - public DerivedTypesEntryNode(TypeDefinition type, ModuleDefinition[] assemblies) + public DerivedTypesEntryNode(TypeDefinition type, PEFile[] assemblies) { this.type = type; this.assemblies = assemblies; @@ -39,12 +41,12 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool ShowExpander { - get { return !type.IsSealed && base.ShowExpander; } + get { return !type.HasFlag(TypeAttributes.Sealed) && base.ShowExpander; } } public override object Text { - get { return this.Language.TypeToString(type, true) + type.MetadataToken.ToSuffixString(); } + get { return type.FullName + type.Handle.ToSuffixString(); } } public override object Icon @@ -57,7 +59,7 @@ namespace ICSharpCode.ILSpy.TreeNodes if (!settings.ShowInternalApi && !IsPublicAPI) return FilterResult.Hidden; if (settings.SearchTermMatches(type.Name)) { - if (type.IsNested && !settings.Language.ShowMember(type)) + if (!type.DeclaringType.IsNil && !settings.Language.ShowMember(type)) return FilterResult.Hidden; else return FilterResult.Match; @@ -100,6 +102,6 @@ namespace ICSharpCode.ILSpy.TreeNodes language.WriteCommentLine(output, language.TypeToString(type, true)); } - MemberReference IMemberTreeNode.Member => type; + IMemberReference IMemberTreeNode.Member => type; } } diff --git a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs index 696afc8c9..09241754c 100644 --- a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs +++ b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs @@ -18,10 +18,13 @@ using System.Collections.Generic; using System.Linq; +using System.Reflection.PortableExecutable; using System.Threading; using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.Decompiler.Util; -using Mono.Cecil; + +using static System.Reflection.Metadata.PEReaderExtensions; namespace ICSharpCode.ILSpy.TreeNodes { @@ -60,18 +63,20 @@ namespace ICSharpCode.ILSpy.TreeNodes IEnumerable FetchChildren(CancellationToken cancellationToken) { // FetchChildren() runs on the main thread; but the enumerator will be consumed on a background thread - var assemblies = list.GetAssemblies().Select(node => node.GetModuleDefinitionOrNull()).Where(asm => asm != null).ToArray(); + var assemblies = list.GetAssemblies().Select(node => node.GetPEFileOrNull()).Where(asm => asm != null).ToArray(); return FindDerivedTypes(type, assemblies, cancellationToken); } - internal static IEnumerable FindDerivedTypes(TypeDefinition type, ModuleDefinition[] assemblies, CancellationToken cancellationToken) + internal static IEnumerable FindDerivedTypes(TypeDefinition type, PEFile[] assemblies, CancellationToken cancellationToken) { - foreach (ModuleDefinition module in assemblies) { - foreach (TypeDefinition td in TreeTraversal.PreOrder(module.Types, t => t.NestedTypes)) { + foreach (var module in assemblies) { + var reader = module.GetMetadataReader(); + foreach (var h in TreeTraversal.PreOrder(reader.GetTopLevelTypeDefinitions(), t => reader.GetTypeDefinition(t).GetNestedTypes())) { cancellationToken.ThrowIfCancellationRequested(); + var td = new TypeDefinition(module, h); if (type.IsInterface && td.HasInterfaces) { foreach (var iface in td.Interfaces) { - if (IsSameType(iface.InterfaceType, type)) + if (IsSameType(iface, type)) yield return new DerivedTypesEntryNode(td, assemblies); } } else if (!type.IsInterface && td.BaseType != null && IsSameType(td.BaseType, type)) { @@ -79,22 +84,13 @@ namespace ICSharpCode.ILSpy.TreeNodes } } } + yield break; } - - static bool IsSameType(TypeReference typeRef, TypeDefinition type) + + static bool IsSameType(ITypeReference typeRef, TypeDefinition type) { - if (typeRef.FullName == type.FullName) - return true; - if (typeRef.Name != type.Name || type.Namespace != typeRef.Namespace) - return false; - if (typeRef.IsNested || type.IsNested) - if (!typeRef.IsNested || !type.IsNested || !IsSameType(typeRef.DeclaringType, type.DeclaringType)) - return false; - var gTypeRef = typeRef as GenericInstanceType; - if (gTypeRef != null || type.HasGenericParameters) - if (gTypeRef == null || !type.HasGenericParameters || gTypeRef.GenericArguments.Count != type.GenericParameters.Count) - return false; - return true; + // FullName contains only namespace, name and type parameter count, therefore this should suffice. + return typeRef.FullName == type.FullName; } public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) diff --git a/ILSpy/TreeNodes/EventTreeNode.cs b/ILSpy/TreeNodes/EventTreeNode.cs index 0094956bc..f5d5a9864 100644 --- a/ILSpy/TreeNodes/EventTreeNode.cs +++ b/ILSpy/TreeNodes/EventTreeNode.cs @@ -17,9 +17,11 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Linq; +using System.Reflection; using System.Windows.Media; using ICSharpCode.Decompiler; -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes { @@ -28,41 +30,39 @@ namespace ICSharpCode.ILSpy.TreeNodes /// public sealed class EventTreeNode : ILSpyTreeNode, IMemberTreeNode { - public EventTreeNode(EventDefinition ev) { - if (ev == null) + if (ev.IsNil) throw new ArgumentNullException(nameof(ev)); this.EventDefinition = ev; - if (ev.AddMethod != null) + if (!ev.AddMethod.IsNil) this.Children.Add(new MethodTreeNode(ev.AddMethod)); - if (ev.RemoveMethod != null) + if (!ev.RemoveMethod.IsNil) this.Children.Add(new MethodTreeNode(ev.RemoveMethod)); - if (ev.InvokeMethod != null) + if (!ev.InvokeMethod.IsNil) this.Children.Add(new MethodTreeNode(ev.InvokeMethod)); - if (ev.HasOtherMethods) { - foreach (var m in ev.OtherMethods) - this.Children.Add(new MethodTreeNode(m)); - } + foreach (var m in ev.OtherMethods) + this.Children.Add(new MethodTreeNode(m)); } public EventDefinition EventDefinition { get; } - public override object Text => GetText(EventDefinition, this.Language) + EventDefinition.MetadataToken.ToSuffixString(); + public override object Text => GetText(EventDefinition, this.Language) + EventDefinition.Handle.ToSuffixString(); public static object GetText(EventDefinition eventDef, Language language) { - return HighlightSearchMatch(eventDef.Name, " : " + language.TypeToString(eventDef.EventType, false, eventDef)); + var eventType = eventDef.DecodeSignature(language.CreateSignatureTypeProvider(false), new GenericContext(eventDef.DeclaringType)); + return HighlightSearchMatch(eventDef.Name, " : " + eventType); } public override object Icon => GetIcon(EventDefinition); public static ImageSource GetIcon(EventDefinition eventDef) { - MethodDefinition accessor = eventDef.AddMethod ?? eventDef.RemoveMethod; - if (accessor != null) - return Images.GetIcon(MemberIcon.Event, GetOverlayIcon(eventDef.AddMethod.Attributes), eventDef.AddMethod.IsStatic); + MethodDefinition accessor = eventDef.GetAccessors().FirstOrDefault().Method; + if (!accessor.IsNil) + return Images.GetIcon(MemberIcon.Event, GetOverlayIcon(accessor.Attributes), accessor.HasFlag(MethodAttributes.Static)); else return Images.GetIcon(MemberIcon.Event, AccessOverlayIcon.Public, false); } @@ -82,7 +82,7 @@ namespace ICSharpCode.ILSpy.TreeNodes return AccessOverlayIcon.ProtectedInternal; case MethodAttributes.Private: return AccessOverlayIcon.Private; - case MethodAttributes.CompilerControlled: + case 0: return AccessOverlayIcon.CompilerControlled; default: throw new NotSupportedException(); @@ -104,14 +104,21 @@ namespace ICSharpCode.ILSpy.TreeNodes language.DecompileEvent(EventDefinition, output, options); } - public override bool IsPublicAPI { get { - MethodDefinition accessor = EventDefinition.AddMethod ?? EventDefinition.RemoveMethod; - return accessor != null && (accessor.IsPublic || accessor.IsFamilyOrAssembly || accessor.IsFamily); + MethodDefinition accessor = EventDefinition.GetAccessors().FirstOrDefault().Method; + if (accessor.IsNil) return false; + switch (accessor.Attributes & MethodAttributes.MemberAccessMask) { + case MethodAttributes.Public: + case MethodAttributes.FamORAssem: + case MethodAttributes.Family: + return true; + default: + return false; + } } } - MemberReference IMemberTreeNode.Member => EventDefinition; + IMemberReference IMemberTreeNode.Member => EventDefinition; } } diff --git a/ILSpy/TreeNodes/FieldTreeNode.cs b/ILSpy/TreeNodes/FieldTreeNode.cs index 3e486f880..14c5dfe9d 100644 --- a/ILSpy/TreeNodes/FieldTreeNode.cs +++ b/ILSpy/TreeNodes/FieldTreeNode.cs @@ -17,9 +17,10 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Reflection; using System.Windows.Media; using ICSharpCode.Decompiler; -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes { @@ -37,37 +38,35 @@ namespace ICSharpCode.ILSpy.TreeNodes this.FieldDefinition = field; } - public override object Text + public override object Text => GetText(FieldDefinition, Language) + FieldDefinition.Handle.ToSuffixString(); + + public static object GetText(FieldDefinition field, Language language) { - get { - return HighlightSearchMatch( - FieldDefinition.Name, - " : " + this.Language.TypeToString(FieldDefinition.FieldType, false, FieldDefinition) + FieldDefinition.MetadataToken.ToSuffixString() - ); - } + string fieldType = field.DecodeSignature(language.CreateSignatureTypeProvider(false), new GenericContext(field.DeclaringType)); + return HighlightSearchMatch(field.Name, " : " + fieldType); } public override object Icon => GetIcon(FieldDefinition); public static ImageSource GetIcon(FieldDefinition field) { - if (field.DeclaringType.IsEnum && !field.Attributes.HasFlag(FieldAttributes.SpecialName)) + if (field.DeclaringType.IsEnum && !field.HasFlag(FieldAttributes.SpecialName)) return Images.GetIcon(MemberIcon.EnumValue, GetOverlayIcon(field.Attributes), false); - if (field.IsLiteral) + if (field.HasFlag(FieldAttributes.Literal)) return Images.GetIcon(MemberIcon.Literal, GetOverlayIcon(field.Attributes), false); - else if (field.IsInitOnly) { + else if (field.HasFlag(FieldAttributes.InitOnly)) { if (IsDecimalConstant(field)) return Images.GetIcon(MemberIcon.Literal, GetOverlayIcon(field.Attributes), false); else - return Images.GetIcon(MemberIcon.FieldReadOnly, GetOverlayIcon(field.Attributes), field.IsStatic); + return Images.GetIcon(MemberIcon.FieldReadOnly, GetOverlayIcon(field.Attributes), field.HasFlag(FieldAttributes.Static)); } else - return Images.GetIcon(MemberIcon.Field, GetOverlayIcon(field.Attributes), field.IsStatic); + return Images.GetIcon(MemberIcon.Field, GetOverlayIcon(field.Attributes), field.HasFlag(FieldAttributes.Static)); } private static bool IsDecimalConstant(FieldDefinition field) { - var fieldType = field.FieldType; + /*var fieldType = field.FieldType; if (fieldType.Name == "Decimal" && fieldType.Namespace == "System") { if (field.HasCustomAttributes) { var attrs = field.CustomAttributes; @@ -77,7 +76,7 @@ namespace ICSharpCode.ILSpy.TreeNodes return true; } } - } + }*/ return false; } @@ -96,7 +95,7 @@ namespace ICSharpCode.ILSpy.TreeNodes return AccessOverlayIcon.ProtectedInternal; case FieldAttributes.Private: return AccessOverlayIcon.Private; - case FieldAttributes.CompilerControlled: + case 0: return AccessOverlayIcon.CompilerControlled; default: throw new NotSupportedException(); @@ -120,10 +119,17 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool IsPublicAPI { get { - return FieldDefinition.IsPublic || FieldDefinition.IsFamily || FieldDefinition.IsFamilyOrAssembly; + switch (FieldDefinition.Attributes & FieldAttributes.FieldAccessMask) { + case FieldAttributes.Public: + case FieldAttributes.FamORAssem: + case FieldAttributes.Family: + return true; + default: + return false; + } } } - MemberReference IMemberTreeNode.Member => FieldDefinition; + IMemberReference IMemberTreeNode.Member => FieldDefinition; } } diff --git a/ILSpy/TreeNodes/IMemberTreeNode.cs b/ILSpy/TreeNodes/IMemberTreeNode.cs index b16164880..57ee5b8fa 100644 --- a/ILSpy/TreeNodes/IMemberTreeNode.cs +++ b/ILSpy/TreeNodes/IMemberTreeNode.cs @@ -16,7 +16,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes { @@ -27,6 +27,6 @@ namespace ICSharpCode.ILSpy.TreeNodes /// public interface IMemberTreeNode { - MemberReference Member { get; } + IMemberReference Member { get; } } } diff --git a/ILSpy/TreeNodes/MethodTreeNode.cs b/ILSpy/TreeNodes/MethodTreeNode.cs index e0b78440f..b88c55e2c 100644 --- a/ILSpy/TreeNodes/MethodTreeNode.cs +++ b/ILSpy/TreeNodes/MethodTreeNode.cs @@ -17,13 +17,15 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Immutable; using System.Linq; +using System.Reflection; using System.Text; -using System.Windows.Controls; using System.Windows.Media; using ICSharpCode.Decompiler; -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; +using SRM = System.Reflection.Metadata; namespace ICSharpCode.ILSpy.TreeNodes { @@ -36,24 +38,27 @@ namespace ICSharpCode.ILSpy.TreeNodes public MethodTreeNode(MethodDefinition method) { - if (method == null) + if (method.IsNil) throw new ArgumentNullException(nameof(method)); this.MethodDefinition = method; } - public override object Text => GetText(MethodDefinition, Language) + MethodDefinition.MetadataToken.ToSuffixString(); + public override object Text => GetText(MethodDefinition, Language) + MethodDefinition.Handle.ToSuffixString(); public static object GetText(MethodDefinition method, Language language) { - StringBuilder b = new StringBuilder(); + var b = new StringBuilder(); + var signatureProvider = language.CreateSignatureTypeProvider(false); + var signature = method.DecodeSignature(signatureProvider, new GenericContext(method)); + b.Append('('); - for (int i = 0; i < method.Parameters.Count; i++) { + for (int i = 0; i < signature.ParameterTypes.Length; i++) { if (i > 0) b.Append(", "); - b.Append(language.TypeToString(method.Parameters[i].ParameterType, false, method.Parameters[i])); + b.Append(signature.ParameterTypes[i]); } - if (method.CallingConvention == MethodCallingConvention.VarArg) { - if (method.HasParameters) + if (signature.Header.CallingConvention == SRM.SignatureCallingConvention.VarArgs) { + if (signature.ParameterTypes.Length > 0) b.Append(", "); b.Append("..."); } @@ -61,7 +66,7 @@ namespace ICSharpCode.ILSpy.TreeNodes b.Append(')'); } else { b.Append(") : "); - b.Append(language.TypeToString(method.ReturnType, false, method.MethodReturnType)); + b.Append(signature.ReturnType); } return HighlightSearchMatch(language.FormatMethodName(method), b.ToString()); } @@ -70,32 +75,28 @@ namespace ICSharpCode.ILSpy.TreeNodes public static ImageSource GetIcon(MethodDefinition method) { - if (method.IsSpecialName && method.Name.StartsWith("op_", StringComparison.Ordinal)) { + if (method.HasFlag(MethodAttributes.SpecialName) && method.Name.StartsWith("op_", StringComparison.Ordinal)) { return Images.GetIcon(MemberIcon.Operator, GetOverlayIcon(method.Attributes), false); } - if (method.IsStatic && method.HasCustomAttributes) { - foreach (var ca in method.CustomAttributes) { - if (ca.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute") { - return Images.GetIcon(MemberIcon.ExtensionMethod, GetOverlayIcon(method.Attributes), false); - } - } + if (method.IsExtensionMethod) { + return Images.GetIcon(MemberIcon.ExtensionMethod, GetOverlayIcon(method.Attributes), false); } - if (method.IsSpecialName && + if (method.HasFlag(MethodAttributes.SpecialName) && (method.Name == ".ctor" || method.Name == ".cctor")) { - return Images.GetIcon(MemberIcon.Constructor, GetOverlayIcon(method.Attributes), method.IsStatic); + return Images.GetIcon(MemberIcon.Constructor, GetOverlayIcon(method.Attributes), method.HasFlag(MethodAttributes.Static)); } if (method.HasPInvokeInfo) return Images.GetIcon(MemberIcon.PInvokeMethod, GetOverlayIcon(method.Attributes), true); - bool showAsVirtual = method.IsVirtual && !(method.IsNewSlot && method.IsFinal) && !method.DeclaringType.IsInterface; + bool showAsVirtual = method.HasFlag(MethodAttributes.Virtual) && !(method.HasFlag(MethodAttributes.NewSlot) && method.HasFlag(MethodAttributes.Final)) && !method.DeclaringType.IsInterface; return Images.GetIcon( showAsVirtual ? MemberIcon.VirtualMethod : MemberIcon.Method, GetOverlayIcon(method.Attributes), - method.IsStatic); + method.HasFlag(MethodAttributes.Static)); } private static AccessOverlayIcon GetOverlayIcon(MethodAttributes methodAttributes) @@ -113,7 +114,7 @@ namespace ICSharpCode.ILSpy.TreeNodes return AccessOverlayIcon.ProtectedInternal; case MethodAttributes.Private: return AccessOverlayIcon.Private; - case MethodAttributes.CompilerControlled: + case 0: return AccessOverlayIcon.CompilerControlled; default: throw new NotSupportedException(); @@ -137,10 +138,17 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool IsPublicAPI { get { - return MethodDefinition.IsPublic || MethodDefinition.IsFamily || MethodDefinition.IsFamilyOrAssembly; + switch (MethodDefinition.Attributes & MethodAttributes.MemberAccessMask) { + case MethodAttributes.Public: + case MethodAttributes.Family: + case MethodAttributes.FamORAssem: + return true; + default: + return false; + } } } - MemberReference IMemberTreeNode.Member => MethodDefinition; + IMemberReference IMemberTreeNode.Member => MethodDefinition; } } diff --git a/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs b/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs index d50057c2c..690272450 100644 --- a/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs +++ b/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs @@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy.TreeNodes /// /// Module reference in ReferenceFolderTreeNode. /// - sealed class ModuleReferenceTreeNode : ILSpyTreeNode + /*sealed class ModuleReferenceTreeNode : ILSpyTreeNode { readonly ModuleReference r; @@ -48,5 +48,5 @@ namespace ICSharpCode.ILSpy.TreeNodes { language.WriteCommentLine(output, r.Name); } - } + }*/ } diff --git a/ILSpy/TreeNodes/PropertyTreeNode.cs b/ILSpy/TreeNodes/PropertyTreeNode.cs index 298731e3a..66100f813 100644 --- a/ILSpy/TreeNodes/PropertyTreeNode.cs +++ b/ILSpy/TreeNodes/PropertyTreeNode.cs @@ -17,9 +17,12 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Reflection; using System.Windows.Media; using ICSharpCode.Decompiler; -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; + +using SRM = System.Reflection.Metadata; namespace ICSharpCode.ILSpy.TreeNodes { @@ -36,39 +39,37 @@ namespace ICSharpCode.ILSpy.TreeNodes throw new ArgumentNullException(nameof(property)); this.PropertyDefinition = property; using (LoadedAssembly.DisableAssemblyLoad()) { - this.isIndexer = property.IsIndexer(); + this.isIndexer = property.IsIndexer; } - if (property.GetMethod != null) + if (!property.GetMethod.IsNil) this.Children.Add(new MethodTreeNode(property.GetMethod)); - if (property.SetMethod != null) + if (!property.SetMethod.IsNil) this.Children.Add(new MethodTreeNode(property.SetMethod)); - if (property.HasOtherMethods) { - foreach (var m in property.OtherMethods) - this.Children.Add(new MethodTreeNode(m)); - } + foreach (var m in property.OtherMethods) + this.Children.Add(new MethodTreeNode(m)); } public PropertyDefinition PropertyDefinition { get; } - public override object Text => GetText(PropertyDefinition, Language, isIndexer) + PropertyDefinition.MetadataToken.ToSuffixString(); + public override object Text => GetText(PropertyDefinition, Language, isIndexer) + PropertyDefinition.Handle.ToSuffixString(); public static object GetText(PropertyDefinition property, Language language, bool? isIndexer = null) { string name = language.FormatPropertyName(property, isIndexer); + var signature = property.DecodeSignature(language.CreateSignatureTypeProvider(false), new GenericContext(property.DeclaringType)); var b = new System.Text.StringBuilder(); if (property.HasParameters) { b.Append('('); - for (int i = 0; i < property.Parameters.Count; i++) + for (int i = 0; i < signature.ParameterTypes.Length; i++) { if (i > 0) b.Append(", "); - b.Append(language.TypeToString(property.Parameters[i].ParameterType, false, property.Parameters[i])); + b.Append(signature.ParameterTypes[i]); } - var method = property.GetMethod ?? property.SetMethod; - if (method.CallingConvention == MethodCallingConvention.VarArg) + if (signature.Header.CallingConvention == SRM.SignatureCallingConvention.VarArgs) { if (property.HasParameters) b.Append(", "); @@ -80,7 +81,7 @@ namespace ICSharpCode.ILSpy.TreeNodes { b.Append(" : "); } - b.Append(language.TypeToString(property.PropertyType, false, property)); + b.Append(signature.ReturnType); return HighlightSearchMatch(name, b.ToString()); } @@ -110,7 +111,7 @@ namespace ICSharpCode.ILSpy.TreeNodes return AccessOverlayIcon.ProtectedInternal; case MethodAttributes.Private: return AccessOverlayIcon.Private; - case MethodAttributes.CompilerControlled: + case 0: return AccessOverlayIcon.CompilerControlled; default: throw new NotSupportedException(); @@ -128,7 +129,7 @@ namespace ICSharpCode.ILSpy.TreeNodes // in numeric order, so we can do an integer comparison of the masked attribute int accessLevel = 0; - if (property.GetMethod != null) { + if (!property.GetMethod.IsNil) { int methodAccessLevel = (int)(property.GetMethod.Attributes & MethodAttributes.MemberAccessMask); if (accessLevel < methodAccessLevel) { accessLevel = methodAccessLevel; @@ -136,7 +137,7 @@ namespace ICSharpCode.ILSpy.TreeNodes } } - if (property.SetMethod != null) { + if (!property.SetMethod.IsNil) { int methodAccessLevel = (int)(property.SetMethod.Attributes & MethodAttributes.MemberAccessMask); if (accessLevel < methodAccessLevel) { accessLevel = methodAccessLevel; @@ -144,13 +145,11 @@ namespace ICSharpCode.ILSpy.TreeNodes } } - if (property.HasOtherMethods) { - foreach (var m in property.OtherMethods) { - int methodAccessLevel = (int)(m.Attributes & MethodAttributes.MemberAccessMask); - if (accessLevel < methodAccessLevel) { - accessLevel = methodAccessLevel; - result = m.Attributes; - } + foreach (var m in property.OtherMethods) { + int methodAccessLevel = (int)(m.Attributes & MethodAttributes.MemberAccessMask); + if (accessLevel < methodAccessLevel) { + accessLevel = methodAccessLevel; + result = m.Attributes; } } @@ -185,6 +184,6 @@ namespace ICSharpCode.ILSpy.TreeNodes } } - MemberReference IMemberTreeNode.Member => PropertyDefinition; + IMemberReference IMemberTreeNode.Member => PropertyDefinition; } } diff --git a/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs b/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs index a788411ab..84b1cb6b4 100644 --- a/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs +++ b/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs @@ -18,9 +18,10 @@ using System; using System.Linq; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; using System.Windows.Threading; using ICSharpCode.Decompiler; -using Mono.Cecil; namespace ICSharpCode.ILSpy.TreeNodes { @@ -29,10 +30,10 @@ namespace ICSharpCode.ILSpy.TreeNodes /// sealed class ReferenceFolderTreeNode : ILSpyTreeNode { - readonly ModuleDefinition module; + readonly MetadataReader module; readonly AssemblyTreeNode parentAssembly; - public ReferenceFolderTreeNode(ModuleDefinition module, AssemblyTreeNode parentAssembly) + public ReferenceFolderTreeNode(MetadataReader module, AssemblyTreeNode parentAssembly) { this.module = module; this.parentAssembly = parentAssembly; @@ -53,10 +54,10 @@ namespace ICSharpCode.ILSpy.TreeNodes protected override void LoadChildren() { - foreach (var r in module.AssemblyReferences.OrderBy(r => r.Name)) - this.Children.Add(new AssemblyReferenceTreeNode(r, parentAssembly)); - foreach (var r in module.ModuleReferences.OrderBy(r => r.Name)) - this.Children.Add(new ModuleReferenceTreeNode(r)); + //foreach (var r in module.AssemblyReferences.OrderBy(r => r.Name)) + // this.Children.Add(new AssemblyReferenceTreeNode(r, parentAssembly)); + //foreach (var r in module.ModuleReferences.OrderBy(r => r.Name)) + // this.Children.Add(new ModuleReferenceTreeNode(r)); } public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) @@ -66,10 +67,10 @@ namespace ICSharpCode.ILSpy.TreeNodes output.WriteLine(); language.WriteCommentLine(output, "Referenced assemblies (in metadata order):"); // Show metadata order of references - foreach (var r in module.AssemblyReferences) + /*foreach (var r in module.AssemblyReferences) new AssemblyReferenceTreeNode(r, parentAssembly).Decompile(language, output, options); foreach (var r in module.ModuleReferences) - language.WriteCommentLine(output, r.Name); + language.WriteCommentLine(output, r.Name);*/ } } } diff --git a/ILSpy/TreeNodes/ResourceListTreeNode.cs b/ILSpy/TreeNodes/ResourceListTreeNode.cs index 74b776d45..4b5cd15bf 100644 --- a/ILSpy/TreeNodes/ResourceListTreeNode.cs +++ b/ILSpy/TreeNodes/ResourceListTreeNode.cs @@ -20,7 +20,7 @@ using System; using System.Linq; using System.Windows.Threading; using ICSharpCode.Decompiler; -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes { @@ -29,9 +29,9 @@ namespace ICSharpCode.ILSpy.TreeNodes /// sealed class ResourceListTreeNode : ILSpyTreeNode { - readonly ModuleDefinition module; + readonly PEFile module; - public ResourceListTreeNode(ModuleDefinition module) + public ResourceListTreeNode(PEFile module) { this.LazyLoading = true; this.module = module; diff --git a/ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs index 5d780ca09..d8ed309ee 100644 --- a/ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs @@ -21,8 +21,8 @@ using System.ComponentModel.Composition; using System.IO; using System.Windows.Controls; using System.Windows.Media.Imaging; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.ILSpy.TextView; -using Mono.Cecil; namespace ICSharpCode.ILSpy.TreeNodes { @@ -33,11 +33,10 @@ namespace ICSharpCode.ILSpy.TreeNodes public ILSpyTreeNode CreateNode(Resource resource) { - EmbeddedResource er = resource as EmbeddedResource; - if (er != null) { - return CreateNode(er.Name, er.GetResourceStream()); - } - return null; + Stream stream = resource.TryOpenStream(); + if (stream == null) + return null; + return CreateNode(resource.Name, stream); } public ILSpyTreeNode CreateNode(string key, object data) diff --git a/ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs b/ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs index 7b3d7cfd7..85f7e7548 100644 --- a/ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs +++ b/ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs @@ -16,7 +16,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes { diff --git a/ILSpy/TreeNodes/ResourceNodes/IconResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/IconResourceEntryNode.cs index 780399d82..0360364f8 100644 --- a/ILSpy/TreeNodes/ResourceNodes/IconResourceEntryNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/IconResourceEntryNode.cs @@ -21,8 +21,8 @@ using System.ComponentModel.Composition; using System.IO; using System.Windows.Controls; using System.Windows.Media.Imaging; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.ILSpy.TextView; -using Mono.Cecil; namespace ICSharpCode.ILSpy.TreeNodes { @@ -31,11 +31,10 @@ namespace ICSharpCode.ILSpy.TreeNodes { public ILSpyTreeNode CreateNode(Resource resource) { - EmbeddedResource er = resource as EmbeddedResource; - if (er != null) { - return CreateNode(er.Name, er.GetResourceStream()); - } - return null; + Stream stream = resource.TryOpenStream(); + if (stream == null) + return null; + return CreateNode(resource.Name, stream); } public ILSpyTreeNode CreateNode(string key, object data) diff --git a/ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs index b945ab137..5cad6e53c 100644 --- a/ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs @@ -20,15 +20,14 @@ using System.ComponentModel.Composition; using System.Drawing; using System.Windows.Forms; using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes { [Export(typeof(IResourceNodeFactory))] sealed class ImageListResourceEntryNodeFactory : IResourceNodeFactory { - #region IResourceNodeFactory Members - - public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) + public ILSpyTreeNode CreateNode(Resource resource) { return null; } @@ -39,8 +38,6 @@ namespace ICSharpCode.ILSpy.TreeNodes return new ImageListResourceEntryNode(key, (ImageListStreamer)data); return null; } - - #endregion } sealed class ImageListResourceEntryNode : ILSpyTreeNode diff --git a/ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs index 07a31f6d2..6866b5f26 100644 --- a/ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs @@ -21,8 +21,8 @@ using System.ComponentModel.Composition; using System.IO; using System.Windows.Controls; using System.Windows.Media.Imaging; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.ILSpy.TextView; -using Mono.Cecil; namespace ICSharpCode.ILSpy.TreeNodes { @@ -33,11 +33,10 @@ namespace ICSharpCode.ILSpy.TreeNodes public ILSpyTreeNode CreateNode(Resource resource) { - EmbeddedResource er = resource as EmbeddedResource; - if (er != null) { - return CreateNode(er.Name, er.GetResourceStream()); - } - return null; + Stream stream = resource.TryOpenStream(); + if (stream == null) + return null; + return CreateNode(resource.Name, stream); } public ILSpyTreeNode CreateNode(string key, object data) diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs index 26bfb0076..021446e59 100644 --- a/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs @@ -18,13 +18,14 @@ using System; using System.IO; +using System.Reflection; using System.Text; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Utils; using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.ILSpy.TextView; using Microsoft.Win32; -using Mono.Cecil; namespace ICSharpCode.ILSpy.TreeNodes { @@ -38,7 +39,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public ResourceTreeNode(Resource r) { - if (r == null) + if (r.IsNil) throw new ArgumentNullException(nameof(r)); this.r = r; } @@ -70,7 +71,7 @@ namespace ICSharpCode.ILSpy.TreeNodes language.WriteCommentLine(output, string.Format("{0} ({1}, {2})", r.Name, r.ResourceType, r.Attributes)); ISmartTextOutput smartOutput = output as ISmartTextOutput; - if (smartOutput != null && r is EmbeddedResource) { + if (smartOutput != null) { smartOutput.AddButton(Images.Save, "Save", delegate { Save(null); }); output.WriteLine(); } @@ -78,24 +79,21 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool View(DecompilerTextView textView) { - EmbeddedResource er = r as EmbeddedResource; - if (er != null) { - Stream s = er.GetResourceStream(); - if (s != null && s.Length < DecompilerTextView.DefaultOutputLengthLimit) { + Stream s = Resource.TryOpenStream(); + if (s != null && s.Length < DecompilerTextView.DefaultOutputLengthLimit) { + s.Position = 0; + FileType type = GuessFileType.DetectFileType(s); + if (type != FileType.Binary) { s.Position = 0; - FileType type = GuessFileType.DetectFileType(s); - if (type != FileType.Binary) { - s.Position = 0; - AvalonEditTextOutput output = new AvalonEditTextOutput(); - output.Write(FileReader.OpenStream(s, Encoding.UTF8).ReadToEnd()); - string ext; - if (type == FileType.Xml) - ext = ".xml"; - else - ext = Path.GetExtension(DecompilerTextView.CleanUpName(er.Name)); - textView.ShowNode(output, this, HighlightingManager.Instance.GetDefinitionByExtension(ext)); - return true; - } + AvalonEditTextOutput output = new AvalonEditTextOutput(); + output.Write(FileReader.OpenStream(s, Encoding.UTF8).ReadToEnd()); + string ext; + if (type == FileType.Xml) + ext = ".xml"; + else + ext = Path.GetExtension(DecompilerTextView.CleanUpName(Resource.Name)); + textView.ShowNode(output, this, HighlightingManager.Instance.GetDefinitionByExtension(ext)); + return true; } } return false; @@ -103,20 +101,18 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool Save(DecompilerTextView textView) { - EmbeddedResource er = r as EmbeddedResource; - if (er != null) { - SaveFileDialog dlg = new SaveFileDialog(); - dlg.FileName = DecompilerTextView.CleanUpName(er.Name); - if (dlg.ShowDialog() == true) { - Stream s = er.GetResourceStream(); - s.Position = 0; - using (var fs = dlg.OpenFile()) { - s.CopyTo(fs); - } + Stream s = Resource.TryOpenStream(); + if (s == null) + return false; + SaveFileDialog dlg = new SaveFileDialog(); + dlg.FileName = DecompilerTextView.CleanUpName(Resource.Name); + if (dlg.ShowDialog() == true) { + s.Position = 0; + using (var fs = dlg.OpenFile()) { + s.CopyTo(fs); } - return true; } - return false; + return true; } public static ILSpyTreeNode Create(Resource resource) diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs index b9512a771..815d7e103 100644 --- a/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs @@ -26,10 +26,10 @@ using System.Linq; using System.Resources; using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.ILSpy.Controls; using ICSharpCode.ILSpy.TextView; using Microsoft.Win32; -using Mono.Cecil; namespace ICSharpCode.ILSpy.TreeNodes { @@ -38,9 +38,8 @@ namespace ICSharpCode.ILSpy.TreeNodes { public ILSpyTreeNode CreateNode(Resource resource) { - EmbeddedResource er = resource as EmbeddedResource; - if (er != null && er.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) { - return new ResourcesFileTreeNode(er); + if (resource.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) { + return new ResourcesFileTreeNode(resource); } return null; } @@ -56,7 +55,7 @@ namespace ICSharpCode.ILSpy.TreeNodes readonly ICollection> stringTableEntries = new ObservableCollection>(); readonly ICollection otherEntries = new ObservableCollection(); - public ResourcesFileTreeNode(EmbeddedResource er) + public ResourcesFileTreeNode(Resource er) : base(er) { this.LazyLoading = true; @@ -69,20 +68,18 @@ namespace ICSharpCode.ILSpy.TreeNodes protected override void LoadChildren() { - EmbeddedResource er = this.Resource as EmbeddedResource; - if (er != null) { - Stream s = er.GetResourceStream(); - s.Position = 0; - ResourceReader reader; - try { - reader = new ResourceReader(s); - } - catch (ArgumentException) { - return; - } - foreach (DictionaryEntry entry in reader.Cast().OrderBy(e => e.Key.ToString())) { - ProcessResourceEntry(entry); - } + Stream s = Resource.TryOpenStream(); + if (s == null) return; + s.Position = 0; + ResourceReader reader; + try { + reader = new ResourceReader(s); + } + catch (ArgumentException) { + return; + } + foreach (DictionaryEntry entry in reader.Cast().OrderBy(e => e.Key.ToString())) { + ProcessResourceEntry(entry); } } @@ -116,33 +113,30 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool Save(DecompilerTextView textView) { - EmbeddedResource er = this.Resource as EmbeddedResource; - if (er != null) { - SaveFileDialog dlg = new SaveFileDialog(); - dlg.FileName = DecompilerTextView.CleanUpName(er.Name); - dlg.Filter = "Resources file (*.resources)|*.resources|Resource XML file|*.resx"; - if (dlg.ShowDialog() == true) { - Stream s = er.GetResourceStream(); - s.Position = 0; - switch (dlg.FilterIndex) { - case 1: - using (var fs = dlg.OpenFile()) { - s.CopyTo(fs); - } - break; - case 2: - var reader = new ResourceReader(s); - using (var writer = new ResXResourceWriter(dlg.OpenFile())) { - foreach (DictionaryEntry entry in reader) { - writer.AddResource(entry.Key.ToString(), entry.Value); - } + Stream s = Resource.TryOpenStream(); + if (s == null) return false; + SaveFileDialog dlg = new SaveFileDialog(); + dlg.FileName = DecompilerTextView.CleanUpName(Resource.Name); + dlg.Filter = "Resources file (*.resources)|*.resources|Resource XML file|*.resx"; + if (dlg.ShowDialog() == true) { + s.Position = 0; + switch (dlg.FilterIndex) { + case 1: + using (var fs = dlg.OpenFile()) { + s.CopyTo(fs); + } + break; + case 2: + var reader = new ResourceReader(s); + using (var writer = new ResXResourceWriter(dlg.OpenFile())) { + foreach (DictionaryEntry entry in reader) { + writer.AddResource(entry.Key.ToString(), entry.Value); } - break; - } + } + break; } - return true; } - return false; + return true; } public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) diff --git a/ILSpy/TreeNodes/ResourceNodes/XamlResourceNode.cs b/ILSpy/TreeNodes/ResourceNodes/XamlResourceNode.cs index dd9bc3003..58d8aa632 100644 --- a/ILSpy/TreeNodes/ResourceNodes/XamlResourceNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/XamlResourceNode.cs @@ -22,6 +22,7 @@ using System.IO; using System.Threading.Tasks; using ICSharpCode.AvalonEdit.Highlighting; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; @@ -30,7 +31,7 @@ namespace ICSharpCode.ILSpy.Xaml [Export(typeof(IResourceNodeFactory))] sealed class XamlResourceNodeFactory : IResourceNodeFactory { - public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) + public ILSpyTreeNode CreateNode(Resource resource) { return null; } diff --git a/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs b/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs index 935fbb4b6..ef8c8503a 100644 --- a/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs @@ -22,9 +22,9 @@ using System.IO; using System.Threading.Tasks; using ICSharpCode.AvalonEdit.Highlighting; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; -using Mono.Cecil; namespace ICSharpCode.ILSpy.Xaml { @@ -35,10 +35,10 @@ namespace ICSharpCode.ILSpy.Xaml public ILSpyTreeNode CreateNode(Resource resource) { - EmbeddedResource er = resource as EmbeddedResource; - if (er != null) - return CreateNode(er.Name, er.GetResourceStream()); - return null; + Stream stream = resource.TryOpenStream(); + if (stream == null) + return null; + return CreateNode(resource.Name, stream); } public ILSpyTreeNode CreateNode(string key, object data) diff --git a/ILSpy/TreeNodes/SearchMsdnContextMenuEntry.cs b/ILSpy/TreeNodes/SearchMsdnContextMenuEntry.cs index 444dd1712..7f10c0dfe 100644 --- a/ILSpy/TreeNodes/SearchMsdnContextMenuEntry.cs +++ b/ILSpy/TreeNodes/SearchMsdnContextMenuEntry.cs @@ -21,7 +21,7 @@ using System.Diagnostics; namespace ICSharpCode.ILSpy.TreeNodes { - [ExportContextMenuEntry(Header = "Search MSDN...", Icon = "images/SearchMsdn.png", Order = 9999)] + /*[ExportContextMenuEntry(Header = "Search MSDN...", Icon = "images/SearchMsdn.png", Order = 9999)] internal sealed class SearchMsdnContextMenuEntry : IContextMenuEntry { private static string msdnAddress = "http://msdn.microsoft.com/en-us/library/{0}"; @@ -108,5 +108,5 @@ namespace ICSharpCode.ILSpy.TreeNodes if (!string.IsNullOrEmpty(address)) MainWindow.OpenLink(address); } - } + }*/ } \ No newline at end of file diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs index b15aec816..e36025b89 100644 --- a/ILSpy/TreeNodes/TypeTreeNode.cs +++ b/ILSpy/TreeNodes/TypeTreeNode.cs @@ -19,32 +19,32 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Windows.Media; using ICSharpCode.Decompiler; -using Mono.Cecil; +using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes { public sealed class TypeTreeNode : ILSpyTreeNode, IMemberTreeNode { - - public TypeTreeNode(TypeDefinition type, AssemblyTreeNode parentAssemblyNode) + readonly TypeDefinition typeDefinition; + + public TypeTreeNode(TypeDefinition typeDefinition, AssemblyTreeNode parentAssemblyNode) { - if (parentAssemblyNode == null) - throw new ArgumentNullException(nameof(parentAssemblyNode)); - if (type == null) - throw new ArgumentNullException(nameof(type)); - this.TypeDefinition = type; - this.ParentAssemblyNode = parentAssemblyNode; + if (typeDefinition.IsNil) + throw new ArgumentNullException(nameof(typeDefinition)); + this.ParentAssemblyNode = parentAssemblyNode ?? throw new ArgumentNullException(nameof(parentAssemblyNode)); + this.typeDefinition = typeDefinition; this.LazyLoading = true; } - public TypeDefinition TypeDefinition { get; } + public TypeDefinition TypeDefinition => typeDefinition; public AssemblyTreeNode ParentAssemblyNode { get; } - public override object Text => HighlightSearchMatch(this.Language.FormatTypeName(TypeDefinition), TypeDefinition.MetadataToken.ToSuffixString()); + public override object Text => HighlightSearchMatch(this.Language.FormatTypeName(TypeDefinition), TypeDefinition.Handle.ToSuffixString()); public override bool IsPublicAPI { get { @@ -76,9 +76,9 @@ namespace ICSharpCode.ILSpy.TreeNodes protected override void LoadChildren() { - if (TypeDefinition.BaseType != null || TypeDefinition.HasInterfaces) + //if (TypeDefinition.BaseType != null || TypeDefinition.HasInterfaces) this.Children.Add(new BaseTypesTreeNode(TypeDefinition)); - if (!TypeDefinition.IsSealed) + if (!TypeDefinition.HasFlag(TypeAttributes.Sealed)) this.Children.Add(new DerivedTypesTreeNode(ParentAssemblyNode.AssemblyList, TypeDefinition)); foreach (TypeDefinition nestedType in TypeDefinition.NestedTypes.OrderBy(m => m.Name, NaturalStringComparer.Instance)) { this.Children.Add(new TypeTreeNode(nestedType, ParentAssemblyNode)); @@ -93,9 +93,8 @@ namespace ICSharpCode.ILSpy.TreeNodes foreach (EventDefinition ev in TypeDefinition.Events.OrderBy(m => m.Name, NaturalStringComparer.Instance)) { this.Children.Add(new EventTreeNode(ev)); } - HashSet accessorMethods = TypeDefinition.GetAccessorMethods(); foreach (MethodDefinition method in TypeDefinition.Methods.OrderBy(m => m.Name, NaturalStringComparer.Instance)) { - if (!accessorMethods.Contains(method)) { + if (method.GetMethodSemanticsAttributes() == 0) { this.Children.Add(new MethodTreeNode(method)); } } @@ -128,7 +127,7 @@ namespace ICSharpCode.ILSpy.TreeNodes } else { if (type.IsInterface) return TypeIcon.Interface; - else if (IsDelegate(type)) + else if (type.IsDelegate) return TypeIcon.Delegate; else if (IsStaticClass(type)) return TypeIcon.StaticClass; @@ -165,16 +164,11 @@ namespace ICSharpCode.ILSpy.TreeNodes return overlay; } - private static bool IsDelegate(TypeDefinition type) - { - return type.BaseType != null && type.BaseType.FullName == typeof(MulticastDelegate).FullName; - } - private static bool IsStaticClass(TypeDefinition type) { - return type.IsSealed && type.IsAbstract; + return type.HasFlag(TypeAttributes.Sealed) && type.HasFlag(TypeAttributes.Abstract); } - MemberReference IMemberTreeNode.Member => TypeDefinition; + IMemberReference IMemberTreeNode.Member => TypeDefinition; } } diff --git a/TestPlugin/ContextMenuCommand.cs b/TestPlugin/ContextMenuCommand.cs index 8305e3535..4e3647903 100644 --- a/TestPlugin/ContextMenuCommand.cs +++ b/TestPlugin/ContextMenuCommand.cs @@ -5,7 +5,6 @@ using System.Linq; using ICSharpCode.ILSpy; using ICSharpCode.ILSpy.TreeNodes; using Microsoft.Win32; -using Mono.Cecil; namespace TestPlugin { @@ -27,14 +26,14 @@ namespace TestPlugin if (context.SelectedTreeNodes == null) return; AssemblyTreeNode node = (AssemblyTreeNode)context.SelectedTreeNodes[0]; - AssemblyDefinition asm = node.LoadedAssembly.GetAssemblyDefinitionOrNull(); + var asm = node.LoadedAssembly.GetAssemblyDefinitionOrNull(); if (asm != null) { - SaveFileDialog dlg = new SaveFileDialog(); + /*SaveFileDialog dlg = new SaveFileDialog(); dlg.FileName = node.LoadedAssembly.FileName; dlg.Filter = "Assembly|*.dll;*.exe"; if (dlg.ShowDialog(MainWindow.Instance) == true) { asm.MainModule.Write(dlg.FileName); - } + }*/ } } } diff --git a/TestPlugin/CustomLanguage.cs b/TestPlugin/CustomLanguage.cs index ea4c03c6b..e47c30449 100644 --- a/TestPlugin/CustomLanguage.cs +++ b/TestPlugin/CustomLanguage.cs @@ -4,8 +4,8 @@ using System.ComponentModel.Composition; using System.Windows.Controls; using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Dom; using ICSharpCode.ILSpy; -using Mono.Cecil; namespace TestPlugin { @@ -32,6 +32,7 @@ namespace TestPlugin public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) { +#if false if (method.Body != null) { output.WriteLine("Size of method: {0} bytes", method.Body.CodeSize); @@ -54,6 +55,7 @@ namespace TestPlugin syntaxTree.AcceptVisitor(visitor); */ } +#endif } } }