Browse Source

Add AnalyzedMethodUsedByTreeNode

pull/1198/head
Siegfried Pammer 8 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 @@
<Compile Include="Metadata\LightJson\Serialization\TextPosition.cs" /> <Compile Include="Metadata\LightJson\Serialization\TextPosition.cs" />
<Compile Include="Metadata\LightJson\Serialization\TextScanner.cs" /> <Compile Include="Metadata\LightJson\Serialization\TextScanner.cs" />
<Compile Include="Metadata\OperandType.cs" /> <Compile Include="Metadata\OperandType.cs" />
<Compile Include="Metadata\SignatureBlobComparer.cs" />
<Compile Include="Metadata\UniversalAssemblyResolver.cs" /> <Compile Include="Metadata\UniversalAssemblyResolver.cs" />
<Compile Include="Metadata\UnresolvedAssemblyNameReference.cs" /> <Compile Include="Metadata\UnresolvedAssemblyNameReference.cs" />
<Compile Include="IL\PointerArithmeticOffset.cs" /> <Compile Include="IL\PointerArithmeticOffset.cs" />

255
ICSharpCode.Decompiler/Metadata/MetadataResolver.cs

@ -256,243 +256,78 @@ namespace ICSharpCode.Decompiler.Metadata
var ms = metadata.GetMethodSpecification(handle); var ms = metadata.GetMethodSpecification(handle);
return ResolveAsMethod(ms.Method, context); 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;
{ }
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;
}
public EntityHandle GetPinnedType(EntityHandle elementType) public EntityHandle GetByReferenceType(EntityHandle elementType)
{ {
return elementType; return elementType;
} }
public EntityHandle GetPointerType(EntityHandle elementType) public EntityHandle GetFunctionPointerType(MethodSignature<EntityHandle> signature)
{ {
return elementType; return MetadataTokens.EntityHandle(0);
} }
public EntityHandle GetPrimitiveType(PrimitiveTypeCode typeCode) public EntityHandle GetGenericInstantiation(EntityHandle genericType, ImmutableArray<EntityHandle> typeArguments)
{ {
return MetadataTokens.EntityHandle(0); return genericType;
} }
public EntityHandle GetSZArrayType(EntityHandle elementType) public EntityHandle GetGenericMethodParameter(Unit genericContext, int index)
{ {
return MetadataTokens.EntityHandle(0); return MetadataTokens.EntityHandle(0);
} }
public EntityHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) public EntityHandle GetGenericTypeParameter(Unit genericContext, int index)
{ {
return handle; return MetadataTokens.EntityHandle(0);
} }
public EntityHandle GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) public EntityHandle GetModifiedType(EntityHandle modifier, EntityHandle unmodifiedType, bool isRequired)
{ {
return handle; return unmodifiedType;
} }
public EntityHandle GetTypeFromSpecification(MetadataReader reader, Unit genericContext, TypeSpecificationHandle handle, byte rawTypeKind) public EntityHandle GetPinnedType(EntityHandle elementType)
{ {
return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext); return elementType;
}
} }
}
public static class SignatureBlobComparer public EntityHandle GetPointerType(EntityHandle elementType)
{
public static bool EqualsMethodSignature(BlobReader a, BlobReader b, MetadataReader contextForA, MetadataReader contextForB)
{ {
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; return MetadataTokens.EntityHandle(0);
// 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;
} }
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) { return handle;
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) public EntityHandle GetTypeFromSpecification(MetadataReader reader, Unit genericContext, TypeSpecificationHandle handle, byte rawTypeKind)
{ {
var typeA = a.ReadTypeHandle(); return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext);
var typeB = b.ReadTypeHandle();
if (typeA.IsNil || typeB.IsNil)
return false;
return typeA.GetFullTypeName(contextForA) == typeB.GetFullTypeName(contextForB);
} }
} }
} }

181
ICSharpCode.Decompiler/Metadata/SignatureBlobComparer.cs

@ -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 @@
<Compile Include="TreeNodes\Analyzer\AnalyzedFieldAccessTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedFieldAccessTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedFieldTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedFieldTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedMethodTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedMethodTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedMethodUsedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedMethodUsesTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedMethodUsesTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyAccessorTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedPropertyAccessorTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedPropertyTreeNode.cs" />

7
ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs

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

6
ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs

@ -50,10 +50,10 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
/*if (analyzedMethod.HasFlag(MethodAttributes.Virtual) && !(analyzedMethod.HasFlag(MethodAttributes.NewSlot) && analyzedMethod.HasFlag(MethodAttributes.Final))) /*if (analyzedMethod.HasFlag(MethodAttributes.Virtual) && !(analyzedMethod.HasFlag(MethodAttributes.NewSlot) && analyzedMethod.HasFlag(MethodAttributes.Final)))
this.Children.Add(new AnalyzedVirtualMethodUsedByTreeNode(analyzedMethod)); this.Children.Add(new AnalyzedVirtualMethodUsedByTreeNode(analyzedMethod));
else else*/
this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedMethod)); this.Children.Add(new AnalyzedMethodUsedByTreeNode(module, analyzedMethod));
if (AnalyzedMethodOverridesTreeNode.CanShow(analyzedMethod)) /*if (AnalyzedMethodOverridesTreeNode.CanShow(analyzedMethod))
this.Children.Add(new AnalyzedMethodOverridesTreeNode(analyzedMethod)); this.Children.Add(new AnalyzedMethodOverridesTreeNode(analyzedMethod));
if (AnalyzedInterfaceMethodImplementedByTreeNode.CanShow(analyzedMethod)) if (AnalyzedInterfaceMethodImplementedByTreeNode.CanShow(analyzedMethod))

100
ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs

@ -20,65 +20,59 @@ using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Threading; using System.Threading;
using Mono.Cecil; using ICSharpCode.Decompiler;
using Mono.Cecil.Cil; using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
/// <summary>
/// Finds members where this method is referenced.
/// </summary>
internal sealed class AnalyzedMethodUsedByTreeNode : AnalyzerSearchTreeNode internal sealed class AnalyzedMethodUsedByTreeNode : AnalyzerSearchTreeNode
{ {
private readonly MethodDefinition analyzedMethod; readonly Decompiler.Metadata.PEFile module;
private ConcurrentDictionary<MethodDefinition, int> foundMethods; 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)); throw new ArgumentNullException(nameof(analyzedMethod));
this.analyzedMethod = analyzedMethod; this.analyzedMethod = analyzedMethod;
} }
public override object Text public override object Text => "Used By";
{
get { return "Used By"; }
}
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct)
{ {
foundMethods = new ConcurrentDictionary<MethodDefinition, int>(); var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(this.Language, module, analyzedMethod, provideTypeSystem: false, FindReferencesInType);
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedMethod, FindReferencesInType);
foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) {
yield return child; 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; var methodDef = this.module.Metadata.GetMethodDefinition(analyzedMethod);
foreach (MethodDefinition method in type.Methods) { var name = this.module.Metadata.GetString(methodDef.Name);
bool found = false;
if (!method.HasBody) var td = module.Metadata.GetTypeDefinition(type);
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;
}
}
method.Body = null; HashSet<MethodDefinitionHandle> alreadyFoundMethods = new HashSet<MethodDefinitionHandle>();
if (found) { foreach (var method in td.GetMethods()) {
MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition; var currentMethod = module.Metadata.GetMethodDefinition(method);
if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) { if (!currentMethod.HasBody())
var node= new AnalyzedMethodTreeNode(codeLocation); 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; node.Language = this.Language;
yield return node; yield return node;
} }
@ -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
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) 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); 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); var td = module.Metadata.GetTypeDefinition(type);
foreach (var h in td.GetMethods()) { foreach (var h in td.GetMethods()) {

4
ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs

@ -50,11 +50,11 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) 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); 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) if (type == this.analyzedType && module == this.module)
yield break; yield break;

55
ILSpy/TreeNodes/Analyzer/Extensions.cs

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

Loading…
Cancel
Save