Browse Source

Add resource search strategy

pull/1707/head
Jan Kučera 6 years ago
parent
commit
ee1096958c
  1. 2
      ILSpy/ContextMenuEntry.cs
  2. 8
      ILSpy/ILSpy.csproj
  3. 125
      ILSpy/Search/AbstractEntitySearchStrategy.cs
  4. 103
      ILSpy/Search/AbstractSearchStrategy.cs
  5. 2
      ILSpy/Search/LiteralSearchStrategy.cs
  6. 2
      ILSpy/Search/MemberSearchStrategy.cs
  7. 2
      ILSpy/Search/MetadataTokenSearchStrategy.cs
  8. 93
      ILSpy/Search/ResourceSearchStrategy.cs
  9. 17
      ILSpy/Search/SearchPane.cs

2
ILSpy/ContextMenuEntry.cs

@ -78,7 +78,7 @@ namespace ICSharpCode.ILSpy @@ -78,7 +78,7 @@ namespace ICSharpCode.ILSpy
if (textView != null)
reference = textView.GetReferenceSegmentAtMousePosition();
else if (listBox?.SelectedItem is SearchResult result)
reference = new ReferenceSegment { Reference = result.Member };
reference = new ReferenceSegment { Reference = result.Reference };
else
reference = null;
var position = textView != null ? textView.GetPositionFromMousePosition() : null;

8
ILSpy/ILSpy.csproj

@ -167,6 +167,10 @@ @@ -167,6 +167,10 @@
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Search\AbstractEntitySearchStrategy.cs">
<SubType>Code</SubType>
<Generator>MSBuild:Compile</Generator>
</Compile>
<Compile Include="Search\LiteralSearchStrategy.cs" />
<Compile Include="LoadedAssembly.cs" />
<Compile Include="LoadedAssemblyExtensions.cs" />
@ -204,6 +208,10 @@ @@ -204,6 +208,10 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Commands\RefreshCommand.cs" />
<Compile Include="Commands\SaveCommand.cs" />
<Compile Include="Search\ResourceSearchStrategy.cs">
<SubType>Code</SubType>
<Generator>MSBuild:Compile</Generator>
</Compile>
<Compile Include="Search\SearchPane.cs">
<DependentUpon>SearchPane.xaml</DependentUpon>
</Compile>

125
ILSpy/Search/AbstractEntitySearchStrategy.cs

@ -0,0 +1,125 @@ @@ -0,0 +1,125 @@
using System;
using System.Collections.Concurrent;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Media;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes;
namespace ICSharpCode.ILSpy.Search
{
abstract class AbstractEntitySearchStrategy : AbstractSearchStrategy
{
protected readonly Language language;
protected readonly ApiVisibility apiVisibility;
protected AbstractEntitySearchStrategy(Language language, ApiVisibility apiVisibility, IProducerConsumerCollection<SearchResult> resultQueue, params string[] terms)
: base(resultQueue, terms)
{
this.language = language;
this.apiVisibility = apiVisibility;
}
protected bool CheckVisibility(IEntity entity)
{
if (apiVisibility == ApiVisibility.All)
return true;
do {
if (apiVisibility == ApiVisibility.PublicOnly) {
if (!(entity.Accessibility == Accessibility.Public ||
entity.Accessibility == Accessibility.Protected ||
entity.Accessibility == Accessibility.ProtectedOrInternal))
return false;
} else if (apiVisibility == ApiVisibility.PublicAndInternal) {
if (!language.ShowMember(entity))
return false;
}
entity = entity.DeclaringTypeDefinition;
}
while (entity != null);
return true;
}
protected void OnFoundResult(IEntity entity)
{
var result = ResultFromEntity(entity);
OnFoundResult(result);
}
SearchResult ResultFromEntity(IEntity item)
{
var declaringType = item.DeclaringTypeDefinition;
return new SearchResult {
Reference = item,
Fitness = CalculateFitness(item),
Image = GetIcon(item),
Name = GetLanguageSpecificName(item),
LocationImage = declaringType != null ? TypeTreeNode.GetIcon(declaringType) : Images.Namespace,
Location = declaringType != null ? language.TypeToString(declaringType, includeNamespace: true) : item.Namespace,
AssemblyImage = Images.Assembly,
Assembly = item.ParentModule.FullAssemblyName,
ToolTip = item.ParentModule.PEFile?.FileName
};
}
float CalculateFitness(IEntity member)
{
string text = member.Name;
// Probably compiler generated types without meaningful names, show them last
if (text.StartsWith("<")) {
return 0;
}
// Constructors always have the same name in IL:
// Use type name instead
if (text == ".cctor" || text == ".ctor") {
text = member.DeclaringType.Name;
}
// Ignore generic arguments, it not possible to search based on them either
text = ReflectionHelper.SplitTypeParameterCountFromReflectionName(text);
return 1.0f / text.Length;
}
string GetLanguageSpecificName(IEntity member)
{
switch (member) {
case ITypeDefinition t:
return language.TypeToString(t, false);
case IField f:
return language.FieldToString(f, true, false, false);
case IProperty p:
return language.PropertyToString(p, true, false, false);
case IMethod m:
return language.MethodToString(m, true, false, false);
case IEvent e:
return language.EventToString(e, true, false, false);
default:
throw new NotSupportedException(member?.GetType() + " not supported!");
}
}
ImageSource GetIcon(IEntity member)
{
switch (member) {
case ITypeDefinition t:
return TypeTreeNode.GetIcon(t);
case IField f:
return FieldTreeNode.GetIcon(f);
case IProperty p:
return PropertyTreeNode.GetIcon(p);
case IMethod m:
return MethodTreeNode.GetIcon(m);
case IEvent e:
return EventTreeNode.GetIcon(e);
default:
throw new NotSupportedException(member?.GetType() + " not supported!");
}
}
}
}

103
ILSpy/Search/AbstractSearchStrategy.cs

@ -15,14 +15,10 @@ namespace ICSharpCode.ILSpy.Search @@ -15,14 +15,10 @@ namespace ICSharpCode.ILSpy.Search
protected readonly Regex regex;
protected readonly bool fullNameSearch;
protected readonly bool omitGenerics;
protected readonly Language language;
protected readonly ApiVisibility apiVisibility;
private readonly IProducerConsumerCollection<SearchResult> resultQueue;
protected AbstractSearchStrategy(Language language, ApiVisibility apiVisibility, IProducerConsumerCollection<SearchResult> resultQueue, params string[] terms)
protected AbstractSearchStrategy(IProducerConsumerCollection<SearchResult> resultQueue, params string[] terms)
{
this.language = language;
this.apiVisibility = apiVisibility;
this.resultQueue = resultQueue;
if (terms.Length == 1 && terms[0].Length > 2) {
@ -87,28 +83,6 @@ namespace ICSharpCode.ILSpy.Search @@ -87,28 +83,6 @@ namespace ICSharpCode.ILSpy.Search
return true;
}
protected bool CheckVisibility(IEntity entity)
{
if (apiVisibility == ApiVisibility.All)
return true;
do {
if (apiVisibility == ApiVisibility.PublicOnly) {
if (!(entity.Accessibility == Accessibility.Public ||
entity.Accessibility == Accessibility.Protected ||
entity.Accessibility == Accessibility.ProtectedOrInternal))
return false;
} else if (apiVisibility == ApiVisibility.PublicAndInternal) {
if (!language.ShowMember(entity))
return false;
}
entity = entity.DeclaringTypeDefinition;
}
while (entity != null);
return true;
}
bool IsNoncontiguousMatch(string text, string searchTerm)
{
if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(searchTerm)) {
@ -135,10 +109,9 @@ namespace ICSharpCode.ILSpy.Search @@ -135,10 +109,9 @@ namespace ICSharpCode.ILSpy.Search
}
return false;
}
protected void OnFoundResult(IEntity entity)
protected void OnFoundResult(SearchResult result)
{
var result = ResultFromEntity(entity);
resultQueue.TryAdd(result);
}
@ -150,75 +123,5 @@ namespace ICSharpCode.ILSpy.Search @@ -150,75 +123,5 @@ namespace ICSharpCode.ILSpy.Search
return null;
}
}
SearchResult ResultFromEntity(IEntity item)
{
var declaringType = item.DeclaringTypeDefinition;
return new SearchResult {
Member = item,
Fitness = CalculateFitness(item),
Name = GetLanguageSpecificName(item),
Location = declaringType != null ? language.TypeToString(declaringType, includeNamespace: true) : item.Namespace,
Assembly = item.ParentModule.FullAssemblyName,
ToolTip = item.ParentModule.PEFile?.FileName
};
}
float CalculateFitness(IEntity member)
{
string text = member.Name;
// Probably compiler generated types without meaningful names, show them last
if (text.StartsWith("<")) {
return 0;
}
// Constructors always have the same name in IL:
// Use type name instead
if (text == ".cctor" || text == ".ctor") {
text = member.DeclaringType.Name;
}
// Ignore generic arguments, it not possible to search based on them either
text = ReflectionHelper.SplitTypeParameterCountFromReflectionName(text);
return 1.0f / text.Length;
}
string GetLanguageSpecificName(IEntity member)
{
switch (member) {
case ITypeDefinition t:
return language.TypeToString(t, false);
case IField f:
return language.FieldToString(f, true, false, false);
case IProperty p:
return language.PropertyToString(p, true, false, false);
case IMethod m:
return language.MethodToString(m, true, false, false);
case IEvent e:
return language.EventToString(e, true, false, false);
default:
throw new NotSupportedException(member?.GetType() + " not supported!");
}
}
internal static ImageSource GetIcon(IEntity member)
{
switch (member) {
case ITypeDefinition t:
return TypeTreeNode.GetIcon(t);
case IField f:
return FieldTreeNode.GetIcon(f);
case IProperty p:
return PropertyTreeNode.GetIcon(p);
case IMethod m:
return MethodTreeNode.GetIcon(m);
case IEvent e:
return EventTreeNode.GetIcon(e);
default:
throw new NotSupportedException(member?.GetType() + " not supported!");
}
}
}
}

2
ILSpy/Search/LiteralSearchStrategy.cs

@ -15,7 +15,7 @@ using System.Collections.Concurrent; @@ -15,7 +15,7 @@ using System.Collections.Concurrent;
namespace ICSharpCode.ILSpy.Search
{
class LiteralSearchStrategy : AbstractSearchStrategy
class LiteralSearchStrategy : AbstractEntitySearchStrategy
{
readonly TypeCode searchTermLiteralType;
readonly object searchTermLiteralValue;

2
ILSpy/Search/MemberSearchStrategy.cs

@ -6,7 +6,7 @@ using ICSharpCode.Decompiler.TypeSystem; @@ -6,7 +6,7 @@ using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy.Search
{
class MemberSearchStrategy : AbstractSearchStrategy
class MemberSearchStrategy : AbstractEntitySearchStrategy
{
readonly MemberSearchKind searchKind;

2
ILSpy/Search/MetadataTokenSearchStrategy.cs

@ -9,7 +9,7 @@ using ICSharpCode.Decompiler.TypeSystem; @@ -9,7 +9,7 @@ using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy.Search
{
class MetadataTokenSearchStrategy : AbstractSearchStrategy
class MetadataTokenSearchStrategy : AbstractEntitySearchStrategy
{
readonly EntityHandle searchTermToken;

93
ILSpy/Search/ResourceSearchStrategy.cs

@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy.Search
{
class ResourceSearchStrategy : AbstractSearchStrategy
{
protected readonly bool searchInside;
protected readonly ApiVisibility apiVisibility;
public ResourceSearchStrategy(ApiVisibility apiVisibility, IProducerConsumerCollection<SearchResult> resultQueue, string term)
: this(apiVisibility, resultQueue, new[] { term })
{
}
public ResourceSearchStrategy(ApiVisibility apiVisibility, IProducerConsumerCollection<SearchResult> resultQueue, string[] terms)
: base(resultQueue, terms)
{
this.apiVisibility = apiVisibility;
this.searchInside = true;
}
protected bool CheckVisibility(Resource resource)
{
if (apiVisibility == ApiVisibility.All)
return true;
if (apiVisibility == ApiVisibility.PublicOnly && (resource.Attributes & ManifestResourceAttributes.VisibilityMask) == ManifestResourceAttributes.Private)
return false;
return true;
}
public override void Search(PEFile module, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var resourcesNode = new ResourceListTreeNode(module);
resourcesNode.EnsureLazyChildren();
foreach (var node in resourcesNode.Children)
Search(module, null, resourcesNode, node, cancellationToken);
return;
}
void Search(PEFile module, object reference, SharpTreeNode parent, SharpTreeNode node, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (node is ResourceTreeNode treeNode) {
if (!CheckVisibility(treeNode.Resource))
return;
reference = treeNode.Resource;
}
if (node.Text != null && IsMatch((string)node.Text))
OnFoundResult(module, reference, node, parent);
if (!searchInside)
return;
node.EnsureLazyChildren();
foreach (var child in node.Children)
Search(module, reference, node, child, cancellationToken);
}
void OnFoundResult(PEFile module, object reference, SharpTreeNode node, SharpTreeNode parent)
{
var result = new SearchResult {
Reference = reference,
Fitness = 1f,
Image = (ImageSource)node.Icon,
Name = (string)node.Text,
LocationImage = (ImageSource)parent.Icon,
Location = (string)parent.Text,
AssemblyImage = Images.Assembly,
Assembly = module.Name,
ToolTip = module.FileName,
};
OnFoundResult(result);
}
}
}

17
ILSpy/Search/SearchPane.cs

@ -76,6 +76,7 @@ namespace ICSharpCode.ILSpy @@ -76,6 +76,7 @@ namespace ICSharpCode.ILSpy
searchModeComboBox.Items.Add(new { Image = Images.Event, Name = "Event" });
searchModeComboBox.Items.Add(new { Image = Images.Literal, Name = "Constant" });
searchModeComboBox.Items.Add(new { Image = Images.Library, Name = "Metadata Token" });
searchModeComboBox.Items.Add(new { Image = Images.ResourceResourcesFile, Name = "Resource" });
ContextMenuProvider.Add(listBox);
MainWindow.Instance.CurrentAssemblyListChanged += MainWindow_Instance_CurrentAssemblyListChanged;
@ -263,7 +264,7 @@ namespace ICSharpCode.ILSpy @@ -263,7 +264,7 @@ namespace ICSharpCode.ILSpy
void JumpToSelectedItem()
{
if (listBox.SelectedItem is SearchResult result) {
MainWindow.Instance.JumpToReference(result.Member);
MainWindow.Instance.JumpToReference(result.Reference);
}
}
@ -342,6 +343,9 @@ namespace ICSharpCode.ILSpy @@ -342,6 +343,9 @@ namespace ICSharpCode.ILSpy
if (searchTerm[0].StartsWith("@", StringComparison.Ordinal))
return new MetadataTokenSearchStrategy(language, apiVisibility, resultQueue, searchTerm[0].Substring(1));
if (searchTerm[0].StartsWith("r:", StringComparison.Ordinal))
return new ResourceSearchStrategy(apiVisibility, resultQueue, searchTerm[0].Substring(2));
}
switch (searchMode)
@ -364,6 +368,8 @@ namespace ICSharpCode.ILSpy @@ -364,6 +368,8 @@ namespace ICSharpCode.ILSpy
return new MemberSearchStrategy(language, apiVisibility, resultQueue, searchTerm, MemberSearchKind.Event);
case SearchMode.Token:
return new MetadataTokenSearchStrategy(language, apiVisibility, resultQueue, searchTerm);
case SearchMode.Resource:
return new ResourceSearchStrategy(apiVisibility, resultQueue, searchTerm);
}
return null;
@ -371,14 +377,16 @@ namespace ICSharpCode.ILSpy @@ -371,14 +377,16 @@ namespace ICSharpCode.ILSpy
}
}
public sealed class SearchResult : IMemberTreeNode
public sealed class SearchResult // : IMemberTreeNode
{
public static readonly System.Collections.Generic.IComparer<SearchResult> Comparer = new SearchResultComparer();
ImageSource image;
ImageSource locationImage;
public static readonly IComparer<SearchResult> Comparer = new SearchResultComparer();
public IEntity Member { get; set; }
public object Reference { get; set; }
public float Fitness { get; set; }
public string Assembly { get; set; }
@ -447,6 +455,7 @@ namespace ICSharpCode.ILSpy @@ -447,6 +455,7 @@ namespace ICSharpCode.ILSpy
Property,
Event,
Literal,
Token
Token,
Resource
}
}
Loading…
Cancel
Save