Browse Source

WIP

pull/1198/head
Siegfried Pammer 7 years ago
parent
commit
47788a38de
  1. 14
      ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs
  2. 106
      ICSharpCode.Decompiler/Metadata/MetadataResolver.cs
  3. 2
      ICSharpCode.Decompiler/Metadata/OperandType.cs
  4. 10
      ICSharpCode.Decompiler/Output/TextTokenWriter.cs
  5. 23
      ICSharpCode.Decompiler/SRMExtensions.cs
  6. 15
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  7. 1
      ICSharpCode.Decompiler/TypeSystem/IDecompilerTypeSystem.cs
  8. 1
      ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedMethod.cs
  9. 6
      ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs
  10. 17
      ILSpy/ILSpy.csproj
  11. 76
      ILSpy/Languages/CSharpLanguage.cs
  12. 63
      ILSpy/Languages/CodeMappingInfo.cs
  13. 172
      ILSpy/Languages/ILSignatureProvider.cs
  14. 175
      ILSpy/Languages/Language.cs
  15. 13
      ILSpy/MainWindow.xaml.cs
  16. 107
      ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs
  17. 4
      ILSpy/TreeNodes/Analyzer/AnalyzedAssemblyTreeNode.cs
  18. 28
      ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs
  19. 93
      ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs
  20. 31
      ILSpy/TreeNodes/Analyzer/AnalyzedFieldTreeNode.cs
  21. 5
      ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs
  22. 34
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs
  23. 122
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs
  24. 6
      ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs
  25. 57
      ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs
  26. 15
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs
  27. 122
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs
  28. 45
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs
  29. 249
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs
  30. 1
      ILSpy/TreeNodes/Analyzer/AnalyzerEntityTreeNode.cs
  31. 3
      ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs
  32. 43
      ILSpy/TreeNodes/Analyzer/Extensions.cs
  33. 128
      ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs
  34. 49
      ILSpy/TreeNodes/CopyFullyQualifiedNameContextMenuEntry.cs
  35. 5
      ILSpy/TreeNodes/TypeTreeNode.cs

14
ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs

@ -174,7 +174,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -174,7 +174,7 @@ namespace ICSharpCode.Decompiler.CSharp
if (handle.Kind.IsTypeKind())
CollectNamespacesForTypeReference(typeSystem.ResolveAsType(handle), namespaces);
else
CollectNamespacesForMemberReference(typeSystem.ResolveAsMember(handle), namespaces);
CollectNamespacesForMemberReference(typeSystem.ResolveAsMember(handle), typeSystem, namespaces);
break;
default:
instructions.SkipOperand(opCode);
@ -183,15 +183,21 @@ namespace ICSharpCode.Decompiler.CSharp @@ -183,15 +183,21 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
static void CollectNamespacesForMemberReference(IMember member, HashSet<string> namespaces)
static void CollectNamespacesForMemberReference(IMember member, DecompilerTypeSystem typeSystem, HashSet<string> namespaces)
{
switch (member) {
case IField field:
CollectNamespacesForTypeReference(field.DeclaringType, namespaces);
if (field.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
CollectNamespaces(field, typeSystem, namespaces);
else
CollectNamespacesForTypeReference(field.DeclaringType, namespaces);
CollectNamespacesForTypeReference(field.ReturnType, namespaces);
break;
case IMethod method:
CollectNamespacesForTypeReference(method.DeclaringType, namespaces);
if (method.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
CollectNamespaces(method, typeSystem, namespaces);
else
CollectNamespacesForTypeReference(method.DeclaringType, namespaces);
CollectNamespacesForTypeReference(method.ReturnType, namespaces);
foreach (var param in method.Parameters)
CollectNamespacesForTypeReference(param.Type, namespaces);

106
ICSharpCode.Decompiler/Metadata/MetadataResolver.cs

@ -76,6 +76,11 @@ namespace ICSharpCode.Decompiler.Metadata @@ -76,6 +76,11 @@ namespace ICSharpCode.Decompiler.Metadata
if (resolved is MethodDefinition m)
return m;
return default;
case HandleKind.MethodSpecification:
resolved = ((MethodSpecificationHandle)handle).Resolve(context);
if (resolved is MethodDefinition m2)
return m2;
return default;
}
throw new NotImplementedException();
}
@ -155,7 +160,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -155,7 +160,7 @@ namespace ICSharpCode.Decompiler.Metadata
var currentNamespace = metadata.GetNamespaceDefinitionRoot();
for (int i = 0; i < namespaceParts.Length; i++) {
string identifier = namespaceParts[i];
var next = currentNamespace.NamespaceDefinitions.FirstOrDefault(ns => metadata.GetString(metadata.GetNamespaceDefinition(ns).Name) == identifier);
var next = currentNamespace.NamespaceDefinitions.FirstOrDefault(ns => metadata.StringComparer.Equals(ns, identifier));
if (next.IsNil)
return null;
currentNamespace = metadata.GetNamespaceDefinition(next);
@ -166,8 +171,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -166,8 +171,7 @@ namespace ICSharpCode.Decompiler.Metadata
static TypeDefinitionHandle FindTypeInNamespace(MetadataReader metadata, NamespaceDefinition @namespace, string name)
{
foreach (var type in @namespace.TypeDefinitions) {
var typeName = metadata.GetString(metadata.GetTypeDefinition(type).Name);
if (name == typeName)
if (metadata.StringComparer.Equals(metadata.GetTypeDefinition(type).Name, name))
return type;
}
return default;
@ -223,7 +227,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -223,7 +227,7 @@ namespace ICSharpCode.Decompiler.Metadata
if (candidates.Count == 0)
throw new NotSupportedException();
foreach (var (method, signature) in candidates) {
if (SignatureBlobComparer.EqualsMethodSignature(targetMetadata.GetBlobReader(signature), metadata.GetBlobReader(mr.Signature), new SimpleMetadataResolveContext(targetModule, context), context))
if (SignatureBlobComparer.EqualsMethodSignature(targetMetadata.GetBlobReader(signature), metadata.GetBlobReader(mr.Signature), targetMetadata, metadata))
return new MethodDefinition(targetModule, method);
}
throw new NotSupportedException();
@ -246,6 +250,13 @@ namespace ICSharpCode.Decompiler.Metadata @@ -246,6 +250,13 @@ namespace ICSharpCode.Decompiler.Metadata
}
}
public static MethodDefinition Resolve(this MethodSpecificationHandle handle, IMetadataResolveContext context)
{
var metadata = context.CurrentModule.Metadata;
var ms = metadata.GetMethodSpecification(handle);
return ResolveAsMethod(ms.Method, context);
}
class Unspecializer : ISignatureTypeProvider<EntityHandle, Unit>
{
public EntityHandle GetArrayType(EntityHandle elementType, ArrayShape shape)
@ -322,12 +333,12 @@ namespace ICSharpCode.Decompiler.Metadata @@ -322,12 +333,12 @@ namespace ICSharpCode.Decompiler.Metadata
public static class SignatureBlobComparer
{
public static bool EqualsMethodSignature(BlobReader a, BlobReader b, IMetadataResolveContext contextForA, IMetadataResolveContext contextForB)
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, IMetadataResolveContext contextForA, IMetadataResolveContext contextForB)
static bool EqualsMethodSignature(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB)
{
SignatureHeader header;
// compare signature headers
@ -349,6 +360,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -349,6 +360,7 @@ namespace ICSharpCode.Decompiler.Metadata
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))
@ -365,50 +377,50 @@ namespace ICSharpCode.Decompiler.Metadata @@ -365,50 +377,50 @@ namespace ICSharpCode.Decompiler.Metadata
static bool IsSameCompressedInteger(ref BlobReader a, ref BlobReader b, out int value)
{
return a.TryReadCompressedInteger(out value) == b.TryReadCompressedInteger(out int otherValue) && value == otherValue;
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;
return a.TryReadCompressedSignedInteger(out value) && b.TryReadCompressedSignedInteger(out int otherValue) && value == otherValue;
}
static bool TypesAreEqual(ref BlobReader a, ref BlobReader b, IMetadataResolveContext contextForA, IMetadataResolveContext contextForB, int typeCode)
static bool TypesAreEqual(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB, int typeCode)
{
switch (typeCode) {
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 22:
case 24:
case 25:
case 28: // primitive types
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 15: // pointer type
case 16: // byref type
case 69: // pinned type
case 29: // szarray type
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 27:
case 0x1B: // ELEMENT_TYPE_FNPTR
if (!EqualsMethodSignature(ref a, ref b, contextForA, contextForB))
return false;
return true;
case 20: // array type
case 0x14: // ELEMENT_TYPE_ARRAY
// element type
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
@ -424,7 +436,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -424,7 +436,7 @@ namespace ICSharpCode.Decompiler.Metadata
if (!IsSameCompressedInteger(ref a, ref b, out _))
return false;
}
// lowerBounds
// lower bounds
if (!IsSameCompressedInteger(ref a, ref b, out int numOfLowerBounds))
return false;
for (int i = 0; i < numOfLowerBounds; i++) {
@ -432,8 +444,8 @@ namespace ICSharpCode.Decompiler.Metadata @@ -432,8 +444,8 @@ namespace ICSharpCode.Decompiler.Metadata
return false;
}
return true;
case 31: // mod-req type
case 32: // mod-opt type
case 0x1F: // ELEMENT_TYPE_CMOD_REQD
case 0x20: // ELEMENT_TYPE_CMOD_OPT
// modifier
if (!TypeHandleEquals(ref a, ref b, contextForA, contextForB))
return false;
@ -443,7 +455,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -443,7 +455,7 @@ namespace ICSharpCode.Decompiler.Metadata
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
return true;
case 21: // generic instance type
case 0x15: // ELEMENT_TYPE_GENERICINST
// generic type
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
@ -458,14 +470,14 @@ namespace ICSharpCode.Decompiler.Metadata @@ -458,14 +470,14 @@ namespace ICSharpCode.Decompiler.Metadata
return false;
}
return true;
case 19: // type parameter
case 30: // method type parameter
case 0x13: // ELEMENT_TYPE_VAR
case 0x1E: // ELEMENT_TYPE_MVAR
// index
if (!IsSameCompressedInteger(ref a, ref b, out _))
return false;
return true;
case 17:
case 18:
case 0x11: // ELEMENT_TYPE_VALUETYPE
case 0x12: // ELEMENT_TYPE_CLASS
if (!TypeHandleEquals(ref a, ref b, contextForA, contextForB))
return false;
return true;
@ -474,21 +486,13 @@ namespace ICSharpCode.Decompiler.Metadata @@ -474,21 +486,13 @@ namespace ICSharpCode.Decompiler.Metadata
}
}
static bool TypeHandleEquals(ref BlobReader a, ref BlobReader b, IMetadataResolveContext contextForA, IMetadataResolveContext contextForB)
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;
var resolvedA = MetadataResolver.ResolveType(typeA, contextForA);
var resolvedB = MetadataResolver.ResolveType(typeB, contextForB);
if (resolvedA.IsNil || resolvedB.IsNil)
return false;
if (resolvedA.Handle != resolvedB.Handle)
return false;
if (resolvedA.Module.FullName != resolvedB.Module.FullName)
return false;
return true;
return typeA.GetFullTypeName(contextForA) == typeB.GetFullTypeName(contextForB);
}
}
}

2
ICSharpCode.Decompiler/Metadata/OperandType.cs

@ -42,7 +42,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -42,7 +42,7 @@ namespace ICSharpCode.Decompiler.Metadata
ShortVariable
}
static partial class ILOpCodeExtensions
public static partial class ILOpCodeExtensions
{
public static OperandType GetOperandType(this ILOpCode opCode)
{

10
ICSharpCode.Decompiler/Output/TextTokenWriter.cs

@ -106,15 +106,15 @@ namespace ICSharpCode.Decompiler @@ -106,15 +106,15 @@ namespace ICSharpCode.Decompiler
var definition = type.GetDefinition();
if (definition == null)
return null;
return new TypeDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.TypeDefinitionHandle)definition.MetadataToken);
return new TypeDefinition(typeSystem.GetModuleDefinition(definition.ParentAssembly), (System.Reflection.Metadata.TypeDefinitionHandle)definition.MetadataToken);
case IMethod method:
return new MethodDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.MethodDefinitionHandle)method.MetadataToken);
return new MethodDefinition(typeSystem.GetModuleDefinition(method.ParentAssembly), (System.Reflection.Metadata.MethodDefinitionHandle)method.MetadataToken);
case IProperty property:
return new PropertyDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.PropertyDefinitionHandle)property.MetadataToken);
return new PropertyDefinition(typeSystem.GetModuleDefinition(property.ParentAssembly), (System.Reflection.Metadata.PropertyDefinitionHandle)property.MetadataToken);
case IEvent @event:
return new EventDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.EventDefinitionHandle)@event.MetadataToken);
return new EventDefinition(typeSystem.GetModuleDefinition(@event.ParentAssembly), (System.Reflection.Metadata.EventDefinitionHandle)@event.MetadataToken);
case IField field:
return new FieldDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.FieldDefinitionHandle)field.MetadataToken);
return new FieldDefinition(typeSystem.GetModuleDefinition(field.ParentAssembly), (System.Reflection.Metadata.FieldDefinitionHandle)field.MetadataToken);
default:
return null;
}

23
ICSharpCode.Decompiler/SRMExtensions.cs

@ -134,6 +134,29 @@ namespace ICSharpCode.Decompiler @@ -134,6 +134,29 @@ namespace ICSharpCode.Decompiler
return accessors.Raiser;
}
public static TypeDefinitionHandle GetDeclaringType(this EntityHandle entity, MetadataReader metadata)
{
switch (entity.Kind) {
case HandleKind.TypeDefinition:
var td = metadata.GetTypeDefinition((TypeDefinitionHandle)entity);
return td.GetDeclaringType();
case HandleKind.FieldDefinition:
var fd = metadata.GetFieldDefinition((FieldDefinitionHandle)entity);
return fd.GetDeclaringType();
case HandleKind.MethodDefinition:
var md = metadata.GetMethodDefinition((MethodDefinitionHandle)entity);
return md.GetDeclaringType();
case HandleKind.EventDefinition:
var ed = metadata.GetEventDefinition((EventDefinitionHandle)entity);
return metadata.GetMethodDefinition(ed.GetAccessors().GetAny()).GetDeclaringType();
case HandleKind.PropertyDefinition:
var pd = metadata.GetPropertyDefinition((PropertyDefinitionHandle)entity);
return metadata.GetMethodDefinition(pd.GetAccessors().GetAny()).GetDeclaringType();
default:
throw new ArgumentOutOfRangeException();
}
}
public static TypeReferenceHandle GetDeclaringType(this TypeReference tr)
{
switch (tr.ResolutionScope.Kind) {

15
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -32,6 +32,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -32,6 +32,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
Dictionary<SRM.EntityHandle, IProperty> propertyLookupCache = new Dictionary<SRM.EntityHandle, IProperty>();
Dictionary<SRM.EntityHandle, IMethod> methodLookupCache = new Dictionary<SRM.EntityHandle, IMethod>();
Dictionary<SRM.EntityHandle, IEvent> eventLookupCache = new Dictionary<SRM.EntityHandle, IEvent>();
Dictionary<IUnresolvedAssembly, Metadata.PEFile> moduleLookup = new Dictionary<IUnresolvedAssembly, Metadata.PEFile>();
public DecompilerTypeSystem(Metadata.PEFile moduleDefinition)
{
@ -52,7 +54,9 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -52,7 +54,9 @@ namespace ICSharpCode.Decompiler.TypeSystem
continue;
var asm = moduleDefinition.AssemblyResolver.Resolve(asmRef);
if (asm != null) {
referencedAssemblies.Add(cecilLoader.LoadModule(asm));
IUnresolvedAssembly unresolvedAsm = cecilLoader.LoadModule(asm);
referencedAssemblies.Add(unresolvedAsm);
moduleLookup.Add(unresolvedAsm, asm);
var metadata = asm.Metadata;
foreach (var h in metadata.ExportedTypes) {
var forwarder = metadata.GetExportedType(h);
@ -85,6 +89,15 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -85,6 +89,15 @@ namespace ICSharpCode.Decompiler.TypeSystem
public SRM.MetadataReader GetMetadata() => moduleDefinition.Metadata;
public Metadata.PEFile GetModuleDefinition(IAssembly assembly)
{
if (assembly == MainAssembly)
return ModuleDefinition;
if (!moduleLookup.TryGetValue(assembly.UnresolvedAssembly, out var file))
return null;
return file;
}
public IType ResolveFromSignature(ITypeReference typeReference)
{
return typeReference.Resolve(context);

1
ICSharpCode.Decompiler/TypeSystem/IDecompilerTypeSystem.cs

@ -36,6 +36,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -36,6 +36,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
MetadataReader GetMetadata();
PEFile ModuleDefinition { get; }
PEFile GetModuleDefinition(IAssembly assembly);
/// <summary>
/// Gets a type system instance that automatically specializes the results

1
ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedMethod.cs

@ -223,6 +223,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -223,6 +223,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
Accessibility = typeDefinition.IsAbstract ? Accessibility.Protected : Accessibility.Public,
IsSynthetic = true,
HasBody = true,
MetadataToken = System.Reflection.Metadata.Ecma335.MetadataTokens.MethodDefinitionHandle(0), // initialize with properly typed nil token, to avoid InvalidCastExceptions
ReturnType = KnownTypeReference.Void
};
}

6
ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.Decompiler.TypeSystem
{
@ -99,5 +100,10 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -99,5 +100,10 @@ namespace ICSharpCode.Decompiler.TypeSystem
member = member.Specialize(substitution);
return member;
}
public PEFile GetModuleDefinition(IAssembly assembly)
{
return context.GetModuleDefinition(assembly);
}
}
}

17
ILSpy/ILSpy.csproj

@ -111,6 +111,7 @@ @@ -111,6 +111,7 @@
<DependentUpon>DebugSteps.xaml</DependentUpon>
</Compile>
<Compile Include="ILSpyTraceListener.cs" />
<Compile Include="Languages\CodeMappingInfo.cs" />
<Compile Include="Languages\CSharpILMixedLanguage.cs" />
<Compile Include="Languages\CSharpLanguage.cs" />
<Compile Include="DecompilationOptions.cs" />
@ -131,6 +132,7 @@ @@ -131,6 +132,7 @@
<Compile Include="ISmartTextOutput.cs" />
<Compile Include="Images\Images.cs" />
<Compile Include="Languages\ILLanguage.cs" />
<Compile Include="Languages\ILSignatureProvider.cs" />
<Compile Include="Languages\IResourceFileHandler.cs" />
<Compile Include="Languages\Language.cs" />
<Compile Include="Languages\Languages.cs" />
@ -186,8 +188,23 @@ @@ -186,8 +188,23 @@
<Compile Include="TextView\EditorCommands.cs" />
<Compile Include="TextView\FoldingCommands.cs" />
<Compile Include="TextView\XmlDocRenderer.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzeContextMenuEntry.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedAssemblyTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedFieldAccessTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedFieldTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedMethodTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedMethodUsesTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyAccessorTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeInstantiationsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeUsedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzerEntityTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzerSearchTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzerTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\Extensions.cs" />
<Compile Include="TreeNodes\Analyzer\RemoveAnalyzeContextMenuEntry.cs" />
<Compile Include="TreeNodes\Analyzer\ScopedWhereUsedAnalyzer.cs" />
<Compile Include="TreeNodes\BaseTypesEntryNode.cs" />
<Compile Include="TreeNodes\CopyFullyQualifiedNameContextMenuEntry.cs" />
<Compile Include="TreeNodes\DerivedTypesEntryNode.cs" />

76
ILSpy/Languages/CSharpLanguage.cs

@ -40,6 +40,7 @@ using System.Reflection.Metadata.Ecma335; @@ -40,6 +40,7 @@ using System.Reflection.Metadata.Ecma335;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
using System.Reflection;
using ICSharpCode.Decompiler.Disassembler;
namespace ICSharpCode.ILSpy
{
@ -601,7 +602,17 @@ namespace ICSharpCode.ILSpy @@ -601,7 +602,17 @@ namespace ICSharpCode.ILSpy
convertTypeOptions |= ConvertTypeOptions.IncludeOuterTypeName;
var metadata = method.Module.Metadata;
var md = metadata.GetMethodDefinition(method.Handle);
var name = (md.IsConstructor(metadata)) ? TypeToString(new Decompiler.Metadata.TypeDefinition(method.Module, md.GetDeclaringType()), includeNamespace: includeNamespace) : metadata.GetString(md.Name);
string name;
if (md.IsConstructor(metadata)) {
name = TypeToString(new Decompiler.Metadata.TypeDefinition(method.Module, md.GetDeclaringType()), includeNamespace: includeNamespace);
} else {
if (includeTypeName) {
name = TypeToString(new Decompiler.Metadata.TypeDefinition(method.Module, md.GetDeclaringType()), includeNamespace: includeNamespace) + ".";
} else {
name = "";
}
name += metadata.GetString(md.Name);
}
var signature = md.DecodeSignature(new AstTypeBuilder(convertTypeOptions), new GenericContext(method));
int i = 0;
@ -692,16 +703,6 @@ namespace ICSharpCode.ILSpy @@ -692,16 +703,6 @@ namespace ICSharpCode.ILSpy
return showAllMembers || !CSharpDecompiler.MemberIsHidden(member.Module, member.Handle, new DecompilationOptions().DecompilerSettings);
}
/*
public override IMetadataEntity GetOriginalCodeLocation(IMetadataEntity member)
{
if (showAllMembers || !new DecompilationOptions().DecompilerSettings.AnonymousMethods)
return member;
else
return TreeNodes.Analyzer.Helpers.GetOriginalCodeLocation(member);
}
*/
public override string GetTooltip(Entity entity)
{
var decompilerTypeSystem = new DecompilerTypeSystem(entity.Module);
@ -733,6 +734,59 @@ namespace ICSharpCode.ILSpy @@ -733,6 +734,59 @@ namespace ICSharpCode.ILSpy
var flags = ConversionFlags.All & ~ConversionFlags.ShowBody;
return new CSharpAmbience() { ConversionFlags = flags }.ConvertSymbol(symbol);
}
public override CodeMappingInfo GetCodeMappingInfo(PEFile module, EntityHandle member)
{
var declaringType = member.GetDeclaringType(module.Metadata);
if (declaringType.IsNil && member.Kind == HandleKind.TypeDefinition) {
declaringType = (TypeDefinitionHandle)member;
}
var info = new CodeMappingInfo(this, module, declaringType);
var td = module.Metadata.GetTypeDefinition(declaringType);
foreach (var method in td.GetMethods()) {
var parent = method;
var part = method;
var connectedMethods = new Queue<MethodDefinitionHandle>();
connectedMethods.Enqueue(part);
while (connectedMethods.Count > 0) {
part = connectedMethods.Dequeue();
var md = module.Metadata.GetMethodDefinition(part);
if (!md.HasBody()) {
info.AddMapping(parent, part);
} else {
// TODO : async and yield fsms
// deal with ldftn instructions, i.e., lambdas
var blob = module.Reader.GetMethodBody(md.RelativeVirtualAddress).GetILReader();
while (blob.RemainingBytes > 0) {
var code = blob.DecodeOpCode();
if (code == ILOpCode.Ldftn) {
var token = MetadataTokens.EntityHandle(blob.ReadInt32());
if (token.Kind == HandleKind.MethodDefinition) {
if (((MethodDefinitionHandle)token).IsCompilerGenerated(module.Metadata))
connectedMethods.Enqueue((MethodDefinitionHandle)token);
}
} else {
blob.SkipOperand(code);
}
}
info.AddMapping(parent, part);
}
}
}
return info;
}
}
class InsertDynamicTypeVisitor : DepthFirstAstVisitor

63
ILSpy/Languages/CodeMappingInfo.cs

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.ILSpy
{
public class CodeMappingInfo
{
public Decompiler.Metadata.PEFile Module { get; }
public Language Language { get; }
public TypeDefinitionHandle TypeDefinition { get; }
Dictionary<MethodDefinitionHandle, List<MethodDefinitionHandle>> parts;
Dictionary<MethodDefinitionHandle, MethodDefinitionHandle> parents;
public CodeMappingInfo(Language language, Decompiler.Metadata.PEFile module, TypeDefinitionHandle type)
{
this.Language = language;
this.Module = module;
this.TypeDefinition = type;
this.parts = new Dictionary<MethodDefinitionHandle, List<MethodDefinitionHandle>>();
this.parents = new Dictionary<MethodDefinitionHandle, MethodDefinitionHandle>();
}
public bool ShowMember(EntityHandle entity)
{
return Language.ShowMember(new Decompiler.Metadata.Entity(Module, entity));
}
public IEnumerable<MethodDefinitionHandle> GetMethodParts(MethodDefinitionHandle method)
{
if (parts.TryGetValue(method, out var p))
return p;
return new[] { method };
}
public MethodDefinitionHandle GetParentMethod(MethodDefinitionHandle method)
{
if (parents.TryGetValue(method, out var p))
return p;
return method;
}
public void AddMapping(MethodDefinitionHandle parent, MethodDefinitionHandle part)
{
Debug.Print("Parent: " + MetadataTokens.GetRowNumber(parent) + " Part: " + MetadataTokens.GetRowNumber(part));
if (parents.ContainsKey(part))
return;
parents.Add(part, parent);
if (!parts.TryGetValue(parent, out var list)) {
list = new List<MethodDefinitionHandle>();
parts.Add(parent, list);
}
list.Add(part);
}
}
}

172
ILSpy/Languages/ILSignatureProvider.cs

@ -0,0 +1,172 @@ @@ -0,0 +1,172 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Immutable;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
using SRM = System.Reflection.Metadata;
namespace ICSharpCode.ILSpy
{
class ILSignatureProvider : SRM.ISignatureTypeProvider<string, GenericContext>
{
public static readonly ILSignatureProvider WithoutNamespace = new ILSignatureProvider(false);
public static readonly ILSignatureProvider WithNamespace = new ILSignatureProvider(true);
bool includeNamespace;
public ILSignatureProvider(bool includeNamespace)
{
this.includeNamespace = includeNamespace;
}
public string GetArrayType(string elementType, SRM.ArrayShape shape)
{
string printedShape = "";
for (int i = 0; i < shape.Rank; i++) {
if (i > 0)
printedShape += ", ";
if (i < shape.LowerBounds.Length || i < shape.Sizes.Length) {
int lower = 0;
if (i < shape.LowerBounds.Length) {
lower = shape.LowerBounds[i];
printedShape += lower.ToString();
}
printedShape += "...";
if (i < shape.Sizes.Length)
printedShape += (lower + shape.Sizes[i] - 1).ToString();
}
}
return $"{elementType}[{printedShape}]";
}
public string GetByReferenceType(string elementType)
{
return elementType + "&";
}
public string GetFunctionPointerType(SRM.MethodSignature<string> signature)
{
return "method " + signature.ReturnType + " *(" + string.Join(", ", signature.ParameterTypes) + ")";
}
public string GetGenericInstantiation(string genericType, ImmutableArray<string> typeArguments)
{
return genericType + "<" + string.Join(", ", typeArguments) + ">";
}
public string GetGenericMethodParameter(GenericContext genericContext, int index)
{
return "!!" + genericContext.GetGenericMethodTypeParameterName(index);
}
public string GetGenericTypeParameter(GenericContext genericContext, int index)
{
return "!" + genericContext.GetGenericTypeParameterName(index);
}
public string GetModifiedType(string modifier, string unmodifiedType, bool isRequired)
{
string modifierKeyword = isRequired ? "modreq" : "modopt";
return $"{unmodifiedType} {modifierKeyword}({modifier})";
}
public string GetPinnedType(string elementType)
{
throw new NotImplementedException();
}
public string GetPointerType(string elementType)
{
return elementType + "*";
}
public string GetPrimitiveType(SRM.PrimitiveTypeCode typeCode)
{
switch (typeCode) {
case SRM.PrimitiveTypeCode.Boolean:
return "bool";
case SRM.PrimitiveTypeCode.Byte:
return "uint8";
case SRM.PrimitiveTypeCode.SByte:
return "int8";
case SRM.PrimitiveTypeCode.Char:
return "char";
case SRM.PrimitiveTypeCode.Int16:
return "int16";
case SRM.PrimitiveTypeCode.UInt16:
return "uint16";
case SRM.PrimitiveTypeCode.Int32:
return "int32";
case SRM.PrimitiveTypeCode.UInt32:
return "uint32";
case SRM.PrimitiveTypeCode.Int64:
return "int64";
case SRM.PrimitiveTypeCode.UInt64:
return "uint64";
case SRM.PrimitiveTypeCode.Single:
return "float32";
case SRM.PrimitiveTypeCode.Double:
return "float64";
case SRM.PrimitiveTypeCode.IntPtr:
return "native int";
case SRM.PrimitiveTypeCode.UIntPtr:
return "native uint";
case SRM.PrimitiveTypeCode.Object:
return "object";
case SRM.PrimitiveTypeCode.String:
return "string";
case SRM.PrimitiveTypeCode.TypedReference:
return "typedref";
case SRM.PrimitiveTypeCode.Void:
return "void";
default:
throw new ArgumentOutOfRangeException();
}
}
public string GetSZArrayType(string elementType)
{
return elementType + "[]";
}
public string GetTypeFromDefinition(SRM.MetadataReader reader, SRM.TypeDefinitionHandle handle, byte rawTypeKind)
{
if (!includeNamespace) {
return Decompiler.Disassembler.DisassemblerHelpers.Escape(handle.GetFullTypeName(reader).Name);
}
return handle.GetFullTypeName(reader).ToILNameString();
}
public string GetTypeFromReference(SRM.MetadataReader reader, SRM.TypeReferenceHandle handle, byte rawTypeKind)
{
if (!includeNamespace) {
return Decompiler.Disassembler.DisassemblerHelpers.Escape(handle.GetFullTypeName(reader).Name);
}
return handle.GetFullTypeName(reader).ToILNameString();
}
public string GetTypeFromSpecification(SRM.MetadataReader reader, GenericContext genericContext, SRM.TypeSpecificationHandle handle, byte rawTypeKind)
{
return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext);
}
}
}

175
ILSpy/Languages/Language.cs

@ -18,7 +18,6 @@ @@ -18,7 +18,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Reflection.PortableExecutable;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Util;
@ -270,7 +269,17 @@ namespace ICSharpCode.ILSpy @@ -270,7 +269,17 @@ namespace ICSharpCode.ILSpy
throw new ArgumentNullException(nameof(method));
var metadata = method.Module.Metadata;
var md = metadata.GetMethodDefinition(method.Handle);
var name = metadata.GetString(md.Name);
string name;
if (includeTypeName) {
if (includeNamespace) {
name = md.GetDeclaringType().GetFullTypeName(metadata) + ".";
} else {
name = md.GetDeclaringType().GetFullTypeName(metadata).Name + ".";
}
name += metadata.GetString(md.Name);
} else {
name = metadata.GetString(md.Name);
}
var signature = md.DecodeSignature(includeNamespace ? ILSignatureProvider.WithNamespace : ILSignatureProvider.WithoutNamespace, new GenericContext(method));
int i = 0;
@ -348,12 +357,18 @@ namespace ICSharpCode.ILSpy @@ -348,12 +357,18 @@ namespace ICSharpCode.ILSpy
return true;
}
/// <summary>
/// Used by the analyzer to map compiler generated code back to the original code's location
/// </summary>
public virtual IMetadataEntity GetOriginalCodeLocation(IMetadataEntity member)
public virtual CodeMappingInfo GetCodeMappingInfo(PEFile module, SRM.EntityHandle member)
{
return member;
var parts = new Dictionary<SRM.MethodDefinitionHandle, SRM.MethodDefinitionHandle[]>();
var locations = new Dictionary<SRM.EntityHandle, SRM.MethodDefinitionHandle>();
var declaringType = member.GetDeclaringType(module.Metadata);
if (declaringType.IsNil && member.Kind == SRM.HandleKind.TypeDefinition) {
declaringType = (SRM.TypeDefinitionHandle)member;
}
return new CodeMappingInfo(this, module, declaringType);
}
public static string GetPlatformDisplayName(PEFile module)
@ -382,150 +397,4 @@ namespace ICSharpCode.ILSpy @@ -382,150 +397,4 @@ namespace ICSharpCode.ILSpy
return module.Metadata.MetadataVersion;
}
}
class ILSignatureProvider : SRM.ISignatureTypeProvider<string, GenericContext>
{
public static readonly ILSignatureProvider WithoutNamespace = new ILSignatureProvider(false);
public static readonly ILSignatureProvider WithNamespace = new ILSignatureProvider(true);
bool includeNamespace;
public ILSignatureProvider(bool includeNamespace)
{
this.includeNamespace = includeNamespace;
}
public string GetArrayType(string elementType, SRM.ArrayShape shape)
{
string printedShape = "";
for (int i = 0; i < shape.Rank; i++) {
if (i > 0)
printedShape += ", ";
if (i < shape.LowerBounds.Length || i < shape.Sizes.Length) {
int lower = 0;
if (i < shape.LowerBounds.Length) {
lower = shape.LowerBounds[i];
printedShape += lower.ToString();
}
printedShape += "...";
if (i < shape.Sizes.Length)
printedShape += (lower + shape.Sizes[i] - 1).ToString();
}
}
return $"{elementType}[{printedShape}]";
}
public string GetByReferenceType(string elementType)
{
return elementType + "&";
}
public string GetFunctionPointerType(SRM.MethodSignature<string> signature)
{
return "method " + signature.ReturnType + " *(" + string.Join(", ", signature.ParameterTypes) + ")";
}
public string GetGenericInstantiation(string genericType, ImmutableArray<string> typeArguments)
{
return genericType + "<" + string.Join(", ", typeArguments) + ">";
}
public string GetGenericMethodParameter(GenericContext genericContext, int index)
{
return "!!" + genericContext.GetGenericMethodTypeParameterName(index);
}
public string GetGenericTypeParameter(GenericContext genericContext, int index)
{
return "!" + genericContext.GetGenericTypeParameterName(index);
}
public string GetModifiedType(string modifier, string unmodifiedType, bool isRequired)
{
string modifierKeyword = isRequired ? "modreq" : "modopt";
return $"{unmodifiedType} {modifierKeyword}({modifier})";
}
public string GetPinnedType(string elementType)
{
throw new NotImplementedException();
}
public string GetPointerType(string elementType)
{
return elementType + "*";
}
public string GetPrimitiveType(SRM.PrimitiveTypeCode typeCode)
{
switch (typeCode) {
case SRM.PrimitiveTypeCode.Boolean:
return "bool";
case SRM.PrimitiveTypeCode.Byte:
return "uint8";
case SRM.PrimitiveTypeCode.SByte:
return "int8";
case SRM.PrimitiveTypeCode.Char:
return "char";
case SRM.PrimitiveTypeCode.Int16:
return "int16";
case SRM.PrimitiveTypeCode.UInt16:
return "uint16";
case SRM.PrimitiveTypeCode.Int32:
return "int32";
case SRM.PrimitiveTypeCode.UInt32:
return "uint32";
case SRM.PrimitiveTypeCode.Int64:
return "int64";
case SRM.PrimitiveTypeCode.UInt64:
return "uint64";
case SRM.PrimitiveTypeCode.Single:
return "float32";
case SRM.PrimitiveTypeCode.Double:
return "float64";
case SRM.PrimitiveTypeCode.IntPtr:
return "native int";
case SRM.PrimitiveTypeCode.UIntPtr:
return "native uint";
case SRM.PrimitiveTypeCode.Object:
return "object";
case SRM.PrimitiveTypeCode.String:
return "string";
case SRM.PrimitiveTypeCode.TypedReference:
return "typedref";
case SRM.PrimitiveTypeCode.Void:
return "void";
default:
throw new NotImplementedException();
}
}
public string GetSZArrayType(string elementType)
{
return elementType + "[]";
}
public string GetTypeFromDefinition(SRM.MetadataReader reader, SRM.TypeDefinitionHandle handle, byte rawTypeKind)
{
if (!includeNamespace) {
return Decompiler.Disassembler.DisassemblerHelpers.Escape(handle.GetFullTypeName(reader).Name);
}
return handle.GetFullTypeName(reader).ToILNameString();
}
public string GetTypeFromReference(SRM.MetadataReader reader, SRM.TypeReferenceHandle handle, byte rawTypeKind)
{
if (!includeNamespace) {
return Decompiler.Disassembler.DisassemblerHelpers.Escape(handle.GetFullTypeName(reader).Name);
}
return handle.GetFullTypeName(reader).ToILNameString();
}
public string GetTypeFromSpecification(SRM.MetadataReader reader, GenericContext genericContext, SRM.TypeSpecificationHandle handle, byte rawTypeKind)
{
return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext);
}
}
}

13
ILSpy/MainWindow.xaml.cs

@ -632,6 +632,17 @@ namespace ICSharpCode.ILSpy @@ -632,6 +632,17 @@ namespace ICSharpCode.ILSpy
}
}
return null;
case MethodSpecification ms:
resolvedMember = ms.Handle.Resolve(new SimpleMetadataResolveContext(ms.Module));
if (!resolvedMember.IsNil) {
switch (resolvedMember) {
case MethodDefinition md:
return assemblyListTreeNode.FindMethodNode(md);
default:
throw new NotSupportedException();
}
}
return null;
default:
return null;
}
@ -655,7 +666,7 @@ namespace ICSharpCode.ILSpy @@ -655,7 +666,7 @@ namespace ICSharpCode.ILSpy
ILSpyTreeNode treeNode = FindTreeNode(reference);
if (treeNode != null) {
SelectNode(treeNode);
} else if (reference is ICSharpCode.Decompiler.Disassembler.OpCodeInfo opCode) {
} else if (reference is Decompiler.Disassembler.OpCodeInfo opCode) {
OpenLink(opCode.Link);
}
return decompilationTask;

107
ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs

@ -16,8 +16,9 @@ @@ -16,8 +16,9 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using ICSharpCode.Decompiler.Dom;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
@ -29,63 +30,107 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -29,63 +30,107 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
if (context.TreeView is AnalyzerTreeView && context.SelectedTreeNodes != null && context.SelectedTreeNodes.All(n => n.Parent.IsRoot))
return false;
if (context.SelectedTreeNodes == null)
return context.Reference != null && context.Reference.Reference is MemberReference;
return context.Reference != null && IsValidReference(context.Reference.Reference);
return context.SelectedTreeNodes.All(n => n is IMemberTreeNode);
}
public bool IsEnabled(TextViewContext context)
{
if (context.SelectedTreeNodes == null)
return context.Reference != null && context.Reference.Reference is MemberReference;
return context.Reference != null && context.Reference.Reference is IMetadataEntity;
foreach (IMemberTreeNode node in context.SelectedTreeNodes) {
if (!(node.Member is TypeDefinition
|| node.Member is FieldDefinition
|| node.Member is MethodDefinition
|| AnalyzedPropertyTreeNode.CanShow(node.Member)
|| AnalyzedEventTreeNode.CanShow(node.Member)))
if (!IsValidReference(node.Member))
return false;
}
return true;
}
bool IsValidReference(object reference)
{
return reference is IMetadataEntity
|| reference is MemberReference
|| reference is MethodSpecification
|| reference is TypeReference
|| reference is TypeSpecification;
}
public void Execute(TextViewContext context)
{
if (context.SelectedTreeNodes != null) {
foreach (IMemberTreeNode node in context.SelectedTreeNodes) {
Analyze(node.Member);
}
} else if (context.Reference != null && context.Reference.Reference is MemberReference) {
if (context.Reference.Reference is MemberReference)
Analyze((MemberReference)context.Reference.Reference);
// TODO: implement support for other references: ParameterReference, etc.
} else if (context.Reference != null && IsValidReference(context.Reference.Reference)) {
Analyze(context.Reference.Reference);
}
}
public static void Analyze(IMemberReference member)
public static void Analyze(object member)
{
var definition = member.GetDefinition();
if (definition == null) return;
switch (definition) {
case TypeDefinition td:
if (!td.IsNil)
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedTypeTreeNode(td));
switch (member) {
case IMetadataEntity entity:
switch (entity) {
case TypeDefinition td:
if (!td.IsNil)
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedTypeTreeNode(td));
break;
case FieldDefinition fd:
//if (!fd.IsNil)
// AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedFieldTreeNode(fd));
break;
case MethodDefinition md:
if (!md.IsNil)
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedMethodTreeNode(md.Module, md.Handle));
break;
case PropertyDefinition pd:
//if (!pd.IsNil)
// AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedPropertyTreeNode(pd));
break;
case EventDefinition ed:
//if (!ed.IsNil)
// AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedEventTreeNode(ed));
break;
default:
throw new NotSupportedException();
}
break;
case FieldDefinition fd:
if (!fd.IsNil)
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedFieldTreeNode(fd));
case TypeReference tr:
var resolved = tr.Handle.Resolve(new SimpleMetadataResolveContext(tr.Module));
if (!resolved.IsNil)
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedTypeTreeNode(resolved));
break;
case MethodDefinition md:
if (!md.IsNil)
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedMethodTreeNode(md));
case TypeSpecification ts:
resolved = ts.Handle.Resolve(new SimpleMetadataResolveContext(ts.Module));
if (!resolved.IsNil)
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedTypeTreeNode(resolved));
break;
case PropertyDefinition pd:
if (!pd.IsNil)
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedPropertyTreeNode(pd));
case MemberReference mr:
var resolvedMember = mr.Handle.Resolve(new SimpleMetadataResolveContext(mr.Module));
if (!resolvedMember.IsNil) {
switch (resolvedMember) {
case FieldDefinition fd:
//AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedFieldTreeNode(fd));
break;
case MethodDefinition md:
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedMethodTreeNode(md.Module, md.Handle));
break;
default:
throw new NotSupportedException();
}
}
break;
case EventDefinition ed:
if (!ed.IsNil)
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedEventTreeNode(ed));
case MethodSpecification ms:
resolvedMember = ms.Handle.Resolve(new SimpleMetadataResolveContext(ms.Module));
if (!resolvedMember.IsNil) {
switch (resolvedMember) {
case MethodDefinition md:
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedMethodTreeNode(md.Module, md.Handle));
break;
default:
throw new NotSupportedException();
}
}
break;
}
}

4
ILSpy/TreeNodes/Analyzer/AnalyzedAssemblyTreeNode.cs

@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.Decompiler.Dom;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
@ -42,6 +42,6 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -42,6 +42,6 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
//this.Children.Add(new AnalyzedAssemblyReferencedByTreeNode(analyzedAssembly));
}
public override IMemberReference Member => null;
public override IMetadataEntity Member => null;
}
}

28
ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs

@ -18,39 +18,35 @@ @@ -18,39 +18,35 @@
using System;
using System.Linq;
using ICSharpCode.Decompiler.Dom;
using System.Reflection.Metadata;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal sealed class AnalyzedEventTreeNode : AnalyzerEntityTreeNode
{
private readonly EventDefinition analyzedEvent;
private readonly string prefix;
readonly Decompiler.Metadata.PEFile module;
readonly EventDefinitionHandle analyzedEvent;
readonly string prefix;
public AnalyzedEventTreeNode(EventDefinition analyzedEvent, string prefix = "")
public AnalyzedEventTreeNode(Decompiler.Metadata.PEFile module, EventDefinitionHandle analyzedEvent, string prefix = "")
{
if (analyzedEvent == null)
throw new ArgumentNullException(nameof(analyzedEvent));
this.module = module;
this.analyzedEvent = analyzedEvent;
this.prefix = prefix;
this.LazyLoading = true;
}
public override IMemberReference Member => analyzedEvent;
public override Decompiler.Metadata.IMetadataEntity Member => new Decompiler.Metadata.EventDefinition(module, analyzedEvent);
public override object Icon
{
get { return EventTreeNode.GetIcon(analyzedEvent); }
get { return EventTreeNode.GetIcon(new Decompiler.Metadata.EventDefinition(module, analyzedEvent)); }
}
public override object Text
{
get
{
// TODO: This way of formatting is not suitable for events which explicitly implement interfaces.
return prefix + Language.TypeToString(analyzedEvent.DeclaringType, true) + "." + EventTreeNode.GetText(analyzedEvent, Language);
}
}
// TODO: This way of formatting is not suitable for events which explicitly implement interfaces.
public override object Text => prefix + Language.EventToString(new Decompiler.Metadata.EventDefinition(module, analyzedEvent), includeTypeName: true, includeNamespace: true);
protected override void LoadChildren()
{
@ -73,7 +69,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -73,7 +69,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
this.Children.Add(new AnalyzedInterfaceEventImplementedByTreeNode(analyzedEvent));
}
public static AnalyzerTreeNode TryCreateAnalyzer(MemberReference member)
/*public static AnalyzerTreeNode TryCreateAnalyzer(MemberReference member)
{
if (CanShow(member))
return new AnalyzedEventTreeNode(member as EventDefinition);
@ -88,6 +84,6 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -88,6 +84,6 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return !MainWindow.Instance.CurrentLanguage.ShowMember(eventDef.GetAccessors().First().Method)
|| AnalyzedEventOverridesTreeNode.CanShow(eventDef);
}
}*/
}
}

93
ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs

@ -20,40 +20,46 @@ using System; @@ -20,40 +20,46 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.Dom;
using ICSharpCode.Decompiler.TypeSystem;
using ILOpCode = System.Reflection.Metadata.ILOpCode;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal sealed class AnalyzedFieldAccessTreeNode : AnalyzerSearchTreeNode
sealed class AnalyzedFieldAccessTreeNode : AnalyzerSearchTreeNode
{
private readonly bool showWrites; // true: show writes; false: show read access
private readonly FieldDefinition analyzedField;
private Lazy<Hashtable> foundMethods;
private readonly object hashLock = new object();
readonly bool showWrites; // true: show writes; false: show read access
readonly Decompiler.Metadata.PEFile module;
readonly FieldDefinitionHandle analyzedField;
readonly FullTypeName analyzedTypeName;
readonly string analyzedFieldName;
Lazy<HashSet<Decompiler.Metadata.MethodDefinition>> foundMethods;
readonly object hashLock = new object();
public AnalyzedFieldAccessTreeNode(FieldDefinition analyzedField, bool showWrites)
public AnalyzedFieldAccessTreeNode(Decompiler.Metadata.PEFile module, FieldDefinitionHandle analyzedField, bool showWrites)
{
if (analyzedField.IsNil)
throw new ArgumentNullException(nameof(analyzedField));
this.module = module;
this.analyzedField = analyzedField;
var fd = module.Metadata.GetFieldDefinition(analyzedField);
this.analyzedTypeName = fd.GetDeclaringType().GetFullTypeName(module.Metadata);
this.analyzedFieldName = module.Metadata.GetString(fd.Name);
this.showWrites = showWrites;
}
public override object Text
{
get { return showWrites ? "Assigned By" : "Read By"; }
}
public override object Text => showWrites ? "Assigned By" : "Read By";
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct)
{
foundMethods = new Lazy<Hashtable>(LazyThreadSafetyMode.ExecutionAndPublication);
foundMethods = new Lazy<HashSet<Decompiler.Metadata.MethodDefinition>>(LazyThreadSafetyMode.ExecutionAndPublication);
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedField, FindReferencesInType);
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(module, analyzedField, provideTypeSystem: false, FindReferencesInType);
foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) {
yield return child;
}
@ -61,35 +67,46 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -61,35 +67,46 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
foundMethods = null;
}
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(TypeDefinition type)
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, IDecompilerTypeSystem typeSystem)
{
string name = analyzedField.Name;
foreach (MethodDefinition method in type.Methods) {
var td = module.Metadata.GetTypeDefinition(type);
foreach (var h in td.GetMethods()) {
bool found = false;
if (!method.HasBody)
var method = module.Metadata.GetMethodDefinition(h);
if (!method.HasBody())
continue;
var blob = method.Body.GetILReader();
while (blob.RemainingBytes > 0) {
var opCode = ILParser.DecodeOpCode(ref blob);
var blob = module.Reader.GetMethodBody(method.RelativeVirtualAddress).GetILReader();
while (!found && blob.RemainingBytes > 0) {
var opCode = blob.DecodeOpCode();
if (!CanBeReference(opCode)) {
ILParser.SkipOperand(ref blob, opCode);
blob.SkipOperand(opCode);
continue;
}
var field = ILParser.DecodeMemberToken(ref blob, method.Module);
if (field == null || field.Name != name)
continue;
var definition = field.GetDefinition() as FieldDefinition?;
if (definition?.DeclaringType.FullName != analyzedField.DeclaringType.FullName)
continue;
found = true;
break;
var member = MetadataTokens.EntityHandle(blob.ReadInt32());
switch (member.Kind) {
case HandleKind.FieldDefinition:
// check whether we're looking at the defining assembly
found = member == analyzedField && module == this.module;
break;
case HandleKind.MemberReference:
var mr = module.Metadata.GetMemberReference((MemberReferenceHandle)member);
// safety-check: should always be a field
if (mr.GetKind() != MemberReferenceKind.Field)
break;
if (!module.Metadata.StringComparer.Equals(mr.Name, analyzedFieldName))
break;
var typeName = mr.Parent.GetFullTypeName(module.Metadata);
found = typeName == analyzedTypeName;
break;
}
}
if (found) {
MethodDefinition? codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition?;
if (codeLocation != null && !HasAlreadyBeenFound(codeLocation.Value)) {
var node = new AnalyzedMethodTreeNode(codeLocation.Value);
var md = new Decompiler.Metadata.MethodDefinition(module, h);
if (IsNewResult(md)) {
var node = new AnalyzedMethodTreeNode(module, h);
node.Language = this.Language;
yield return node;
}
@ -97,7 +114,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -97,7 +114,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
}
}
private bool CanBeReference(ILOpCode code)
bool CanBeReference(ILOpCode code)
{
switch (code) {
case ILOpCode.Ldfld:
@ -114,14 +131,14 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -114,14 +131,14 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
}
}
private bool HasAlreadyBeenFound(MethodDefinition method)
bool IsNewResult(Decompiler.Metadata.MethodDefinition method)
{
Hashtable hashtable = foundMethods.Value;
var hashtable = foundMethods.Value;
lock (hashLock) {
if (hashtable.Contains(method)) {
return true;
} else {
hashtable.Add(method, null);
hashtable.Add(method);
return false;
}
}

31
ILSpy/TreeNodes/Analyzer/AnalyzedFieldTreeNode.cs

@ -17,40 +17,37 @@ @@ -17,40 +17,37 @@
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.Decompiler.Dom;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal class AnalyzedFieldTreeNode : AnalyzerEntityTreeNode
class AnalyzedFieldTreeNode : AnalyzerEntityTreeNode
{
private readonly FieldDefinition analyzedField;
readonly Decompiler.Metadata.PEFile module;
readonly FieldDefinitionHandle analyzedField;
public AnalyzedFieldTreeNode(FieldDefinition analyzedField)
public AnalyzedFieldTreeNode(Decompiler.Metadata.PEFile module, FieldDefinitionHandle analyzedField)
{
if (analyzedField.IsNil)
throw new ArgumentNullException(nameof(analyzedField));
this.module = module;
this.analyzedField = analyzedField;
this.LazyLoading = true;
}
public override object Icon => FieldTreeNode.GetIcon(analyzedField);
public override object Icon => FieldTreeNode.GetIcon(new Decompiler.Metadata.FieldDefinition(module, analyzedField));
public override object Text
{
get
{
return Language.TypeToString(analyzedField.DeclaringType, true) +
"." + analyzedField.Name + " : " + this.Language.TypeToString(analyzedField.FieldType, false, analyzedField);
}
}
public override object Text => Language.FieldToString(new Decompiler.Metadata.FieldDefinition(module, analyzedField), true, true);
protected override void LoadChildren()
{
this.Children.Add(new AnalyzedFieldAccessTreeNode(analyzedField, false));
if (!analyzedField.IsLiteral)
this.Children.Add(new AnalyzedFieldAccessTreeNode(analyzedField, true));
this.Children.Add(new AnalyzedFieldAccessTreeNode(module, analyzedField, false));
var fd = module.Metadata.GetFieldDefinition(analyzedField);
if (!fd.HasFlag(System.Reflection.FieldAttributes.Literal))
this.Children.Add(new AnalyzedFieldAccessTreeNode(module, analyzedField, true));
}
public override IMemberReference Member => analyzedField;
public override Decompiler.Metadata.IMetadataEntity Member => new Decompiler.Metadata.FieldDefinition(module, analyzedField);
}
}

5
ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Threading;
using ICSharpCode.Decompiler.TypeSystem;
using Mono.Cecil;
@ -27,9 +28,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -27,9 +28,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal sealed class AnalyzedInterfaceMethodImplementedByTreeNode : AnalyzerSearchTreeNode
{
private readonly MethodDefinition analyzedMethod;
private readonly MethodDefinitionHandle analyzedMethod;
public AnalyzedInterfaceMethodImplementedByTreeNode(MethodDefinition analyzedMethod)
public AnalyzedInterfaceMethodImplementedByTreeNode(MethodDefinitionHandle analyzedMethod)
{
if (analyzedMethod == null)
throw new ArgumentNullException(nameof(analyzedMethod));

34
ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs

@ -18,43 +18,37 @@ @@ -18,43 +18,37 @@
using System;
using System.Reflection;
using ICSharpCode.Decompiler.Dom;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal class AnalyzedMethodTreeNode : AnalyzerEntityTreeNode
{
private readonly MethodDefinition analyzedMethod;
private readonly string prefix;
readonly Decompiler.Metadata.PEFile module;
readonly MethodDefinitionHandle analyzedMethod;
readonly string prefix;
public AnalyzedMethodTreeNode(MethodDefinition analyzedMethod, string prefix = "")
public AnalyzedMethodTreeNode(Decompiler.Metadata.PEFile module, MethodDefinitionHandle analyzedMethod, string prefix = "")
{
if (analyzedMethod.IsNil)
throw new ArgumentNullException(nameof(analyzedMethod));
this.module = module;
this.analyzedMethod = analyzedMethod;
this.prefix = prefix;
this.LazyLoading = true;
}
public override object Icon
{
get { return MethodTreeNode.GetIcon(analyzedMethod); }
}
public override object Icon => MethodTreeNode.GetIcon(new Decompiler.Metadata.MethodDefinition(module, analyzedMethod));
public override object Text
{
get
{
return prefix + Language.TypeToString(analyzedMethod.DeclaringType, true) + "." + MethodTreeNode.GetText(analyzedMethod, Language);
}
}
public override object Text => prefix + Language.MethodToString(new Decompiler.Metadata.MethodDefinition(module, analyzedMethod), true, true);
protected override void LoadChildren()
{
if (analyzedMethod.HasBody)
this.Children.Add(new AnalyzedMethodUsesTreeNode(analyzedMethod));
if (analyzedMethod.HasBody(module.Metadata))
this.Children.Add(new AnalyzedMethodUsesTreeNode(module, analyzedMethod));
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));
else
this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedMethod));
@ -63,9 +57,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -63,9 +57,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
this.Children.Add(new AnalyzedMethodOverridesTreeNode(analyzedMethod));
if (AnalyzedInterfaceMethodImplementedByTreeNode.CanShow(analyzedMethod))
this.Children.Add(new AnalyzedInterfaceMethodImplementedByTreeNode(analyzedMethod));
this.Children.Add(new AnalyzedInterfaceMethodImplementedByTreeNode(analyzedMethod));*/
}
public override IMemberReference Member => analyzedMethod;
public override Decompiler.Metadata.IMetadataEntity Member => new Decompiler.Metadata.MethodDefinition(module, analyzedMethod);
}
}

122
ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs

@ -19,10 +19,13 @@ @@ -19,10 +19,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.Dom;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
@ -31,73 +34,84 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -31,73 +34,84 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
/// </summary>
internal sealed class AnalyzedMethodUsesTreeNode : AnalyzerSearchTreeNode
{
private readonly MethodDefinition analyzedMethod;
readonly Decompiler.Metadata.PEFile module;
readonly MethodDefinitionHandle analyzedMethod;
public AnalyzedMethodUsesTreeNode(MethodDefinition analyzedMethod)
public AnalyzedMethodUsesTreeNode(Decompiler.Metadata.PEFile module, MethodDefinitionHandle analyzedMethod)
{
if (analyzedMethod.IsNil)
throw new ArgumentNullException(nameof(analyzedMethod));
this.module = module;
this.analyzedMethod = analyzedMethod;
}
public override object Text
{
get { return "Uses"; }
}
public override object Text => "Uses";
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct)
{
foreach (var f in GetUsedFields().Distinct()) {
var node = new AnalyzedFieldTreeNode(f);
node.Language = this.Language;
yield return node;
}
foreach (var m in GetUsedMethods().Distinct()) {
var node = new AnalyzedMethodTreeNode(m);
node.Language = this.Language;
yield return node;
}
}
private IEnumerable<MethodDefinition> GetUsedMethods()
{
if (!analyzedMethod.HasBody) yield break;
var blob = analyzedMethod.Body.GetILReader();
while (blob.RemainingBytes > 0) {
var opCode = ILParser.DecodeOpCode(ref blob);
switch (opCode.GetOperandType()) {
case OperandType.Method:
case OperandType.Sig:
case OperandType.Tok:
var member = ILParser.DecodeMemberToken(ref blob, analyzedMethod.Module).GetDefinition();
if (member is MethodDefinition md)
yield return md;
break;
default:
ILParser.SkipOperand(ref blob, opCode);
break;
var mapping = Language.GetCodeMappingInfo(module, analyzedMethod);
foreach (var part in mapping.GetMethodParts(analyzedMethod)) {
foreach (var node in ScanMethod(part)) {
node.Language = this.Language;
yield return node;
}
}
}
IEnumerable<FieldDefinition> GetUsedFields()
{
if (!analyzedMethod.HasBody) yield break;
var blob = analyzedMethod.Body.GetILReader();
while (blob.RemainingBytes > 0) {
var opCode = ILParser.DecodeOpCode(ref blob);
switch (opCode.GetOperandType()) {
case OperandType.Field:
case OperandType.Sig:
case OperandType.Tok:
var member = ILParser.DecodeMemberToken(ref blob, analyzedMethod.Module).GetDefinition();
if (member is FieldDefinition fd)
yield return fd;
break;
default:
ILParser.SkipOperand(ref blob, opCode);
break;
IEnumerable<AnalyzerTreeNode> ScanMethod(MethodDefinitionHandle handle)
{
var md = module.Metadata.GetMethodDefinition(handle);
if (!md.HasBody()) yield break;
var blob = module.Reader.GetMethodBody(md.RelativeVirtualAddress).GetILReader();
var resolveContext = new SimpleMetadataResolveContext(module);
while (blob.RemainingBytes > 0) {
var opCode = ILParser.DecodeOpCode(ref blob);
Decompiler.Metadata.MethodDefinition method;
switch (opCode.GetOperandType()) {
case OperandType.Field:
case OperandType.Method:
case OperandType.Sig:
case OperandType.Tok:
var member = MetadataTokens.EntityHandle(blob.ReadInt32());
switch (member.Kind) {
case HandleKind.FieldDefinition:
if (!Language.ShowMember(new Decompiler.Metadata.TypeDefinition(module, member.GetDeclaringType(module.Metadata))) || !Language.ShowMember(new Decompiler.Metadata.FieldDefinition(module, (FieldDefinitionHandle)member))) break;
yield return new AnalyzedFieldTreeNode(module, (FieldDefinitionHandle)member);
break;
case HandleKind.MethodDefinition:
if (!Language.ShowMember(new Decompiler.Metadata.TypeDefinition(module, member.GetDeclaringType(module.Metadata))) || !Language.ShowMember(new Decompiler.Metadata.MethodDefinition(module, (MethodDefinitionHandle)member))) break;
yield return new AnalyzedMethodTreeNode(module, (MethodDefinitionHandle)member);
break;
case HandleKind.MemberReference:
var mr = module.Metadata.GetMemberReference((MemberReferenceHandle)member);
switch (mr.GetKind()) {
case MemberReferenceKind.Method:
method = MetadataResolver.ResolveAsMethod(member, resolveContext);
if (method.IsNil || !Language.ShowMember(new Decompiler.Metadata.TypeDefinition(method.Module, method.Handle.GetDeclaringType(method.Module.Metadata))) || !Language.ShowMember(method)) break;
yield return new AnalyzedMethodTreeNode(method.Module, method.Handle);
break;
case MemberReferenceKind.Field:
var field = MetadataResolver.ResolveAsField(member, resolveContext);
if (field.IsNil || !Language.ShowMember(new Decompiler.Metadata.TypeDefinition(field.Module, field.Handle.GetDeclaringType(field.Module.Metadata))) || !Language.ShowMember(field)) break;
yield return new AnalyzedFieldTreeNode(field.Module, field.Handle);
break;
default:
throw new ArgumentOutOfRangeException();
}
break;
case HandleKind.MethodSpecification:
method = MetadataResolver.ResolveAsMethod(member, resolveContext);
if (method.IsNil || !Language.ShowMember(new Decompiler.Metadata.TypeDefinition(method.Module, method.Handle.GetDeclaringType(method.Module.Metadata))) || !Language.ShowMember(method)) break;
yield return new AnalyzedMethodTreeNode(method.Module, method.Handle);
break;
}
break;
default:
ILParser.SkipOperand(ref blob, opCode);
break;
}
}
}
}

6
ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs

@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using ICSharpCode.Decompiler.Dom;
using System.Reflection.Metadata;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
@ -24,8 +24,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -24,8 +24,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
private readonly string name;
public AnalyzedPropertyAccessorTreeNode(MethodDefinition analyzedMethod, string name)
: base(analyzedMethod)
public AnalyzedPropertyAccessorTreeNode(Decompiler.Metadata.PEFile module, MethodDefinitionHandle analyzedMethod, string name)
: base(module, analyzedMethod)
{
this.name = name;
}

57
ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs

@ -17,57 +17,54 @@ @@ -17,57 +17,54 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Dom;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal sealed class AnalyzedPropertyTreeNode : AnalyzerEntityTreeNode
sealed class AnalyzedPropertyTreeNode : AnalyzerEntityTreeNode
{
private readonly PropertyDefinition analyzedProperty;
private readonly bool isIndexer;
private readonly string prefix;
readonly Decompiler.Metadata.PEFile module;
readonly PropertyDefinitionHandle analyzedProperty;
readonly bool isIndexer;
readonly string prefix;
public AnalyzedPropertyTreeNode(PropertyDefinition analyzedProperty, string prefix = "")
public AnalyzedPropertyTreeNode(Decompiler.Metadata.PEFile module, PropertyDefinitionHandle analyzedProperty, string prefix = "")
{
if (analyzedProperty == null)
throw new ArgumentNullException(nameof(analyzedProperty));
this.isIndexer = analyzedProperty.IsIndexer;
using (LoadedAssembly.DisableAssemblyLoad()) {
this.isIndexer = analyzedProperty.HasMatchingDefaultMemberAttribute(module, out _);
}
this.module = module;
this.analyzedProperty = analyzedProperty;
this.prefix = prefix;
this.LazyLoading = true;
}
public override object Icon
{
get { return PropertyTreeNode.GetIcon(analyzedProperty, isIndexer); }
}
public override object Icon => PropertyTreeNode.GetIcon(new Decompiler.Metadata.PropertyDefinition(module, analyzedProperty), isIndexer);
public override object Text
{
get
{
// TODO: This way of formatting is not suitable for properties which explicitly implement interfaces.
return prefix + Language.TypeToString(analyzedProperty.DeclaringType, true) + "." + PropertyTreeNode.GetText(analyzedProperty, Language, isIndexer);
}
}
// TODO: This way of formatting is not suitable for properties which explicitly implement interfaces.
public override object Text => prefix + Language.PropertyToString(new Decompiler.Metadata.PropertyDefinition(module, analyzedProperty), includeNamespace: true, includeTypeName: true, isIndexer: isIndexer);
protected override void LoadChildren()
{
if (!analyzedProperty.GetMethod.IsNil)
this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.GetMethod, "get"));
if (!analyzedProperty.SetMethod.IsNil)
this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.SetMethod, "set"));
foreach (var accessor in analyzedProperty.OtherMethods)
this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null));
var accessors = module.Metadata.GetPropertyDefinition(analyzedProperty).GetAccessors();
if (!accessors.Getter.IsNil)
this.Children.Add(new AnalyzedPropertyAccessorTreeNode(module, accessors.Getter, "get"));
if (!accessors.Setter.IsNil)
this.Children.Add(new AnalyzedPropertyAccessorTreeNode(module, accessors.Setter, "set"));
//foreach (var accessor in analyzedProperty.OtherMethods)
// this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null));
if (AnalyzedPropertyOverridesTreeNode.CanShow(analyzedProperty))
/*if (AnalyzedPropertyOverridesTreeNode.CanShow(analyzedProperty))
this.Children.Add(new AnalyzedPropertyOverridesTreeNode(analyzedProperty));
if (AnalyzedInterfacePropertyImplementedByTreeNode.CanShow(analyzedProperty))
this.Children.Add(new AnalyzedInterfacePropertyImplementedByTreeNode(analyzedProperty));
this.Children.Add(new AnalyzedInterfacePropertyImplementedByTreeNode(analyzedProperty));*/
}
public static AnalyzerTreeNode TryCreateAnalyzer(IMemberReference member)
/*public static AnalyzerTreeNode TryCreateAnalyzer(IMemberReference member)
{
if (CanShow(member))
return new AnalyzedPropertyTreeNode((PropertyDefinition)member);
@ -82,8 +79,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -82,8 +79,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return !MainWindow.Instance.CurrentLanguage.ShowMember(property.GetMethod.IsNil ? property.SetMethod : property.GetMethod)
|| AnalyzedPropertyOverridesTreeNode.CanShow(property);
}
}*/
public override IMemberReference Member => analyzedProperty;
public override Decompiler.Metadata.IMetadataEntity Member => new Decompiler.Metadata.PropertyDefinition(module, analyzedProperty);
}
}

15
ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs

@ -21,13 +21,12 @@ using System.Collections.Generic; @@ -21,13 +21,12 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using ICSharpCode.Decompiler.Dom;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal sealed class AnalyzedTypeExposedByTreeNode : AnalyzerSearchTreeNode
{
private readonly TypeDefinition analyzedType;
private readonly Decompiler.Metadata.TypeDefinition analyzedType;
public AnalyzedTypeExposedByTreeNode(TypeDefinition analyzedType)
{
@ -100,7 +99,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -100,7 +99,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return false;
}
private bool TypeIsExposedBy(PropertyDefinition property)
private bool TypeIsExposedBy(Decompiler.Metadata.PropertyDefinition property)
{
if (IsPrivate(property))
return false;
@ -111,7 +110,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -111,7 +110,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return false;
}
private bool TypeIsExposedBy(EventDefinition eventDef)
private bool TypeIsExposedBy(Decompiler.Metadata.EventDefinition eventDef)
{
if (IsPrivate(eventDef))
return false;
@ -122,7 +121,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -122,7 +121,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return false;
}
private bool TypeIsExposedBy(MethodDefinition method)
private bool TypeIsExposedBy(Decompiler.Metadata.MethodDefinition method)
{
// if the method has overrides, it is probably an explicit interface member
// and should be considered part of the public API even though it is marked private.
@ -152,21 +151,21 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -152,21 +151,21 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return false;
}
private static bool IsPrivate(PropertyDefinition property)
private static bool IsPrivate(Decompiler.Metadata.PropertyDefinition property)
{
bool isGetterPublic = (!property.GetMethod.IsNil && !property.GetMethod.IsPrivate);
bool isSetterPublic = (!property.SetMethod.IsNil && !property.SetMethod.IsPrivate);
return !(isGetterPublic || isSetterPublic);
}
private static bool IsPrivate(EventDefinition eventDef)
private static bool IsPrivate(Decompiler.Metadata.EventDefinition eventDef)
{
bool isAdderPublic = (eventDef.AddMethod != null && !eventDef.AddMethod.IsPrivate);
bool isRemoverPublic = (eventDef.RemoveMethod != null && !eventDef.RemoveMethod.IsPrivate);
return !(isAdderPublic || isRemoverPublic);
}
public static bool CanShow(TypeDefinition type)
public static bool CanShow(Decompiler.Metadata.TypeDefinition type)
{
return true;
}

122
ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs

@ -20,83 +20,133 @@ using System; @@ -20,83 +20,133 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.Dom;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal sealed class AnalyzedTypeInstantiationsTreeNode : AnalyzerSearchTreeNode
sealed class AnalyzedTypeInstantiationsTreeNode : AnalyzerSearchTreeNode
{
private readonly TypeDefinition analyzedType;
private readonly bool isSystemObject;
readonly Decompiler.Metadata.PEFile module;
readonly TypeDefinitionHandle analyzedType;
readonly FullTypeName analyzedTypeName;
public AnalyzedTypeInstantiationsTreeNode(TypeDefinition analyzedType)
public AnalyzedTypeInstantiationsTreeNode(Decompiler.Metadata.PEFile module, TypeDefinitionHandle analyzedType)
{
if (analyzedType.IsNil)
throw new ArgumentNullException(nameof(analyzedType));
this.module = module;
this.analyzedType = analyzedType;
this.isSystemObject = (analyzedType.FullName.ToString() == "System.Object");
this.analyzedTypeName = analyzedType.GetFullTypeName(module.Metadata);
}
public override object Text
{
get { return "Instantiated By"; }
}
public override object Text => "Instantiated By";
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct)
{
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedType, FindReferencesInType);
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(module, analyzedType, provideTypeSystem: false, FindReferencesInType);
return analyzer.PerformAnalysis(ct).OrderBy(n => n.Text);
}
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(TypeDefinition type)
IEnumerable<AnalyzerTreeNode> FindReferencesInType(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, IDecompilerTypeSystem typeSystem)
{
foreach (MethodDefinition method in type.Methods) {
var td = module.Metadata.GetTypeDefinition(type);
foreach (var h in td.GetMethods()) {
bool found = false;
if (!method.HasBody)
continue;
// ignore chained constructors
// (since object is the root of everything, we can short circuit the test in this case)
if (method.IsConstructor && (isSystemObject || analyzedType == type || analyzedType.IsBaseTypeOf(type)))
var method = module.Metadata.GetMethodDefinition(h);
if (!method.HasBody())
continue;
var blob = method.Body.GetILReader();
var blob = module.Reader.GetMethodBody(method.RelativeVirtualAddress).GetILReader();
while (!found && blob.RemainingBytes > 0) {
var opCode = ILParser.DecodeOpCode(ref blob);
switch (opCode.GetOperandType()) {
case OperandType.Method:
case OperandType.Sig:
case OperandType.Tok:
var member = ILParser.DecodeMemberToken(ref blob, method.Module);
if (member.Name == ".ctor") {
if (member.DeclaringType.FullName == analyzedType.FullName) {
found = true;
}
var opCode = blob.DecodeOpCode();
switch (opCode) {
case ILOpCode.Newobj:
var member = MetadataTokens.EntityHandle(blob.ReadInt32());
switch (member.Kind) {
case HandleKind.MethodDefinition:
// check whether we're looking at the defining assembly:
if (module != this.module)
break;
var md = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)member);
if (!module.Metadata.StringComparer.Equals(md.Name, ".ctor"))
break;
found = md.GetDeclaringType() == analyzedType;
break;
case HandleKind.MemberReference:
var mr = module.Metadata.GetMemberReference((MemberReferenceHandle)member);
// safety-check: should always be a method
if (mr.GetKind() != MemberReferenceKind.Method)
break;
if (!module.Metadata.StringComparer.Equals(mr.Name, ".ctor"))
break;
switch (mr.Parent.Kind) {
case HandleKind.MethodDefinition: // varargs method
var parentMD = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)mr.Parent);
found = parentMD.GetDeclaringType() == analyzedType;
break;
case HandleKind.ModuleReference: // global function
throw new NotSupportedException();
default:
var typeName = mr.Parent.GetFullTypeName(module.Metadata);
found = typeName == analyzedTypeName;
break;
}
break;
case HandleKind.MethodSpecification: // do we need to handle these?
throw new NotSupportedException();
default:
throw new ArgumentOutOfRangeException();
}
break;
case ILOpCode.Initobj:
var referencedType = MetadataTokens.EntityHandle(blob.ReadInt32());
switch (referencedType.Kind) {
case HandleKind.TypeDefinition:
// check whether we're looking at the defining assembly:
if (module != this.module)
break;
found = referencedType == analyzedType;
break;
case HandleKind.TypeReference:
case HandleKind.TypeSpecification:
var referencedTypeName = referencedType.GetFullTypeName(module.Metadata);
found = referencedTypeName == analyzedTypeName;
break;
default:
throw new ArgumentOutOfRangeException();
}
break;
default:
ILParser.SkipOperand(ref blob, opCode);
blob.SkipOperand(opCode);
break;
}
}
if (found) {
var node = new AnalyzedMethodTreeNode(method);
var node = new AnalyzedMethodTreeNode(module, h);
node.Language = this.Language;
yield return node;
}
}
}
public static bool CanShow(TypeDefinition type)
public static bool CanShow(MetadataReader metadata, TypeDefinitionHandle handle)
{
return (type.IsClass && !(type.HasFlag(TypeAttributes.Abstract) && type.HasFlag(TypeAttributes.Sealed)) && !type.IsEnum);
var td = metadata.GetTypeDefinition(handle);
return (td.Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Class
&& !((td.Attributes & TypeAttributes.Abstract) != 0 && (td.Attributes & TypeAttributes.Sealed) != 0)
&& !handle.IsEnum(metadata);
}
}
}

45
ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs

@ -17,53 +17,48 @@ @@ -17,53 +17,48 @@
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.Decompiler.Dom;
using ICSharpCode.Decompiler.Metadata;
using SRM = System.Reflection.Metadata;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal class AnalyzedTypeTreeNode : AnalyzerEntityTreeNode
{
private readonly TypeDefinition analyzedType;
readonly TypeDefinition analyzedType;
readonly SRM.TypeDefinition td;
public AnalyzedTypeTreeNode(TypeDefinition analyzedType)
{
if (analyzedType.IsNil)
throw new ArgumentNullException(nameof(analyzedType));
this.analyzedType = analyzedType;
this.td = analyzedType.Module.Metadata.GetTypeDefinition(analyzedType.Handle);
this.LazyLoading = true;
}
public override object Icon
{
get { return TypeTreeNode.GetIcon(analyzedType); }
}
public override object Icon => TypeTreeNode.GetIcon(analyzedType);
public override object Text
{
get
{
return Language.TypeToString(analyzedType, true);
}
}
public override object Text => Language.TypeToString(analyzedType, includeNamespace: true);
protected override void LoadChildren()
{
if (AnalyzedAttributeAppliedToTreeNode.CanShow(analyzedType))
this.Children.Add(new AnalyzedAttributeAppliedToTreeNode(analyzedType));
if (AnalyzedTypeInstantiationsTreeNode.CanShow(analyzedType))
this.Children.Add(new AnalyzedTypeInstantiationsTreeNode(analyzedType));
if (AnalyzedTypeUsedByTreeNode.CanShow(analyzedType))
this.Children.Add(new AnalyzedTypeUsedByTreeNode(analyzedType));
//if (AnalyzedAttributeAppliedToTreeNode.CanShow(analyzedType))
// this.Children.Add(new AnalyzedAttributeAppliedToTreeNode(analyzedType));
if (AnalyzedTypeExposedByTreeNode.CanShow(analyzedType))
if (AnalyzedTypeInstantiationsTreeNode.CanShow(analyzedType.Module.Metadata, analyzedType.Handle))
this.Children.Add(new AnalyzedTypeInstantiationsTreeNode(analyzedType.Module, analyzedType.Handle));
if (AnalyzedTypeUsedByTreeNode.CanShow(analyzedType.Module, analyzedType.Handle))
this.Children.Add(new AnalyzedTypeUsedByTreeNode(analyzedType.Module, analyzedType.Handle));
/*
if (AnalyzedTypeExposedByTreeNode.CanShow(analyzedType.Module.Metadata, analyzedType.Handle))
this.Children.Add(new AnalyzedTypeExposedByTreeNode(analyzedType));
if (AnalyzedTypeExtensionMethodsTreeNode.CanShow(analyzedType))
this.Children.Add(new AnalyzedTypeExtensionMethodsTreeNode(analyzedType));
if (AnalyzedTypeExtensionMethodsTreeNode.CanShow(analyzedType.Module.Metadata, analyzedType.Handle))
this.Children.Add(new AnalyzedTypeExtensionMethodsTreeNode(analyzedType));*/
}
public override IMemberReference Member => analyzedType;
public override IMetadataEntity Member => analyzedType;
}
}

249
ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs

@ -19,176 +19,221 @@ @@ -19,176 +19,221 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.Dom;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal sealed class AnalyzedTypeUsedByTreeNode : AnalyzerSearchTreeNode
{
private readonly TypeDefinition analyzedType;
readonly Decompiler.Metadata.PEFile module;
readonly TypeDefinitionHandle analyzedType;
readonly FullTypeName analyzedTypeName;
public AnalyzedTypeUsedByTreeNode(TypeDefinition analyzedType)
public AnalyzedTypeUsedByTreeNode(Decompiler.Metadata.PEFile module, TypeDefinitionHandle analyzedType)
{
if (analyzedType.IsNil)
throw new ArgumentNullException(nameof(analyzedType));
this.module = module;
this.analyzedType = analyzedType;
this.analyzedTypeName = analyzedType.GetFullTypeName(module.Metadata);
}
public override object Text
{
get { return "Used By"; }
}
public override object Text => "Used By";
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct)
{
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedType, FindTypeUsage);
return analyzer.PerformAnalysis(ct)
.Cast<AnalyzerEntityTreeNode>()
.Where(n => n.Member.DeclaringType.FullName != analyzedType.FullName)
.Distinct(new AnalyzerEntityTreeNodeComparer())
.OrderBy(n => n.Text);
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerEntityTreeNode>(module, analyzedType, provideTypeSystem: true, FindTypeUsage);
return analyzer.PerformAnalysis(ct).Distinct(AnalyzerEntityTreeNodeComparer.Instance).OrderBy(n => n.Text);
}
private IEnumerable<AnalyzerEntityTreeNode> FindTypeUsage(TypeDefinition type)
IEnumerable<AnalyzerEntityTreeNode> FindTypeUsage(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, IDecompilerTypeSystem typeSystem)
{
if (type == analyzedType)
if (type == this.analyzedType && module == this.module)
yield break;
if (IsUsedInTypeDefinition(type))
yield return new AnalyzedTypeTreeNode(type) { Language = Language };
// TODO : cache / optimize this per assembly
var analyzedTypeDefinition = typeSystem.Compilation.FindType(analyzedTypeName).GetDefinition();
var typeDefinition = typeSystem.ResolveAsType(type).GetDefinition();
foreach (var field in type.Fields.Where(IsUsedInField))
yield return new AnalyzedFieldTreeNode(field) { Language = Language };
if (analyzedTypeDefinition == null || typeDefinition == null)
yield break;
foreach (var method in type.Methods.Where(IsUsedInMethodDefinition))
yield return HandleSpecialMethodNode(method);
}
var visitor = new TypeDefinitionUsedVisitor(analyzedTypeDefinition);
private AnalyzerEntityTreeNode HandleSpecialMethodNode(MethodDefinition method)
{
var property = method.DeclaringType.Properties.FirstOrDefault(p => p.GetMethod == method || p.SetMethod == method);
if (property != null)
return new AnalyzedPropertyTreeNode(property) { Language = Language };
if (typeDefinition.DirectBaseTypes.Any(bt => analyzedTypeDefinition.Equals(bt.GetDefinition())))
yield return new AnalyzedTypeTreeNode(new Decompiler.Metadata.TypeDefinition(module, type)) { Language = Language };
return new AnalyzedMethodTreeNode(method) { Language = Language };
}
foreach (var field in typeDefinition.Fields.Where(f => IsUsedInField(f, visitor)))
yield return new AnalyzedFieldTreeNode(module, (FieldDefinitionHandle)field.MetadataToken) { Language = Language };
private bool IsUsedInTypeReferences(IEnumerable<TypeReference> types)
{
return types.Any(IsUsedInTypeReference);
}
foreach (var method in typeDefinition.Methods.Where(m => IsUsedInMethodDefinition(m, visitor, typeSystem, module)))
yield return new AnalyzedMethodTreeNode(module, (MethodDefinitionHandle)method.MetadataToken) { Language = Language };
private bool IsUsedInTypeReference(ITypeReference type)
{
if (type == null)
return false;
return TypeMatches(type.DeclaringType)
|| TypeMatches(type);
foreach (var property in typeDefinition.Properties.Where(p => IsUsedInProperty(p, visitor, typeSystem, module)))
yield return new AnalyzedPropertyTreeNode(module, (PropertyDefinitionHandle)property.MetadataToken) { Language = Language };
}
private bool IsUsedInTypeDefinition(TypeDefinition type)
bool IsUsedInField(IField field, TypeDefinitionUsedVisitor visitor)
{
return IsUsedInTypeReference(type)
|| TypeMatches(type.BaseType)
|| IsUsedInTypeReferences(type.Interfaces.Select(i => i.InterfaceType));
visitor.Found = false;
field.ReturnType.AcceptVisitor(visitor);
return visitor.Found;
}
private bool IsUsedInField(FieldDefinition field)
bool IsUsedInProperty(IProperty property, TypeDefinitionUsedVisitor visitor, IDecompilerTypeSystem typeSystem, PEFile module)
{
if (field.IsNil) return false;
return TypeMatches(field.DeclaringType) || field.DecodeSignature(new TypeUsedInSignature(analyzedType), default(Unit));
visitor.Found = false;
property.ReturnType.AcceptVisitor(visitor);
for (int i = 0; i < property.Parameters.Count && !visitor.Found; i++)
property.Parameters[i].Type.AcceptVisitor(visitor);
return visitor.Found
|| (property.CanGet && IsUsedInMethodBody(module, visitor, typeSystem, (MethodDefinitionHandle)property.Getter.MetadataToken))
|| (property.CanSet && IsUsedInMethodBody(module, visitor, typeSystem, (MethodDefinitionHandle)property.Setter.MetadataToken));
}
private bool IsUsedInMethod(MethodDefinition method)
bool IsUsedInMethodDefinition(IMethod method, TypeDefinitionUsedVisitor visitor, IDecompilerTypeSystem typeSystem, PEFile module)
{
if (method == null)
return false;
return TypeMatches(method.DeclaringType)
|| TypeMatches(method.ReturnType)
|| IsUsedInMethodParameters(method.Parameters);
visitor.Found = false;
method.ReturnType.AcceptVisitor(visitor);
for (int i = 0; i < method.Parameters.Count && !visitor.Found; i++)
method.Parameters[i].Type.AcceptVisitor(visitor);
return visitor.Found || IsUsedInMethodBody(module, visitor, typeSystem, (MethodDefinitionHandle)method.MetadataToken);
}
private bool IsUsedInMethodDefinition(MethodDefinition method)
bool IsUsedInMethod(IMethod method, TypeDefinitionUsedVisitor visitor)
{
return IsUsedInMethodReference(method)
|| IsUsedInMethodBody(method);
visitor.Found = false;
method.ReturnType.AcceptVisitor(visitor);
for (int i = 0; i < method.Parameters.Count && !visitor.Found; i++)
method.Parameters[i].Type.AcceptVisitor(visitor);
return visitor.Found;
}
private bool IsUsedInMethodBody(MethodDefinition method)
bool IsUsedInMethodBody(PEFile module, TypeDefinitionUsedVisitor visitor, IDecompilerTypeSystem typeSystem, MethodDefinitionHandle method)
{
if (method.Body == null)
if (method.IsNil)
return false;
var md = module.Metadata.GetMethodDefinition(method);
if (!md.HasBody())
return false;
bool found = false;
foreach (var instruction in method.Body.Instructions) {
TypeReference tr = instruction.Operand as TypeReference;
if (IsUsedInTypeReference(tr)) {
found = true;
break;
}
FieldReference fr = instruction.Operand as FieldReference;
if (IsUsedInFieldReference(fr)) {
found = true;
break;
}
MethodReference mr = instruction.Operand as MethodReference;
if (IsUsedInMethodReference(mr)) {
found = true;
break;
var blob = module.Reader.GetMethodBody(md.RelativeVirtualAddress).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.TypeReference:
case HandleKind.TypeSpecification:
var resolvedType = typeSystem.ResolveAsType(member);
resolvedType.AcceptVisitor(visitor);
if (visitor.Found)
return true;
break;
case HandleKind.TypeDefinition:
if (this.module != module)
break;
if (member == analyzedType)
return true;
break;
case HandleKind.FieldDefinition:
if (this.module != module)
break;
var resolvedField = typeSystem.ResolveAsField(member);
if (IsUsedInField(resolvedField, visitor))
return true;
break;
case HandleKind.MethodDefinition:
var resolvedMethod = typeSystem.ResolveAsMethod(member);
if (resolvedMethod == null)
break;
if (IsUsedInMethod(resolvedMethod, visitor))
return true;
break;
case HandleKind.MemberReference:
var resolvedMember = typeSystem.ResolveAsMember(member);
if (resolvedMember == null)
break;
if (resolvedMember is IField f && IsUsedInField(f, visitor))
return true;
if (resolvedMember is IMethod m && IsUsedInMethod(m, visitor))
return true;
break;
case HandleKind.MethodSpecification:
resolvedMethod = typeSystem.ResolveAsMethod(member);
if (resolvedMethod == null)
break;
if (IsUsedInMethod(resolvedMethod, visitor))
return true;
break;
default:
break;
}
break;
default:
blob.SkipOperand(opCode);
break;
}
}
method.Body = null; // discard body to reduce memory pressure & higher GC gen collections
return found;
return false;
}
private bool IsUsedInMethodParameters(IEnumerable<ParameterDefinition> parameters)
public static bool CanShow(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type)
{
return parameters.Any(IsUsedInMethodParameter);
return !type.IsNil;
}
}
private bool IsUsedInMethodParameter(ParameterDefinition parameter)
{
return TypeMatches(parameter.ParameterType);
}
class AnalyzerEntityTreeNodeComparer : IEqualityComparer<AnalyzerEntityTreeNode>
{
public static readonly AnalyzerEntityTreeNodeComparer Instance = new AnalyzerEntityTreeNodeComparer();
private bool TypeMatches(ITypeReference tref)
public bool Equals(AnalyzerEntityTreeNode x, AnalyzerEntityTreeNode y)
{
if (tref != null && tref.Name == analyzedType.Name) {
var tdef = tref.GetDefinition();
if (tdef != null) {
return (tdef == analyzedType);
}
}
return false;
return x.Member == y.Member;
}
public static bool CanShow(TypeDefinition type)
public int GetHashCode(AnalyzerEntityTreeNode obj)
{
return type != null;
return obj.Member.GetHashCode();
}
}
internal class AnalyzerEntityTreeNodeComparer : IEqualityComparer<AnalyzerEntityTreeNode>
class TypeDefinitionUsedVisitor : TypeVisitor
{
public bool Equals(AnalyzerEntityTreeNode x, AnalyzerEntityTreeNode y)
readonly ITypeDefinition typeDefinition;
public bool Found { get; set; }
public TypeDefinitionUsedVisitor(ITypeDefinition definition)
{
return x.Member == y.Member;
this.typeDefinition = definition;
}
public int GetHashCode(AnalyzerEntityTreeNode node)
public override IType VisitTypeDefinition(ITypeDefinition type)
{
return node.Member.GetHashCode();
Found |= typeDefinition.Equals(type);
return base.VisitTypeDefinition(type);
}
}
}

1
ILSpy/TreeNodes/Analyzer/AnalyzerEntityTreeNode.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System.Collections.Generic;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer

3
ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs

@ -18,10 +18,7 @@ @@ -18,10 +18,7 @@
using System;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Threading;
using ICSharpCode.Decompiler.Disassembler;
using Dom = ICSharpCode.Decompiler.Dom;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{

43
ILSpy/TreeNodes/Analyzer/Extensions.cs

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
public static class Extensions
{
public static TypeDefinitionHandle GetDeclaringType(this MethodDefinitionHandle method, MetadataReader metadata)
{
if (method.IsNil)
throw new ArgumentNullException(nameof(method));
return metadata.GetMethodDefinition(method).GetDeclaringType();
}
public static TypeDefinitionHandle GetDeclaringType(this FieldDefinitionHandle field, MetadataReader metadata)
{
if (field.IsNil)
throw new ArgumentNullException(nameof(field));
return metadata.GetFieldDefinition(field).GetDeclaringType();
}
public static TypeDefinitionHandle GetDeclaringType(this PropertyDefinitionHandle property, MetadataReader metadata)
{
if (property.IsNil)
throw new ArgumentNullException(nameof(property));
var accessor = metadata.GetPropertyDefinition(property).GetAccessors().GetAny();
return metadata.GetMethodDefinition(accessor).GetDeclaringType();
}
public static TypeDefinitionHandle GetDeclaringType(this EventDefinitionHandle @event, MetadataReader metadata)
{
if (@event.IsNil)
throw new ArgumentNullException(nameof(@event));
var accessor = metadata.GetEventDefinition(@event).GetAccessors().GetAny();
return metadata.GetMethodDefinition(accessor).GetDeclaringType();
}
}
}

128
ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs

@ -20,9 +20,10 @@ using System; @@ -20,9 +20,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Dom;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
@ -31,49 +32,57 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -31,49 +32,57 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
/// <summary>
/// Determines the accessibility domain of a member for where-used analysis.
/// </summary>
internal class ScopedWhereUsedAnalyzer<T>
class ScopedWhereUsedAnalyzer<T>
{
private readonly PEFile assemblyScope;
private TypeDefinition typeScope;
private static readonly TypeSystemAttributeTypeProvider typeProvider = TypeSystemAttributeTypeProvider.CreateDefault();
readonly Decompiler.Metadata.PEFile assemblyScope;
readonly bool provideTypeSystem;
TypeDefinitionHandle typeScopeHandle;
TypeDefinition typeScope;
static readonly TypeSystemAttributeTypeProvider typeProvider = TypeSystemAttributeTypeProvider.CreateDefault();
private readonly Accessibility memberAccessibility = Accessibility.Public;
private Accessibility typeAccessibility = Accessibility.Public;
private readonly Func<TypeDefinition, IEnumerable<T>> typeAnalysisFunction;
readonly Accessibility memberAccessibility = Accessibility.Public;
Accessibility typeAccessibility = Accessibility.Public;
readonly Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction;
public ScopedWhereUsedAnalyzer(TypeDefinition type, Func<TypeDefinition, IEnumerable<T>> typeAnalysisFunction)
public ScopedWhereUsedAnalyzer(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction)
{
this.typeScope = type;
this.assemblyScope = type.Module;
this.typeScopeHandle = type;
this.assemblyScope = module;
this.typeScope = module.Metadata.GetTypeDefinition(typeScopeHandle);
this.provideTypeSystem = provideTypeSystem;
this.typeAnalysisFunction = typeAnalysisFunction;
}
public ScopedWhereUsedAnalyzer(MethodDefinition method, Func<TypeDefinition, IEnumerable<T>> typeAnalysisFunction)
: this(method.DeclaringType, 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)
{
this.memberAccessibility = GetMethodAccessibility(method);
this.memberAccessibility = GetMethodAccessibility(module.Metadata, method);
}
public ScopedWhereUsedAnalyzer(PropertyDefinition property, Func<TypeDefinition, IEnumerable<T>> typeAnalysisFunction)
: this(property.DeclaringType, typeAnalysisFunction)
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)
{
Accessibility getterAccessibility = (property.GetMethod.IsNil) ? Accessibility.Private : GetMethodAccessibility(property.GetMethod);
Accessibility setterAccessibility = (property.SetMethod.IsNil) ? Accessibility.Private : GetMethodAccessibility(property.SetMethod);
var pd = module.Metadata.GetPropertyDefinition(property);
var accessors = pd.GetAccessors();
Accessibility getterAccessibility = (accessors.Getter.IsNil) ? Accessibility.Private : GetMethodAccessibility(module.Metadata, accessors.Getter);
Accessibility setterAccessibility = (accessors.Setter.IsNil) ? Accessibility.Private : GetMethodAccessibility(module.Metadata, accessors.Setter);
this.memberAccessibility = (Accessibility)Math.Max((int)getterAccessibility, (int)setterAccessibility);
}
public ScopedWhereUsedAnalyzer(EventDefinition eventDef, Func<TypeDefinition, IEnumerable<T>> typeAnalysisFunction)
: this(eventDef.DeclaringType, typeAnalysisFunction)
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)
{
// 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.]
this.memberAccessibility = GetMethodAccessibility(eventDef.AddMethod);
var ed = module.Metadata.GetEventDefinition(eventDef);
this.memberAccessibility = GetMethodAccessibility(module.Metadata, ed.GetAccessors().Adder);
}
public ScopedWhereUsedAnalyzer(FieldDefinition field, Func<TypeDefinition, IEnumerable<T>> typeAnalysisFunction)
: this(field.DeclaringType, typeAnalysisFunction)
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)
{
switch (field.Attributes & FieldAttributes.FieldAccessMask) {
var fd = module.Metadata.GetFieldDefinition(field);
switch (fd.Attributes & FieldAttributes.FieldAccessMask) {
case FieldAttributes.Private:
default:
memberAccessibility = Accessibility.Private;
@ -96,10 +105,11 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -96,10 +105,11 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
}
}
private Accessibility GetMethodAccessibility(MethodDefinition method)
Accessibility GetMethodAccessibility(MetadataReader metadata, MethodDefinitionHandle method)
{
Accessibility accessibility;
switch (method.Attributes & MethodAttributes.MemberAccessMask) {
var methodInfo = metadata.GetMethodDefinition(method);
switch (methodInfo.Attributes & MethodAttributes.MemberAccessMask) {
case MethodAttributes.Private:
default:
accessibility = Accessibility.Private;
@ -144,25 +154,26 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -144,25 +154,26 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return FindReferencesGlobal(ct);
}
private void DetermineTypeAccessibility()
void DetermineTypeAccessibility()
{
while (!typeScope.DeclaringType.IsNil) {
while (!typeScope.GetDeclaringType().IsNil) {
Accessibility accessibility = GetNestedTypeAccessibility(typeScope);
if ((int)typeAccessibility > (int)accessibility) {
typeAccessibility = accessibility;
if (typeAccessibility == Accessibility.Private)
return;
}
typeScope = typeScope.DeclaringType;
typeScopeHandle = typeScope.GetDeclaringType();
typeScope = assemblyScope.Metadata.GetTypeDefinition(typeScopeHandle);
}
if (typeScope.IsNotPublic &&
if ((typeScope.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NotPublic &&
((int)typeAccessibility > (int)Accessibility.Internal)) {
typeAccessibility = Accessibility.Internal;
}
}
private static Accessibility GetNestedTypeAccessibility(TypeDefinition type)
static Accessibility GetNestedTypeAccessibility(TypeDefinition type)
{
Accessibility result;
switch (type.Attributes & TypeAttributes.VisibilityMask) {
@ -193,7 +204,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -193,7 +204,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
/// <summary>
/// The effective accessibility of a member
/// </summary>
private enum Accessibility
enum Accessibility
{
Private,
FamilyAndInternal,
@ -203,7 +214,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -203,7 +214,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
Public
}
private IEnumerable<T> FindReferencesInAssemblyAndFriends(CancellationToken ct)
IEnumerable<T> FindReferencesInAssemblyAndFriends(CancellationToken ct)
{
var assemblies = GetAssemblyAndAnyFriends(assemblyScope, ct);
@ -211,7 +222,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -211,7 +222,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return assemblies.AsParallel().WithCancellation(ct).SelectMany(a => FindReferencesInAssembly(a, ct));
}
private IEnumerable<T> FindReferencesGlobal(CancellationToken ct)
IEnumerable<T> FindReferencesGlobal(CancellationToken ct)
{
var assemblies = GetReferencingAssemblies(assemblyScope, ct);
@ -219,43 +230,50 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -219,43 +230,50 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return assemblies.AsParallel().WithCancellation(ct).SelectMany(asm => FindReferencesInAssembly(asm, ct));
}
private IEnumerable<T> FindReferencesInAssembly(PEFile asm, CancellationToken ct)
IEnumerable<T> FindReferencesInAssembly(Decompiler.Metadata.PEFile module, CancellationToken ct)
{
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.TypeDefinitions, t => t.NestedTypes)) {
IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(module) : null;
var metadata = module.Metadata;
foreach (var type in TreeTraversal.PreOrder(metadata.TypeDefinitions, t => metadata.GetTypeDefinition(t).GetNestedTypes())) {
ct.ThrowIfCancellationRequested();
foreach (var result in typeAnalysisFunction(type)) {
foreach (var result in typeAnalysisFunction(module, type, ts)) {
ct.ThrowIfCancellationRequested();
yield return result;
}
}
}
private IEnumerable<T> FindReferencesInTypeScope(CancellationToken ct)
IEnumerable<T> FindReferencesInTypeScope(CancellationToken ct)
{
foreach (TypeDefinition type in TreeTraversal.PreOrder(typeScope, t => t.NestedTypes)) {
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(type)) {
foreach (var result in typeAnalysisFunction(assemblyScope, type, ts)) {
ct.ThrowIfCancellationRequested();
yield return result;
}
}
}
private IEnumerable<T> FindReferencesInEnclosingTypeScope(CancellationToken ct)
IEnumerable<T> FindReferencesInEnclosingTypeScope(CancellationToken ct)
{
foreach (TypeDefinition type in TreeTraversal.PreOrder(typeScope.DeclaringType, t => t.NestedTypes)) {
IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope) : null;
foreach (var type in TreeTraversal.PreOrder(typeScope.GetDeclaringType(), t => assemblyScope.Metadata.GetTypeDefinition(t).GetNestedTypes())) {
ct.ThrowIfCancellationRequested();
foreach (var result in typeAnalysisFunction(type)) {
foreach (var result in typeAnalysisFunction(assemblyScope, type, ts)) {
ct.ThrowIfCancellationRequested();
yield return result;
}
}
}
private IEnumerable<PEFile> GetReferencingAssemblies(PEFile asm, CancellationToken ct)
IEnumerable<Decompiler.Metadata.PEFile> GetReferencingAssemblies(Decompiler.Metadata.PEFile asm, CancellationToken ct)
{
yield return asm;
string typeScopeNamespace = asm.Metadata.GetString(typeScope.Namespace);
string typeScopeName = asm.Metadata.GetString(typeScope.Name);
IEnumerable<LoadedAssembly> assemblies = MainWindow.Instance.CurrentAssemblyList.GetAssemblies().Where(assy => assy.GetPEFileOrNull()?.IsAssembly == true);
foreach (var assembly in assemblies) {
@ -265,7 +283,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -265,7 +283,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
if (module == null)
continue;
var resolver = assembly.GetAssemblyResolver();
var metadata = module.GetMetadataReader();
var metadata = module.Metadata;
foreach (var reference in module.AssemblyReferences) {
using (LoadedAssembly.DisableAssemblyLoad()) {
if (resolver.Resolve(reference) == asm) {
@ -274,17 +292,20 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -274,17 +292,20 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
}
}
}
if (found && AssemblyReferencesScopeType(module))
if (found && AssemblyReferencesScopeType(metadata, typeScopeName, typeScopeNamespace))
yield return module;
}
}
private IEnumerable<PEFile> GetAssemblyAndAnyFriends(PEFile asm, CancellationToken ct)
IEnumerable<Decompiler.Metadata.PEFile> GetAssemblyAndAnyFriends(Decompiler.Metadata.PEFile asm, CancellationToken ct)
{
yield return asm;
var reader = asm.GetMetadataReader();
var metadata = asm.Metadata;
string typeScopeNamespace = metadata.GetString(typeScope.Namespace);
string typeScopeName = metadata.GetString(typeScope.Name);
var attributes = reader.CustomAttributes.Select(h => reader.GetCustomAttribute(h)).Where(ca => ca.GetAttributeType(asm).FullName.ToString() == "System.Runtime.CompilerServices.InternalsVisibleToAttribute");
var attributes = metadata.CustomAttributes.Select(h => metadata.GetCustomAttribute(h)).Where(ca => ca.GetAttributeType(metadata).GetFullTypeName(metadata).ToString() == "System.Runtime.CompilerServices.InternalsVisibleToAttribute");
var friendAssemblies = new HashSet<string>();
foreach (var attribute in attributes) {
string assemblyName = attribute.DecodeValue(typeProvider).FixedArguments[0].Value as string;
@ -301,18 +322,19 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -301,18 +322,19 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
var module = assembly.GetPEFileOrNull();
if (module == null)
continue;
if (AssemblyReferencesScopeType(module))
if (AssemblyReferencesScopeType(module.Metadata, typeScopeName, typeScopeNamespace))
yield return module;
}
}
}
}
private bool AssemblyReferencesScopeType(PEFile asm)
bool AssemblyReferencesScopeType(MetadataReader metadata, string typeScopeName, string typeScopeNamespace)
{
bool hasRef = false;
foreach (var typeRef in asm.TypeReferences) {
if (typeRef.Name == typeScope.Name && typeRef.Namespace == typeScope.Namespace) {
foreach (var h in metadata.TypeReferences) {
var typeRef = metadata.GetTypeReference(h);
if (metadata.StringComparer.Equals(typeRef.Name, typeScopeName) && metadata.StringComparer.Equals(typeRef.Namespace, typeScopeNamespace)) {
hasRef = true;
break;
}

49
ILSpy/TreeNodes/CopyFullyQualifiedNameContextMenuEntry.cs

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
using System;
using System.Windows;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.ILSpy.TreeNodes
@ -17,7 +18,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -17,7 +18,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public void Execute(TextViewContext context)
{
var member = GetMemberNodeFromContext(context)?.Member;
if (member == null) return;
if (member == null || member.IsNil) return;
Clipboard.SetText(GetFullyQualifiedName(member));
}
@ -31,14 +32,46 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -31,14 +32,46 @@ namespace ICSharpCode.ILSpy.TreeNodes
/// </summary>
private string GetFullyQualifiedName(IMetadataEntity member)
{
/*if (member.DeclaringType != null) {
if (member is TypeReference)
return GetFullyQualifiedName(member.DeclaringType) + "+" + member.Name;
else
return GetFullyQualifiedName(member.DeclaringType) + "." + member.Name;
string name;
System.Reflection.Metadata.TypeDefinitionHandle declaringType;
switch (member.Handle.Kind) {
case System.Reflection.Metadata.HandleKind.TypeDefinition:
return ((System.Reflection.Metadata.TypeDefinitionHandle)member.Handle).GetFullTypeName(member.Module.Metadata).ToString();
case System.Reflection.Metadata.HandleKind.FieldDefinition:
name = "";
declaringType = member.Handle.GetDeclaringType(member.Module.Metadata);
var fd = member.Module.Metadata.GetFieldDefinition((System.Reflection.Metadata.FieldDefinitionHandle)member.Handle);
if (!declaringType.IsNil) {
name = declaringType.GetFullTypeName(member.Module.Metadata) + ".";
}
return name + member.Module.Metadata.GetString(fd.Name);
case System.Reflection.Metadata.HandleKind.MethodDefinition:
name = "";
declaringType = member.Handle.GetDeclaringType(member.Module.Metadata);
var md = member.Module.Metadata.GetMethodDefinition((System.Reflection.Metadata.MethodDefinitionHandle)member.Handle);
if (!declaringType.IsNil) {
name = declaringType.GetFullTypeName(member.Module.Metadata) + ".";
}
return name + member.Module.Metadata.GetString(md.Name);
case System.Reflection.Metadata.HandleKind.EventDefinition:
name = "";
declaringType = member.Handle.GetDeclaringType(member.Module.Metadata);
var ed = member.Module.Metadata.GetEventDefinition((System.Reflection.Metadata.EventDefinitionHandle)member.Handle);
if (!declaringType.IsNil) {
name = declaringType.GetFullTypeName(member.Module.Metadata) + ".";
}
return name + member.Module.Metadata.GetString(ed.Name);
case System.Reflection.Metadata.HandleKind.PropertyDefinition:
name = "";
declaringType = member.Handle.GetDeclaringType(member.Module.Metadata);
var pd = member.Module.Metadata.GetPropertyDefinition((System.Reflection.Metadata.PropertyDefinitionHandle)member.Handle);
if (!declaringType.IsNil) {
name = declaringType.GetFullTypeName(member.Module.Metadata) + ".";
}
return name + member.Module.Metadata.GetString(pd.Name);
default:
throw new ArgumentOutOfRangeException();
}
return (member is TypeReference t ? t.Namespace + "." : "") + member.Name;*/
throw new NotImplementedException();
}
}
}

5
ILSpy/TreeNodes/TypeTreeNode.cs

@ -30,7 +30,6 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -30,7 +30,6 @@ namespace ICSharpCode.ILSpy.TreeNodes
{
public sealed class TypeTreeNode : ILSpyTreeNode, IMemberTreeNode
{
readonly TypeDefinition typeDefinition;
readonly SRM.TypeDefinition td;
public TypeTreeNode(TypeDefinition typeDefinition, AssemblyTreeNode parentAssemblyNode)
@ -38,12 +37,12 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -38,12 +37,12 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (typeDefinition.IsNil)
throw new ArgumentNullException(nameof(typeDefinition));
this.ParentAssemblyNode = parentAssemblyNode ?? throw new ArgumentNullException(nameof(parentAssemblyNode));
this.typeDefinition = typeDefinition;
this.TypeDefinition = typeDefinition;
this.td = typeDefinition.Module.Metadata.GetTypeDefinition(typeDefinition.Handle);
this.LazyLoading = true;
}
public TypeDefinition TypeDefinition => typeDefinition;
public TypeDefinition TypeDefinition { get; }
public AssemblyTreeNode ParentAssemblyNode { get; }

Loading…
Cancel
Save