
16 changed files with 0 additions and 2023 deletions
-
4ILSpy/ILSpy.csproj
-
372ILSpy/TreeNodes/Analyzer/AnalyzedAttributeAppliedToTreeNode.cs
-
132ILSpy/TreeNodes/Analyzer/AnalyzedEventFiredByTreeNode.cs
-
74ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs
-
88ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceEventImplementedByTreeNode.cs
-
83ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs
-
86ILSpy/TreeNodes/Analyzer/AnalyzedInterfacePropertyImplementedByTreeNode.cs
-
86ILSpy/TreeNodes/Analyzer/AnalyzedMethodOverridesTreeNode.cs
-
118ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs
-
119ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs
-
74ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs
-
173ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs
-
84ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs
-
152ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs
-
239ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs
-
139ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs
@ -1,372 +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.Threading; |
|||
using System.Collections.Concurrent; |
|||
using ICSharpCode.Decompiler.Util; |
|||
using ICSharpCode.Decompiler.Dom; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
internal sealed class AnalyzedAttributeAppliedToTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
private readonly TypeDefinition analyzedType; |
|||
private readonly string attributeName; |
|||
|
|||
private AttributeTargets usage = AttributeTargets.All; |
|||
private bool allowMutiple; |
|||
private bool inherited = true; |
|||
private ConcurrentDictionary<MethodDefinition, int> foundMethods; |
|||
|
|||
public static bool CanShow(TypeDefinition type) |
|||
{ |
|||
return type.IsClass && type.IsCustomAttribute(); |
|||
} |
|||
|
|||
public AnalyzedAttributeAppliedToTreeNode(TypeDefinition analyzedType) |
|||
{ |
|||
if (analyzedType.IsNil) |
|||
throw new ArgumentNullException(nameof(analyzedType)); |
|||
|
|||
this.analyzedType = analyzedType; |
|||
attributeName = this.analyzedType.FullName; |
|||
GetAttributeUsage(); |
|||
} |
|||
|
|||
private void GetAttributeUsage() |
|||
{ |
|||
if (analyzedType.HasCustomAttributes) { |
|||
foreach (CustomAttribute ca in analyzedType.CustomAttributes) { |
|||
TypeReference t = ca.AttributeType; |
|||
if (t.Name == "AttributeUsageAttribute" && t.Namespace == "System") { |
|||
this.usage = (AttributeTargets)ca.ConstructorArguments[0].Value; |
|||
if (ca.ConstructorArguments.Count > 1) { |
|||
this.allowMutiple = (bool)ca.ConstructorArguments[1].Value; |
|||
this.inherited = (bool)ca.ConstructorArguments[2].Value; |
|||
} |
|||
if (ca.HasProperties) { |
|||
foreach (var namedArgument in ca.Properties) { |
|||
switch (namedArgument.Name) { |
|||
case "AllowMultiple": |
|||
this.allowMutiple = (bool)namedArgument.Argument.Value; |
|||
break; |
|||
case "Inherited": |
|||
this.inherited = (bool)namedArgument.Argument.Value; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override object Text |
|||
{ |
|||
get { return "Applied To"; } |
|||
} |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
foundMethods = new ConcurrentDictionary<MethodDefinition, int>(); |
|||
|
|||
//get the assemblies to search
|
|||
var currentAssembly = analyzedType.Module.Assembly; |
|||
var assemblies = analyzedType.IsPublic ? GetReferencingAssemblies(currentAssembly, ct) : GetAssemblyAndAnyFriends(currentAssembly, ct); |
|||
|
|||
var results = assemblies.AsParallel().WithCancellation(ct).SelectMany(a => FindReferencesInAssembly(a.Item1.MainModule, a.Item2, ct)); |
|||
|
|||
foreach (var result in results.OrderBy(n => n.Text)) { |
|||
yield return result; |
|||
} |
|||
|
|||
foundMethods = null; |
|||
} |
|||
|
|||
#region standard custom attributes
|
|||
|
|||
private IEnumerable<AnalyzerTreeNode> FindReferencesInAssembly(PEFile module, TypeReference tr, CancellationToken ct) |
|||
{ |
|||
//since we do not display modules as separate entities, coalesce the assembly and module searches
|
|||
bool foundInAssyOrModule = false; |
|||
|
|||
if ((usage & AttributeTargets.Assembly) != 0) { |
|||
AssemblyDefinition asm = module.Assembly; |
|||
if (asm != null && asm.HasCustomAttributes) { |
|||
foreach (var attribute in asm.CustomAttributes) { |
|||
if (attribute.AttributeType == tr) { |
|||
foundInAssyOrModule = true; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (!foundInAssyOrModule) { |
|||
ct.ThrowIfCancellationRequested(); |
|||
|
|||
//search module
|
|||
if ((usage & AttributeTargets.Module) != 0) { |
|||
if (module.HasCustomAttributes) { |
|||
foreach (var attribute in module.CustomAttributes) { |
|||
if (attribute.AttributeType == tr) { |
|||
foundInAssyOrModule = true; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
if (foundInAssyOrModule) { |
|||
yield return new AnalyzedAssemblyTreeNode(module); |
|||
} |
|||
|
|||
ct.ThrowIfCancellationRequested(); |
|||
|
|||
foreach (TypeDefinition type in TreeTraversal.PreOrder(module.Types, t => t.NestedTypes).OrderBy(t => t.FullName)) { |
|||
ct.ThrowIfCancellationRequested(); |
|||
foreach (var result in FindReferencesWithinInType(type, tr)) { |
|||
ct.ThrowIfCancellationRequested(); |
|||
yield return result; |
|||
} |
|||
} |
|||
} |
|||
|
|||
private IEnumerable<AnalyzerTreeNode> FindReferencesWithinInType(TypeDefinition type, TypeReference attrTypeRef) |
|||
{ |
|||
|
|||
bool searchRequired = (type.IsClass && usage.HasFlag(AttributeTargets.Class)) |
|||
|| (type.IsEnum && usage.HasFlag(AttributeTargets.Enum)) |
|||
|| (type.IsInterface && usage.HasFlag(AttributeTargets.Interface)) |
|||
|| (type.IsValueType && usage.HasFlag(AttributeTargets.Struct)); |
|||
if (searchRequired) { |
|||
if (type.HasCustomAttributes) { |
|||
foreach (var attribute in type.CustomAttributes) { |
|||
if (attribute.AttributeType == attrTypeRef) { |
|||
var node = new AnalyzedTypeTreeNode(type); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if ((this.usage & AttributeTargets.GenericParameter) != 0 && type.HasGenericParameters) { |
|||
foreach (var parameter in type.GenericParameters) { |
|||
if (parameter.HasCustomAttributes) { |
|||
foreach (var attribute in parameter.CustomAttributes) { |
|||
if (attribute.AttributeType == attrTypeRef) { |
|||
var node = new AnalyzedTypeTreeNode(type); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if ((this.usage & AttributeTargets.Field) != 0 && type.HasFields) { |
|||
foreach (var field in type.Fields) { |
|||
if (field.HasCustomAttributes) { |
|||
foreach (var attribute in field.CustomAttributes) { |
|||
if (attribute.AttributeType == attrTypeRef) { |
|||
var node = new AnalyzedFieldTreeNode(field); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (((usage & AttributeTargets.Property) != 0) && type.HasProperties) { |
|||
foreach (var property in type.Properties) { |
|||
if (property.HasCustomAttributes) { |
|||
foreach (var attribute in property.CustomAttributes) { |
|||
if (attribute.AttributeType == attrTypeRef) { |
|||
var node = new AnalyzedPropertyTreeNode(property); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
if (((usage & AttributeTargets.Event) != 0) && type.HasEvents) { |
|||
foreach (var _event in type.Events) { |
|||
if (_event.HasCustomAttributes) { |
|||
foreach (var attribute in _event.CustomAttributes) { |
|||
if (attribute.AttributeType == attrTypeRef) { |
|||
var node = new AnalyzedEventTreeNode(_event); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (type.HasMethods) { |
|||
foreach (var method in type.Methods) { |
|||
bool found = false; |
|||
if ((usage & (AttributeTargets.Method | AttributeTargets.Constructor)) != 0) { |
|||
if (method.HasCustomAttributes) { |
|||
foreach (var attribute in method.CustomAttributes) { |
|||
if (attribute.AttributeType == attrTypeRef) { |
|||
found = true; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
if (!found && |
|||
((usage & AttributeTargets.ReturnValue) != 0) && |
|||
method.MethodReturnType.HasCustomAttributes) { |
|||
foreach (var attribute in method.MethodReturnType.CustomAttributes) { |
|||
if (attribute.AttributeType == attrTypeRef) { |
|||
found = true; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (!found && |
|||
((usage & AttributeTargets.Parameter) != 0) && |
|||
method.HasParameters) { |
|||
foreach (var parameter in method.Parameters) { |
|||
foreach (var attribute in parameter.CustomAttributes) { |
|||
if (attribute.AttributeType == attrTypeRef) { |
|||
found = true; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (found) { |
|||
MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition; |
|||
if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) { |
|||
var node = new AnalyzedMethodTreeNode(codeLocation); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
private bool HasAlreadyBeenFound(MethodDefinition method) |
|||
{ |
|||
return !foundMethods.TryAdd(method, 0); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region search scope
|
|||
|
|||
private IEnumerable<Tuple<AssemblyDefinition, TypeReference>> GetReferencingAssemblies(AssemblyDefinition asm, CancellationToken ct) |
|||
{ |
|||
yield return new Tuple<AssemblyDefinition, TypeReference>(asm, this.analyzedType); |
|||
|
|||
string requiredAssemblyFullName = asm.FullName; |
|||
|
|||
IEnumerable<LoadedAssembly> assemblies = MainWindow.Instance.CurrentAssemblyList.GetAssemblies().Where(assy => assy.GetAssemblyDefinitionOrNull() != null); |
|||
|
|||
foreach (var assembly in assemblies) { |
|||
ct.ThrowIfCancellationRequested(); |
|||
bool found = false; |
|||
var module = assembly.GetModuleDefinitionOrNull(); |
|||
if (module == null) |
|||
continue; |
|||
foreach (var reference in module.AssemblyReferences) { |
|||
if (requiredAssemblyFullName == reference.FullName) { |
|||
found = true; |
|||
break; |
|||
} |
|||
} |
|||
if (found) { |
|||
var typeref = GetScopeTypeReferenceInAssembly(module.Assembly); |
|||
if (typeref != null) |
|||
yield return new Tuple<AssemblyDefinition, TypeReference>(module.Assembly, typeref); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private IEnumerable<Tuple<AssemblyDefinition, TypeReference>> GetAssemblyAndAnyFriends(AssemblyDefinition asm, CancellationToken ct) |
|||
{ |
|||
yield return new Tuple<AssemblyDefinition, TypeReference>(asm, analyzedType); |
|||
|
|||
if (asm.HasCustomAttributes) { |
|||
var attributes = asm.CustomAttributes |
|||
.Where(attr => attr.AttributeType.FullName == "System.Runtime.CompilerServices.InternalsVisibleToAttribute"); |
|||
var friendAssemblies = new HashSet<string>(); |
|||
foreach (var attribute in attributes) { |
|||
string assemblyName = attribute.ConstructorArguments[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(); |
|||
var module = assembly.GetModuleDefinitionOrNull(); |
|||
if (module == null) |
|||
continue; |
|||
if (friendAssemblies.Contains(assembly.ShortName)) { |
|||
var typeref = GetScopeTypeReferenceInAssembly(module.Assembly); |
|||
if (typeref != null) { |
|||
yield return new Tuple<AssemblyDefinition, TypeReference>(module.Assembly, typeref); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
private TypeReference GetScopeTypeReferenceInAssembly(AssemblyDefinition asm) |
|||
{ |
|||
foreach (var typeref in asm.MainModule.GetTypeReferences()) { |
|||
if (typeref.Name == analyzedType.Name && typeref.Namespace == analyzedType.Namespace) { |
|||
return typeref; |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
internal static class ExtensionMethods |
|||
{ |
|||
public static bool HasCustomAttribute(this MemberReference member, string attributeTypeName) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
} |
@ -1,132 +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.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using Mono.Cecil; |
|||
using Mono.Cecil.Cil; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
internal sealed class AnalyzedEventFiredByTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
private readonly EventDefinition analyzedEvent; |
|||
private readonly FieldDefinition eventBackingField; |
|||
private readonly MethodDefinition eventFiringMethod; |
|||
|
|||
private ConcurrentDictionary<MethodDefinition, int> foundMethods; |
|||
|
|||
public AnalyzedEventFiredByTreeNode(EventDefinition analyzedEvent) |
|||
{ |
|||
if (analyzedEvent == null) |
|||
throw new ArgumentNullException(nameof(analyzedEvent)); |
|||
|
|||
this.analyzedEvent = analyzedEvent; |
|||
|
|||
this.eventBackingField = GetBackingField(analyzedEvent); |
|||
this.eventFiringMethod = analyzedEvent.EventType.Resolve().Methods.First(md => md.Name == "Invoke"); |
|||
} |
|||
|
|||
public override object Text |
|||
{ |
|||
get { return "Raised By"; } |
|||
} |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
foundMethods = new ConcurrentDictionary<MethodDefinition, int>(); |
|||
|
|||
foreach (var child in FindReferencesInType(analyzedEvent.DeclaringType).OrderBy(n => n.Text)) { |
|||
yield return child; |
|||
} |
|||
|
|||
foundMethods = null; |
|||
} |
|||
|
|||
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(TypeDefinition type) |
|||
{ |
|||
// HACK: in lieu of proper flow analysis, I'm going to use a simple heuristic
|
|||
// If the method accesses the event's backing field, and calls invoke on a delegate
|
|||
// with the same signature, then it is (most likely) raise the given event.
|
|||
|
|||
foreach (MethodDefinition method in type.Methods) { |
|||
bool readBackingField = false; |
|||
bool found = false; |
|||
if (!method.HasBody) |
|||
continue; |
|||
foreach (Instruction instr in method.Body.Instructions) { |
|||
Code code = instr.OpCode.Code; |
|||
if (code == Code.Ldfld || code == Code.Ldflda) { |
|||
FieldReference fr = instr.Operand as FieldReference; |
|||
if (fr != null && fr.Name == eventBackingField.Name && fr == eventBackingField) { |
|||
readBackingField = true; |
|||
} |
|||
} |
|||
if (readBackingField && (code == Code.Callvirt || code == Code.Call)) { |
|||
MethodReference mr = instr.Operand as MethodReference; |
|||
if (mr != null && mr.Name == eventFiringMethod.Name && mr.Resolve() == eventFiringMethod) { |
|||
found = true; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
method.Body = null; |
|||
|
|||
if (found) { |
|||
MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition; |
|||
if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) { |
|||
var node = new AnalyzedMethodTreeNode(codeLocation); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
private bool HasAlreadyBeenFound(MethodDefinition method) |
|||
{ |
|||
return !foundMethods.TryAdd(method, 0); |
|||
} |
|||
|
|||
// HACK: we should probably examine add/remove methods to determine this
|
|||
private static FieldDefinition GetBackingField(EventDefinition ev) |
|||
{ |
|||
var fieldName = ev.Name; |
|||
var vbStyleFieldName = fieldName + "Event"; |
|||
var fieldType = ev.EventType; |
|||
|
|||
foreach (var fd in ev.DeclaringType.Fields) { |
|||
if (fd.Name == fieldName || fd.Name == vbStyleFieldName) |
|||
if (fd.FieldType.FullName == fieldType.FullName) |
|||
return fd; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
|
|||
public static bool CanShow(EventDefinition ev) |
|||
{ |
|||
return GetBackingField(ev) != null; |
|||
} |
|||
} |
|||
} |
@ -1,74 +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; |
|||
using System.Threading; |
|||
using ICSharpCode.Decompiler.Disassembler; |
|||
using ICSharpCode.Decompiler.Dom; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
internal sealed class AnalyzedEventOverridesTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
private readonly EventDefinition analyzedEvent; |
|||
|
|||
public AnalyzedEventOverridesTreeNode(EventDefinition analyzedEvent) |
|||
{ |
|||
if (analyzedEvent.IsNil) |
|||
throw new ArgumentNullException(nameof(analyzedEvent)); |
|||
|
|||
this.analyzedEvent = analyzedEvent; |
|||
} |
|||
|
|||
public override object Text |
|||
{ |
|||
get { return "Overridden By"; } |
|||
} |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedEvent, FindReferencesInType); |
|||
return analyzer.PerformAnalysis(ct).OrderBy(n => n.Text); |
|||
} |
|||
|
|||
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(TypeDefinition type) |
|||
{ |
|||
if (!analyzedEvent.DeclaringType.IsBaseTypeOf(type)) |
|||
yield break; |
|||
|
|||
foreach (EventDefinition eventDef in type.Events) { |
|||
if (TypesHierarchyHelpers.IsBaseEvent(analyzedEvent, eventDef)) { |
|||
MethodDefinition anyAccessor = eventDef.AddMethod ?? eventDef.RemoveMethod; |
|||
bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot; |
|||
var node = new AnalyzedEventTreeNode(eventDef, hidesParent ? "(hides) " : ""); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public static bool CanShow(EventDefinition property) |
|||
{ |
|||
var accessor = property.GetAccessors().First().Method; |
|||
return accessor.HasFlag(MethodAttributes.Virtual) && !accessor.HasFlag(MethodAttributes.Final) && !accessor.DeclaringType.IsInterface; |
|||
} |
|||
} |
|||
} |
@ -1,88 +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.Threading; |
|||
using ICSharpCode.Decompiler.TypeSystem; |
|||
using Mono.Cecil; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
internal sealed class AnalyzedInterfaceEventImplementedByTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
private readonly EventDefinition analyzedEvent; |
|||
private readonly MethodDefinition analyzedMethod; |
|||
|
|||
public AnalyzedInterfaceEventImplementedByTreeNode(EventDefinition analyzedEvent) |
|||
{ |
|||
if (analyzedEvent == null) |
|||
throw new ArgumentNullException(nameof(analyzedEvent)); |
|||
|
|||
this.analyzedEvent = analyzedEvent; |
|||
this.analyzedMethod = this.analyzedEvent.AddMethod ?? this.analyzedEvent.RemoveMethod; |
|||
} |
|||
|
|||
public override object Text |
|||
{ |
|||
get { return "Implemented By"; } |
|||
} |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedMethod, FindReferencesInType); |
|||
foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { |
|||
yield return child; |
|||
} |
|||
} |
|||
|
|||
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(TypeDefinition type) |
|||
{ |
|||
if (!type.HasInterfaces) |
|||
yield break; |
|||
TypeReference implementedInterfaceRef = type.Interfaces.FirstOrDefault(i => i.InterfaceType.Resolve() == analyzedMethod.DeclaringType)?.InterfaceType; |
|||
if (implementedInterfaceRef == null) |
|||
yield break; |
|||
|
|||
foreach (EventDefinition ev in type.Events.Where(e => e.Name == analyzedEvent.Name)) { |
|||
MethodDefinition accessor = ev.AddMethod ?? ev.RemoveMethod; |
|||
if (TypesHierarchyHelpers.MatchInterfaceMethod(accessor, analyzedMethod, implementedInterfaceRef)) { |
|||
var node = new AnalyzedEventTreeNode(ev); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
yield break; |
|||
} |
|||
|
|||
foreach (EventDefinition ev in type.Events.Where(e => e.Name.EndsWith(analyzedEvent.Name))) { |
|||
MethodDefinition accessor = ev.AddMethod ?? ev.RemoveMethod; |
|||
if (accessor.HasOverrides && accessor.Overrides.Any(m => m.Resolve() == analyzedMethod)) { |
|||
var node = new AnalyzedEventTreeNode(ev); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public static bool CanShow(EventDefinition ev) |
|||
{ |
|||
return ev.DeclaringType.IsInterface; |
|||
} |
|||
} |
|||
} |
@ -1,83 +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.TypeSystem; |
|||
using Mono.Cecil; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
internal sealed class AnalyzedInterfaceMethodImplementedByTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
private readonly MethodDefinitionHandle analyzedMethod; |
|||
|
|||
public AnalyzedInterfaceMethodImplementedByTreeNode(MethodDefinitionHandle analyzedMethod) |
|||
{ |
|||
if (analyzedMethod == null) |
|||
throw new ArgumentNullException(nameof(analyzedMethod)); |
|||
|
|||
this.analyzedMethod = analyzedMethod; |
|||
} |
|||
|
|||
public override object Text |
|||
{ |
|||
get { return "Implemented By"; } |
|||
} |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedMethod, FindReferencesInType); |
|||
return analyzer.PerformAnalysis(ct).OrderBy(n => n.Text); |
|||
} |
|||
|
|||
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(TypeDefinition type) |
|||
{ |
|||
if (!type.HasInterfaces) |
|||
yield break; |
|||
TypeReference implementedInterfaceRef = type.Interfaces.FirstOrDefault(i => i.InterfaceType.Resolve() == analyzedMethod.DeclaringType)?.InterfaceType; |
|||
if (implementedInterfaceRef == null) |
|||
yield break; |
|||
|
|||
foreach (MethodDefinition method in type.Methods.Where(m => m.Name == analyzedMethod.Name)) { |
|||
if (TypesHierarchyHelpers.MatchInterfaceMethod(method, analyzedMethod, implementedInterfaceRef)) { |
|||
var node = new AnalyzedMethodTreeNode(method); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
yield break; |
|||
} |
|||
|
|||
foreach (MethodDefinition method in type.Methods) { |
|||
if (method.HasOverrides && method.Overrides.Any(m => m.Resolve() == analyzedMethod)) { |
|||
var node = new AnalyzedMethodTreeNode(method); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public static bool CanShow(MethodDefinition method) |
|||
{ |
|||
return method.DeclaringType.IsInterface; |
|||
} |
|||
} |
|||
} |
@ -1,86 +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.Threading; |
|||
using ICSharpCode.Decompiler.TypeSystem; |
|||
using Mono.Cecil; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
internal sealed class AnalyzedInterfacePropertyImplementedByTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
private readonly PropertyDefinition analyzedProperty; |
|||
private readonly MethodDefinition analyzedMethod; |
|||
|
|||
public AnalyzedInterfacePropertyImplementedByTreeNode(PropertyDefinition analyzedProperty) |
|||
{ |
|||
if (analyzedProperty == null) |
|||
throw new ArgumentNullException(nameof(analyzedProperty)); |
|||
|
|||
this.analyzedProperty = analyzedProperty; |
|||
this.analyzedMethod = this.analyzedProperty.GetMethod ?? this.analyzedProperty.SetMethod; |
|||
} |
|||
|
|||
public override object Text |
|||
{ |
|||
get { return "Implemented By"; } |
|||
} |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedMethod, FindReferencesInType); |
|||
return analyzer.PerformAnalysis(ct).OrderBy(n => n.Text); |
|||
} |
|||
|
|||
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(TypeDefinition type) |
|||
{ |
|||
if (!type.HasInterfaces) |
|||
yield break; |
|||
TypeReference implementedInterfaceRef = type.Interfaces.FirstOrDefault(i => i.InterfaceType.Resolve() == analyzedMethod.DeclaringType)?.InterfaceType; |
|||
if (implementedInterfaceRef == null) |
|||
yield break; |
|||
|
|||
foreach (PropertyDefinition property in type.Properties.Where(e => e.Name == analyzedProperty.Name)) { |
|||
MethodDefinition accessor = property.GetMethod ?? property.SetMethod; |
|||
if (TypesHierarchyHelpers.MatchInterfaceMethod(accessor, analyzedMethod, implementedInterfaceRef)) { |
|||
var node = new AnalyzedPropertyTreeNode(property); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
yield break; |
|||
} |
|||
|
|||
foreach (PropertyDefinition property in type.Properties.Where(e => e.Name.EndsWith(analyzedProperty.Name))) { |
|||
MethodDefinition accessor = property.GetMethod ?? property.SetMethod; |
|||
if (accessor.HasOverrides && accessor.Overrides.Any(m => m.Resolve() == analyzedMethod)) { |
|||
var node = new AnalyzedPropertyTreeNode(property); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public static bool CanShow(PropertyDefinition property) |
|||
{ |
|||
return property.DeclaringType.IsInterface; |
|||
} |
|||
} |
|||
} |
@ -1,86 +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.Threading; |
|||
using ICSharpCode.Decompiler.TypeSystem; |
|||
using Mono.Cecil; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
/// <summary>
|
|||
/// Searches for overrides of the analyzed method.
|
|||
/// </summary>
|
|||
internal sealed class AnalyzedMethodOverridesTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
private readonly MethodDefinition analyzedMethod; |
|||
|
|||
public AnalyzedMethodOverridesTreeNode(MethodDefinition analyzedMethod) |
|||
{ |
|||
if (analyzedMethod == null) |
|||
throw new ArgumentNullException(nameof(analyzedMethod)); |
|||
|
|||
this.analyzedMethod = analyzedMethod; |
|||
} |
|||
|
|||
public override object Text |
|||
{ |
|||
get { return "Overridden By"; } |
|||
} |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedMethod, FindReferencesInType); |
|||
return analyzer.PerformAnalysis(ct).OrderBy(n => n.Text); |
|||
} |
|||
|
|||
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(TypeDefinition type) |
|||
{ |
|||
AnalyzerTreeNode newNode = null; |
|||
try { |
|||
if (!TypesHierarchyHelpers.IsBaseType(analyzedMethod.DeclaringType, type, resolveTypeArguments: false)) |
|||
yield break; |
|||
|
|||
foreach (MethodDefinition method in type.Methods) { |
|||
if (TypesHierarchyHelpers.IsBaseMethod(analyzedMethod, method)) { |
|||
bool hidesParent = !method.IsVirtual ^ method.IsNewSlot; |
|||
newNode = new AnalyzedMethodTreeNode(method, hidesParent ? "(hides) " : ""); |
|||
} |
|||
} |
|||
} |
|||
catch (ReferenceResolvingException) { |
|||
// ignore this type definition. maybe add a notification about such cases.
|
|||
} |
|||
|
|||
if (newNode != null) { |
|||
newNode.Language = this.Language; |
|||
yield return newNode; |
|||
} |
|||
} |
|||
|
|||
public static bool CanShow(MethodDefinition method) |
|||
{ |
|||
return method.IsVirtual && |
|||
!method.IsFinal && |
|||
!method.DeclaringType.IsSealed && |
|||
!method.DeclaringType.IsInterface; // interface methods are definitions not implementations - cannot be overridden
|
|||
} |
|||
} |
|||
} |
@ -1,118 +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.Concurrent; |
|||
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.Metadata; |
|||
using ICSharpCode.Decompiler.TypeSystem; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
/// <summary>
|
|||
/// Finds members where this method is referenced.
|
|||
/// </summary>
|
|||
internal sealed class AnalyzedMethodUsedByTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
readonly Decompiler.Metadata.PEFile module; |
|||
readonly MethodDefinitionHandle analyzedMethod; |
|||
|
|||
public AnalyzedMethodUsedByTreeNode(Decompiler.Metadata.PEFile module, MethodDefinitionHandle analyzedMethod) |
|||
{ |
|||
this.module = module ?? throw new ArgumentNullException(nameof(module)); |
|||
if (analyzedMethod.IsNil) |
|||
throw new ArgumentNullException(nameof(analyzedMethod)); |
|||
this.analyzedMethod = analyzedMethod; |
|||
} |
|||
|
|||
public override object Text => "Used By"; |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(this.Language, module, analyzedMethod, provideTypeSystem: false, FindReferencesInType); |
|||
foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { |
|||
yield return child; |
|||
} |
|||
} |
|||
|
|||
IEnumerable<AnalyzerTreeNode> FindReferencesInType(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, CodeMappingInfo codeMapping, IDecompilerTypeSystem typeSystem) |
|||
{ |
|||
var methodDef = this.module.Metadata.GetMethodDefinition(analyzedMethod); |
|||
var name = this.module.Metadata.GetString(methodDef.Name); |
|||
|
|||
var td = module.Metadata.GetTypeDefinition(type); |
|||
|
|||
HashSet<MethodDefinitionHandle> alreadyFoundMethods = new HashSet<MethodDefinitionHandle>(); |
|||
|
|||
foreach (var method in td.GetMethods()) { |
|||
var currentMethod = module.Metadata.GetMethodDefinition(method); |
|||
if (!currentMethod.HasBody()) |
|||
continue; |
|||
if (ScanMethodBody(module, currentMethod.RelativeVirtualAddress)) { |
|||
var parentMethod = codeMapping.GetParentMethod(method); |
|||
if (!parentMethod.IsNil && alreadyFoundMethods.Add(parentMethod)) { |
|||
var node = new AnalyzedMethodTreeNode(module, parentMethod); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
bool ScanMethodBody(PEFile module, int rva) |
|||
{ |
|||
var blob = module.Reader.GetMethodBody(rva).GetILReader(); |
|||
while (blob.RemainingBytes > 0) { |
|||
var opCode = blob.DecodeOpCode(); |
|||
switch (opCode.GetOperandType()) { |
|||
case OperandType.Field: |
|||
case OperandType.Method: |
|||
case OperandType.Sig: |
|||
case OperandType.Tok: |
|||
case OperandType.Type: |
|||
var member = MetadataTokens.EntityHandle(blob.ReadInt32()); |
|||
switch (member.Kind) { |
|||
case HandleKind.MethodDefinition: |
|||
if (this.module != module || analyzedMethod != (MethodDefinitionHandle)member) |
|||
break; |
|||
return true; |
|||
case HandleKind.MemberReference: |
|||
var mr = module.Metadata.GetMemberReference((MemberReferenceHandle)member); |
|||
if (mr.GetKind() != MemberReferenceKind.Method) |
|||
break; |
|||
return Helpers.IsSameMethod(analyzedMethod, this.module, member, module); |
|||
case HandleKind.MethodSpecification: |
|||
return Helpers.IsSameMethod(analyzedMethod, this.module, member, module); |
|||
} |
|||
break; |
|||
default: |
|||
blob.SkipOperand(opCode); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
} |
@ -1,119 +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.Reflection.Metadata.Ecma335; |
|||
using System.Threading; |
|||
using ICSharpCode.Decompiler; |
|||
using ICSharpCode.Decompiler.Disassembler; |
|||
using ICSharpCode.Decompiler.IL; |
|||
using ICSharpCode.Decompiler.Metadata; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
/// <summary>
|
|||
/// Shows the methods that are used by this method.
|
|||
/// </summary>
|
|||
internal sealed class AnalyzedMethodUsesTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
readonly Decompiler.Metadata.PEFile module; |
|||
readonly MethodDefinitionHandle 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 => "Uses"; |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
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<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; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -1,74 +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; |
|||
using System.Threading; |
|||
using ICSharpCode.Decompiler.Disassembler; |
|||
using ICSharpCode.Decompiler.Dom; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
internal sealed class AnalyzedPropertyOverridesTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
private readonly PropertyDefinition analyzedProperty; |
|||
|
|||
public AnalyzedPropertyOverridesTreeNode(PropertyDefinition analyzedProperty) |
|||
{ |
|||
if (analyzedProperty == null) |
|||
throw new ArgumentNullException(nameof(analyzedProperty)); |
|||
|
|||
this.analyzedProperty = analyzedProperty; |
|||
} |
|||
|
|||
public override object Text |
|||
{ |
|||
get { return "Overridden By"; } |
|||
} |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedProperty, FindReferencesInType); |
|||
return analyzer.PerformAnalysis(ct).OrderBy(n => n.Text); |
|||
} |
|||
|
|||
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(TypeDefinition type) |
|||
{ |
|||
if (!analyzedProperty.DeclaringType.IsBaseTypeOf(type)) |
|||
yield break; |
|||
|
|||
foreach (PropertyDefinition property in type.Properties) { |
|||
if (TypesHierarchyHelpers.IsBaseProperty(analyzedProperty, property)) { |
|||
MethodDefinition anyAccessor = property.GetMethod ?? property.SetMethod; |
|||
bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot; |
|||
var node = new AnalyzedPropertyTreeNode(property, hidesParent ? "(hides) " : ""); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public static bool CanShow(PropertyDefinition property) |
|||
{ |
|||
var accessor = property.GetAccessors().First().Method; |
|||
return accessor.HasFlag(MethodAttributes.Virtual) && !accessor.HasFlag(MethodAttributes.Final) && !accessor.DeclaringType.IsInterface; |
|||
} |
|||
} |
|||
} |
@ -1,173 +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; |
|||
using System.Threading; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
internal sealed class AnalyzedTypeExposedByTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
private readonly Decompiler.Metadata.TypeDefinition analyzedType; |
|||
|
|||
public AnalyzedTypeExposedByTreeNode(TypeDefinition analyzedType) |
|||
{ |
|||
if (analyzedType.IsNil) |
|||
throw new ArgumentNullException(nameof(analyzedType)); |
|||
|
|||
this.analyzedType = analyzedType; |
|||
} |
|||
|
|||
public override object Text |
|||
{ |
|||
get { return "Exposed By"; } |
|||
} |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedType, FindReferencesInType); |
|||
return analyzer.PerformAnalysis(ct).OrderBy(n => n.Text); |
|||
} |
|||
|
|||
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(TypeDefinition type) |
|||
{ |
|||
if (analyzedType.IsEnum && type == analyzedType) |
|||
yield break; |
|||
|
|||
if (!this.Language.ShowMember(type)) |
|||
yield break; |
|||
|
|||
foreach (FieldDefinition field in type.Fields) { |
|||
if (TypeIsExposedBy(field)) { |
|||
var node = new AnalyzedFieldTreeNode(field); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
|
|||
foreach (PropertyDefinition property in type.Properties) { |
|||
if (TypeIsExposedBy(property)) { |
|||
var node = new AnalyzedPropertyTreeNode(property); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
|
|||
foreach (EventDefinition eventDef in type.Events) { |
|||
if (TypeIsExposedBy(eventDef)) { |
|||
var node = new AnalyzedEventTreeNode(eventDef); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
|
|||
foreach (MethodDefinition method in type.Methods) { |
|||
if (TypeIsExposedBy(method)) { |
|||
var node = new AnalyzedMethodTreeNode(method); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
} |
|||
|
|||
private bool TypeIsExposedBy(FieldDefinition field) |
|||
{ |
|||
if (field.IsPrivate) |
|||
return false; |
|||
|
|||
if (field.FieldType.Resolve() == analyzedType) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
private bool TypeIsExposedBy(Decompiler.Metadata.PropertyDefinition property) |
|||
{ |
|||
if (IsPrivate(property)) |
|||
return false; |
|||
|
|||
if (property.PropertyType.Resolve() == analyzedType) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
private bool TypeIsExposedBy(Decompiler.Metadata.EventDefinition eventDef) |
|||
{ |
|||
if (IsPrivate(eventDef)) |
|||
return false; |
|||
|
|||
if (eventDef.EventType.Resolve() == analyzedType) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
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.
|
|||
if (method.IsPrivate) { |
|||
if (!method.HasOverrides) |
|||
return false; |
|||
var typeDefinition = method.Overrides[0].DeclaringType.Resolve(); |
|||
if (typeDefinition != null && !typeDefinition.IsInterface) |
|||
return false; |
|||
} |
|||
|
|||
// exclude methods with 'semantics'. for example, property getters & setters.
|
|||
// HACK: this is a potentially fragile implementation, as the MethodSemantics may be extended to other uses at a later date.
|
|||
if (method.GetMethodSemanticsAttributes() != 0) |
|||
return false; |
|||
|
|||
if (method.ReturnType.Resolve() == analyzedType) |
|||
return true; |
|||
|
|||
if (method.HasParameters) { |
|||
foreach (var parameter in method.Parameters) { |
|||
if (parameter.ParameterType.Resolve() == analyzedType) |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
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(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(Decompiler.Metadata.TypeDefinition type) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
} |
@ -1,84 +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.Threading; |
|||
using Mono.Cecil; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
internal class AnalyzedTypeExtensionMethodsTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
private readonly TypeDefinition analyzedType; |
|||
|
|||
public AnalyzedTypeExtensionMethodsTreeNode(TypeDefinition analyzedType) |
|||
{ |
|||
if (analyzedType == null) |
|||
throw new ArgumentNullException(nameof(analyzedType)); |
|||
|
|||
this.analyzedType = analyzedType; |
|||
} |
|||
|
|||
public override object Text |
|||
{ |
|||
get { return "Extension Methods"; } |
|||
} |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedType, FindReferencesInType); |
|||
return analyzer.PerformAnalysis(ct).OrderBy(n => n.Text); |
|||
} |
|||
|
|||
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(TypeDefinition type) |
|||
{ |
|||
if (!HasExtensionAttribute(type)) |
|||
yield break; |
|||
foreach (MethodDefinition method in type.Methods) { |
|||
if (method.IsStatic && HasExtensionAttribute(method)) { |
|||
if (method.HasParameters && method.Parameters[0].ParameterType.Resolve() == analyzedType) { |
|||
var node = new AnalyzedMethodTreeNode(method); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
bool HasExtensionAttribute(ICustomAttributeProvider p) |
|||
{ |
|||
if (p.HasCustomAttributes) { |
|||
foreach (CustomAttribute ca in p.CustomAttributes) { |
|||
TypeReference t = ca.AttributeType; |
|||
if (t.Name == "ExtensionAttribute" && t.Namespace == "System.Runtime.CompilerServices") |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
|
|||
public static bool CanShow(TypeDefinition type) |
|||
{ |
|||
// show on all types except static classes
|
|||
return !(type.IsAbstract && type.IsSealed); |
|||
} |
|||
} |
|||
} |
@ -1,152 +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; |
|||
using System.Reflection.Metadata; |
|||
using System.Reflection.Metadata.Ecma335; |
|||
using System.Threading; |
|||
|
|||
using ICSharpCode.Decompiler; |
|||
using ICSharpCode.Decompiler.Disassembler; |
|||
using ICSharpCode.Decompiler.TypeSystem; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
sealed class AnalyzedTypeInstantiationsTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
readonly Decompiler.Metadata.PEFile module; |
|||
readonly TypeDefinitionHandle analyzedType; |
|||
readonly FullTypeName analyzedTypeName; |
|||
|
|||
public AnalyzedTypeInstantiationsTreeNode(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 => "Instantiated By"; |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(this.Language, module, analyzedType, provideTypeSystem: false, FindReferencesInType); |
|||
return analyzer.PerformAnalysis(ct).OrderBy(n => n.Text); |
|||
} |
|||
|
|||
IEnumerable<AnalyzerTreeNode> FindReferencesInType(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, CodeMappingInfo codeMapping, IDecompilerTypeSystem typeSystem) |
|||
{ |
|||
var td = module.Metadata.GetTypeDefinition(type); |
|||
foreach (var h in td.GetMethods()) { |
|||
bool found = false; |
|||
|
|||
var method = module.Metadata.GetMethodDefinition(h); |
|||
if (!method.HasBody()) |
|||
continue; |
|||
|
|||
var blob = module.Reader.GetMethodBody(method.RelativeVirtualAddress).GetILReader(); |
|||
while (!found && blob.RemainingBytes > 0) { |
|||
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: |
|||
blob.SkipOperand(opCode); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (found) { |
|||
var node = new AnalyzedMethodTreeNode(module, h); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public static bool CanShow(MetadataReader metadata, TypeDefinitionHandle handle) |
|||
{ |
|||
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); |
|||
} |
|||
} |
|||
} |
@ -1,239 +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.Reflection.Metadata.Ecma335; |
|||
using System.Threading; |
|||
using ICSharpCode.Decompiler; |
|||
using ICSharpCode.Decompiler.Metadata; |
|||
using ICSharpCode.Decompiler.Disassembler; |
|||
using ICSharpCode.Decompiler.TypeSystem; |
|||
using ICSharpCode.Decompiler.Util; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
internal sealed class AnalyzedTypeUsedByTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
readonly Decompiler.Metadata.PEFile module; |
|||
readonly TypeDefinitionHandle analyzedType; |
|||
readonly FullTypeName analyzedTypeName; |
|||
|
|||
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 => "Used By"; |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerEntityTreeNode>(this.Language, module, analyzedType, provideTypeSystem: true, FindTypeUsage); |
|||
return analyzer.PerformAnalysis(ct).Distinct(AnalyzerEntityTreeNodeComparer.Instance).OrderBy(n => n.Text); |
|||
} |
|||
|
|||
IEnumerable<AnalyzerEntityTreeNode> FindTypeUsage(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, CodeMappingInfo codeMapping, IDecompilerTypeSystem typeSystem) |
|||
{ |
|||
if (type == this.analyzedType && module == this.module) |
|||
yield break; |
|||
|
|||
// TODO : cache / optimize this per assembly
|
|||
var analyzedTypeDefinition = typeSystem.Compilation.FindType(analyzedTypeName).GetDefinition(); |
|||
var typeDefinition = typeSystem.ResolveAsType(type).GetDefinition(); |
|||
|
|||
if (analyzedTypeDefinition == null || typeDefinition == null) |
|||
yield break; |
|||
|
|||
var visitor = new TypeDefinitionUsedVisitor(analyzedTypeDefinition); |
|||
|
|||
if (typeDefinition.DirectBaseTypes.Any(bt => analyzedTypeDefinition.Equals(bt.GetDefinition()))) |
|||
yield return new AnalyzedTypeTreeNode(new Decompiler.Metadata.TypeDefinition(module, type)) { Language = Language }; |
|||
|
|||
foreach (var field in typeDefinition.Fields.Where(f => IsUsedInField(f, visitor))) |
|||
yield return new AnalyzedFieldTreeNode(module, (FieldDefinitionHandle)field.MetadataToken) { Language = Language }; |
|||
|
|||
foreach (var method in typeDefinition.Methods.Where(m => IsUsedInMethodDefinition(m, visitor, typeSystem, module))) |
|||
yield return new AnalyzedMethodTreeNode(module, (MethodDefinitionHandle)method.MetadataToken) { Language = Language }; |
|||
|
|||
foreach (var property in typeDefinition.Properties.Where(p => IsUsedInProperty(p, visitor, typeSystem, module))) |
|||
yield return new AnalyzedPropertyTreeNode(module, (PropertyDefinitionHandle)property.MetadataToken) { Language = Language }; |
|||
} |
|||
|
|||
bool IsUsedInField(IField field, TypeDefinitionUsedVisitor visitor) |
|||
{ |
|||
visitor.Found = false; |
|||
field.ReturnType.AcceptVisitor(visitor); |
|||
return visitor.Found; |
|||
} |
|||
|
|||
bool IsUsedInProperty(IProperty property, TypeDefinitionUsedVisitor visitor, IDecompilerTypeSystem typeSystem, PEFile module) |
|||
{ |
|||
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)); |
|||
} |
|||
|
|||
bool IsUsedInMethodDefinition(IMethod method, TypeDefinitionUsedVisitor visitor, IDecompilerTypeSystem typeSystem, PEFile module) |
|||
{ |
|||
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); |
|||
} |
|||
|
|||
bool IsUsedInMethod(IMethod method, TypeDefinitionUsedVisitor visitor) |
|||
{ |
|||
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; |
|||
} |
|||
|
|||
bool IsUsedInMethodBody(PEFile module, TypeDefinitionUsedVisitor visitor, IDecompilerTypeSystem typeSystem, MethodDefinitionHandle method) |
|||
{ |
|||
if (method.IsNil) |
|||
return false; |
|||
var md = module.Metadata.GetMethodDefinition(method); |
|||
if (!md.HasBody()) |
|||
return false; |
|||
|
|||
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; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static bool CanShow(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type) |
|||
{ |
|||
return !type.IsNil; |
|||
} |
|||
} |
|||
|
|||
class AnalyzerEntityTreeNodeComparer : IEqualityComparer<AnalyzerEntityTreeNode> |
|||
{ |
|||
public static readonly AnalyzerEntityTreeNodeComparer Instance = new AnalyzerEntityTreeNodeComparer(); |
|||
|
|||
public bool Equals(AnalyzerEntityTreeNode x, AnalyzerEntityTreeNode y) |
|||
{ |
|||
return x.Member == y.Member; |
|||
} |
|||
|
|||
public int GetHashCode(AnalyzerEntityTreeNode obj) |
|||
{ |
|||
return obj.Member.GetHashCode(); |
|||
} |
|||
} |
|||
|
|||
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.Equals(type); |
|||
return base.VisitTypeDefinition(type); |
|||
} |
|||
} |
|||
} |
@ -1,139 +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.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using ICSharpCode.Decompiler.TypeSystem; |
|||
using Mono.Cecil; |
|||
using Mono.Cecil.Cil; |
|||
|
|||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
|||
{ |
|||
internal sealed class AnalyzedVirtualMethodUsedByTreeNode : AnalyzerSearchTreeNode |
|||
{ |
|||
private readonly MethodDefinition analyzedMethod; |
|||
private ConcurrentDictionary<MethodDefinition, int> foundMethods; |
|||
private MethodDefinition baseMethod; |
|||
private List<TypeReference> possibleTypes; |
|||
|
|||
public AnalyzedVirtualMethodUsedByTreeNode(MethodDefinition analyzedMethod) |
|||
{ |
|||
if (analyzedMethod == null) |
|||
throw new ArgumentNullException(nameof(analyzedMethod)); |
|||
|
|||
this.analyzedMethod = analyzedMethod; |
|||
} |
|||
|
|||
public override object Text |
|||
{ |
|||
get { return "Used By"; } |
|||
} |
|||
|
|||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
|||
{ |
|||
InitializeAnalyzer(); |
|||
|
|||
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedMethod, FindReferencesInType); |
|||
foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { |
|||
yield return child; |
|||
} |
|||
|
|||
ReleaseAnalyzer(); |
|||
} |
|||
|
|||
private void InitializeAnalyzer() |
|||
{ |
|||
foundMethods = new ConcurrentDictionary<MethodDefinition, int>(); |
|||
|
|||
var baseMethods = TypesHierarchyHelpers.FindBaseMethods(analyzedMethod).ToArray(); |
|||
if (baseMethods.Length > 0) { |
|||
baseMethod = baseMethods[baseMethods.Length - 1]; |
|||
} else |
|||
baseMethod = analyzedMethod; |
|||
|
|||
possibleTypes = new List<TypeReference>(); |
|||
|
|||
TypeReference type = analyzedMethod.DeclaringType.BaseType; |
|||
while (type != null) { |
|||
possibleTypes.Add(type); |
|||
type = type.Resolve().BaseType; |
|||
} |
|||
} |
|||
|
|||
private void ReleaseAnalyzer() |
|||
{ |
|||
foundMethods = null; |
|||
baseMethod = null; |
|||
} |
|||
|
|||
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(TypeDefinition type) |
|||
{ |
|||
string name = analyzedMethod.Name; |
|||
foreach (MethodDefinition method in type.Methods) { |
|||
bool found = false; |
|||
string prefix = string.Empty; |
|||
if (!method.HasBody) |
|||
continue; |
|||
foreach (Instruction instr in method.Body.Instructions) { |
|||
MethodReference mr = instr.Operand as MethodReference; |
|||
if (mr != null && mr.Name == name) { |
|||
// explicit call to the requested method
|
|||
if (instr.OpCode.Code == Code.Call |
|||
&& Helpers.IsSameType(analyzedMethod.DeclaringType, mr.DeclaringType) |
|||
&& mr.Resolve() == analyzedMethod) { |
|||
found = true; |
|||
prefix = "(as base) "; |
|||
break; |
|||
} |
|||
// virtual call to base method
|
|||
if (instr.OpCode.Code == Code.Callvirt) { |
|||
MethodDefinition md = mr.Resolve(); |
|||
if (md == null) { |
|||
// cannot resolve the operand, so ignore this method
|
|||
break; |
|||
} |
|||
if (md == baseMethod) { |
|||
found = true; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
method.Body = null; |
|||
|
|||
if (found) { |
|||
MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition; |
|||
if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) { |
|||
var node = new AnalyzedMethodTreeNode(codeLocation); |
|||
node.Language = this.Language; |
|||
yield return node; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
private bool HasAlreadyBeenFound(MethodDefinition method) |
|||
{ |
|||
return !foundMethods.TryAdd(method, 0); |
|||
} |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue