Skip to content

Commit

Permalink
Add all interface's class-level annotations to its DefaultImpls class. (
Browse files Browse the repository at this point in the history
#161)

Fixes #155
  • Loading branch information
fzhinkin committed Jan 18, 2024
1 parent 066e01e commit 1d7505b
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 5 deletions.
4 changes: 3 additions & 1 deletion src/main/kotlin/api/AsmMetadataLoading.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ private const val publishedApiAnnotationName = "kotlin/PublishedApi"
private fun ClassNode.isPublishedApi() = findAnnotation(publishedApiAnnotationName, includeInvisible = true) != null
internal fun List<AnnotationNode>.isPublishedApi() = firstOrNull { it.refersToName(publishedApiAnnotationName) } != null

internal fun ClassNode.isDefaultImpls(metadata: KotlinClassMetadata?) = isInner() && name.endsWith("\$DefaultImpls") && metadata.isSyntheticClass()
internal const val DefaultImplsNameSuffix = "\$DefaultImpls"
internal fun ClassNode.isDefaultImpls(metadata: KotlinClassMetadata?) =
isInner() && name.endsWith(DefaultImplsNameSuffix) && metadata.isSyntheticClass()

internal fun ClassNode.findAnnotation(annotationName: String, includeInvisible: Boolean = false) =
findAnnotation(annotationName, visibleAnnotations, invisibleAnnotations, includeInvisible)
Expand Down
15 changes: 13 additions & 2 deletions src/main/kotlin/api/KotlinSignaturesLoading.kt
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,22 @@ public fun Sequence<InputStream>.loadApiFromJvmClasses(visibilityFilter: (String
val methodSignatures = methods.map { it.buildMethodSignature(mVisibility, this) }
.filter { it.isEffectivelyPublic(classAccess, mVisibility) }

/**
* For synthetic $DefaultImpls classes copy annotations from the original interface
*/
val inheritedAnnotations = mutableListOf<AnnotationNode>().apply {
if (classNode.isDefaultImpls(kotlinMetadata)) {
val originalInterface = classNodeMap[classNode.name.dropLast(DefaultImplsNameSuffix.length)]
addAll(originalInterface?.visibleAnnotations.orEmpty())
addAll(originalInterface?.invisibleAnnotations.orEmpty())
}
}

ClassBinarySignature(
name, superName, outerClassName, supertypes, fieldSignatures + methodSignatures, classAccess,
isEffectivelyPublic(mVisibility),
metadata.isFileOrMultipartFacade() || isDefaultImpls(metadata),
annotations(visibleAnnotations, invisibleAnnotations)
annotations(visibleAnnotations, invisibleAnnotations) + inheritedAnnotations
)
}
}
Expand Down Expand Up @@ -182,7 +193,7 @@ public fun List<ClassBinarySignature>.filterOutAnnotated(targetAnnotations: Set<
}

signature.copy(memberSignatures = notAnnotatedMemberSignatures)
}
}.filterNot { it.isNotUsedWhenEmpty && it.memberSignatures.isEmpty() }
}

private fun List<ClassBinarySignature>.filterOutNotAnnotated(
Expand Down
3 changes: 3 additions & 0 deletions src/test/kotlin/cases/default/default.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ public final class cases/default/InterfaceFunctions$DefaultImpls {
public static synthetic fun withSomeDefaults$default (Lcases/default/InterfaceFunctions;ILjava/lang/String;ILjava/lang/Object;)V
}

public abstract interface class cases/default/PublicInterfaceWithAllFunctionsFilteredOut {
}

public final class cases/default/PublishedApiWithDefaultsKt {
public static final fun twoDefaults (ILjava/lang/Object;Ljava/lang/String;)V
public static synthetic fun twoDefaults$default (ILjava/lang/Object;Ljava/lang/String;ILjava/lang/Object;)V
Expand Down
17 changes: 16 additions & 1 deletion src/test/kotlin/cases/default/functions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,19 @@ interface InterfaceFunctions {

fun withSomeDefaults(par1: Int, par2: String? = null)

}
}

@PrivateApi
annotation class PrivateApi

@PrivateApi
interface PrivateInterfaceWithDefaultMethod {
fun foo() {}

fun bar() {}
}

interface PublicInterfaceWithAllFunctionsFilteredOut {
@PrivateApi
fun foo() {}
}
2 changes: 1 addition & 1 deletion src/test/kotlin/tests/CasesPublicAPITest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class CasesPublicAPITest {

@Test fun companions() { snapshotAPIAndCompare(testName.methodName, setOf("cases/companions/PrivateApi")) }

@Test fun default() { snapshotAPIAndCompare(testName.methodName) }
@Test fun default() { snapshotAPIAndCompare(testName.methodName, setOf("cases/default/PrivateApi")) }

@Test fun inline() { snapshotAPIAndCompare(testName.methodName) }

Expand Down

0 comments on commit 1d7505b

Please sign in to comment.