From e8d81ed17c67db03bfae5856e001c9c949e81328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Wed, 6 Apr 2011 19:51:07 +0200 Subject: [PATCH] Fixed "Overrided By" method analyzer. Added similar analyzer for properties. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 195 +------------- .../Ast/TypesHierarchyHelpers.cs | 247 ++++++++++++++++++ .../ICSharpCode.Decompiler.csproj | 1 + ILSpy/ContextMenuEntry.cs | 6 +- ILSpy/ILSpy.csproj | 2 + .../Analyzer/AnalyzeContextMenuEntry.cs | 7 +- .../Analyzer/AnalyzedMethodTreeNode.cs | 7 +- .../AnalyzedPropertyOverridesTreeNode.cs | 92 +++++++ .../Analyzer/AnalyzedPropertyTreeNode.cs | 80 ++++++ .../AnalyzerMethodOverridesTreeNode.cs | 121 +-------- ILSpy/TreeNodes/PropertyTreeNode.cs | 20 +- 11 files changed, 461 insertions(+), 317 deletions(-) create mode 100644 ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs create mode 100644 ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs create mode 100644 ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index d67128779..3fd0595cb 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -630,7 +630,7 @@ namespace ICSharpCode.Decompiler.Ast if (!methodDef.HasOverrides) { astMethod.Modifiers = ConvertModifiers(methodDef); if (methodDef.IsVirtual ^ !methodDef.IsNewSlot) { - if (TypeMap.FindBaseMethods(methodDef).Any()) + if (TypesHierarchyHelpers.FindBaseMethods(methodDef).Any()) astMethod.Modifiers |= Modifiers.New; } } else @@ -745,7 +745,7 @@ namespace ICSharpCode.Decompiler.Ast setterModifiers = ConvertModifiers(propDef.SetMethod); astProp.Modifiers = FixUpVisibility(getterModifiers | setterModifiers); if (accessor.IsVirtual && !accessor.IsNewSlot && (propDef.GetMethod == null || propDef.SetMethod == null)) - foreach (var basePropDef in TypeMap.FindBaseProperties(propDef)) + foreach (var basePropDef in TypesHierarchyHelpers.FindBaseProperties(propDef)) if (basePropDef.GetMethod != null && basePropDef.SetMethod != null) { var propVisibilityModifiers = ConvertModifiers(basePropDef.GetMethod) | ConvertModifiers(basePropDef.SetMethod); astProp.Modifiers = FixUpVisibility((astProp.Modifiers & ~Modifiers.VisibilityMask) | (propVisibilityModifiers & Modifiers.VisibilityMask)); @@ -753,7 +753,7 @@ namespace ICSharpCode.Decompiler.Ast } else if ((basePropDef.GetMethod ?? basePropDef.SetMethod).IsNewSlot) break; if (accessor.IsVirtual ^ !accessor.IsNewSlot) { - if (TypeMap.FindBaseProperties(propDef).Any()) + if (TypesHierarchyHelpers.FindBaseProperties(propDef).Any()) astProp.Modifiers |= Modifiers.New; } } @@ -1300,194 +1300,5 @@ namespace ICSharpCode.Decompiler.Ast return Tuple.Create(ca.ConstructorArguments.Single().Value as string, ca); return new Tuple(null, null); } - - - class TypeMap - { - public static IEnumerable 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 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 candidate, GenericContext 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 candidate, GenericContext 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 baseParameterType, GenericContext parameterType) - { - var baseParam = baseParameterType.Resolve(baseParameterType.Item.ParameterType); - var param = parameterType.Resolve(parameterType.Item.ParameterType); - return baseParam == param; - } - - private static IEnumerable> BaseTypes(TypeDefinition type) - { - return BaseTypes(CreateGenericContext(type)); - } - - private static IEnumerable> BaseTypes(GenericContext type) - { - while (type.Item.BaseType != null) { - var baseType = type.Item.BaseType; - var genericBaseType = baseType as GenericInstanceType; - if (genericBaseType != null) { - type = new GenericContext(genericBaseType.Resolve(), - genericBaseType.GenericArguments.Select(t => type.Resolve(t))); - } else - type = new GenericContext(baseType.Resolve()); - yield return type; - } - } - - private static GenericContext CreateGenericContext(TypeDefinition type) - { - return new GenericContext(type, type.GenericParameters); - } - - struct GenericContext - { - private static readonly ReadOnlyCollection Empty = new ReadOnlyCollection(new List()); - - public readonly T Item; - public readonly ReadOnlyCollection TypeArguments; - - public GenericContext(T item) - { - Item = item; - TypeArguments = Empty; - } - - public GenericContext(T item, IEnumerable typeArguments) - { - Item = item; - var list = new List(); - foreach (var arg in typeArguments) { - if (arg == null) - throw new ArgumentNullException("typeArguments"); - if (!arg.IsGenericParameter) - list.Add(arg.Resolve()); - else - list.Add(arg); - } - TypeArguments = new ReadOnlyCollection(list); - } - - private GenericContext(T item, ReadOnlyCollection 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]; - } - return type.Resolve(); - } - - public GenericContext ApplyTo(T2 item) - { - return new GenericContext(item, this.TypeArguments); - } - } - } } } diff --git a/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs b/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs new file mode 100644 index 000000000..48b635037 --- /dev/null +++ b/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs @@ -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 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 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 candidate, GenericContext 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 candidate, GenericContext 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 baseParameterType, GenericContext parameterType) + { + var baseParam = baseParameterType.Resolve(baseParameterType.Item.ParameterType); + var param = parameterType.Resolve(parameterType.Item.ParameterType); + return baseParam == param; + } + + private static IEnumerable> BaseTypes(TypeDefinition type) + { + return BaseTypes(CreateGenericContext(type)); + } + + private static IEnumerable> BaseTypes(GenericContext type) + { + while (type.Item.BaseType != null) { + var baseType = type.Item.BaseType; + var genericBaseType = baseType as GenericInstanceType; + if (genericBaseType != null) { + type = new GenericContext(genericBaseType.Resolve(), + genericBaseType.GenericArguments.Select(t => type.Resolve(t))); + } else + type = new GenericContext(baseType.Resolve()); + yield return type; + } + } + + private static GenericContext CreateGenericContext(TypeDefinition type) + { + return type.HasGenericParameters + ? new GenericContext(type, type.GenericParameters) + : new GenericContext(type); + } + + struct GenericContext + { + private static readonly ReadOnlyCollection Empty = new ReadOnlyCollection(new List()); + + public readonly T Item; + public readonly ReadOnlyCollection TypeArguments; + + public GenericContext(T item) + { + Item = item; + TypeArguments = Empty; + } + + public GenericContext(T item, IEnumerable typeArguments) + { + Item = item; + var list = new List(); + foreach (var arg in typeArguments) { + var resolved = arg != null ? arg.Resolve() : arg; + list.Add(resolved != null ? resolved : arg); + } + TypeArguments = new ReadOnlyCollection(list); + } + + private GenericContext(T item, ReadOnlyCollection 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 ApplyTo(T2 item) + { + return new GenericContext(item, this.TypeArguments); + } + } + } +} diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 0507c8fea..effdc610c 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -68,6 +68,7 @@ + diff --git a/ILSpy/ContextMenuEntry.cs b/ILSpy/ContextMenuEntry.cs index ddb616abf..ba86b487d 100644 --- a/ILSpy/ContextMenuEntry.cs +++ b/ILSpy/ContextMenuEntry.cs @@ -102,10 +102,12 @@ namespace ICSharpCode.ILSpy }; } if (entryPair.Value.IsEnabled(selectedNodes)) { - menuItem.Click += delegate { + menuItem.Click += delegate + { entry.Execute(selectedNodes); }; - } + } else + menuItem.IsEnabled = false; menu.Items.Add(menuItem); } } diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index d0a039257..636ebb9d9 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -129,6 +129,8 @@ + + README.txt diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs b/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs index 79edd30d5..c7c4e0266 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs @@ -34,7 +34,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public bool IsEnabled(SharpTreeNode[] selectedNodes) { foreach (IMemberTreeNode node in selectedNodes) { - if (!(node.Member is FieldDefinition || node.Member is MethodDefinition)) + if (!(node.Member is FieldDefinition + || node.Member is MethodDefinition + || Analyzer.AnalyzedPropertyTreeNode.CanShow(node.Member))) return false; } return true; @@ -51,6 +53,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer MethodDefinition method = node.Member as MethodDefinition; if (method != null) MainWindow.Instance.AddToAnalyzer(new AnalyzedMethodTreeNode(method)); + var propertyAnalyzer = Analyzer.AnalyzedPropertyTreeNode.TryCreateAnalyzer(node.Member); + if(propertyAnalyzer != null) + MainWindow.Instance.AddToAnalyzer(propertyAnalyzer); } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs index b919d6839..1108cfb07 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs @@ -24,12 +24,14 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer class AnalyzedMethodTreeNode : AnalyzerTreeNode, IMemberTreeNode { MethodDefinition analyzedMethod; + string prefix; - public AnalyzedMethodTreeNode(MethodDefinition analyzedMethod) + public AnalyzedMethodTreeNode(MethodDefinition analyzedMethod, string prefix = "") { if (analyzedMethod == null) throw new ArgumentNullException("analyzedMethod"); this.analyzedMethod = analyzedMethod; + this.prefix = prefix; this.LazyLoading = true; } @@ -38,7 +40,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer } public override object Text { - get { return Language.TypeToString(analyzedMethod.DeclaringType, true) + "." + MethodTreeNode.GetText(analyzedMethod, Language); } + get { + return prefix + Language.TypeToString(analyzedMethod.DeclaringType, true) + "." + MethodTreeNode.GetText(analyzedMethod, Language); } } public override void ActivateItem(System.Windows.RoutedEventArgs e) diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs new file mode 100644 index 000000000..b3e21b6e1 --- /dev/null +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs @@ -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 FetchChildren(CancellationToken ct) + { + return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct); + } + + IEnumerable 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 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; + } + } +} diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs new file mode 100644 index 000000000..cf3d80075 --- /dev/null +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs @@ -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); + } + } +} diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs index 709323e02..b3db85f3c 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs @@ -3,6 +3,7 @@ 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; @@ -17,11 +18,6 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer readonly MethodDefinition analyzedMethod; readonly ThreadingSupport threading; - /// - /// Controls whether overrides of already overriden method should be included. - /// - readonly bool onlyDirectOverrides = false; - public AnalyzerMethodOverridesTreeNode(MethodDefinition analyzedMethod) { if (analyzedMethod == null) @@ -77,127 +73,20 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { ct.ThrowIfCancellationRequested(); - if (!IsDerived(type, analyzedMethod.DeclaringType)) + if (!TypesHierarchyHelpers.IsBaseType(analyzedMethod.DeclaringType, type, resolveTypeArguments: false)) continue; foreach (MethodDefinition method in type.Methods) { ct.ThrowIfCancellationRequested(); - if (HasCompatibleSpecification(method) && !method.IsNewSlot && DoesOverrideCorrectMethod(method)) + if (TypesHierarchyHelpers.IsBaseMethod(analyzedMethod, method)) { - yield return new AnalyzedMethodTreeNode(method); + bool hidesParent = !method.IsVirtual ^ method.IsNewSlot; + yield return new AnalyzedMethodTreeNode(method, hidesParent ? "(hides) " : ""); } } } } - - /// - /// Tests whether the method could override analyzed method by comparing its name, return type and parameters. - /// - /// The method to test. - /// true if the method has the same specyfication as analyzed method, otherwise false. - private bool HasCompatibleSpecification(MethodDefinition method) - { - return method.Name == analyzedMethod.Name - && method.IsVirtual - && AreSameType(method.ReturnType, analyzedMethod.ReturnType) - && HaveTheSameParameters(method); - } - - /// - /// Checks whether between given and analyzed method are overrides with new (newSlot) modifier. - /// - /// The method to test. - /// true if the method overrides analyzed method, false if it overrides some other method that hides analyzed method. - private bool DoesOverrideCorrectMethod(MethodDefinition method) - { - var type = method.DeclaringType.BaseType.Resolve(); - while (type != analyzedMethod.DeclaringType) - { - var parentOverride = type.Methods.Where(m => HasCompatibleSpecification(m)).SingleOrDefault(); - if (parentOverride != null) - { - if (parentOverride.IsNewSlot) - return false; - else - return !onlyDirectOverrides; - } - type = type.BaseType.Resolve(); - } - return true; - } - - /// - /// Checks whether one type derives (directly or indirectly) from base type. - /// - /// The possible derived type. - /// The base type. - /// true if derives from , overwise false. - private static bool IsDerived(TypeDefinition derivedType, TypeDefinition baseType) - { - while (derivedType != null && derivedType.BaseType != null) - { - if (AreSameType(derivedType.BaseType, baseType)) - return true; - derivedType = derivedType.BaseType.Resolve(); - } - return false; - } - - /// - /// Checks whether both instances references the same type. - /// - /// The first type reference. - /// The second type reference. - /// true if both instances references the same type, overwise false. - private static bool AreSameType(TypeReference ref1, TypeReference ref2) - { - if (ref1 == ref2) - return true; - - if (ref1.Name != ref2.Name || ref1.FullName != ref2.FullName) - return false; - - return ref1.Resolve() == ref2.Resolve(); - } - - /// - /// Checkes whether the given method and the analyzed one has identical lists of parameters. - /// - /// The method to test. - /// true if both methods has the same parameters, otherwise false. - private bool HaveTheSameParameters(MethodDefinition method) - { - if (analyzedMethod.HasParameters) - { - return CompareParameterLists(analyzedMethod.Parameters, method.Parameters); - } - else - { - return !method.HasParameters; - } - } - - /// - /// Compares the list of method's parameters. - /// - /// The first list to compare. - /// The second list to copare. - /// true if both list have parameters of the same types at the same positions. - private static bool CompareParameterLists(Mono.Collections.Generic.Collection coll1, Mono.Collections.Generic.Collection coll2) - { - if (coll1.Count != coll2.Count) - return false; - - for (int index = 0; index < coll1.Count; index++) - { - var param1 = coll1[index]; - var param2 = coll2[index]; - if (param1.Attributes != param2.Attributes || !AreSameType(param1.ParameterType, param2.ParameterType)) - return false; - } - return true; - } } } diff --git a/ILSpy/TreeNodes/PropertyTreeNode.cs b/ILSpy/TreeNodes/PropertyTreeNode.cs index 466543bd6..1dbb7f049 100644 --- a/ILSpy/TreeNodes/PropertyTreeNode.cs +++ b/ILSpy/TreeNodes/PropertyTreeNode.cs @@ -17,6 +17,8 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Windows.Controls; +using System.Windows.Media.Imaging; using ICSharpCode.Decompiler; using Mono.Cecil; @@ -36,7 +38,6 @@ namespace ICSharpCode.ILSpy.TreeNodes throw new ArgumentNullException("property"); this.property = property; this.isIndexer = isIndexer; - if (property.GetMethod != null) this.Children.Add(new MethodTreeNode(property.GetMethod)); if (property.SetMethod != null) @@ -45,21 +46,32 @@ namespace ICSharpCode.ILSpy.TreeNodes foreach (var m in property.OtherMethods) this.Children.Add(new MethodTreeNode(m)); } + } - + public PropertyDefinition PropertyDefinition { get { return property; } } public override object Text { - get { return HighlightSearchMatch(property.Name, " : " + this.Language.TypeToString(property.PropertyType, false, property)); } + get { return GetText(property, Language); } } + public static object GetText(PropertyDefinition property, Language language) + { + return HighlightSearchMatch(property.Name, " : " + language.TypeToString(property.PropertyType, false, property)); + } + public override object Icon { get { - return isIndexer ? Images.Indexer : Images.Property; + return GetIcon(property, isIndexer); } } + + public static BitmapImage GetIcon(PropertyDefinition property, bool? isIndexer = null) + { + return (isIndexer ?? false) ? Images.Indexer : Images.Property; + } public override FilterResult Filter(FilterSettings settings) {