Skip to content

Commit f6a8606

Browse files
authored
Merge pull request #20264 from wordpress-mobile/ksp
Use `ksp` in the project
2 parents 4787df0 + 4bdc95d commit f6a8606

File tree

9 files changed

+146
-137
lines changed

9 files changed

+146
-137
lines changed

WordPress/build.gradle

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import se.bjurr.violations.lib.model.SEVERITY
44
plugins {
55
id "com.android.application"
66
id "org.jetbrains.kotlin.android"
7-
id "org.jetbrains.kotlin.kapt"
87
id "org.jetbrains.kotlin.plugin.parcelize"
98
id "org.jetbrains.kotlin.plugin.allopen"
109
id "io.sentry.android.gradle"
1110
id "se.bjurr.violations.violation-comments-to-github-gradle-plugin"
1211
id "com.google.gms.google-services"
1312
id "com.google.dagger.hilt.android"
1413
id "org.jetbrains.kotlinx.kover"
14+
id "com.google.devtools.ksp"
1515
}
1616

1717
sentry {
@@ -336,16 +336,12 @@ static def addBuildConfigFieldsFromPrefixedProperties(variant, properties, prefi
336336
variant.buildConfigField "String", it.key.toUpperCase(), "\"${it.value}\""
337337
}
338338
}
339-
kapt {
340-
// Enable to infer error types in stubs (see: https://kotlinlang.org/docs/kapt.html#non-existent-type-correction)
341-
correctErrorTypes true
342-
}
343339

344340
dependencies {
345341
implementation 'androidx.webkit:webkit:1.10.0'
346342
implementation "androidx.navigation:navigation-compose:$androidxComposeNavigationVersion"
347343
compileOnly project(path: ':libs:annotations')
348-
kapt project(':libs:processors')
344+
ksp project(':libs:processors')
349345
implementation (project(path:':libs:networking')) {
350346
exclude group: "com.android.volley"
351347
exclude group: 'org.wordpress', module: 'utils'
@@ -447,7 +443,7 @@ dependencies {
447443
exclude group: 'androidx.appcompat', module: 'appcompat'
448444
}
449445
implementation "com.github.bumptech.glide:glide:$glideVersion"
450-
kapt "com.github.bumptech.glide:compiler:$glideVersion"
446+
ksp "com.github.bumptech.glide:ksp:$glideVersion"
451447
implementation "com.github.bumptech.glide:volley-integration:$glideVersion"
452448
implementation "com.github.indexos.media-for-mobile:domain:$indexosMediaForMobileVersion"
453449
implementation "com.github.indexos.media-for-mobile:android:$indexosMediaForMobileVersion"
@@ -461,9 +457,9 @@ dependencies {
461457
exclude group: 'com.android.support', module: 'support-annotations'
462458
}
463459
implementation "com.google.dagger:dagger-android-support:$gradle.ext.daggerVersion"
464-
kapt "com.google.dagger:dagger-android-processor:$gradle.ext.daggerVersion"
460+
ksp "com.google.dagger:dagger-android-processor:$gradle.ext.daggerVersion"
465461
implementation "com.google.dagger:hilt-android:$gradle.ext.daggerVersion"
466-
kapt "com.google.dagger:hilt-compiler:$gradle.ext.daggerVersion"
462+
ksp "com.google.dagger:hilt-compiler:$gradle.ext.daggerVersion"
467463

468464
testImplementation("androidx.arch.core:core-testing:$androidxArchCoreVersion", {
469465
exclude group: 'com.android.support', module: 'support-compat'
@@ -518,7 +514,7 @@ dependencies {
518514
androidTestImplementation (name:'cloudtestingscreenshotter_lib', ext:'aar') // Screenshots on Firebase Cloud Testing
519515
androidTestImplementation "androidx.work:work-testing:$androidxWorkManagerVersion"
520516
androidTestImplementation "com.google.dagger:hilt-android-testing:$gradle.ext.daggerVersion"
521-
kaptAndroidTest "com.google.dagger:hilt-android-compiler:$gradle.ext.daggerVersion"
517+
kspAndroidTest "com.google.dagger:hilt-android-compiler:$gradle.ext.daggerVersion"
522518
// Enables Java 8+ API desugaring support
523519
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:$androidDesugarVersion"
524520
lintChecks "org.wordpress:lint:$wordPressLintVersion"

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ plugins {
99
id "com.android.library" apply false
1010
id 'com.google.gms.google-services' apply false
1111
id "org.jetbrains.kotlin.plugin.parcelize" apply false
12+
id "com.google.devtools.ksp" apply false
1213
}
1314

1415
ext {

config/lint/lint.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<!-- TODO: https://github.com/wordpress-mobile/WordPress-Android/issues/18185 -->
2020
<issue id="MissingFirebaseInstanceTokenRefresh">
2121
<!-- GCM -->
22-
<ignore path="**/generated/source/kapt/**/org/wordpress/android/push/Hilt_GCMMessageService.java" />
22+
<ignore path="**/generated/ksp/**/org/wordpress/android/push/Hilt_GCMMessageService.java" />
2323
</issue>
2424
<issue id="GradleDependency" severity="ignore" /> <!-- Dependabot will take care of this -->
2525
<issue id="MissingNullAnnotationOnField">
@@ -63,7 +63,7 @@
6363
<ignore path="**/src/wordpress/res" /> <!-- drawable-hdpi, drawable-xxhdpi -->
6464
</issue>
6565
<issue id="ObsoleteSdkInt">
66-
<ignore path="**/generated/source/kapt/**/org/wordpress/android/ui/main/Hilt_WPMainNavigationView.java" />
66+
<ignore path="**/generated/ksp/**/org/wordpress/android/ui/main/Hilt_WPMainNavigationView.java" />
6767
</issue>
6868
<!-- INTEROPERABILITY -->
6969
<issue id="UnknownNullness" severity="informational">

libs/processors/build.gradle

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
plugins {
22
id "org.jetbrains.kotlin.jvm"
3-
id "org.jetbrains.kotlin.kapt"
43
id "org.jetbrains.kotlinx.kover"
54
}
65

@@ -10,11 +9,13 @@ targetCompatibility = JavaVersion.VERSION_1_8
109
dependencies {
1110
implementation project(":libs:annotations")
1211

13-
implementation "com.google.auto.service:auto-service:$googleAutoServiceVersion"
14-
kapt "com.google.auto.service:auto-service:$googleAutoServiceVersion"
1512
implementation "com.squareup:kotlinpoet:$squareupKotlinPoetVersion"
13+
implementation "com.squareup:kotlinpoet-ksp:$squareupKotlinPoetVersion"
14+
implementation "com.google.devtools.ksp:symbol-processing-api:$gradle.ext.kspVersion"
1615

17-
testImplementation "com.github.tschuchortdev:kotlin-compile-testing:1.5.0"
16+
def kctVersion = "1.5.0"
17+
testImplementation "com.github.tschuchortdev:kotlin-compile-testing:$kctVersion"
18+
testImplementation "com.github.tschuchortdev:kotlin-compile-testing-ksp:$kctVersion"
1819
testImplementation "junit:junit:$junitVersion"
1920
testImplementation "org.assertj:assertj-core:$assertjVersion"
2021
testImplementation "org.jetbrains.kotlin:kotlin-reflect:$gradle.ext.kotlinVersion"
Lines changed: 110 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,131 @@
1+
@file:OptIn(KspExperimental::class)
2+
3+
14
package org.wordpress.android.processor
25

3-
import com.google.auto.service.AutoService
4-
import com.squareup.kotlinpoet.DelicateKotlinPoetApi
5-
import com.squareup.kotlinpoet.TypeName
6-
import com.squareup.kotlinpoet.asTypeName
6+
import com.google.devtools.ksp.KspExperimental
7+
import com.google.devtools.ksp.containingFile
8+
import com.google.devtools.ksp.getAnnotationsByType
9+
import com.google.devtools.ksp.processing.CodeGenerator
10+
import com.google.devtools.ksp.processing.Resolver
11+
import com.google.devtools.ksp.processing.SymbolProcessor
12+
import com.google.devtools.ksp.symbol.KSAnnotated
13+
import com.google.devtools.ksp.symbol.KSClassDeclaration
14+
import com.squareup.kotlinpoet.ksp.toTypeName
15+
import com.squareup.kotlinpoet.ksp.writeTo
716
import org.wordpress.android.annotation.Experiment
817
import org.wordpress.android.annotation.Feature
9-
import org.wordpress.android.annotation.FeatureInDevelopment
1018
import org.wordpress.android.annotation.RemoteFieldDefaultGenerater
11-
import java.io.File
12-
import javax.annotation.processing.AbstractProcessor
13-
import javax.annotation.processing.Processor
14-
import javax.annotation.processing.RoundEnvironment
15-
import javax.annotation.processing.SupportedAnnotationTypes
16-
import javax.annotation.processing.SupportedSourceVersion
17-
import javax.lang.model.SourceVersion
18-
import javax.lang.model.element.TypeElement
19-
import javax.tools.Diagnostic.Kind
20-
21-
@AutoService(Processor::class) // For registering the service
22-
@SupportedSourceVersion(SourceVersion.RELEASE_8) // to support Java 8
23-
@SupportedAnnotationTypes(
24-
"org.wordpress.android.annotation.Experiment",
25-
"org.wordpress.android.annotation.Feature",
26-
"org.wordpress.android.annotation.FeatureInDevelopment",
27-
"org.wordpress.android.annotation.RemoteFieldDefaultGenerater"
28-
)
29-
class RemoteConfigProcessor : AbstractProcessor() {
30-
@OptIn(DelicateKotlinPoetApi::class)
31-
@Suppress("DEPRECATION")
32-
override fun process(p0: MutableSet<out TypeElement>?, roundEnvironment: RoundEnvironment?): Boolean {
33-
val experiments = roundEnvironment?.getElementsAnnotatedWith(Experiment::class.java)?.map { element ->
34-
val annotation = element.getAnnotation(Experiment::class.java)
35-
annotation.remoteField to annotation.defaultVariant
36-
} ?: listOf()
37-
val remoteFeatureNames = mutableListOf<TypeName>()
38-
val features = roundEnvironment?.getElementsAnnotatedWith(Feature::class.java)?.map { element ->
39-
val annotation = element.getAnnotation(Feature::class.java)
40-
remoteFeatureNames.add(element.asType().asTypeName())
41-
annotation.remoteField to annotation.defaultValue.toString()
42-
} ?: listOf()
43-
val remoteFields = roundEnvironment?.getElementsAnnotatedWith(RemoteFieldDefaultGenerater::class.java)
44-
?.map { element ->
45-
val annotation = element.getAnnotation(RemoteFieldDefaultGenerater::class.java)
46-
annotation.remoteField to annotation.defaultValue
47-
} ?: listOf()
48-
val featuresInDevelopment = roundEnvironment?.getElementsAnnotatedWith(FeatureInDevelopment::class.java)
49-
?.map { element ->
50-
element.asType().toString()
51-
} ?: listOf()
52-
return if (experiments.isNotEmpty() || features.isNotEmpty()) {
53-
generateRemoteFieldConfigDefaults(remoteFields.toMap())
54-
generateRemoteFeatureConfigDefaults((experiments + features).toMap())
55-
generateRemoteFeatureConfigCheck(remoteFeatureNames)
56-
generateFeaturesInDevelopment(featuresInDevelopment)
57-
true
58-
} else {
59-
false
19+
20+
@OptIn(KspExperimental::class)
21+
class RemoteConfigProcessor(
22+
private val codeGenerator: CodeGenerator,
23+
) : SymbolProcessor {
24+
/**
25+
* In the case of this processor, we only one need round. Generated files do not depend on each other
26+
* or any other processor.
27+
*
28+
* See: https://github.com/google/ksp/issues/797#issuecomment-1041127747
29+
* Also: https://github.com/google/ksp/blob/a0cd7774a7f65cec45a50ecc8960ef5e4d47fc21/examples/playground/test-processor/src/main/kotlin/TestProcessor.kt#L20
30+
*/
31+
private var invoked = false
32+
33+
override fun process(resolver: Resolver): List<KSAnnotated> {
34+
if (invoked) {
35+
return emptyList()
6036
}
37+
38+
val remoteFeatures = resolver.getSymbolsWithAnnotation("org.wordpress.android.annotation.Feature")
39+
.toList()
40+
41+
generateRemoteFeatureConfigDefaults(resolver, remoteFeatures)
42+
generateRemoteFieldsConfigDefaults(resolver)
43+
generateFeaturesInDevelopment(resolver)
44+
generateRemoteFeatureConfigCheck(remoteFeatures)
45+
46+
invoked = true
47+
return emptyList()
6148
}
6249

63-
@Suppress("TooGenericExceptionCaught", "SwallowedException")
64-
private fun generateRemoteFeatureConfigDefaults(
65-
remoteConfigDefaults: Map<String, String>
66-
) {
67-
try {
68-
val fileContent = RemoteFeatureConfigDefaultsBuilder(remoteConfigDefaults).getContent()
69-
70-
val kaptKotlinGeneratedDir = processingEnv.options[KAPT_KOTLIN_GENERATED_OPTION_NAME]
71-
fileContent.writeTo(File(kaptKotlinGeneratedDir))
72-
} catch (e: Exception) {
73-
processingEnv.messager.printMessage(Kind.ERROR, "Failed to generate remote feature config defaults")
50+
private fun generateRemoteFeatureConfigDefaults(resolver: Resolver, remoteFeatures: List<KSAnnotated>) {
51+
val experiments = resolver.getSymbolsWithAnnotation("org.wordpress.android.annotation.Experiment")
52+
.toList()
53+
54+
val defaults = (remoteFeatures + experiments)
55+
.map { element: KSAnnotated ->
56+
val featuresDefaults = element.getAnnotationsByType(Feature::class)
57+
.toList().associate { annotation ->
58+
annotation.remoteField to annotation.defaultValue.toString()
59+
}
60+
val experimentsDefaults = element.getAnnotationsByType(Experiment::class).toList()
61+
.toList().associate { annotation ->
62+
annotation.remoteField to annotation.defaultVariant
63+
}
64+
featuresDefaults + experimentsDefaults
65+
}.flatMap { it.toList() }
66+
.toMap()
67+
68+
if (defaults.isNotEmpty()) {
69+
RemoteFeatureConfigDefaultsBuilder(defaults).getContent()
70+
.writeTo(
71+
codeGenerator,
72+
aggregating = true,
73+
originatingKSFiles = remoteFeatures.map { it.containingFile!! }
74+
)
7475
}
7576
}
7677

77-
@Suppress("TooGenericExceptionCaught", "SwallowedException")
78-
private fun generateRemoteFieldConfigDefaults(
79-
remoteConfigDefaults: Map<String, String>
80-
) {
81-
try {
82-
val fileContent = RemoteFieldConfigDefaultsBuilder(remoteConfigDefaults).getContent()
83-
84-
val kaptKotlinGeneratedDir = processingEnv.options[KAPT_KOTLIN_GENERATED_OPTION_NAME]
85-
fileContent.writeTo(File(kaptKotlinGeneratedDir))
86-
} catch (e: Exception) {
87-
processingEnv.messager.printMessage(Kind.ERROR, "Failed to generate remote feature config defaults")
78+
private fun generateRemoteFieldsConfigDefaults(resolver: Resolver) {
79+
val remoteFields =
80+
resolver.getSymbolsWithAnnotation("org.wordpress.android.annotation.RemoteFieldDefaultGenerater")
81+
.toList()
82+
val remoteFieldDefaults = remoteFields
83+
.associate { element: KSAnnotated ->
84+
element.getAnnotationsByType(RemoteFieldDefaultGenerater::class)
85+
.toList()
86+
.first()
87+
.let { annotation ->
88+
annotation.remoteField to annotation.defaultValue
89+
}
90+
}
91+
92+
if(remoteFieldDefaults.isNotEmpty()) {
93+
RemoteFieldConfigDefaultsBuilder(remoteFieldDefaults).getContent()
94+
.writeTo(
95+
codeGenerator,
96+
aggregating = true,
97+
originatingKSFiles = remoteFields.map { it.containingFile!! }
98+
)
8899
}
89100
}
90101

91-
@Suppress("TooGenericExceptionCaught")
92-
private fun generateRemoteFeatureConfigCheck(
93-
remoteFeatureNames: List<TypeName>
94-
) {
95-
try {
96-
val fileContent = RemoteFeatureConfigCheckBuilder(remoteFeatureNames).getContent()
97-
98-
val kaptKotlinGeneratedDir = processingEnv.options[KAPT_KOTLIN_GENERATED_OPTION_NAME]
99-
fileContent.writeTo(File(kaptKotlinGeneratedDir))
100-
} catch (e: Exception) {
101-
processingEnv.messager.printMessage(
102-
Kind.ERROR,
103-
"Failed to generate remote feature config check: $e"
104-
)
102+
private fun generateFeaturesInDevelopment(resolver: Resolver) {
103+
val featuresInDevelopment =
104+
resolver.getSymbolsWithAnnotation("org.wordpress.android.annotation.FeatureInDevelopment")
105+
.filterIsInstance<KSClassDeclaration>()
106+
.toList()
107+
val featuresInDevelopmentDefaults = featuresInDevelopment
108+
.map { it.simpleName.asString() }
109+
110+
if(featuresInDevelopmentDefaults.isNotEmpty()) {
111+
FeaturesInDevelopmentDefaultsBuilder(featuresInDevelopmentDefaults).getContent()
112+
.writeTo(
113+
codeGenerator,
114+
aggregating = true,
115+
originatingKSFiles = featuresInDevelopment.map { it.containingFile!! }
116+
)
105117
}
106118
}
107119

108-
@Suppress("TooGenericExceptionCaught")
109-
private fun generateFeaturesInDevelopment(
110-
remoteFeatureNames: List<String>
111-
) {
112-
try {
113-
val fileContent = FeaturesInDevelopmentDefaultsBuilder(remoteFeatureNames).getContent()
114-
115-
val kaptKotlinGeneratedDir = processingEnv.options[KAPT_KOTLIN_GENERATED_OPTION_NAME]
116-
fileContent.writeTo(File(kaptKotlinGeneratedDir))
117-
} catch (e: Exception) {
118-
processingEnv.messager.printMessage(
119-
Kind.ERROR,
120-
"Failed to generate remote config check: $e"
120+
private fun generateRemoteFeatureConfigCheck(remoteFeatures: List<KSAnnotated>) {
121+
if(remoteFeatures.isNotEmpty()) {
122+
RemoteFeatureConfigCheckBuilder(
123+
remoteFeatures.filterIsInstance<KSClassDeclaration>().map { it.asType(emptyList()).toTypeName() }
124+
).getContent().writeTo(
125+
codeGenerator,
126+
aggregating = true,
127+
originatingKSFiles = remoteFeatures.map { it.containingFile!! }
121128
)
122129
}
123130
}
124-
125-
companion object {
126-
const val KAPT_KOTLIN_GENERATED_OPTION_NAME = "kapt.kotlin.generated"
127-
}
128131
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.wordpress.android.processor
2+
3+
import com.google.devtools.ksp.processing.SymbolProcessor
4+
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
5+
import com.google.devtools.ksp.processing.SymbolProcessorProvider
6+
7+
class RemoteConfigProcessorProvider : SymbolProcessorProvider {
8+
override fun create(
9+
environment: SymbolProcessorEnvironment
10+
): SymbolProcessor {
11+
return RemoteConfigProcessor(environment.codeGenerator)
12+
}
13+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.wordpress.android.processor.RemoteConfigProcessorProvider

0 commit comments

Comments
 (0)