Skip to content
Draft

K2 #371

Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions deeplinkdispatch-base/build.gradle
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'org.jmailen.kotlinter'

sourceCompatibility = 11

apply plugin: 'checkstyle'
apply from: '../publishing.gradle'

Expand Down
7 changes: 3 additions & 4 deletions deeplinkdispatch-processor/build.gradle
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'org.jmailen.kotlinter'

sourceCompatibility = 11

apply plugin: 'checkstyle'
apply from: '../publishing.gradle'

Expand Down Expand Up @@ -34,8 +31,10 @@ checkstyle {
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlin {
jvmToolchain(21)
}
kotlinOptions {
jvmTarget = "11"
freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
freeCompilerArgs += "-Xopt-in=androidx.room.compiler.processing.ExperimentalProcessingApi"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,14 @@ abstract class BaseProcessor(val symbolProcessorEnvironment: SymbolProcessorEnvi
symbolProcessorEnvironment,
resolver,
)
process(null, environment, XRoundEnv.create(environment))
process(null, environment, XRoundEnv.create(environment), resolver)
return emptyList()
}

abstract fun process(
annotations: Set<XTypeElement>?,
environment: XProcessingEnv,
round: XRoundEnv
round: XRoundEnv,
resolver: Resolver? = null,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.airbnb.deeplinkdispatch

import androidx.room.compiler.processing.XAnnotation
import androidx.room.compiler.processing.XAnnotationValue
import androidx.room.compiler.processing.XElement
import androidx.room.compiler.processing.XExecutableParameterElement
import androidx.room.compiler.processing.XFiler
Expand All @@ -34,6 +35,7 @@ import com.airbnb.deeplinkdispatch.base.Utils.isConfigurablePathSegment
import com.airbnb.deeplinkdispatch.handler.DeepLinkParamType
import com.airbnb.deeplinkdispatch.handler.DeeplinkParam
import com.airbnb.deeplinkdispatch.handler.TypeConverters
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.squareup.javapoet.ClassName
import com.squareup.javapoet.CodeBlock
Expand Down Expand Up @@ -123,19 +125,31 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
override fun process(
annotations: Set<XTypeElement>?,
environment: XProcessingEnv,
round: XRoundEnv
round: XRoundEnv,
resolver: Resolver?,
) {
try {
// source -> https://github.com/google/ksp/issues/2225
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you still planning on porting this?

val customAnnotations = resolver
?.getSymbolsWithAnnotation(DEEP_LINK_SPEC_CLASS.simpleName ?: "")
?.filterIsInstance<XTypeElement>()
?.toList() ?: emptyList()

val prefixes = customAnnotationPrefixes(customAnnotations)


// If we run KSP or this is configured to be incremental we need to rely on the
// incrementalMetadata for custom annotations. If not filter them out of the
// set of annotations we were given.
val customAnnotations = if (incrementalMetadata.incremental ||
/*val customAnnotations = if (incrementalMetadata.incremental ||
environment.backend == XProcessingEnv.Backend.KSP
) {
incrementalMetadata.customAnnotations
} else {
annotations?.filterAnnotatedAnnotations(DeepLinkSpec::class) ?: emptySet()
}
*/

val allDeepLinkAnnotatedElements =
customAnnotations.flatMap { round.getElementsAnnotatedWith(it.qualifiedName) } +
round.getElementsAnnotatedWith(DEEP_LINK_CLASS)
Expand Down Expand Up @@ -168,7 +182,7 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
annotatedMethodElements = annotatedMethodElements,
annotatedObjectElements = annotatedObjectElements,
deepLinkElements = collectDeepLinkElements(
prefixes = customAnnotationPrefixes(customAnnotations),
prefixes = prefixes,
classElementsToProcess = annotatedClassElements,
objectElementsToProcess = annotatedObjectElements,
methodElementsToProcess = annotatedMethodElements,
Expand Down Expand Up @@ -222,18 +236,21 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
uri = uri,
element = element
)

element is XTypeElement && element.isActivity() ->
DeepLinkAnnotatedElement.ActivityAnnotatedElement(
uri = uri,
element = element
)

element is XTypeElement && element.isHandler() -> {
verifyHandlerMatchArgs(element, uri)
DeepLinkAnnotatedElement.HandlerAnnotatedElement(
uri = uri,
element = element
)
}

else -> error(
"Internal error: Elements can only be 'MethodAnnotatedElement', " +
"'ActivityAnnotatedElement' or 'HandlerAnnotatedElement'"
Expand All @@ -255,7 +272,8 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
return getAllDeeplinkUrIsFromCustomDeepLinksOnElement(
element = element,
prefixesMap = prefixes
) + (element.getAnnotation(DEEP_LINK_CLASS)?.value?.value?.toList() ?: emptyList())
) + (element.getAnnotation(DEEP_LINK_CLASS)?.getAsStringList("value")?.toList()
?: emptyList())
}

private fun verifyCass(classElement: XTypeElement) {
Expand Down Expand Up @@ -331,6 +349,7 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
)
}
val allArgParameters = argsConstructor.parameters

val allPathParameters = allArgParameters.filterAnnotationType(DeepLinkParamType.Path)
val allQueryParameters = allArgParameters.filterAnnotationType(DeepLinkParamType.Query)
if (allPathParameters.size + allQueryParameters.size != allArgParameters.size) {
Expand All @@ -344,7 +363,7 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
val deepLinkUriTemplate = DeepLinkUri.parseTemplate(uriTemplate)
val templateHostPathSchemePlaceholders = deepLinkUriTemplate.schemeHostPathPlaceholders
val annotatedPathParameterNames = allPathParameters.mapNotNull {
it.getAnnotation(DeeplinkParam::class)?.value?.name
it.getAnnotation(DeeplinkParam::class)?.getAsString("name")
}.toSet()
val annotatedPathParametersThatAreNotInUrlTemplate =
annotatedPathParameterNames.filter { !templateHostPathSchemePlaceholders.contains(it) }
Expand All @@ -360,14 +379,23 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?

private fun List<XExecutableParameterElement>.filterAnnotationType(
deepLinkParamType: DeepLinkParamType
) =
filter { argParameter ->
argParameter.getAllAnnotations().find { annotation ->
annotation.qualifiedName == DeeplinkParam::class.qualifiedName
}?.annotationValues?.any { annotationValue ->
annotationValue.value.toString() == deepLinkParamType.toString()
} ?: false
}
) = filter { param ->
val deeplinkAnn = param.getAllAnnotations()
.firstOrNull { it.qualifiedName == DeeplinkParam::class.qualifiedName }
?: return@filter false

val enumArgValue = deeplinkAnn.annotationValues
.firstOrNull { it.name == "type" }
?.value
?.let { v ->
when (v) {
is Enum<*> -> v.name
else -> v.toString().substringAfterLast('.')
}
}

enumArgValue == deepLinkParamType.name
}

private fun verifyObjectElement(element: XTypeElement) {
if (!element.isHandler()) {
Expand All @@ -389,17 +417,20 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
}
}

private fun customAnnotationPrefixes(customAnnotations: Set<XTypeElement>): Map<XType, Array<String>> {
return customAnnotations.map { customAnnotationTypeElement ->
private fun customAnnotationPrefixes(customAnnotations: List<XTypeElement>): Map<XType, Array<String>> {
return customAnnotations.associate { customAnnotationTypeElement ->
if (!customAnnotationTypeElement.isAnnotationClass()) {
logError(
element = customAnnotationTypeElement,
message = "Only annotation types can be annotated with @${DEEP_LINK_SPEC_CLASS.simpleName}"
)
}
val prefix: Array<String> =
customAnnotationTypeElement.getAnnotation(DEEP_LINK_SPEC_CLASS)
?.let { it.value.prefix } ?: emptyArray()
val prefix: Array<String> = customAnnotationTypeElement
.getAnnotation(DEEP_LINK_SPEC_CLASS)
?.getAsStringList("prefix")
?.toTypedArray()
?: emptyArray()

if (prefix.hasEmptyOrNullString()) {
logError(
element = customAnnotationTypeElement,
Expand All @@ -411,7 +442,7 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
message = "Prefix property cannot be empty"
)
customAnnotationTypeElement.type to prefix
}.toMap()
}
}

private fun verifyAnnotatedType(
Expand Down Expand Up @@ -443,7 +474,7 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
logError(
element = it.value.first().enclosingTypeElement,
message = "Only one @DeepLinkHandler annotated element allowed per package!" +
" ${it.key} has ${it.value.joinToString { it.qualifiedName }}.",
" ${it.key} has ${it.value.joinToString { it.qualifiedName }}.",
)
}
return false
Expand Down Expand Up @@ -727,6 +758,7 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
?: ""
)
)

is DeepLinkAnnotatedElement.MethodAnnotatedElement ->
urisTrie.addToTrie(
DeepLinkEntry.MethodDeeplinkEntry(
Expand All @@ -736,6 +768,7 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
method = element.method
)
)

is DeepLinkAnnotatedElement.HandlerAnnotatedElement ->
urisTrie.addToTrie(
DeepLinkEntry.HandlerDeepLinkEntry(
Expand Down Expand Up @@ -866,13 +899,13 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
prefixesMap: Map<XType, Array<String>>
): List<String> {
return element.findAnnotatedAnnotation<DeepLinkSpec>().flatMap { customAnnotation ->
val suffixes = customAnnotation.getAsList<String>("value")
val suffixes = customAnnotation.getAsList<XAnnotationValue>("value")
val prefixes = prefixesMap[customAnnotation.type]
?: throw DeepLinkProcessorException(
"Unable to find annotation '${customAnnotation.qualifiedName}' you must " +
"update 'deepLink.customAnnotations' within the build.gradle"
"update 'deepLink.customAnnotations' within the build.gradle"
)
prefixes.flatMap { prefix -> suffixes.map { suffix -> prefix + suffix } }
prefixes.flatMap { prefix -> suffixes.map { suffix -> prefix + suffix.asString() } }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,11 @@ fun XTypeElement.directlyImplementsInterfaces(fqnList: List<String>): Boolean {
}

inline fun <reified T> XAnnotation.getAsList(method: String): List<T> {
val originalList = get<List<T>>(method)
// In new XProcessing versions List values are wrapped in XAnnotationValue but in old versions
// they are the raw type.
return if (originalList.firstOrNull() is XAnnotationValue) {
// TODO: In the next full release of xprocessing we should be able to safely assume
// the list type is always XAnnotationValue and can remove this if/else.
(originalList as List<XAnnotationValue>).map { xAnnotationValue ->
check(xAnnotationValue.value is T) {
"Expected type ${T::class} but got ${xAnnotationValue.value?.javaClass}"
}
xAnnotationValue.value as T
}
val annotationValue = get(method)
return if (annotationValue != null) {
@Suppress("UNCHECKED_CAST")
(annotationValue.value as? List<T>) ?: emptyList()
} else {
return originalList
emptyList()
}
}
7 changes: 5 additions & 2 deletions deeplinkdispatch/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
apply plugin: 'com.android.library'

sourceCompatibility = 11

apply plugin: 'checkstyle'

apply plugin: 'kotlin-android'
Expand Down Expand Up @@ -37,4 +35,9 @@ android {
testOptions {
unitTests.returnDefaultValues = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}
namespace 'com.airbnb.android.deeplinkdispatch'
}
3 changes: 1 addition & 2 deletions deeplinkdispatch/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.airbnb.android.deeplinkdispatch"/>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
10 changes: 5 additions & 5 deletions dependencies.gradle
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
def versions = [
kotlinVersion : '1.8.10',
kotlinVersion : '2.1.21',
appCompatVersion : '1.4.1',
localBroadcastManagerVersion : '1.1.0',
roboelectricVersion : '4.9',
benchmarkVersion : '1.0.0',
compileTestingVersion : '1.5.0',
kspVersion : '1.8.10-1.0.9',
xProcessorVersion : '2.6.0-alpha01',
kspVersion : '2.1.21-2.0.2',
xProcessorVersion : '2.7.2',
mockkVersion : '1.12.3',
ktlintGradlePluginVersion : '3.8.0',
ktlintGradlePluginVersion : '5.1.0',
androidXTestingVersion : '1.4.0'
]

ext.versions = versions
ext.androidConfig = [
agpVersion : '7.4.0',
agpVersion : '8.11.1',
compileSdkVersion : 32,
minSdkVersion : 16,
targetSdkVersion : 30
Expand Down
3 changes: 3 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ android.enableR8.fullMode=true
# Publishing configuration for vanniktech/gradle-maven-publish-plugin
SONATYPE_HOST=DEFAULT
SONATYPE_AUTOMATIC_RELEASE=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 3 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#Mon Nov 18 16:19:47 PST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip
Loading
Loading