Browse Source

Merge pull request #1707 from miloush/search-strategies

Resource search strategy
pull/1710/head
Siegfried Pammer 7 years ago committed by GitHub
parent
commit
b8c2e7c35a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      ILSpy/ContextMenuEntry.cs
  2. 3
      ILSpy/ILSpy.csproj
  3. 2
      ILSpy/MainWindow.xaml.cs
  4. 122
      ILSpy/Search/AbstractEntitySearchStrategy.cs
  5. 109
      ILSpy/Search/AbstractSearchStrategy.cs
  6. 2
      ILSpy/Search/LiteralSearchStrategy.cs
  7. 2
      ILSpy/Search/MemberSearchStrategy.cs
  8. 2
      ILSpy/Search/MetadataTokenSearchStrategy.cs
  9. 91
      ILSpy/Search/ResourceSearchStrategy.cs
  10. 65
      ILSpy/Search/SearchPane.cs
  11. 97
      ILSpy/Search/SearchResult.cs
  12. 12
      ILSpy/TreeNodes/AssemblyListTreeNode.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;

3
ILSpy/ILSpy.csproj

@ -167,6 +167,7 @@ @@ -167,6 +167,7 @@
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Search\AbstractEntitySearchStrategy.cs" />
<Compile Include="Search\LiteralSearchStrategy.cs" />
<Compile Include="LoadedAssembly.cs" />
<Compile Include="LoadedAssemblyExtensions.cs" />
@ -204,11 +205,13 @@ @@ -204,11 +205,13 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Commands\RefreshCommand.cs" />
<Compile Include="Commands\SaveCommand.cs" />
<Compile Include="Search\ResourceSearchStrategy.cs" />
<Compile Include="Search\SearchPane.cs">
<DependentUpon>SearchPane.xaml</DependentUpon>
</Compile>
<Compile Include="Commands\SimpleCommand.cs" />
<Compile Include="Search\AbstractSearchStrategy.cs" />
<Compile Include="Search\SearchResult.cs" />
<Compile Include="SolutionWriter.cs" />
<Compile Include="TaskHelper.cs" />
<Compile Include="TextView\BracketHighlightRenderer.cs" />

2
ILSpy/MainWindow.xaml.cs

@ -713,6 +713,8 @@ namespace ICSharpCode.ILSpy @@ -713,6 +713,8 @@ namespace ICSharpCode.ILSpy
return assemblyListTreeNode.FindAssemblyNode(asm);
case Resource res:
return assemblyListTreeNode.FindResourceNode(res);
case ValueTuple<Resource, string> resName:
return assemblyListTreeNode.FindResourceNode(resName.Item1, resName.Item2);
case ITypeDefinition type:
return assemblyListTreeNode.FindTypeNode(type);
case IField fd:

122
ILSpy/Search/AbstractEntitySearchStrategy.cs

@ -0,0 +1,122 @@ @@ -0,0 +1,122 @@
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 MemberSearchResult {
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!");
}
}
static internal 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!");
}
}
}
}

109
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) {
@ -44,17 +40,17 @@ namespace ICSharpCode.ILSpy.Search @@ -44,17 +40,17 @@ namespace ICSharpCode.ILSpy.Search
public abstract void Search(PEFile module, CancellationToken cancellationToken);
protected virtual bool IsMatch(string entityName)
protected virtual bool IsMatch(string name)
{
if (regex != null) {
return regex.IsMatch(entityName);
return regex.IsMatch(name);
}
for (int i = 0; i < searchTerm.Length; ++i) {
// How to handle overlapping matches?
var term = searchTerm[i];
if (string.IsNullOrEmpty(term)) continue;
string text = entityName;
string text = name;
switch (term[0]) {
case '+': // must contain
term = term.Substring(1);
@ -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;

91
ILSpy/Search/ResourceSearchStrategy.cs

@ -0,0 +1,91 @@ @@ -0,0 +1,91 @@
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);
foreach (Resource resource in module.Resources)
Search(module, resource, resourcesNode, ResourceTreeNode.Create(resource), cancellationToken);
}
void Search(PEFile module, Resource resource, SharpTreeNode parent, SharpTreeNode node, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (node is ResourceTreeNode treeNode) {
if (!CheckVisibility(treeNode.Resource))
return;
resource = treeNode.Resource;
}
if (node.Text != null && IsMatch((string)node.Text))
OnFoundResult(module, resource, node, parent);
if (!searchInside)
return;
node.EnsureLazyChildren();
foreach (var child in node.Children)
Search(module, resource, node, child, cancellationToken);
}
void OnFoundResult(PEFile module, Resource resource, SharpTreeNode node, SharpTreeNode parent)
{
var name = (string)node.Text;
var result = new ResourceSearchResult {
Resource = resource,
Fitness = 1.0f / name.Length,
Image = (ImageSource)node.Icon,
Name = name,
LocationImage = (ImageSource)parent.Icon,
Location = (string)parent.Text,
Assembly = module.FullName,
ToolTip = module.FileName,
};
OnFoundResult(result);
}
}
}

65
ILSpy/Search/SearchPane.cs

@ -32,7 +32,6 @@ using System.Windows.Media; @@ -32,7 +32,6 @@ using System.Windows.Media;
using System.Windows.Threading;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Search;
using ICSharpCode.ILSpy.TreeNodes;
namespace ICSharpCode.ILSpy
{
@ -76,6 +75,7 @@ namespace ICSharpCode.ILSpy @@ -76,6 +75,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.Resource, Name = "Resource" });
ContextMenuProvider.Add(listBox);
MainWindow.Instance.CurrentAssemblyListChanged += MainWindow_Instance_CurrentAssemblyListChanged;
@ -263,7 +263,7 @@ namespace ICSharpCode.ILSpy @@ -263,7 +263,7 @@ namespace ICSharpCode.ILSpy
void JumpToSelectedItem()
{
if (listBox.SelectedItem is SearchResult result) {
MainWindow.Instance.JumpToReference(result.Member);
MainWindow.Instance.JumpToReference(result.Reference);
}
}
@ -342,6 +342,9 @@ namespace ICSharpCode.ILSpy @@ -342,6 +342,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 +367,8 @@ namespace ICSharpCode.ILSpy @@ -364,6 +367,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,59 +376,6 @@ namespace ICSharpCode.ILSpy @@ -371,59 +376,6 @@ namespace ICSharpCode.ILSpy
}
}
public sealed class SearchResult : IMemberTreeNode
{
ImageSource image;
ImageSource locationImage;
public static readonly IComparer<SearchResult> Comparer = new SearchResultComparer();
public IEntity Member { get; set; }
public float Fitness { get; set; }
public string Assembly { get; set; }
public string Location { get; set; }
public string Name { get; set; }
public object ToolTip { get; set; }
public ImageSource Image {
get {
if (image == null) {
image = AbstractSearchStrategy.GetIcon(Member);
}
return image;
}
}
public ImageSource LocationImage {
get {
if (locationImage == null) {
locationImage = Member.DeclaringTypeDefinition != null ? TypeTreeNode.GetIcon(Member.DeclaringTypeDefinition) : Images.Namespace;
}
return locationImage;
}
}
public ImageSource AssemblyImage {
get {
return Images.Assembly;
}
}
public override string ToString()
{
return Name;
}
class SearchResultComparer : System.Collections.Generic.IComparer<SearchResult>
{
public int Compare(SearchResult x, SearchResult y)
{
return StringComparer.Ordinal.Compare(x?.Name ?? "", y?.Name ?? "");
}
}
}
[ExportMainMenuCommand(Menu = nameof(Properties.Resources._View), Header =nameof(Properties.Resources.Search), MenuIcon = "Images/Search", MenuCategory = nameof(Properties.Resources.View), MenuOrder = 100)]
[ExportToolbarCommand(ToolTip = nameof(Properties.Resources.SearchCtrlShiftFOrCtrlE), ToolbarIcon = "Images/Search", ToolbarCategory = nameof(Properties.Resources.View), ToolbarOrder = 100)]
sealed class ShowSearchCommand : CommandWrapper
@ -447,6 +399,7 @@ namespace ICSharpCode.ILSpy @@ -447,6 +399,7 @@ namespace ICSharpCode.ILSpy
Property,
Event,
Literal,
Token
Token,
Resource
}
}

97
ILSpy/Search/SearchResult.cs

@ -0,0 +1,97 @@ @@ -0,0 +1,97 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Windows.Media;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Search;
using ICSharpCode.ILSpy.TreeNodes;
namespace ICSharpCode.ILSpy
{
public class SearchResult
{
public static readonly IComparer<SearchResult> Comparer = new SearchResultComparer();
public virtual object Reference {
get {
return null;
}
}
public float Fitness { get; set; }
public string Name { get; set; }
public string Location { get; set; }
public string Assembly { get; set; }
public object ToolTip { get; set; }
public virtual ImageSource Image { get; set; }
public virtual ImageSource LocationImage { get; set; }
public ImageSource AssemblyImage {
get {
return Images.Assembly;
}
}
public override string ToString()
{
return Name;
}
class SearchResultComparer : IComparer<SearchResult>
{
public int Compare(SearchResult x, SearchResult y)
{
return StringComparer.Ordinal.Compare(x?.Name ?? "", y?.Name ?? "");
}
}
}
public class MemberSearchResult : SearchResult
{
public IEntity Member { get; set; }
public override object Reference => Member;
public override ImageSource Image {
get {
if (base.Image == null) {
base.Image = AbstractEntitySearchStrategy.GetIcon(Member);
}
return base.Image;
}
}
public override ImageSource LocationImage {
get {
if (base.LocationImage == null) {
base.LocationImage = Member.DeclaringTypeDefinition != null ? TypeTreeNode.GetIcon(Member.DeclaringTypeDefinition) : Images.Namespace;
}
return base.LocationImage;
}
}
}
public class ResourceSearchResult : SearchResult
{
public Resource Resource { get; set; }
public override object Reference => ValueTuple.Create(Resource, Name);
}
}

12
ILSpy/TreeNodes/AssemblyListTreeNode.cs

@ -155,7 +155,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -155,7 +155,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
#region Find*Node
public ILSpyTreeNode FindResourceNode(Resource resource)
{
if (resource == null)
if (resource == null || resource.IsNil)
return null;
foreach (AssemblyTreeNode node in this.Children)
{
@ -177,6 +177,16 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -177,6 +177,16 @@ namespace ICSharpCode.ILSpy.TreeNodes
return null;
}
public ILSpyTreeNode FindResourceNode(Resource resource, string name)
{
var resourceNode = FindResourceNode(resource);
if (resourceNode == null || name == null || name.Equals(resourceNode.Text))
return resourceNode;
resourceNode.EnsureLazyChildren();
return resourceNode.Children.OfType<ILSpyTreeNode>().Where(x => name.Equals(x.Text)).FirstOrDefault() ?? resourceNode;
}
public AssemblyTreeNode FindAssemblyNode(IModule module)
{
return FindAssemblyNode(module.PEFile);

Loading…
Cancel
Save