Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Workspaces] Bug fixes #248

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/AsmResolver.Workspaces.DotNet/Analyzers/AnalyzerUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,22 @@ internal static IEnumerable<MethodDefinition> FindBaseMethods(this MethodDefinit
}
}
}

public static AssemblyDescriptor? GetAssembly(IMetadataMember member) => member switch
{
AssemblyDescriptor assembly => assembly,
MemberReference {Parent: { } parent} => GetAssembly(parent),
ITypeDescriptor {Scope: { } scope} => scope.GetAssembly(),
IResolutionScope scope => scope.GetAssembly(),
IModuleProvider {Module: {Assembly: { } assembly}} => assembly,
_ => null
};

public static bool ContainsSubjectAssembly(this Workspace workspace, IMetadataMember member)
=> workspace is DotNetWorkspace dotNetWorkspace
&& GetAssembly(member) is { } assembly
&& dotNetWorkspace.Assemblies
.Any(a => _comparer.Equals(a, assembly));

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ private static void ScheduleMembersForAnalysis(AnalysisContext context, MethodDe
}

// Schedule method body for analysis.
if (subject.CilMethodBody is not null && context.HasAnalyzers(typeof(CilMethodBody)))
if (subject.IsIL && subject.CilMethodBody is not null && context.HasAnalyzers(typeof(CilMethodBody)))
Washi1337 marked this conversation as resolved.
Show resolved Hide resolved
{
context.ScheduleForAnalysis(subject.CilMethodBody);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ protected override void Analyze(AnalysisContext context, AssemblyReference subje
if (context.Workspace is not DotNetWorkspace workspace)
return;

var definition = subject.Resolve();
if (definition is null || !workspace.Assemblies.Contains(definition))
if(!context.Workspace.ContainsSubjectAssembly(subject))
return;
if (subject.Resolve() is not {} definition)
return;

var index = context.Workspace.Index;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
using System.Linq;

namespace AsmResolver.Workspaces.DotNet.Analyzers.Reference
{
Expand All @@ -7,6 +9,8 @@ namespace AsmResolver.Workspaces.DotNet.Analyzers.Reference
/// </summary>
public class ExportedTypeAnalyzer : ObjectAnalyzer<ExportedType>
{
private readonly SignatureComparer _comparer = new();

/// <inheritdoc />
protected override void Analyze(AnalysisContext context, ExportedType subject)
{
Expand All @@ -15,13 +19,9 @@ protected override void Analyze(AnalysisContext context, ExportedType subject)
context.ScheduleForAnalysis(subject.DeclaringType);
}

if (context.Workspace is not DotNetWorkspace workspace)
return;

var definition = subject.Resolve();
if (definition is not { Module: { Assembly: { } } })
if(!context.Workspace.ContainsSubjectAssembly(subject))
return;
if (!workspace.Assemblies.Contains(definition.Module.Assembly))
if (subject.Resolve() is not {} definition)
return;

var index = context.Workspace.Index;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
using System.Linq;

namespace AsmResolver.Workspaces.DotNet.Analyzers.Reference
{
Expand All @@ -7,6 +9,7 @@ namespace AsmResolver.Workspaces.DotNet.Analyzers.Reference
/// </summary>
public class MemberReferenceAnalyzer : ObjectAnalyzer<MemberReference>
{

/// <inheritdoc />
protected override void Analyze(AnalysisContext context, MemberReference subject)
{
Expand All @@ -21,14 +24,10 @@ protected override void Analyze(AnalysisContext context, MemberReference subject
context.ScheduleForAnalysis(subject.Signature);
}

if (context.Workspace is not DotNetWorkspace workspace)
if(!context.Workspace.ContainsSubjectAssembly(subject))
return;

var definition = subject.Resolve();
if (definition is not { Module: { Assembly: { } } })
if (subject.Resolve() is not {} definition)
return;
if (!workspace.Assemblies.Contains(definition.Module.Assembly))
return; //TODO: Maybe add some warning log?

var index = context.Workspace.Index;
var node = index.GetOrCreateNode(definition);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
using AsmResolver.DotNet.Signatures.Types;

namespace AsmResolver.Workspaces.DotNet.Analyzers.Definition
namespace AsmResolver.Workspaces.DotNet.Analyzers.Reference
{
/// <summary>
/// Provides a default implementation for an <see cref="MethodSpecification"/> analyzer.
Expand All @@ -25,6 +24,13 @@ protected override void Analyze(AnalysisContext context, MethodSpecification sub
{
context.ScheduleForAnalysis(subject.DeclaringType);
}

if (subject.Method is not null)
{
var specification = context.Workspace.Index.GetOrCreateNode(subject);
var methodNode = context.Workspace.Index.GetOrCreateNode(subject.Method);
methodNode.ForwardRelations.Add(DotNetRelations.ReferenceMember, specification);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
using System.Linq;

namespace AsmResolver.Workspaces.DotNet.Analyzers.Reference
{
Expand All @@ -7,6 +9,8 @@ namespace AsmResolver.Workspaces.DotNet.Analyzers.Reference
/// </summary>
public class TypeReferenceAnalyzer : ObjectAnalyzer<TypeReference>
{
private readonly SignatureComparer _comparer = new();

/// <inheritdoc />
protected override void Analyze(AnalysisContext context, TypeReference subject)
{
Expand All @@ -15,13 +19,9 @@ protected override void Analyze(AnalysisContext context, TypeReference subject)
context.ScheduleForAnalysis(subject.DeclaringType);
}

if (context.Workspace is not DotNetWorkspace workspace)
return;

var definition = subject.Resolve();
if (definition is not { Module: { Assembly: { } } })
if(!context.Workspace.ContainsSubjectAssembly(subject))
return;
if (!workspace.Assemblies.Contains(definition.Module.Assembly))
if (subject.Resolve() is not {} definition)
return;

var index = context.Workspace.Index;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
using System.Linq;
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
using AsmResolver.DotNet.Signatures.Types;

namespace AsmResolver.Workspaces.DotNet.Analyzers.Definition
namespace AsmResolver.Workspaces.DotNet.Analyzers.Reference
{
/// <summary>
/// Provides a default implementation for an <see cref="TypeSpecification"/> analyzer.
/// </summary>
public class TypeSpecificationAnalyzer : ObjectAnalyzer<TypeSpecification>
{
private readonly SignatureComparer _comparer = new();

/// <inheritdoc />
protected override void Analyze(AnalysisContext context, TypeSpecification subject)
{

if (subject.Signature is not null && context.HasAnalyzers(typeof(TypeSignature)))
{
context.ScheduleForAnalysis(subject.Signature);
Expand All @@ -21,6 +25,15 @@ protected override void Analyze(AnalysisContext context, TypeSpecification subje
{
context.ScheduleForAnalysis(subject.DeclaringType);
}

if(!context.Workspace.ContainsSubjectAssembly(subject))
return;
if (subject.Resolve() is not {} definition)
return;

var specification = context.Workspace.Index.GetOrCreateNode(subject);
var typeNode = context.Workspace.Index.GetOrCreateNode(definition);
typeNode.ForwardRelations.Add(DotNetRelations.ReferenceType, specification);
}
}
}
10 changes: 6 additions & 4 deletions src/AsmResolver.Workspaces.DotNet/DotNetRelations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,18 @@ public static class DotNetRelations
new Guid("52a81339-0850-4f81-b059-30d7aacc430f"));

/// <summary>
/// Describes the relationship between a method or field definition and its reference.
/// Describes the relationship between a method or field definition and its reference
/// or method definition/reference to its specification.
/// </summary>
public static readonly ObjectRelation<IMemberDefinition, MemberReference> ReferenceMember = new(
public static readonly ObjectRelation<IMemberDescriptor , IMemberDescriptor> ReferenceMember = new(
"ReferenceMember",
new Guid("ce11d2f6-a423-429d-ad37-2f073fdf63be"));


/// <summary>
/// Describes the relationship between a type definition and its reference.
/// Describes the relationship between a type definition and its reference or specification.
/// </summary>
public static readonly ObjectRelation<TypeDefinition, TypeReference> ReferenceType = new(
public static readonly ObjectRelation<TypeDefinition, ITypeDefOrRef> ReferenceType = new(
"ReferenceType",
new Guid("3cc86779-338c-4165-a00c-da547a2e8549"));

Expand Down
89 changes: 89 additions & 0 deletions test/AsmResolver.Workspaces.DotNet.Tests/ReferenceRelationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,95 @@ public void MethodTest()
node.ForwardRelations.GetObjects(DotNetRelations.ReferenceMember));
}

[Fact]
public void TypeSpecificationTest()
{
var assembly1 = new AssemblyDefinition("Assembly1", new Version(1, 0, 0, 0));
var module1 = new ModuleDefinition("Assembly1");
var assembly2 = new AssemblyDefinition("Assembly1", new Version(1, 0, 0, 0));
var module2 = new ModuleDefinition("Assembly2");

var type1 = new TypeDefinition("Namespace", "Type", TypeAttributes.Class);
var type2 = new TypeDefinition("Namespace", "Type2", TypeAttributes.Class);

var factory = module2.CorLibTypeFactory;
var method = new MethodDefinition("Method", MethodAttributes.Static, MethodSignature.CreateInstance(factory.Void));
var body = new CilMethodBody(method);

assembly1.Modules.Add(module1);
assembly2.Modules.Add(module2);

module1.TopLevelTypes.Add(type1);
module2.TopLevelTypes.Add(type2);

type2.Methods.Add(method);

var typeSpecification = new TypeSpecification(type1.ToTypeSignature());

body.Instructions.Add(new CilInstruction(CilOpCodes.Sizeof, typeSpecification));
body.Instructions.Add(new CilInstruction(CilOpCodes.Pop));
method.MethodBody = body;

var workspace = new DotNetWorkspace();
workspace.Assemblies.Add(assembly1);
workspace.Assemblies.Add(assembly2);

workspace.Analyze();

var node = workspace.Index.GetOrCreateNode(type1);
Assert.Contains(typeSpecification,
node.ForwardRelations.GetObjects(DotNetRelations.ReferenceType));
}

[Fact]
public void MethodSpecificationTest()
{
var assembly1 = new AssemblyDefinition("Assembly1", new Version(1, 0, 0, 0));
var module1 = new ModuleDefinition("Assembly1");
var assembly2 = new AssemblyDefinition("Assembly1", new Version(1, 0, 0, 0));
var module2 = new ModuleDefinition("Assembly2");

var type1 = new TypeDefinition("Namespace", "Type", TypeAttributes.Class);
var type2 = new TypeDefinition("Namespace", "Type2", TypeAttributes.Class);

var factory = module2.CorLibTypeFactory;
var method1 = new MethodDefinition("Method1", MethodAttributes.Static, MethodSignature.CreateInstance(factory.Void));
var method2 = new MethodDefinition("Method2", MethodAttributes.Static, MethodSignature.CreateInstance(factory.Void));
var body = new CilMethodBody(method2);

assembly1.Modules.Add(module1);
assembly2.Modules.Add(module2);

module1.TopLevelTypes.Add(type1);
module2.TopLevelTypes.Add(type2);

type1.Methods.Add(method1);
type2.Methods.Add(method2);

var typeSpecification = new TypeSpecification(type1.ToTypeSignature());
var methodRef = new MemberReference(typeSpecification, method1.Name, method1.Signature);
var mehtodSpecification = new MethodSpecification(methodRef, new GenericInstanceMethodSignature());

body.Instructions.Add(new CilInstruction(CilOpCodes.Call, mehtodSpecification));
method2.MethodBody = body;

var workspace = new DotNetWorkspace();
workspace.Assemblies.Add(assembly1);
workspace.Assemblies.Add(assembly2);

workspace.Analyze();

var typeNode = workspace.Index.GetOrCreateNode(type1);
var methodNode = workspace.Index.GetOrCreateNode(method1);

var methodRefNode = methodNode.ForwardRelations.GetNodes(DotNetRelations.ReferenceMember).First();

Assert.Contains(mehtodSpecification,
methodRefNode.ForwardRelations.GetObjects(DotNetRelations.ReferenceMember));
Assert.Contains(typeSpecification,
typeNode.ForwardRelations.GetObjects(DotNetRelations.ReferenceType));
}

[Fact]
public void FieldTest()
{
Expand Down