Browse Source

Added Event analysis.

pull/138/head
Ed Harvey 14 years ago
parent
commit
e86aee752d
  1. 52
      ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs
  2. 3
      ILSpy/ILSpy.csproj
  3. 6
      ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs
  4. 58
      ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorsTreeNode.cs
  5. 93
      ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs
  6. 81
      ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs
  7. 27
      ILSpy/TreeNodes/EventTreeNode.cs

52
ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs

@ -61,6 +61,14 @@ namespace ICSharpCode.Decompiler.Ast @@ -61,6 +61,14 @@ namespace ICSharpCode.Decompiler.Ast
return FindBaseProperties(childProperty).Any(m => m == parentProperty);
}
public static bool IsBaseEvent(EventDefinition parentEvent, EventDefinition childEvent)
{
if (parentEvent.Name != childEvent.Name)
return false;
return FindBaseEvents(childEvent).Any(m => m == parentEvent);
}
public static IEnumerable<MethodDefinition> FindBaseMethods(MethodDefinition method)
{
if (method == null)
@ -97,6 +105,25 @@ namespace ICSharpCode.Decompiler.Ast @@ -97,6 +105,25 @@ namespace ICSharpCode.Decompiler.Ast
}
public static IEnumerable<EventDefinition> FindBaseEvents(EventDefinition eventDef)
{
if (eventDef == null)
throw new ArgumentNullException("eventDef");
var typeContext = CreateGenericContext(eventDef.DeclaringType);
var gEvent = typeContext.ApplyTo(eventDef);
foreach (var baseType in BaseTypes(eventDef.DeclaringType))
foreach (var baseEvent in baseType.Item.Events)
if (MatchEvent(baseType.ApplyTo(baseEvent), gEvent) && IsVisbleFrom(baseEvent, eventDef)) {
yield return baseEvent;
var anyEventAccessor = baseEvent.AddMethod ?? baseEvent.RemoveMethod;
if (!(anyEventAccessor.IsNewSlot ^ anyEventAccessor.IsVirtual))
yield break;
}
}
private static bool IsVisbleFrom(MethodDefinition baseCandidate, MethodDefinition method)
{
if (baseCandidate.IsPrivate)
@ -115,6 +142,15 @@ namespace ICSharpCode.Decompiler.Ast @@ -115,6 +142,15 @@ namespace ICSharpCode.Decompiler.Ast
return false;
}
private static bool IsVisbleFrom(EventDefinition baseCandidate, EventDefinition eventDef)
{
if (baseCandidate.AddMethod != null && eventDef.AddMethod != null && IsVisbleFrom(baseCandidate.AddMethod, eventDef.AddMethod))
return true;
if (baseCandidate.RemoveMethod != null && eventDef.RemoveMethod != null && IsVisbleFrom(baseCandidate.RemoveMethod, eventDef.RemoveMethod))
return true;
return false;
}
private static bool MatchMethod(GenericContext<MethodDefinition> candidate, GenericContext<MethodDefinition> method)
{
var mCandidate = candidate.Item;
@ -172,6 +208,22 @@ namespace ICSharpCode.Decompiler.Ast @@ -172,6 +208,22 @@ namespace ICSharpCode.Decompiler.Ast
return true;
}
private static bool MatchEvent(GenericContext<EventDefinition> candidate, GenericContext<EventDefinition> ev)
{
var mCandidate = candidate.Item;
var mEvent = ev.Item;
if (mCandidate.Name != mEvent.Name)
return false;
if ((mCandidate.AddMethod ?? mCandidate.RemoveMethod).HasOverrides)
return false;
if (!IsSameType(candidate.ResolveWithContext(mCandidate.EventType), ev.ResolveWithContext(mEvent.EventType)))
return false;
return true;
}
private static bool MatchParameters(GenericContext<ParameterDefinition> baseParameterType, GenericContext<ParameterDefinition> parameterType)
{
var baseParam = baseParameterType.ResolveWithContext(baseParameterType.Item.ParameterType);

3
ILSpy/ILSpy.csproj

@ -131,6 +131,9 @@ @@ -131,6 +131,9 @@
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzeContextMenuEntry.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventAccessorsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventOverridesTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\Helpers.cs" />
<Compile Include="TreeNodes\Analyzer\ScopedWhereUsedAnalyzer.cs" />
<Compile Include="TreeNodes\IMemberTreeNode.cs" />

6
ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs

@ -36,7 +36,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -36,7 +36,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
foreach (IMemberTreeNode node in selectedNodes) {
if (!(node.Member is FieldDefinition
|| node.Member is MethodDefinition
|| Analyzer.AnalyzedPropertyTreeNode.CanShow(node.Member)))
|| Analyzer.AnalyzedPropertyTreeNode.CanShow(node.Member)
|| Analyzer.AnalyzedEventTreeNode.CanShow(node.Member)))
return false;
}
return true;
@ -56,6 +57,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -56,6 +57,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
var propertyAnalyzer = Analyzer.AnalyzedPropertyTreeNode.TryCreateAnalyzer(node.Member);
if(propertyAnalyzer != null)
MainWindow.Instance.AddToAnalyzer(propertyAnalyzer);
var eventAnalyzer = Analyzer.AnalyzedEventTreeNode.TryCreateAnalyzer(node.Member);
if (eventAnalyzer != null)
MainWindow.Instance.AddToAnalyzer(eventAnalyzer);
}
}
}

58
ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorsTreeNode.cs

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
using System;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
/// <summary>
/// Description of AnalyzedEventAccessorsTreeNode.
/// </summary>
public class AnalyzedEventAccessorsTreeNode : AnalyzerTreeNode
{
EventDefinition analyzedEvent;
public AnalyzedEventAccessorsTreeNode(EventDefinition analyzedEvent)
{
if (analyzedEvent == null)
throw new ArgumentNullException("analyzedEvent");
this.analyzedEvent = analyzedEvent;
if (analyzedEvent.AddMethod != null)
this.Children.Add(new AnalyzedEventAccessorTreeNode(analyzedEvent.AddMethod, "add"));
if (analyzedEvent.RemoveMethod != null)
this.Children.Add(new AnalyzedEventAccessorTreeNode(analyzedEvent.RemoveMethod, "remove"));
foreach (var accessor in analyzedEvent.OtherMethods)
this.Children.Add(new AnalyzedEventAccessorTreeNode(accessor, null));
}
public override object Icon
{
get { return Images.Search; }
}
public override object Text
{
get { return "Accessors"; }
}
public static bool CanShow(EventDefinition property)
{
return !MainWindow.Instance.CurrentLanguage.ShowMember(property.AddMethod ?? property.RemoveMethod);
}
class AnalyzedEventAccessorTreeNode : AnalyzedMethodTreeNode
{
string name;
public AnalyzedEventAccessorTreeNode(MethodDefinition analyzedMethod, string name)
: base(analyzedMethod)
{
this.name = name;
}
public override object Text
{
get { return name ?? base.Text; }
}
}
}
}

93
ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs

@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
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 AnalyzedEventOverridesTreeNode : AnalyzerTreeNode
{
readonly EventDefinition analyzedEvent;
readonly ThreadingSupport threading;
public AnalyzedEventOverridesTreeNode(EventDefinition analyzedEvent)
{
if (analyzedEvent == null)
throw new ArgumentNullException("analyzedEvent");
this.analyzedEvent = analyzedEvent;
this.threading = new ThreadingSupport();
this.LazyLoading = true;
}
public override object Text
{
get { return "Overriden 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.CurrentAssemblyList.GetAssemblies(), ct);
}
IEnumerable<SharpTreeNode> FindReferences(IEnumerable<LoadedAssembly> assemblies, CancellationToken ct)
{
assemblies = assemblies.Where(asm => asm.AssemblyDefinition != null);
// 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 = analyzedEvent.Name;
string declTypeName = analyzedEvent.DeclaringType.FullName;
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) {
ct.ThrowIfCancellationRequested();
if (!TypesHierarchyHelpers.IsBaseType(analyzedEvent.DeclaringType, type, resolveTypeArguments: false))
continue;
foreach (EventDefinition eventDef in type.Events) {
ct.ThrowIfCancellationRequested();
if (TypesHierarchyHelpers.IsBaseEvent(analyzedEvent, eventDef)) {
MethodDefinition anyAccessor = eventDef.AddMethod ?? eventDef.RemoveMethod;
bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot;
yield return new AnalyzedEventTreeNode(eventDef, hidesParent ? "(hides) " : "");
}
}
}
}
public static bool CanShowAnalyzer(EventDefinition property)
{
var accessor = property.AddMethod ?? property.RemoveMethod;
return accessor.IsVirtual && !accessor.IsFinal && !accessor.DeclaringType.IsInterface;
}
}
}

81
ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs

@ -0,0 +1,81 @@ @@ -0,0 +1,81 @@
// 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;
using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
class AnalyzedEventTreeNode : AnalyzerTreeNode
{
EventDefinition analyzedEvent;
string prefix;
public AnalyzedEventTreeNode(EventDefinition analyzedEvent, string prefix = "")
{
if (analyzedEvent == null)
throw new ArgumentNullException("analyzedMethod");
this.analyzedEvent = analyzedEvent;
this.prefix = prefix;
this.LazyLoading = true;
}
public override object Icon {
get { return EventTreeNode.GetIcon(analyzedEvent); }
}
public override object Text {
get {
// TODO: This way of formatting is not suitable for events which explicitly implement interfaces.
return prefix + Language.TypeToString(analyzedEvent.DeclaringType, true) + "." + EventTreeNode.GetText(analyzedEvent, Language); }
}
public override void ActivateItem(System.Windows.RoutedEventArgs e)
{
e.Handled = true;
MainWindow.Instance.JumpToReference(analyzedEvent);
}
protected override void LoadChildren()
{
if(AnalyzedEventAccessorsTreeNode.CanShow(analyzedEvent))
this.Children.Add(new AnalyzedEventAccessorsTreeNode(analyzedEvent));
if (AnalyzedEventOverridesTreeNode.CanShowAnalyzer(analyzedEvent))
this.Children.Add(new AnalyzedEventOverridesTreeNode(analyzedEvent));
}
public static AnalyzerTreeNode TryCreateAnalyzer(MemberReference member)
{
if (CanShow(member))
return new AnalyzedEventTreeNode(member as EventDefinition);
else
return null;
}
public static bool CanShow(MemberReference member)
{
var property = member as EventDefinition;
if (property == null)
return false;
return AnalyzedEventAccessorsTreeNode.CanShow(property)
|| AnalyzedEventOverridesTreeNode.CanShowAnalyzer(property);
}
}
}

27
ILSpy/TreeNodes/EventTreeNode.cs

@ -47,17 +47,33 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -47,17 +47,33 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
public EventDefinition EventDefinition {
public EventDefinition EventDefinition
{
get { return ev; }
}
public override object Text {
get { return HighlightSearchMatch(ev.Name, " : " + this.Language.TypeToString(ev.EventType, false, ev)); }
public override object Text
{
get { return GetText(ev, this.Language); }
}
public static object GetText(EventDefinition eventDef, Language language)
{
return HighlightSearchMatch(eventDef.Name, " : " + language.TypeToString(eventDef.EventType, false, eventDef));
}
public override object Icon
{
get { return Images.GetIcon(MemberIcon.Event, GetOverlayIcon(ev.AddMethod.Attributes), ev.AddMethod.IsStatic); }
get { return GetIcon(ev); }
}
public static object GetIcon(EventDefinition eventDef)
{
MethodDefinition accessor = eventDef.AddMethod ?? eventDef.RemoveMethod;
if (accessor != null)
return Images.GetIcon(MemberIcon.Event, GetOverlayIcon(eventDef.AddMethod.Attributes), eventDef.AddMethod.IsStatic);
else
return Images.GetIcon(MemberIcon.Event, AccessOverlayIcon.Public, false);
}
private static AccessOverlayIcon GetOverlayIcon(MethodAttributes methodAttributes)
@ -91,7 +107,8 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -91,7 +107,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
language.DecompileEvent(ev, output, options);
}
MemberReference IMemberTreeNode.Member {
MemberReference IMemberTreeNode.Member
{
get { return ev; }
}
}

Loading…
Cancel
Save