Browse Source

Fix performance of SearchStrategies.

pull/1213/head
Siegfried Pammer 8 years ago
parent
commit
0b498df891
  1. 82
      ILSpy/Languages/CSharpLanguage.cs
  2. 45
      ILSpy/Languages/Language.cs
  3. 19
      ILSpy/Search/AbstractSearchStrategy.cs
  4. 4
      ILSpy/Search/LiteralSearchStrategy.cs
  5. 70
      ILSpy/Search/MemberSearchStrategy.cs

82
ILSpy/Languages/CSharpLanguage.cs

@ -40,6 +40,7 @@ using ICSharpCode.Decompiler.Util; @@ -40,6 +40,7 @@ using ICSharpCode.Decompiler.Util;
using System.Reflection;
using ICSharpCode.Decompiler.Disassembler;
using GenericContext = ICSharpCode.Decompiler.Metadata.GenericContext;
using System.Text;
namespace ICSharpCode.ILSpy
{
@ -555,9 +556,86 @@ namespace ICSharpCode.ILSpy @@ -555,9 +556,86 @@ namespace ICSharpCode.ILSpy
return buffer.ToString();
}
public override bool SearchCanUseILNames(string text)
string ToCSharpString(MetadataReader metadata, TypeDefinitionHandle handle, bool fullName)
{
return !text.Contains("<");
StringBuilder builder = new StringBuilder();
var currentTypeDefHandle = handle;
var typeDef = metadata.GetTypeDefinition(currentTypeDefHandle);
while (!currentTypeDefHandle.IsNil) {
if (builder.Length > 0)
builder.Insert(0, '.');
typeDef = metadata.GetTypeDefinition(currentTypeDefHandle);
var part = ReflectionHelper.SplitTypeParameterCountFromReflectionName(metadata.GetString(typeDef.Name), out int typeParamCount);
var genericParams = typeDef.GetGenericParameters();
if (genericParams.Count > 0) {
builder.Insert(0, '>');
int firstIndex = genericParams.Count - typeParamCount;
for (int i = genericParams.Count - 1; i >= genericParams.Count - typeParamCount; i--) {
builder.Insert(0, metadata.GetString(metadata.GetGenericParameter(genericParams[i]).Name));
builder.Insert(0, i == firstIndex ? '<' : ',');
}
}
builder.Insert(0, part);
currentTypeDefHandle = typeDef.GetDeclaringType();
if (!fullName) break;
}
if (fullName && !typeDef.Namespace.IsNil) {
builder.Insert(0, '.');
builder.Insert(0, metadata.GetString(typeDef.Namespace));
}
return builder.ToString();
}
public override string GetEntityName(PEFile module, EntityHandle handle, bool fullName)
{
MetadataReader metadata = module.Metadata;
switch (handle.Kind) {
case HandleKind.TypeDefinition:
return ToCSharpString(metadata, (TypeDefinitionHandle)handle, fullName);
case HandleKind.FieldDefinition:
var fd = metadata.GetFieldDefinition((FieldDefinitionHandle)handle);
var declaringType = fd.GetDeclaringType();
if (fullName)
return ToCSharpString(metadata, declaringType, fullName) + "." + metadata.GetString(fd.Name);
return metadata.GetString(fd.Name);
case HandleKind.MethodDefinition:
var md = metadata.GetMethodDefinition((MethodDefinitionHandle)handle);
declaringType = md.GetDeclaringType();
string methodName = metadata.GetString(md.Name);
var genericParams = md.GetGenericParameters();
if (genericParams.Count > 0) {
methodName += "<";
int i = 0;
foreach (var h in genericParams) {
if (i > 0)
methodName += ",";
var gp = metadata.GetGenericParameter(h);
methodName += metadata.GetString(gp.Name);
}
methodName += ">";
}
if (fullName)
return ToCSharpString(metadata, declaringType, fullName) + "." + methodName;
return methodName;
case HandleKind.EventDefinition:
var ed = metadata.GetEventDefinition((EventDefinitionHandle)handle);
declaringType = metadata.GetMethodDefinition(ed.GetAccessors().GetAny()).GetDeclaringType();
if (fullName)
return ToCSharpString(metadata, declaringType, fullName) + "." + metadata.GetString(ed.Name);
return metadata.GetString(ed.Name);
case HandleKind.PropertyDefinition:
var pd = metadata.GetPropertyDefinition((PropertyDefinitionHandle)handle);
declaringType = metadata.GetMethodDefinition(pd.GetAccessors().GetAny()).GetDeclaringType();
if (fullName)
return ToCSharpString(metadata, declaringType, fullName) + "." + metadata.GetString(pd.Name);
return metadata.GetString(pd.Name);
default:
return null;
}
}
public override bool ShowMember(IEntity member)

45
ILSpy/Languages/Language.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
@ -266,9 +267,49 @@ namespace ICSharpCode.ILSpy @@ -266,9 +267,49 @@ namespace ICSharpCode.ILSpy
return true;
}
public virtual bool SearchCanUseILNames(string text)
/// <summary>
/// This should produce a string representation of the entity for search to match search strings against.
/// </summary>
public virtual string GetEntityName(PEFile module, EntityHandle handle, bool fullName)
{
return true;
MetadataReader metadata = module.Metadata;
switch (handle.Kind) {
case HandleKind.TypeDefinition:
if (fullName)
return ((TypeDefinitionHandle)handle).GetFullTypeName(metadata).ToILNameString();
var td = metadata.GetTypeDefinition((TypeDefinitionHandle)handle);
return metadata.GetString(td.Name);
case HandleKind.FieldDefinition:
var fd = metadata.GetFieldDefinition((FieldDefinitionHandle)handle);
var declaringType = fd.GetDeclaringType();
if (fullName)
return fd.GetDeclaringType().GetFullTypeName(metadata).ToILNameString() + "." + metadata.GetString(fd.Name);
return metadata.GetString(fd.Name);
case HandleKind.MethodDefinition:
var md = metadata.GetMethodDefinition((MethodDefinitionHandle)handle);
declaringType = md.GetDeclaringType();
string methodName = metadata.GetString(md.Name);
int genericParamCount = md.GetGenericParameters().Count;
if (genericParamCount > 0)
methodName += "``" + genericParamCount;
if (fullName)
return md.GetDeclaringType().GetFullTypeName(metadata).ToILNameString() + "." + methodName;
return methodName;
case HandleKind.EventDefinition:
var ed = metadata.GetEventDefinition((EventDefinitionHandle)handle);
declaringType = metadata.GetMethodDefinition(ed.GetAccessors().GetAny()).GetDeclaringType();
if (fullName)
return declaringType.GetFullTypeName(metadata).ToILNameString() + "." + metadata.GetString(ed.Name);
return metadata.GetString(ed.Name);
case HandleKind.PropertyDefinition:
var pd = metadata.GetPropertyDefinition((PropertyDefinitionHandle)handle);
declaringType = metadata.GetMethodDefinition(pd.GetAccessors().GetAny()).GetDeclaringType();
if (fullName)
return declaringType.GetFullTypeName(metadata).ToILNameString() + "." + metadata.GetString(pd.Name);
return metadata.GetString(pd.Name);
default:
return null;
}
}
public virtual CodeMappingInfo GetCodeMappingInfo(PEFile module, SRM.EntityHandle member)

19
ILSpy/Search/AbstractSearchStrategy.cs

@ -15,10 +15,9 @@ namespace ICSharpCode.ILSpy.Search @@ -15,10 +15,9 @@ namespace ICSharpCode.ILSpy.Search
{
abstract class AbstractSearchStrategy
{
protected readonly (string Term, bool CanUseILNames)[] searchTerm;
protected readonly string[] searchTerm;
protected readonly Regex regex;
protected readonly bool fullNameSearch;
protected readonly bool needsLanguageSpecificNames;
protected readonly Language language;
protected readonly Action<SearchResult> addResult;
@ -35,17 +34,11 @@ namespace ICSharpCode.ILSpy.Search @@ -35,17 +34,11 @@ namespace ICSharpCode.ILSpy.Search
if (regexString.EndsWith("/", StringComparison.Ordinal))
regexString = regexString.Substring(0, regexString.Length - 1);
regex = SafeNewRegex(regexString);
needsLanguageSpecificNames = true;
searchTerm = new[] { (search, false) };
} else {
fullNameSearch = search.Contains(".");
needsLanguageSpecificNames = fullNameSearch || !language.SearchCanUseILNames(search);
searchTerm = new[] { (search, !needsLanguageSpecificNames) };
}
} else {
searchTerm = terms.SelectArray(t => (t, language.SearchCanUseILNames(t)));
needsLanguageSpecificNames = searchTerm.Any(t => !t.CanUseILNames);
}
searchTerm = terms;
}
protected float CalculateFitness(IEntity member)
@ -69,17 +62,17 @@ namespace ICSharpCode.ILSpy.Search @@ -69,17 +62,17 @@ namespace ICSharpCode.ILSpy.Search
return 1.0f / text.Length;
}
protected virtual bool IsMatch(MetadataReader metadata, StringHandle nameHandle, string languageSpecificName)
protected virtual bool IsMatch(string entityName)
{
if (regex != null) {
return regex.IsMatch(languageSpecificName);
return regex.IsMatch(entityName);
}
for (int i = 0; i < searchTerm.Length; ++i) {
// How to handle overlapping matches?
var term = searchTerm[i].Term;
var term = searchTerm[i];
if (string.IsNullOrEmpty(term)) continue;
string text = nameHandle.IsNil || !searchTerm[i].CanUseILNames || term.Contains(".") ? languageSpecificName : metadata.GetString(nameHandle);
string text = entityName;
switch (term[0]) {
case '+': // must contain
term = term.Substring(1);

4
ILSpy/Search/LiteralSearchStrategy.cs

@ -96,7 +96,7 @@ namespace ICSharpCode.ILSpy.Search @@ -96,7 +96,7 @@ namespace ICSharpCode.ILSpy.Search
return searchTermLiteralValue.Equals(val);
default:
// substring search with searchTerm
return IsMatch(metadata, MetadataTokens.StringHandle(0), val.ToString());
return IsMatch(val.ToString());
}
}
@ -208,7 +208,7 @@ namespace ICSharpCode.ILSpy.Search @@ -208,7 +208,7 @@ namespace ICSharpCode.ILSpy.Search
ILParser.SkipOperand(ref blob, code);
continue;
}
if (IsMatch(module.Metadata, MetadataTokens.StringHandle(0), ILParser.DecodeUserString(ref blob, module.Metadata)))
if (IsMatch(ILParser.DecodeUserString(ref blob, module.Metadata)))
return true;
}
}

70
ILSpy/Search/MemberSearchStrategy.cs

@ -27,18 +27,10 @@ namespace ICSharpCode.ILSpy.Search @@ -27,18 +27,10 @@ namespace ICSharpCode.ILSpy.Search
if (searchKind == MemberSearchKind.All || searchKind == MemberSearchKind.Type) {
foreach (var handle in metadata.TypeDefinitions) {
var td = metadata.GetTypeDefinition(handle);
string languageSpecificName = null;
ITypeDefinition type = null;
if (needsLanguageSpecificNames) {
type = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
languageSpecificName = GetLanguageSpecificName(type, fullName: true);
}
if (!IsMatch(module.Metadata, td.Name, languageSpecificName))
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch);
if (languageSpecificName != null && !IsMatch(languageSpecificName))
continue;
if (type == null) {
type = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
}
var type = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
addResult(ResultFromEntity(type));
}
}
@ -46,72 +38,40 @@ namespace ICSharpCode.ILSpy.Search @@ -46,72 +38,40 @@ namespace ICSharpCode.ILSpy.Search
if (searchKind == MemberSearchKind.All || searchKind == MemberSearchKind.Member || searchKind == MemberSearchKind.Method) {
foreach (var handle in metadata.MethodDefinitions) {
// TODO use method semantics to skip accessors
var md = metadata.GetMethodDefinition(handle);
string languageSpecificName = null;
IMethod method = null;
if (needsLanguageSpecificNames) {
method = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
languageSpecificName = GetLanguageSpecificName(method, fullName: true);
}
if (!IsMatch(module.Metadata, md.Name, languageSpecificName))
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch);
if (languageSpecificName != null && !IsMatch(languageSpecificName))
continue;
if (method == null) {
method = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
}
var method = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
addResult(ResultFromEntity(method));
}
}
if (searchKind == MemberSearchKind.All || searchKind == MemberSearchKind.Member || searchKind == MemberSearchKind.Field) {
foreach (var handle in metadata.FieldDefinitions) {
var fd = metadata.GetFieldDefinition(handle);
string languageSpecificName = null;
IField field = null;
if (needsLanguageSpecificNames) {
field = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
languageSpecificName = GetLanguageSpecificName(field, fullName: true);
}
if (!IsMatch(module.Metadata, fd.Name, languageSpecificName))
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch);
if (languageSpecificName != null && !IsMatch(languageSpecificName))
continue;
if (field == null) {
field = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
}
var field = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
addResult(ResultFromEntity(field));
}
}
if (searchKind == MemberSearchKind.All || searchKind == MemberSearchKind.Member || searchKind == MemberSearchKind.Property) {
foreach (var handle in metadata.PropertyDefinitions) {
var pd = metadata.GetPropertyDefinition(handle);
string languageSpecificName = null;
IProperty property = null;
if (needsLanguageSpecificNames) {
property = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
languageSpecificName = GetLanguageSpecificName(property, fullName: true);
}
if (!IsMatch(module.Metadata, pd.Name, languageSpecificName))
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch);
if (languageSpecificName != null && !IsMatch(languageSpecificName))
continue;
if (property == null) {
property = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
}
var property = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
addResult(ResultFromEntity(property));
}
}
if (searchKind == MemberSearchKind.All || searchKind == MemberSearchKind.Member || searchKind == MemberSearchKind.Event) {
foreach (var handle in metadata.EventDefinitions) {
var ed = metadata.GetEventDefinition(handle);
string languageSpecificName = null;
IEvent @event = null;
if (needsLanguageSpecificNames) {
@event = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
languageSpecificName = GetLanguageSpecificName(@event, fullName: true);
}
if (!IsMatch(module.Metadata, ed.Name, languageSpecificName))
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch);
if (!IsMatch(languageSpecificName))
continue;
if (@event == null) {
@event = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
}
var @event = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
addResult(ResultFromEntity(@event));
}
}

Loading…
Cancel
Save