Browse Source

Add AnalyzedMethodUsedByTreeNode

pull/1198/head
Siegfried Pammer 7 years ago
parent
commit
c2b1ce4443
  1. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  2. 255
      ICSharpCode.Decompiler/Metadata/MetadataResolver.cs
  3. 181
      ICSharpCode.Decompiler/Metadata/SignatureBlobComparer.cs
  4. 1
      ILSpy/ILSpy.csproj
  5. 7
      ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs
  6. 6
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs
  7. 100
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs
  8. 4
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs
  9. 4
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs
  10. 55
      ILSpy/TreeNodes/Analyzer/Extensions.cs
  11. 31
      ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -294,6 +294,7 @@ @@ -294,6 +294,7 @@
<Compile Include="Metadata\LightJson\Serialization\TextPosition.cs" />
<Compile Include="Metadata\LightJson\Serialization\TextScanner.cs" />
<Compile Include="Metadata\OperandType.cs" />
<Compile Include="Metadata\SignatureBlobComparer.cs" />
<Compile Include="Metadata\UniversalAssemblyResolver.cs" />
<Compile Include="Metadata\UnresolvedAssemblyNameReference.cs" />
<Compile Include="IL\PointerArithmeticOffset.cs" />

255
ICSharpCode.Decompiler/Metadata/MetadataResolver.cs

@ -256,243 +256,78 @@ namespace ICSharpCode.Decompiler.Metadata @@ -256,243 +256,78 @@ namespace ICSharpCode.Decompiler.Metadata
var ms = metadata.GetMethodSpecification(handle);
return ResolveAsMethod(ms.Method, context);
}
}
class Unspecializer : ISignatureTypeProvider<EntityHandle, Unit>
public class Unspecializer : ISignatureTypeProvider<EntityHandle, Unit>
{
public EntityHandle GetArrayType(EntityHandle elementType, ArrayShape shape)
{
public EntityHandle GetArrayType(EntityHandle elementType, ArrayShape shape)
{
return elementType;
}
public EntityHandle GetByReferenceType(EntityHandle elementType)
{
return elementType;
}
public EntityHandle GetFunctionPointerType(MethodSignature<EntityHandle> signature)
{
return MetadataTokens.EntityHandle(0);
}
public EntityHandle GetGenericInstantiation(EntityHandle genericType, ImmutableArray<EntityHandle> 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;
}
return elementType;
}
public EntityHandle GetPinnedType(EntityHandle elementType)
{
return elementType;
}
public EntityHandle GetByReferenceType(EntityHandle elementType)
{
return elementType;
}
public EntityHandle GetPointerType(EntityHandle elementType)
{
return elementType;
}
public EntityHandle GetFunctionPointerType(MethodSignature<EntityHandle> signature)
{
return MetadataTokens.EntityHandle(0);
}
public EntityHandle GetPrimitiveType(PrimitiveTypeCode typeCode)
{
return MetadataTokens.EntityHandle(0);
}
public EntityHandle GetGenericInstantiation(EntityHandle genericType, ImmutableArray<EntityHandle> typeArguments)
{
return genericType;
}
public EntityHandle GetSZArrayType(EntityHandle elementType)
{
return MetadataTokens.EntityHandle(0);
}
public EntityHandle GetGenericMethodParameter(Unit genericContext, int index)
{
return MetadataTokens.EntityHandle(0);
}
public EntityHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind)
{
return handle;
}
public EntityHandle GetGenericTypeParameter(Unit genericContext, int index)
{
return MetadataTokens.EntityHandle(0);
}
public EntityHandle GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind)
{
return handle;
}
public EntityHandle GetModifiedType(EntityHandle modifier, EntityHandle unmodifiedType, bool isRequired)
{
return unmodifiedType;
}
public EntityHandle GetTypeFromSpecification(MetadataReader reader, Unit genericContext, TypeSpecificationHandle handle, byte rawTypeKind)
{
return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext);
}
public EntityHandle GetPinnedType(EntityHandle elementType)
{
return elementType;
}
}
public static class SignatureBlobComparer
{
public static bool EqualsMethodSignature(BlobReader a, BlobReader b, MetadataReader contextForA, MetadataReader contextForB)
public EntityHandle GetPointerType(EntityHandle elementType)
{
return EqualsMethodSignature(ref a, ref b, contextForA, contextForB);
return elementType;
}
static bool EqualsMethodSignature(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB)
public EntityHandle GetPrimitiveType(PrimitiveTypeCode typeCode)
{
SignatureHeader header;
// compare signature headers
if (a.RemainingBytes == 0 || b.RemainingBytes == 0 || (header = a.ReadSignatureHeader()) != b.ReadSignatureHeader())
return false;
if (header.IsGeneric) {
// read & compare generic parameter count
if (!IsSameCompressedInteger(ref a, ref b, out _))
return false;
}
// read & compare parameter count
if (!IsSameCompressedInteger(ref a, ref b, out int totalParameterCount))
return false;
if (!IsSameCompressedInteger(ref a, ref b, out int typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
int i = 0;
for (; i < totalParameterCount; i++) {
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
//
if (typeCode == 65)
break;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
}
for (; i < totalParameterCount; i++) {
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
}
return true;
return MetadataTokens.EntityHandle(0);
}
static bool IsSameCompressedInteger(ref BlobReader a, ref BlobReader b, out int value)
public EntityHandle GetSZArrayType(EntityHandle elementType)
{
return a.TryReadCompressedInteger(out value) && b.TryReadCompressedInteger(out int otherValue) && value == otherValue;
return MetadataTokens.EntityHandle(0);
}
static bool IsSameCompressedSignedInteger(ref BlobReader a, ref BlobReader b, out int value)
public EntityHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind)
{
return a.TryReadCompressedSignedInteger(out value) && b.TryReadCompressedSignedInteger(out int otherValue) && value == otherValue;
return handle;
}
static bool TypesAreEqual(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB, int typeCode)
public EntityHandle GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind)
{
switch (typeCode) {
case 0x1: // ELEMENT_TYPE_VOID
case 0x2: // ELEMENT_TYPE_BOOLEAN
case 0x3: // ELEMENT_TYPE_CHAR
case 0x4: // ELEMENT_TYPE_I1
case 0x5: // ELEMENT_TYPE_U1
case 0x6: // ELEMENT_TYPE_I2
case 0x7: // ELEMENT_TYPE_U2
case 0x8: // ELEMENT_TYPE_I4
case 0x9: // ELEMENT_TYPE_U4
case 0xA: // ELEMENT_TYPE_I8
case 0xB: // ELEMENT_TYPE_U8
case 0xC: // ELEMENT_TYPE_R4
case 0xD: // ELEMENT_TYPE_R8
case 0xE: // ELEMENT_TYPE_STRING
case 0x16: // ELEMENT_TYPE_TYPEDBYREF
case 0x18: // ELEMENT_TYPE_I
case 0x19: // ELEMENT_TYPE_U
case 0x1C: // ELEMENT_TYPE_OBJECT
return true;
case 0xF: // ELEMENT_TYPE_PTR
case 0x10: // ELEMENT_TYPE_BYREF
case 0x45: // ELEMENT_TYPE_PINNED
case 0x1D: // ELEMENT_TYPE_SZARRAY
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
return true;
case 0x1B: // ELEMENT_TYPE_FNPTR
if (!EqualsMethodSignature(ref a, ref b, contextForA, contextForB))
return false;
return true;
case 0x14: // ELEMENT_TYPE_ARRAY
// element type
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
// rank
if (!IsSameCompressedInteger(ref a, ref b, out _))
return false;
// sizes
if (!IsSameCompressedInteger(ref a, ref b, out int numOfSizes))
return false;
for (int i = 0; i < numOfSizes; i++) {
if (!IsSameCompressedInteger(ref a, ref b, out _))
return false;
}
// lower bounds
if (!IsSameCompressedInteger(ref a, ref b, out int numOfLowerBounds))
return false;
for (int i = 0; i < numOfLowerBounds; i++) {
if (!IsSameCompressedSignedInteger(ref a, ref b, out _))
return false;
}
return true;
case 0x1F: // ELEMENT_TYPE_CMOD_REQD
case 0x20: // ELEMENT_TYPE_CMOD_OPT
// modifier
if (!TypeHandleEquals(ref a, ref b, contextForA, contextForB))
return false;
// unmodified type
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
return true;
case 0x15: // ELEMENT_TYPE_GENERICINST
// generic type
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
if (!IsSameCompressedInteger(ref a, ref b, out int numOfArguments))
return false;
for (int i = 0; i < numOfArguments; i++) {
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
}
return true;
case 0x13: // ELEMENT_TYPE_VAR
case 0x1E: // ELEMENT_TYPE_MVAR
// index
if (!IsSameCompressedInteger(ref a, ref b, out _))
return false;
return true;
case 0x11: // ELEMENT_TYPE_VALUETYPE
case 0x12: // ELEMENT_TYPE_CLASS
if (!TypeHandleEquals(ref a, ref b, contextForA, contextForB))
return false;
return true;
default:
return false;
}
return handle;
}
static bool TypeHandleEquals(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB)
public EntityHandle GetTypeFromSpecification(MetadataReader reader, Unit genericContext, TypeSpecificationHandle handle, byte rawTypeKind)
{
var typeA = a.ReadTypeHandle();
var typeB = b.ReadTypeHandle();
if (typeA.IsNil || typeB.IsNil)
return false;
return typeA.GetFullTypeName(contextForA) == typeB.GetFullTypeName(contextForB);
return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext);
}
}
}

181
ICSharpCode.Decompiler/Metadata/SignatureBlobComparer.cs

@ -0,0 +1,181 @@ @@ -0,0 +1,181 @@
using System.Reflection.Metadata;
namespace ICSharpCode.Decompiler.Metadata
{
public static class SignatureBlobComparer
{
public static bool EqualsMethodSignature(BlobReader a, BlobReader b, MetadataReader contextForA, MetadataReader contextForB)
{
return EqualsMethodSignature(ref a, ref b, contextForA, contextForB);
}
static bool EqualsMethodSignature(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB)
{
SignatureHeader header;
// compare signature headers
if (a.RemainingBytes == 0 || b.RemainingBytes == 0 || (header = a.ReadSignatureHeader()) != b.ReadSignatureHeader())
return false;
if (header.IsGeneric) {
// read & compare generic parameter count
if (!IsSameCompressedInteger(ref a, ref b, out _))
return false;
}
// read & compare parameter count
if (!IsSameCompressedInteger(ref a, ref b, out int totalParameterCount))
return false;
if (!IsSameCompressedInteger(ref a, ref b, out int typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
int i = 0;
for (; i < totalParameterCount; i++) {
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
//
if (typeCode == 65)
break;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
}
for (; i < totalParameterCount; i++) {
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
}
return true;
}
public static bool EqualsTypeSignature(BlobReader a, BlobReader b, MetadataReader contextForA, MetadataReader contextForB)
{
return EqualsTypeSignature(ref a, ref b, contextForA, contextForB);
}
static bool EqualsTypeSignature(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB)
{
if (!IsSameCompressedInteger(ref a, ref b, out int typeCode))
return false;
return TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode);
}
static bool IsSameCompressedInteger(ref BlobReader a, ref BlobReader b, out int value)
{
return a.TryReadCompressedInteger(out value) && b.TryReadCompressedInteger(out int otherValue) && value == otherValue;
}
static bool IsSameCompressedSignedInteger(ref BlobReader a, ref BlobReader b, out int value)
{
return a.TryReadCompressedSignedInteger(out value) && b.TryReadCompressedSignedInteger(out int otherValue) && value == otherValue;
}
static bool TypesAreEqual(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB, int typeCode)
{
switch (typeCode) {
case 0x1: // ELEMENT_TYPE_VOID
case 0x2: // ELEMENT_TYPE_BOOLEAN
case 0x3: // ELEMENT_TYPE_CHAR
case 0x4: // ELEMENT_TYPE_I1
case 0x5: // ELEMENT_TYPE_U1
case 0x6: // ELEMENT_TYPE_I2
case 0x7: // ELEMENT_TYPE_U2
case 0x8: // ELEMENT_TYPE_I4
case 0x9: // ELEMENT_TYPE_U4
case 0xA: // ELEMENT_TYPE_I8
case 0xB: // ELEMENT_TYPE_U8
case 0xC: // ELEMENT_TYPE_R4
case 0xD: // ELEMENT_TYPE_R8
case 0xE: // ELEMENT_TYPE_STRING
case 0x16: // ELEMENT_TYPE_TYPEDBYREF
case 0x18: // ELEMENT_TYPE_I
case 0x19: // ELEMENT_TYPE_U
case 0x1C: // ELEMENT_TYPE_OBJECT
return true;
case 0xF: // ELEMENT_TYPE_PTR
case 0x10: // ELEMENT_TYPE_BYREF
case 0x45: // ELEMENT_TYPE_PINNED
case 0x1D: // ELEMENT_TYPE_SZARRAY
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
return true;
case 0x1B: // ELEMENT_TYPE_FNPTR
if (!EqualsMethodSignature(ref a, ref b, contextForA, contextForB))
return false;
return true;
case 0x14: // ELEMENT_TYPE_ARRAY
// element type
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
// rank
if (!IsSameCompressedInteger(ref a, ref b, out _))
return false;
// sizes
if (!IsSameCompressedInteger(ref a, ref b, out int numOfSizes))
return false;
for (int i = 0; i < numOfSizes; i++) {
if (!IsSameCompressedInteger(ref a, ref b, out _))
return false;
}
// lower bounds
if (!IsSameCompressedInteger(ref a, ref b, out int numOfLowerBounds))
return false;
for (int i = 0; i < numOfLowerBounds; i++) {
if (!IsSameCompressedSignedInteger(ref a, ref b, out _))
return false;
}
return true;
case 0x1F: // ELEMENT_TYPE_CMOD_REQD
case 0x20: // ELEMENT_TYPE_CMOD_OPT
// modifier
if (!TypeHandleEquals(ref a, ref b, contextForA, contextForB))
return false;
// unmodified type
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
return true;
case 0x15: // ELEMENT_TYPE_GENERICINST
// generic type
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
if (!IsSameCompressedInteger(ref a, ref b, out int numOfArguments))
return false;
for (int i = 0; i < numOfArguments; i++) {
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
}
return true;
case 0x13: // ELEMENT_TYPE_VAR
case 0x1E: // ELEMENT_TYPE_MVAR
// index
if (!IsSameCompressedInteger(ref a, ref b, out _))
return false;
return true;
case 0x11: // ELEMENT_TYPE_VALUETYPE
case 0x12: // ELEMENT_TYPE_CLASS
if (!TypeHandleEquals(ref a, ref b, contextForA, contextForB))
return false;
return true;
default:
return false;
}
}
static bool TypeHandleEquals(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB)
{
var typeA = a.ReadTypeHandle();
var typeB = b.ReadTypeHandle();
if (typeA.IsNil || typeB.IsNil)
return false;
return typeA.GetFullTypeName(contextForA) == typeB.GetFullTypeName(contextForB);
}
}
}

1
ILSpy/ILSpy.csproj

@ -192,6 +192,7 @@ @@ -192,6 +192,7 @@
<Compile Include="TreeNodes\Analyzer\AnalyzedFieldAccessTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedFieldTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedMethodTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedMethodUsedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedMethodUsesTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyAccessorTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyTreeNode.cs" />

7
ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs

@ -30,6 +30,9 @@ using ILOpCode = System.Reflection.Metadata.ILOpCode; @@ -30,6 +30,9 @@ using ILOpCode = System.Reflection.Metadata.ILOpCode;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
/// <summary>
/// Finds methods where this field is read or written.
/// </summary>
sealed class AnalyzedFieldAccessTreeNode : AnalyzerSearchTreeNode
{
readonly bool showWrites; // true: show writes; false: show read access
@ -59,7 +62,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -59,7 +62,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
foundMethods = new Lazy<HashSet<Decompiler.Metadata.MethodDefinition>>(LazyThreadSafetyMode.ExecutionAndPublication);
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(module, analyzedField, provideTypeSystem: false, FindReferencesInType);
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(this.Language, module, analyzedField, provideTypeSystem: false, FindReferencesInType);
foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) {
yield return child;
}
@ -67,7 +70,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -67,7 +70,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
foundMethods = null;
}
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, IDecompilerTypeSystem typeSystem)
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, CodeMappingInfo codeMapping, IDecompilerTypeSystem typeSystem)
{
var td = module.Metadata.GetTypeDefinition(type);
foreach (var h in td.GetMethods()) {

6
ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs

@ -50,10 +50,10 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -50,10 +50,10 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
/*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));
else*/
this.Children.Add(new AnalyzedMethodUsedByTreeNode(module, analyzedMethod));
if (AnalyzedMethodOverridesTreeNode.CanShow(analyzedMethod))
/*if (AnalyzedMethodOverridesTreeNode.CanShow(analyzedMethod))
this.Children.Add(new AnalyzedMethodOverridesTreeNode(analyzedMethod));
if (AnalyzedInterfaceMethodImplementedByTreeNode.CanShow(analyzedMethod))

100
ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs

@ -20,65 +20,59 @@ using System; @@ -20,65 +20,59 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Threading;
using Mono.Cecil;
using Mono.Cecil.Cil;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
/// <summary>
/// Finds members where this method is referenced.
/// </summary>
internal sealed class AnalyzedMethodUsedByTreeNode : AnalyzerSearchTreeNode
{
private readonly MethodDefinition analyzedMethod;
private ConcurrentDictionary<MethodDefinition, int> foundMethods;
readonly Decompiler.Metadata.PEFile module;
readonly MethodDefinitionHandle analyzedMethod;
public AnalyzedMethodUsedByTreeNode(MethodDefinition analyzedMethod)
public AnalyzedMethodUsedByTreeNode(Decompiler.Metadata.PEFile module, MethodDefinitionHandle analyzedMethod)
{
if (analyzedMethod == null)
this.module = module ?? throw new ArgumentNullException(nameof(module));
if (analyzedMethod.IsNil)
throw new ArgumentNullException(nameof(analyzedMethod));
this.analyzedMethod = analyzedMethod;
}
public override object Text
{
get { return "Used By"; }
}
public override object Text => "Used By";
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct)
{
foundMethods = new ConcurrentDictionary<MethodDefinition, int>();
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedMethod, FindReferencesInType);
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(this.Language, module, analyzedMethod, provideTypeSystem: false, FindReferencesInType);
foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) {
yield return child;
}
foundMethods = null;
}
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(TypeDefinition type)
IEnumerable<AnalyzerTreeNode> FindReferencesInType(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, CodeMappingInfo codeMapping, IDecompilerTypeSystem typeSystem)
{
string name = analyzedMethod.Name;
foreach (MethodDefinition method in type.Methods) {
bool found = false;
if (!method.HasBody)
continue;
foreach (Instruction instr in method.Body.Instructions) {
MethodReference mr = instr.Operand as MethodReference;
if (mr != null && mr.Name == name &&
Helpers.IsSameType(analyzedMethod.DeclaringType, mr.DeclaringType) &&
mr.Resolve() == analyzedMethod) {
found = true;
break;
}
}
var methodDef = this.module.Metadata.GetMethodDefinition(analyzedMethod);
var name = this.module.Metadata.GetString(methodDef.Name);
var td = module.Metadata.GetTypeDefinition(type);
method.Body = null;
HashSet<MethodDefinitionHandle> alreadyFoundMethods = new HashSet<MethodDefinitionHandle>();
if (found) {
MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition;
if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) {
var node= new AnalyzedMethodTreeNode(codeLocation);
foreach (var method in td.GetMethods()) {
var currentMethod = module.Metadata.GetMethodDefinition(method);
if (!currentMethod.HasBody())
continue;
if (ScanMethodBody(module, currentMethod.RelativeVirtualAddress)) {
var parentMethod = codeMapping.GetParentMethod(method);
if (!parentMethod.IsNil && alreadyFoundMethods.Add(parentMethod)) {
var node = new AnalyzedMethodTreeNode(module, parentMethod);
node.Language = this.Language;
yield return node;
}
@ -86,9 +80,39 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -86,9 +80,39 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
}
}
private bool HasAlreadyBeenFound(MethodDefinition method)
bool ScanMethodBody(PEFile module, int rva)
{
return !foundMethods.TryAdd(method, 0);
var blob = module.Reader.GetMethodBody(rva).GetILReader();
while (blob.RemainingBytes > 0) {
var opCode = blob.DecodeOpCode();
switch (opCode.GetOperandType()) {
case OperandType.Field:
case OperandType.Method:
case OperandType.Sig:
case OperandType.Tok:
case OperandType.Type:
var member = MetadataTokens.EntityHandle(blob.ReadInt32());
switch (member.Kind) {
case HandleKind.MethodDefinition:
if (this.module != module || analyzedMethod != (MethodDefinitionHandle)member)
break;
return true;
case HandleKind.MemberReference:
var mr = module.Metadata.GetMemberReference((MemberReferenceHandle)member);
if (mr.GetKind() != MemberReferenceKind.Method)
break;
return Helpers.IsSameMethod(analyzedMethod, this.module, member, module);
case HandleKind.MethodSpecification:
return Helpers.IsSameMethod(analyzedMethod, this.module, member, module);
}
break;
default:
blob.SkipOperand(opCode);
break;
}
}
return false;
}
}
}

4
ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs

@ -50,11 +50,11 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -50,11 +50,11 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct)
{
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(module, analyzedType, provideTypeSystem: false, FindReferencesInType);
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(this.Language, module, analyzedType, provideTypeSystem: false, FindReferencesInType);
return analyzer.PerformAnalysis(ct).OrderBy(n => n.Text);
}
IEnumerable<AnalyzerTreeNode> FindReferencesInType(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, IDecompilerTypeSystem typeSystem)
IEnumerable<AnalyzerTreeNode> FindReferencesInType(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, CodeMappingInfo codeMapping, IDecompilerTypeSystem typeSystem)
{
var td = module.Metadata.GetTypeDefinition(type);
foreach (var h in td.GetMethods()) {

4
ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs

@ -50,11 +50,11 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -50,11 +50,11 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct)
{
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerEntityTreeNode>(module, analyzedType, provideTypeSystem: true, FindTypeUsage);
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerEntityTreeNode>(this.Language, module, analyzedType, provideTypeSystem: true, FindTypeUsage);
return analyzer.PerformAnalysis(ct).Distinct(AnalyzerEntityTreeNodeComparer.Instance).OrderBy(n => n.Text);
}
IEnumerable<AnalyzerEntityTreeNode> FindTypeUsage(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, IDecompilerTypeSystem typeSystem)
IEnumerable<AnalyzerEntityTreeNode> FindTypeUsage(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, CodeMappingInfo codeMapping, IDecompilerTypeSystem typeSystem)
{
if (type == this.analyzedType && module == this.module)
yield break;

55
ILSpy/TreeNodes/Analyzer/Extensions.cs

@ -5,10 +5,11 @@ using System.Reflection.Metadata; @@ -5,10 +5,11 @@ using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
public static class Extensions
public static class Helpers
{
public static TypeDefinitionHandle GetDeclaringType(this MethodDefinitionHandle method, MetadataReader metadata)
{
@ -39,5 +40,57 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -39,5 +40,57 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
var accessor = metadata.GetEventDefinition(@event).GetAccessors().GetAny();
return metadata.GetMethodDefinition(accessor).GetDeclaringType();
}
public static bool IsSameMethod(MethodDefinitionHandle method, PEFile definitionModule, EntityHandle entity, PEFile entityModule)
{
if (method.IsNil || entity.IsNil)
return false;
var md = definitionModule.Metadata.GetMethodDefinition(method);
if (entity.Kind == HandleKind.MethodSpecification) {
var ms = entityModule.Metadata.GetMethodSpecification((MethodSpecificationHandle)entity);
entity = ms.Method;
}
switch (entity.Kind) {
case HandleKind.MethodDefinition:
return method == entity && definitionModule == entityModule;
case HandleKind.MemberReference:
var mr = entityModule.Metadata.GetMemberReference((MemberReferenceHandle)entity);
if (mr.GetKind() != MemberReferenceKind.Method)
return false;
if (!entityModule.Metadata.StringComparer.Equals(mr.Name, definitionModule.Metadata.GetString(md.Name)))
return false;
if (mr.Parent.Kind.IsTypeKind()) {
if (!IsSameType(md.GetDeclaringType(), definitionModule, mr.Parent, entityModule))
return false;
} else {
// TODO ...
}
return SignatureBlobComparer.EqualsMethodSignature(
definitionModule.Metadata.GetBlobReader(md.Signature),
entityModule.Metadata.GetBlobReader(mr.Signature),
definitionModule.Metadata, entityModule.Metadata);
default:
return false;
}
}
public static bool IsSameType(TypeDefinitionHandle type, PEFile module, EntityHandle entity, PEFile entityModule)
{
if (type.IsNil || entity.IsNil)
return false;
var td = module.Metadata.GetTypeDefinition(type);
if (entity.Kind == HandleKind.TypeSpecification) {
var ts = entityModule.Metadata.GetTypeSpecification((TypeSpecificationHandle)entity);
entity = ts.DecodeSignature(new Unspecializer(), default);
}
switch (entity.Kind) {
case HandleKind.TypeDefinition:
return type == entity && module == entityModule;
case HandleKind.TypeReference:
return type.GetFullTypeName(module.Metadata) == entity.GetFullTypeName(entityModule.Metadata);
default:
return false;
}
}
}
}

31
ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs

@ -34,6 +34,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -34,6 +34,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
/// </summary>
class ScopedWhereUsedAnalyzer<T>
{
readonly Language language;
readonly Decompiler.Metadata.PEFile assemblyScope;
readonly bool provideTypeSystem;
TypeDefinitionHandle typeScopeHandle;
@ -42,10 +43,11 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -42,10 +43,11 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
readonly Accessibility memberAccessibility = Accessibility.Public;
Accessibility typeAccessibility = Accessibility.Public;
readonly Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction;
readonly Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, CodeMappingInfo, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction;
public ScopedWhereUsedAnalyzer(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction)
public ScopedWhereUsedAnalyzer(Language language, Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, CodeMappingInfo, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction)
{
this.language = language;
this.typeScopeHandle = type;
this.assemblyScope = module;
this.typeScope = module.Metadata.GetTypeDefinition(typeScopeHandle);
@ -53,14 +55,14 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -53,14 +55,14 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
this.typeAnalysisFunction = typeAnalysisFunction;
}
public ScopedWhereUsedAnalyzer(Decompiler.Metadata.PEFile module, MethodDefinitionHandle method, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction)
: this(module, method.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction)
public ScopedWhereUsedAnalyzer(Language language, Decompiler.Metadata.PEFile module, MethodDefinitionHandle method, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, CodeMappingInfo, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction)
: this(language, module, method.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction)
{
this.memberAccessibility = GetMethodAccessibility(module.Metadata, method);
}
public ScopedWhereUsedAnalyzer(Decompiler.Metadata.PEFile module, PropertyDefinitionHandle property, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction)
: this(module, property.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction)
public ScopedWhereUsedAnalyzer(Language language, Decompiler.Metadata.PEFile module, PropertyDefinitionHandle property, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, CodeMappingInfo, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction)
: this(language, module, property.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction)
{
var pd = module.Metadata.GetPropertyDefinition(property);
var accessors = pd.GetAccessors();
@ -69,8 +71,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -69,8 +71,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
this.memberAccessibility = (Accessibility)Math.Max((int)getterAccessibility, (int)setterAccessibility);
}
public ScopedWhereUsedAnalyzer(Decompiler.Metadata.PEFile module, EventDefinitionHandle eventDef, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction)
: this(module, eventDef.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction)
public ScopedWhereUsedAnalyzer(Language language, Decompiler.Metadata.PEFile module, EventDefinitionHandle eventDef, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, CodeMappingInfo, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction)
: this(language, module, eventDef.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction)
{
// we only have to check the accessibility of the the get method
// [CLS Rule 30: The accessibility of an event and of its accessors shall be identical.]
@ -78,8 +80,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -78,8 +80,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
this.memberAccessibility = GetMethodAccessibility(module.Metadata, ed.GetAccessors().Adder);
}
public ScopedWhereUsedAnalyzer(Decompiler.Metadata.PEFile module, FieldDefinitionHandle field, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction)
: this(module, field.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction)
public ScopedWhereUsedAnalyzer(Language language, Decompiler.Metadata.PEFile module, FieldDefinitionHandle field, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, CodeMappingInfo, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction)
: this(language, module, field.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction)
{
var fd = module.Metadata.GetFieldDefinition(field);
switch (fd.Attributes & FieldAttributes.FieldAccessMask) {
@ -236,7 +238,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -236,7 +238,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
var metadata = module.Metadata;
foreach (var type in TreeTraversal.PreOrder(metadata.TypeDefinitions, t => metadata.GetTypeDefinition(t).GetNestedTypes())) {
ct.ThrowIfCancellationRequested();
foreach (var result in typeAnalysisFunction(module, type, ts)) {
var codeMappingInfo = language.GetCodeMappingInfo(assemblyScope, type);
foreach (var result in typeAnalysisFunction(module, type, codeMappingInfo, ts)) {
ct.ThrowIfCancellationRequested();
yield return result;
}
@ -248,7 +251,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -248,7 +251,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope) : null;
foreach (var type in TreeTraversal.PreOrder(typeScopeHandle, t => assemblyScope.Metadata.GetTypeDefinition(t).GetNestedTypes())) {
ct.ThrowIfCancellationRequested();
foreach (var result in typeAnalysisFunction(assemblyScope, type, ts)) {
var codeMappingInfo = language.GetCodeMappingInfo(assemblyScope, type);
foreach (var result in typeAnalysisFunction(assemblyScope, type, codeMappingInfo, ts)) {
ct.ThrowIfCancellationRequested();
yield return result;
}
@ -258,9 +262,10 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -258,9 +262,10 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
IEnumerable<T> FindReferencesInEnclosingTypeScope(CancellationToken ct)
{
IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope) : null;
var codeMappingInfo = language.GetCodeMappingInfo(assemblyScope, typeScope.GetDeclaringType());
foreach (var type in TreeTraversal.PreOrder(typeScope.GetDeclaringType(), t => assemblyScope.Metadata.GetTypeDefinition(t).GetNestedTypes())) {
ct.ThrowIfCancellationRequested();
foreach (var result in typeAnalysisFunction(assemblyScope, type, ts)) {
foreach (var result in typeAnalysisFunction(assemblyScope, type, codeMappingInfo, ts)) {
ct.ThrowIfCancellationRequested();
yield return result;
}

Loading…
Cancel
Save