Browse Source

Add TypeInstantiatedByAnalyzer and TypeUsedByAnalyzer

pull/1030/head
Siegfried Pammer 8 years ago
parent
commit
dd7f3753ad
  1. 57
      ILSpy/Analyzers/Builtin/TypeInstantiatedByAnalyzer.cs
  2. 170
      ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs
  3. 10
      ILSpy/ILSpy.csproj

57
ILSpy/Analyzers/Builtin/TypeInstantiatedByAnalyzer.cs

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy.Analyzers.Builtin
{
/// <summary>
/// Shows methods that instantiate a type.
/// </summary>
[Export(typeof(IAnalyzer<ITypeDefinition>))]
class TypeInstantiatedByAnalyzer : IMethodBodyAnalyzer<ITypeDefinition>
{
public string Text => "Instantiated By";
public IEnumerable<IEntity> Analyze(ITypeDefinition analyzedEntity, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context)
{
bool found = false;
var blob = methodBody.GetILReader();
while (!found && blob.RemainingBytes > 0) {
var opCode = blob.DecodeOpCode();
if (!CanBeReference(opCode)) {
blob.SkipOperand(opCode);
continue;
}
EntityHandle methodHandle = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32());
if (!methodHandle.Kind.IsMemberKind())
continue;
var ctor = context.TypeSystem.ResolveAsMethod(methodHandle);
if (ctor == null || !ctor.IsConstructor)
continue;
found = ctor.DeclaringTypeDefinition?.MetadataToken == analyzedEntity.MetadataToken
&& ctor.ParentAssembly.PEFile == analyzedEntity.ParentAssembly.PEFile;
}
if (found) {
yield return method;
}
}
bool CanBeReference(ILOpCode opCode)
{
return opCode == ILOpCode.Newobj || opCode == ILOpCode.Initobj;
}
public bool Show(ITypeDefinition entity) => !entity.IsAbstract && !entity.IsStatic;
}
}

170
ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs

@ -0,0 +1,170 @@ @@ -0,0 +1,170 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy.Analyzers.Builtin
{
/// <summary>
/// Shows entities that use a type.
/// </summary>
[Export(typeof(IAnalyzer<ITypeDefinition>))]
class TypeUsedByAnalyzer : IMethodBodyAnalyzer<ITypeDefinition>, ITypeDefinitionAnalyzer<ITypeDefinition>
{
public string Text => "Used By";
public IEnumerable<IEntity> Analyze(ITypeDefinition analyzedEntity, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context)
{
var typeSystem = context.TypeSystem;
var visitor = new TypeDefinitionUsedVisitor(analyzedEntity);
if (!methodBody.LocalSignature.IsNil) {
foreach (var type in typeSystem.DecodeLocalSignature(methodBody.LocalSignature)) {
type.AcceptVisitor(visitor);
if (visitor.Found) {
yield return method;
yield break;
}
}
}
var blob = methodBody.GetILReader();
while (!visitor.Found && 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 = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32());
if (member.IsNil) continue;
switch (member.Kind) {
case HandleKind.TypeReference:
case HandleKind.TypeSpecification:
case HandleKind.TypeDefinition:
typeSystem.ResolveAsType(member).AcceptVisitor(visitor);
if (visitor.Found) {
yield return method;
yield break;
}
break;
case HandleKind.FieldDefinition:
case HandleKind.MethodDefinition:
case HandleKind.MemberReference:
case HandleKind.MethodSpecification:
VisitMember(visitor, typeSystem.ResolveAsMember(member));
if (visitor.Found) {
yield return method;
yield break;
}
break;
case HandleKind.StandaloneSignature:
var signature = typeSystem.DecodeMethodSignature((StandaloneSignatureHandle)member);
foreach (var type in signature.ParameterTypes) {
type.AcceptVisitor(visitor);
}
signature.ReturnType.AcceptVisitor(visitor);
if (visitor.Found) {
yield return method;
yield break;
}
break;
default:
break;
}
break;
default:
blob.SkipOperand(opCode);
break;
}
}
}
void VisitMember(TypeDefinitionUsedVisitor visitor, IMember member)
{
switch (member) {
case IField field:
field.ReturnType.AcceptVisitor(visitor);
break;
case IMethod method:
foreach (var p in method.Parameters) {
p.Type.AcceptVisitor(visitor);
}
method.ReturnType.AcceptVisitor(visitor);
break;
case IProperty property:
foreach (var p in property.Parameters) {
p.Type.AcceptVisitor(visitor);
}
property.ReturnType.AcceptVisitor(visitor);
break;
case IEvent @event:
@event.ReturnType.AcceptVisitor(visitor);
break;
}
}
public IEnumerable<IEntity> Analyze(ITypeDefinition analyzedEntity, ITypeDefinition type, AnalyzerContext context)
{
var typeSystem = context.TypeSystem;
var visitor = new TypeDefinitionUsedVisitor(analyzedEntity);
foreach (var bt in type.DirectBaseTypes) {
bt.AcceptVisitor(visitor);
}
if (visitor.Found)
yield return type;
foreach (var member in type.Members) {
visitor.Found = false;
VisitMember(visitor, member);
if (visitor.Found)
yield return member;
}
}
bool CanBeReference(ILOpCode opCode)
{
return opCode == ILOpCode.Newobj || opCode == ILOpCode.Initobj;
}
public bool Show(ITypeDefinition entity) => !entity.IsAbstract && !entity.IsStatic;
}
class TypeDefinitionUsedVisitor : TypeVisitor
{
readonly ITypeDefinition typeDefinition;
public bool Found { get; set; }
public TypeDefinitionUsedVisitor(ITypeDefinition definition)
{
this.typeDefinition = definition;
}
public override IType VisitTypeDefinition(ITypeDefinition type)
{
Found |= typeDefinition.MetadataToken == type.MetadataToken
&& typeDefinition.ParentAssembly.PEFile == type.ParentAssembly.PEFile;
return base.VisitTypeDefinition(type);
}
}
}

10
ILSpy/ILSpy.csproj

@ -68,11 +68,16 @@ @@ -68,11 +68,16 @@
<Compile Include="AboutPage.cs" />
<Compile Include="Analyzers\Builtin\MethodUsedByAnalyzer.cs" />
<Compile Include="Analyzers\Builtin\MethodUsesAnalyzer.cs" />
<Compile Include="Analyzers\Builtin\TypeInstantiatedByAnalyzer.cs" />
<Compile Include="Analyzers\Builtin\TypeUsedByAnalyzer.cs" />
<Compile Include="Analyzers\IAnalyzer.cs" />
<Compile Include="Analyzers\AnalyzerTreeView.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Analyzers\TreeNodes\AnalyzedAccessorTreeNode.cs" />
<Compile Include="Analyzers\TreeNodes\AnalyzedEventTreeNode.cs" />
<Compile Include="Analyzers\TreeNodes\AnalyzedMethodTreeNode.cs" />
<Compile Include="Analyzers\TreeNodes\AnalyzedPropertyTreeNode.cs" />
<Compile Include="Analyzers\TreeNodes\AnalyzedTypeTreeNode.cs" />
<Compile Include="App.xaml.cs">
<SubType>Code</SubType>
@ -200,7 +205,6 @@ @@ -200,7 +205,6 @@
<Compile Include="Analyzers\AnalyzerEntityTreeNode.cs" />
<Compile Include="Analyzers\AnalyzerSearchTreeNode.cs" />
<Compile Include="Analyzers\AnalyzerTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\Extensions.cs" />
<Compile Include="Analyzers\RemoveAnalyzeContextMenuEntry.cs" />
<Compile Include="Analyzers\ScopedWhereUsedAnalyzer.cs" />
<Compile Include="TreeNodes\BaseTypesEntryNode.cs" />
@ -374,6 +378,10 @@ @@ -374,6 +378,10 @@
<None Include="@(Resource)" />
</ItemGroup>
<ItemGroup>
<Folder Include="TreeNodes\Analyzer\" />
</ItemGroup>
<!--
Work around to fix Intellisense file generation for XAML projects
https://github.com/dotnet/project-system/issues/2488

Loading…
Cancel
Save