Skip to content

Commit

Permalink
Introduce animalsniffer checks to coroutines and compile against Java… (
Browse files Browse the repository at this point in the history
Kotlin#2963)

* Introduce animalsniffer checks to coroutines and compile against Java 8 source and binary target, but still avoiding Java 7+ API
* Do not use deprecated target, language desugaring will handle default interface methods and Math/Long/Int static methods
* Partially migrate to .gradle.kts

Fixes Kotlin#1589
  • Loading branch information
qwwdfsad authored and yorickhenning committed Jan 28, 2022
1 parent eb9a33c commit f223698
Show file tree
Hide file tree
Showing 14 changed files with 93 additions and 16 deletions.
19 changes: 12 additions & 7 deletions build.gradle
Expand Up @@ -3,7 +3,9 @@
*/


import org.jetbrains.kotlin.config.KotlinCompilerVersion
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.dokka.gradle.DokkaTaskPartial

Expand Down Expand Up @@ -54,6 +56,7 @@ buildscript {
classpath "org.jetbrains.kotlinx:kotlinx-knit:$knit_version"
classpath "com.moowork.gradle:gradle-node-plugin:$gradle_node_version"
classpath "org.jetbrains.kotlinx:binary-compatibility-validator:$binary_compatibility_validator_version"
classpath "ru.vyarus:gradle-animalsniffer-plugin:1.5.3" // Android API check

// JMH plugins
classpath "com.github.jengelman.gradle.plugins:shadow:5.1.0"
Expand Down Expand Up @@ -101,6 +104,8 @@ allprojects {
}

apply plugin: "binary-compatibility-validator"
apply plugin: 'base'

apiValidation {
ignoredProjects += unpublished + ["kotlinx-coroutines-bom"]
if (build_snapshot_train) {
Expand All @@ -126,7 +131,7 @@ allprojects {
// Add dependency to core source sets. Core is configured in kx-core/build.gradle
configure(subprojects.findAll { !sourceless.contains(it.name) && it.name != coreModule }) {
evaluationDependsOn(":$coreModule")
if (it.name in multiplatform) {
if (isMultiplatform(it)) {
apply plugin: "kotlin-multiplatform"
apply from: rootProject.file("gradle/compile-jvm-multiplatform.gradle")
apply from: rootProject.file("gradle/compile-common.gradle")
Expand Down Expand Up @@ -162,8 +167,8 @@ configure(subprojects.findAll { !sourceless.contains(it.name) }) {
apply plugin: 'kotlinx-atomicfu'

// Configure options for all Kotlin compilation tasks
tasks.withType(org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile).all {
kotlinOptions.freeCompilerArgs += OptInPresetKt.optInAnnotations.collect { "-Xopt-in=" + it }
tasks.withType(AbstractKotlinCompile).all {
kotlinOptions.freeCompilerArgs += OptInPreset.optInAnnotations.collect { "-Xopt-in=" + it }
kotlinOptions.freeCompilerArgs += "-progressive"
// Disable KT-36770 for RxJava2 integration
kotlinOptions.freeCompilerArgs += "-XXLanguage:-ProhibitUsingNullableTypeParameterAgainstNotNullAnnotated"
Expand Down Expand Up @@ -207,7 +212,7 @@ if (build_snapshot_train) {

// Redefine source sets because we are not using 'kotlin/main/fqn' folder convention
configure(subprojects.findAll {
!sourceless.contains(it.name) && !multiplatform.contains(it.name) &&
!sourceless.contains(it.name) && !isMultiplatform(it) &&
it.name != "benchmarks" &&
it.name != "example-frontend-js"
}) {
Expand Down Expand Up @@ -262,7 +267,7 @@ configure(subprojects.findAll { !unpublished.contains(it.name) }) {
}

List<String> jarTasks
if (it.name in multiplatform) {
if (isMultiplatform(it)) {
jarTasks = ["jvmJar", "metadataJar"]
} else if (it.name == "kotlinx-coroutines-debug") {
// We shadow debug module instead of just packaging it
Expand All @@ -282,7 +287,7 @@ configure(subprojects.findAll { !unpublished.contains(it.name) }) {
}

// Report Kotlin compiler version when building project
println("Using Kotlin compiler version: $org.jetbrains.kotlin.config.KotlinCompilerVersion.VERSION")
println("Using Kotlin compiler version: $KotlinCompilerVersion.VERSION")

// --------------- Cache redirector ---------------

Expand All @@ -296,7 +301,7 @@ def publishTasks = getTasksByName("publish", true) + getTasksByName("publishNpm"

task deploy(dependsOn: publishTasks)

apply plugin: 'base'
apply plugin: 'animalsniffer-convention'

clean.dependsOn gradle.includedBuilds.collect { it.task(':clean') }

Expand Down
1 change: 1 addition & 0 deletions buildSrc/build.gradle.kts
Expand Up @@ -46,4 +46,5 @@ dependencies {
implementation(kotlin("gradle-plugin", version("kotlin")))
implementation("org.jetbrains.dokka:dokka-gradle-plugin:${version("dokka")}")
implementation("org.jetbrains.dokka:dokka-core:${version("dokka")}")
implementation("ru.vyarus:gradle-animalsniffer-plugin:1.5.3") // Android API check
}
3 changes: 2 additions & 1 deletion buildSrc/src/main/kotlin/OptInPreset.kt
@@ -1,6 +1,7 @@
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmName("OptInPreset")

val optInAnnotations = listOf(
"kotlin.RequiresOptIn",
Expand All @@ -10,4 +11,4 @@ val optInAnnotations = listOf(
"kotlinx.coroutines.ExperimentalCoroutinesApi",
"kotlinx.coroutines.ObsoleteCoroutinesApi",
"kotlinx.coroutines.InternalCoroutinesApi",
"kotlinx.coroutines.FlowPreview")
"kotlinx.coroutines.FlowPreview")
13 changes: 12 additions & 1 deletion buildSrc/src/main/kotlin/Projects.kt
Expand Up @@ -2,7 +2,7 @@
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmName("Projects")
import org.gradle.api.Project
import org.gradle.api.*

fun Project.version(target: String): String =
property("${target}_version") as String
Expand All @@ -18,3 +18,14 @@ val internal = setOf("kotlinx.coroutines", "benchmarks", "integration-testing")
val unpublished = internal + setOf("example-frontend-js", "android-unit-tests")

val Project.isMultiplatform: Boolean get() = name in multiplatform

// Projects that we do not check for Android API level 14 check due to various limitations
val androidNonCompatibleProjects = setOf(
"kotlinx-coroutines-debug",
"kotlinx-coroutines-swing",
"kotlinx-coroutines-javafx",
"kotlinx-coroutines-jdk8",
"kotlinx-coroutines-jdk9",
"kotlinx-coroutines-reactor",
"kotlinx-coroutines-test"
)
27 changes: 27 additions & 0 deletions buildSrc/src/main/kotlin/animalsniffer-convention.gradle.kts
@@ -0,0 +1,27 @@
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

import ru.vyarus.gradle.plugin.animalsniffer.*

subprojects {
// Skip JDK 8 projects or unpublished ones
if (!shouldSniff()) return@subprojects
apply(plugin = "ru.vyarus.animalsniffer")
configure<AnimalSnifferExtension> {
sourceSets = listOf((project.extensions.getByName("sourceSets") as SourceSetContainer).getByName("main"))
}
val signature: Configuration by configurations
dependencies {
signature("net.sf.androidscents.signature:android-api-level-14:4.0_r4@signature")
signature("org.codehaus.mojo.signature:java17:1.0@signature")
}
}

fun Project.shouldSniff(): Boolean {
// Skip all non-JVM projects
if (platformOf(project) != "jvm") return false
val name = project.name
if (name in unpublished || name in sourceless || name in androidNonCompatibleProjects) return false
return true
}
4 changes: 2 additions & 2 deletions buildSrc/src/main/kotlin/kotlin-jvm-conventions.gradle.kts
Expand Up @@ -11,8 +11,8 @@ plugins {
}

java {
sourceCompatibility = JavaVersion.VERSION_1_6
targetCompatibility = JavaVersion.VERSION_1_6
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

dependencies {
Expand Down
8 changes: 6 additions & 2 deletions gradle/compile-jvm-multiplatform.gradle
Expand Up @@ -2,12 +2,16 @@
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

sourceCompatibility = 1.6
targetCompatibility = 1.6
sourceCompatibility = 1.8
targetCompatibility = 1.8

kotlin {
jvm {}
sourceSets {
jvmMain.dependencies {
compileOnly "org.codehaus.mojo:animal-sniffer-annotations:1.20"
}

jvmTest.dependencies {
api "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
// Workaround to make addSuppressed work in tests
Expand Down
5 changes: 5 additions & 0 deletions kotlinx-coroutines-core/build.gradle
Expand Up @@ -90,6 +90,11 @@ kotlin {
}
}
}

jvm {
// For animal sniffer
withJava()
}
}

configurations {
Expand Down
3 changes: 2 additions & 1 deletion kotlinx-coroutines-core/common/src/flow/SharingStarted.kt
Expand Up @@ -5,7 +5,7 @@
package kotlinx.coroutines.flow

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.internal.*
import kotlinx.coroutines.internal.IgnoreJreRequirement
import kotlin.time.*

/**
Expand Down Expand Up @@ -204,5 +204,6 @@ private class StartedWhileSubscribed(
stopTimeout == other.stopTimeout &&
replayExpiration == other.replayExpiration

@IgnoreJreRequirement // desugared hashcode implementation
override fun hashCode(): Int = stopTimeout.hashCode() * 31 + replayExpiration.hashCode()
}
@@ -0,0 +1,10 @@
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.coroutines.internal

// Ignore JRE requirements for animal-sniffer, compileOnly dependency
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE)
@OptionalExpectation
internal expect annotation class IgnoreJreRequirement()
4 changes: 3 additions & 1 deletion kotlinx-coroutines-core/common/src/internal/Symbol.kt
Expand Up @@ -4,12 +4,14 @@

package kotlinx.coroutines.internal

import kotlin.jvm.*

/**
* A symbol class that is used to define unique constants that are self-explanatory in debugger.
*
* @suppress **This is unstable API and it is subject to change.**
*/
internal class Symbol(val symbol: String) {
internal class Symbol(@JvmField val symbol: String) {
override fun toString(): String = "<$symbol>"

@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
Expand Down
2 changes: 1 addition & 1 deletion kotlinx-coroutines-core/jvm/src/CoroutineContext.kt
Expand Up @@ -5,7 +5,6 @@
package kotlinx.coroutines

import kotlinx.coroutines.internal.*
import kotlinx.coroutines.scheduling.*
import kotlin.coroutines.*
import kotlin.coroutines.jvm.internal.CoroutineStackFrame

Expand Down Expand Up @@ -159,6 +158,7 @@ internal actual val CoroutineContext.coroutineName: String? get() {

private const val DEBUG_THREAD_NAME_SEPARATOR = " @"

@IgnoreJreRequirement // desugared hashcode implementation
internal data class CoroutineId(
val id: Long
) : ThreadContextElement<String>, AbstractCoroutineContextElement(CoroutineId) {
Expand Down
2 changes: 2 additions & 0 deletions kotlinx-coroutines-core/jvm/src/debug/AgentPremain.kt
Expand Up @@ -6,6 +6,7 @@ package kotlinx.coroutines.debug

import android.annotation.*
import kotlinx.coroutines.debug.internal.*
import org.codehaus.mojo.animal_sniffer.*
import sun.misc.*
import java.lang.instrument.*
import java.lang.instrument.ClassFileTransformer
Expand All @@ -17,6 +18,7 @@ import java.security.*
*/
@Suppress("unused")
@SuppressLint("all")
@IgnoreJRERequirement // Never touched on Android
internal object AgentPremain {

private val enableCreationStackTraces = runCatching {
Expand Down
@@ -0,0 +1,8 @@
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.coroutines.internal

@Suppress("ACTUAL_WITHOUT_EXPECT") // Not the same name to WA the bug in the compiler
internal actual typealias IgnoreJreRequirement = org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement

0 comments on commit f223698

Please sign in to comment.