Upgrade Kotlin to v2.0 (#3594)

* Bump Kotlin to v2.0

* Fix lots of issues due to the upgrade: lint issues, function signature incompatibilities, broken tests, etc.

---------

Co-authored-by: Benoit Marty <benoit@matrix.org>
This commit is contained in:
Jorge Martin Espinosa
2024-10-10 10:32:00 +02:00
committed by GitHub
parent 11467051d1
commit e44b5ad98d
27 changed files with 93 additions and 69 deletions

2
.idea/kotlinc.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.25" />
<option name="version" value="2.0.20" />
</component>
</project>

View File

@@ -478,7 +478,7 @@ class LoggedInPresenterTest {
distributors = listOf(Distributor("aDistributorValue1", "aDistributorName1")),
currentDistributor = { null },
),
registerWithLambda: suspend (MatrixClient, PushProvider, Distributor) -> Result<Unit> = { _, _, _ ->
registerWithLambda: (MatrixClient, PushProvider, Distributor) -> Result<Unit> = { _, _, _ ->
Result.success(Unit)
},
selectPushProviderLambda: (MatrixClient, PushProvider) -> Unit = { _, _ -> lambdaError() },

View File

@@ -18,6 +18,7 @@ plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.anvil) apply false
alias(libs.plugins.kotlin.jvm) apply false
@@ -82,20 +83,15 @@ allprojects {
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
// Warnings are potential errors, so stop ignoring them
// This is disabled by default, but the CI will enforce this.
// You can override by passing `-PallWarningsAsErrors=true` in the command line
// Or add a line with "allWarningsAsErrors=true" in your ~/.gradle/gradle.properties file
kotlinOptions.allWarningsAsErrors = project.properties["allWarningsAsErrors"] == "true"
compilerOptions {
// Warnings are potential errors, so stop ignoring them
// This is disabled by default, but the CI will enforce this.
// You can override by passing `-PallWarningsAsErrors=true` in the command line
// Or add a line with "allWarningsAsErrors=true" in your ~/.gradle/gradle.properties file
allWarningsAsErrors = project.properties["allWarningsAsErrors"] == "true"
kotlinOptions {
/*
// Uncomment to suppress Compose Kotlin compiler compatibility warning
freeCompilerArgs += listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:suppressKotlinVersionCompatibilityCheck=true"
)
*/
// freeCompilerArgs.addAll(listOf("-P", "plugin:androidx.compose.compiler.plugins.kotlin:suppressKotlinVersionCompatibilityCheck=true"))
}
}
}
@@ -192,19 +188,23 @@ subprojects {
subprojects {
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions {
compilerOptions {
if (project.findProperty("composeCompilerReports") == "true") {
freeCompilerArgs += listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" +
"${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler"
freeCompilerArgs.addAll(
listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" +
"${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler"
)
)
}
if (project.findProperty("composeCompilerMetrics") == "true") {
freeCompilerArgs += listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" +
"${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler"
freeCompilerArgs.addAll(
listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" +
"${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler"
)
)
}
}

View File

@@ -1,3 +1,5 @@
import extension.setupAnvil
/*
* Copyright 2023, 2024 New Vector Ltd.
*
@@ -7,13 +9,14 @@
plugins {
id("io.element.android-library")
alias(libs.plugins.anvil)
}
android {
namespace = "io.element.android.features.cachecleaner.api"
}
setupAnvil()
dependencies {
implementation(projects.libraries.architecture)
implementation(libs.androidx.startup)

View File

@@ -109,12 +109,7 @@ class CallScreenPresenterTest {
assertThat(initialState.isInWidgetMode).isTrue()
assertThat(widgetProvider.getWidgetCalled).isTrue()
assertThat(widgetDriver.runCalledCount).isEqualTo(1)
// Called several times because of the recomposition
analyticsLambda.assertions().isCalledExactly(2)
.withSequence(
listOf(value(MobileScreen.ScreenName.RoomCall)),
listOf(value(MobileScreen.ScreenName.RoomCall))
)
analyticsLambda.assertions().isCalledOnce().with(value(MobileScreen.ScreenName.RoomCall))
sendCallNotificationIfNeededLambda.assertions().isCalledOnce()
}
}

View File

@@ -1,3 +1,5 @@
import extension.setupAnvil
/*
* Copyright 2024 New Vector Ltd.
*
@@ -6,13 +8,14 @@
*/
plugins {
id("io.element.android-library")
alias(libs.plugins.anvil)
}
android {
namespace = "io.element.android.features.enterprise.impl"
}
setupAnvil()
dependencies {
implementation(projects.anvilannotations)
api(projects.features.enterprise.api)

View File

@@ -1,3 +1,5 @@
import extension.setupAnvil
/*
* Copyright 2024 New Vector Ltd.
*
@@ -7,7 +9,6 @@
plugins {
id("io.element.android-compose-library")
alias(libs.plugins.anvil)
id("kotlin-parcelize")
}
@@ -15,6 +16,8 @@ android {
namespace = "io.element.android.features.ftue.test"
}
setupAnvil()
dependencies {
implementation(projects.features.ftue.api)
implementation(projects.tests.testutils)

View File

@@ -99,7 +99,7 @@ class AcceptDeclineInvitePresenterTest {
InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite
)
}
skipItems(1)
skipItems(2)
awaitItem().also { state ->
assertThat(state.declineAction).isInstanceOf(AsyncAction.Failure::class.java)
state.eventSink(
@@ -147,7 +147,7 @@ class AcceptDeclineInvitePresenterTest {
InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite
)
}
skipItems(1)
skipItems(2)
awaitItem().also { state ->
assertThat(state.declineAction).isInstanceOf(AsyncAction.Success::class.java)
}

View File

@@ -338,11 +338,15 @@ class JoinRoomPresenterTest {
awaitItem().also { state ->
state.eventSink(JoinRoomEvents.KnockRoom)
}
assertThat(awaitItem().knockAction).isEqualTo(AsyncAction.Loading)
awaitItem().also { state ->
assertThat(state.knockAction).isEqualTo(AsyncAction.Success(Unit))
fakeKnockRoom.lambda = knockRoomFailure
state.eventSink(JoinRoomEvents.KnockRoom)
}
assertThat(awaitItem().knockAction).isEqualTo(AsyncAction.Loading)
awaitItem().also { state ->
assertThat(state.knockAction).isInstanceOf(AsyncAction.Failure::class.java)
}

View File

@@ -10,7 +10,6 @@ import extension.setupAnvil
plugins {
id("io.element.android-compose-library")
id("kotlin-parcelize")
alias(libs.plugins.anvil)
alias(libs.plugins.kotlin.serialization)
}

View File

@@ -51,7 +51,7 @@ class WebViewMessageInterceptor(
}
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
request ?: return super.shouldOverrideUrlLoading(view, request)
request ?: return false
// Load the URL in a Chrome Custom Tab, and return true to cancel the load
onOpenExternalUrl(request.url.toString())
return true

View File

@@ -1,3 +1,5 @@
import extension.setupAnvil
/*
* Copyright 2024 New Vector Ltd.
*
@@ -7,13 +9,14 @@
plugins {
id("io.element.android-compose-library")
alias(libs.plugins.anvil)
}
android {
namespace = "io.element.android.features.migration.impl"
}
setupAnvil()
dependencies {
implementation(projects.features.migration.api)
implementation(projects.libraries.architecture)

View File

@@ -9,7 +9,6 @@ import extension.setupAnvil
plugins {
id("io.element.android-compose-library")
alias(libs.plugins.anvil)
id("kotlin-parcelize")
}

View File

@@ -343,6 +343,7 @@ class VerifySelfSessionPresenterTest {
skipItems(1)
val initialItem = awaitItem()
initialItem.eventSink(VerifySelfSessionViewEvents.SignOut)
assertThat(awaitItem().signOutAction.isLoading()).isTrue()
val finalItem = awaitItem()
assertThat(finalItem.signOutAction.isSuccess()).isTrue()
assertThat(finalItem.signOutAction.dataOrNull()).isEqualTo("aUrl")

View File

@@ -4,9 +4,9 @@
[versions]
# Project
android_gradle_plugin = "8.7.0"
kotlin = "1.9.25"
kotlin = "2.0.20"
kotlinpoetKsp = "1.18.1"
ksp = "1.9.25-1.0.20"
ksp = "2.0.20-1.0.25"
firebaseAppDistribution = "5.0.0"
# AndroidX
@@ -62,6 +62,7 @@ kover = "0.8.3"
[libraries]
# Project
android_gradle_plugin = { module = "com.android.tools.build:gradle", version.ref = "android_gradle_plugin" }
compose_compiler_plugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" }
# https://developer.android.com/studio/write/java8-support#library-desugaring-versions
android_desugar = "com.android.tools:desugar_jdk_libs:2.1.2"
anvil_gradle_plugin = { module = "dev.zacsweers.anvil:gradle-plugin", version.ref = "anvil" }
@@ -238,3 +239,4 @@ firebaseAppDistribution = { id = "com.google.firebase.appdistribution", version.
knit = { id = "org.jetbrains.kotlinx.knit", version = "0.5.0" }
sonarqube = "org.sonarqube:5.1.0.4882"
licensee = "app.cash.licensee:1.11.0"
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }

View File

@@ -7,7 +7,6 @@
package io.element.android.libraries.designsystem.theme.components.bottomsheet
import androidx.compose.animation.core.DecayAnimationSpec
import androidx.compose.animation.core.SpringSpec
import androidx.compose.animation.core.exponentialDecay
import androidx.compose.foundation.ExperimentalFoundationApi
@@ -296,13 +295,9 @@ internal object AnchoredDraggableDefaults {
/**
* The default animation used by [AnchoredDraggableState].
*/
@get:ExperimentalMaterial3Api
@Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
@ExperimentalMaterial3Api
val SnapAnimationSpec = SpringSpec<Float>()
@get:ExperimentalMaterial3Api
@Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
@ExperimentalMaterial3Api
val DecayAnimationSpec = exponentialDecay<Float>()
}

View File

@@ -1,3 +1,5 @@
import extension.setupAnvil
/*
* Copyright 2023, 2024 New Vector Ltd.
*
@@ -7,9 +9,10 @@
plugins {
id("io.element.android-compose-library")
alias(libs.plugins.anvil)
}
setupAnvil()
android {
namespace = "io.element.android.libraries.mediapickers.api"

View File

@@ -1,3 +1,5 @@
import extension.setupAnvil
/*
* Copyright 2023, 2024 New Vector Ltd.
*
@@ -7,9 +9,10 @@
plugins {
id("io.element.android-compose-library")
alias(libs.plugins.anvil)
}
setupAnvil()
android {
namespace = "io.element.android.libraries.mediapickers.test"

View File

@@ -10,7 +10,7 @@ package io.element.android.libraries.pushproviders.unifiedpush
import io.element.android.tests.testutils.lambda.lambdaError
class FakeUnifiedPushNewGatewayHandler(
private val handleResult: suspend (String, String, String) -> Result<Unit> = { _, _, _ -> lambdaError() },
private val handleResult: (String, String, String) -> Result<Unit> = { _, _, _ -> lambdaError() },
) : UnifiedPushNewGatewayHandler {
override suspend fun handle(endpoint: String, pushGateway: String, clientSecret: String): Result<Unit> {
return handleResult(endpoint, pushGateway, clientSecret)

View File

@@ -9,6 +9,7 @@ package io.element.android.libraries.roomselect.impl
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
@@ -22,6 +23,7 @@ import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
import io.element.android.libraries.roomselect.api.RoomSelectMode
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
@@ -50,7 +52,7 @@ class RoomSelectPresenter @AssistedInject constructor(
val roomSummaryDetailsList by dataSource.roomInfoList.collectAsState(initial = persistentListOf())
val searchResults by remember {
val searchResults by remember<State<SearchBarResultState<ImmutableList<SelectRoomInfo>>>> {
derivedStateOf {
when {
roomSummaryDetailsList.isNotEmpty() -> SearchBarResultState.Results(roomSummaryDetailsList.toImmutableList())

View File

@@ -24,4 +24,5 @@ dependencies {
implementation(libs.autonomousapps.dependencyanalysis.plugin)
implementation(libs.anvil.gradle.plugin)
implementation(libs.ksp.gradle.plugin)
implementation(libs.compose.compiler.plugin)
}

View File

@@ -10,7 +10,6 @@ package extension
import Versions
import com.android.build.api.dsl.CommonExtension
import isEnterpriseBuild
import org.gradle.accessors.dm.LibrariesForLibs
import org.gradle.api.Project
import java.io.File
@@ -44,21 +43,18 @@ fun CommonExtension<*, *, *, *, *, *>.androidConfig(project: Project) {
}
checkDependencies = false
abortOnError = true
ignoreTestSources = true
ignoreTestFixturesSources = true
checkGeneratedSources = false
}
}
fun CommonExtension<*, *, *, *, *, *>.composeConfig(libs: LibrariesForLibs) {
fun CommonExtension<*, *, *, *, *, *>.composeConfig() {
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = libs.versions.composecompiler.get()
}
packaging {
resources.excludes.apply {
add("META-INF/AL2.0")

View File

@@ -19,11 +19,12 @@ plugins {
id("com.android.application")
id("kotlin-android")
id("com.autonomousapps.dependency-analysis")
id("org.jetbrains.kotlin.plugin.compose")
}
android {
androidConfig(project)
composeConfig(libs)
composeConfig()
compileOptions {
isCoreLibraryDesugaringEnabled = true
}

View File

@@ -19,11 +19,12 @@ plugins {
id("com.android.library")
id("kotlin-android")
id("com.autonomousapps.dependency-analysis")
id("org.jetbrains.kotlin.plugin.compose")
}
android {
androidConfig(project)
composeConfig(libs)
composeConfig()
compileOptions {
isCoreLibraryDesugaringEnabled = true
}

View File

@@ -7,6 +7,8 @@
package io.element.android.tests.testutils.lambda
import kotlinx.coroutines.runBlocking
/**
* A recorder that can be used to record the parameters of lambda invocation.
*/
@@ -93,21 +95,21 @@ inline fun <reified R> lambdaAnyRecorder(
class LambdaNoParamRecorder<out R>(ensureNeverCalled: Boolean, val block: () -> R) : LambdaRecorder(ensureNeverCalled), () -> R {
override fun invoke(): R {
onInvoke()
return block()
return runBlocking { block() }
}
}
class LambdaOneParamRecorder<in T, out R>(ensureNeverCalled: Boolean, val block: (T) -> R) : LambdaRecorder(ensureNeverCalled), (T) -> R {
override fun invoke(p: T): R {
onInvoke(p)
return block(p)
return runBlocking { block(p) }
}
}
class LambdaTwoParamsRecorder<in T1, in T2, out R>(ensureNeverCalled: Boolean, val block: (T1, T2) -> R) : LambdaRecorder(ensureNeverCalled), (T1, T2) -> R {
override fun invoke(p1: T1, p2: T2): R {
onInvoke(p1, p2)
return block(p1, p2)
return runBlocking { block(p1, p2) }
}
}
@@ -116,7 +118,7 @@ class LambdaThreeParamsRecorder<in T1, in T2, in T3, out R>(ensureNeverCalled: B
), (T1, T2, T3) -> R {
override fun invoke(p1: T1, p2: T2, p3: T3): R {
onInvoke(p1, p2, p3)
return block(p1, p2, p3)
return runBlocking { block(p1, p2, p3) }
}
}
@@ -125,16 +127,19 @@ class LambdaFourParamsRecorder<in T1, in T2, in T3, in T4, out R>(ensureNeverCal
), (T1, T2, T3, T4) -> R {
override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4): R {
onInvoke(p1, p2, p3, p4)
return block(p1, p2, p3, p4)
return runBlocking { block(p1, p2, p3, p4) }
}
}
class LambdaFiveParamsRecorder<in T1, in T2, in T3, in T4, in T5, out R>(ensureNeverCalled: Boolean, val block: (T1, T2, T3, T4, T5) -> R) : LambdaRecorder(
class LambdaFiveParamsRecorder<in T1, in T2, in T3, in T4, in T5, out R>(
ensureNeverCalled: Boolean,
val block: (T1, T2, T3, T4, T5) -> R,
) : LambdaRecorder(
ensureNeverCalled
), (T1, T2, T3, T4, T5) -> R {
override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4, p5: T5): R {
onInvoke(p1, p2, p3, p4, p5)
return block(p1, p2, p3, p4, p5)
return runBlocking { block(p1, p2, p3, p4, p5) }
}
}
@@ -144,7 +149,7 @@ class LambdaSixParamsRecorder<in T1, in T2, in T3, in T4, in T5, in T6, out R>(
) : LambdaRecorder(ensureNeverCalled), (T1, T2, T3, T4, T5, T6) -> R {
override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4, p5: T5, p6: T6): R {
onInvoke(p1, p2, p3, p4, p5, p6)
return block(p1, p2, p3, p4, p5, p6)
return runBlocking { block(p1, p2, p3, p4, p5, p6) }
}
}
@@ -154,7 +159,7 @@ class LambdaSevenParamsRecorder<in T1, in T2, in T3, in T4, in T5, in T6, in T7,
) : LambdaRecorder(ensureNeverCalled), (T1, T2, T3, T4, T5, T6, T7) -> R {
override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4, p5: T5, p6: T6, p7: T7): R {
onInvoke(p1, p2, p3, p4, p5, p6, p7)
return block(p1, p2, p3, p4, p5, p6, p7)
return runBlocking { block(p1, p2, p3, p4, p5, p6, p7) }
}
}
@@ -164,7 +169,7 @@ class LambdaEightParamsRecorder<in T1, in T2, in T3, in T4, in T5, in T6, in T7,
) : LambdaRecorder(ensureNeverCalled), (T1, T2, T3, T4, T5, T6, T7, T8) -> R {
override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4, p5: T5, p6: T6, p7: T7, p8: T8): R {
onInvoke(p1, p2, p3, p4, p5, p6, p7, p8)
return block(p1, p2, p3, p4, p5, p6, p7, p8)
return runBlocking { block(p1, p2, p3, p4, p5, p6, p7, p8) }
}
}
@@ -174,7 +179,7 @@ class LambdaNineParamsRecorder<in T1, in T2, in T3, in T4, in T5, in T6, in T7,
) : LambdaRecorder(ensureNeverCalled), (T1, T2, T3, T4, T5, T6, T7, T8, T9) -> R {
override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4, p5: T5, p6: T6, p7: T7, p8: T8, p9: T9): R {
onInvoke(p1, p2, p3, p4, p5, p6, p7, p8, p9)
return block(p1, p2, p3, p4, p5, p6, p7, p8, p9)
return runBlocking { block(p1, p2, p3, p4, p5, p6, p7, p8, p9) }
}
}

View File

@@ -3,7 +3,7 @@
style:
AlsoCouldBeApply:
active: true
OptionalWhenBraces:
BracesOnWhenStatements:
active: false
CascadingCallWrapping:
active: true

View File

@@ -117,4 +117,9 @@
<!-- Compose -->
<issue id="UnnecessaryComposedModifier" severity="error" />
<!-- There seems to be an issue with this check, it flags lots of false positives. -->
<!-- See https://issuetracker.google.com/issues/349411310 -->
<!-- TODO: check again in the near future. -->
<issue id="ProduceStateDoesNotAssignValue" severity="ignore" />
</lint>