Browse Source

Clean up of IAnalyzer API.

pull/1213/head
Siegfried Pammer 7 years ago
parent
commit
0464b1a02d
  1. 201
      ILSpy/Analyzers/AnalyzerScope.cs
  2. 36
      ILSpy/Analyzers/AnalyzerSearchTreeNode.cs
  3. 21
      ILSpy/Analyzers/Builtin/EventImplementsInterfaceAnalyzer.cs
  4. 29
      ILSpy/Analyzers/Builtin/EventOverriddenByAnalyzer.cs
  5. 85
      ILSpy/Analyzers/Builtin/FieldAccessAnalyzer.cs
  6. 21
      ILSpy/Analyzers/Builtin/MethodImplementsInterfaceAnalyzer.cs
  7. 34
      ILSpy/Analyzers/Builtin/MethodOverriddenByAnalyzer.cs
  8. 73
      ILSpy/Analyzers/Builtin/MethodUsedByAnalyzer.cs
  9. 16
      ILSpy/Analyzers/Builtin/MethodUsesAnalyzer.cs
  10. 70
      ILSpy/Analyzers/Builtin/MethodVirtualUsedByAnalyzer.cs
  11. 21
      ILSpy/Analyzers/Builtin/PropertyImplementsInterfaceAnalyzer.cs
  12. 21
      ILSpy/Analyzers/Builtin/PropertyOverriddenByAnalyzer.cs
  13. 19
      ILSpy/Analyzers/Builtin/TypeExposedByAnalyzer.cs
  14. 19
      ILSpy/Analyzers/Builtin/TypeExtensionMethodsAnalyzer.cs
  15. 71
      ILSpy/Analyzers/Builtin/TypeInstantiatedByAnalyzer.cs
  16. 173
      ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs
  17. 83
      ILSpy/Analyzers/IAnalyzer.cs
  18. 269
      ILSpy/Analyzers/ScopedWhereUsedAnalyzer.cs
  19. 4
      ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs
  20. 4
      ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs
  21. 4
      ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs
  22. 4
      ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs
  23. 4
      ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs
  24. 2
      ILSpy/ILSpy.csproj

201
ILSpy/Analyzers/AnalyzerScope.cs

@ -0,0 +1,201 @@ @@ -0,0 +1,201 @@
// Copyright (c) 2018 Siegfried Pammer
//
// 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.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.ILSpy.Analyzers
{
public class AnalyzerScope
{
readonly ITypeDefinition typeScope;
/// <summary>
/// Returns whether this scope is local, i.e., AnalyzedSymbol is only reachable
/// from the current module or containing type.
/// </summary>
public bool IsLocal { get; }
public AssemblyList AssemblyList { get; }
public ISymbol AnalyzedSymbol { get; }
public ITypeDefinition TypeScope => typeScope;
Accessibility memberAccessibility, typeAccessibility;
public AnalyzerScope(AssemblyList assemblyList, IEntity entity)
{
AssemblyList = assemblyList;
AnalyzedSymbol = entity;
if (entity is ITypeDefinition type) {
typeScope = type;
memberAccessibility = Accessibility.None;
} else {
typeScope = entity.DeclaringTypeDefinition;
memberAccessibility = entity.Accessibility;
}
typeAccessibility = DetermineTypeAccessibility(ref typeScope);
IsLocal = memberAccessibility == Accessibility.Private || typeAccessibility == Accessibility.Private;
}
public IEnumerable<PEFile> GetModulesInScope(CancellationToken ct)
{
if (IsLocal)
return new[] { TypeScope.ParentModule.PEFile };
if (memberAccessibility == Accessibility.Internal ||
memberAccessibility == Accessibility.ProtectedOrInternal ||
typeAccessibility == Accessibility.Internal ||
typeAccessibility == Accessibility.ProtectedAndInternal)
return GetModuleAndAnyFriends(TypeScope, ct);
return GetReferencingModules(TypeScope.ParentModule.PEFile, ct);
}
public IEnumerable<PEFile> GetAllModules()
{
foreach (var module in AssemblyList.GetAssemblies()) {
var file = module.GetPEFileOrNull();
if (file == null) continue;
yield return file;
}
}
public IEnumerable<ITypeDefinition> GetTypesInScope(CancellationToken ct)
{
if (IsLocal) {
var typeSystem = new DecompilerTypeSystem(TypeScope.ParentModule.PEFile, TypeScope.ParentModule.PEFile.GetAssemblyResolver());
if (memberAccessibility == Accessibility.Private) {
foreach (var type in TreeTraversal.PreOrder(typeScope, t => t.NestedTypes)) {
yield return type;
}
} else {
foreach (var type in TreeTraversal.PreOrder(typeScope.DeclaringTypeDefinition, t => t.NestedTypes)) {
yield return type;
}
}
} else {
foreach (var module in GetModulesInScope(ct)) {
var typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver());
foreach (var type in typeSystem.MainModule.TypeDefinitions) {
yield return type;
}
}
}
}
Accessibility DetermineTypeAccessibility(ref ITypeDefinition typeScope)
{
var typeAccessibility = typeScope.Accessibility;
while (typeScope.DeclaringType != null) {
Accessibility accessibility = typeScope.Accessibility;
if ((int)typeAccessibility > (int)accessibility) {
typeAccessibility = accessibility;
if (typeAccessibility == Accessibility.Private)
break;
}
typeScope = typeScope.DeclaringTypeDefinition;
}
if ((int)typeAccessibility > (int)Accessibility.Internal) {
typeAccessibility = Accessibility.Internal;
}
return typeAccessibility;
}
#region Find modules
IEnumerable<PEFile> GetReferencingModules(PEFile self, CancellationToken ct)
{
yield return self;
foreach (var assembly in AssemblyList.GetAssemblies()) {
ct.ThrowIfCancellationRequested();
bool found = false;
var module = assembly.GetPEFileOrNull();
if (module == null || !module.IsAssembly)
continue;
var resolver = assembly.GetAssemblyResolver();
foreach (var reference in module.AssemblyReferences) {
using (LoadedAssembly.DisableAssemblyLoad()) {
if (resolver.Resolve(reference) == self) {
found = true;
break;
}
}
}
if (found && ModuleReferencesScopeType(module.Metadata, typeScope.Name, typeScope.Namespace))
yield return module;
}
}
IEnumerable<PEFile> GetModuleAndAnyFriends(ITypeDefinition typeScope, CancellationToken ct)
{
var self = typeScope.ParentModule.PEFile;
yield return self;
var typeProvider = MetadataExtensions.MinimalAttributeTypeProvider;
var attributes = self.Metadata.CustomAttributes.Select(h => self.Metadata.GetCustomAttribute(h))
.Where(ca => ca.GetAttributeType(self.Metadata).GetFullTypeName(self.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;
assemblyName = assemblyName.Split(',')[0]; // strip off any public key info
friendAssemblies.Add(assemblyName);
}
if (friendAssemblies.Count > 0) {
IEnumerable<LoadedAssembly> assemblies = AssemblyList.GetAssemblies();
foreach (var assembly in assemblies) {
ct.ThrowIfCancellationRequested();
if (friendAssemblies.Contains(assembly.ShortName)) {
var module = assembly.GetPEFileOrNull();
if (module == null)
continue;
if (ModuleReferencesScopeType(module.Metadata, typeScope.Name, typeScope.Namespace))
yield return module;
}
}
}
}
bool ModuleReferencesScopeType(MetadataReader metadata, string typeScopeName, string typeScopeNamespace)
{
bool hasRef = false;
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;
}
}
return hasRef;
}
#endregion
}
}

36
ILSpy/Analyzers/AnalyzerSearchTreeNode.cs

@ -26,15 +26,15 @@ using ICSharpCode.ILSpy.TreeNodes; @@ -26,15 +26,15 @@ using ICSharpCode.ILSpy.TreeNodes;
namespace ICSharpCode.ILSpy.Analyzers
{
class AnalyzerSearchTreeNode<T> : AnalyzerTreeNode where T : IEntity
class AnalyzerSearchTreeNode : AnalyzerTreeNode
{
private readonly ThreadingSupport threading = new ThreadingSupport();
readonly T analyzedEntity;
readonly IAnalyzer<T> analyzer;
readonly ISymbol symbol;
readonly IAnalyzer analyzer;
public AnalyzerSearchTreeNode(T entity, IAnalyzer<T> analyzer)
public AnalyzerSearchTreeNode(ISymbol symbol, IAnalyzer analyzer)
{
this.analyzedEntity = entity;
this.symbol = symbol;
this.analyzer = analyzer ?? throw new ArgumentNullException(nameof(analyzer));
this.LazyLoading = true;
}
@ -50,31 +50,29 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -50,31 +50,29 @@ namespace ICSharpCode.ILSpy.Analyzers
protected IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct)
{
if (analyzer is IEntityAnalyzer<T> entityAnalyzer) {
var module = analyzedEntity.ParentModule.PEFile;
if (symbol is IEntity entity) {
var module = entity.ParentModule.PEFile;
var ts = new DecompilerTypeSystem(module, module.GetAssemblyResolver());
var context = new AnalyzerContext(ts) {
var context = new AnalyzerContext() {
CancellationToken = ct,
Language = Language,
CodeMappingInfo = Language.GetCodeMappingInfo(module, analyzedEntity.MetadataToken)
AssemblyList = MainWindow.Instance.CurrentAssemblyList
};
foreach (var result in entityAnalyzer.Analyze(analyzedEntity, context)) {
yield return EntityTreeNodeFactory(result);
foreach (var result in analyzer.Analyze(symbol, context)) {
yield return SymbolTreeNodeFactory(result);
}
} else {
foreach (var result in new ScopedWhereUsedAnalyzer<T>(Language, analyzedEntity, analyzer).PerformAnalysis(ct).Distinct()) {
yield return EntityTreeNodeFactory(result);
}
throw new NotSupportedException("Currently symbols that are not entities are not supported!");
}
}
AnalyzerTreeNode EntityTreeNodeFactory(IEntity entity)
AnalyzerTreeNode SymbolTreeNodeFactory(ISymbol symbol)
{
if (entity == null) {
throw new ArgumentNullException(nameof(entity));
if (symbol == null) {
throw new ArgumentNullException(nameof(symbol));
}
switch (entity) {
switch (symbol) {
case ITypeDefinition td:
return new AnalyzedTypeTreeNode(td) {
Language = this.Language
@ -96,7 +94,7 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -96,7 +94,7 @@ namespace ICSharpCode.ILSpy.Analyzers
Language = this.Language
};
default:
throw new ArgumentOutOfRangeException(nameof(entity), $"Entity {entity.GetType().FullName} is not supported.");
throw new ArgumentOutOfRangeException(nameof(symbol), $"Symbol {symbol.GetType().FullName} is not supported.");
}
}

21
ILSpy/Analyzers/Builtin/EventImplementsInterfaceAnalyzer.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
@ -26,12 +27,22 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -26,12 +27,22 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Shows events that implement an interface event.
/// </summary>
[Export(typeof(IAnalyzer<IEvent>))]
class EventImplementsInterfaceAnalyzer : ITypeDefinitionAnalyzer<IEvent>
[Export(typeof(IAnalyzer))]
class EventImplementsInterfaceAnalyzer : IAnalyzer
{
public string Text => "Implemented By";
public IEnumerable<IEntity> Analyze(IEvent analyzedEntity, ITypeDefinition type, AnalyzerContext context)
public IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context)
{
Debug.Assert(analyzedSymbol is IEvent);
var scope = context.GetScopeOf((IEvent)analyzedSymbol);
foreach (var type in scope.GetTypesInScope(context.CancellationToken)) {
foreach (var result in AnalyzeType((IEvent)analyzedSymbol, type))
yield return result;
}
}
IEnumerable<IEntity> AnalyzeType(IEvent analyzedEntity, ITypeDefinition type)
{
var token = analyzedEntity.DeclaringTypeDefinition.MetadataToken;
var module = analyzedEntity.DeclaringTypeDefinition.ParentModule.PEFile;
@ -46,9 +57,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -46,9 +57,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
}
}
public bool Show(IEvent entity)
public bool Show(ISymbol symbol)
{
return entity.DeclaringType.Kind == TypeKind.Interface;
return symbol is IEvent entity && entity.DeclaringType.Kind == TypeKind.Interface;
}
}
}

29
ILSpy/Analyzers/Builtin/EventOverriddenByAnalyzer.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
@ -26,30 +27,40 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -26,30 +27,40 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Shows events that override an event.
/// </summary>
[Export(typeof(IAnalyzer<IEvent>))]
class EventOverriddenByAnalyzer : ITypeDefinitionAnalyzer<IEvent>
[Export(typeof(IAnalyzer))]
class EventOverriddenByAnalyzer : IAnalyzer
{
public string Text => "Overridden By";
public IEnumerable<IEntity> Analyze(IEvent analyzedEntity, ITypeDefinition type, AnalyzerContext context)
public IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context)
{
Debug.Assert(analyzedSymbol is IEvent);
var scope = context.GetScopeOf((IEvent)analyzedSymbol);
foreach (var type in scope.GetTypesInScope(context.CancellationToken)) {
foreach (var result in AnalyzeType((IEvent)analyzedSymbol, type))
yield return result;
}
}
IEnumerable<IEntity> AnalyzeType(IEvent analyzedEntity, ITypeDefinition type)
{
if (!analyzedEntity.DeclaringType.GetAllBaseTypeDefinitions()
.Any(t => t.MetadataToken == analyzedEntity.DeclaringTypeDefinition.MetadataToken && t.ParentModule.PEFile == type.ParentModule.PEFile))
yield break;
foreach (var property in type.Properties) {
if (!property.IsOverride) continue;
if (InheritanceHelper.GetBaseMembers(property, false)
foreach (var @event in type.Events) {
if (!@event.IsOverride) continue;
if (InheritanceHelper.GetBaseMembers(@event, false)
.Any(p => p.MetadataToken == analyzedEntity.MetadataToken &&
p.ParentModule.PEFile == analyzedEntity.ParentModule.PEFile)) {
yield return property;
yield return @event;
}
}
}
public bool Show(IEvent entity)
public bool Show(ISymbol symbol)
{
return entity.IsOverridable && entity.DeclaringType.Kind != TypeKind.Interface;
return symbol is IEvent entity && entity.IsOverridable && entity.DeclaringType.Kind != TypeKind.Interface;
}
}
}

85
ILSpy/Analyzers/Builtin/FieldAccessAnalyzer.cs

@ -20,6 +20,7 @@ using System; @@ -20,6 +20,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
@ -36,7 +37,7 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -36,7 +37,7 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Finds methods where this field is read.
/// </summary>
[Export(typeof(IAnalyzer<IField>))]
[Export(typeof(IAnalyzer))]
class AssignedByFieldAccessAnalyzer : FieldAccessAnalyzer
{
public AssignedByFieldAccessAnalyzer() : base(true) { }
@ -45,7 +46,7 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -45,7 +46,7 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Finds methods where this field is written.
/// </summary>
[Export(typeof(IAnalyzer<IField>))]
[Export(typeof(IAnalyzer))]
class ReadByFieldAccessAnalyzer : FieldAccessAnalyzer
{
public ReadByFieldAccessAnalyzer() : base(false) { }
@ -54,8 +55,10 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -54,8 +55,10 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Finds methods where this field is read or written.
/// </summary>
class FieldAccessAnalyzer : IMethodBodyAnalyzer<IField>
class FieldAccessAnalyzer : IAnalyzer
{
const GetMemberOptions Options = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions;
readonly bool showWrites; // true: show writes; false: show read access
public string Text => showWrites ? "Assigned By" : "Read By";
@ -65,18 +68,73 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -65,18 +68,73 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
this.showWrites = showWrites;
}
public bool Show(IField field)
public bool Show(ISymbol symbol)
{
return symbol is IField field && (!showWrites || !field.IsConst);
}
public IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context)
{
Debug.Assert(analyzedSymbol is IField);
var scope = context.GetScopeOf((IEntity)analyzedSymbol);
foreach (var type in scope.GetTypesInScope(context.CancellationToken)) {
var mappingInfo = context.Language.GetCodeMappingInfo(type.ParentModule.PEFile, type.MetadataToken);
var methods = type.GetMembers(m => m is IMethod, Options).OfType<IMethod>();
foreach (var method in methods) {
if (IsUsedInMethod((IField)analyzedSymbol, method, mappingInfo, context))
yield return method;
}
foreach (var property in type.Properties) {
if (property.CanGet && IsUsedInMethod((IField)analyzedSymbol, property.Getter, mappingInfo, context)) {
yield return property;
continue;
}
if (property.CanSet && IsUsedInMethod((IField)analyzedSymbol, property.Setter, mappingInfo, context)) {
yield return property;
continue;
}
}
foreach (var @event in type.Events) {
if (@event.CanAdd && IsUsedInMethod((IField)analyzedSymbol, @event.AddAccessor, mappingInfo, context)) {
yield return @event;
continue;
}
if (@event.CanRemove && IsUsedInMethod((IField)analyzedSymbol, @event.RemoveAccessor, mappingInfo, context)) {
yield return @event;
continue;
}
if (@event.CanInvoke && IsUsedInMethod((IField)analyzedSymbol, @event.InvokeAccessor, mappingInfo, context)) {
yield return @event;
continue;
}
}
}
}
bool IsUsedInMethod(IField analyzedField, IMethod method, CodeMappingInfo mappingInfo, AnalyzerContext context)
{
return !showWrites || !field.IsConst;
var module = method.ParentModule.PEFile;
foreach (var part in mappingInfo.GetMethodParts((MethodDefinitionHandle)method.MetadataToken)) {
var md = module.Metadata.GetMethodDefinition(part);
if (!md.HasBody()) continue;
if (ScanMethodBody(analyzedField, method, module.Reader.GetMethodBody(md.RelativeVirtualAddress)))
return true;
}
return false;
}
public IEnumerable<IEntity> Analyze(IField analyzedField, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context)
bool ScanMethodBody(IField analyzedField, IMethod method, MethodBodyBlock methodBody)
{
bool found = false;
if (methodBody == null)
return false;
var mainModule = (MetadataModule)method.ParentModule;
var blob = methodBody.GetILReader();
var genericContext = new Decompiler.TypeSystem.GenericContext(); // type parameters don't matter for this analyzer
while (!found && blob.RemainingBytes > 0) {
while (blob.RemainingBytes > 0) {
var opCode = blob.DecodeOpCode();
if (!CanBeReference(opCode)) {
blob.SkipOperand(opCode);
@ -85,17 +143,16 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -85,17 +143,16 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
EntityHandle fieldHandle = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32());
if (!fieldHandle.Kind.IsMemberKind())
continue;
var field = context.TypeSystem.MainModule.ResolveEntity(fieldHandle, genericContext) as IField;
var field = mainModule.ResolveEntity(fieldHandle, genericContext) as IField;
if (field == null)
continue;
found = field.MetadataToken == analyzedField.MetadataToken
&& field.ParentModule.PEFile == analyzedField.ParentModule.PEFile;
if (field.MetadataToken == analyzedField.MetadataToken
&& field.ParentModule.PEFile == analyzedField.ParentModule.PEFile)
return true;
}
if (found) {
yield return method;
}
return false;
}
bool CanBeReference(ILOpCode code)

21
ILSpy/Analyzers/Builtin/MethodImplementsInterfaceAnalyzer.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -29,12 +30,22 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -29,12 +30,22 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Shows methods that implement an interface method.
/// </summary>
[Export(typeof(IAnalyzer<IMethod>))]
class MethodImplementsInterfaceAnalyzer : ITypeDefinitionAnalyzer<IMethod>
[Export(typeof(IAnalyzer))]
class MethodImplementsInterfaceAnalyzer : IAnalyzer
{
public string Text => "Implemented By";
public IEnumerable<IEntity> Analyze(IMethod analyzedEntity, ITypeDefinition type, AnalyzerContext context)
public IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context)
{
Debug.Assert(analyzedSymbol is IMethod);
var scope = context.GetScopeOf((IEntity)analyzedSymbol);
foreach (var type in scope.GetTypesInScope(context.CancellationToken)) {
foreach (var result in AnalyzeType((IMethod)analyzedSymbol, type))
yield return result;
}
}
IEnumerable<IEntity> AnalyzeType(IMethod analyzedEntity, ITypeDefinition type)
{
var token = analyzedEntity.DeclaringTypeDefinition.MetadataToken;
var module = analyzedEntity.DeclaringTypeDefinition.ParentModule.PEFile;
@ -49,9 +60,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -49,9 +60,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
}
}
public bool Show(IMethod entity)
public bool Show(ISymbol entity)
{
return entity.DeclaringType.Kind == TypeKind.Interface;
return entity is IMethod method && method.DeclaringType.Kind == TypeKind.Interface;
}
}
}

34
ILSpy/Analyzers/Builtin/MethodOverriddenByAnalyzer.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
@ -26,30 +27,43 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -26,30 +27,43 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Shows methods that override a method.
/// </summary>
[Export(typeof(IAnalyzer<IMethod>))]
class MethodOverriddenByAnalyzer : ITypeDefinitionAnalyzer<IMethod>
[Export(typeof(IAnalyzer))]
class MethodOverriddenByAnalyzer : IAnalyzer
{
const GetMemberOptions Options = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions;
public string Text => "Overridden By";
public IEnumerable<IEntity> Analyze(IMethod analyzedEntity, ITypeDefinition type, AnalyzerContext context)
public IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context)
{
Debug.Assert(analyzedSymbol is IMethod);
var scope = context.GetScopeOf((IEntity)analyzedSymbol);
foreach (var type in scope.GetTypesInScope(context.CancellationToken)) {
foreach (var result in AnalyzeType((IMethod)analyzedSymbol, type))
yield return result;
}
}
IEnumerable<IEntity> AnalyzeType(IMethod analyzedEntity, ITypeDefinition type)
{
if (!analyzedEntity.DeclaringType.GetAllBaseTypeDefinitions()
.Any(t => t.MetadataToken == analyzedEntity.DeclaringTypeDefinition.MetadataToken && t.ParentModule.PEFile == type.ParentModule.PEFile))
.Any(t => t.MetadataToken == analyzedEntity.DeclaringTypeDefinition.MetadataToken
&& t.ParentModule.PEFile == type.ParentModule.PEFile))
yield break;
foreach (var property in type.Properties) {
if (!property.IsOverride) continue;
if (InheritanceHelper.GetBaseMembers(property, false)
foreach (var method in type.Methods) {
if (!method.IsOverride) continue;
if (InheritanceHelper.GetBaseMembers(method, false)
.Any(p => p.MetadataToken == analyzedEntity.MetadataToken &&
p.ParentModule.PEFile == analyzedEntity.ParentModule.PEFile)) {
yield return property;
yield return method;
}
}
}
public bool Show(IMethod entity)
public bool Show(ISymbol entity)
{
return entity.IsOverridable && entity.DeclaringType.Kind != TypeKind.Interface;
return entity is IMethod method && method.IsOverridable && method.DeclaringType.Kind != TypeKind.Interface;
}
}
}

73
ILSpy/Analyzers/Builtin/MethodUsedByAnalyzer.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler;
@ -30,15 +31,69 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -30,15 +31,69 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Shows entities that are used by a method.
/// </summary>
[Export(typeof(IAnalyzer<IMethod>))]
class MethodUsedByAnalyzer : IMethodBodyAnalyzer<IMethod>
[Export(typeof(IAnalyzer))]
class MethodUsedByAnalyzer : IAnalyzer
{
const GetMemberOptions Options = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions;
public string Text => "Used By";
public bool Show(IMethod entity) => !entity.IsVirtual;
public bool Show(ISymbol symbol) => symbol is IMethod method && !method.IsVirtual;
public IEnumerable<IEntity> Analyze(IMethod analyzedMethod, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context)
public IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context)
{
Debug.Assert(analyzedSymbol is IMethod);
var scope = context.GetScopeOf((IEntity)analyzedSymbol);
foreach (var type in scope.GetTypesInScope(context.CancellationToken)) {
var mappingInfo = context.Language.GetCodeMappingInfo(type.ParentModule.PEFile, type.MetadataToken);
var methods = type.GetMembers(m => m is IMethod, Options).OfType<IMethod>();
foreach (var method in methods) {
if (IsUsedInMethod((IMethod)analyzedSymbol, method, mappingInfo, context))
yield return method;
}
foreach (var property in type.Properties) {
if (property.CanGet && IsUsedInMethod((IMethod)analyzedSymbol, property.Getter, mappingInfo, context)) {
yield return property;
continue;
}
if (property.CanSet && IsUsedInMethod((IMethod)analyzedSymbol, property.Setter, mappingInfo, context)) {
yield return property;
continue;
}
}
foreach (var @event in type.Events) {
if (@event.CanAdd && IsUsedInMethod((IMethod)analyzedSymbol, @event.AddAccessor, mappingInfo, context)) {
yield return @event;
continue;
}
if (@event.CanRemove && IsUsedInMethod((IMethod)analyzedSymbol, @event.RemoveAccessor, mappingInfo, context)) {
yield return @event;
continue;
}
if (@event.CanInvoke && IsUsedInMethod((IMethod)analyzedSymbol, @event.InvokeAccessor, mappingInfo, context)) {
yield return @event;
continue;
}
}
}
}
bool IsUsedInMethod(IMethod analyzedEntity, IMethod method, CodeMappingInfo mappingInfo, AnalyzerContext context)
{
var module = method.ParentModule.PEFile;
var md = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
if (!md.HasBody()) return false;
return ScanMethodBody(analyzedEntity, method, module.Reader.GetMethodBody(md.RelativeVirtualAddress));
}
static bool ScanMethodBody(IMethod analyzedMethod, IMethod method, MethodBodyBlock methodBody)
{
if (methodBody == null)
return false;
var mainModule = (MetadataModule)method.ParentModule;
var blob = methodBody.GetILReader();
var baseMethod = InheritanceHelper.GetBaseMember(analyzedMethod);
@ -53,23 +108,23 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -53,23 +108,23 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
var member = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32());
if (member.IsNil || !member.Kind.IsMemberKind()) continue;
var m = (context.TypeSystem.MainModule.ResolveEntity(member, genericContext) as IMember)?.MemberDefinition;
var m = (mainModule.ResolveEntity(member, genericContext) as IMember)?.MemberDefinition;
if (m == null) continue;
if (opCode == ILOpCode.Call) {
if (IsSameMember(analyzedMethod, m)) {
yield return method;
yield break;
return true;
}
}
if (opCode == ILOpCode.Callvirt && baseMethod != null) {
if (IsSameMember(baseMethod, m)) {
yield return method;
yield break;
return true;
}
}
}
return false;
}
static bool IsSameMember(IMember analyzedMethod, IMember m)

16
ILSpy/Analyzers/Builtin/MethodUsesAnalyzer.cs

@ -33,17 +33,21 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -33,17 +33,21 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Shows entities that are used by a method.
/// </summary>
[Export(typeof(IAnalyzer<IMethod>))]
class MethodUsesAnalyzer : IEntityAnalyzer<IMethod>
[Export(typeof(IAnalyzer))]
class MethodUsesAnalyzer : IAnalyzer
{
public string Text => "Uses";
public bool Show(IMethod entity) => true;
public bool Show(ISymbol symbol) => symbol is IMethod;
public IEnumerable<IEntity> Analyze(IMethod analyzedMethod, AnalyzerContext context)
public IEnumerable<ISymbol> Analyze(ISymbol symbol, AnalyzerContext context)
{
return context.CodeMappingInfo.GetMethodParts((MethodDefinitionHandle)analyzedMethod.MetadataToken)
.SelectMany(h => ScanMethod(analyzedMethod, h, context)).Distinct();
if (symbol is IMethod method) {
return context.Language.GetCodeMappingInfo(method.ParentModule.PEFile, method.MetadataToken)
.GetMethodParts((MethodDefinitionHandle)method.MetadataToken)
.SelectMany(h => ScanMethod(method, h, context)).Distinct();
}
throw new InvalidOperationException("Should never happen.");
}
IEnumerable<IEntity> ScanMethod(IMethod analyzedMethod, MethodDefinitionHandle handle, AnalyzerContext context)

70
ILSpy/Analyzers/Builtin/MethodVirtualUsedByAnalyzer.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler;
@ -30,15 +31,71 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -30,15 +31,71 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Shows entities that are used by a method.
/// </summary>
[Export(typeof(IAnalyzer<IMethod>))]
class MethodVirtualUsedByAnalyzer : IMethodBodyAnalyzer<IMethod>
[Export(typeof(IAnalyzer))]
class MethodVirtualUsedByAnalyzer : IAnalyzer
{
const GetMemberOptions Options = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions;
public string Text => "Used By";
public bool Show(IMethod entity) => entity.IsVirtual;
public IEnumerable<IEntity> Analyze(IMethod analyzedMethod, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context)
public bool Show(ISymbol symbol) => symbol is IMethod method && !method.IsVirtual;
public IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context)
{
Debug.Assert(analyzedSymbol is IMethod);
var scope = context.GetScopeOf((IEntity)analyzedSymbol);
foreach (var type in scope.GetTypesInScope(context.CancellationToken)) {
var mappingInfo = context.Language.GetCodeMappingInfo(type.ParentModule.PEFile, type.MetadataToken);
var methods = type.GetMembers(m => m is IMethod, Options).OfType<IMethod>();
foreach (var method in methods) {
if (IsUsedInMethod((IMethod)analyzedSymbol, method, mappingInfo, context))
yield return method;
}
foreach (var property in type.Properties) {
if (property.CanGet && IsUsedInMethod((IMethod)analyzedSymbol, property.Getter, mappingInfo, context)) {
yield return property;
continue;
}
if (property.CanSet && IsUsedInMethod((IMethod)analyzedSymbol, property.Setter, mappingInfo, context)) {
yield return property;
continue;
}
}
foreach (var @event in type.Events) {
if (@event.CanAdd && IsUsedInMethod((IMethod)analyzedSymbol, @event.AddAccessor, mappingInfo, context)) {
yield return @event;
continue;
}
if (@event.CanRemove && IsUsedInMethod((IMethod)analyzedSymbol, @event.RemoveAccessor, mappingInfo, context)) {
yield return @event;
continue;
}
if (@event.CanInvoke && IsUsedInMethod((IMethod)analyzedSymbol, @event.InvokeAccessor, mappingInfo, context)) {
yield return @event;
continue;
}
}
}
}
bool IsUsedInMethod(IMethod analyzedEntity, IMethod method, CodeMappingInfo mappingInfo, AnalyzerContext context)
{
var module = method.ParentModule.PEFile;
var md = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
if (!md.HasBody()) return false;
return ScanMethodBody(analyzedEntity, method, module.Reader.GetMethodBody(md.RelativeVirtualAddress));
}
static bool ScanMethodBody(IMethod analyzedMethod, IMethod method, MethodBodyBlock methodBody)
{
if (methodBody == null)
return false;
var mainModule = (MetadataModule)method.ParentModule;
var blob = methodBody.GetILReader();
var genericContext = new Decompiler.TypeSystem.GenericContext();
@ -56,10 +113,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -56,10 +113,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
case HandleKind.MethodDefinition:
case HandleKind.MethodSpecification:
case HandleKind.MemberReference:
var m = (context.TypeSystem.MainModule.ResolveEntity(member, genericContext) as IMember)?.MemberDefinition;
var m = (mainModule.ResolveEntity(member, genericContext) as IMember)?.MemberDefinition;
if (m.MetadataToken == analyzedMethod.MetadataToken && m.ParentModule.PEFile == analyzedMethod.ParentModule.PEFile) {
yield return method;
yield break;
return true;
}
break;
}
@ -69,6 +125,8 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -69,6 +125,8 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
break;
}
}
return false;
}
}
}

21
ILSpy/Analyzers/Builtin/PropertyImplementsInterfaceAnalyzer.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
@ -26,12 +27,22 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -26,12 +27,22 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Shows properties that implement an interface property.
/// </summary>
[Export(typeof(IAnalyzer<IProperty>))]
class PropertyImplementsInterfaceAnalyzer : ITypeDefinitionAnalyzer<IProperty>
[Export(typeof(IAnalyzer))]
class PropertyImplementsInterfaceAnalyzer : IAnalyzer
{
public string Text => "Implemented By";
public IEnumerable<IEntity> Analyze(IProperty analyzedEntity, ITypeDefinition type, AnalyzerContext context)
public IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context)
{
Debug.Assert(analyzedSymbol is IProperty);
var scope = context.GetScopeOf((IProperty)analyzedSymbol);
foreach (var type in scope.GetTypesInScope(context.CancellationToken)) {
foreach (var result in AnalyzeType((IProperty)analyzedSymbol, type))
yield return result;
}
}
IEnumerable<IEntity> AnalyzeType(IProperty analyzedEntity, ITypeDefinition type)
{
var token = analyzedEntity.DeclaringTypeDefinition.MetadataToken;
var module = analyzedEntity.DeclaringTypeDefinition.ParentModule.PEFile;
@ -46,9 +57,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -46,9 +57,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
}
}
public bool Show(IProperty entity)
public bool Show(ISymbol symbol)
{
return entity.DeclaringType.Kind == TypeKind.Interface;
return symbol is IProperty entity && entity.DeclaringType.Kind == TypeKind.Interface;
}
}
}

21
ILSpy/Analyzers/Builtin/PropertyOverriddenByAnalyzer.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -29,12 +30,22 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -29,12 +30,22 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Shows properties that override a property.
/// </summary>
[Export(typeof(IAnalyzer<IProperty>))]
class PropertyOverriddenByAnalyzer : ITypeDefinitionAnalyzer<IProperty>
[Export(typeof(IAnalyzer))]
class PropertyOverriddenByAnalyzer : IAnalyzer
{
public string Text => "Overridden By";
public IEnumerable<IEntity> Analyze(IProperty analyzedEntity, ITypeDefinition type, AnalyzerContext context)
public IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context)
{
Debug.Assert(analyzedSymbol is IProperty);
var scope = context.GetScopeOf((IProperty)analyzedSymbol);
foreach (var type in scope.GetTypesInScope(context.CancellationToken)) {
foreach (var result in AnalyzeType((IProperty)analyzedSymbol, type))
yield return result;
}
}
IEnumerable<IEntity> AnalyzeType(IProperty analyzedEntity, ITypeDefinition type)
{
if (!analyzedEntity.DeclaringType.GetAllBaseTypeDefinitions()
.Any(t => t.MetadataToken == analyzedEntity.DeclaringTypeDefinition.MetadataToken && t.ParentModule.PEFile == type.ParentModule.PEFile))
@ -50,9 +61,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -50,9 +61,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
}
}
public bool Show(IProperty entity)
public bool Show(ISymbol entity)
{
return entity.IsOverridable && entity.DeclaringType.Kind != TypeKind.Interface;
return entity is IProperty property && property.IsOverridable && property.DeclaringType.Kind != TypeKind.Interface;
}
}
}

19
ILSpy/Analyzers/Builtin/TypeExposedByAnalyzer.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -29,14 +30,24 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -29,14 +30,24 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Finds all entities that expose a type.
/// </summary>
[Export(typeof(IAnalyzer<ITypeDefinition>))]
class TypeExposedByAnalyzer : ITypeDefinitionAnalyzer<ITypeDefinition>
[Export(typeof(IAnalyzer))]
class TypeExposedByAnalyzer : IAnalyzer
{
public string Text => "Exposed By";
public bool Show(ITypeDefinition entity) => true;
public bool Show(ISymbol entity) => entity is ITypeDefinition;
public IEnumerable<IEntity> Analyze(ITypeDefinition analyzedType, ITypeDefinition type, AnalyzerContext context)
public IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context)
{
Debug.Assert(analyzedSymbol is ITypeDefinition);
var scope = context.GetScopeOf((ITypeDefinition)analyzedSymbol);
foreach (var type in scope.GetTypesInScope(context.CancellationToken)) {
foreach (var result in ScanType((ITypeDefinition)analyzedSymbol, type, context))
yield return result;
}
}
IEnumerable<IEntity> ScanType(ITypeDefinition analyzedType, ITypeDefinition type, AnalyzerContext context)
{
if (analyzedType.Kind == TypeKind.Enum
&& type.MetadataToken == analyzedType.MetadataToken

19
ILSpy/Analyzers/Builtin/TypeExtensionMethodsAnalyzer.cs

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy.Analyzers.Builtin
@ -7,14 +8,24 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -7,14 +8,24 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Finds all extension methods defined for a type.
/// </summary>
[Export(typeof(IAnalyzer<ITypeDefinition>))]
class TypeExtensionMethodsAnalyzer : ITypeDefinitionAnalyzer<ITypeDefinition>
[Export(typeof(IAnalyzer))]
class TypeExtensionMethodsAnalyzer : IAnalyzer
{
public string Text => "Extension Methods";
public bool Show(ITypeDefinition entity) => !entity.IsStatic;
public bool Show(ISymbol symbol) => symbol is ITypeDefinition entity && !entity.IsStatic;
public IEnumerable<IEntity> Analyze(ITypeDefinition analyzedType, ITypeDefinition type, AnalyzerContext context)
public IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context)
{
Debug.Assert(analyzedSymbol is ITypeDefinition);
var scope = context.GetScopeOf((ITypeDefinition)analyzedSymbol);
foreach (var type in scope.GetTypesInScope(context.CancellationToken)) {
foreach (var result in ScanType((ITypeDefinition)analyzedSymbol, type, context))
yield return result;
}
}
IEnumerable<IEntity> ScanType(ITypeDefinition analyzedType, ITypeDefinition type, AnalyzerContext context)
{
if (!type.HasExtensionMethods)
yield break;

71
ILSpy/Analyzers/Builtin/TypeInstantiatedByAnalyzer.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
@ -33,15 +34,66 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -33,15 +34,66 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Shows methods that instantiate a type.
/// </summary>
[Export(typeof(IAnalyzer<ITypeDefinition>))]
class TypeInstantiatedByAnalyzer : IMethodBodyAnalyzer<ITypeDefinition>
[Export(typeof(IAnalyzer))]
class TypeInstantiatedByAnalyzer : IAnalyzer
{
const GetMemberOptions Options = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions;
public string Text => "Instantiated By";
public IEnumerable<IEntity> Analyze(ITypeDefinition analyzedEntity, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context)
public IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context)
{
Debug.Assert(analyzedSymbol is ITypeDefinition);
var scope = context.GetScopeOf((ITypeDefinition)analyzedSymbol);
foreach (var type in scope.GetTypesInScope(context.CancellationToken)) {
var mappingInfo = context.Language.GetCodeMappingInfo(type.ParentModule.PEFile, type.MetadataToken);
var methods = type.GetMembers(m => m is IMethod, Options).OfType<IMethod>();
foreach (var method in methods) {
if (IsUsedInMethod((ITypeDefinition)analyzedSymbol, method, mappingInfo, context))
yield return method;
}
foreach (var property in type.Properties) {
if (property.CanGet && IsUsedInMethod((ITypeDefinition)analyzedSymbol, property.Getter, mappingInfo, context)) {
yield return property;
continue;
}
if (property.CanSet && IsUsedInMethod((ITypeDefinition)analyzedSymbol, property.Setter, mappingInfo, context)) {
yield return property;
continue;
}
}
foreach (var @event in type.Events) {
if (@event.CanAdd && IsUsedInMethod((ITypeDefinition)analyzedSymbol, @event.AddAccessor, mappingInfo, context)) {
yield return @event;
continue;
}
if (@event.CanRemove && IsUsedInMethod((ITypeDefinition)analyzedSymbol, @event.RemoveAccessor, mappingInfo, context)) {
yield return @event;
continue;
}
if (@event.CanInvoke && IsUsedInMethod((ITypeDefinition)analyzedSymbol, @event.InvokeAccessor, mappingInfo, context)) {
yield return @event;
continue;
}
}
}
}
bool IsUsedInMethod(ITypeDefinition analyzedEntity, IMethod method, CodeMappingInfo mappingInfo, AnalyzerContext context)
{
var module = method.ParentModule.PEFile;
var md = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
if (!md.HasBody()) return false;
return ScanMethodBody(analyzedEntity, method, module.Reader.GetMethodBody(md.RelativeVirtualAddress));
}
bool ScanMethodBody(ITypeDefinition analyzedEntity, IMethod method, MethodBodyBlock methodBody)
{
bool found = false;
var blob = methodBody.GetILReader();
var module = (MetadataModule)method.ParentModule;
var genericContext = new Decompiler.TypeSystem.GenericContext(); // type parameters don't matter for this analyzer
while (!found && blob.RemainingBytes > 0) {
@ -53,17 +105,16 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -53,17 +105,16 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
EntityHandle methodHandle = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32());
if (!methodHandle.Kind.IsMemberKind())
continue;
var ctor = context.TypeSystem.MainModule.ResolveMethod(methodHandle, genericContext);
var ctor = module.ResolveMethod(methodHandle, genericContext);
if (ctor == null || !ctor.IsConstructor)
continue;
found = ctor.DeclaringTypeDefinition?.MetadataToken == analyzedEntity.MetadataToken
&& ctor.ParentModule.PEFile == analyzedEntity.ParentModule.PEFile;
if (ctor.DeclaringTypeDefinition?.MetadataToken == analyzedEntity.MetadataToken
&& ctor.ParentModule.PEFile == analyzedEntity.ParentModule.PEFile)
return true;
}
if (found) {
yield return method;
}
return false;
}
bool CanBeReference(ILOpCode opCode)
@ -71,6 +122,6 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -71,6 +122,6 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
return opCode == ILOpCode.Newobj || opCode == ILOpCode.Initobj;
}
public bool Show(ITypeDefinition entity) => !entity.IsAbstract && !entity.IsStatic;
public bool Show(ISymbol symbol) => symbol is ITypeDefinition entity && !entity.IsAbstract && !entity.IsStatic;
}
}

173
ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler;
@ -31,25 +32,103 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -31,25 +32,103 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
/// <summary>
/// Shows entities that use a type.
/// </summary>
[Export(typeof(IAnalyzer<ITypeDefinition>))]
class TypeUsedByAnalyzer : IMethodBodyAnalyzer<ITypeDefinition>, ITypeDefinitionAnalyzer<ITypeDefinition>
[Export(typeof(IAnalyzer))]
class TypeUsedByAnalyzer : IAnalyzer
{
public string Text => "Used By";
public IEnumerable<IEntity> Analyze(ITypeDefinition analyzedEntity, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context)
public IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context)
{
var module = context.TypeSystem.MainModule;
Debug.Assert(analyzedSymbol is ITypeDefinition);
var scope = context.GetScopeOf((ITypeDefinition)analyzedSymbol);
foreach (var type in scope.GetTypesInScope(context.CancellationToken)) {
foreach (var result in ScanType((ITypeDefinition)analyzedSymbol, type, context))
yield return result;
}
}
IEnumerable<IEntity> ScanType(ITypeDefinition analyzedEntity, ITypeDefinition type, AnalyzerContext context)
{
if (analyzedEntity.ParentModule.PEFile == type.ParentModule.PEFile
&& analyzedEntity.MetadataToken == type.MetadataToken)
yield break;
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, context, scanBodies: true);
if (visitor.Found)
yield return member;
}
}
void VisitMember(TypeDefinitionUsedVisitor visitor, IMember member, AnalyzerContext context, bool scanBodies = false)
{
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);
if (scanBodies && !visitor.Found)
ScanMethodBody(visitor, method, context.GetMethodBody(method), context);
break;
case IProperty property:
foreach (var p in property.Parameters) {
p.Type.AcceptVisitor(visitor);
}
property.ReturnType.AcceptVisitor(visitor);
if (scanBodies && !visitor.Found && property.CanGet)
ScanMethodBody(visitor, property.Getter, context.GetMethodBody(property.Getter), context);
if (scanBodies && !visitor.Found && property.CanSet)
ScanMethodBody(visitor, property.Setter, context.GetMethodBody(property.Setter), context);
break;
case IEvent @event:
@event.ReturnType.AcceptVisitor(visitor);
if (scanBodies && !visitor.Found && @event.CanAdd)
ScanMethodBody(visitor, @event.AddAccessor, context.GetMethodBody(@event.AddAccessor), context);
if (scanBodies && !visitor.Found && @event.CanRemove)
ScanMethodBody(visitor, @event.RemoveAccessor, context.GetMethodBody(@event.RemoveAccessor), context);
if (scanBodies && !visitor.Found && @event.CanInvoke)
ScanMethodBody(visitor, @event.InvokeAccessor, context.GetMethodBody(@event.InvokeAccessor), context);
break;
}
}
void ScanMethodBody(TypeDefinitionUsedVisitor visitor, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context)
{
if (methodBody == null)
return;
var module = (MetadataModule)method.ParentModule;
var genericContext = new Decompiler.TypeSystem.GenericContext(); // type parameters don't matter for this analyzer
if (!methodBody.LocalSignature.IsNil) {
foreach (var type in module.DecodeLocalSignature(methodBody.LocalSignature, genericContext)) {
type.AcceptVisitor(visitor);
if (visitor.Found) {
yield return method;
yield break;
}
if (visitor.Found) return;
}
}
@ -70,22 +149,16 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -70,22 +149,16 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
case HandleKind.TypeSpecification:
case HandleKind.TypeDefinition:
module.ResolveType(member, genericContext).AcceptVisitor(visitor);
if (visitor.Found) {
yield return method;
yield break;
}
if (visitor.Found) return;
break;
case HandleKind.FieldDefinition:
case HandleKind.MethodDefinition:
case HandleKind.MemberReference:
case HandleKind.MethodSpecification:
VisitMember(visitor, module.ResolveEntity(member, genericContext) as IMember);
VisitMember(visitor, module.ResolveEntity(member, genericContext) as IMember, context);
if (visitor.Found) {
yield return method;
yield break;
}
if (visitor.Found) return;
break;
case HandleKind.StandaloneSignature:
@ -96,10 +169,7 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -96,10 +169,7 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
signature.ReturnType.AcceptVisitor(visitor);
if (visitor.Found) {
yield return method;
yield break;
}
if (visitor.Found) return;
break;
default:
@ -113,80 +183,29 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -113,80 +183,29 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
}
}
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)
{
if (analyzedEntity.ParentModule.PEFile == type.ParentModule.PEFile
&& analyzedEntity.MetadataToken == type.MetadataToken)
yield break;
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;
public bool Show(ISymbol symbol) => symbol is ITypeDefinition entity && !entity.IsAbstract && !entity.IsStatic;
}
class TypeDefinitionUsedVisitor : TypeVisitor
{
readonly ITypeDefinition typeDefinition;
public readonly ITypeDefinition TypeDefinition;
public bool Found { get; set; }
public TypeDefinitionUsedVisitor(ITypeDefinition definition)
{
this.typeDefinition = definition;
this.TypeDefinition = definition;
}
public override IType VisitTypeDefinition(ITypeDefinition type)
{
Found |= typeDefinition.MetadataToken == type.MetadataToken
&& typeDefinition.ParentModule.PEFile == type.ParentModule.PEFile;
Found |= TypeDefinition.MetadataToken == type.MetadataToken
&& TypeDefinition.ParentModule.PEFile == type.ParentModule.PEFile;
return base.VisitTypeDefinition(type);
}
}

83
ILSpy/Analyzers/IAnalyzer.cs

@ -21,16 +21,17 @@ using System.Collections.Generic; @@ -21,16 +21,17 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy.Analyzers
{
/// <summary>
/// This is the common interface for all analyzers. Note: implementing this interface alone will not provide a full analyzer.
/// You must implement either the <see cref="ITypeDefinitionAnalyzer{T}"/>, <see cref="IEntityAnalyzer{T}"/> or <see cref="IMethodBodyAnalyzer{T}"/> interfaces.
/// Base interface for all analyzers. You can register an analyzer for any <see cref="ISymbol"/> by implementing
/// this interface and adding an appropriate <see cref="System.ComponentModel.Composition.ExportAttribute"/>.
/// </summary>
public interface IAnalyzer<T> where T : IEntity
public interface IAnalyzer
{
/// <summary>
/// The caption used in the analyzer tree view.
@ -38,53 +39,14 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -38,53 +39,14 @@ namespace ICSharpCode.ILSpy.Analyzers
string Text { get; }
/// <summary>
/// Returns true, if the analyzer should be shown for an entity, otherwise false.
/// Returns true, if the analyzer should be shown for a symbol, otherwise false.
/// </summary>
bool Show(T entity);
}
/// <summary>
/// This interface can be used to implement an analyzer that runs on a single entity.
/// For an example see <see cref="Builtin.MethodUsesAnalyzer"/>.
/// </summary>
/// <typeparam name="T">The type of enitities to be analyzed.</typeparam>
public interface IEntityAnalyzer<T> : IAnalyzer<T> where T : IEntity
{
/// <summary>
/// Returns all entities that the analyzer found in the given entity.
/// </summary>
IEnumerable<IEntity> Analyze(T analyzedEntity, AnalyzerContext context);
}
bool Show(ISymbol symbol);
/// <summary>
/// This interface can be used to implement an analyzer that runs on multiple types.
/// </summary>
/// <typeparam name="T">The type of enitities to be analyzed.</typeparam>
public interface ITypeDefinitionAnalyzer<T> : IAnalyzer<T> where T : IEntity
{
/// <summary>
/// Returns all entities that the analyzer found in the given entity.
/// </summary>
/// <param name="analyzedEntity">The entity, which we are looking for.</param>
/// <param name="type">The type definition, we currently analyze.</param>
/// <param name="context">Context providing additional information.</param>
IEnumerable<IEntity> Analyze(T analyzedEntity, ITypeDefinition type, AnalyzerContext context);
}
/// <summary>
/// This interface can be used to implement an analyzer that runs on method bodies.
/// </summary>
/// <typeparam name="T">The type of enitities to be analyzed.</typeparam>
public interface IMethodBodyAnalyzer<T> : IAnalyzer<T> where T : IEntity
{
/// <summary>
/// Returns all entities that the analyzer found in the given method body.
/// Returns all symbols found by this analyzer.
/// </summary>
/// <param name="analyzedEntity">The entity, which we are looking for.</param>
/// <param name="method">The method we analyze.</param>
/// <param name="methodBody">The method body.</param>
/// <param name="context">Context providing additional information.</param>
IEnumerable<IEntity> Analyze(T analyzedEntity, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context);
IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context);
}
/// <summary>
@ -92,29 +54,30 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -92,29 +54,30 @@ namespace ICSharpCode.ILSpy.Analyzers
/// </summary>
public class AnalyzerContext
{
public AnalyzerContext(IDecompilerTypeSystem typeSystem)
{
this.TypeSystem = typeSystem;
}
/// <summary>
/// A type system where all entities of the current assembly and its references can be found.
/// </summary>
public IDecompilerTypeSystem TypeSystem { get; }
public AssemblyList AssemblyList { get; internal set; }
/// <summary>
/// CancellationToken. Currently Analyzers do not support cancellation from the UI, but it should be checked nonetheless.
/// </summary>
public CancellationToken CancellationToken { get; internal set; }
/// <summary>
/// Mapping info to find parts of a method.
/// </summary>
public CodeMappingInfo CodeMappingInfo { get; internal set; }
/// <summary>
/// Currently used language.
/// </summary>
public Language Language { get; internal set; }
public MethodBodyBlock GetMethodBody(IMethod method)
{
if (!method.HasBody || method.MetadataToken.IsNil)
return null;
var module = method.ParentModule.PEFile;
var md = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
return module.Reader.GetMethodBody(md.RelativeVirtualAddress);
}
public AnalyzerScope GetScopeOf(IEntity entity)
{
return new AnalyzerScope(AssemblyList, entity);
}
}
}

269
ILSpy/Analyzers/ScopedWhereUsedAnalyzer.cs

@ -1,269 +0,0 @@ @@ -1,269 +0,0 @@
// 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.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.ILSpy.Analyzers
{
/// <summary>
/// Determines the accessibility domain of a member for where-used analysis.
/// </summary>
class ScopedWhereUsedAnalyzer<T> where T : IEntity
{
readonly Language language;
readonly IAnalyzer<T> analyzer;
readonly IModule assemblyScope;
readonly T analyzedEntity;
ITypeDefinition typeScope;
readonly Accessibility memberAccessibility = Accessibility.Public;
Accessibility typeAccessibility = Accessibility.Public;
public ScopedWhereUsedAnalyzer(Language language, T analyzedEntity, IAnalyzer<T> analyzer)
{
this.language = language ?? throw new ArgumentNullException(nameof(language));
this.analyzer = analyzer ?? throw new ArgumentNullException(nameof(analyzer));
this.analyzedEntity = analyzedEntity;
this.assemblyScope = analyzedEntity.ParentModule;
if (analyzedEntity is ITypeDefinition type) {
this.typeScope = type;
this.typeAccessibility = type.Accessibility;
} else {
this.typeScope = analyzedEntity.DeclaringTypeDefinition;
this.typeAccessibility = this.typeScope.Accessibility;
this.memberAccessibility = analyzedEntity.Accessibility;
}
}
public IEnumerable<IEntity> PerformAnalysis(CancellationToken ct)
{
if (memberAccessibility == Accessibility.Private) {
return FindReferencesInTypeScope(ct);
}
DetermineTypeAccessibility();
if (typeAccessibility == Accessibility.Private && typeScope.DeclaringType != null) {
return FindReferencesInEnclosingTypeScope(ct);
}
if (memberAccessibility == Accessibility.Internal ||
memberAccessibility == Accessibility.ProtectedOrInternal ||
typeAccessibility == Accessibility.Internal ||
typeAccessibility == Accessibility.ProtectedAndInternal)
return FindReferencesInAssemblyAndFriends(ct);
return FindReferencesGlobal(ct);
}
void DetermineTypeAccessibility()
{
while (typeScope.DeclaringType != null) {
Accessibility accessibility = typeScope.Accessibility;
if ((int)typeAccessibility > (int)accessibility) {
typeAccessibility = accessibility;
if (typeAccessibility == Accessibility.Private)
return;
}
typeScope = typeScope.DeclaringTypeDefinition;
}
if ((int)typeAccessibility > (int)Accessibility.Internal) {
typeAccessibility = Accessibility.Internal;
}
}
IEnumerable<IEntity> FindReferencesInAssemblyAndFriends(CancellationToken ct)
{
var assemblies = GetAssemblyAndAnyFriends(assemblyScope.PEFile, ct);
return assemblies.AsParallel().WithCancellation(ct).SelectMany(a => FindReferencesInAssembly(a, ct));
}
IEnumerable<IEntity> FindReferencesGlobal(CancellationToken ct)
{
var assemblies = GetReferencingAssemblies(assemblyScope.PEFile, ct);
return assemblies.AsParallel().WithCancellation(ct).SelectMany(asm => FindReferencesInAssembly(asm, ct));
}
IEnumerable<IEntity> FindReferencesInAssembly(PEFile module, CancellationToken ct)
{
var ts = new DecompilerTypeSystem(module, module.GetAssemblyResolver());
var context = new AnalyzerContext(ts) { CancellationToken = ct, Language = language };
foreach (var type in ts.MainModule.TypeDefinitions) {
ct.ThrowIfCancellationRequested();
if (type.MetadataToken.IsNil) continue;
context.CodeMappingInfo = language.GetCodeMappingInfo(module, type.MetadataToken);
foreach (var result in RunAnalysisOn(module, type, context)) {
ct.ThrowIfCancellationRequested();
yield return result;
}
}
}
IEnumerable<IEntity> FindReferencesInTypeScope(CancellationToken ct)
{
var ts = new DecompilerTypeSystem(assemblyScope.PEFile, assemblyScope.PEFile.GetAssemblyResolver());
var context = new AnalyzerContext(ts) { CancellationToken = ct, Language = language };
var types = TreeTraversal.PreOrder(typeScope,
t => t.GetNestedTypes(options: GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions)
.Select(td => td.GetDefinition()));
foreach (var type in types) {
ct.ThrowIfCancellationRequested();
if (type.MetadataToken.IsNil) continue;
context.CodeMappingInfo = language.GetCodeMappingInfo(assemblyScope.PEFile, type.MetadataToken);
foreach (var result in RunAnalysisOn(assemblyScope.PEFile, type, context)) {
ct.ThrowIfCancellationRequested();
yield return result;
}
}
}
IEnumerable<IEntity> FindReferencesInEnclosingTypeScope(CancellationToken ct)
{
var ts = new DecompilerTypeSystem(assemblyScope.PEFile, assemblyScope.PEFile.GetAssemblyResolver());
var context = new AnalyzerContext(ts) { CancellationToken = ct, Language = language };
var types = TreeTraversal.PreOrder(typeScope.DeclaringTypeDefinition,
t => t.GetNestedTypes(options: GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions)
.Select(td => td.GetDefinition()));
foreach (var type in types) {
ct.ThrowIfCancellationRequested();
if (type.MetadataToken.IsNil) continue;
context.CodeMappingInfo = language.GetCodeMappingInfo(assemblyScope.PEFile, type.MetadataToken);
foreach (var result in RunAnalysisOn(assemblyScope.PEFile, type, context)) {
ct.ThrowIfCancellationRequested();
yield return result;
}
}
}
IEnumerable<PEFile> GetReferencingAssemblies(PEFile asm, CancellationToken ct)
{
yield return asm;
IEnumerable<LoadedAssembly> assemblies = MainWindow.Instance.CurrentAssemblyList.GetAssemblies();
foreach (var assembly in assemblies) {
ct.ThrowIfCancellationRequested();
bool found = false;
var module = assembly.GetPEFileOrNull();
if (module == null || !module.IsAssembly)
continue;
var resolver = assembly.GetAssemblyResolver();
foreach (var reference in module.AssemblyReferences) {
using (LoadedAssembly.DisableAssemblyLoad()) {
if (resolver.Resolve(reference) == asm) {
found = true;
break;
}
}
}
if (found && AssemblyReferencesScopeType(module.Metadata, typeScope.Name, typeScope.Namespace))
yield return module;
}
}
IEnumerable<PEFile> GetAssemblyAndAnyFriends(PEFile asm, CancellationToken ct)
{
yield return asm;
var typeProvider = MetadataExtensions.MinimalAttributeTypeProvider;
var attributes = asm.Metadata.CustomAttributes.Select(h => asm.Metadata.GetCustomAttribute(h))
.Where(ca => ca.GetAttributeType(asm.Metadata).GetFullTypeName(asm.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;
assemblyName = assemblyName.Split(',')[0]; // strip off any public key info
friendAssemblies.Add(assemblyName);
}
if (friendAssemblies.Count > 0) {
IEnumerable<LoadedAssembly> assemblies = MainWindow.Instance.CurrentAssemblyList.GetAssemblies();
foreach (var assembly in assemblies) {
ct.ThrowIfCancellationRequested();
if (friendAssemblies.Contains(assembly.ShortName)) {
var module = assembly.GetPEFileOrNull();
if (module == null)
continue;
if (AssemblyReferencesScopeType(module.Metadata, typeScope.Name, typeScope.Namespace))
yield return module;
}
}
}
}
bool AssemblyReferencesScopeType(MetadataReader metadata, string typeScopeName, string typeScopeNamespace)
{
bool hasRef = false;
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;
}
}
return hasRef;
}
IEnumerable<IEntity> RunAnalysisOn(PEFile module, ITypeDefinition type, AnalyzerContext context)
{
if (analyzer is IMethodBodyAnalyzer<T> methodAnalyzer) {
var reader = module.Reader;
foreach (var method in type.GetMethods(options: GetMemberOptions.IgnoreInheritedMembers)) {
if (!method.HasBody || method.MetadataToken.IsNil) continue;
var md = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
var body = reader.GetMethodBody(md.RelativeVirtualAddress);
foreach (var result in methodAnalyzer.Analyze(analyzedEntity, method, body, context))
yield return GetParentEntity(context, result);
}
foreach (var method in type.GetAccessors(options: GetMemberOptions.IgnoreInheritedMembers)) {
if (!method.HasBody || method.MetadataToken.IsNil) continue;
var md = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
var body = reader.GetMethodBody(md.RelativeVirtualAddress);
foreach (var result in methodAnalyzer.Analyze(analyzedEntity, method, body, context))
yield return GetParentEntity(context, result);
}
}
if (analyzer is ITypeDefinitionAnalyzer<T> typeDefinitionAnalyzer) {
foreach (var result in typeDefinitionAnalyzer.Analyze(analyzedEntity, type, context))
yield return GetParentEntity(context, result);
}
}
private IEntity GetParentEntity(AnalyzerContext context, IEntity entity)
{
if (entity.MetadataToken.Kind == HandleKind.MethodDefinition && !entity.MetadataToken.IsNil) {
var parentHandle = context.CodeMappingInfo.GetParentMethod((MethodDefinitionHandle)entity.MetadataToken);
if (entity.MetadataToken == parentHandle)
return entity;
var method = context.TypeSystem.MainModule.ResolveMethod(parentHandle, new Decompiler.TypeSystem.GenericContext());
if (method != null) {
return method.AccessorOwner ?? method;
}
}
return entity;
}
}
}

4
ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs

@ -54,10 +54,10 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes @@ -54,10 +54,10 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
//foreach (var accessor in analyzedEvent.OtherMethods)
// this.Children.Add(new AnalyzedAccessorTreeNode(accessor, null));
foreach (var lazy in App.ExportProvider.GetExports<IAnalyzer<IEvent>>()) {
foreach (var lazy in App.ExportProvider.GetExports<IAnalyzer>()) {
var analyzer = lazy.Value;
if (analyzer.Show(analyzedEvent)) {
this.Children.Add(new AnalyzerSearchTreeNode<IEvent>(analyzedEvent, analyzer));
this.Children.Add(new AnalyzerSearchTreeNode(analyzedEvent, analyzer));
}
}
}

4
ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs

@ -38,10 +38,10 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes @@ -38,10 +38,10 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
protected override void LoadChildren()
{
foreach (var lazy in App.ExportProvider.GetExports<IAnalyzer<IField>>()) {
foreach (var lazy in App.ExportProvider.GetExports<IAnalyzer>()) {
var analyzer = lazy.Value;
if (analyzer.Show(analyzedField)) {
this.Children.Add(new AnalyzerSearchTreeNode<IField>(analyzedField, analyzer));
this.Children.Add(new AnalyzerSearchTreeNode(analyzedField, analyzer));
}
}
}

4
ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs

@ -40,10 +40,10 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes @@ -40,10 +40,10 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
protected override void LoadChildren()
{
foreach (var lazy in App.ExportProvider.GetExports<IAnalyzer<IMethod>>()) {
foreach (var lazy in App.ExportProvider.GetExports<IAnalyzer>()) {
var analyzer = lazy.Value;
if (analyzer.Show(analyzedMethod)) {
this.Children.Add(new AnalyzerSearchTreeNode<IMethod>(analyzedMethod, analyzer));
this.Children.Add(new AnalyzerSearchTreeNode(analyzedMethod, analyzer));
}
}
}

4
ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs

@ -48,10 +48,10 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes @@ -48,10 +48,10 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
//foreach (var accessor in analyzedProperty.OtherMethods)
// this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null));
foreach (var lazy in App.ExportProvider.GetExports<IAnalyzer<IProperty>>()) {
foreach (var lazy in App.ExportProvider.GetExports<IAnalyzer>()) {
var analyzer = lazy.Value;
if (analyzer.Show(analyzedProperty)) {
this.Children.Add(new AnalyzerSearchTreeNode<IProperty>(analyzedProperty, analyzer));
this.Children.Add(new AnalyzerSearchTreeNode(analyzedProperty, analyzer));
}
}
}

4
ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs

@ -38,10 +38,10 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes @@ -38,10 +38,10 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
protected override void LoadChildren()
{
foreach (var lazy in App.ExportProvider.GetExports<IAnalyzer<ITypeDefinition>>()) {
foreach (var lazy in App.ExportProvider.GetExports<IAnalyzer>()) {
var analyzer = lazy.Value;
if (analyzer.Show(analyzedType)) {
this.Children.Add(new AnalyzerSearchTreeNode<ITypeDefinition>(analyzedType, analyzer));
this.Children.Add(new AnalyzerSearchTreeNode(analyzedType, analyzer));
}
}
}

2
ILSpy/ILSpy.csproj

@ -66,6 +66,7 @@ @@ -66,6 +66,7 @@
<ItemGroup>
<Compile Include="AboutPage.cs" />
<Compile Include="Analyzers\AnalyzerScope.cs" />
<Compile Include="Analyzers\Builtin\EventImplementsInterfaceAnalyzer.cs" />
<Compile Include="Analyzers\Builtin\EventOverriddenByAnalyzer.cs" />
<Compile Include="Analyzers\Builtin\MethodImplementsInterfaceAnalyzer.cs" />
@ -216,7 +217,6 @@ @@ -216,7 +217,6 @@
<Compile Include="Analyzers\AnalyzerSearchTreeNode.cs" />
<Compile Include="Analyzers\AnalyzerTreeNode.cs" />
<Compile Include="Analyzers\RemoveAnalyzeContextMenuEntry.cs" />
<Compile Include="Analyzers\ScopedWhereUsedAnalyzer.cs" />
<Compile Include="TreeNodes\BaseTypesEntryNode.cs" />
<Compile Include="TreeNodes\CopyFullyQualifiedNameContextMenuEntry.cs" />
<Compile Include="TreeNodes\DerivedTypesEntryNode.cs" />

Loading…
Cancel
Save