diff --git a/WORKSPACE b/WORKSPACE index 8ba89d24ea4..9795eae78df 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -147,14 +147,17 @@ http_archive( load("@io_bazel_rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories", "kotlinc_version") -KOTLIN_VERSION = "1.9.24" +# TODO: update to Kotlin 2 once rules_kotlin support it. +# See https://github.com/bazelbuild/rules_kotlin/issues/1176 +KOTLINC_VERSION = "1.9.24" # Get from https://github.com/JetBrains/kotlin/releases/ KOTLINC_RELEASE_SHA = "eb7b68e01029fa67bc8d060ee54c12018f2c60ddc438cf21db14517229aa693b" kotlin_repositories( compiler_release = kotlinc_version( - release = KOTLIN_VERSION, + release = KOTLINC_VERSION, + # Get from https://github.com/JetBrains/kotlin/releases/ sha256 = KOTLINC_RELEASE_SHA, ), ) @@ -203,7 +206,9 @@ GRPC_VERSION = "1.2.0" INCAP_VERSION = "0.2" -KSP_VERSION = KOTLIN_VERSION + "-1.0.20" +KOTLIN_VERSION = "2.0.21" + +KSP_VERSION = KOTLIN_VERSION + "-1.0.28" MAVEN_VERSION = "3.3.3" @@ -245,6 +250,8 @@ maven_install( "com.google.code.findbugs:jsr305:3.0.1", "com.google.devtools.ksp:symbol-processing:%s" % KSP_VERSION, "com.google.devtools.ksp:symbol-processing-api:%s" % KSP_VERSION, + "com.google.devtools.ksp:symbol-processing-common-deps:%s" % KSP_VERSION, + "com.google.devtools.ksp:symbol-processing-aa-embeddable:%s" % KSP_VERSION, "com.google.errorprone:error_prone_annotation:%s" % ERROR_PRONE_VERSION, "com.google.errorprone:error_prone_annotations:%s" % ERROR_PRONE_VERSION, "com.google.errorprone:error_prone_check_api:%s" % ERROR_PRONE_VERSION, @@ -290,8 +297,8 @@ maven_install( "org.jetbrains.kotlin:kotlin-annotation-processing-embeddable:%s" % KOTLIN_VERSION, "org.jetbrains.kotlin:kotlin-compiler-embeddable:%s" % KOTLIN_VERSION, "org.jetbrains.kotlin:kotlin-daemon-embeddable:%s" % KOTLIN_VERSION, + "org.jetbrains.kotlin:kotlin-metadata-jvm:%s" % KOTLIN_VERSION, "org.jetbrains.kotlin:kotlin-stdlib:%s" % KOTLIN_VERSION, - "org.jetbrains.kotlin:kotlin-metadata-jvm:2.0.0-Beta5", "org.jspecify:jspecify:1.0.0", "org.mockito:mockito-core:2.28.2", "org.pantsbuild:jarjar:1.7.2", diff --git a/java/dagger/hilt/android/plugin/build.gradle b/java/dagger/hilt/android/plugin/build.gradle index 8627290c34b..e40d4ed9e95 100644 --- a/java/dagger/hilt/android/plugin/build.gradle +++ b/java/dagger/hilt/android/plugin/build.gradle @@ -1,8 +1,8 @@ buildscript { ext { - kotlin_version = "1.9.24" + kotlin_version = "2.0.21" agp_version = System.getenv('AGP_VERSION') ?: "8.1.1" - ksp_version = "$kotlin_version-1.0.20" + ksp_version = "$kotlin_version-1.0.28" pluginArtifactId = 'hilt-android-gradle-plugin' pluginId = 'com.google.dagger.hilt.android' } diff --git a/java/dagger/hilt/android/testing/compile/HiltCompilerTests.java b/java/dagger/hilt/android/testing/compile/HiltCompilerTests.java index e9c2b9af39a..39e90a98a3d 100644 --- a/java/dagger/hilt/android/testing/compile/HiltCompilerTests.java +++ b/java/dagger/hilt/android/testing/compile/HiltCompilerTests.java @@ -70,6 +70,14 @@ /** {@link Compiler} instances for testing Android Hilt. */ public final class HiltCompilerTests { + private static final ImmutableList DEFAULT_JAVAC_OPTIONS = ImmutableList.of(); + + private static final ImmutableList DEFAULT_KOTLINC_OPTIONS = + ImmutableList.of( + "-api-version=1.9", + "-language-version=1.9", + "-P", "plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true"); + /** Returns the {@link XProcessingEnv.Backend} for the given {@link CompilationResultSubject}. */ public static XProcessingEnv.Backend backend(CompilationResultSubject subject) { return CompilerTests.backend(subject); @@ -161,9 +169,8 @@ public static void compileWithKapt( sources, /* classpath= */ ImmutableList.of(CompilerTests.compilerDepsJar()), /* inheritClasspath= */ false, - /* javacArguments= */ ImmutableList.of(), - /* kotlincArguments= */ ImmutableList.of( - ), + /* javacArguments= */ DEFAULT_JAVAC_OPTIONS, + /* kotlincArguments= */ DEFAULT_KOTLINC_OPTIONS, /* kaptProcessors= */ ImmutableList.builder() .addAll(defaultProcessors()) .addAll(additionalProcessors) @@ -275,10 +282,12 @@ public void compile(Consumer onCompilationResult) { sources().asList(), /* classpath= */ ImmutableList.of(CompilerTests.compilerDepsJar()), /* options= */ processorOptions(), - /* javacArguments= */ javacArguments().asList(), - /* kotlincArguments= */ ImmutableList.of( - "-P", - "plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true"), + /* javacArguments= */ + ImmutableList.builder() + .addAll(DEFAULT_JAVAC_OPTIONS) + .addAll(javacArguments()) + .build(), + /* kotlincArguments= */ DEFAULT_KOTLINC_OPTIONS, /* config= */ HiltProcessingEnvConfigs.CONFIGS, /* javacProcessors= */ ImmutableList.builder() .addAll(mergeProcessors(defaultProcessors(), additionalJavacProcessors())) diff --git a/java/dagger/hilt/processor/internal/kotlin/BUILD b/java/dagger/hilt/processor/internal/kotlin/BUILD index 5fe9052c14e..32343ab403d 100644 --- a/java/dagger/hilt/processor/internal/kotlin/BUILD +++ b/java/dagger/hilt/processor/internal/kotlin/BUILD @@ -15,13 +15,16 @@ # Description: # Sources related to Kotlin metadata. -load("@rules_java//java:defs.bzl", "java_library") +load("//tools:bazel_compat.bzl", "compat_kt_jvm_library") package(default_visibility = ["//:src"]) -java_library( +compat_kt_jvm_library( name = "kotlin", - srcs = glob(["*.java"]), + srcs = glob([ + "*.java", + "*.kt", + ]), deps = [ "//:dagger_with_compiler", "//java/dagger/hilt/processor/internal:classnames", diff --git a/java/dagger/hilt/processor/internal/kotlin/ClassMetadata.kt b/java/dagger/hilt/processor/internal/kotlin/ClassMetadata.kt new file mode 100644 index 00000000000..d8ec6bda0ff --- /dev/null +++ b/java/dagger/hilt/processor/internal/kotlin/ClassMetadata.kt @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2023 The Dagger Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dagger.hilt.processor.internal.kotlin + +import androidx.room.compiler.processing.XAnnotation +import androidx.room.compiler.processing.XFieldElement +import androidx.room.compiler.processing.XMethodElement +import androidx.room.compiler.processing.XTypeElement +import kotlin.Metadata +import kotlin.metadata.declaresDefaultValue +import kotlin.metadata.KmClass +import kotlin.metadata.KmConstructor +import kotlin.metadata.KmFunction +import kotlin.metadata.KmProperty +import kotlin.metadata.KmValueParameter +import kotlin.metadata.jvm.KotlinClassMetadata +import kotlin.metadata.jvm.fieldSignature +import kotlin.metadata.jvm.getterSignature +import kotlin.metadata.jvm.signature +import kotlin.metadata.jvm.syntheticMethodForAnnotations + +/** Container classes for kotlin metadata types. */ +class ClassMetadata private constructor(private val kmClass: KmClass) { + val functionsBySignature = buildList { + addAll(kmClass.constructors.map { ConstructorMetadata(it) }) + addAll(kmClass.functions.map { MethodMetadata(it) }) + }.associateBy { it.signature } + + val propertiesBySignature = + kmClass.properties + .filter { it.fieldSignature != null } + .map { PropertyMetadata(it) } + .associateBy { it.fieldSignature } + + fun constructors(): List = + functionsBySignature.values.filterIsInstance() + + companion object { + /** Parse Kotlin class metadata from a given type element. */ + @JvmStatic + fun of(typeElement: XTypeElement): ClassMetadata { + val metadataAnnotation = checkNotNull(typeElement.getAnnotation(Metadata::class)).value + return when (val classMetadata = KotlinClassMetadata.readStrict(metadataAnnotation)) { + is KotlinClassMetadata.Class -> ClassMetadata(classMetadata.kmClass) + else -> error("Unsupported metadata type: ${classMetadata}") + } + } + } +} + +class ConstructorMetadata(private val kmConstructor: KmConstructor) : FunctionMetadata { + override val name = "" + override val signature = kmConstructor.signature!!.toString() + override val parameters = kmConstructor.valueParameters.map { ParameterMetadata(it) } +} + +class MethodMetadata(private val kmFunction: KmFunction) : FunctionMetadata { + override val name = kmFunction.name + override val signature = kmFunction.signature!!.toString() + override val parameters = kmFunction.valueParameters.map { ParameterMetadata(it) } +} + +interface FunctionMetadata { + val name: String + val signature: String + val parameters: List +} + +class PropertyMetadata(private val kmProperty: KmProperty) { + val name = kmProperty.name + + /** Returns the JVM field descriptor of the backing field of this property. */ + val fieldSignature = kmProperty.fieldSignature?.toString() + + val getterSignature = kmProperty.getterSignature?.toString() + + /** Returns JVM method descriptor of the synthetic method for property annotations. */ + val methodForAnnotationsSignature = kmProperty.syntheticMethodForAnnotations?.toString() +} + +class ParameterMetadata(private val kmValueParameter: KmValueParameter) { + val name = kmValueParameter.name + + fun declaresDefaultValue() = kmValueParameter.declaresDefaultValue +} + diff --git a/java/dagger/hilt/processor/internal/kotlin/KotlinMetadata.java b/java/dagger/hilt/processor/internal/kotlin/KotlinMetadata.java index 67b2177a089..47edf6e8ce0 100644 --- a/java/dagger/hilt/processor/internal/kotlin/KotlinMetadata.java +++ b/java/dagger/hilt/processor/internal/kotlin/KotlinMetadata.java @@ -17,37 +17,20 @@ package dagger.hilt.processor.internal.kotlin; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap; -import static kotlin.metadata.Flag.ValueParameter.DECLARES_DEFAULT_VALUE; -import androidx.room.compiler.processing.XAnnotation; import androidx.room.compiler.processing.XFieldElement; import androidx.room.compiler.processing.XMethodElement; import androidx.room.compiler.processing.XTypeElement; import com.google.auto.value.AutoValue; import com.google.auto.value.extension.memoized.Memoized; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import dagger.hilt.processor.internal.ClassNames; import dagger.internal.codegen.extension.DaggerCollectors; import dagger.internal.codegen.xprocessing.XElements; import java.util.HashMap; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.function.Function; import javax.annotation.Nullable; -import kotlin.Metadata; -import kotlin.metadata.Flag; -import kotlin.metadata.KmClass; -import kotlin.metadata.KmConstructor; -import kotlin.metadata.KmFunction; -import kotlin.metadata.KmProperty; -import kotlin.metadata.jvm.JvmExtensionsKt; -import kotlin.metadata.jvm.JvmFieldSignature; -import kotlin.metadata.jvm.JvmMetadataUtil; -import kotlin.metadata.jvm.JvmMethodSignature; -import kotlin.metadata.jvm.KotlinClassMetadata; /** Data class of a TypeElement and its Kotlin metadata. */ @AutoValue @@ -79,8 +62,8 @@ ImmutableMap methodDescriptors() { @Memoized boolean containsConstructorWithDefaultParam() { return classMetadata().constructors().stream() - .flatMap(constructor -> constructor.parameters().stream()) - .anyMatch(parameter -> parameter.flags(DECLARES_DEFAULT_VALUE)); + .flatMap(constructor -> constructor.getParameters().stream()) + .anyMatch(parameter -> parameter.declaresDefaultValue()); } /** Gets the synthetic method for annotations of a given field element. */ @@ -102,8 +85,7 @@ private Optional getAnnotationMethod(XFieldElement fieldEl } private Optional getAnnotationMethodUncached(XFieldElement fieldElement) { - return findProperty(fieldElement) - .methodForAnnotationsSignature() + return Optional.ofNullable(findProperty(fieldElement).getMethodForAnnotationsSignature()) .map( signature -> Optional.ofNullable(methodDescriptors().get(signature)) @@ -120,20 +102,19 @@ Optional getPropertyGetter(XFieldElement fieldElement) { } private Optional getPropertyGetterUncached(XFieldElement fieldElement) { - return findProperty(fieldElement) - .getterSignature() + return Optional.ofNullable(findProperty(fieldElement).getGetterSignature()) .flatMap(signature -> Optional.ofNullable(methodDescriptors().get(signature))); } private PropertyMetadata findProperty(XFieldElement field) { String fieldDescriptor = field.getJvmDescriptor(); - if (classMetadata().propertiesByFieldSignature().containsKey(fieldDescriptor)) { - return classMetadata().propertiesByFieldSignature().get(fieldDescriptor); + if (classMetadata().getPropertiesBySignature().containsKey(fieldDescriptor)) { + return classMetadata().getPropertiesBySignature().get(fieldDescriptor); } else { // Fallback to finding property by name, see: https://youtrack.jetbrains.com/issue/KT-35124 final String propertyName = getPropertyNameFromField(field); - return classMetadata().propertiesByFieldSignature().values().stream() - .filter(property -> propertyName.contentEquals(property.name())) + return classMetadata().getPropertiesBySignature().values().stream() + .filter(property -> propertyName.contentEquals(property.getName())) // SUPPRESS_GET_NAME_CHECK .collect(DaggerCollectors.onlyElement()); } } @@ -149,204 +130,7 @@ private static String getPropertyNameFromField(XFieldElement field) { /** Parse Kotlin class metadata from a given type element. */ static KotlinMetadata from(XTypeElement typeElement) { - return new AutoValue_KotlinMetadata(typeElement, ClassMetadata.create(metadataOf(typeElement))); - } - - private static KotlinClassMetadata.Class metadataOf(XTypeElement typeElement) { - XAnnotation annotation = typeElement.getAnnotation(ClassNames.KOTLIN_METADATA); - Metadata metadataAnnotation = - JvmMetadataUtil.Metadata( - annotation.getAsInt("k"), - annotation.getAsIntList("mv").stream().mapToInt(Integer::intValue).toArray(), - annotation.getAsStringList("d1").toArray(new String[0]), - annotation.getAsStringList("d2").toArray(new String[0]), - annotation.getAsString("xs"), - getOptionalStringValue(annotation, "pn").orElse(null), - getOptionalIntValue(annotation, "xi").orElse(null)); - KotlinClassMetadata metadata = KotlinClassMetadata.read(metadataAnnotation); - if (metadata == null) { - // Can happen if Kotlin < 1.0 or if metadata version is not supported, i.e. - // kotlinx-metadata-jvm is outdated. - throw new IllegalStateException( - "Unable to read Kotlin metadata due to unsupported metadata version."); - } - if (metadata instanceof KotlinClassMetadata.Class) { - // TODO(danysantiago): If when we need other types of metadata then move to right method. - return (KotlinClassMetadata.Class) metadata; - } else { - throw new IllegalStateException("Unsupported metadata type: " + metadata); - } - } - - @AutoValue - abstract static class ClassMetadata extends BaseMetadata { - abstract Optional companionObjectName(); - - abstract ImmutableSet constructors(); - - abstract ImmutableMap functionsBySignature(); - - abstract ImmutableMap propertiesByFieldSignature(); - - static ClassMetadata create(KotlinClassMetadata.Class metadata) { - KmClass kmClass = metadata.toKmClass(); - ClassMetadata.Builder builder = ClassMetadata.builder(kmClass.getFlags(), kmClass.getName()); - builder.companionObjectName(Optional.ofNullable(kmClass.getCompanionObject())); - kmClass.getConstructors().forEach(it -> builder.addConstructor(FunctionMetadata.create(it))); - kmClass.getFunctions().forEach(it -> builder.addFunction(FunctionMetadata.create(it))); - kmClass.getProperties().forEach(it -> builder.addProperty(PropertyMetadata.create(it))); - return builder.build(); - } - - private static Builder builder(int flags, String name) { - return new AutoValue_KotlinMetadata_ClassMetadata.Builder().flags(flags).name(name); - } - - @AutoValue.Builder - abstract static class Builder implements BaseMetadata.Builder { - abstract Builder companionObjectName(Optional companionObjectName); - - abstract ImmutableSet.Builder constructorsBuilder(); - - abstract ImmutableMap.Builder functionsBySignatureBuilder(); - - abstract ImmutableMap.Builder propertiesByFieldSignatureBuilder(); - - Builder addConstructor(FunctionMetadata constructor) { - constructorsBuilder().add(constructor); - functionsBySignatureBuilder().put(constructor.signature(), constructor); - return this; - } - - Builder addFunction(FunctionMetadata function) { - functionsBySignatureBuilder().put(function.signature(), function); - return this; - } - - Builder addProperty(PropertyMetadata property) { - if (property.fieldSignature().isPresent()) { - propertiesByFieldSignatureBuilder().put(property.fieldSignature().get(), property); - } - return this; - } - - abstract ClassMetadata build(); - } - } - - @AutoValue - abstract static class FunctionMetadata extends BaseMetadata { - abstract String signature(); - - abstract ImmutableList parameters(); - - static FunctionMetadata create(KmConstructor metadata) { - FunctionMetadata.Builder builder = FunctionMetadata.builder(metadata.getFlags(), ""); - metadata - .getValueParameters() - .forEach( - it -> - builder.addParameter(ValueParameterMetadata.create(it.getFlags(), it.getName()))); - builder.signature(Objects.requireNonNull(JvmExtensionsKt.getSignature(metadata)).asString()); - return builder.build(); - } - - static FunctionMetadata create(KmFunction metadata) { - FunctionMetadata.Builder builder = - FunctionMetadata.builder(metadata.getFlags(), metadata.getName()); - metadata - .getValueParameters() - .forEach( - it -> - builder.addParameter(ValueParameterMetadata.create(it.getFlags(), it.getName()))); - builder.signature(Objects.requireNonNull(JvmExtensionsKt.getSignature(metadata)).asString()); - return builder.build(); - } - - private static Builder builder(int flags, String name) { - return new AutoValue_KotlinMetadata_FunctionMetadata.Builder().flags(flags).name(name); - } - - @AutoValue.Builder - abstract static class Builder implements BaseMetadata.Builder { - abstract Builder signature(String signature); - - abstract ImmutableList.Builder parametersBuilder(); - - Builder addParameter(ValueParameterMetadata parameter) { - parametersBuilder().add(parameter); - return this; - } - - abstract FunctionMetadata build(); - } - } - - @AutoValue - abstract static class PropertyMetadata extends BaseMetadata { - /** Returns the JVM field descriptor of the backing field of this property. */ - abstract Optional fieldSignature(); - - abstract Optional getterSignature(); - - /** Returns JVM method descriptor of the synthetic method for property annotations. */ - abstract Optional methodForAnnotationsSignature(); - - static PropertyMetadata create(KmProperty metadata) { - PropertyMetadata.Builder builder = - PropertyMetadata.builder(metadata.getFlags(), metadata.getName()); - builder.fieldSignature( - Optional.ofNullable(JvmExtensionsKt.getFieldSignature(metadata)) - .map(JvmFieldSignature::asString)); - builder.getterSignature( - Optional.ofNullable(JvmExtensionsKt.getGetterSignature(metadata)) - .map(JvmMethodSignature::asString)); - builder.methodForAnnotationsSignature( - Optional.ofNullable(JvmExtensionsKt.getSyntheticMethodForAnnotations(metadata)) - .map(JvmMethodSignature::asString)); - return builder.build(); - } - - private static Builder builder(int flags, String name) { - return new AutoValue_KotlinMetadata_PropertyMetadata.Builder().flags(flags).name(name); - } - - @AutoValue.Builder - interface Builder extends BaseMetadata.Builder { - Builder fieldSignature(Optional signature); - - Builder getterSignature(Optional signature); - - Builder methodForAnnotationsSignature(Optional signature); - - PropertyMetadata build(); - } - } - - @AutoValue - abstract static class ValueParameterMetadata extends BaseMetadata { - private static ValueParameterMetadata create(int flags, String name) { - return new AutoValue_KotlinMetadata_ValueParameterMetadata(flags, name); - } - } - - abstract static class BaseMetadata { - /** Returns the Kotlin metadata flags for this property. */ - abstract int flags(); - - /** returns {@code true} if the given flag (e.g. {@link Flag.IS_PRIVATE}) applies. */ - boolean flags(Flag flag) { - return flag.invoke(flags()); - } - - /** Returns the simple name of this property. */ - abstract String name(); - - interface Builder { - BuilderT flags(int flags); - - BuilderT name(String name); - } + return new AutoValue_KotlinMetadata(typeElement, ClassMetadata.of(typeElement)); } @AutoValue @@ -360,21 +144,4 @@ static MethodForAnnotations create(XMethodElement method) { @Nullable abstract XMethodElement method(); } - - private static Optional getOptionalIntValue(XAnnotation annotation, String valueName) { - return isValuePresent(annotation, valueName) - ? Optional.of(annotation.getAsInt(valueName)) - : Optional.empty(); - } - - private static Optional getOptionalStringValue(XAnnotation annotation, String valueName) { - return isValuePresent(annotation, valueName) - ? Optional.of(annotation.getAsString(valueName)) - : Optional.empty(); - } - - private static boolean isValuePresent(XAnnotation annotation, String valueName) { - return annotation.getAnnotationValues().stream() - .anyMatch(member -> member.getName().equals(valueName)); - } } diff --git a/java/dagger/internal/codegen/kotlin/BUILD b/java/dagger/internal/codegen/kotlin/BUILD index 41b82ab5078..ed750cd1b49 100644 --- a/java/dagger/internal/codegen/kotlin/BUILD +++ b/java/dagger/internal/codegen/kotlin/BUILD @@ -15,13 +15,16 @@ # Description: # Sources related to Kotlin metadata. -load("@rules_java//java:defs.bzl", "java_library") +load("//tools:bazel_compat.bzl", "compat_kt_jvm_library") package(default_visibility = ["//:src"]) -java_library( +compat_kt_jvm_library( name = "kotlin", - srcs = glob(["*.java"]), + srcs = glob([ + "*.java", + "*.kt", + ]), plugins = ["//java/dagger/internal/codegen/bootstrap"], tags = ["maven:merged"], deps = [ diff --git a/java/dagger/internal/codegen/kotlin/ClassMetadata.kt b/java/dagger/internal/codegen/kotlin/ClassMetadata.kt new file mode 100644 index 00000000000..737057b7df8 --- /dev/null +++ b/java/dagger/internal/codegen/kotlin/ClassMetadata.kt @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2023 The Dagger Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dagger.internal.codegen.kotlin + +import androidx.room.compiler.processing.XAnnotation +import androidx.room.compiler.processing.XFieldElement +import androidx.room.compiler.processing.XMethodElement +import androidx.room.compiler.processing.XTypeElement +import kotlin.Metadata +import kotlin.metadata.KmClass +import kotlin.metadata.KmConstructor +import kotlin.metadata.KmFunction +import kotlin.metadata.KmProperty +import kotlin.metadata.KmValueParameter +import kotlin.metadata.jvm.KotlinClassMetadata +import kotlin.metadata.jvm.signature +import kotlin.metadata.jvm.fieldSignature +import kotlin.metadata.jvm.getterSignature +import kotlin.metadata.jvm.syntheticMethodForAnnotations + +/** Container classes for kotlin metadata types. */ +class ClassMetadata private constructor(private val kmClass: KmClass) { + val functionsBySignature = buildList { + addAll(kmClass.constructors.map { ConstructorMetadata(it) }) + addAll(kmClass.functions.map { MethodMetadata(it) }) + }.associateBy { it.signature } + + val propertiesBySignature = + kmClass.properties + .filter { it.fieldSignature != null } + .map { PropertyMetadata(it) } + .associateBy { it.fieldSignature } + + companion object { + /** Parse Kotlin class metadata from a given type element. */ + @JvmStatic + fun of(typeElement: XTypeElement): ClassMetadata { + val metadataAnnotation = checkNotNull(typeElement.getAnnotation(Metadata::class)).value + return when (val classMetadata = KotlinClassMetadata.readStrict(metadataAnnotation)) { + is KotlinClassMetadata.Class -> ClassMetadata(classMetadata.kmClass) + else -> error("Unsupported metadata type: ${classMetadata}") + } + } + } +} + +class ConstructorMetadata(private val kmConstructor: KmConstructor) : FunctionMetadata { + override val name = "" + override val signature = kmConstructor.signature!!.toString() + override val parameters = kmConstructor.valueParameters.map { ParameterMetadata(it) } +} + +class MethodMetadata(private val kmFunction: KmFunction) : FunctionMetadata { + override val name = kmFunction.name + override val signature = kmFunction.signature!!.toString() + override val parameters = kmFunction.valueParameters.map { ParameterMetadata(it) } +} + +interface FunctionMetadata { + val name: String + val signature: String + val parameters: List +} + +class PropertyMetadata(private val kmProperty: KmProperty) { + val name = kmProperty.name + + /** Returns the JVM field descriptor of the backing field of this property. */ + val fieldSignature = kmProperty.fieldSignature?.toString() + + val getterSignature = kmProperty.getterSignature?.toString() + + /** Returns JVM method descriptor of the synthetic method for property annotations. */ + val methodForAnnotationsSignature = kmProperty.syntheticMethodForAnnotations?.toString() +} + +class ParameterMetadata(private val kmValueParameter: KmValueParameter) { + val name = kmValueParameter.name +} diff --git a/java/dagger/internal/codegen/kotlin/KotlinMetadata.java b/java/dagger/internal/codegen/kotlin/KotlinMetadata.java index ef8f9a08e98..b06fd728a7d 100644 --- a/java/dagger/internal/codegen/kotlin/KotlinMetadata.java +++ b/java/dagger/internal/codegen/kotlin/KotlinMetadata.java @@ -19,35 +19,18 @@ import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap; import static dagger.internal.codegen.xprocessing.XElements.getSimpleName; -import androidx.room.compiler.processing.XAnnotation; import androidx.room.compiler.processing.XFieldElement; import androidx.room.compiler.processing.XMethodElement; import androidx.room.compiler.processing.XTypeElement; import com.google.auto.value.AutoValue; import com.google.auto.value.extension.memoized.Memoized; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import dagger.internal.codegen.extension.DaggerCollectors; -import dagger.internal.codegen.javapoet.TypeNames; import java.util.HashMap; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.function.Function; import javax.annotation.Nullable; -import kotlin.Metadata; -import kotlin.metadata.Flag; -import kotlin.metadata.KmClass; -import kotlin.metadata.KmConstructor; -import kotlin.metadata.KmFunction; -import kotlin.metadata.KmProperty; -import kotlin.metadata.jvm.JvmExtensionsKt; -import kotlin.metadata.jvm.JvmFieldSignature; -import kotlin.metadata.jvm.JvmMetadataUtil; -import kotlin.metadata.jvm.JvmMethodSignature; -import kotlin.metadata.jvm.KotlinClassMetadata; /** Data class of a TypeElement and its Kotlin metadata. */ @AutoValue @@ -107,8 +90,7 @@ private Optional getAnnotationMethod(XFieldElement fieldEl } private Optional getAnnotationMethodUncached(XFieldElement fieldElement) { - return findProperty(fieldElement) - .methodForAnnotationsSignature() + return Optional.ofNullable(findProperty(fieldElement).getMethodForAnnotationsSignature()) .map( signature -> Optional.ofNullable(methodDescriptors().get(signature)) @@ -125,20 +107,19 @@ Optional getPropertyGetter(XFieldElement fieldElement) { } private Optional getPropertyGetterUncached(XFieldElement fieldElement) { - return findProperty(fieldElement) - .getterSignature() + return Optional.ofNullable(findProperty(fieldElement).getGetterSignature()) .flatMap(signature -> Optional.ofNullable(methodDescriptors().get(signature))); } private PropertyMetadata findProperty(XFieldElement field) { String fieldDescriptor = field.getJvmDescriptor(); - if (classMetadata().propertiesByFieldSignature().containsKey(fieldDescriptor)) { - return classMetadata().propertiesByFieldSignature().get(fieldDescriptor); + if (classMetadata().getPropertiesBySignature().containsKey(fieldDescriptor)) { + return classMetadata().getPropertiesBySignature().get(fieldDescriptor); } else { // Fallback to finding property by name, see: https://youtrack.jetbrains.com/issue/KT-35124 final String propertyName = getPropertyNameFromField(field); - return classMetadata().propertiesByFieldSignature().values().stream() - .filter(property -> propertyName.contentEquals(property.name())) + return classMetadata().getPropertiesBySignature().values().stream() + .filter(property -> propertyName.contentEquals(property.getName())) // SUPPRESS_GET_NAME_CHECK .collect(DaggerCollectors.onlyElement()); } } @@ -154,217 +135,7 @@ private static String getPropertyNameFromField(XFieldElement field) { /** Parse Kotlin class metadata from a given type element. */ static KotlinMetadata from(XTypeElement typeElement) { - return new AutoValue_KotlinMetadata(typeElement, ClassMetadata.create(metadataOf(typeElement))); - } - - private static KotlinClassMetadata.Class metadataOf(XTypeElement typeElement) { - XAnnotation annotationMirror = typeElement.getAnnotation(TypeNames.KOTLIN_METADATA); - Preconditions.checkNotNull(annotationMirror); - Metadata metadataAnnotation = - JvmMetadataUtil.Metadata( - annotationMirror.getAsInt("k"), - annotationMirror.getAsIntList("mv").stream().mapToInt(Integer::intValue).toArray(), - annotationMirror.getAsStringList("d1").toArray(new String[0]), - annotationMirror.getAsStringList("d2").toArray(new String[0]), - annotationMirror.getAsString("xs"), - annotationMirror.getAnnotationValue("pn").hasStringValue() - ? annotationMirror.getAsString("pn") - : null, - annotationMirror.getAnnotationValue("xi").hasIntValue() - ? annotationMirror.getAsInt("xi") - : null); - KotlinClassMetadata metadata = KotlinClassMetadata.read(metadataAnnotation); - if (metadata == null) { - // Can happen if Kotlin < 1.0 or if metadata version is not supported, i.e. - // kotlinx-metadata-jvm is outdated. - throw new IllegalStateException( - "Unable to read Kotlin metadata due to unsupported metadata version."); - } - if (metadata instanceof KotlinClassMetadata.Class) { - // TODO(danysantiago): If when we need other types of metadata then move to right method. - return (KotlinClassMetadata.Class) metadata; - } else { - throw new IllegalStateException("Unsupported metadata type: " + metadata); - } - } - - @AutoValue - abstract static class ClassMetadata extends BaseMetadata { - abstract Optional companionObjectName(); - - abstract ImmutableSet constructors(); - - abstract ImmutableMap functionsBySignature(); - - abstract ImmutableMap propertiesByFieldSignature(); - - static ClassMetadata create(KotlinClassMetadata.Class metadata) { - KmClass kmClass = metadata.toKmClass(); - ClassMetadata.Builder builder = - ClassMetadata.builder( - kmClass.getFlags(), kmClass.getName()); // // SUPPRESS_GET_NAME_CHECK - builder.companionObjectName(Optional.ofNullable(kmClass.getCompanionObject())); - kmClass.getConstructors().forEach(it -> builder.addConstructor(FunctionMetadata.create(it))); - kmClass.getFunctions().forEach(it -> builder.addFunction(FunctionMetadata.create(it))); - kmClass.getProperties().forEach(it -> builder.addProperty(PropertyMetadata.create(it))); - return builder.build(); - } - - private static Builder builder(int flags, String name) { - return new AutoValue_KotlinMetadata_ClassMetadata.Builder().flags(flags).name(name); - } - - @AutoValue.Builder - abstract static class Builder implements BaseMetadata.Builder { - abstract Builder companionObjectName(Optional companionObjectName); - - abstract ImmutableSet.Builder constructorsBuilder(); - - abstract ImmutableMap.Builder functionsBySignatureBuilder(); - - abstract ImmutableMap.Builder propertiesByFieldSignatureBuilder(); - - Builder addConstructor(FunctionMetadata constructor) { - constructorsBuilder().add(constructor); - functionsBySignatureBuilder().put(constructor.signature(), constructor); - return this; - } - - Builder addFunction(FunctionMetadata function) { - functionsBySignatureBuilder().put(function.signature(), function); - return this; - } - - Builder addProperty(PropertyMetadata property) { - if (property.fieldSignature().isPresent()) { - propertiesByFieldSignatureBuilder().put(property.fieldSignature().get(), property); - } - return this; - } - - abstract ClassMetadata build(); - } - } - - @AutoValue - abstract static class FunctionMetadata extends BaseMetadata { - abstract String signature(); - - abstract ImmutableList parameters(); - - static FunctionMetadata create(KmConstructor metadata) { - FunctionMetadata.Builder builder = FunctionMetadata.builder(metadata.getFlags(), ""); - metadata - .getValueParameters() - .forEach( - it -> - builder.addParameter( - ValueParameterMetadata.create( - it.getFlags(), it.getName()))); // SUPPRESS_GET_NAME_CHECK - builder.signature(Objects.requireNonNull(JvmExtensionsKt.getSignature(metadata)).asString()); - return builder.build(); - } - - static FunctionMetadata create(KmFunction metadata) { - FunctionMetadata.Builder builder = - FunctionMetadata.builder( - metadata.getFlags(), metadata.getName()); // SUPPRESS_GET_NAME_CHECK - metadata - .getValueParameters() - .forEach( - it -> - builder.addParameter( - ValueParameterMetadata.create( - it.getFlags(), it.getName()))); // SUPPRESS_GET_NAME_CHECK - builder.signature(Objects.requireNonNull(JvmExtensionsKt.getSignature(metadata)).asString()); - return builder.build(); - } - - private static Builder builder(int flags, String name) { - return new AutoValue_KotlinMetadata_FunctionMetadata.Builder().flags(flags).name(name); - } - - @AutoValue.Builder - abstract static class Builder implements BaseMetadata.Builder { - abstract Builder signature(String signature); - - abstract ImmutableList.Builder parametersBuilder(); - - Builder addParameter(ValueParameterMetadata parameter) { - parametersBuilder().add(parameter); - return this; - } - - abstract FunctionMetadata build(); - } - } - - @AutoValue - abstract static class PropertyMetadata extends BaseMetadata { - /** Returns the JVM field descriptor of the backing field of this property. */ - abstract Optional fieldSignature(); - - abstract Optional getterSignature(); - - /** Returns JVM method descriptor of the synthetic method for property annotations. */ - abstract Optional methodForAnnotationsSignature(); - - static PropertyMetadata create(KmProperty metadata) { - PropertyMetadata.Builder builder = - PropertyMetadata.builder( - metadata.getFlags(), metadata.getName()); // SUPPRESS_GET_NAME_CHECK - builder.fieldSignature( - Optional.ofNullable(JvmExtensionsKt.getFieldSignature(metadata)) - .map(JvmFieldSignature::asString)); - builder.getterSignature( - Optional.ofNullable(JvmExtensionsKt.getGetterSignature(metadata)) - .map(JvmMethodSignature::asString)); - builder.methodForAnnotationsSignature( - Optional.ofNullable(JvmExtensionsKt.getSyntheticMethodForAnnotations(metadata)) - .map(JvmMethodSignature::asString)); - return builder.build(); - } - - private static Builder builder(int flags, String name) { - return new AutoValue_KotlinMetadata_PropertyMetadata.Builder().flags(flags).name(name); - } - - @AutoValue.Builder - interface Builder extends BaseMetadata.Builder { - Builder fieldSignature(Optional signature); - - Builder getterSignature(Optional signature); - - Builder methodForAnnotationsSignature(Optional signature); - - PropertyMetadata build(); - } - } - - @AutoValue - abstract static class ValueParameterMetadata extends BaseMetadata { - private static ValueParameterMetadata create(int flags, String name) { - return new AutoValue_KotlinMetadata_ValueParameterMetadata(flags, name); - } - } - - abstract static class BaseMetadata { - /** Returns the Kotlin metadata flags for this property. */ - abstract int flags(); - - /** returns {@code true} if the given flag (e.g. {@link Flag.IS_PRIVATE}) applies. */ - boolean flags(Flag flag) { - return flag.invoke(flags()); - } - - /** Returns the simple name of this property. */ - abstract String name(); - - interface Builder { - BuilderT flags(int flags); - - BuilderT name(String name); - } + return new AutoValue_KotlinMetadata(typeElement, ClassMetadata.of(typeElement)); } @AutoValue diff --git a/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java b/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java index 991b81ab4b6..9f80b3b10a6 100644 --- a/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java +++ b/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java @@ -29,7 +29,6 @@ import com.google.common.collect.ImmutableSet; import com.squareup.javapoet.ClassName; import dagger.internal.codegen.javapoet.TypeNames; -import dagger.internal.codegen.kotlin.KotlinMetadata.FunctionMetadata; import java.util.Optional; import javax.inject.Inject; @@ -86,7 +85,12 @@ public Optional getPropertyGetter(XFieldElement fieldElement) { public ImmutableMap getAllMethodNamesBySignature(XTypeElement element) { checkState( hasMetadata(element), "Can not call getAllMethodNamesBySignature for non-Kotlin class"); - return metadataFactory.create(element).classMetadata().functionsBySignature().values().stream() - .collect(toImmutableMap(FunctionMetadata::signature, FunctionMetadata::name)); + return metadataFactory.create(element) + .classMetadata() + .getFunctionsBySignature().values().stream() + .collect( + toImmutableMap( + FunctionMetadata::getSignature, + FunctionMetadata::getName)); // SUPPRESS_GET_NAME_CHECK } } diff --git a/java/dagger/internal/codegen/xprocessing/BUILD b/java/dagger/internal/codegen/xprocessing/BUILD index 4b549edee1a..f03b2f935a3 100644 --- a/java/dagger/internal/codegen/xprocessing/BUILD +++ b/java/dagger/internal/codegen/xprocessing/BUILD @@ -64,6 +64,8 @@ java_library( exports = [ ":xprocessing-testing-lib", "@maven//:com_google_devtools_ksp_symbol_processing", + "@maven//:com_google_devtools_ksp_symbol_processing_aa_embeddable", + "@maven//:com_google_devtools_ksp_symbol_processing_common_deps", "@maven//:org_jetbrains_kotlin_kotlin_annotation_processing_embeddable", "@maven//:org_jetbrains_kotlin_kotlin_compiler_embeddable", "@maven//:org_jetbrains_kotlin_kotlin_daemon_embeddable", diff --git a/java/dagger/internal/codegen/xprocessing/xprocessing-testing.jar b/java/dagger/internal/codegen/xprocessing/xprocessing-testing.jar index 4d0d7fd0086..880787cd9a5 100644 Binary files a/java/dagger/internal/codegen/xprocessing/xprocessing-testing.jar and b/java/dagger/internal/codegen/xprocessing/xprocessing-testing.jar differ diff --git a/java/dagger/internal/codegen/xprocessing/xprocessing.jar b/java/dagger/internal/codegen/xprocessing/xprocessing.jar index 7c041d68f2c..c19640ffed6 100644 Binary files a/java/dagger/internal/codegen/xprocessing/xprocessing.jar and b/java/dagger/internal/codegen/xprocessing/xprocessing.jar differ diff --git a/java/dagger/testing/compile/CompilerTests.java b/java/dagger/testing/compile/CompilerTests.java index 2567f52b041..39d22cb8ce7 100644 --- a/java/dagger/testing/compile/CompilerTests.java +++ b/java/dagger/testing/compile/CompilerTests.java @@ -68,6 +68,14 @@ public final class CompilerTests { ImmutableMap.of( "dagger.experimentalDaggerErrorMessages", "enabled"); + private static final ImmutableList DEFAULT_JAVAC_OPTIONS = ImmutableList.of(); + + private static final ImmutableList DEFAULT_KOTLINC_OPTIONS = + ImmutableList.of( + "-api-version=1.9", + "-language-version=1.9", + "-P", "plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true"); + /** Returns the {@link XProcessingEnv.Backend} for the given {@link CompilationResultSubject}. */ public static XProcessingEnv.Backend backend(CompilationResultSubject subject) { // TODO(bcorso): Create a more official API for this in XProcessing testing. @@ -136,9 +144,8 @@ public void compile(Consumer onInvocation) { sources(), /* classpath= */ ImmutableList.of(), processorOptions(), - /* javacArguments= */ ImmutableList.of(), - /* kotlincArguments= */ ImmutableList.of( - ), + /* javacArguments= */ DEFAULT_JAVAC_OPTIONS, + /* kotlincArguments= */ DEFAULT_KOTLINC_OPTIONS, /* config= */ PROCESSING_ENV_CONFIG, invocation -> { onInvocation.accept(invocation); @@ -229,10 +236,8 @@ public void compile(Consumer onCompilationResult) { sources().asList(), /* classpath= */ ImmutableList.of(), processorOptions(), - /* javacArguments= */ ImmutableList.of(), - /* kotlincArguments= */ ImmutableList.of( - "-P", - "plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true"), + /* javacArguments= */ DEFAULT_JAVAC_OPTIONS, + /* kotlincArguments= */ DEFAULT_KOTLINC_OPTIONS, /* config= */ PROCESSING_ENV_CONFIG, /* javacProcessors= */ mergeProcessors( ImmutableList.of( @@ -315,9 +320,8 @@ public static void compileWithKapt( sources, /* classpath= */ ImmutableList.of(compilerDepsJar()), /* inheritClasspath= */ false, - /* javacArguments= */ ImmutableList.of(), - /* kotlincArguments= */ ImmutableList.of( - ), + /* javacArguments= */ DEFAULT_JAVAC_OPTIONS, + /* kotlincArguments= */ DEFAULT_KOTLINC_OPTIONS, /* kaptProcessors= */ ImmutableList.of(new ComponentProcessor()), /* symbolProcessorProviders= */ ImmutableList.of(), /* processorOptions= */ processorOptions)); diff --git a/javatests/artifacts/dagger-android-ksp/build.gradle b/javatests/artifacts/dagger-android-ksp/build.gradle index c438e4187cf..f6757914b32 100644 --- a/javatests/artifacts/dagger-android-ksp/build.gradle +++ b/javatests/artifacts/dagger-android-ksp/build.gradle @@ -17,8 +17,8 @@ buildscript { ext { agp_version = "8.1.1" - kotlin_version = "1.9.24" - ksp_version = "$kotlin_version-1.0.20" + kotlin_version = "2.0.21" + ksp_version = "$kotlin_version-1.0.28" } repositories { google() diff --git a/javatests/artifacts/dagger-ksp/build.gradle b/javatests/artifacts/dagger-ksp/build.gradle index 1864e003030..63b03418204 100644 --- a/javatests/artifacts/dagger-ksp/build.gradle +++ b/javatests/artifacts/dagger-ksp/build.gradle @@ -17,8 +17,8 @@ buildscript { ext { dagger_version = "LOCAL-SNAPSHOT" - kotlin_version = "1.9.24" - ksp_version = "$kotlin_version-1.0.20" + kotlin_version = "2.0.21" + ksp_version = "$kotlin_version-1.0.28" junit_version = "4.13" truth_version = "1.0.1" } diff --git a/javatests/artifacts/dagger/build.gradle b/javatests/artifacts/dagger/build.gradle index db2b9c05627..6c72ef04ee5 100644 --- a/javatests/artifacts/dagger/build.gradle +++ b/javatests/artifacts/dagger/build.gradle @@ -17,8 +17,8 @@ buildscript { ext { dagger_version = "LOCAL-SNAPSHOT" - kotlin_version = "1.9.24" - ksp_version = "$kotlin_version-1.0.20" + kotlin_version = "2.0.21" + ksp_version = "$kotlin_version-1.0.28" junit_version = "4.13" truth_version = "1.0.1" } diff --git a/javatests/artifacts/dagger/lazyclasskey/build.gradle b/javatests/artifacts/dagger/lazyclasskey/build.gradle index 9fdb3428637..16982d496d0 100644 --- a/javatests/artifacts/dagger/lazyclasskey/build.gradle +++ b/javatests/artifacts/dagger/lazyclasskey/build.gradle @@ -18,7 +18,7 @@ buildscript { ext { dagger_version = 'LOCAL-SNAPSHOT' agp_version = "8.1.1" - kotlin_version = '1.9.24' + kotlin_version = '2.0.21' } repositories { google() diff --git a/javatests/artifacts/hilt-android/lazyclasskey/build.gradle b/javatests/artifacts/hilt-android/lazyclasskey/build.gradle index d284e2790b6..53ced2c3e47 100644 --- a/javatests/artifacts/hilt-android/lazyclasskey/build.gradle +++ b/javatests/artifacts/hilt-android/lazyclasskey/build.gradle @@ -18,7 +18,7 @@ buildscript { ext { hilt_version = 'LOCAL-SNAPSHOT' agp_version = "8.1.1" - kotlin_version = '1.9.24' + kotlin_version = '2.0.21' } repositories { google() diff --git a/javatests/artifacts/hilt-android/simple/build.gradle b/javatests/artifacts/hilt-android/simple/build.gradle index 376aca054b5..3dfb1b9c034 100644 --- a/javatests/artifacts/hilt-android/simple/build.gradle +++ b/javatests/artifacts/hilt-android/simple/build.gradle @@ -17,7 +17,7 @@ buildscript { ext { dagger_version = 'LOCAL-SNAPSHOT' - kotlin_version = '1.9.24' + kotlin_version = '2.0.21' agp_version = System.getenv('AGP_VERSION') ?: "8.1.1" } repositories { diff --git a/javatests/artifacts/hilt-android/simpleKotlin/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/build.gradle index 48409476bec..b109613571e 100644 --- a/javatests/artifacts/hilt-android/simpleKotlin/build.gradle +++ b/javatests/artifacts/hilt-android/simpleKotlin/build.gradle @@ -16,8 +16,8 @@ buildscript { ext { - kotlin_version = '1.9.24' - ksp_version = "$kotlin_version-1.0.20" + kotlin_version = '2.0.21' + ksp_version = "$kotlin_version-1.0.28" agp_version = System.getenv('AGP_VERSION') ?: "8.1.1" } repositories { diff --git a/javatests/artifacts/hilt-android/viewmodel/build.gradle b/javatests/artifacts/hilt-android/viewmodel/build.gradle index 13c72dc2002..cb70181735c 100644 --- a/javatests/artifacts/hilt-android/viewmodel/build.gradle +++ b/javatests/artifacts/hilt-android/viewmodel/build.gradle @@ -18,7 +18,7 @@ buildscript { ext { hilt_version = 'LOCAL-SNAPSHOT' agp_version = "8.1.1" - kotlin_version = '1.9.24' + kotlin_version = '2.0.21' } repositories { google() diff --git a/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java b/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java index dc3dfe2d656..dffe7014a78 100644 --- a/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java +++ b/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java @@ -475,18 +475,23 @@ public void invalidAnnotationValue() { () -> superficialValidation.validateElement(testClassElement)); // TODO(b/248552462): Javac and KSP should match once this bug is fixed. boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC; - assertThat(exception) - .hasMessageThat() - .contains( - String.format( - NEW_LINES.join( - "Validation trace:", - " => element (CLASS): test.Outer.TestClass", - " => annotation type: test.Outer.TestAnnotation", - " => annotation: @test.Outer.TestAnnotation(classes={<%1$s>})", - " => annotation value (TYPE_ARRAY): classes={<%1$s>}", - " => annotation value (TYPE): classes=<%1$s>"), - isJavac ? "error" : "Error")); + String expectedMessage = + String.format( + NEW_LINES.join( + "Validation trace:", + " => element (CLASS): test.Outer.TestClass", + " => annotation type: test.Outer.TestAnnotation", + " => annotation: @test.Outer.TestAnnotation(classes={<%1$s>})", + " => annotation value (TYPE_ARRAY): classes={<%1$s>}", + " => annotation value (TYPE): classes=<%1$s>"), + isJavac ? "error" : "ERROR TYPE: MissingType"); + if (!isJavac) { + expectedMessage = + NEW_LINES.join( + expectedMessage, + " => type (ERROR annotation value type): error.NonExistentClass"); + } + assertThat(exception).hasMessageThat().contains(expectedMessage); }); } @@ -533,20 +538,25 @@ public void invalidAnnotationValueOnParameter() { () -> superficialValidation.validateElement(parameter)); // TODO(b/248552462): Javac and KSP should match once this bug is fixed. boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC; - assertThat(exception) - .hasMessageThat() - .contains( - String.format( - NEW_LINES.join( - "Validation trace:", - " => element (CLASS): test.Outer.TestClass", - " => element (CONSTRUCTOR): TestClass(java.lang.String)", - " => element (PARAMETER): strParam", - " => annotation type: test.Outer.TestAnnotation", - " => annotation: @test.Outer.TestAnnotation(classes={<%1$s>})", - " => annotation value (TYPE_ARRAY): classes={<%1$s>}", - " => annotation value (TYPE): classes=<%1$s>"), - isJavac ? "error" : "Error")); + String expectedMessage = + String.format( + NEW_LINES.join( + "Validation trace:", + " => element (CLASS): test.Outer.TestClass", + " => element (CONSTRUCTOR): TestClass(java.lang.String)", + " => element (PARAMETER): strParam", + " => annotation type: test.Outer.TestAnnotation", + " => annotation: @test.Outer.TestAnnotation(classes={<%1$s>})", + " => annotation value (TYPE_ARRAY): classes={<%1$s>}", + " => annotation value (TYPE): classes=<%1$s>"), + isJavac ? "error" : "ERROR TYPE: MissingType"); + if (!isJavac) { + expectedMessage = + NEW_LINES.join( + expectedMessage, + " => type (ERROR annotation value type): error.NonExistentClass"); + } + assertThat(exception).hasMessageThat().contains(expectedMessage); }); } diff --git a/javatests/dagger/internal/codegen/XTypesStripTypeNameTest.java b/javatests/dagger/internal/codegen/XTypesStripTypeNameTest.java index 8a97b47e926..8c231028714 100644 --- a/javatests/dagger/internal/codegen/XTypesStripTypeNameTest.java +++ b/javatests/dagger/internal/codegen/XTypesStripTypeNameTest.java @@ -16,21 +16,15 @@ package dagger.internal.codegen; -import static androidx.room.compiler.processing.util.ProcessorTestExtKt.runProcessorTest; import static com.google.common.truth.Truth.assertThat; import static dagger.internal.codegen.extension.DaggerCollectors.onlyElement; import static dagger.internal.codegen.xprocessing.XTypes.stripVariances; import androidx.room.compiler.processing.XMethodElement; -import androidx.room.compiler.processing.XProcessingEnvConfig; import androidx.room.compiler.processing.XTypeElement; import androidx.room.compiler.processing.util.Source; -import androidx.room.compiler.processing.util.XTestInvocation; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; import com.squareup.javapoet.TypeName; import dagger.testing.compile.CompilerTests; -import java.util.function.Function; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -149,54 +143,39 @@ public void arrayType() { @Test public void typeVariableSameVariableName() { - runTest( + CompilerTests.invocationCompiler( CompilerTests.javaSource( - "Subject", - "interface Subject {", - " Foo method1();", - " Foo method2();", - "", - " interface Foo {}", - " interface Bar {}", - " interface Baz {}", - "}"), - invocation -> { - XTypeElement subject = invocation.getProcessingEnv().requireTypeElement("Subject"); - TypeName method1ReturnTypeName = - getDeclaredMethod(subject, "method1").getReturnType().getTypeName(); - TypeName method2ReturnTypeName = - getDeclaredMethod(subject, "method2").getReturnType().getTypeName(); - assertThat(method1ReturnTypeName).isEqualTo(method2ReturnTypeName); - return null; - }); + "Subject", + "interface Subject {", + " Foo method1();", + " Foo method2();", + "", + " interface Foo {}", + " interface Bar {}", + " interface Baz {}", + "}")) + .compile( + invocation -> { + XTypeElement subject = invocation.getProcessingEnv().requireTypeElement("Subject"); + TypeName method1ReturnTypeName = + getDeclaredMethod(subject, "method1").getReturnType().getTypeName(); + TypeName method2ReturnTypeName = + getDeclaredMethod(subject, "method2").getReturnType().getTypeName(); + assertThat(method1ReturnTypeName).isEqualTo(method2ReturnTypeName); + }); } private static void assertStrippedWildcardTypeNameEquals(Source source, String strippedTypeName) { - runTest( - source, - invocation -> { - XTypeElement subject = invocation.getProcessingEnv().requireTypeElement("Subject"); - TypeName returnTypeName = - getDeclaredMethod(subject, "method").getReturnType().getTypeName(); - assertThat(stripVariances(returnTypeName).toString().replace("Subject.", "")) - .isEqualTo(strippedTypeName); - return null; - }); - } - - private static void runTest(Source source, Function handler) { - runProcessorTest( - ImmutableList.of(source), - /* classpath= */ ImmutableList.of(), - /* options= */ ImmutableMap.of(), - /* javacArguments= */ ImmutableList.of(), - /* kotlincArguments= */ ImmutableList.of( - ), - /* config= */ new XProcessingEnvConfig.Builder().build(), - /* handler= */ invocation -> { - handler.apply(invocation); - return null; - }); + CompilerTests.invocationCompiler(source) + .compile( + invocation -> { + XTypeElement subject = invocation.getProcessingEnv().requireTypeElement("Subject"); + TypeName returnTypeName = + getDeclaredMethod(subject, "method").getReturnType().getTypeName(); + assertThat(stripVariances(returnTypeName).toString().replace("Subject.", "")) + .isEqualTo(strippedTypeName); + } + ); } private static XMethodElement getDeclaredMethod(XTypeElement typeElement, String jvmName) { diff --git a/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD b/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD index ce7197a0cd8..0a1873c4678 100644 --- a/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD +++ b/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD @@ -25,6 +25,7 @@ GenJavaTests( srcs = glob(["*.java"]), functional = False, javacopts = DOCLINT_HTML_AND_SYNTAX, + shard_count = 3, deps = [ "//java/dagger/internal/codegen/bindinggraphvalidation", "//java/dagger/internal/codegen/xprocessing", diff --git a/tools/bazel_compat.bzl b/tools/bazel_compat.bzl index bc8b04a36e7..9660588fe7d 100644 --- a/tools/bazel_compat.bzl +++ b/tools/bazel_compat.bzl @@ -12,14 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Macros for building with Bazel. -""" +# Description: +# Macros for building with Bazel. load("//third_party/kotlin/build_extensions:rules.bzl", "kt_android_library") +load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") def compat_kt_android_library(name, **kwargs): bazel_kt_android_library(name, kwargs) +def compat_kt_jvm_library(name, **kwargs): + bazel_kt_jvm_library(name, kwargs) + def bazel_kt_android_library(name, kwargs): """A macro that wraps Bazel's kt_android_library. @@ -63,3 +67,24 @@ def bazel_kt_android_library(name, kwargs): name = "lib{}-src.jar".format(name), actual = ":{}_internal_kt-sources.jar".format(name), ) + +def bazel_kt_jvm_library(name, kwargs): + """A macro that wraps Bazel's kt_jvm_library. + + This macro wraps Bazel's kt_jvm_library to output the jars files + in the expected locations (https://github.com/bazelbuild/rules_kotlin/issues/324). + + Args: + name: the name of the library. + kwargs: Additional arguments of the library. + """ + + kt_jvm_library( + name = name, + **kwargs + ) + + native.alias( + name = "lib{}-src.jar".format(name), + actual = ":{}-sources.jar".format(name), + )