mirror of https://github.com/icsharpcode/ILSpy.git
3 changed files with 367 additions and 381 deletions
@ -0,0 +1,336 @@
@@ -0,0 +1,336 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Text.RegularExpressions; |
||||
using System.Windows.Media; |
||||
using ICSharpCode.ILSpy.TreeNodes; |
||||
using ICSharpCode.NRefactory.CSharp; |
||||
using ICSharpCode.NRefactory.Utils; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
|
||||
namespace ICSharpCode.ILSpy |
||||
{ |
||||
abstract class AbstractSearchStrategy |
||||
{ |
||||
protected string[] searchTerm; |
||||
protected Regex regex; |
||||
|
||||
protected AbstractSearchStrategy(params string[] terms) |
||||
{ |
||||
if (terms.Length == 1 && terms[0].Length > 2) { |
||||
var search = terms[0]; |
||||
if (search.StartsWith("/") && search.EndsWith("/") && search.Length > 4) |
||||
regex = SafeNewRegex(search.Substring(1, search.Length - 2)); |
||||
|
||||
terms[0] = search; |
||||
} |
||||
|
||||
searchTerm = terms; |
||||
} |
||||
|
||||
protected bool IsMatch(string text) |
||||
{ |
||||
if (regex != null) |
||||
return regex.IsMatch(text); |
||||
|
||||
for (int i = 0; i < searchTerm.Length; ++i) { |
||||
// How to handle overlapping matches?
|
||||
if (text.IndexOf(searchTerm[i], StringComparison.OrdinalIgnoreCase) < 0) |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
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; |
||||
} |
||||
|
||||
void Add<T>(IEnumerable<T> items, TypeDefinition type, Language language, Action<SearchResult> addResult, Func<T, bool> matcher, Func<T, ImageSource> image) where T : MemberReference |
||||
{ |
||||
foreach (var item in items) { |
||||
if (matcher(item)) { |
||||
addResult(new SearchResult |
||||
{ |
||||
Member = item, |
||||
Image = image(item), |
||||
Name = item.Name, |
||||
LocationImage = TypeTreeNode.GetIcon(type), |
||||
Location = language.TypeToString(type, includeNamespace: true) |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public virtual void Search(TypeDefinition type, Language language, Action<SearchResult> addResult) |
||||
{ |
||||
Add(type.Fields, type, language, addResult, IsMatch, FieldTreeNode.GetIcon); |
||||
Add(type.Properties, type, language, addResult, IsMatch, p => PropertyTreeNode.GetIcon(p)); |
||||
Add(type.Events, type, language, addResult, IsMatch, EventTreeNode.GetIcon); |
||||
Add(type.Methods.Where(NotSpecialMethod), type, language, addResult, IsMatch, MethodTreeNode.GetIcon); |
||||
} |
||||
|
||||
bool NotSpecialMethod(MethodDefinition arg) |
||||
{ |
||||
return (arg.SemanticsAttributes & ( |
||||
MethodSemanticsAttributes.Setter |
||||
| MethodSemanticsAttributes.Getter |
||||
| MethodSemanticsAttributes.AddOn |
||||
| MethodSemanticsAttributes.RemoveOn |
||||
| MethodSemanticsAttributes.Fire)) == 0; |
||||
} |
||||
|
||||
Regex SafeNewRegex(string unsafePattern) |
||||
{ |
||||
try { |
||||
return new Regex(unsafePattern, RegexOptions.Compiled); |
||||
} catch (ArgumentException) { |
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
class LiteralSearchStrategy : AbstractSearchStrategy |
||||
{ |
||||
readonly TypeCode searchTermLiteralType; |
||||
readonly object searchTermLiteralValue; |
||||
|
||||
public LiteralSearchStrategy(params string[] terms) |
||||
: base(terms) |
||||
{ |
||||
if (1 == searchTerm.Length) { |
||||
var parser = new CSharpParser(); |
||||
var 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; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected override bool IsMatch(FieldDefinition field) |
||||
{ |
||||
return IsLiteralMatch(field.Constant); |
||||
} |
||||
|
||||
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; |
||||
} |
||||
} |
||||
} 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; |
||||
} |
||||
} |
||||
|
||||
class MemberSearchStrategy : AbstractSearchStrategy |
||||
{ |
||||
public MemberSearchStrategy(params 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); |
||||
} |
||||
} |
||||
|
||||
class TypeSearchStrategy : AbstractSearchStrategy |
||||
{ |
||||
public TypeSearchStrategy(params string[] terms) |
||||
: base(terms) |
||||
{ |
||||
} |
||||
|
||||
public override void Search(TypeDefinition type, Language language, Action<SearchResult> addResult) |
||||
{ |
||||
if (IsMatch(type.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, |
||||
Location = type.DeclaringType != null ? language.TypeToString(type.DeclaringType, includeNamespace: true) : type.Namespace |
||||
}); |
||||
} |
||||
|
||||
foreach (TypeDefinition nestedType in type.NestedTypes) { |
||||
Search(nestedType, language, addResult); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue