Browse Source

support for specifying the type of the search directly in the textbox (t: for type, m: for member and c: for constant)

for instance, t:MyType will search for types matching "MyType"  (match behavior did not change)
pull/481/head
Adriano Carlos Verona 11 years ago
parent
commit
530c31608e
  1. 637
      ILSpy/SearchPane.cs

637
ILSpy/SearchPane.cs

@ -20,7 +20,6 @@ using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
using System.IO;
using System.Threading; using System.Threading;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
@ -53,9 +52,9 @@ namespace ICSharpCode.ILSpy
} }
} }
const int SearchMode_Type = 0; public const int SearchMode_Type = 0;
const int SearchMode_Member = 1; public const int SearchMode_Member = 1;
const int SearchMode_Literal = 2; public const int SearchMode_Literal = 2;
private SearchPane() private SearchPane()
{ {
@ -183,7 +182,12 @@ namespace ICSharpCode.ILSpy
listBox.SelectedIndex = 0; listBox.SelectedIndex = 0;
} }
} }
internal interface ISearch
{
void Search(TypeDefinition type, Language language, Action<SearchResult> addResult);
}
sealed class RunningSearch sealed class RunningSearch
{ {
readonly Dispatcher dispatcher; readonly Dispatcher dispatcher;
@ -195,9 +199,6 @@ namespace ICSharpCode.ILSpy
public readonly ObservableCollection<SearchResult> Results = new ObservableCollection<SearchResult>(); public readonly ObservableCollection<SearchResult> Results = new ObservableCollection<SearchResult>();
int resultCount; int resultCount;
TypeCode searchTermLiteralType = TypeCode.Empty;
object searchTermLiteralValue;
public RunningSearch(LoadedAssembly[] assemblies, string searchTerm, int searchMode, Language language) public RunningSearch(LoadedAssembly[] assemblies, string searchTerm, int searchMode, Language language)
{ {
this.dispatcher = Dispatcher.CurrentDispatcher; this.dispatcher = Dispatcher.CurrentDispatcher;
@ -217,44 +218,17 @@ namespace ICSharpCode.ILSpy
public void Run() public void Run()
{ {
try { try {
if (searchMode == SearchMode_Literal) { var searcher = ResolveSearcher(searchMode, searchTerm);
if (1 == searchTerm.Length) foreach (var loadedAssembly in assemblies)
{ {
CSharpParser parser = new CSharpParser();
PrimitiveExpression pe = parser.ParseExpression(searchTerm[0]) as PrimitiveExpression;
if (pe != null && pe.Value != null) {
TypeCode peValueType = Type.GetTypeCode(pe.Value.GetType());
switch (peValueType) {
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
searchTermLiteralType = TypeCode.Int64;
searchTermLiteralValue = CSharpPrimitiveCast.Cast(TypeCode.Int64, pe.Value, false);
break;
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.String:
searchTermLiteralType = peValueType;
searchTermLiteralValue = pe.Value;
break;
}
}
}
}
foreach (var loadedAssembly in assemblies) {
ModuleDefinition module = loadedAssembly.ModuleDefinition; ModuleDefinition module = loadedAssembly.ModuleDefinition;
if (module == null) if (module == null)
continue; continue;
CancellationToken cancellationToken = cts.Token; CancellationToken cancellationToken = cts.Token;
foreach (TypeDefinition type in module.Types) { foreach (TypeDefinition type in module.Types) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
PerformSearch(type); searcher.Search(type, language, AddResult);
} }
} }
} catch (OperationCanceledException) { } catch (OperationCanceledException) {
@ -277,254 +251,401 @@ namespace ICSharpCode.ILSpy
new Action(delegate { this.Results.Insert(this.Results.Count - 1, result); })); new Action(delegate { this.Results.Insert(this.Results.Count - 1, result); }));
cts.Token.ThrowIfCancellationRequested(); cts.Token.ThrowIfCancellationRequested();
} }
bool IsMatch(string text) private ISearch ResolveSearcher(int mode, string[] terms)
{ {
for (int i = 0; i < searchTerm.Length; ++i) { if (terms.Length == 1)
// How to handle overlapping matches? {
if (text.IndexOf(searchTerm[i], StringComparison.OrdinalIgnoreCase) < 0) if (terms[0].StartsWith("t:"))
return false; return new TypeSearcher(terms);
}
return true; if (terms[0].StartsWith("m:"))
return new MemberSearcher(terms);
if (terms[0].StartsWith("c:"))
return new LiteralSearcher(terms);
}
switch (mode)
{
case SearchMode_Type: return new TypeSearcher(terms);
case SearchMode_Member: return new MemberSearcher(terms);
case SearchMode_Literal: return new LiteralSearcher(terms);
}
return null;
}
}
internal sealed class SearchResult : INotifyPropertyChanged, IMemberTreeNode
{
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged {
add { }
remove { }
} }
void PerformSearch(TypeDefinition type) public MemberReference Member { get; set; }
public string Location { get; set; }
public string Name { get; set; }
public ImageSource Image { get; set; }
public ImageSource LocationImage { get; set; }
public override string ToString()
{ {
if (searchMode == SearchMode_Type && IsMatch(type.Name)) { return Name;
AddResult(new SearchResult { }
Member = type, }
Image = TypeTreeNode.GetIcon(type), }
Name = language.TypeToString(type, includeNamespace: false),
LocationImage = type.DeclaringType != null ? TypeTreeNode.GetIcon(type.DeclaringType) : Images.Namespace, internal class LiteralSearcher : SearcherBase
Location = type.DeclaringType != null ? language.TypeToString(type.DeclaringType, includeNamespace: true) : type.Namespace {
}); private readonly TypeCode searchTermLiteralType;
} private readonly object searchTermLiteralValue;
foreach (TypeDefinition nestedType in type.NestedTypes) { public LiteralSearcher(string[] terms) : base(terms)
PerformSearch(nestedType); {
} if (1 == searchTerm.Length)
{
if (searchMode == SearchMode_Type) var parser = new CSharpParser();
return; var pe = parser.ParseExpression(searchTerm[0]) as PrimitiveExpression;
foreach (FieldDefinition field in type.Fields) { if (pe != null && pe.Value != null)
if (IsMatch(field)) { {
AddResult(new SearchResult { TypeCode peValueType = Type.GetTypeCode(pe.Value.GetType());
Member = field, switch (peValueType)
Image = FieldTreeNode.GetIcon(field), {
Name = field.Name, case TypeCode.Byte:
LocationImage = TypeTreeNode.GetIcon(type), case TypeCode.SByte:
Location = language.TypeToString(type, includeNamespace: true) case TypeCode.Int16:
}); case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
searchTermLiteralType = TypeCode.Int64;
searchTermLiteralValue = CSharpPrimitiveCast.Cast(TypeCode.Int64, pe.Value, false);
break;
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.String:
searchTermLiteralType = peValueType;
searchTermLiteralValue = pe.Value;
break;
} }
} }
foreach (PropertyDefinition property in type.Properties) { }
if (IsMatch(property)) { }
AddResult(new SearchResult {
Member = property, protected override bool IsMatch(FieldDefinition field)
Image = PropertyTreeNode.GetIcon(property), {
Name = property.Name, return IsLiteralMatch(field.Constant);
LocationImage = TypeTreeNode.GetIcon(type), }
Location = language.TypeToString(type, includeNamespace: true)
}); protected override bool IsMatch(PropertyDefinition property)
{
return MethodIsLiteralMatch(property.GetMethod) || MethodIsLiteralMatch(property.SetMethod);
}
protected override bool IsMatch(EventDefinition ev)
{
return MethodIsLiteralMatch(ev.AddMethod) || MethodIsLiteralMatch(ev.RemoveMethod) || MethodIsLiteralMatch(ev.InvokeMethod);
}
protected override bool IsMatch(MethodDefinition m)
{
return MethodIsLiteralMatch(m);
}
bool IsLiteralMatch(object val)
{
if (val == null)
return false;
switch (searchTermLiteralType)
{
case TypeCode.Int64:
TypeCode tc = Type.GetTypeCode(val.GetType());
if (tc >= TypeCode.SByte && tc <= TypeCode.UInt64)
return CSharpPrimitiveCast.Cast(TypeCode.Int64, val, false).Equals(searchTermLiteralValue);
else
return false;
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.String:
return searchTermLiteralValue.Equals(val);
default:
// substring search with searchTerm
return IsMatch(val.ToString());
}
}
bool MethodIsLiteralMatch(MethodDefinition m)
{
if (m == null)
return false;
var body = m.Body;
if (body == null)
return false;
if (searchTermLiteralType == TypeCode.Int64)
{
long val = (long)searchTermLiteralValue;
foreach (var inst in body.Instructions)
{
switch (inst.OpCode.Code)
{
case Code.Ldc_I8:
if (val == (long)inst.Operand)
return true;
break;
case Code.Ldc_I4:
if (val == (int)inst.Operand)
return true;
break;
case Code.Ldc_I4_S:
if (val == (sbyte)inst.Operand)
return true;
break;
case Code.Ldc_I4_M1:
if (val == -1)
return true;
break;
case Code.Ldc_I4_0:
if (val == 0)
return true;
break;
case Code.Ldc_I4_1:
if (val == 1)
return true;
break;
case Code.Ldc_I4_2:
if (val == 2)
return true;
break;
case Code.Ldc_I4_3:
if (val == 3)
return true;
break;
case Code.Ldc_I4_4:
if (val == 4)
return true;
break;
case Code.Ldc_I4_5:
if (val == 5)
return true;
break;
case Code.Ldc_I4_6:
if (val == 6)
return true;
break;
case Code.Ldc_I4_7:
if (val == 7)
return true;
break;
case Code.Ldc_I4_8:
if (val == 8)
return true;
break;
} }
} }
foreach (EventDefinition ev in type.Events) { }
if (IsMatch(ev)) { else if (searchTermLiteralType != TypeCode.Empty)
AddResult(new SearchResult { {
Member = ev, Code expectedCode;
Image = EventTreeNode.GetIcon(ev), switch (searchTermLiteralType)
Name = ev.Name, {
LocationImage = TypeTreeNode.GetIcon(type), case TypeCode.Single:
Location = language.TypeToString(type, includeNamespace: true) expectedCode = Code.Ldc_R4;
}); break;
} case TypeCode.Double:
expectedCode = Code.Ldc_R8;
break;
case TypeCode.String:
expectedCode = Code.Ldstr;
break;
default:
throw new InvalidOperationException();
} }
foreach (MethodDefinition method in type.Methods) { foreach (var inst in body.Instructions)
switch (method.SemanticsAttributes) { {
case MethodSemanticsAttributes.Setter: if (inst.OpCode.Code == expectedCode && searchTermLiteralValue.Equals(inst.Operand))
case MethodSemanticsAttributes.Getter: return true;
case MethodSemanticsAttributes.AddOn:
case MethodSemanticsAttributes.RemoveOn:
case MethodSemanticsAttributes.Fire:
continue;
}
if (IsMatch(method)) {
AddResult(new SearchResult {
Member = method,
Image = MethodTreeNode.GetIcon(method),
Name = method.Name,
LocationImage = TypeTreeNode.GetIcon(type),
Location = language.TypeToString(type, includeNamespace: true)
});
}
} }
} }
else
bool IsMatch(FieldDefinition field)
{ {
if (searchMode == SearchMode_Literal) foreach (var inst in body.Instructions)
return IsLiteralMatch(field.Constant); {
else if (inst.OpCode.Code == Code.Ldstr && IsMatch((string)inst.Operand))
return IsMatch(field.Name); return true;
}
} }
return false;
bool IsMatch(PropertyDefinition property) }
}
internal class MemberSearcher : SearcherBase
{
public MemberSearcher(string[] terms) : base(terms)
{
}
protected override bool IsMatch(FieldDefinition field)
{
return IsMatch(field.Name);
}
protected override bool IsMatch(PropertyDefinition property)
{
return IsMatch(property.Name);
}
protected override bool IsMatch(EventDefinition ev)
{
return IsMatch(ev.Name);
}
protected override bool IsMatch(MethodDefinition m)
{
return IsMatch(m.Name);
}
}
internal abstract class SearcherBase : SearchPane.ISearch
{
protected string[] searchTerm;
protected SearcherBase(string[] terms)
{
if (terms.Length == 1 && terms[0].Length > 2 && terms[0][1] == ':')
terms[0] = terms[0].Substring(2);
searchTerm = terms;
}
protected bool IsMatch(string text)
{
for (int i = 0; i < searchTerm.Length; ++i)
{ {
if (searchMode == SearchMode_Literal) // How to handle overlapping matches?
return MethodIsLiteralMatch(property.GetMethod) || MethodIsLiteralMatch(property.SetMethod); if (text.IndexOf(searchTerm[i], StringComparison.OrdinalIgnoreCase) < 0)
else return false;
return IsMatch(property.Name);
} }
return true;
bool IsMatch(EventDefinition ev) }
protected virtual bool IsMatch(FieldDefinition field)
{
return false;
}
protected virtual bool IsMatch(PropertyDefinition property)
{
return false;
}
protected virtual bool IsMatch(EventDefinition ev)
{
return false;
}
protected virtual bool IsMatch(MethodDefinition m)
{
return false;
}
public virtual void Search(TypeDefinition type, Language language, Action<SearchPane.SearchResult> addResult)
{
foreach (FieldDefinition field in type.Fields)
{ {
if (searchMode == SearchMode_Literal) if (IsMatch(field))
return MethodIsLiteralMatch(ev.AddMethod) || MethodIsLiteralMatch(ev.RemoveMethod) || MethodIsLiteralMatch(ev.InvokeMethod); {
else addResult(new SearchPane.SearchResult
return IsMatch(ev.Name); {
Member = field,
Image = FieldTreeNode.GetIcon(field),
Name = field.Name,
LocationImage = TypeTreeNode.GetIcon(type),
Location = language.TypeToString(type, includeNamespace: true)
});
}
} }
foreach (PropertyDefinition property in type.Properties)
bool IsMatch(MethodDefinition m)
{ {
if (searchMode == SearchMode_Literal) if (IsMatch(property))
return MethodIsLiteralMatch(m); {
else addResult(new SearchPane.SearchResult
return IsMatch(m.Name); {
Member = property,
Image = PropertyTreeNode.GetIcon(property),
Name = property.Name,
LocationImage = TypeTreeNode.GetIcon(type),
Location = language.TypeToString(type, includeNamespace: true)
});
}
} }
foreach (EventDefinition ev in type.Events)
bool IsLiteralMatch(object val)
{ {
if (val == null) if (IsMatch(ev))
return false; {
switch (searchTermLiteralType) { addResult(new SearchPane.SearchResult
case TypeCode.Int64: {
TypeCode tc = Type.GetTypeCode(val.GetType()); Member = ev,
if (tc >= TypeCode.SByte && tc <= TypeCode.UInt64) Image = EventTreeNode.GetIcon(ev),
return CSharpPrimitiveCast.Cast(TypeCode.Int64, val, false).Equals(searchTermLiteralValue); Name = ev.Name,
else LocationImage = TypeTreeNode.GetIcon(type),
return false; Location = language.TypeToString(type, includeNamespace: true)
case TypeCode.Single: });
case TypeCode.Double:
case TypeCode.String:
return searchTermLiteralValue.Equals(val);
default:
// substring search with searchTerm
return IsMatch(val.ToString());
} }
} }
foreach (MethodDefinition method in type.Methods)
bool MethodIsLiteralMatch(MethodDefinition m)
{ {
if (m == null) switch (method.SemanticsAttributes)
return false; {
var body = m.Body; case MethodSemanticsAttributes.Setter:
if (body == null) case MethodSemanticsAttributes.Getter:
return false; case MethodSemanticsAttributes.AddOn:
if (searchTermLiteralType == TypeCode.Int64) { case MethodSemanticsAttributes.RemoveOn:
long val = (long)searchTermLiteralValue; case MethodSemanticsAttributes.Fire:
foreach (var inst in body.Instructions) { continue;
switch (inst.OpCode.Code) { }
case Code.Ldc_I8: if (IsMatch(method))
if (val == (long)inst.Operand) {
return true; addResult(new SearchPane.SearchResult
break; {
case Code.Ldc_I4: Member = method,
if (val == (int)inst.Operand) Image = MethodTreeNode.GetIcon(method),
return true; Name = method.Name,
break; LocationImage = TypeTreeNode.GetIcon(type),
case Code.Ldc_I4_S: Location = language.TypeToString(type, includeNamespace: true)
if (val == (sbyte)inst.Operand) });
return true;
break;
case Code.Ldc_I4_M1:
if (val == -1)
return true;
break;
case Code.Ldc_I4_0:
if (val == 0)
return true;
break;
case Code.Ldc_I4_1:
if (val == 1)
return true;
break;
case Code.Ldc_I4_2:
if (val == 2)
return true;
break;
case Code.Ldc_I4_3:
if (val == 3)
return true;
break;
case Code.Ldc_I4_4:
if (val == 4)
return true;
break;
case Code.Ldc_I4_5:
if (val == 5)
return true;
break;
case Code.Ldc_I4_6:
if (val == 6)
return true;
break;
case Code.Ldc_I4_7:
if (val == 7)
return true;
break;
case Code.Ldc_I4_8:
if (val == 8)
return true;
break;
}
}
} else if (searchTermLiteralType != TypeCode.Empty) {
Code expectedCode;
switch (searchTermLiteralType) {
case TypeCode.Single:
expectedCode = Code.Ldc_R4;
break;
case TypeCode.Double:
expectedCode = Code.Ldc_R8;
break;
case TypeCode.String:
expectedCode = Code.Ldstr;
break;
default:
throw new InvalidOperationException();
}
foreach (var inst in body.Instructions) {
if (inst.OpCode.Code == expectedCode && searchTermLiteralValue.Equals(inst.Operand))
return true;
}
} else {
foreach (var inst in body.Instructions) {
if (inst.OpCode.Code == Code.Ldstr && IsMatch((string)inst.Operand))
return true;
}
} }
return false;
} }
} }
}
sealed class SearchResult : INotifyPropertyChanged, IMemberTreeNode
internal class TypeSearcher : SearcherBase
{
public TypeSearcher(string[] terms) : base(terms)
{ {
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged { }
add { }
remove { } public override void Search(TypeDefinition type, Language language, Action<SearchPane.SearchResult> addResult)
{
if (IsMatch(type.Name))
{
addResult(new SearchPane.SearchResult
{
Member = type,
Image = TypeTreeNode.GetIcon(type),
Name = language.TypeToString(type, includeNamespace: false),
LocationImage = type.DeclaringType != null ? TypeTreeNode.GetIcon(type.DeclaringType) : Images.Namespace,
Location = type.DeclaringType != null ? language.TypeToString(type.DeclaringType, includeNamespace: true) : type.Namespace
});
} }
public MemberReference Member { get; set; } foreach (TypeDefinition nestedType in type.NestedTypes)
public string Location { get; set; }
public string Name { get; set; }
public ImageSource Image { get; set; }
public ImageSource LocationImage { get; set; }
public override string ToString()
{ {
return Name; Search(nestedType, language, addResult);
} }
} }
} }

Loading…
Cancel
Save