mirror of https://github.com/icsharpcode/ILSpy.git
25 changed files with 841 additions and 1013 deletions
@ -0,0 +1,92 @@
@@ -0,0 +1,92 @@
|
||||
// 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.Linq; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
using ICSharpCode.ILSpy.TreeNodes; |
||||
using ICSharpCode.ILSpy.TreeNodes.Analyzer; |
||||
|
||||
namespace ICSharpCode.ILSpy.Analyzers |
||||
{ |
||||
[ExportContextMenuEntry(Header = "Analyze", Icon = "images/Search.png", Category = "Analyze", Order = 100)] |
||||
internal sealed class AnalyzeContextMenuEntry : IContextMenuEntry |
||||
{ |
||||
public bool IsVisible(TextViewContext context) |
||||
{ |
||||
if (context.TreeView is AnalyzerTreeView && context.SelectedTreeNodes != null && context.SelectedTreeNodes.All(n => n.Parent.IsRoot)) |
||||
return false; |
||||
if (context.SelectedTreeNodes == null) |
||||
return context.Reference != null && IsValidReference(context.Reference.Reference); |
||||
return context.SelectedTreeNodes.All(n => n is IMemberTreeNode); |
||||
} |
||||
|
||||
public bool IsEnabled(TextViewContext context) |
||||
{ |
||||
if (context.SelectedTreeNodes == null) |
||||
return context.Reference != null && context.Reference.Reference is IEntity; |
||||
foreach (IMemberTreeNode node in context.SelectedTreeNodes) { |
||||
if (!IsValidReference(node.Member)) |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool IsValidReference(object reference) |
||||
{ |
||||
return reference is IEntity; |
||||
} |
||||
|
||||
public void Execute(TextViewContext context) |
||||
{ |
||||
if (context.SelectedTreeNodes != null) { |
||||
foreach (IMemberTreeNode node in context.SelectedTreeNodes) { |
||||
Analyze(node.Member); |
||||
} |
||||
} else if (context.Reference != null && context.Reference.Reference is IEntity entity) { |
||||
Analyze(entity); |
||||
} |
||||
} |
||||
|
||||
public static void Analyze(IEntity entity) |
||||
{ |
||||
if (entity == null) |
||||
return; |
||||
switch (entity) { |
||||
case ITypeDefinition td: |
||||
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedTypeTreeNode(td)); |
||||
break; |
||||
case IField fd: |
||||
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedFieldTreeNode(fd)); |
||||
break; |
||||
case IMethod md: |
||||
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedMethodTreeNode(md)); |
||||
break; |
||||
case IProperty pd: |
||||
//AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedPropertyTreeNode(pd));
|
||||
break; |
||||
case IEvent ed: |
||||
//AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedEventTreeNode(ed));
|
||||
break; |
||||
default: |
||||
throw new NotSupportedException(); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,117 @@
@@ -0,0 +1,117 @@
|
||||
// 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; |
||||
using System.Collections.Generic; |
||||
using System.ComponentModel.Composition; |
||||
using System.Linq; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
using System.Threading; |
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.Disassembler; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
using ICSharpCode.ILSpy.Analyzers; |
||||
using ILOpCode = System.Reflection.Metadata.ILOpCode; |
||||
|
||||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
||||
{ |
||||
/// <summary>
|
||||
/// Finds methods where this field is read.
|
||||
/// </summary>
|
||||
[Export(typeof(IAnalyzer<IField>))] |
||||
class AssignedByFieldAccessAnalyzer : FieldAccessAnalyzer |
||||
{ |
||||
public AssignedByFieldAccessAnalyzer() : base(true) { } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Finds methods where this field is written.
|
||||
/// </summary>
|
||||
[Export(typeof(IAnalyzer<IField>))] |
||||
class ReadByFieldAccessAnalyzer : FieldAccessAnalyzer |
||||
{ |
||||
public ReadByFieldAccessAnalyzer() : base(false) { } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Finds methods where this field is read or written.
|
||||
/// </summary>
|
||||
class FieldAccessAnalyzer : IMethodBodyAnalyzer<IField> |
||||
{ |
||||
readonly bool showWrites; // true: show writes; false: show read access
|
||||
|
||||
public string Text => showWrites ? "Assigned By" : "Read By"; |
||||
|
||||
public FieldAccessAnalyzer(bool showWrites) |
||||
{ |
||||
this.showWrites = showWrites; |
||||
} |
||||
|
||||
public bool Show(IField field) |
||||
{ |
||||
return !showWrites || !field.IsConst; |
||||
} |
||||
|
||||
public IEnumerable<IEntity> Analyze(IField analyzedField, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context) |
||||
{ |
||||
bool found = false; |
||||
var blob = methodBody.GetILReader(); |
||||
|
||||
while (!found && blob.RemainingBytes > 0) { |
||||
var opCode = blob.DecodeOpCode(); |
||||
if (!CanBeReference(opCode)) { |
||||
blob.SkipOperand(opCode); |
||||
continue; |
||||
} |
||||
EntityHandle fieldHandle = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32()); |
||||
if (!fieldHandle.Kind.IsMemberKind()) |
||||
continue; |
||||
var field = context.TypeSystem.ResolveAsField(fieldHandle); |
||||
if (field == null) |
||||
continue; |
||||
|
||||
found = field.MetadataToken == analyzedField.MetadataToken |
||||
&& field.ParentAssembly.PEFile == analyzedField.ParentAssembly.PEFile; |
||||
} |
||||
|
||||
if (found) { |
||||
yield return method; |
||||
} |
||||
} |
||||
|
||||
bool CanBeReference(ILOpCode code) |
||||
{ |
||||
switch (code) { |
||||
case ILOpCode.Ldfld: |
||||
case ILOpCode.Ldsfld: |
||||
return !showWrites; |
||||
case ILOpCode.Stfld: |
||||
case ILOpCode.Stsfld: |
||||
return showWrites; |
||||
case ILOpCode.Ldflda: |
||||
case ILOpCode.Ldsflda: |
||||
return true; // always show address-loading
|
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,66 @@
@@ -0,0 +1,66 @@
|
||||
using System.Collections.Generic; |
||||
using System.ComponentModel.Composition; |
||||
using System.Linq; |
||||
using System.Reflection.Metadata; |
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.Disassembler; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
|
||||
namespace ICSharpCode.ILSpy.Analyzers.Builtin |
||||
{ |
||||
/// <summary>
|
||||
/// Shows entities that are used by a method.
|
||||
/// </summary>
|
||||
[Export(typeof(IAnalyzer<IMethod>))] |
||||
class MethodUsedByAnalyzer : IMethodBodyAnalyzer<IMethod> |
||||
{ |
||||
public string Text => "Used By"; |
||||
|
||||
public bool Show(IMethod entity) => true; |
||||
|
||||
public IEnumerable<IEntity> Analyze(IMethod analyzedMethod, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context) |
||||
{ |
||||
var blob = methodBody.GetILReader(); |
||||
|
||||
while (blob.RemainingBytes > 0) { |
||||
var opCode = blob.DecodeOpCode(); |
||||
switch (opCode.GetOperandType()) { |
||||
case OperandType.Field: |
||||
case OperandType.Method: |
||||
case OperandType.Sig: |
||||
case OperandType.Tok: |
||||
var member = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32()); |
||||
if (member.IsNil) continue; |
||||
|
||||
switch (member.Kind) { |
||||
case HandleKind.MethodDefinition: |
||||
case HandleKind.MethodSpecification: |
||||
case HandleKind.MemberReference: |
||||
var m = context.TypeSystem.ResolveAsMember(member)?.MemberDefinition; |
||||
if (m.MetadataToken == analyzedMethod.MetadataToken && m.ParentAssembly.PEFile == analyzedMethod.ParentAssembly.PEFile) { |
||||
yield return method; |
||||
yield break; |
||||
} |
||||
break; |
||||
} |
||||
break; |
||||
default: |
||||
ILParser.SkipOperand(ref blob, opCode); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
bool ScanMethodBody(PEFile module, int rva) |
||||
{ |
||||
var blob = module.Reader.GetMethodBody(rva).GetILReader(); |
||||
while (blob.RemainingBytes > 0) { |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,76 @@
@@ -0,0 +1,76 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.ComponentModel.Composition; |
||||
using System.Linq; |
||||
using System.Reflection.Metadata; |
||||
using System.Text; |
||||
using System.Threading.Tasks; |
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.Disassembler; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
|
||||
namespace ICSharpCode.ILSpy.Analyzers.Builtin |
||||
{ |
||||
/// <summary>
|
||||
/// Shows entities that are used by a method.
|
||||
/// </summary>
|
||||
[Export(typeof(IAnalyzer<IMethod>))] |
||||
class MethodUsesAnalyzer : IEntityAnalyzer<IMethod> |
||||
{ |
||||
public string Text => "Uses"; |
||||
|
||||
public bool Show(IMethod entity) => true; |
||||
|
||||
public IEnumerable<IEntity> Analyze(IMethod analyzedMethod, AnalyzerContext context) |
||||
{ |
||||
return context.CodeMappingInfo.GetMethodParts((MethodDefinitionHandle)analyzedMethod.MetadataToken) |
||||
.SelectMany(h => ScanMethod(analyzedMethod, h, context)).Distinct(); |
||||
} |
||||
|
||||
IEnumerable<IEntity> ScanMethod(IMethod analyzedMethod, MethodDefinitionHandle handle, AnalyzerContext context) |
||||
{ |
||||
var module = analyzedMethod.ParentAssembly.PEFile; |
||||
var md = module.Metadata.GetMethodDefinition(handle); |
||||
if (!md.HasBody()) yield break; |
||||
|
||||
var blob = module.Reader.GetMethodBody(md.RelativeVirtualAddress).GetILReader(); |
||||
|
||||
while (blob.RemainingBytes > 0) { |
||||
var opCode = blob.DecodeOpCode(); |
||||
switch (opCode.GetOperandType()) { |
||||
case OperandType.Field: |
||||
case OperandType.Method: |
||||
case OperandType.Sig: |
||||
case OperandType.Tok: |
||||
var member = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32()); |
||||
if (member.IsNil) continue; |
||||
|
||||
switch (member.Kind) { |
||||
case HandleKind.StandaloneSignature: |
||||
break; |
||||
case HandleKind.TypeDefinition: |
||||
case HandleKind.TypeReference: |
||||
case HandleKind.TypeSpecification: |
||||
var type = context.TypeSystem.ResolveAsType(member).GetDefinition(); |
||||
if (type != null) |
||||
yield return type; |
||||
break; |
||||
case HandleKind.MethodDefinition: |
||||
case HandleKind.MethodSpecification: |
||||
case HandleKind.MemberReference: |
||||
case HandleKind.FieldDefinition: |
||||
var m = context.TypeSystem.ResolveAsMember(member); |
||||
if (m != null) |
||||
yield return m; |
||||
break; |
||||
} |
||||
break; |
||||
default: |
||||
ILParser.SkipOperand(ref blob, opCode); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,48 @@
@@ -0,0 +1,48 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Reflection.Metadata; |
||||
using System.Text; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
|
||||
namespace ICSharpCode.ILSpy.Analyzers |
||||
{ |
||||
/// <summary>
|
||||
/// This is the common interface for all analyzers. Note: implementing this interface alone will not provide a full analyzer.
|
||||
/// You must implement either the <see cref="ITypeDefinitionAnalyzer{T}"/>, <see cref="IEntityAnalyzer{T}"/> or <see cref="IMethodBodyAnalyzer{T}"/> interfaces.
|
||||
/// </summary>
|
||||
public interface IAnalyzer<T> where T : IEntity |
||||
{ |
||||
string Text { get; } |
||||
bool Show(T entity); |
||||
} |
||||
|
||||
public interface IEntityAnalyzer<T> : IAnalyzer<T> where T : IEntity |
||||
{ |
||||
IEnumerable<IEntity> Analyze(T analyzedEntity, AnalyzerContext context); |
||||
} |
||||
|
||||
public interface ITypeDefinitionAnalyzer<T> : IAnalyzer<T> where T : IEntity |
||||
{ |
||||
IEnumerable<IEntity> Analyze(T analyzedEntity, ITypeDefinition type, AnalyzerContext context); |
||||
} |
||||
|
||||
public interface IMethodBodyAnalyzer<T> : IAnalyzer<T> where T : IEntity |
||||
{ |
||||
IEnumerable<IEntity> Analyze(T analyzedEntity, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context); |
||||
} |
||||
|
||||
public class AnalyzerContext |
||||
{ |
||||
public AnalyzerContext(IDecompilerTypeSystem typeSystem) |
||||
{ |
||||
this.TypeSystem = typeSystem; |
||||
} |
||||
|
||||
public IDecompilerTypeSystem TypeSystem { get; } |
||||
public CancellationToken CancellationToken { get; internal set; } |
||||
public CodeMappingInfo CodeMappingInfo { get; internal set; } |
||||
} |
||||
} |
@ -0,0 +1,269 @@
@@ -0,0 +1,269 @@
|
||||
// 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.Linq; |
||||
using System.Reflection; |
||||
using System.Reflection.Metadata; |
||||
using System.Threading; |
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
using ICSharpCode.Decompiler.Util; |
||||
using ICSharpCode.ILSpy.Analyzers; |
||||
|
||||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
||||
{ |
||||
/// <summary>
|
||||
/// Determines the accessibility domain of a member for where-used analysis.
|
||||
/// </summary>
|
||||
class ScopedWhereUsedAnalyzer<T> where T : IEntity |
||||
{ |
||||
readonly Language language; |
||||
readonly IAnalyzer<T> analyzer; |
||||
readonly IAssembly assemblyScope; |
||||
readonly T analyzedEntity; |
||||
ITypeDefinition typeScope; |
||||
|
||||
readonly Accessibility memberAccessibility = Accessibility.Public; |
||||
Accessibility typeAccessibility = Accessibility.Public; |
||||
|
||||
public ScopedWhereUsedAnalyzer(Language language, T analyzedEntity, IAnalyzer<T> analyzer) |
||||
{ |
||||
this.language = language ?? throw new ArgumentNullException(nameof(language)); |
||||
this.analyzer = analyzer ?? throw new ArgumentNullException(nameof(analyzer)); |
||||
this.analyzedEntity = analyzedEntity ; |
||||
this.assemblyScope = analyzedEntity.ParentAssembly; |
||||
if (analyzedEntity is ITypeDefinition type) { |
||||
this.typeScope = type; |
||||
this.typeAccessibility = type.Accessibility; |
||||
} else { |
||||
this.typeScope = analyzedEntity.DeclaringTypeDefinition; |
||||
this.typeAccessibility = this.typeScope.Accessibility; |
||||
this.memberAccessibility = analyzedEntity.Accessibility; |
||||
} |
||||
} |
||||
|
||||
public IEnumerable<IEntity> PerformAnalysis(CancellationToken ct) |
||||
{ |
||||
if (memberAccessibility == Accessibility.Private) { |
||||
return FindReferencesInTypeScope(ct); |
||||
} |
||||
|
||||
DetermineTypeAccessibility(); |
||||
|
||||
if (typeAccessibility == Accessibility.Private && typeScope.DeclaringType != null) { |
||||
return FindReferencesInEnclosingTypeScope(ct); |
||||
} |
||||
|
||||
if (memberAccessibility == Accessibility.Internal || |
||||
memberAccessibility == Accessibility.ProtectedOrInternal || |
||||
typeAccessibility == Accessibility.Internal || |
||||
typeAccessibility == Accessibility.ProtectedAndInternal) |
||||
return FindReferencesInAssemblyAndFriends(ct); |
||||
|
||||
return FindReferencesGlobal(ct); |
||||
} |
||||
|
||||
void DetermineTypeAccessibility() |
||||
{ |
||||
while (typeScope.DeclaringType != null) { |
||||
Accessibility accessibility = typeScope.Accessibility; |
||||
if ((int)typeAccessibility > (int)accessibility) { |
||||
typeAccessibility = accessibility; |
||||
if (typeAccessibility == Accessibility.Private) |
||||
return; |
||||
} |
||||
typeScope = typeScope.DeclaringTypeDefinition; |
||||
} |
||||
|
||||
if ((int)typeAccessibility > (int)Accessibility.Internal) { |
||||
typeAccessibility = Accessibility.Internal; |
||||
} |
||||
} |
||||
|
||||
IEnumerable<IEntity> FindReferencesInAssemblyAndFriends(CancellationToken ct) |
||||
{ |
||||
var assemblies = GetAssemblyAndAnyFriends(assemblyScope.PEFile, ct); |
||||
return assemblies.AsParallel().WithCancellation(ct).SelectMany(a => FindReferencesInAssembly(a, ct)); |
||||
} |
||||
|
||||
IEnumerable<IEntity> FindReferencesGlobal(CancellationToken ct) |
||||
{ |
||||
var assemblies = GetReferencingAssemblies(assemblyScope.PEFile, ct); |
||||
return assemblies.AsParallel().WithCancellation(ct).SelectMany(asm => FindReferencesInAssembly(asm, ct)); |
||||
} |
||||
|
||||
IEnumerable<IEntity> FindReferencesInAssembly(PEFile module, CancellationToken ct) |
||||
{ |
||||
var ts = new DecompilerTypeSystem(module, module.GetAssemblyResolver()); |
||||
var context = new AnalyzerContext(ts) { CancellationToken = ct }; |
||||
foreach (var type in ts.MainAssembly.TypeDefinitions) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
if (type.MetadataToken.IsNil) continue; |
||||
context.CodeMappingInfo = language.GetCodeMappingInfo(module, type.MetadataToken); |
||||
foreach (var result in RunAnalysisOn(module, type, context)) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
yield return result; |
||||
} |
||||
} |
||||
} |
||||
|
||||
IEnumerable<IEntity> FindReferencesInTypeScope(CancellationToken ct) |
||||
{ |
||||
var ts = new DecompilerTypeSystem(assemblyScope.PEFile, assemblyScope.PEFile.GetAssemblyResolver()); |
||||
var context = new AnalyzerContext(ts) { CancellationToken = ct }; |
||||
var types = TreeTraversal.PreOrder(typeScope, |
||||
t => t.GetNestedTypes(options: GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions) |
||||
.Select(td => td.GetDefinition())); |
||||
foreach (var type in types) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
if (type.MetadataToken.IsNil) continue; |
||||
context.CodeMappingInfo = language.GetCodeMappingInfo(assemblyScope.PEFile, type.MetadataToken); |
||||
foreach (var result in RunAnalysisOn(assemblyScope.PEFile, type, context)) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
yield return result; |
||||
} |
||||
} |
||||
} |
||||
|
||||
IEnumerable<IEntity> FindReferencesInEnclosingTypeScope(CancellationToken ct) |
||||
{ |
||||
var ts = new DecompilerTypeSystem(assemblyScope.PEFile, assemblyScope.PEFile.GetAssemblyResolver()); |
||||
var context = new AnalyzerContext(ts) { CancellationToken = ct }; |
||||
var types = TreeTraversal.PreOrder(typeScope.DeclaringTypeDefinition, |
||||
t => t.GetNestedTypes(options: GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions) |
||||
.Select(td => td.GetDefinition())); |
||||
foreach (var type in types) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
if (type.MetadataToken.IsNil) continue; |
||||
context.CodeMappingInfo = language.GetCodeMappingInfo(assemblyScope.PEFile, type.MetadataToken); |
||||
foreach (var result in RunAnalysisOn(assemblyScope.PEFile, type, context)) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
yield return result; |
||||
} |
||||
} |
||||
} |
||||
|
||||
IEnumerable<PEFile> GetReferencingAssemblies(PEFile asm, CancellationToken ct) |
||||
{ |
||||
yield return asm; |
||||
|
||||
IEnumerable<LoadedAssembly> assemblies = MainWindow.Instance.CurrentAssemblyList.GetAssemblies(); |
||||
foreach (var assembly in assemblies) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
bool found = false; |
||||
var module = assembly.GetPEFileOrNull(); |
||||
if (module == null || !module.IsAssembly) |
||||
continue; |
||||
var resolver = assembly.GetAssemblyResolver(); |
||||
foreach (var reference in module.AssemblyReferences) { |
||||
using (LoadedAssembly.DisableAssemblyLoad()) { |
||||
if (resolver.Resolve(reference) == asm) { |
||||
found = true; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if (found && AssemblyReferencesScopeType(module.Metadata, typeScope.Name, typeScope.Namespace)) |
||||
yield return module; |
||||
} |
||||
} |
||||
|
||||
IEnumerable<PEFile> GetAssemblyAndAnyFriends(PEFile asm, CancellationToken ct) |
||||
{ |
||||
yield return asm; |
||||
|
||||
var typeProvider = MetadataExtensions.MinimalAttributeTypeProvider; |
||||
var attributes = asm.Metadata.CustomAttributes.Select(h => asm.Metadata.GetCustomAttribute(h)) |
||||
.Where(ca => ca.GetAttributeType(asm.Metadata).GetFullTypeName(asm.Metadata).ToString() == "System.Runtime.CompilerServices.InternalsVisibleToAttribute"); |
||||
var friendAssemblies = new HashSet<string>(); |
||||
foreach (var attribute in attributes) { |
||||
string assemblyName = attribute.DecodeValue(typeProvider).FixedArguments[0].Value as string; |
||||
assemblyName = assemblyName.Split(',')[0]; // strip off any public key info
|
||||
friendAssemblies.Add(assemblyName); |
||||
} |
||||
|
||||
if (friendAssemblies.Count > 0) { |
||||
IEnumerable<LoadedAssembly> assemblies = MainWindow.Instance.CurrentAssemblyList.GetAssemblies(); |
||||
|
||||
foreach (var assembly in assemblies) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
if (friendAssemblies.Contains(assembly.ShortName)) { |
||||
var module = assembly.GetPEFileOrNull(); |
||||
if (module == null) |
||||
continue; |
||||
if (AssemblyReferencesScopeType(module.Metadata, typeScope.Name, typeScope.Namespace)) |
||||
yield return module; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
bool AssemblyReferencesScopeType(MetadataReader metadata, string typeScopeName, string typeScopeNamespace) |
||||
{ |
||||
bool hasRef = false; |
||||
foreach (var h in metadata.TypeReferences) { |
||||
var typeRef = metadata.GetTypeReference(h); |
||||
if (metadata.StringComparer.Equals(typeRef.Name, typeScopeName) && metadata.StringComparer.Equals(typeRef.Namespace, typeScopeNamespace)) { |
||||
hasRef = true; |
||||
break; |
||||
} |
||||
} |
||||
return hasRef; |
||||
} |
||||
|
||||
IEnumerable<IEntity> RunAnalysisOn(PEFile module, ITypeDefinition type, AnalyzerContext context) |
||||
{ |
||||
if (analyzer is IMethodBodyAnalyzer<T> methodAnalyzer) { |
||||
var reader = module.Reader; |
||||
foreach (var method in type.GetMethods(options: GetMemberOptions.IgnoreInheritedMembers)) { |
||||
if (!method.HasBody || method.MetadataToken.IsNil) continue; |
||||
var md = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken); |
||||
var body = reader.GetMethodBody(md.RelativeVirtualAddress); |
||||
foreach (var result in methodAnalyzer.Analyze(analyzedEntity, method, body, context)) |
||||
yield return GetParentEntity(context, result); |
||||
} |
||||
foreach (var method in type.GetAccessors(options: GetMemberOptions.IgnoreInheritedMembers)) { |
||||
if (!method.HasBody || method.MetadataToken.IsNil) continue; |
||||
var md = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken); |
||||
var body = reader.GetMethodBody(md.RelativeVirtualAddress); |
||||
foreach (var result in methodAnalyzer.Analyze(analyzedEntity, method, body, context)) |
||||
yield return GetParentEntity(context, result); |
||||
} |
||||
} |
||||
if (analyzer is ITypeDefinitionAnalyzer<T> typeDefinitionAnalyzer) { |
||||
foreach (var result in typeDefinitionAnalyzer.Analyze(analyzedEntity, type, context)) |
||||
yield return GetParentEntity(context, result); |
||||
} |
||||
} |
||||
|
||||
private IEntity GetParentEntity(AnalyzerContext context, IEntity entity) |
||||
{ |
||||
if (entity.MetadataToken.Kind == HandleKind.MethodDefinition && !entity.MetadataToken.IsNil) { |
||||
var parentHandle = context.CodeMappingInfo.GetParentMethod((MethodDefinitionHandle)entity.MetadataToken); |
||||
var method = context.TypeSystem.ResolveAsMethod(parentHandle); |
||||
if (method != null) { |
||||
return method.AccessorOwner ?? method; |
||||
} |
||||
} |
||||
return entity; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
// 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.Reflection; |
||||
using System.Reflection.Metadata; |
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
using ICSharpCode.ILSpy.Analyzers; |
||||
|
||||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
||||
{ |
||||
internal class AnalyzedMethodTreeNode : AnalyzerEntityTreeNode |
||||
{ |
||||
readonly IMethod analyzedMethod; |
||||
readonly string prefix; |
||||
|
||||
public AnalyzedMethodTreeNode(IMethod analyzedMethod, string prefix = "") |
||||
{ |
||||
this.analyzedMethod = analyzedMethod ?? throw new ArgumentNullException(nameof(analyzedMethod)); |
||||
this.prefix = prefix; |
||||
this.LazyLoading = true; |
||||
} |
||||
|
||||
public override object Icon => MethodTreeNode.GetIcon(analyzedMethod); |
||||
|
||||
public override object Text => prefix + Language.MethodToString(analyzedMethod, true, true); |
||||
|
||||
protected override void LoadChildren() |
||||
{ |
||||
foreach (var lazy in App.ExportProvider.GetExports<IAnalyzer<IMethod>>()) { |
||||
var analyzer = lazy.Value; |
||||
if (analyzer.Show(analyzedMethod)) { |
||||
this.Children.Add(new AnalyzerSearchTreeNode<IMethod>(analyzedMethod, analyzer)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public override IEntity Member => analyzedMethod; |
||||
} |
||||
} |
@ -1,135 +0,0 @@
@@ -1,135 +0,0 @@
|
||||
// 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.Linq; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
|
||||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
||||
{ |
||||
[ExportContextMenuEntry(Header = "Analyze", Icon = "images/Search.png", Category = "Analyze", Order = 100)] |
||||
internal sealed class AnalyzeContextMenuEntry : IContextMenuEntry |
||||
{ |
||||
public bool IsVisible(TextViewContext context) |
||||
{ |
||||
if (context.TreeView is AnalyzerTreeView && context.SelectedTreeNodes != null && context.SelectedTreeNodes.All(n => n.Parent.IsRoot)) |
||||
return false; |
||||
if (context.SelectedTreeNodes == null) |
||||
return context.Reference != null && IsValidReference(context.Reference.Reference); |
||||
return context.SelectedTreeNodes.All(n => n is IMemberTreeNode); |
||||
} |
||||
|
||||
public bool IsEnabled(TextViewContext context) |
||||
{ |
||||
if (context.SelectedTreeNodes == null) |
||||
return context.Reference != null && context.Reference.Reference is IEntity; |
||||
foreach (IMemberTreeNode node in context.SelectedTreeNodes) { |
||||
if (!IsValidReference(node.Member)) |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool IsValidReference(object reference) |
||||
{ |
||||
return reference is IEntity; |
||||
} |
||||
|
||||
public void Execute(TextViewContext context) |
||||
{ |
||||
if (context.SelectedTreeNodes != null) { |
||||
foreach (IMemberTreeNode node in context.SelectedTreeNodes) { |
||||
Analyze(node.Member); |
||||
} |
||||
} else if (context.Reference != null && IsValidReference(context.Reference.Reference)) { |
||||
Analyze(context.Reference.Reference); |
||||
} |
||||
} |
||||
|
||||
public static void Analyze(object member) |
||||
{/* |
||||
switch (member) { |
||||
case IMetadataEntity entity: |
||||
switch (entity) { |
||||
case TypeDefinition td: |
||||
if (!td.IsNil) |
||||
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedTypeTreeNode(td)); |
||||
break; |
||||
case FieldDefinition fd: |
||||
if (!fd.IsNil) |
||||
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedFieldTreeNode(fd.Module, fd.Handle)); |
||||
break; |
||||
case MethodDefinition md: |
||||
if (!md.IsNil) |
||||
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedMethodTreeNode(md.Module, md.Handle)); |
||||
break; |
||||
case PropertyDefinition pd: |
||||
//if (!pd.IsNil)
|
||||
// AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedPropertyTreeNode(pd));
|
||||
break; |
||||
case EventDefinition ed: |
||||
//if (!ed.IsNil)
|
||||
// AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedEventTreeNode(ed));
|
||||
break; |
||||
default: |
||||
throw new NotSupportedException(); |
||||
} |
||||
break; |
||||
case TypeReference tr: |
||||
var resolved = tr.Handle.Resolve(new SimpleMetadataResolveContext(tr.Module)); |
||||
if (!resolved.IsNil) |
||||
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedTypeTreeNode(resolved)); |
||||
break; |
||||
case TypeSpecification ts: |
||||
resolved = ts.Handle.Resolve(new SimpleMetadataResolveContext(ts.Module)); |
||||
if (!resolved.IsNil) |
||||
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedTypeTreeNode(resolved)); |
||||
break; |
||||
case MemberReference mr: |
||||
var resolvedMember = mr.Handle.Resolve(new SimpleMetadataResolveContext(mr.Module)); |
||||
if (!resolvedMember.IsNil) { |
||||
switch (resolvedMember) { |
||||
case FieldDefinition fd: |
||||
//AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedFieldTreeNode(fd));
|
||||
break; |
||||
case MethodDefinition md: |
||||
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedMethodTreeNode(md.Module, md.Handle)); |
||||
break; |
||||
default: |
||||
throw new NotSupportedException(); |
||||
} |
||||
} |
||||
break; |
||||
case MethodSpecification ms: |
||||
resolvedMember = ms.Handle.Resolve(new SimpleMetadataResolveContext(ms.Module)); |
||||
if (!resolvedMember.IsNil) { |
||||
switch (resolvedMember) { |
||||
case MethodDefinition md: |
||||
AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedMethodTreeNode(md.Module, md.Handle)); |
||||
break; |
||||
default: |
||||
throw new NotSupportedException(); |
||||
} |
||||
} |
||||
break; |
||||
} |
||||
*/ |
||||
} |
||||
} |
||||
} |
@ -1,145 +0,0 @@
@@ -1,145 +0,0 @@
|
||||
// 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; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
using System.Threading; |
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.Disassembler; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
using ILOpCode = System.Reflection.Metadata.ILOpCode; |
||||
|
||||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
||||
{ |
||||
/// <summary>
|
||||
/// Finds methods where this field is read or written.
|
||||
/// </summary>
|
||||
sealed class AnalyzedFieldAccessTreeNode : AnalyzerSearchTreeNode |
||||
{ |
||||
readonly bool showWrites; // true: show writes; false: show read access
|
||||
readonly Decompiler.Metadata.PEFile module; |
||||
readonly FieldDefinitionHandle analyzedField; |
||||
readonly FullTypeName analyzedTypeName; |
||||
readonly string analyzedFieldName; |
||||
Lazy<HashSet<Decompiler.Metadata.MethodDefinition>> foundMethods; |
||||
readonly object hashLock = new object(); |
||||
|
||||
public AnalyzedFieldAccessTreeNode(Decompiler.Metadata.PEFile module, FieldDefinitionHandle analyzedField, bool showWrites) |
||||
{ |
||||
if (analyzedField.IsNil) |
||||
throw new ArgumentNullException(nameof(analyzedField)); |
||||
|
||||
this.module = module; |
||||
this.analyzedField = analyzedField; |
||||
var fd = module.Metadata.GetFieldDefinition(analyzedField); |
||||
this.analyzedTypeName = fd.GetDeclaringType().GetFullTypeName(module.Metadata); |
||||
this.analyzedFieldName = module.Metadata.GetString(fd.Name); |
||||
this.showWrites = showWrites; |
||||
} |
||||
|
||||
public override object Text => showWrites ? "Assigned By" : "Read By"; |
||||
|
||||
protected override IEnumerable<AnalyzerTreeNode> FetchChildren(CancellationToken ct) |
||||
{ |
||||
foundMethods = new Lazy<HashSet<Decompiler.Metadata.MethodDefinition>>(LazyThreadSafetyMode.ExecutionAndPublication); |
||||
|
||||
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(this.Language, module, analyzedField, provideTypeSystem: false, FindReferencesInType); |
||||
foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { |
||||
yield return child; |
||||
} |
||||
|
||||
foundMethods = null; |
||||
} |
||||
|
||||
private IEnumerable<AnalyzerTreeNode> FindReferencesInType(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, CodeMappingInfo codeMapping, IDecompilerTypeSystem typeSystem) |
||||
{ |
||||
var td = module.Metadata.GetTypeDefinition(type); |
||||
foreach (var h in td.GetMethods()) { |
||||
bool found = false; |
||||
|
||||
var method = module.Metadata.GetMethodDefinition(h); |
||||
if (!method.HasBody()) |
||||
continue; |
||||
|
||||
var blob = module.Reader.GetMethodBody(method.RelativeVirtualAddress).GetILReader(); |
||||
while (!found && blob.RemainingBytes > 0) { |
||||
var opCode = blob.DecodeOpCode(); |
||||
if (!CanBeReference(opCode)) { |
||||
blob.SkipOperand(opCode); |
||||
continue; |
||||
} |
||||
var member = MetadataTokens.EntityHandle(blob.ReadInt32()); |
||||
switch (member.Kind) { |
||||
case HandleKind.FieldDefinition: |
||||
// check whether we're looking at the defining assembly
|
||||
found = member == analyzedField && module == this.module; |
||||
break; |
||||
case HandleKind.MemberReference: |
||||
var mr = module.Metadata.GetMemberReference((MemberReferenceHandle)member); |
||||
// safety-check: should always be a field
|
||||
if (mr.GetKind() != MemberReferenceKind.Field) |
||||
break; |
||||
if (!module.Metadata.StringComparer.Equals(mr.Name, analyzedFieldName)) |
||||
break; |
||||
var typeName = mr.Parent.GetFullTypeName(module.Metadata); |
||||
found = typeName == analyzedTypeName; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (found) { |
||||
var md = new Decompiler.Metadata.MethodDefinition(module, h); |
||||
if (IsNewResult(md)) { |
||||
var node = new AnalyzedMethodTreeNode(module, h); |
||||
node.Language = this.Language; |
||||
yield return node; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
bool CanBeReference(ILOpCode code) |
||||
{ |
||||
switch (code) { |
||||
case ILOpCode.Ldfld: |
||||
case ILOpCode.Ldsfld: |
||||
return !showWrites; |
||||
case ILOpCode.Stfld: |
||||
case ILOpCode.Stsfld: |
||||
return showWrites; |
||||
case ILOpCode.Ldflda: |
||||
case ILOpCode.Ldsflda: |
||||
return true; // always show address-loading
|
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
bool IsNewResult(Decompiler.Metadata.MethodDefinition method) |
||||
{ |
||||
var hashSet = foundMethods.Value; |
||||
lock (hashLock) { |
||||
return hashSet.Add(method); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,65 +0,0 @@
@@ -1,65 +0,0 @@
|
||||
// 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.Reflection; |
||||
using System.Reflection.Metadata; |
||||
using ICSharpCode.Decompiler; |
||||
|
||||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
||||
{ |
||||
internal class AnalyzedMethodTreeNode : AnalyzerEntityTreeNode |
||||
{ |
||||
readonly Decompiler.Metadata.PEFile module; |
||||
readonly MethodDefinitionHandle analyzedMethod; |
||||
readonly string prefix; |
||||
|
||||
public AnalyzedMethodTreeNode(Decompiler.Metadata.PEFile module, MethodDefinitionHandle analyzedMethod, string prefix = "") |
||||
{ |
||||
if (analyzedMethod.IsNil) |
||||
throw new ArgumentNullException(nameof(analyzedMethod)); |
||||
this.module = module; |
||||
this.analyzedMethod = analyzedMethod; |
||||
this.prefix = prefix; |
||||
this.LazyLoading = true; |
||||
} |
||||
|
||||
public override object Icon => MethodTreeNode.GetIcon(new Decompiler.Metadata.MethodDefinition(module, analyzedMethod)); |
||||
|
||||
public override object Text => prefix + Language.MethodToString(new Decompiler.Metadata.MethodDefinition(module, analyzedMethod), true, true); |
||||
|
||||
protected override void LoadChildren() |
||||
{ |
||||
if (module.Metadata.GetMethodDefinition(analyzedMethod).HasBody()) |
||||
this.Children.Add(new AnalyzedMethodUsesTreeNode(module, analyzedMethod)); |
||||
|
||||
/*if (analyzedMethod.HasFlag(MethodAttributes.Virtual) && !(analyzedMethod.HasFlag(MethodAttributes.NewSlot) && analyzedMethod.HasFlag(MethodAttributes.Final))) |
||||
this.Children.Add(new AnalyzedVirtualMethodUsedByTreeNode(analyzedMethod)); |
||||
else*/ |
||||
this.Children.Add(new AnalyzedMethodUsedByTreeNode(module, analyzedMethod)); |
||||
|
||||
/*if (AnalyzedMethodOverridesTreeNode.CanShow(analyzedMethod)) |
||||
this.Children.Add(new AnalyzedMethodOverridesTreeNode(analyzedMethod)); |
||||
|
||||
if (AnalyzedInterfaceMethodImplementedByTreeNode.CanShow(analyzedMethod)) |
||||
this.Children.Add(new AnalyzedInterfaceMethodImplementedByTreeNode(analyzedMethod));*/ |
||||
} |
||||
|
||||
public override Decompiler.Metadata.IMetadataEntity Member => new Decompiler.Metadata.MethodDefinition(module, analyzedMethod); |
||||
} |
||||
} |
@ -1,96 +0,0 @@
@@ -1,96 +0,0 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Reflection.Metadata; |
||||
using System.Text; |
||||
using System.Threading.Tasks; |
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
||||
{ |
||||
public static class Helpers |
||||
{ |
||||
public static TypeDefinitionHandle GetDeclaringType(this MethodDefinitionHandle method, MetadataReader metadata) |
||||
{ |
||||
if (method.IsNil) |
||||
throw new ArgumentNullException(nameof(method)); |
||||
return metadata.GetMethodDefinition(method).GetDeclaringType(); |
||||
} |
||||
|
||||
public static TypeDefinitionHandle GetDeclaringType(this FieldDefinitionHandle field, MetadataReader metadata) |
||||
{ |
||||
if (field.IsNil) |
||||
throw new ArgumentNullException(nameof(field)); |
||||
return metadata.GetFieldDefinition(field).GetDeclaringType(); |
||||
} |
||||
|
||||
public static TypeDefinitionHandle GetDeclaringType(this PropertyDefinitionHandle property, MetadataReader metadata) |
||||
{ |
||||
if (property.IsNil) |
||||
throw new ArgumentNullException(nameof(property)); |
||||
var accessor = metadata.GetPropertyDefinition(property).GetAccessors().GetAny(); |
||||
return metadata.GetMethodDefinition(accessor).GetDeclaringType(); |
||||
} |
||||
|
||||
public static TypeDefinitionHandle GetDeclaringType(this EventDefinitionHandle @event, MetadataReader metadata) |
||||
{ |
||||
if (@event.IsNil) |
||||
throw new ArgumentNullException(nameof(@event)); |
||||
var accessor = metadata.GetEventDefinition(@event).GetAccessors().GetAny(); |
||||
return metadata.GetMethodDefinition(accessor).GetDeclaringType(); |
||||
} |
||||
|
||||
public static bool IsSameMethod(MethodDefinitionHandle method, PEFile definitionModule, EntityHandle entity, PEFile entityModule) |
||||
{ |
||||
if (method.IsNil || entity.IsNil) |
||||
return false; |
||||
var md = definitionModule.Metadata.GetMethodDefinition(method); |
||||
if (entity.Kind == HandleKind.MethodSpecification) { |
||||
var ms = entityModule.Metadata.GetMethodSpecification((MethodSpecificationHandle)entity); |
||||
entity = ms.Method; |
||||
} |
||||
switch (entity.Kind) { |
||||
case HandleKind.MethodDefinition: |
||||
return method == entity && definitionModule == entityModule; |
||||
case HandleKind.MemberReference: |
||||
var mr = entityModule.Metadata.GetMemberReference((MemberReferenceHandle)entity); |
||||
if (mr.GetKind() != MemberReferenceKind.Method) |
||||
return false; |
||||
if (!entityModule.Metadata.StringComparer.Equals(mr.Name, definitionModule.Metadata.GetString(md.Name))) |
||||
return false; |
||||
if (mr.Parent.Kind.IsTypeKind()) { |
||||
if (!IsSameType(md.GetDeclaringType(), definitionModule, mr.Parent, entityModule)) |
||||
return false; |
||||
} else { |
||||
// TODO ...
|
||||
} |
||||
return SignatureBlobComparer.EqualsMethodSignature( |
||||
definitionModule.Metadata.GetBlobReader(md.Signature), |
||||
entityModule.Metadata.GetBlobReader(mr.Signature), |
||||
definitionModule.Metadata, entityModule.Metadata); |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public static bool IsSameType(TypeDefinitionHandle type, PEFile module, EntityHandle entity, PEFile entityModule) |
||||
{ |
||||
if (type.IsNil || entity.IsNil) |
||||
return false; |
||||
var td = module.Metadata.GetTypeDefinition(type); |
||||
if (entity.Kind == HandleKind.TypeSpecification) { |
||||
var ts = entityModule.Metadata.GetTypeSpecification((TypeSpecificationHandle)entity); |
||||
entity = ts.DecodeSignature(new Unspecializer(), default); |
||||
} |
||||
switch (entity.Kind) { |
||||
case HandleKind.TypeDefinition: |
||||
return type == entity && module == entityModule; |
||||
case HandleKind.TypeReference: |
||||
return type.GetFullTypeName(module.Metadata) == entity.GetFullTypeName(entityModule.Metadata); |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,144 +0,0 @@
@@ -1,144 +0,0 @@
|
||||
// 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.Linq; |
||||
using ICSharpCode.Decompiler; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
|
||||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
||||
{ |
||||
internal static class Helpers |
||||
{ |
||||
public static bool IsSameType(TypeDefinition type, TypeReference typeRef) |
||||
{ |
||||
// TODO: move it to a better place after adding support for more cases.
|
||||
if (type == null) |
||||
throw new ArgumentNullException(nameof(type)); |
||||
if (typeRef == null) |
||||
throw new ArgumentNullException(nameof(typeRef)); |
||||
|
||||
if (type == typeRef) |
||||
return true; |
||||
if (type.Name != typeRef.Name) |
||||
return false; |
||||
if (type.Namespace != typeRef.Namespace) |
||||
return false; |
||||
|
||||
if (type.DeclaringType != null || typeRef.DeclaringType != null) { |
||||
if (type.DeclaringType == null || typeRef.DeclaringType == null) |
||||
return false; |
||||
if (!IsSameType(type.DeclaringType, typeRef.DeclaringType)) |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
public static MemberReference GetOriginalCodeLocation(MemberReference member) |
||||
{ |
||||
if (member is MethodDefinition) |
||||
return GetOriginalCodeLocation((MethodDefinition)member); |
||||
return member; |
||||
} |
||||
|
||||
public static MethodDefinition GetOriginalCodeLocation(MethodDefinition method) |
||||
{ |
||||
if (method.IsCompilerGenerated()) { |
||||
return FindMethodUsageInType(method.DeclaringType, method) ?? method; |
||||
} |
||||
|
||||
var typeUsage = GetOriginalCodeLocation(method.DeclaringType); |
||||
|
||||
return typeUsage ?? method; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Given a compiler-generated type, returns the method where that type is used.
|
||||
/// Used to detect the 'parent method' for a lambda/iterator/async state machine.
|
||||
/// </summary>
|
||||
public static MethodDefinition GetOriginalCodeLocation(TypeDefinition type) |
||||
{ |
||||
if (type != null && type.DeclaringType != null && type.IsCompilerGenerated()) { |
||||
if (type.IsValueType) { |
||||
// Value types might not have any constructor; but they must be stored in a local var
|
||||
// because 'initobj' (or 'call .ctor') expects a managed ref.
|
||||
return FindVariableOfTypeUsageInType(type.DeclaringType, type); |
||||
} else { |
||||
MethodDefinition constructor = GetTypeConstructor(type); |
||||
if (constructor == null) |
||||
return null; |
||||
return FindMethodUsageInType(type.DeclaringType, constructor); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
private static MethodDefinition GetTypeConstructor(TypeDefinition type) |
||||
{ |
||||
return type.Methods.FirstOrDefault(method => !method.IsStatic && method.IsConstructor); |
||||
} |
||||
|
||||
private static MethodDefinition FindMethodUsageInType(TypeDefinition type, MethodDefinition analyzedMethod) |
||||
{ |
||||
string name = analyzedMethod.Name; |
||||
foreach (MethodDefinition method in type.Methods) { |
||||
bool found = false; |
||||
if (!method.HasBody) |
||||
continue; |
||||
foreach (Instruction instr in method.Body.Instructions) { |
||||
MethodReference mr = instr.Operand as MethodReference; |
||||
if (mr != null && mr.Name == name && |
||||
IsSameType(analyzedMethod.DeclaringType, mr.DeclaringType) && |
||||
mr.Resolve() == analyzedMethod) { |
||||
found = true; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
method.Body = null; |
||||
|
||||
if (found) |
||||
return method; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
private static MethodDefinition FindVariableOfTypeUsageInType(TypeDefinition type, TypeDefinition variableType) |
||||
{ |
||||
foreach (MethodDefinition method in type.Methods) { |
||||
bool found = false; |
||||
if (!method.HasBody) |
||||
continue; |
||||
foreach (var v in method.Body.Variables) { |
||||
if (v.VariableType.ResolveWithinSameModule() == variableType) { |
||||
found = true; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
method.Body = null; |
||||
|
||||
if (found) |
||||
return method; |
||||
} |
||||
return null; |
||||
} |
||||
} |
||||
} |
@ -1,350 +0,0 @@
@@ -1,350 +0,0 @@
|
||||
// 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.Linq; |
||||
using System.Reflection; |
||||
using System.Reflection.Metadata; |
||||
using System.Threading; |
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
using ICSharpCode.Decompiler.TypeSystem.Implementation; |
||||
using ICSharpCode.Decompiler.Util; |
||||
|
||||
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer |
||||
{ |
||||
/// <summary>
|
||||
/// Determines the accessibility domain of a member for where-used analysis.
|
||||
/// </summary>
|
||||
class ScopedWhereUsedAnalyzer<T> |
||||
{ |
||||
readonly Language language; |
||||
readonly Decompiler.Metadata.PEFile assemblyScope; |
||||
readonly bool provideTypeSystem; |
||||
TypeDefinitionHandle typeScopeHandle; |
||||
TypeDefinition typeScope; |
||||
|
||||
readonly Accessibility memberAccessibility = Accessibility.Public; |
||||
Accessibility typeAccessibility = Accessibility.Public; |
||||
readonly Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, CodeMappingInfo, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction; |
||||
|
||||
public ScopedWhereUsedAnalyzer(Language language, Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, CodeMappingInfo, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction) |
||||
{ |
||||
this.language = language; |
||||
this.typeScopeHandle = type; |
||||
this.assemblyScope = module; |
||||
this.typeScope = module.Metadata.GetTypeDefinition(typeScopeHandle); |
||||
this.provideTypeSystem = provideTypeSystem; |
||||
this.typeAnalysisFunction = typeAnalysisFunction; |
||||
} |
||||
|
||||
public ScopedWhereUsedAnalyzer(Language language, Decompiler.Metadata.PEFile module, MethodDefinitionHandle method, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, CodeMappingInfo, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction) |
||||
: this(language, module, method.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction) |
||||
{ |
||||
this.memberAccessibility = GetMethodAccessibility(module.Metadata, method); |
||||
} |
||||
|
||||
public ScopedWhereUsedAnalyzer(Language language, Decompiler.Metadata.PEFile module, PropertyDefinitionHandle property, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, CodeMappingInfo, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction) |
||||
: this(language, module, property.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction) |
||||
{ |
||||
var pd = module.Metadata.GetPropertyDefinition(property); |
||||
var accessors = pd.GetAccessors(); |
||||
Accessibility getterAccessibility = (accessors.Getter.IsNil) ? Accessibility.Private : GetMethodAccessibility(module.Metadata, accessors.Getter); |
||||
Accessibility setterAccessibility = (accessors.Setter.IsNil) ? Accessibility.Private : GetMethodAccessibility(module.Metadata, accessors.Setter); |
||||
this.memberAccessibility = (Accessibility)Math.Max((int)getterAccessibility, (int)setterAccessibility); |
||||
} |
||||
|
||||
public ScopedWhereUsedAnalyzer(Language language, Decompiler.Metadata.PEFile module, EventDefinitionHandle eventDef, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, CodeMappingInfo, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction) |
||||
: this(language, module, eventDef.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction) |
||||
{ |
||||
// we only have to check the accessibility of the the get method
|
||||
// [CLS Rule 30: The accessibility of an event and of its accessors shall be identical.]
|
||||
var ed = module.Metadata.GetEventDefinition(eventDef); |
||||
this.memberAccessibility = GetMethodAccessibility(module.Metadata, ed.GetAccessors().Adder); |
||||
} |
||||
|
||||
public ScopedWhereUsedAnalyzer(Language language, Decompiler.Metadata.PEFile module, FieldDefinitionHandle field, bool provideTypeSystem, Func<Decompiler.Metadata.PEFile, TypeDefinitionHandle, CodeMappingInfo, IDecompilerTypeSystem, IEnumerable<T>> typeAnalysisFunction) |
||||
: this(language, module, field.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction) |
||||
{ |
||||
var fd = module.Metadata.GetFieldDefinition(field); |
||||
switch (fd.Attributes & FieldAttributes.FieldAccessMask) { |
||||
case FieldAttributes.Private: |
||||
default: |
||||
memberAccessibility = Accessibility.Private; |
||||
break; |
||||
case FieldAttributes.FamANDAssem: |
||||
memberAccessibility = Accessibility.FamilyAndInternal; |
||||
break; |
||||
case FieldAttributes.Assembly: |
||||
memberAccessibility = Accessibility.Internal; |
||||
break; |
||||
case FieldAttributes.Family: |
||||
memberAccessibility = Accessibility.Family; |
||||
break; |
||||
case FieldAttributes.FamORAssem: |
||||
memberAccessibility = Accessibility.FamilyOrInternal; |
||||
break; |
||||
case FieldAttributes.Public: |
||||
memberAccessibility = Accessibility.Public; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
Accessibility GetMethodAccessibility(MetadataReader metadata, MethodDefinitionHandle method) |
||||
{ |
||||
Accessibility accessibility; |
||||
var methodInfo = metadata.GetMethodDefinition(method); |
||||
switch (methodInfo.Attributes & MethodAttributes.MemberAccessMask) { |
||||
case MethodAttributes.Private: |
||||
default: |
||||
accessibility = Accessibility.Private; |
||||
break; |
||||
case MethodAttributes.FamANDAssem: |
||||
accessibility = Accessibility.FamilyAndInternal; |
||||
break; |
||||
case MethodAttributes.Family: |
||||
accessibility = Accessibility.Family; |
||||
break; |
||||
case MethodAttributes.Assembly: |
||||
accessibility = Accessibility.Internal; |
||||
break; |
||||
case MethodAttributes.FamORAssem: |
||||
accessibility = Accessibility.FamilyOrInternal; |
||||
break; |
||||
case MethodAttributes.Public: |
||||
accessibility = Accessibility.Public; |
||||
break; |
||||
} |
||||
return accessibility; |
||||
} |
||||
|
||||
public IEnumerable<T> PerformAnalysis(CancellationToken ct) |
||||
{ |
||||
if (memberAccessibility == Accessibility.Private) { |
||||
return FindReferencesInTypeScope(ct); |
||||
} |
||||
|
||||
DetermineTypeAccessibility(); |
||||
|
||||
if (typeAccessibility == Accessibility.Private) { |
||||
return FindReferencesInEnclosingTypeScope(ct); |
||||
} |
||||
|
||||
if (memberAccessibility == Accessibility.Internal || |
||||
memberAccessibility == Accessibility.FamilyAndInternal || |
||||
typeAccessibility == Accessibility.Internal || |
||||
typeAccessibility == Accessibility.FamilyAndInternal) |
||||
return FindReferencesInAssemblyAndFriends(ct); |
||||
|
||||
return FindReferencesGlobal(ct); |
||||
} |
||||
|
||||
void DetermineTypeAccessibility() |
||||
{ |
||||
while (!typeScope.GetDeclaringType().IsNil) { |
||||
Accessibility accessibility = GetNestedTypeAccessibility(typeScope); |
||||
if ((int)typeAccessibility > (int)accessibility) { |
||||
typeAccessibility = accessibility; |
||||
if (typeAccessibility == Accessibility.Private) |
||||
return; |
||||
} |
||||
typeScopeHandle = typeScope.GetDeclaringType(); |
||||
typeScope = assemblyScope.Metadata.GetTypeDefinition(typeScopeHandle); |
||||
} |
||||
|
||||
if ((typeScope.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NotPublic && |
||||
((int)typeAccessibility > (int)Accessibility.Internal)) { |
||||
typeAccessibility = Accessibility.Internal; |
||||
} |
||||
} |
||||
|
||||
static Accessibility GetNestedTypeAccessibility(TypeDefinition type) |
||||
{ |
||||
Accessibility result; |
||||
switch (type.Attributes & TypeAttributes.VisibilityMask) { |
||||
case TypeAttributes.NestedPublic: |
||||
result = Accessibility.Public; |
||||
break; |
||||
case TypeAttributes.NestedPrivate: |
||||
result = Accessibility.Private; |
||||
break; |
||||
case TypeAttributes.NestedFamily: |
||||
result = Accessibility.Family; |
||||
break; |
||||
case TypeAttributes.NestedAssembly: |
||||
result = Accessibility.Internal; |
||||
break; |
||||
case TypeAttributes.NestedFamANDAssem: |
||||
result = Accessibility.FamilyAndInternal; |
||||
break; |
||||
case TypeAttributes.NestedFamORAssem: |
||||
result = Accessibility.FamilyOrInternal; |
||||
break; |
||||
default: |
||||
throw new InvalidOperationException(); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The effective accessibility of a member
|
||||
/// </summary>
|
||||
enum Accessibility |
||||
{ |
||||
Private, |
||||
FamilyAndInternal, |
||||
Internal, |
||||
Family, |
||||
FamilyOrInternal, |
||||
Public |
||||
} |
||||
|
||||
IEnumerable<T> FindReferencesInAssemblyAndFriends(CancellationToken ct) |
||||
{ |
||||
var assemblies = GetAssemblyAndAnyFriends(assemblyScope, ct); |
||||
|
||||
// use parallelism only on the assembly level (avoid locks within Cecil)
|
||||
return assemblies.AsParallel().WithCancellation(ct).SelectMany(a => FindReferencesInAssembly(a, ct)); |
||||
} |
||||
|
||||
IEnumerable<T> FindReferencesGlobal(CancellationToken ct) |
||||
{ |
||||
var assemblies = GetReferencingAssemblies(assemblyScope, ct); |
||||
|
||||
// use parallelism only on the assembly level (avoid locks within Cecil)
|
||||
return assemblies.AsParallel().WithCancellation(ct).SelectMany(asm => FindReferencesInAssembly(asm, ct)); |
||||
} |
||||
|
||||
IEnumerable<T> FindReferencesInAssembly(Decompiler.Metadata.PEFile module, CancellationToken ct) |
||||
{ |
||||
IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(module, module.GetAssemblyResolver()) : null; |
||||
var metadata = module.Metadata; |
||||
foreach (var type in TreeTraversal.PreOrder(metadata.TypeDefinitions, t => metadata.GetTypeDefinition(t).GetNestedTypes())) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
var codeMappingInfo = language.GetCodeMappingInfo(assemblyScope, type); |
||||
foreach (var result in typeAnalysisFunction(module, type, codeMappingInfo, ts)) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
yield return result; |
||||
} |
||||
} |
||||
} |
||||
|
||||
IEnumerable<T> FindReferencesInTypeScope(CancellationToken ct) |
||||
{ |
||||
IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope, assemblyScope.GetAssemblyResolver()) : null; |
||||
foreach (var type in TreeTraversal.PreOrder(typeScopeHandle, t => assemblyScope.Metadata.GetTypeDefinition(t).GetNestedTypes())) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
var codeMappingInfo = language.GetCodeMappingInfo(assemblyScope, type); |
||||
foreach (var result in typeAnalysisFunction(assemblyScope, type, codeMappingInfo, ts)) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
yield return result; |
||||
} |
||||
} |
||||
} |
||||
|
||||
IEnumerable<T> FindReferencesInEnclosingTypeScope(CancellationToken ct) |
||||
{ |
||||
IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope, assemblyScope.GetAssemblyResolver()) : null; |
||||
var codeMappingInfo = language.GetCodeMappingInfo(assemblyScope, typeScope.GetDeclaringType()); |
||||
foreach (var type in TreeTraversal.PreOrder(typeScope.GetDeclaringType(), t => assemblyScope.Metadata.GetTypeDefinition(t).GetNestedTypes())) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
foreach (var result in typeAnalysisFunction(assemblyScope, type, codeMappingInfo, ts)) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
yield return result; |
||||
} |
||||
} |
||||
} |
||||
|
||||
IEnumerable<Decompiler.Metadata.PEFile> GetReferencingAssemblies(Decompiler.Metadata.PEFile asm, CancellationToken ct) |
||||
{ |
||||
yield return asm; |
||||
|
||||
string typeScopeNamespace = asm.Metadata.GetString(typeScope.Namespace); |
||||
string typeScopeName = asm.Metadata.GetString(typeScope.Name); |
||||
|
||||
IEnumerable<LoadedAssembly> assemblies = MainWindow.Instance.CurrentAssemblyList.GetAssemblies().Where(assy => assy.GetPEFileOrNull()?.IsAssembly == true); |
||||
|
||||
foreach (var assembly in assemblies) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
bool found = false; |
||||
var module = assembly.GetPEFileOrNull(); |
||||
if (module == null) |
||||
continue; |
||||
var resolver = assembly.GetAssemblyResolver(); |
||||
var metadata = module.Metadata; |
||||
foreach (var reference in module.AssemblyReferences) { |
||||
using (LoadedAssembly.DisableAssemblyLoad()) { |
||||
if (resolver.Resolve(reference) == asm) { |
||||
found = true; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if (found && AssemblyReferencesScopeType(metadata, typeScopeName, typeScopeNamespace)) |
||||
yield return module; |
||||
} |
||||
} |
||||
|
||||
IEnumerable<Decompiler.Metadata.PEFile> GetAssemblyAndAnyFriends(Decompiler.Metadata.PEFile asm, CancellationToken ct) |
||||
{ |
||||
yield return asm; |
||||
var metadata = asm.Metadata; |
||||
|
||||
string typeScopeNamespace = metadata.GetString(typeScope.Namespace); |
||||
string typeScopeName = metadata.GetString(typeScope.Name); |
||||
|
||||
var typeProvider = Decompiler.Metadata.MetadataExtensions.MinimalAttributeTypeProvider; |
||||
var attributes = metadata.CustomAttributes.Select(h => metadata.GetCustomAttribute(h)).Where(ca => ca.GetAttributeType(metadata).GetFullTypeName(metadata).ToString() == "System.Runtime.CompilerServices.InternalsVisibleToAttribute"); |
||||
var friendAssemblies = new HashSet<string>(); |
||||
foreach (var attribute in attributes) { |
||||
string assemblyName = attribute.DecodeValue(typeProvider).FixedArguments[0].Value as string; |
||||
assemblyName = assemblyName.Split(',')[0]; // strip off any public key info
|
||||
friendAssemblies.Add(assemblyName); |
||||
} |
||||
|
||||
if (friendAssemblies.Count > 0) { |
||||
IEnumerable<LoadedAssembly> assemblies = MainWindow.Instance.CurrentAssemblyList.GetAssemblies(); |
||||
|
||||
foreach (var assembly in assemblies) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
if (friendAssemblies.Contains(assembly.ShortName)) { |
||||
var module = assembly.GetPEFileOrNull(); |
||||
if (module == null) |
||||
continue; |
||||
if (AssemblyReferencesScopeType(module.Metadata, typeScopeName, typeScopeNamespace)) |
||||
yield return module; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
bool AssemblyReferencesScopeType(MetadataReader metadata, string typeScopeName, string typeScopeNamespace) |
||||
{ |
||||
bool hasRef = false; |
||||
foreach (var h in metadata.TypeReferences) { |
||||
var typeRef = metadata.GetTypeReference(h); |
||||
if (metadata.StringComparer.Equals(typeRef.Name, typeScopeName) && metadata.StringComparer.Equals(typeRef.Namespace, typeScopeNamespace)) { |
||||
hasRef = true; |
||||
break; |
||||
} |
||||
} |
||||
return hasRef; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue