Skip to content

Commit

Permalink
Added Type Analysis - Exposed BY, Instantiated BY, Extension Methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Ed Harvey committed Apr 27, 2011
1 parent 70ee261 commit 46e5a2a
Show file tree
Hide file tree
Showing 7 changed files with 508 additions and 5 deletions.
4 changes: 4 additions & 0 deletions ILSpy/ILSpy.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down
12 changes: 8 additions & 4 deletions ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,36 @@ public bool IsVisible(SharpTreeNode[] selectedNodes)
{
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)))
return false;
}
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));
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)
if (propertyAnalyzer != null)
MainWindow.Instance.AddToAnalyzer(propertyAnalyzer);
var eventAnalyzer = Analyzer.AnalyzedEventTreeNode.TryCreateAnalyzer(node.Member);
if (eventAnalyzer != null)
Expand Down
188 changes: 188 additions & 0 deletions ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs
Original file line number Diff line number Diff line change
@@ -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 changes: 119 additions & 0 deletions ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs
Original file line number Diff line number Diff line change
@@ -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);
}

}
}
Loading

0 comments on commit 46e5a2a

Please sign in to comment.