From dd7f3753adce35a0b8ad306ed9a5955d4acc77ee Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Mon, 9 Jul 2018 17:50:50 +0200 Subject: [PATCH] Add TypeInstantiatedByAnalyzer and TypeUsedByAnalyzer --- .../Builtin/TypeInstantiatedByAnalyzer.cs | 57 ++++++ ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs | 170 ++++++++++++++++++ ILSpy/ILSpy.csproj | 10 +- 3 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 ILSpy/Analyzers/Builtin/TypeInstantiatedByAnalyzer.cs create mode 100644 ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs diff --git a/ILSpy/Analyzers/Builtin/TypeInstantiatedByAnalyzer.cs b/ILSpy/Analyzers/Builtin/TypeInstantiatedByAnalyzer.cs new file mode 100644 index 000000000..f9ab5fea0 --- /dev/null +++ b/ILSpy/Analyzers/Builtin/TypeInstantiatedByAnalyzer.cs @@ -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 +{ + /// + /// Shows methods that instantiate a type. + /// + [Export(typeof(IAnalyzer))] + class TypeInstantiatedByAnalyzer : IMethodBodyAnalyzer + { + public string Text => "Instantiated By"; + + public IEnumerable 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; + } +} diff --git a/ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs b/ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs new file mode 100644 index 000000000..f1b50afff --- /dev/null +++ b/ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs @@ -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 +{ + /// + /// Shows entities that use a type. + /// + [Export(typeof(IAnalyzer))] + class TypeUsedByAnalyzer : IMethodBodyAnalyzer, ITypeDefinitionAnalyzer + { + public string Text => "Used By"; + + public IEnumerable 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 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); + } + } +} diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 929100cd9..0fff9fb62 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -68,11 +68,16 @@ + + Code + + + Code @@ -200,7 +205,6 @@ - @@ -374,6 +378,10 @@ + + + +