Browse Source

Added Type Analysis - Exposed BY, Instantiated BY, Extension Methods

pull/147/head
Ed Harvey 15 years ago
parent
commit
46e5a2afb9
  1. 4
      ILSpy/ILSpy.csproj
  2. 12
      ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs
  3. 188
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs
  4. 119
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs
  5. 116
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs
  6. 72
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs
  7. 2
      ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs

4
ILSpy/ILSpy.csproj

@ -135,6 +135,10 @@ @@ -135,6 +135,10 @@
<Compile Include="TreeNodes\Analyzer\AnalyzedEventAccessorsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventOverridesTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeExposedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeExtensionMethodsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeInstantiationsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\Helpers.cs" />
<Compile Include="TreeNodes\Analyzer\ScopedWhereUsedAnalyzer.cs" />
<Compile Include="TreeNodes\IMemberTreeNode.cs" />

12
ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs

@ -30,11 +30,12 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -30,11 +30,12 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
return selectedNodes.All(n => n is IMemberTreeNode);
}
public bool IsEnabled(SharpTreeNode[] selectedNodes)
{
foreach (IMemberTreeNode node in selectedNodes) {
if (!(node.Member is FieldDefinition
if (!(node.Member is TypeDefinition
|| node.Member is FieldDefinition
|| node.Member is MethodDefinition
|| Analyzer.AnalyzedPropertyTreeNode.CanShow(node.Member)
|| Analyzer.AnalyzedEventTreeNode.CanShow(node.Member)))
@ -42,12 +43,15 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -42,12 +43,15 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
}
return true;
}
public void Execute(SharpTreeNode[] selectedNodes)
{
// TODO: figure out when equivalent nodes are already present
// and focus those instead.
foreach (IMemberTreeNode node in selectedNodes) {
TypeDefinition type = node.Member as TypeDefinition;
if (type != null)
MainWindow.Instance.AddToAnalyzer(new AnalyzedTypeTreeNode(type));
FieldDefinition field = node.Member as FieldDefinition;
if (field != null)
MainWindow.Instance.AddToAnalyzer(new AnalyzedFieldNode(field));
@ -55,7 +59,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -55,7 +59,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
if (method != null)
MainWindow.Instance.AddToAnalyzer(new AnalyzedMethodTreeNode(method));
var propertyAnalyzer = Analyzer.AnalyzedPropertyTreeNode.TryCreateAnalyzer(node.Member);
if(propertyAnalyzer != null)
if (propertyAnalyzer != null)
MainWindow.Instance.AddToAnalyzer(propertyAnalyzer);
var eventAnalyzer = Analyzer.AnalyzedEventTreeNode.TryCreateAnalyzer(node.Member);
if (eventAnalyzer != null)

188
ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs

@ -0,0 +1,188 @@ @@ -0,0 +1,188 @@
// 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.Threading;
using ICSharpCode.TreeView;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
class AnalyzedTypeExposedByTreeNode : AnalyzerTreeNode
{
TypeDefinition analyzedType;
ThreadingSupport threading;
bool IsSystemObject;
public AnalyzedTypeExposedByTreeNode(TypeDefinition analyzedType)
{
if (analyzedType == null)
throw new ArgumentNullException("analyzedType");
this.analyzedType = analyzedType;
this.threading = new ThreadingSupport();
this.LazyLoading = true;
this.IsSystemObject = (analyzedType.FullName == "System.Object");
}
public override object Text
{
get { return "Exposed 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)
{
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedType, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
IEnumerable<SharpTreeNode> 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))
yield return new AnalyzedFieldNode(field);
}
foreach (PropertyDefinition property in type.Properties) {
if (TypeIsExposedBy(property))
yield return new AnalyzedPropertyTreeNode(property);
}
foreach (EventDefinition eventDef in type.Events) {
if (TypeIsExposedBy(eventDef))
yield return new AnalyzedEventTreeNode(eventDef);
}
foreach (MethodDefinition method in type.Methods) {
if (TypeIsExposedBy(method))
yield return new AnalyzedMethodTreeNode(method);
}
}
private bool TypeIsExposedBy(FieldDefinition field)
{
if (field.IsPrivate)
return false;
if (field.FieldType.Resolve() == analyzedType)
return true;
return false;
}
private bool TypeIsExposedBy(PropertyDefinition property)
{
if (IsPrivate(property))
return false;
if (property.PropertyType.Resolve() == analyzedType)
return true;
return false;
}
private bool TypeIsExposedBy(EventDefinition eventDef)
{
if (IsPrivate(eventDef))
return false;
if (eventDef.EventType.Resolve() == analyzedType)
return true;
return false;
}
private bool TypeIsExposedBy(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;
else if (!method.Overrides[0].DeclaringType.Resolve().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.SemanticsAttributes != MethodSemanticsAttributes.None)
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 bool IsPrivate(PropertyDefinition property)
{
bool isGetterPublic = (property.GetMethod != null && !property.GetMethod.IsPrivate);
bool isSetterPublic = (property.SetMethod != null && !property.SetMethod.IsPrivate);
return !(isGetterPublic || isSetterPublic);
}
private bool IsPrivate(EventDefinition eventDef)
{
bool isAdderPublic = (eventDef.AddMethod != null && !eventDef.AddMethod.IsPrivate);
bool isRemoverPublic = (eventDef.RemoveMethod != null && !eventDef.RemoveMethod.IsPrivate);
return !(isAdderPublic || isRemoverPublic);
}
public static bool CanShowAnalyzer(TypeDefinition type)
{
return true;
}
}
}

119
ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs

@ -0,0 +1,119 @@ @@ -0,0 +1,119 @@
// 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.TreeView;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
class AnalyzedTypeExtensionMethodsTreeNode : AnalyzerTreeNode
{
TypeDefinition analyzedType;
ThreadingSupport threading;
bool IsSystemObject;
public AnalyzedTypeExtensionMethodsTreeNode(TypeDefinition analyzedType)
{
if (analyzedType == null)
throw new ArgumentNullException("analyzedType");
this.analyzedType = analyzedType;
this.threading = new ThreadingSupport();
this.LazyLoading = true;
this.IsSystemObject = (analyzedType.FullName == "System.Object");
}
public override object Text
{
get { return "Extension Methods"; }
}
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)
{
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedType, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
{
foreach (MethodDefinition method in type.Methods) {
if (method.IsStatic && method.HasCustomAttributes) {
if (method.CustomAttributes.Any(ca => ca.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")) {
if (method.HasParameters && method.Parameters[0].ParameterType.Resolve() == analyzedType) {
yield return new AnalyzedMethodTreeNode(method);
}
}
}
}
}
private bool TypeIsExposedBy(MethodDefinition method)
{
if (method.IsPrivate)
return false;
// exclude methods with 'semantics'. for example, property getters & setters.
if (method.SemanticsAttributes != MethodSemanticsAttributes.None)
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;
}
public static bool CanShowAnalyzer(TypeDefinition type)
{
return !(type.IsEnum);
}
}
}

116
ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs

@ -0,0 +1,116 @@ @@ -0,0 +1,116 @@
// 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.Ast;
using ICSharpCode.TreeView;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
class AnalyzedTypeInstantiationsTreeNode : AnalyzerTreeNode
{
TypeDefinition analyzedType;
ThreadingSupport threading;
bool IsSystemObject;
public AnalyzedTypeInstantiationsTreeNode(TypeDefinition analyzedType)
{
if (analyzedType == null)
throw new ArgumentNullException("analyzedType");
this.analyzedType = analyzedType;
this.threading = new ThreadingSupport();
this.LazyLoading = true;
this.IsSystemObject = (analyzedType.FullName == "System.Object");
}
public override object Text
{
get { return "Instantiated 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)
{
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedType, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
{
foreach (MethodDefinition method in type.Methods) {
bool found = false;
if (!method.HasBody)
continue;
// ignore chained constructors
// (since object is the root of everything, we can short circuit the test in this case)
if (method.Name == ".ctor" &&
(IsSystemObject || analyzedType == type || TypesHierarchyHelpers.IsBaseType(analyzedType, type, false)))
continue;
foreach (Instruction instr in method.Body.Instructions) {
MethodReference mr = instr.Operand as MethodReference;
if (mr != null && mr.Name == ".ctor") {
if (Helpers.IsReferencedBy(analyzedType, mr.DeclaringType)) {
found = true;
break;
}
}
}
if (found)
yield return new AnalyzedMethodTreeNode(method);
}
}
public static bool CanShowAnalyzer(TypeDefinition type)
{
if (type.IsClass && !type.IsEnum) {
return type.Methods.Where(m => m.Name == ".ctor").Any(m => !m.IsPrivate);
}
return false;
}
}
}

72
ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs

@ -0,0 +1,72 @@ @@ -0,0 +1,72 @@
// 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 AnalyzedTypeTreeNode : AnalyzerTreeNode, IMemberTreeNode
{
TypeDefinition analyzedType;
public AnalyzedTypeTreeNode(TypeDefinition analyzedType)
{
if (analyzedType == null)
throw new ArgumentNullException("analyzedType");
this.analyzedType = analyzedType;
this.LazyLoading = true;
}
public override object Icon
{
get { return TypeTreeNode.GetIcon(analyzedType); }
}
public override object Text
{
get
{
return Language.TypeToString(analyzedType, true);
}
}
public override void ActivateItem(System.Windows.RoutedEventArgs e)
{
e.Handled = true;
MainWindow.Instance.JumpToReference(analyzedType);
}
protected override void LoadChildren()
{
if (AnalyzedTypeInstantiationsTreeNode.CanShowAnalyzer(analyzedType))
this.Children.Add(new AnalyzedTypeInstantiationsTreeNode(analyzedType));
if (AnalyzedTypeExposedByTreeNode.CanShowAnalyzer(analyzedType))
this.Children.Add(new AnalyzedTypeExposedByTreeNode(analyzedType));
if (AnalyzedTypeExtensionMethodsTreeNode.CanShowAnalyzer(analyzedType))
this.Children.Add(new AnalyzedTypeExtensionMethodsTreeNode(analyzedType));
}
MemberReference IMemberTreeNode.Member
{
get { return analyzedType; }
}
}
}

2
ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs

@ -21,7 +21,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -21,7 +21,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private Accessibility typeAccessibility = Accessibility.Public;
private Func<TypeDefinition, IEnumerable<T>> typeAnalysisFunction;
private ScopedWhereUsedScopeAnalyzer(TypeDefinition type, Func<TypeDefinition, IEnumerable<T>> typeAnalysisFunction)
public ScopedWhereUsedScopeAnalyzer(TypeDefinition type, Func<TypeDefinition, IEnumerable<T>> typeAnalysisFunction)
{
this.typeScope = type;
this.assemblyScope = type.Module.Assembly;

Loading…
Cancel
Save