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; } } } } }
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(); }
/// <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.); }
/// <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; }
static MethodDef?GetVirtualAccessor(MethodDef?accessor) { if (accessor is not null && (accessor.IsVirtual || accessor.IsAbstract)) { return(accessor); } return(null); }
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)); } } } } }
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); }
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); }
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)); }
/// <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); }
/// <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(); } }
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); }
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; } }
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)); }
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); }
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; } }
/// <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; }
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()); }
public void Dispose() { lastModule = null; lastMethod = null; }
/// <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; }
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); }
public TypeDefOrRefAndCAsVM(string editString, string createString, ModuleDef ownerModule, IDecompilerService decompilerService, TypeDef?ownerType, MethodDef?ownerMethod) : base(editString, createString, ownerModule, decompilerService, ownerType, ownerMethod) { }
public MethodOverridesVM(ModuleDef ownerModule, IDecompilerService decompilerService, TypeDef?ownerType, MethodDef?ownerMethod) : base(dnSpy_AsmEditor_Resources.EditMethodOverride, dnSpy_AsmEditor_Resources.CreateMethodOverride, ownerModule, decompilerService, ownerType, ownerMethod) { }
private static bool MatchMethod(MethodDef?mCandidate, MethodBaseSig?mCandidateSig, MethodDef?mMethod, bool compareReturnType = true) => MatchMethod(mCandidate, mCandidateSig, mMethod, mMethod?.MethodSig, compareReturnType);
void ReleaseAnalyzer() { foundMethods = null; baseMethod = null; }