diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 6746357..6b2fb62 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,6 +1,6 @@  - 2.0.1-pre04 + 2.0.1-pre05 Copyright © JetBrains 2024 Apache-2.0 diff --git a/src/Refasmer/Importer/ImportLogic.cs b/src/Refasmer/Importer/ImportLogic.cs index 2ee152d..30cdbcb 100644 --- a/src/Refasmer/Importer/ImportLogic.cs +++ b/src/Refasmer/Importer/ImportLogic.cs @@ -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 = GetAllowedMethodImplementations(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; @@ -406,6 +402,19 @@ public bool IsReferenceAssembly() => .Select(_reader.GetFullname) .Any(name => name == FullNames.ReferenceAssembly); + private ImmutableHashSet GetAllowedMethodImplementations(TypeDefinition type) => + type.GetMethodImplementations() + .Select(_reader.GetMethodImplementation) + .Where(mi => AllowImportType(_reader.GetMethodClass(mi.MethodDeclaration))) + .Select(mi => (MethodDefinitionHandle)mi.MethodBody) + .ToImmutableHashSet(); + + private bool AllowImportMethod( + IImmutableSet implementations, + MethodDefinitionHandle methodHandle, + MethodDefinition method) => + !implementations.Contains(methodHandle) && (Filter == null || Filter.AllowImport(method, _reader)); + public ReservedBlob Import() { if (_reader.IsAssembly) @@ -646,10 +655,11 @@ private IEnumerable CalculateInternalTypesToPreserve( AcceptFieldSignature(field, collector); } + var methodImplementations = GetAllowedMethodImplementations(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); } diff --git a/tests/Refasmer.Tests/IntegrationTestBase.cs b/tests/Refasmer.Tests/IntegrationTestBase.cs index 4f988b5..5de5758 100644 --- a/tests/Refasmer.Tests/IntegrationTestBase.cs +++ b/tests/Refasmer.Tests/IntegrationTestBase.cs @@ -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; diff --git a/tests/Refasmer.Tests/IntegrationTests.cs b/tests/Refasmer.Tests/IntegrationTests.cs index 2256709..cea0d85 100644 --- a/tests/Refasmer.Tests/IntegrationTests.cs +++ b/tests/Refasmer.Tests/IntegrationTests.cs @@ -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(); @@ -62,6 +63,7 @@ public async Task InternalTypeInPublicApi(string mainClassName, string auxiliary await VerifyTypeContents( resultAssembly, [fullMainClassName, ..fullAuxiliaryClassNames], + assertTypeExists: false, parameters: [mainClassName]); } } diff --git a/tests/Refasmer.Tests/Printer.cs b/tests/Refasmer.Tests/Printer.cs index d2ec172..f6f0ad5 100644 --- a/tests/Refasmer.Tests/Printer.cs +++ b/tests/Refasmer.Tests/Printer.cs @@ -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:"); diff --git a/tests/Refasmer.Tests/data/IntegrationTests.InternalTypeInPublicApi_mainClassName=PublicClassImplementingInternal.verified.txt b/tests/Refasmer.Tests/data/IntegrationTests.InternalTypeInPublicApi_mainClassName=PublicClassImplementingInternal.verified.txt index 6beb1d5..3cdda3d 100644 --- a/tests/Refasmer.Tests/data/IntegrationTests.InternalTypeInPublicApi_mainClassName=PublicClassImplementingInternal.verified.txt +++ b/tests/Refasmer.Tests/data/IntegrationTests.InternalTypeInPublicApi_mainClassName=PublicClassImplementingInternal.verified.txt @@ -1,4 +1,5 @@ public class: RefasmerTestAssembly.PublicClassImplementingInternal + - interface impl: RefasmerTestAssembly.IInterface1ToBeMarkedInternal methods: - .ctor(): System.Void: internal interface: RefasmerTestAssembly.IInterface1ToBeMarkedInternal diff --git a/tests/Refasmer.Tests/data/IntegrationTests.InternalTypeInPublicApi_mainClassName=PublicClassWithInternalInterfaceImpl.verified.txt b/tests/Refasmer.Tests/data/IntegrationTests.InternalTypeInPublicApi_mainClassName=PublicClassWithInternalInterfaceImpl.verified.txt index ce5a3ce..26f3343 100644 --- a/tests/Refasmer.Tests/data/IntegrationTests.InternalTypeInPublicApi_mainClassName=PublicClassWithInternalInterfaceImpl.verified.txt +++ b/tests/Refasmer.Tests/data/IntegrationTests.InternalTypeInPublicApi_mainClassName=PublicClassWithInternalInterfaceImpl.verified.txt @@ -1,9 +1,6 @@ public class: RefasmerTestAssembly.PublicClassWithInternalInterfaceImpl + - interface impl: RefasmerTestAssembly.IInterface2ToBeMarkedInternal`1 methods: -- RefasmerTestAssembly.IInterface2ToBeMarkedInternal.Foo(): RefasmerTestAssembly.Class3ToBeMarkedInternal: - .ctor(): System.Void: internal class: RefasmerTestAssembly.Class3ToBeMarkedInternal -public interface: RefasmerTestAssembly.IInterface2ToBeMarkedInternal`1 -methods: -- Foo(): T: - - +internal interface: RefasmerTestAssembly.IInterface2ToBeMarkedInternal`1 diff --git a/tests/Refasmer.Tests/data/IntegrationTests.InternalTypeInPublicApi_mainClassName=PublicClassWithInternalTypeInExplicitImpl.verified.txt b/tests/Refasmer.Tests/data/IntegrationTests.InternalTypeInPublicApi_mainClassName=PublicClassWithInternalTypeInExplicitImpl.verified.txt new file mode 100644 index 0000000..c65bcde --- /dev/null +++ b/tests/Refasmer.Tests/data/IntegrationTests.InternalTypeInPublicApi_mainClassName=PublicClassWithInternalTypeInExplicitImpl.verified.txt @@ -0,0 +1,5 @@ +public class: RefasmerTestAssembly.PublicClassWithInternalTypeInExplicitImpl + - interface impl: RefasmerTestAssembly.IInterface3 +methods: +- .ctor(): System.Void: +internal interface: RefasmerTestAssembly.IInterface3 diff --git a/tests/RefasmerTestAssembly/InternalClassInApi.cs b/tests/RefasmerTestAssembly/InternalTypesInApi.cs similarity index 70% rename from tests/RefasmerTestAssembly/InternalClassInApi.cs rename to tests/RefasmerTestAssembly/InternalTypesInApi.cs index 67e6d92..1e58399 100644 --- a/tests/RefasmerTestAssembly/InternalClassInApi.cs +++ b/tests/RefasmerTestAssembly/InternalTypesInApi.cs @@ -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 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 Foo(); +} +public class Class3ToBeMarkedInternal; public class PublicClassWithInternalInterfaceImpl : IInterface2ToBeMarkedInternal { Class3ToBeMarkedInternal IInterface2ToBeMarkedInternal.Foo() => throw new Exception("123"); -} \ No newline at end of file +} + +internal class InternalClass3; +internal interface IInterface3 +{ + void Accept(InternalClass3 arg); +} +public class PublicClassWithInternalTypeInExplicitImpl : IInterface3 +{ + void IInterface3.Accept(InternalClass3 arg) {} +}