Skip to content

Commit c6e8c6d

Browse files
KirpichenkovPavelshanshin
authored andcommitted
[ABI Validation] Support for explicit public API markers
* Add support for defining public declarations explicitly If the added properties are used, all unmatched declarations will be excluded from the API check. If properties for both ignored and explicit markers are set, filtering of ignored declarations will happen after filtering of declarations not explicitly marked as public. * Support validation of non-main source sets for kotlin-jvm projects Pull request Kotlin/binary-compatibility-validator#116
1 parent afa3af9 commit c6e8c6d

File tree

13 files changed

+357
-38
lines changed

13 files changed

+357
-38
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2016-2022 JetBrains s.r.o.
3+
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
4+
*/
5+
6+
package kotlinx.validation.test
7+
8+
import kotlinx.validation.api.*
9+
import kotlinx.validation.api.buildGradleKts
10+
import kotlinx.validation.api.kotlin
11+
import kotlinx.validation.api.resolve
12+
import kotlinx.validation.api.test
13+
import org.junit.Test
14+
15+
class MixedMarkersTest : BaseKotlinGradleTest() {
16+
17+
@Test
18+
fun testMixedMarkers() {
19+
val runner = test {
20+
buildGradleKts {
21+
resolve("examples/gradle/base/withPlugin.gradle.kts")
22+
resolve("examples/gradle/configuration/publicMarkers/mixedMarkers.gradle.kts")
23+
}
24+
25+
kotlin("MixedAnnotations.kt") {
26+
resolve("examples/classes/MixedAnnotations.kt")
27+
}
28+
29+
apiFile(projectName = rootProjectDir.name) {
30+
resolve("examples/classes/MixedAnnotations.dump")
31+
}
32+
33+
runner {
34+
arguments.add(":apiCheck")
35+
}
36+
}
37+
38+
runner.withDebug(true).build().apply {
39+
assertTaskSuccess(":apiCheck")
40+
}
41+
}
42+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2016-2022 JetBrains s.r.o.
3+
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
4+
*/
5+
6+
package kotlinx.validation.test
7+
8+
import kotlinx.validation.api.*
9+
import kotlinx.validation.api.buildGradleKts
10+
import kotlinx.validation.api.kotlin
11+
import kotlinx.validation.api.resolve
12+
import kotlinx.validation.api.test
13+
import org.junit.Test
14+
15+
class PublicMarkersTest : BaseKotlinGradleTest() {
16+
17+
@Test
18+
fun testPublicMarkers() {
19+
val runner = test {
20+
buildGradleKts {
21+
resolve("examples/gradle/base/withPlugin.gradle.kts")
22+
resolve("examples/gradle/configuration/publicMarkers/markers.gradle.kts")
23+
}
24+
25+
kotlin("ClassWithPublicMarkers.kt") {
26+
resolve("examples/classes/ClassWithPublicMarkers.kt")
27+
}
28+
29+
kotlin("ClassInPublicPackage.kt") {
30+
resolve("examples/classes/ClassInPublicPackage.kt")
31+
}
32+
33+
apiFile(projectName = rootProjectDir.name) {
34+
resolve("examples/classes/ClassWithPublicMarkers.dump")
35+
}
36+
37+
runner {
38+
arguments.add(":apiCheck")
39+
}
40+
}
41+
42+
runner.withDebug(true).build().apply {
43+
assertTaskSuccess(":apiCheck")
44+
}
45+
}
46+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/*
2+
* Copyright 2016-2022 JetBrains s.r.o.
3+
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
4+
*/
5+
6+
package foo.api
7+
8+
class ClassInPublicPackage {
9+
class Inner
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
public final class foo/ClassWithPublicMarkers {
2+
public final fun getBar1 ()I
3+
public final fun getBar2 ()I
4+
public final fun setBar1 (I)V
5+
public final fun setBar2 (I)V
6+
}
7+
8+
public final class foo/ClassWithPublicMarkers$MarkedClass {
9+
public fun <init> ()V
10+
public final fun getBar1 ()I
11+
}
12+
13+
public abstract interface annotation class foo/PublicClass : java/lang/annotation/Annotation {
14+
}
15+
16+
public final class foo/api/ClassInPublicPackage {
17+
public fun <init> ()V
18+
}
19+
20+
public final class foo/api/ClassInPublicPackage$Inner {
21+
public fun <init> ()V
22+
}
23+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2016-2022 JetBrains s.r.o.
3+
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
4+
*/
5+
6+
package foo
7+
8+
@Target(AnnotationTarget.CLASS)
9+
annotation class PublicClass
10+
11+
@Target(AnnotationTarget.FIELD)
12+
annotation class PublicField
13+
14+
@Target(AnnotationTarget.PROPERTY)
15+
annotation class PublicProperty
16+
17+
public class ClassWithPublicMarkers {
18+
@PublicField
19+
var bar1 = 42
20+
21+
@PublicProperty
22+
var bar2 = 42
23+
24+
@PublicClass
25+
class MarkedClass {
26+
val bar1 = 41
27+
}
28+
29+
var notMarkedPublic = 42
30+
31+
class NotMarkedClass
32+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public final class mixed/MarkedPublicWithPrivateMembers {
2+
public fun <init> ()V
3+
public final fun otherFun ()V
4+
}
5+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2016-2022 JetBrains s.r.o.
3+
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
4+
*/
5+
6+
package mixed
7+
8+
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FIELD, AnnotationTarget.FUNCTION)
9+
annotation class PublicApi
10+
11+
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FIELD, AnnotationTarget.FUNCTION)
12+
annotation class PrivateApi
13+
14+
@PublicApi
15+
class MarkedPublicWithPrivateMembers {
16+
@PrivateApi
17+
var private1 = 42
18+
19+
@field:PrivateApi
20+
var private2 = 15
21+
22+
@PrivateApi
23+
fun privateFun() = Unit
24+
25+
@PublicApi
26+
@PrivateApi
27+
fun privateFun2() = Unit
28+
29+
fun otherFun() = Unit
30+
}
31+
32+
// Member annotations should be ignored in explicitly private classes
33+
@PrivateApi
34+
class MarkedPrivateWithPublicMembers {
35+
@PublicApi
36+
var public1 = 42
37+
38+
@field:PublicApi
39+
var public2 = 15
40+
41+
@PublicApi
42+
fun publicFun() = Unit
43+
44+
fun otherFun() = Unit
45+
}
46+
47+
@PrivateApi
48+
@PublicApi
49+
class PublicAndPrivateFilteredOut
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Copyright 2016-2022 JetBrains s.r.o.
3+
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
4+
*/
5+
6+
configure<kotlinx.validation.ApiValidationExtension> {
7+
publicMarkers.add("foo.PublicClass")
8+
publicMarkers.add("foo.PublicField")
9+
publicMarkers.add("foo.PublicProperty")
10+
11+
publicPackages.add("foo.api")
12+
publicClasses.add("foo.PublicClass")
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*
2+
* Copyright 2016-2022 JetBrains s.r.o.
3+
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
4+
*/
5+
6+
configure<kotlinx.validation.ApiValidationExtension> {
7+
nonPublicMarkers.add("mixed.PrivateApi")
8+
publicMarkers.add("mixed.PublicApi")
9+
}

libraries/tools/abi-validation/src/main/kotlin/ApiValidationExtension.kt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,34 @@ open class ApiValidationExtension {
3434
* Example of such a class could be `com.package.android.BuildConfig`.
3535
*/
3636
public var ignoredClasses: MutableSet<String> = HashSet()
37+
38+
/**
39+
* Fully qualified names of annotations that can be used to explicitly mark public declarations.
40+
* If at least one of [publicMarkers], [publicPackages] or [publicClasses] is defined,
41+
* all declarations not covered by any of them will be considered non-public.
42+
* [ignoredPackages], [ignoredClasses] and [nonPublicMarkers] can be used for additional filtering.
43+
*/
44+
public var publicMarkers: MutableSet<String> = HashSet()
45+
46+
/**
47+
* Fully qualified package names that contain public declarations.
48+
* If at least one of [publicMarkers], [publicPackages] or [publicClasses] is defined,
49+
* all declarations not covered by any of them will be considered non-public.
50+
* [ignoredPackages], [ignoredClasses] and [nonPublicMarkers] can be used for additional filtering.
51+
*/
52+
public var publicPackages: MutableSet<String> = HashSet()
53+
54+
/**
55+
* Fully qualified names of public classes.
56+
* If at least one of [publicMarkers], [publicPackages] or [publicClasses] is defined,
57+
* all declarations not covered by any of them will be considered non-public.
58+
* [ignoredPackages], [ignoredClasses] and [nonPublicMarkers] can be used for additional filtering.
59+
*/
60+
public var publicClasses: MutableSet<String> = HashSet()
61+
62+
/**
63+
* Non-default Gradle SourceSet names that should be validated.
64+
* By default, only the `main` source set is checked.
65+
*/
66+
public var additionalSourceSets: MutableSet<String> = HashSet()
3767
}

0 commit comments

Comments
 (0)