예제 #1
0
        public static IEnumerable <MethodDef> FindBaseMethods(MethodDef?method, TypeDef?declType, bool compareReturnType = true)
        {
            if (method is null || declType is null)
            {
                yield break;
            }

            foreach (var baseType in BaseTypes(declType))
            {
                var baseTypeDef = baseType.Resolve();
                if (baseTypeDef is null)
                {
                    continue;
                }
                foreach (var baseMethod in baseTypeDef.Methods)
                {
                    if (MatchMethod(baseMethod, Resolve(baseMethod.MethodSig, baseType), method, compareReturnType) && IsVisibleFromDerived(baseMethod, declType))
                    {
                        yield return(baseMethod);

                        if (baseMethod.IsNewSlot == baseMethod.IsVirtual)
                        {
                            yield break;
                        }
                    }
                }
            }
        }
예제 #2
0
        public FormatterMethodInfo(IMethod method, bool retTypeIsLastArgType = false, bool includeReturnTypeInArgsList = false)
        {
            ModuleDef                   = method.Module;
            TypeGenericParams           = null;
            MethodGenericParams         = null;
            MethodSig                   = method.MethodSig ?? new MethodSig(CallingConvention.Default);
            RetTypeIsLastArgType        = retTypeIsLastArgType;
            IncludeReturnTypeInArgsList = includeReturnTypeInArgsList;

            MethodDef = method as MethodDef;
            var ms = method as MethodSpec;
            var mr = method as MemberRef;

            if (!(ms is null))
            {
                var ts = ms.Method is null ? null : ms.Method.DeclaringType as TypeSpec;
                if (!(ts is null))
                {
                    if (ts.TypeSig.RemovePinnedAndModifiers() is GenericInstSig gp)
                    {
                        TypeGenericParams = gp.GenericArguments;
                    }
                }

                var gsSig = ms.GenericInstMethodSig;
                if (!(gsSig is null))
                {
                    MethodGenericParams = gsSig.GenericArguments;
                }

                MethodDef = ms.Method.ResolveMethodDef();
            }
예제 #3
0
        /// <summary>
        /// Determines whether one method overrides or hides another method.
        /// </summary>
        /// <param name="parentMethod">The method declared in a base type.</param>
        /// <param name="childMethod">The method declared in a derived type.</param>
        /// <returns>true if <paramref name="childMethod"/> hides or overrides <paramref name="parentMethod"/>,
        /// otherwise false.</returns>
        public static bool IsBaseMethod(MethodDef?parentMethod, MethodDef?childMethod)
        {
            if (parentMethod is null)
            {
                return(false);
            }
            if (childMethod is null)
            {
                return(false);
            }

            if (parentMethod.Name != childMethod.Name)
            {
                return(false);
            }

            var parentParams = parentMethod.MethodSig.GetParamCount();
            var childParams  = childMethod.MethodSig.GetParamCount();

            if (parentParams > 0 || childParams > 0)
            {
                if (parentParams == 0 || childParams == 0 || parentParams != childParams)
                {
                    return(false);
                }
            }

            return(FindBaseMethods(childMethod).Any(m => CheckEquals(m, parentMethod)));           // || (parentMethod.HasGenericParameters && m.);
        }
예제 #4
0
        /// <summary>
        /// Finds all methods from base types overridden or hidden by the specified method.
        /// </summary>
        /// <param name="method">The method which overrides or hides methods from base types.</param>
        /// <returns>Methods overriden or hidden by the specified method.</returns>
        public static IEnumerable <MethodDef> FindBaseMethods(MethodDef?method)
        {
            if (method is null)
            {
                yield break;
            }

            foreach (var baseType in BaseTypes(method.DeclaringType))
            {
                var baseTypeDef = baseType.Resolve();
                if (baseTypeDef is null)
                {
                    continue;
                }
                foreach (var baseMethod in baseTypeDef.Methods)
                {
                    if (MatchMethod(baseMethod, Resolve(baseMethod.MethodSig, baseType), method) && IsVisibleFromDerived(baseMethod, method.DeclaringType))
                    {
                        yield return(baseMethod);

                        if (baseMethod.IsNewSlot == baseMethod.IsVirtual)
                        {
                            yield break;
                        }
                    }
                }
            }
        }
 public InterfacePropertyImplementedByNode(PropertyDef analyzedProperty)
 {
     this.analyzedProperty = analyzedProperty ?? throw new ArgumentNullException(nameof(analyzedProperty));
     if (!(this.analyzedProperty.GetMethod is null))
     {
         analyzedMethod = this.analyzedProperty.GetMethod;
         isGetter       = true;
     }
예제 #6
0
 static MethodDef?GetVirtualAccessor(MethodDef?accessor)
 {
     if (accessor is not null && (accessor.IsVirtual || accessor.IsAbstract))
     {
         return(accessor);
     }
     return(null);
 }
예제 #7
0
        public static bool MatchInterfaceMethod(MethodDef?candidate, MethodDef?method, ITypeDefOrRef interfaceContextType)
        {
            var genericInstSig = interfaceContextType.TryGetGenericInstSig();

            if (!(genericInstSig is null))
            {
                return(MatchMethod(candidate, candidate?.MethodSig, method, GenericArgumentResolver.Resolve(method?.MethodSig, genericInstSig.GenericArguments, null)));
            }
 public InterfaceEventImplementedByNode(EventDef analyzedEvent)
 {
     this.analyzedEvent = analyzedEvent ?? throw new ArgumentNullException(nameof(analyzedEvent));
     if (!(this.analyzedEvent.AddMethod is null))
     {
         analyzedMethod = this.analyzedEvent.AddMethod;
         isAdder        = true;
     }
        public override IEnumerable <SnapshotSpan> GetFrameSpans(ITextView textView, NormalizedSnapshotSpanCollection spans)
        {
            if (activeStatements.Count == 0)
            {
                yield break;
            }

            var docViewer = textView.TextBuffer.TryGetDocumentViewer();

            if (docViewer is null)
            {
                yield break;
            }

            var methodDebugService = docViewer.TryGetMethodDebugService();

            if (methodDebugService is null)
            {
                yield break;
            }

            var         snapshot  = spans[0].Snapshot;
            MethodDef?  method    = null;
            List <uint>?ilOffsets = null;

            foreach (var span in spans)
            {
                foreach (var info in methodDebugService.GetStatementsByTextSpan(span.Span))
                {
                    if (info.Method != method)
                    {
                        method = info.Method;
                        var moduleTokenId = new ModuleTokenId(moduleIdProvider.Create(method.Module), method.MDToken);
                        if (!activeStatements.TryGetValue(moduleTokenId, out ilOffsets))
                        {
                            continue;
                        }
                    }
                    else if (ilOffsets is null)
                    {
                        continue;
                    }
                    var textSpan = info.Statement.TextSpan;
                    if (textSpan.End > snapshot.Length)
                    {
                        yield break;                        // Old data, but we'll get called again
                    }
                    var ilSpan = info.Statement.ILSpan;
                    foreach (uint ilOffset in ilOffsets)
                    {
                        if (ilOffset >= ilSpan.Start && ilOffset < ilSpan.End)
                        {
                            yield return(new SnapshotSpan(snapshot, textSpan.Start, textSpan.Length));
                        }
                    }
                }
            }
        }
예제 #10
0
 static MethodDef?GetAccessor(MethodDef?accessor)
 {
     if (accessor is not null &&
         accessor.DeclaringType.BaseType is not null &&
         (accessor.IsVirtual || accessor.IsAbstract) && accessor.IsReuseSlot)
     {
         return(accessor);
     }
     return(null);
 }
예제 #11
0
 public EventDefOptions(EventDef evt)
 {
     Attributes   = evt.Attributes;
     Name         = evt.Name;
     EventType    = evt.EventType;
     AddMethod    = evt.AddMethod;
     InvokeMethod = evt.InvokeMethod;
     RemoveMethod = evt.RemoveMethod;
     OtherMethods.AddRange(evt.OtherMethods);
     CustomAttributes.AddRange(evt.CustomAttributes);
 }
예제 #12
0
        public EventFiredByNode(EventDef analyzedEvent)
        {
            this.analyzedEvent = analyzedEvent ?? throw new ArgumentNullException(nameof(analyzedEvent));

            eventBackingField = GetBackingField(analyzedEvent);
            var eventType = analyzedEvent.EventType.ResolveTypeDef();

            if (!(eventType is null))
            {
                eventFiringMethod = eventType.Methods.First(md => md.Name == "Invoke");
            }
        }
        static bool MatchMethod(MethodDef?mCandidate, MethodBaseSig?mCandidateSig, MethodDef?mMethod, MethodBaseSig?mMethodSig)
        {
            if (mCandidate is null || mCandidateSig is null || mMethod is null)
            {
                return(false);
            }

            if (mCandidate.Name != mMethod.Name)
            {
                return(false);
            }

            return(new SigComparer().Equals(mCandidateSig, mMethodSig));
        }
예제 #14
0
        /// <summary>
        /// Gets the state machine kickoff method. It's the original async/iterator method that the compiler moves to the MoveNext method
        /// </summary>
        /// <param name="method">A possible state machine MoveNext method</param>
        /// <param name="kickoffMethod">Updated with kickoff method on success</param>
        /// <returns></returns>
        public static bool TryGetKickoffMethod(MethodDef method, [NotNullWhenTrue] out MethodDef?kickoffMethod)
        {
            kickoffMethod = null;
            var declType = method.DeclaringType;

            // Assume all state machine types are nested types
            if (!declType.IsNested)
            {
                return(false);
            }

            if (ImplementsInterface(declType, System_Runtime_CompilerServices, IAsyncStateMachine))
            {
                // async method

                if (TryGetKickoffMethodFromAttributes(declType, out kickoffMethod))
                {
                    return(true);
                }

                foreach (var possibleKickoffMethod in declType.DeclaringType.Methods)
                {
                    if (GetAsyncStateMachineTypeFromInstructionsCore(possibleKickoffMethod) == declType)
                    {
                        kickoffMethod = possibleKickoffMethod;
                        return(true);
                    }
                }
            }
            else if (ImplementsInterface(declType, System_Collections, IEnumerator))
            {
                // IEnumerable, IEnumerable<T>, IEnumerator, IEnumerator<T>

                if (TryGetKickoffMethodFromAttributes(declType, out kickoffMethod))
                {
                    return(true);
                }

                foreach (var possibleKickoffMethod in declType.DeclaringType.Methods)
                {
                    if (GetIteratorStateMachineTypeFromInstructionsCore(possibleKickoffMethod) == declType)
                    {
                        kickoffMethod = possibleKickoffMethod;
                        return(true);
                    }
                }
            }

            return(false);
        }
예제 #15
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="decompilerSettingsVersion">Decompiler settings version number. This version number should get incremented when the settings change.</param>
 /// <param name="stateMachineKind">State machine kind</param>
 /// <param name="method">Method</param>
 /// <param name="kickoffMethod">Kickoff method or null</param>
 public MethodDebugInfoBuilder(int decompilerSettingsVersion, StateMachineKind stateMachineKind, MethodDef method, MethodDef?kickoffMethod)
 {
     this.decompilerSettingsVersion = decompilerSettingsVersion;
     this.stateMachineKind          = stateMachineKind;
     this.method        = method ?? throw new ArgumentNullException(nameof(method));
     this.kickoffMethod = kickoffMethod;
     statements         = new List <SourceStatement>();
     Scope      = new MethodDebugScopeBuilder();
     Scope.Span = ILSpan.FromBounds(0, (uint)method.Body.GetCodeSize());
     if (method == kickoffMethod)
     {
         throw new ArgumentException();
     }
 }
예제 #16
0
        static bool TryGetKickoffMethodFromAttributes(TypeDef smType, [NotNullWhenTrue] out MethodDef?kickoffMethod)
        {
            foreach (var possibleKickoffMethod in smType.DeclaringType.Methods)
            {
                if (GetStateMachineTypeFromCustomAttributesCore(possibleKickoffMethod) == smType)
                {
                    kickoffMethod = possibleKickoffMethod;
                    return(true);
                }
            }

            kickoffMethod = null;
            return(false);
        }
예제 #17
0
        void InitializeAnalyzer()
        {
            foundMethods = new ConcurrentDictionary <MethodDef, int>();

            var baseMethods = TypesHierarchyHelpers.FindBaseMethods(analyzedMethod).ToArray();

            if (baseMethods.Length > 0)
            {
                baseMethod = baseMethods[baseMethods.Length - 1];
            }
            else
            {
                baseMethod = analyzedMethod;
            }
        }
예제 #18
0
        static bool MatchMethod(MethodDef?mCandidate, MethodBaseSig?mCandidateSig, MethodDef?mMethod, MethodBaseSig?mMethodSig, bool compareReturnType = true)
        {
            if (mCandidate is null || mCandidateSig is null || mMethod is null)
            {
                return(false);
            }

            if (mCandidate.Name != mMethod.Name)
            {
                return(false);
            }

            var options = compareReturnType ? 0 : SigComparerOptions.DontCompareReturnType;

            return(new SigComparer(options).Equals(mCandidateSig, mMethodSig));
        }
예제 #19
0
 MethodDef?GetMetadataMethod(DisasmInfo method)
 {
     if (!StringComparer.OrdinalIgnoreCase.Equals(lastModule?.Location, method.ModuleFilename))
     {
         lastModule = metadataProvider.GetModule(method.ModuleFilename);
         lastMethod = null;
     }
     if (lastModule?.PdbState is null)
     {
         return(null);
     }
     if (lastMethod?.MDToken.Raw != method.MethodToken)
     {
         lastMethod = lastModule?.ResolveToken(method.MethodToken) as MethodDef;
     }
     return(lastMethod);
 }
예제 #20
0
        public EventFiredByNode(EventDef analyzedEvent)
        {
            if (analyzedEvent is null)
            {
                throw new ArgumentNullException(nameof(analyzedEvent));
            }
            analyzedTypes = new List <TypeDef> {
                analyzedEvent.DeclaringType
            };

            eventBackingField = GetBackingField(analyzedEvent);
            var eventType = analyzedEvent.EventType.ResolveTypeDef();

            if (!(eventType is null))
            {
                eventFiringMethod = eventType.Methods.First(md => md.Name == "Invoke");
            }
        }
 public InterfaceEventImplementedByNode(EventDef analyzedEvent)
 {
     this.analyzedEvent = analyzedEvent ?? throw new ArgumentNullException(nameof(analyzedEvent));
     if (this.analyzedEvent.AddMethod is not null)
     {
         analyzedMethod = this.analyzedEvent.AddMethod;
         accessorKind   = AccessorKind.Adder;
     }
     else if (this.analyzedEvent.RemoveMethod is not null)
     {
         analyzedMethod = this.analyzedEvent.RemoveMethod;
         accessorKind   = AccessorKind.Remover;
     }
     else
     {
         analyzedMethod = this.analyzedEvent.InvokeMethod;
         accessorKind   = AccessorKind.Invoker;
     }
 }
예제 #22
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="compilerName">Compiler name (<see cref="PredefinedCompilerNames"/>) or null</param>
 /// <param name="decompilerSettingsVersion">Decompiler settings version number. This version number should get incremented when the settings change.</param>
 /// <param name="stateMachineKind">State machine kind</param>
 /// <param name="method">Method</param>
 /// <param name="kickoffMethod">Kickoff method or null</param>
 /// <param name="parameters">Parameters or null</param>
 /// <param name="statements">Statements</param>
 /// <param name="scope">Root scope</param>
 /// <param name="methodSpan">Method span or null to calculate it from <paramref name="statements"/></param>
 /// <param name="asyncMethodDebugInfo">Async info or null</param>
 public MethodDebugInfo(string?compilerName, int decompilerSettingsVersion, StateMachineKind stateMachineKind, MethodDef method, MethodDef?kickoffMethod, SourceParameter[]?parameters, SourceStatement[] statements, MethodDebugScope scope, TextSpan?methodSpan, AsyncMethodDebugInfo?asyncMethodDebugInfo)
 {
     if (statements is null)
     {
         throw new ArgumentNullException(nameof(statements));
     }
     CompilerName  = compilerName;
     Method        = method ?? throw new ArgumentNullException(nameof(method));
     KickoffMethod = kickoffMethod;
     Parameters    = parameters ?? Array.Empty <SourceParameter>();
     if (statements.Length > 1)
     {
         Array.Sort(statements, SourceStatement.SpanStartComparer);
     }
     DecompilerSettingsVersion = decompilerSettingsVersion;
     Statements = statements;
     Scope      = scope ?? throw new ArgumentNullException(nameof(scope));
     Span       = methodSpan ?? CalculateMethodSpan(statements) ?? new TextSpan(0, 0);
     AsyncInfo  = asyncMethodDebugInfo;
 }
예제 #23
0
        public static uint[]? GetInstructionOffsets(MethodDef?method, IList <MethodSourceStatement> list)
        {
            if (method is null)
            {
                return(null);
            }
            var body = method.Body;

            if (body is null)
            {
                return(null);
            }

            var foundInstrs = new HashSet <uint>();
            // The instructions' offset field is assumed to be valid
            var instrs = body.Instructions.Select(a => a.Offset).ToArray();

            foreach (var ilSpan in list.Select(a => a.Statement.ILSpan))
            {
                int index = Array.BinarySearch(instrs, ilSpan.Start);
                if (index < 0)
                {
                    continue;
                }
                for (int i = index; i < instrs.Length; i++)
                {
                    uint instrOffset = instrs[i];
                    if (instrOffset >= ilSpan.End)
                    {
                        break;
                    }

                    foundInstrs.Add(instrOffset);
                }
            }

            return(foundInstrs.ToArray());
        }
예제 #24
0
 public void Dispose()
 {
     lastModule = null;
     lastMethod = null;
 }
예제 #25
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="decompilerSettingsVersion">Decompiler settings version number. This version number should get incremented when the settings change.</param>
 /// <param name="stateMachineKind">State machine kind</param>
 /// <param name="method">Method</param>
 /// <param name="kickoffMethod">Kickoff method or null</param>
 /// <param name="locals">Locals</param>
 /// <param name="parameters">Parameters or null</param>
 /// <param name="asyncInfo">Async method info or null</param>
 public MethodDebugInfoBuilder(int decompilerSettingsVersion, StateMachineKind stateMachineKind, MethodDef method, MethodDef?kickoffMethod, SourceLocal[] locals, SourceParameter[]?parameters, AsyncMethodDebugInfo?asyncInfo)
     : this(decompilerSettingsVersion, stateMachineKind, method, kickoffMethod)
 {
     Scope.Locals.AddRange(locals);
     Parameters = parameters;
     AsyncInfo  = asyncInfo;
 }
예제 #26
0
        public override void Decompile(MethodDef method, IDecompilerOutput output, DecompilationContext ctx)
        {
            WriteCommentBegin(output, true);
            output.Write("Method: ", BoxedTextColor.Comment);
            output.Write(IdentifierEscaper.Escape(method.FullName), method, DecompilerReferenceFlags.Definition, BoxedTextColor.Comment);
            WriteCommentEnd(output, true);
            output.WriteLine();

            if (!method.HasBody)
            {
                return;
            }

            var bodyInfo = StartKeywordBlock(output, ".body", method);

            ILAstBuilder      astBuilder = new ILAstBuilder();
            ILBlock           ilMethod   = new ILBlock(CodeBracesRangeFlags.MethodBraces);
            DecompilerContext context    = new DecompilerContext(settingsVersion, method.Module, MetadataTextColorProvider)
            {
                CurrentType      = method.DeclaringType,
                CurrentMethod    = method,
                CalculateILSpans = ctx.CalculateILSpans,
            };

            ilMethod.Body = astBuilder.Build(method, inlineVariables, context);

            var                  stateMachineKind = StateMachineKind.None;
            MethodDef?           inlinedMethod    = null;
            AsyncMethodDebugInfo?asyncInfo        = null;
            string?              compilerName     = null;

            if (!(abortBeforeStep is null))
            {
                var optimizer = new ILAstOptimizer();
                optimizer.Optimize(context, ilMethod, out stateMachineKind, out inlinedMethod, out asyncInfo, abortBeforeStep.Value);
                compilerName = optimizer.CompilerName;
            }

            if (context.CurrentMethodIsYieldReturn)
            {
                output.Write("yield", BoxedTextColor.Keyword);
                output.Write(" ", BoxedTextColor.Text);
                output.WriteLine("return", BoxedTextColor.Keyword);
            }
            if (context.CurrentMethodIsAsync)
            {
                output.Write("async", BoxedTextColor.Keyword);
                output.Write("/", BoxedTextColor.Punctuation);
                output.WriteLine("await", BoxedTextColor.Keyword);
            }

            var allVariables = ilMethod.GetSelfAndChildrenRecursive <ILExpression>().Select(e => e.Operand as ILVariable)
                               .Where(v => !(v is null) && !v.IsParameter).Distinct();

            foreach (ILVariable v in allVariables)
            {
                output.Write(IdentifierEscaper.Escape(v.Name), v.GetTextReferenceObject(), DecompilerReferenceFlags.Local | DecompilerReferenceFlags.Definition, v.IsParameter ? BoxedTextColor.Parameter : BoxedTextColor.Local);
                if (!(v.Type is null))
                {
                    output.Write(" ", BoxedTextColor.Text);
                    output.Write(":", BoxedTextColor.Punctuation);
                    output.Write(" ", BoxedTextColor.Text);
                    if (v.IsPinned)
                    {
                        output.Write("pinned", BoxedTextColor.Keyword);
                        output.Write(" ", BoxedTextColor.Text);
                    }
                    v.Type.WriteTo(output, ILNameSyntax.ShortTypeName);
                }
                if (v.GeneratedByDecompiler)
                {
                    output.Write(" ", BoxedTextColor.Text);
                    var start = output.NextPosition;
                    output.Write("[", BoxedTextColor.Punctuation);
                    output.Write("generated", BoxedTextColor.Keyword);
                    var end = output.NextPosition;
                    output.Write("]", BoxedTextColor.Punctuation);
                    output.AddBracePair(new TextSpan(start, 1), new TextSpan(end, 1), CodeBracesRangeFlags.SquareBrackets);
                }
                output.WriteLine();
            }

            var localVariables = new HashSet <ILVariable>(GetVariables(ilMethod));
            var builder        = new MethodDebugInfoBuilder(settingsVersion, stateMachineKind, inlinedMethod ?? method, !(inlinedMethod is null) ? method : null, CreateSourceLocals(localVariables), CreateSourceParameters(localVariables), asyncInfo);

            builder.CompilerName = compilerName;
            foreach (ILNode node in ilMethod.Body)
            {
                node.WriteTo(output, builder);
                if (!node.WritesNewLine)
                {
                    output.WriteLine();
                }
            }
            output.AddDebugInfo(builder.Create());
            EndKeywordBlock(output, bodyInfo, CodeBracesRangeFlags.MethodBraces, addLineSeparator: true);
        }
예제 #27
0
 public TypeDefOrRefAndCAsVM(string editString, string createString, ModuleDef ownerModule, IDecompilerService decompilerService, TypeDef?ownerType, MethodDef?ownerMethod)
     : base(editString, createString, ownerModule, decompilerService, ownerType, ownerMethod)
 {
 }
예제 #28
0
 public MethodOverridesVM(ModuleDef ownerModule, IDecompilerService decompilerService, TypeDef?ownerType, MethodDef?ownerMethod)
     : base(dnSpy_AsmEditor_Resources.EditMethodOverride, dnSpy_AsmEditor_Resources.CreateMethodOverride, ownerModule, decompilerService, ownerType, ownerMethod)
 {
 }
예제 #29
0
 private static bool MatchMethod(MethodDef?mCandidate, MethodBaseSig?mCandidateSig, MethodDef?mMethod, bool compareReturnType = true) =>
 MatchMethod(mCandidate, mCandidateSig, mMethod, mMethod?.MethodSig, compareReturnType);
예제 #30
0
 void ReleaseAnalyzer()
 {
     foundMethods = null;
     baseMethod   = null;
 }