diff --git a/ILSpy/Analyzers/Builtin/MethodUsedByAnalyzer.cs b/ILSpy/Analyzers/Builtin/MethodUsedByAnalyzer.cs index 845c01b9c..98b39a948 100644 --- a/ILSpy/Analyzers/Builtin/MethodUsedByAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/MethodUsedByAnalyzer.cs @@ -17,39 +17,46 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin { public string Text => "Used By"; - public bool Show(IMethod entity) => true; + public bool Show(IMethod entity) => !entity.IsVirtual; public IEnumerable Analyze(IMethod analyzedMethod, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context) { var blob = methodBody.GetILReader(); + var baseMethod = InheritanceHelper.GetBaseMember(analyzedMethod); + while (blob.RemainingBytes > 0) { var opCode = blob.DecodeOpCode(); - switch (opCode.GetOperandType()) { - case OperandType.Field: - case OperandType.Method: - case OperandType.Sig: - case OperandType.Tok: - var member = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32()); - if (member.IsNil) continue; - - switch (member.Kind) { - case HandleKind.MethodDefinition: - case HandleKind.MethodSpecification: - case HandleKind.MemberReference: - var m = context.TypeSystem.ResolveAsMember(member)?.MemberDefinition; - if (m.MetadataToken == analyzedMethod.MetadataToken && m.ParentAssembly.PEFile == analyzedMethod.ParentAssembly.PEFile) { - yield return method; - yield break; - } - break; - } - break; - default: - ILParser.SkipOperand(ref blob, opCode); - break; + if (opCode != ILOpCode.Call && opCode != ILOpCode.Callvirt) { + ILParser.SkipOperand(ref blob, opCode); + continue; + } + var member = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32()); + if (member.IsNil || !member.Kind.IsMemberKind()) continue; + + var m = context.TypeSystem.ResolveAsMember(member)?.MemberDefinition; + if (m == null) continue; + + if (opCode == ILOpCode.Call) { + if (IsSameMember(analyzedMethod, m)) { + yield return method; + yield break; + } + } + + if (opCode == ILOpCode.Callvirt && baseMethod != null) { + if (IsSameMember(baseMethod, m)) { + yield return method; + yield break; + } } } } + + static bool IsSameMember(IMember analyzedMethod, IMember m) + { + return m.MetadataToken == analyzedMethod.MetadataToken + && m.ParentAssembly.PEFile == analyzedMethod.ParentAssembly.PEFile; + } } } diff --git a/ILSpy/Analyzers/Builtin/MethodVirtualUsedByAnalyzer.cs b/ILSpy/Analyzers/Builtin/MethodVirtualUsedByAnalyzer.cs new file mode 100644 index 000000000..ee3d8f483 --- /dev/null +++ b/ILSpy/Analyzers/Builtin/MethodVirtualUsedByAnalyzer.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Reflection.Metadata; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; + +namespace ICSharpCode.ILSpy.Analyzers.Builtin +{ + /// + /// Shows entities that are used by a method. + /// + [Export(typeof(IAnalyzer))] + class MethodVirtualUsedByAnalyzer : IMethodBodyAnalyzer + { + public string Text => "Used By"; + + public bool Show(IMethod entity) => entity.IsVirtual; + + public IEnumerable Analyze(IMethod analyzedMethod, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context) + { + var blob = methodBody.GetILReader(); + + while (blob.RemainingBytes > 0) { + var opCode = blob.DecodeOpCode(); + switch (opCode.GetOperandType()) { + case OperandType.Field: + case OperandType.Method: + case OperandType.Sig: + case OperandType.Tok: + var member = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32()); + if (member.IsNil) continue; + + switch (member.Kind) { + case HandleKind.MethodDefinition: + case HandleKind.MethodSpecification: + case HandleKind.MemberReference: + var m = context.TypeSystem.ResolveAsMember(member)?.MemberDefinition; + if (m.MetadataToken == analyzedMethod.MetadataToken && m.ParentAssembly.PEFile == analyzedMethod.ParentAssembly.PEFile) { + yield return method; + yield break; + } + break; + } + break; + default: + ILParser.SkipOperand(ref blob, opCode); + break; + } + } + } + } +} diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 1d85e4c1a..f83a9d532 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -66,11 +66,14 @@ + + +