mirror of https://github.com/icsharpcode/ILSpy.git
11 changed files with 461 additions and 317 deletions
@ -0,0 +1,247 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Collections.ObjectModel; |
||||||
|
using System.Linq; |
||||||
|
using System.Text; |
||||||
|
using Mono.Cecil; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.Ast |
||||||
|
{ |
||||||
|
public static class TypesHierarchyHelpers |
||||||
|
{ |
||||||
|
public static bool IsBaseType(TypeDefinition baseType, TypeDefinition derivedType, bool resolveTypeArguments) |
||||||
|
{ |
||||||
|
if (resolveTypeArguments) |
||||||
|
return BaseTypes(derivedType).Any(t => t.Item == baseType); |
||||||
|
else { |
||||||
|
var comparableBaseType = baseType.Resolve(); |
||||||
|
while (derivedType.BaseType != null) { |
||||||
|
var resolvedBaseType = derivedType.BaseType.Resolve(); |
||||||
|
if (resolvedBaseType == null) |
||||||
|
return false; |
||||||
|
if (comparableBaseType == resolvedBaseType) |
||||||
|
return true; |
||||||
|
derivedType = resolvedBaseType; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static bool IsBaseMethod(MethodDefinition parentMethod, MethodDefinition childMethod) |
||||||
|
{ |
||||||
|
if (parentMethod.Name != childMethod.Name) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (parentMethod.HasParameters || childMethod.HasParameters) |
||||||
|
if(!parentMethod.HasParameters || ! childMethod.HasParameters || parentMethod.Parameters.Count != childMethod.Parameters.Count) |
||||||
|
return false; |
||||||
|
|
||||||
|
return FindBaseMethods(childMethod).Any(m => m == parentMethod);// || (parentMethod.HasGenericParameters && m.);
|
||||||
|
} |
||||||
|
|
||||||
|
public static bool IsBaseProperty(PropertyDefinition parentProperty, PropertyDefinition childProperty) |
||||||
|
{ |
||||||
|
if (parentProperty.Name != childProperty.Name) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (parentProperty.HasParameters || childProperty.HasParameters) |
||||||
|
if (!parentProperty.HasParameters || !childProperty.HasParameters || parentProperty.Parameters.Count != childProperty.Parameters.Count) |
||||||
|
return false; |
||||||
|
|
||||||
|
return FindBaseProperties(childProperty).Any(m => m == parentProperty); |
||||||
|
} |
||||||
|
|
||||||
|
public static IEnumerable<MethodDefinition> FindBaseMethods(MethodDefinition method) |
||||||
|
{ |
||||||
|
var typeContext = CreateGenericContext(method.DeclaringType); |
||||||
|
var gMethod = typeContext.ApplyTo(method); |
||||||
|
|
||||||
|
foreach (var baseType in BaseTypes(method.DeclaringType)) |
||||||
|
foreach (var baseMethod in baseType.Item.Methods) |
||||||
|
if (MatchMethod(baseType.ApplyTo(baseMethod), gMethod) && IsVisbleFrom(baseMethod, method)) { |
||||||
|
yield return baseMethod; |
||||||
|
if (!(baseMethod.IsNewSlot ^ baseMethod.IsVirtual)) |
||||||
|
yield break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static IEnumerable<PropertyDefinition> FindBaseProperties(PropertyDefinition property) |
||||||
|
{ |
||||||
|
var typeContext = CreateGenericContext(property.DeclaringType); |
||||||
|
var gProperty = typeContext.ApplyTo(property); |
||||||
|
|
||||||
|
foreach (var baseType in BaseTypes(property.DeclaringType)) |
||||||
|
foreach (var baseProperty in baseType.Item.Properties) |
||||||
|
if (MatchProperty(baseType.ApplyTo(baseProperty), gProperty) && IsVisbleFrom(baseProperty, property)) { |
||||||
|
yield return baseProperty; |
||||||
|
var anyPropertyAccessor = baseProperty.GetMethod ?? baseProperty.SetMethod; |
||||||
|
if (!(anyPropertyAccessor.IsNewSlot ^ anyPropertyAccessor.IsVirtual)) |
||||||
|
yield break; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private static bool IsVisbleFrom(MethodDefinition baseCandidate, MethodDefinition method) |
||||||
|
{ |
||||||
|
if (baseCandidate.IsPrivate) |
||||||
|
return false; |
||||||
|
if ((baseCandidate.IsAssembly || baseCandidate.IsFamilyAndAssembly) && baseCandidate.Module != method.Module) |
||||||
|
return false; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private static bool IsVisbleFrom(PropertyDefinition baseCandidate, PropertyDefinition property) |
||||||
|
{ |
||||||
|
if (baseCandidate.GetMethod != null && property.GetMethod != null && IsVisbleFrom(baseCandidate.GetMethod, property.GetMethod)) |
||||||
|
return true; |
||||||
|
if (baseCandidate.SetMethod != null && property.SetMethod != null && IsVisbleFrom(baseCandidate.SetMethod, property.SetMethod)) |
||||||
|
return true; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private static bool MatchMethod(GenericContext<MethodDefinition> candidate, GenericContext<MethodDefinition> method) |
||||||
|
{ |
||||||
|
var mCandidate = candidate.Item; |
||||||
|
var mMethod = method.Item; |
||||||
|
if (mCandidate.Name != mMethod.Name) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (mCandidate.HasOverrides) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (candidate.Resolve(mCandidate.ReturnType) != method.Resolve(mMethod.ReturnType)) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (mCandidate.HasGenericParameters || mMethod.HasGenericParameters) { |
||||||
|
if (!mCandidate.HasGenericParameters || !mMethod.HasGenericParameters || mCandidate.GenericParameters.Count != mMethod.GenericParameters.Count) |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (mCandidate.HasParameters || mMethod.HasParameters) { |
||||||
|
if (!mCandidate.HasParameters || !mMethod.HasParameters || mCandidate.Parameters.Count != mMethod.Parameters.Count) |
||||||
|
return false; |
||||||
|
|
||||||
|
for (int index = 0; index < mCandidate.Parameters.Count; index++) { |
||||||
|
if (!MatchParameters(candidate.ApplyTo(mCandidate.Parameters[index]), method.ApplyTo(mMethod.Parameters[index]))) |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private static bool MatchProperty(GenericContext<PropertyDefinition> candidate, GenericContext<PropertyDefinition> property) |
||||||
|
{ |
||||||
|
var mCandidate = candidate.Item; |
||||||
|
var mProperty = property.Item; |
||||||
|
if (mCandidate.Name != mProperty.Name) |
||||||
|
return false; |
||||||
|
|
||||||
|
if ((mCandidate.GetMethod ?? mCandidate.SetMethod).HasOverrides) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (candidate.Resolve(mCandidate.PropertyType) != property.Resolve(mProperty.PropertyType)) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (mCandidate.HasParameters || mProperty.HasParameters) { |
||||||
|
if (!mCandidate.HasParameters || !mProperty.HasParameters || mCandidate.Parameters.Count != mProperty.Parameters.Count) |
||||||
|
return false; |
||||||
|
|
||||||
|
for (int index = 0; index < mCandidate.Parameters.Count; index++) { |
||||||
|
if (!MatchParameters(candidate.ApplyTo(mCandidate.Parameters[index]), property.ApplyTo(mProperty.Parameters[index]))) |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private static bool MatchParameters(GenericContext<ParameterDefinition> baseParameterType, GenericContext<ParameterDefinition> parameterType) |
||||||
|
{ |
||||||
|
var baseParam = baseParameterType.Resolve(baseParameterType.Item.ParameterType); |
||||||
|
var param = parameterType.Resolve(parameterType.Item.ParameterType); |
||||||
|
return baseParam == param; |
||||||
|
} |
||||||
|
|
||||||
|
private static IEnumerable<GenericContext<TypeDefinition>> BaseTypes(TypeDefinition type) |
||||||
|
{ |
||||||
|
return BaseTypes(CreateGenericContext(type)); |
||||||
|
} |
||||||
|
|
||||||
|
private static IEnumerable<GenericContext<TypeDefinition>> BaseTypes(GenericContext<TypeDefinition> type) |
||||||
|
{ |
||||||
|
while (type.Item.BaseType != null) { |
||||||
|
var baseType = type.Item.BaseType; |
||||||
|
var genericBaseType = baseType as GenericInstanceType; |
||||||
|
if (genericBaseType != null) { |
||||||
|
type = new GenericContext<TypeDefinition>(genericBaseType.Resolve(), |
||||||
|
genericBaseType.GenericArguments.Select(t => type.Resolve(t))); |
||||||
|
} else |
||||||
|
type = new GenericContext<TypeDefinition>(baseType.Resolve()); |
||||||
|
yield return type; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static GenericContext<TypeDefinition> CreateGenericContext(TypeDefinition type) |
||||||
|
{ |
||||||
|
return type.HasGenericParameters |
||||||
|
? new GenericContext<TypeDefinition>(type, type.GenericParameters) |
||||||
|
: new GenericContext<TypeDefinition>(type); |
||||||
|
} |
||||||
|
|
||||||
|
struct GenericContext<T> |
||||||
|
{ |
||||||
|
private static readonly ReadOnlyCollection<TypeReference> Empty = new ReadOnlyCollection<TypeReference>(new List<TypeReference>()); |
||||||
|
|
||||||
|
public readonly T Item; |
||||||
|
public readonly ReadOnlyCollection<TypeReference> TypeArguments; |
||||||
|
|
||||||
|
public GenericContext(T item) |
||||||
|
{ |
||||||
|
Item = item; |
||||||
|
TypeArguments = Empty; |
||||||
|
} |
||||||
|
|
||||||
|
public GenericContext(T item, IEnumerable<TypeReference> typeArguments) |
||||||
|
{ |
||||||
|
Item = item; |
||||||
|
var list = new List<TypeReference>(); |
||||||
|
foreach (var arg in typeArguments) { |
||||||
|
var resolved = arg != null ? arg.Resolve() : arg; |
||||||
|
list.Add(resolved != null ? resolved : arg); |
||||||
|
} |
||||||
|
TypeArguments = new ReadOnlyCollection<TypeReference>(list); |
||||||
|
} |
||||||
|
|
||||||
|
private GenericContext(T item, ReadOnlyCollection<TypeReference> typeArguments) |
||||||
|
{ |
||||||
|
Item = item; |
||||||
|
TypeArguments = typeArguments; |
||||||
|
} |
||||||
|
|
||||||
|
public TypeReference Resolve(TypeReference type) |
||||||
|
{ |
||||||
|
var genericParameter = type as GenericParameter; |
||||||
|
if (genericParameter != null && genericParameter.Owner.GenericParameterType == GenericParameterType.Type) { |
||||||
|
return this.TypeArguments[genericParameter.Position]; |
||||||
|
} |
||||||
|
var arrayType = type as ArrayType; |
||||||
|
if (arrayType != null) { |
||||||
|
var resolvedElementType = Resolve(arrayType.ElementType); |
||||||
|
if (resolvedElementType == null) |
||||||
|
return null; |
||||||
|
var newArrayType = new ArrayType(resolvedElementType, arrayType.Rank); |
||||||
|
for (int dimension = 0; dimension < arrayType.Rank; dimension++) |
||||||
|
newArrayType.Dimensions[dimension] = arrayType.Dimensions[dimension]; |
||||||
|
return newArrayType; |
||||||
|
} |
||||||
|
return type.Resolve(); |
||||||
|
} |
||||||
|
|
||||||
|
public GenericContext<T2> ApplyTo<T2>(T2 item) |
||||||
|
{ |
||||||
|
return new GenericContext<T2>(item, this.TypeArguments); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,92 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Text; |
||||||
|
using System.Threading; |
||||||
|
using ICSharpCode.Decompiler.Ast; |
||||||
|
using ICSharpCode.NRefactory.Utils; |
||||||
|
using ICSharpCode.TreeView; |
||||||
|
using Mono.Cecil; |
||||||
|
|
||||||
|
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
||||||
|
{ |
||||||
|
class AnalyzedPropertyOverridesTreeNode : AnalyzerTreeNode |
||||||
|
{ |
||||||
|
readonly PropertyDefinition analyzedProperty; |
||||||
|
readonly ThreadingSupport threading; |
||||||
|
|
||||||
|
public AnalyzedPropertyOverridesTreeNode(PropertyDefinition analyzedProperty) |
||||||
|
{ |
||||||
|
if (analyzedProperty == null) |
||||||
|
throw new ArgumentNullException("analyzedProperty"); |
||||||
|
|
||||||
|
this.analyzedProperty = analyzedProperty; |
||||||
|
this.threading = new ThreadingSupport(); |
||||||
|
this.LazyLoading = true; |
||||||
|
} |
||||||
|
|
||||||
|
public override object Text |
||||||
|
{ |
||||||
|
get { return "Overrided By"; } |
||||||
|
} |
||||||
|
|
||||||
|
public override object Icon |
||||||
|
{ |
||||||
|
get { return Images.Search; } |
||||||
|
} |
||||||
|
|
||||||
|
protected override void LoadChildren() |
||||||
|
{ |
||||||
|
threading.LoadChildren(this, FetchChildren); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnCollapsing() |
||||||
|
{ |
||||||
|
if (threading.IsRunning) { |
||||||
|
this.LazyLoading = true; |
||||||
|
threading.Cancel(); |
||||||
|
this.Children.Clear(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) |
||||||
|
{ |
||||||
|
return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct); |
||||||
|
} |
||||||
|
|
||||||
|
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly[] assemblies, CancellationToken ct) |
||||||
|
{ |
||||||
|
// use parallelism only on the assembly level (avoid locks within Cecil)
|
||||||
|
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct)); |
||||||
|
} |
||||||
|
|
||||||
|
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly asm, CancellationToken ct) |
||||||
|
{ |
||||||
|
string asmName = asm.AssemblyDefinition.Name.Name; |
||||||
|
string name = analyzedProperty.Name; |
||||||
|
string declTypeName = analyzedProperty.DeclaringType.FullName; |
||||||
|
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) { |
||||||
|
ct.ThrowIfCancellationRequested(); |
||||||
|
|
||||||
|
if (!TypesHierarchyHelpers.IsBaseType(analyzedProperty.DeclaringType, type, resolveTypeArguments: false)) |
||||||
|
continue; |
||||||
|
|
||||||
|
foreach (PropertyDefinition property in type.Properties) { |
||||||
|
ct.ThrowIfCancellationRequested(); |
||||||
|
|
||||||
|
if (TypesHierarchyHelpers.IsBaseProperty(analyzedProperty, property)) { |
||||||
|
MethodDefinition anyAccessor = property.GetMethod ?? property.SetMethod; |
||||||
|
bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot; |
||||||
|
yield return new AnalyzedPropertyTreeNode(property, hidesParent ? "(hides) " : ""); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static bool CanShowAnalyzer(PropertyDefinition property) |
||||||
|
{ |
||||||
|
var accessor = property.GetMethod ?? property.SetMethod; |
||||||
|
return accessor.IsVirtual && !accessor.IsFinal && !accessor.DeclaringType.IsInterface; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,80 @@ |
|||||||
|
// 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 Mono.Cecil; |
||||||
|
|
||||||
|
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
||||||
|
{ |
||||||
|
class AnalyzedPropertyTreeNode : AnalyzerTreeNode |
||||||
|
{ |
||||||
|
PropertyDefinition analyzedProperty; |
||||||
|
string prefix; |
||||||
|
|
||||||
|
public AnalyzedPropertyTreeNode(PropertyDefinition analyzedProperty, string prefix = "") |
||||||
|
{ |
||||||
|
if (analyzedProperty == null) |
||||||
|
throw new ArgumentNullException("analyzedMethod"); |
||||||
|
|
||||||
|
this.analyzedProperty = analyzedProperty; |
||||||
|
this.prefix = prefix; |
||||||
|
this.LazyLoading = true; |
||||||
|
} |
||||||
|
|
||||||
|
public override object Icon { |
||||||
|
get { return PropertyTreeNode.GetIcon(analyzedProperty); } |
||||||
|
} |
||||||
|
|
||||||
|
public override object Text { |
||||||
|
get { |
||||||
|
return prefix + Language.TypeToString(analyzedProperty.DeclaringType, true) + "." + PropertyTreeNode.GetText(analyzedProperty, Language); } |
||||||
|
} |
||||||
|
|
||||||
|
public override void ActivateItem(System.Windows.RoutedEventArgs e) |
||||||
|
{ |
||||||
|
e.Handled = true; |
||||||
|
MainWindow.Instance.JumpToReference(analyzedProperty); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void LoadChildren() |
||||||
|
{ |
||||||
|
if (AnalyzedPropertyOverridesTreeNode.CanShowAnalyzer(analyzedProperty)) |
||||||
|
this.Children.Add(new AnalyzedPropertyOverridesTreeNode(analyzedProperty)); |
||||||
|
//if (analyzedProperty.HasBody)
|
||||||
|
// this.Children.Add(new AnalyzedMethodUsesNode(analyzedProperty));
|
||||||
|
//this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedProperty));
|
||||||
|
} |
||||||
|
|
||||||
|
public static AnalyzerTreeNode TryCreateAnalyzer(MemberReference member) |
||||||
|
{ |
||||||
|
if (CanShow(member)) |
||||||
|
return new AnalyzedPropertyTreeNode(member as PropertyDefinition); |
||||||
|
else |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public static bool CanShow(MemberReference member) |
||||||
|
{ |
||||||
|
var property = member as PropertyDefinition; |
||||||
|
if (property == null) |
||||||
|
return false; |
||||||
|
|
||||||
|
return AnalyzedPropertyOverridesTreeNode.CanShowAnalyzer(property); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue