Do not include $DefaultImpls inner classes in public API when they do not contain any public members (i.e. used only as a container to hold synthetic methods with annotations for properties or typealiases)
This commit is contained in:
+2
-2
@@ -41,7 +41,7 @@ fun getBinaryAPI(classStreams: Sequence<InputStream>, visibilityMap: Map<String,
|
|||||||
it.isEffectivelyPublic(classAccess, classVisibility)
|
it.isEffectivelyPublic(classAccess, classVisibility)
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassBinarySignature(name, superName, outerClassName, supertypes, memberSignatures, classAccess, isEffectivelyPublic(classVisibility), isFileOrMultipartFacade())
|
ClassBinarySignature(name, superName, outerClassName, supertypes, memberSignatures, classAccess, isEffectivelyPublic(classVisibility), isFileOrMultipartFacade() || isDefaultImpls())
|
||||||
}}
|
}}
|
||||||
.asIterable()
|
.asIterable()
|
||||||
.sortedBy { it.name }
|
.sortedBy { it.name }
|
||||||
@@ -74,7 +74,7 @@ fun List<ClassBinarySignature>.filterOutNonPublic(): List<ClassBinarySignature>
|
|||||||
|
|
||||||
return filter { it.isPublicAndAccessible() }
|
return filter { it.isPublicAndAccessible() }
|
||||||
.map { it.flattenNonPublicBases() }
|
.map { it.flattenNonPublicBases() }
|
||||||
.filterNot { it.isFileOrMultipartFacade && it.memberSignatures.isEmpty()}
|
.filterNot { it.isNotUsedWhenEmpty && it.memberSignatures.isEmpty()}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun List<ClassBinarySignature>.dump() = dump(to = System.out)
|
fun List<ClassBinarySignature>.dump() = dump(to = System.out)
|
||||||
|
|||||||
+4
-1
@@ -23,7 +23,7 @@ data class ClassBinarySignature(
|
|||||||
val memberSignatures: List<MemberBinarySignature>,
|
val memberSignatures: List<MemberBinarySignature>,
|
||||||
val access: AccessFlags,
|
val access: AccessFlags,
|
||||||
val isEffectivelyPublic: Boolean,
|
val isEffectivelyPublic: Boolean,
|
||||||
val isFileOrMultipartFacade: Boolean) {
|
val isNotUsedWhenEmpty: Boolean) {
|
||||||
|
|
||||||
val signature: String
|
val signature: String
|
||||||
get() = "${access.getModifierString()} class $name" + if (supertypes.isEmpty()) "" else " : ${supertypes.joinToString()}"
|
get() = "${access.getModifierString()} class $name" + if (supertypes.isEmpty()) "" else " : ${supertypes.joinToString()}"
|
||||||
@@ -121,6 +121,7 @@ fun ClassNode.isEffectivelyPublic(classVisibility: ClassVisibility?) =
|
|||||||
|
|
||||||
val ClassNode.innerClassNode: InnerClassNode? get() = innerClasses.singleOrNull { it.name == name }
|
val ClassNode.innerClassNode: InnerClassNode? get() = innerClasses.singleOrNull { it.name == name }
|
||||||
fun ClassNode.isLocal() = innerClassNode?.run { innerName == null && outerName == null} ?: false
|
fun ClassNode.isLocal() = innerClassNode?.run { innerName == null && outerName == null} ?: false
|
||||||
|
fun ClassNode.isInner() = innerClassNode != null
|
||||||
fun ClassNode.isWhenMappings() = isSynthetic(access) && name.endsWith("\$WhenMappings")
|
fun ClassNode.isWhenMappings() = isSynthetic(access) && name.endsWith("\$WhenMappings")
|
||||||
|
|
||||||
val ClassNode.effectiveAccess: Int get() = innerClassNode?.access ?: access
|
val ClassNode.effectiveAccess: Int get() = innerClassNode?.access ?: access
|
||||||
@@ -134,12 +135,14 @@ fun FieldNode.isInlineExposed() = hasAnnotation(inlineExposedAnnotationName, inc
|
|||||||
|
|
||||||
private object KotlinClassKind {
|
private object KotlinClassKind {
|
||||||
const val FILE = 2
|
const val FILE = 2
|
||||||
|
const val SYNTHETIC_CLASS = 3
|
||||||
const val MULTIPART_FACADE = 4
|
const val MULTIPART_FACADE = 4
|
||||||
|
|
||||||
val FILE_OR_MULTIPART_FACADE_KINDS = listOf(FILE, MULTIPART_FACADE)
|
val FILE_OR_MULTIPART_FACADE_KINDS = listOf(FILE, MULTIPART_FACADE)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ClassNode.isFileOrMultipartFacade() = kotlinClassKind.let { it != null && it in KotlinClassKind.FILE_OR_MULTIPART_FACADE_KINDS }
|
fun ClassNode.isFileOrMultipartFacade() = kotlinClassKind.let { it != null && it in KotlinClassKind.FILE_OR_MULTIPART_FACADE_KINDS }
|
||||||
|
fun ClassNode.isDefaultImpls() = isInner() && name.endsWith("\$DefaultImpls") && kotlinClassKind == KotlinClassKind.SYNTHETIC_CLASS
|
||||||
|
|
||||||
|
|
||||||
val ClassNode.kotlinClassKind: Int?
|
val ClassNode.kotlinClassKind: Int?
|
||||||
|
|||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cases.interfaces
|
||||||
|
|
||||||
|
public interface EmptyImpls {
|
||||||
|
@SinceKotlin("1.1")
|
||||||
|
val property: String
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cases.interfaces
|
||||||
|
|
||||||
|
public interface BaseWithImpl {
|
||||||
|
fun foo() = 42
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface DerivedWithImpl : BaseWithImpl {
|
||||||
|
override fun foo(): Int {
|
||||||
|
return super.foo() + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface DerivedWithoutImpl : BaseWithImpl
|
||||||
|
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
public abstract interface class cases/interfaces/BaseWithImpl {
|
||||||
|
public abstract fun foo ()I
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class cases/interfaces/BaseWithImpl$DefaultImpls {
|
||||||
|
public static fun foo (Lcases/interfaces/BaseWithImpl;)I
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class cases/interfaces/DerivedWithImpl : cases/interfaces/BaseWithImpl {
|
||||||
|
public abstract fun foo ()I
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class cases/interfaces/DerivedWithImpl$DefaultImpls {
|
||||||
|
public static fun foo (Lcases/interfaces/DerivedWithImpl;)I
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class cases/interfaces/DerivedWithoutImpl : cases/interfaces/BaseWithImpl {
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class cases/interfaces/DerivedWithoutImpl$DefaultImpls {
|
||||||
|
public static fun foo (Lcases/interfaces/DerivedWithoutImpl;)I
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class cases/interfaces/EmptyImpls {
|
||||||
|
public abstract fun getProperty ()Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
+2
@@ -20,6 +20,8 @@ class CasesPublicAPITest {
|
|||||||
|
|
||||||
@Test fun inline() { snapshotAPIAndCompare(testName.methodName) }
|
@Test fun inline() { snapshotAPIAndCompare(testName.methodName) }
|
||||||
|
|
||||||
|
@Test fun interfaces() { snapshotAPIAndCompare(testName.methodName) }
|
||||||
|
|
||||||
@Test fun internal() { snapshotAPIAndCompare(testName.methodName) }
|
@Test fun internal() { snapshotAPIAndCompare(testName.methodName) }
|
||||||
|
|
||||||
@Test fun java() { snapshotAPIAndCompare(testName.methodName) }
|
@Test fun java() { snapshotAPIAndCompare(testName.methodName) }
|
||||||
|
|||||||
Reference in New Issue
Block a user