mirror of https://github.com/icsharpcode/ILSpy.git
16 changed files with 0 additions and 2023 deletions
@ -1,372 +0,0 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue