Browse Source

Merge "Improved names of indexers in the tree view and analyzers bug fix"

pull/124/head
Daniel Grunwald 14 years ago
parent
commit
4912bef543
  1. 55
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 55
      ICSharpCode.Decompiler/CecilExtensions.cs
  3. 33
      ILSpy/CSharpLanguage.cs
  4. 7
      ILSpy/Language.cs
  5. 3
      ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessNode.cs
  6. 3
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs
  7. 3
      ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs
  8. 9
      ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs
  9. 3
      ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs
  10. 10
      ILSpy/TreeNodes/PropertyTreeNode.cs
  11. 10
      ILSpy/TreeNodes/TypeTreeNode.cs

55
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -168,7 +168,7 @@ namespace ICSharpCode.Decompiler.Ast
AstNode node = method.IsConstructor ? (AstNode)CreateConstructor(method) : CreateMethod(method); AstNode node = method.IsConstructor ? (AstNode)CreateConstructor(method) : CreateMethod(method);
astCompileUnit.AddChild(node, CompilationUnit.MemberRole); astCompileUnit.AddChild(node, CompilationUnit.MemberRole);
} }
public void AddProperty(PropertyDefinition property) public void AddProperty(PropertyDefinition property)
{ {
astCompileUnit.AddChild(CreateProperty(property), CompilationUnit.MemberRole); astCompileUnit.AddChild(CreateProperty(property), CompilationUnit.MemberRole);
@ -269,10 +269,9 @@ namespace ICSharpCode.Decompiler.Ast
foreach (var i in typeDef.Interfaces) foreach (var i in typeDef.Interfaces)
astType.AddChild(ConvertType(i), TypeDeclaration.BaseTypeRole); astType.AddChild(ConvertType(i), TypeDeclaration.BaseTypeRole);
AddTypeMembers(astType, typeDef); AddTypeMembers(astType, typeDef);
if (astType.Members.Any(m => m is IndexerDeclaration)) { if (astType.Members.OfType<IndexerDeclaration>().Any(idx => idx.PrivateImplementationType.IsNull)) {
// Remove the [DefaultMember] attribute if the class contains indexers // Remove the [DefaultMember] attribute if the class contains indexers
foreach (AttributeSection section in astType.Attributes) { foreach (AttributeSection section in astType.Attributes) {
foreach (Ast.Attribute attr in section.Attributes) { foreach (Ast.Attribute attr in section.Attributes) {
@ -775,39 +774,12 @@ namespace ICSharpCode.Decompiler.Ast
} }
ConvertCustomAttributes(astProp, propDef); ConvertCustomAttributes(astProp, propDef);
// Check whether the property is an indexer: if(propDef.IsIndexer())
if (propDef.HasParameters) { return ConvertPropertyToIndexer(astProp, propDef);
PropertyDefinition basePropDef = propDef; else
if (accessor.HasOverrides) { return astProp;
// if the property is explicitly implementing an interface, look up the property in the interface:
MethodDefinition baseAccessor = accessor.Overrides.First().Resolve();
if (baseAccessor != null) {
foreach (PropertyDefinition baseProp in baseAccessor.DeclaringType.Properties) {
if (baseProp.GetMethod == baseAccessor || baseProp.SetMethod == baseAccessor) {
basePropDef = baseProp;
break;
}
}
}
}
// figure out the name of the indexer:
string defaultMemberName = null;
var defaultMemberAttribute = basePropDef.DeclaringType.CustomAttributes.FirstOrDefault(IsDefaultMemberAttribute);
if (defaultMemberAttribute != null && defaultMemberAttribute.ConstructorArguments.Count == 1) {
defaultMemberName = defaultMemberAttribute.ConstructorArguments[0].Value as string;
}
if (basePropDef.Name == defaultMemberName) {
return ConvertPropertyToIndexer(astProp, propDef);
}
}
return astProp;
} }
bool IsDefaultMemberAttribute(CustomAttribute ca)
{
return ca.AttributeType.Name == "DefaultMemberAttribute" && ca.AttributeType.Namespace == "System.Reflection";
}
IndexerDeclaration ConvertPropertyToIndexer(PropertyDeclaration astProp, PropertyDefinition propDef) IndexerDeclaration ConvertPropertyToIndexer(PropertyDeclaration astProp, PropertyDefinition propDef)
{ {
var astIndexer = new IndexerDeclaration(); var astIndexer = new IndexerDeclaration();
@ -1313,18 +1285,5 @@ namespace ICSharpCode.Decompiler.Ast
return type.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.FlagsAttribute"); return type.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.FlagsAttribute");
} }
/// <summary>
/// Gets the name of the default member of the type pointed by the <see cref="System.Reflection.DefaultMemberAttribute"/> attribute.
/// </summary>
/// <param name="type">The type definition.</param>
/// <returns>The name of the default member or null if no <see cref="System.Reflection.DefaultMemberAttribute"/> attribute has been found.</returns>
private static Tuple<string, CustomAttribute> GetDefaultMember(TypeDefinition type)
{
foreach (CustomAttribute ca in type.CustomAttributes)
if (ca.Constructor.FullName == "System.Void System.Reflection.DefaultMemberAttribute::.ctor(System.String)")
return Tuple.Create(ca.ConstructorArguments.Single().Value as string, ca);
return new Tuple<string,CustomAttribute>(null, null);
}
} }
} }

55
ICSharpCode.Decompiler/CecilExtensions.cs

@ -18,6 +18,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
@ -234,5 +235,59 @@ namespace ICSharpCode.Decompiler
else else
return false; return false;
} }
public static string GetDefaultMemberName(this TypeDefinition type)
{
CustomAttribute attr;
return type.GetDefaultMemberName(out attr);
}
public static string GetDefaultMemberName(this TypeDefinition type, out CustomAttribute defaultMemberAttribute)
{
if (type.HasCustomAttributes)
foreach (CustomAttribute ca in type.CustomAttributes)
if (ca.Constructor.DeclaringType.Name == "DefaultMemberAttribute" && ca.Constructor.DeclaringType.Namespace == "System.Reflection"
&& ca.Constructor.FullName == @"System.Void System.Reflection.DefaultMemberAttribute::.ctor(System.String)") {
defaultMemberAttribute = ca;
return ca.ConstructorArguments[0].Value as string;
}
defaultMemberAttribute = null;
return null;
}
public static bool IsIndexer(this PropertyDefinition property)
{
CustomAttribute attr;
return property.IsIndexer(out attr);
}
public static bool IsIndexer(this PropertyDefinition property, out CustomAttribute defaultMemberAttribute)
{
defaultMemberAttribute = null;
if (property.HasParameters) {
var accessor = property.GetMethod ?? property.SetMethod;
PropertyDefinition basePropDef = property;
if (accessor.HasOverrides) {
// if the property is explicitly implementing an interface, look up the property in the interface:
MethodDefinition baseAccessor = accessor.Overrides.First().Resolve();
if (baseAccessor != null) {
foreach (PropertyDefinition baseProp in baseAccessor.DeclaringType.Properties) {
if (baseProp.GetMethod == baseAccessor || baseProp.SetMethod == baseAccessor) {
basePropDef = baseProp;
break;
}
}
} else
return false;
}
CustomAttribute attr;
var defaultMemberName = basePropDef.DeclaringType.GetDefaultMemberName(out attr);
if (defaultMemberName == basePropDef.Name) {
defaultMemberAttribute = attr;
return true;
}
}
return false;
}
} }
} }

33
ILSpy/CSharpLanguage.cs

@ -418,7 +418,38 @@ namespace ICSharpCode.ILSpy
astType.AcceptVisitor(new OutputVisitor(w, new CSharpFormattingPolicy()), null); astType.AcceptVisitor(new OutputVisitor(w, new CSharpFormattingPolicy()), null);
return w.ToString(); return w.ToString();
} }
public override string FormatPropertyName(PropertyDefinition property, bool? isIndexer)
{
if (property == null)
throw new ArgumentNullException("property");
if (!isIndexer.HasValue) {
isIndexer = property.IsIndexer();
}
if (isIndexer.Value) {
var buffer = new System.Text.StringBuilder();
var accessor = property.GetMethod ?? property.SetMethod;
if (accessor.HasOverrides) {
var declaringType = accessor.Overrides.First().DeclaringType;
buffer.Append(TypeToString(declaringType, includeNamespace: true));
buffer.Append(@".");
}
buffer.Append(@"this[");
bool addSeparator = false;
foreach (var p in property.Parameters) {
if (addSeparator)
buffer.Append(@", ");
else
addSeparator = true;
buffer.Append(TypeToString(p.ParameterType, includeNamespace: true));
}
buffer.Append(@"]");
return buffer.ToString();
} else
return property.Name;
}
public override bool ShowMember(MemberReference member) public override bool ShowMember(MemberReference member)
{ {
return showAllMembers || !AstBuilder.MemberIsHidden(member, new DecompilationOptions().DecompilerSettings); return showAllMembers || !AstBuilder.MemberIsHidden(member, new DecompilationOptions().DecompilerSettings);

7
ILSpy/Language.cs

@ -105,6 +105,13 @@ namespace ICSharpCode.ILSpy
else else
return type.Name; return type.Name;
} }
public virtual string FormatPropertyName(PropertyDefinition property, bool? isIndexer = null)
{
if (property == null)
throw new ArgumentNullException("property");
return property.Name;
}
/// <summary> /// <summary>
/// Used for WPF keyboard navigation. /// Used for WPF keyboard navigation.

3
ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessNode.cs

@ -57,8 +57,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct); return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct);
} }
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly[] assemblies, CancellationToken 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) // use parallelism only on the assembly level (avoid locks within Cecil)
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct)); return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
} }

3
ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs

@ -70,8 +70,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct); return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct);
} }
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly[] assemblies, CancellationToken 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) // use parallelism only on the assembly level (avoid locks within Cecil)
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct)); return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
} }

3
ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs

@ -54,8 +54,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct); return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct);
} }
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly[] assemblies, CancellationToken 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) // use parallelism only on the assembly level (avoid locks within Cecil)
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct)); return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
} }

9
ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs

@ -18,31 +18,34 @@
using System; using System;
using Mono.Cecil; using Mono.Cecil;
using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
class AnalyzedPropertyTreeNode : AnalyzerTreeNode class AnalyzedPropertyTreeNode : AnalyzerTreeNode
{ {
PropertyDefinition analyzedProperty; PropertyDefinition analyzedProperty;
bool isIndexer;
string prefix; string prefix;
public AnalyzedPropertyTreeNode(PropertyDefinition analyzedProperty, string prefix = "") public AnalyzedPropertyTreeNode(PropertyDefinition analyzedProperty, string prefix = "")
{ {
if (analyzedProperty == null) if (analyzedProperty == null)
throw new ArgumentNullException("analyzedMethod"); throw new ArgumentNullException("analyzedMethod");
this.isIndexer = analyzedProperty.IsIndexer();
this.analyzedProperty = analyzedProperty; this.analyzedProperty = analyzedProperty;
this.prefix = prefix; this.prefix = prefix;
this.LazyLoading = true; this.LazyLoading = true;
} }
public override object Icon { public override object Icon {
get { return PropertyTreeNode.GetIcon(analyzedProperty); } get { return PropertyTreeNode.GetIcon(analyzedProperty, isIndexer); }
} }
public override object Text { public override object Text {
get { get {
return prefix + Language.TypeToString(analyzedProperty.DeclaringType, true) + "." + PropertyTreeNode.GetText(analyzedProperty, Language); } // TODO: This way of formatting is not suitable for properties which explicitly implement interfaces.
return prefix + Language.TypeToString(analyzedProperty.DeclaringType, true) + "." + PropertyTreeNode.GetText(analyzedProperty, Language, isIndexer); }
} }
public override void ActivateItem(System.Windows.RoutedEventArgs e) public override void ActivateItem(System.Windows.RoutedEventArgs e)

3
ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs

@ -58,8 +58,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct); return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct);
} }
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly[] assemblies, CancellationToken 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) // use parallelism only on the assembly level (avoid locks within Cecil)
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct)); return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
} }

10
ILSpy/TreeNodes/PropertyTreeNode.cs

@ -31,12 +31,12 @@ namespace ICSharpCode.ILSpy.TreeNodes
readonly PropertyDefinition property; readonly PropertyDefinition property;
readonly bool isIndexer; readonly bool isIndexer;
public PropertyTreeNode(PropertyDefinition property, bool isIndexer) public PropertyTreeNode(PropertyDefinition property)
{ {
if (property == null) if (property == null)
throw new ArgumentNullException("property"); throw new ArgumentNullException("property");
this.property = property; this.property = property;
this.isIndexer = isIndexer; this.isIndexer = property.IsIndexer();
if (property.GetMethod != null) if (property.GetMethod != null)
this.Children.Add(new MethodTreeNode(property.GetMethod)); this.Children.Add(new MethodTreeNode(property.GetMethod));
@ -55,12 +55,12 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override object Text public override object Text
{ {
get { return GetText(property, Language); } get { return GetText(property, Language, isIndexer); }
} }
public static object GetText(PropertyDefinition property, Language language) public static object GetText(PropertyDefinition property, Language language, bool? isIndexer = null)
{ {
return HighlightSearchMatch(property.Name, " : " + language.TypeToString(property.PropertyType, false, property)); return HighlightSearchMatch(language.FormatPropertyName(property, isIndexer), " : " + language.TypeToString(property.PropertyType, false, property));
} }
public override object Icon public override object Icon

10
ILSpy/TreeNodes/TypeTreeNode.cs

@ -103,16 +103,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
this.Children.Add(new FieldTreeNode(field)); this.Children.Add(new FieldTreeNode(field));
} }
// figure out the name of the indexer:
string defaultMemberName = null;
var defaultMemberAttribute = type.CustomAttributes.FirstOrDefault(
a => a.AttributeType.FullName == typeof(System.Reflection.DefaultMemberAttribute).FullName);
if (defaultMemberAttribute != null && defaultMemberAttribute.ConstructorArguments.Count == 1) {
defaultMemberName = defaultMemberAttribute.ConstructorArguments[0].Value as string;
}
foreach (PropertyDefinition property in type.Properties.OrderBy(m => m.Name)) { foreach (PropertyDefinition property in type.Properties.OrderBy(m => m.Name)) {
this.Children.Add(new PropertyTreeNode(property, property.Name == defaultMemberName)); this.Children.Add(new PropertyTreeNode(property));
} }
foreach (EventDefinition ev in type.Events.OrderBy(m => m.Name)) { foreach (EventDefinition ev in type.Events.OrderBy(m => m.Name)) {
this.Children.Add(new EventTreeNode(ev)); this.Children.Add(new EventTreeNode(ev));

Loading…
Cancel
Save