Skip to content

Commit

Permalink
(#38) ImportLogic: fix import for explicit methods of internal interf…
Browse files Browse the repository at this point in the history
…aces
  • Loading branch information
ForNeVeR committed Dec 29, 2024
1 parent c91d13d commit 4099faf
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup Label="Packaging">
<Version>2.0.1-pre04</Version>
<Version>2.0.1-pre05</Version>
<Copyright>Copyright © JetBrains 2024</Copyright>

<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
Expand Down
24 changes: 17 additions & 7 deletions src/Refasmer/Importer/ImportLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,13 @@ private TypeDefinitionHandle ImportTypeDefinitionSkeleton(TypeDefinitionHandle s
if (!forcePreservePrivateFields)
PostProcessSkippedValueTypeFields(skippedInstanceFields!, importedInstanceFields!);

var implementations = src.GetMethodImplementations()
.Select(_reader.GetMethodImplementation)
.Where(mi => AllowImportType(_reader.GetMethodClass(mi.MethodDeclaration)))
.Select(mi => (MethodDefinitionHandle)mi.MethodBody)
.ToImmutableHashSet();
var implementations = GetAllowedInterfaceMethodImplementations(src);

foreach (var srcMethodHandle in src.GetMethods())
{
var srcMethod = _reader.GetMethodDefinition(srcMethodHandle);

if (!implementations.Contains(srcMethodHandle) && Filter?.AllowImport(srcMethod, _reader) == false)
if (!AllowImportMethod(implementations, srcMethodHandle, srcMethod))
{
Trace?.Invoke($"Not imported {_reader.ToString(srcMethod)}");
continue;
Expand Down Expand Up @@ -406,6 +402,19 @@ public bool IsReferenceAssembly() =>
.Select(_reader.GetFullname)
.Any(name => name == FullNames.ReferenceAssembly);

private ImmutableHashSet<MethodDefinitionHandle> GetAllowedInterfaceMethodImplementations(TypeDefinition type) =>
type.GetMethodImplementations()
.Select(_reader.GetMethodImplementation)
.Where(mi => AllowImportType(_reader.GetMethodClass(mi.MethodDeclaration)))
.Select(mi => (MethodDefinitionHandle)mi.MethodBody)
.ToImmutableHashSet();

private bool AllowImportMethod(
IImmutableSet<MethodDefinitionHandle> implementations,
MethodDefinitionHandle methodHandle,
MethodDefinition method) =>
!implementations.Contains(methodHandle) && (Filter == null || Filter.AllowImport(method, _reader));

public ReservedBlob<GuidHandle> Import()
{
if (_reader.IsAssembly)
Expand Down Expand Up @@ -646,10 +655,11 @@ private IEnumerable<TypeDefinitionHandle> CalculateInternalTypesToPreserve(
AcceptFieldSignature(field, collector);
}

var methodImplementations = GetAllowedInterfaceMethodImplementations(type);
foreach (var methodHandle in type.GetMethods())
{
var method = _reader.GetMethodDefinition(methodHandle);
if (Filter == null || Filter.AllowImport(method, _reader))
if (AllowImportMethod(methodImplementations, methodHandle, method))
AcceptMethodSignature(method, collector);
}

Expand Down
3 changes: 2 additions & 1 deletion tests/Refasmer.Tests/IntegrationTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ private static void MarkTypesInternal(string inputAssemblyPath, string outputAss
var assemblyDefinition = AssemblyDefinition.ReadAssembly(inputAssemblyPath);
foreach (var type in assemblyDefinition.MainModule.Types)
{
if (type.IsPublic && type.Name.EndsWith(typeNameSuffix))
var friendlyTypeName = type.Name.Split('`')[0]; // strip generic suffix
if (type.IsPublic && friendlyTypeName.EndsWith(typeNameSuffix))
{
type.IsPublic = false;
type.IsNotPublic = true;
Expand Down
2 changes: 2 additions & 0 deletions tests/Refasmer.Tests/IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ await VerifyTypeContents(
[TestCase("PublicClassDerivingFromInternal", "Class2ToBeMarkedInternal")]
[TestCase("PublicClassImplementingInternal", "IInterface1ToBeMarkedInternal")]
[TestCase("PublicClassWithInternalInterfaceImpl", "Class3ToBeMarkedInternal,IInterface2ToBeMarkedInternal`1")]
[TestCase("PublicClassWithInternalTypeInExplicitImpl", "IInterface3")]
public async Task InternalTypeInPublicApi(string mainClassName, string auxiliaryClassNames)
{
var assemblyPath = await BuildTestAssemblyWithInternalTypeInPublicApi();
Expand All @@ -62,6 +63,7 @@ public async Task InternalTypeInPublicApi(string mainClassName, string auxiliary
await VerifyTypeContents(
resultAssembly,
[fullMainClassName, ..fullAuxiliaryClassNames],
assertTypeExists: false,
parameters: [mainClassName]);
}
}
15 changes: 15 additions & 0 deletions tests/Refasmer.Tests/Printer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ public static void PrintType(TypeDefinition type, StringBuilder printout, string
var access = GetAccessString(type);
var typeKind = GetTypeKindString(type);
printout.AppendLine($"{indent}{access} {typeKind}: {type.FullName}");

var baseType = type.BaseType;
if (baseType != null && baseType.FullName != "System.Object" && baseType.FullName != "System.ValueType")
{
printout.AppendLine($"{indent} - base type: {baseType.FullName}");
}

if (type.HasInterfaces)
{
foreach (var @interface in type.Interfaces)
{
printout.AppendLine($"{indent} - interface impl: {@interface.InterfaceType.FullName}");
}
}

if (type.HasFields)
{
printout.AppendLine($"{indent}fields:");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
public class: RefasmerTestAssembly.PublicClassImplementingInternal
- interface impl: RefasmerTestAssembly.IInterface1ToBeMarkedInternal
methods:
- .ctor(): System.Void:
internal interface: RefasmerTestAssembly.IInterface1ToBeMarkedInternal
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
public class: RefasmerTestAssembly.PublicClassWithInternalInterfaceImpl
- interface impl: RefasmerTestAssembly.IInterface2ToBeMarkedInternal`1<RefasmerTestAssembly.Class3ToBeMarkedInternal>
methods:
- RefasmerTestAssembly.IInterface2ToBeMarkedInternal<RefasmerTestAssembly.Class3ToBeMarkedInternal>.Foo(): RefasmerTestAssembly.Class3ToBeMarkedInternal:
- .ctor(): System.Void:
internal class: RefasmerTestAssembly.Class3ToBeMarkedInternal
public interface: RefasmerTestAssembly.IInterface2ToBeMarkedInternal`1
methods:
- Foo(): T:
- <abstract>
internal interface: RefasmerTestAssembly.IInterface2ToBeMarkedInternal`1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
public class: RefasmerTestAssembly.PublicClassWithInternalTypeInExplicitImpl
- interface impl: RefasmerTestAssembly.IInterface3
methods:
- .ctor(): System.Void:
internal interface: RefasmerTestAssembly.IInterface3
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,36 @@

namespace RefasmerTestAssembly;

// Post-processed and converted to internal by tests:
// Types suffixed by "ToBeMarkedInternal" are post-processed and converted to internal by tests.
public class Class1ToBeMarkedInternal;
public class Class2ToBeMarkedInternal;
public class Class3ToBeMarkedInternal;
public interface IInterface1ToBeMarkedInternal;
public interface IInterface2ToBeMarkedInternal<T>
{
T Foo();
}

public class PublicClassWithInternalTypeInApi
{
public void Accept(Class1ToBeMarkedInternal argument) {}
}

public class Class2ToBeMarkedInternal;
public class PublicClassDerivingFromInternal : Class2ToBeMarkedInternal;

public interface IInterface1ToBeMarkedInternal;
public class PublicClassImplementingInternal : IInterface1ToBeMarkedInternal;

public interface IInterface2ToBeMarkedInternal<T>
{
T Foo();
}
public class Class3ToBeMarkedInternal;
public class PublicClassWithInternalInterfaceImpl : IInterface2ToBeMarkedInternal<Class3ToBeMarkedInternal>
{
Class3ToBeMarkedInternal IInterface2ToBeMarkedInternal<Class3ToBeMarkedInternal>.Foo() => throw new Exception("123");
}
}

internal class InternalClass3;
internal interface IInterface3
{
void Accept(InternalClass3 arg);
}
public class PublicClassWithInternalTypeInExplicitImpl : IInterface3
{
void IInterface3.Accept(InternalClass3 arg) {}
}

0 comments on commit 4099faf

Please sign in to comment.