From 2bfc559c50be3ca1b13da34bd77c510853293302 Mon Sep 17 00:00:00 2001 From: Sebastian Sellmair Date: Fri, 25 Nov 2022 14:53:58 +0100 Subject: [PATCH] [Gradle] Implement IdeaKotlinEntityTest and IdeaKotlinEntity annotations KT-55112 --- .../gradle/idea/tcs/IdeaKotlinDependency.kt | 1 + .../tcs/IdeaKotlinDependencyCoordinates.kt | 1 + .../gradle/idea/tcs/IdeaKotlinEntitiy.kt | 15 ++++++ .../IdeaKotlinProjectArtifactDependency.kt | 1 + .../idea/tcs/IdeaKotlinProjectCoordinates.kt | 1 + .../idea/tcs/IdeaKotlinSourceDependency.kt | 2 + .../tcs/IdeaKotlinEntityAnnotationUtils.kt | 20 ++++++++ .../gradle/idea/tcs/IdeaKotlinEntityTest.kt | 47 +++++++++++++++++++ ...t.kt => IdeaKotlinModelObjectGraphTest.kt} | 24 +++------- .../gradle/idea/tcs/ReflectionTestUtils.kt | 25 ++++++++++ 10 files changed, 120 insertions(+), 17 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinEntitiy.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinEntityAnnotationUtils.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinEntityTest.kt rename libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/{IdeaKotlinObjectGraphTest.kt => IdeaKotlinModelObjectGraphTest.kt} (83%) create mode 100644 libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/ReflectionTestUtils.kt diff --git a/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinDependency.kt b/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinDependency.kt index 4111cbda13a..d8e730b979c 100644 --- a/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinDependency.kt +++ b/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinDependency.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.idea.tcs import org.jetbrains.kotlin.tooling.core.MutableExtras import java.io.Serializable +@IdeaKotlinModel sealed interface IdeaKotlinDependency : Serializable { val coordinates: IdeaKotlinDependencyCoordinates? val extras: MutableExtras diff --git a/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinDependencyCoordinates.kt b/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinDependencyCoordinates.kt index 356759923c4..85c373a9972 100644 --- a/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinDependencyCoordinates.kt +++ b/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinDependencyCoordinates.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.idea.tcs import java.io.File import java.io.Serializable +@IdeaKotlinModel sealed interface IdeaKotlinDependencyCoordinates : Serializable data class IdeaKotlinBinaryCoordinates( diff --git a/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinEntitiy.kt b/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinEntitiy.kt new file mode 100644 index 00000000000..53a72f77c61 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinEntitiy.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.idea.tcs + +@Target(AnnotationTarget.ANNOTATION_CLASS) +annotation class IdeaKotlinEntity + +@IdeaKotlinEntity +annotation class IdeaKotlinModel + +@IdeaKotlinEntity +annotation class IdeaKotlinService \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinProjectArtifactDependency.kt b/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinProjectArtifactDependency.kt index f2b248a2d31..9c7e4a507d6 100644 --- a/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinProjectArtifactDependency.kt +++ b/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinProjectArtifactDependency.kt @@ -14,6 +14,7 @@ data class IdeaKotlinProjectArtifactDependency( override val extras: MutableExtras = mutableExtrasOf() ) : IdeaKotlinDependency { + @IdeaKotlinService fun interface Resolver { fun resolve(dependency: IdeaKotlinProjectArtifactDependency): IdeaKotlinSourceDependency? diff --git a/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinProjectCoordinates.kt b/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinProjectCoordinates.kt index 1df575d9bfb..710eb4c308b 100644 --- a/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinProjectCoordinates.kt +++ b/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinProjectCoordinates.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.idea.tcs import java.io.Serializable +@IdeaKotlinModel data class IdeaKotlinProjectCoordinates( val buildId: String, val projectPath: String, diff --git a/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinSourceDependency.kt b/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinSourceDependency.kt index fcdc37065c0..71cdab32156 100644 --- a/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinSourceDependency.kt +++ b/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinSourceDependency.kt @@ -14,6 +14,8 @@ data class IdeaKotlinSourceDependency( override val coordinates: IdeaKotlinSourceCoordinates, override val extras: MutableExtras = mutableExtrasOf() ) : IdeaKotlinDependency { + + @IdeaKotlinModel enum class Type : Serializable { Regular, Friend, DependsOn; diff --git a/libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinEntityAnnotationUtils.kt b/libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinEntityAnnotationUtils.kt new file mode 100644 index 00000000000..7bd83f0ec3e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinEntityAnnotationUtils.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.idea.tcs + +import kotlin.reflect.KClass +import kotlin.reflect.full.allSuperclasses +import kotlin.reflect.full.findAnnotation + +fun KClass<*>.findIdeaKotlinEntityAnnotations(): List { + return (annotations + allSuperclasses.flatMap { it.annotations }).filter { annotation -> + annotation.annotationClass.findAnnotation() != null + } +} + +val KClass<*>.isIdeaKotlinModel get() = findIdeaKotlinEntityAnnotations().singleOrNull() is IdeaKotlinModel + +val KClass<*>.isIdeaKotlinService get() = findIdeaKotlinEntityAnnotations().singleOrNull() is IdeaKotlinService diff --git a/libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinEntityTest.kt b/libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinEntityTest.kt new file mode 100644 index 00000000000..7639a545b39 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinEntityTest.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.idea.tcs + +import org.jetbrains.kotlin.gradle.idea.tcs.ReflectionTestUtils.displayName +import org.jetbrains.kotlin.gradle.idea.tcs.ReflectionTestUtils.ideaTcsPackage +import org.jetbrains.kotlin.gradle.idea.tcs.ReflectionTestUtils.ideaTcsReflections +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import org.reflections.scanners.Scanners +import kotlin.reflect.KClass +import kotlin.test.Test +import kotlin.test.fail + +@RunWith(Parameterized::class) +class IdeaKotlinEntityTest(private val node: KClass<*>, private val clazzName: String) { + + @Test + fun `test - node is marked as IdeaKotlinEntity`() { + val entityAnnotations = node.findIdeaKotlinEntityAnnotations() + + if (entityAnnotations.isEmpty()) + fail("Expected class $clazzName to be marked with any ${IdeaKotlinEntity::class.java.simpleName} annotation") + + if (entityAnnotations.size > 1) + fail("Conflicting ${IdeaKotlinEntity::class.java.simpleName} annotations on $clazzName ($entityAnnotations)") + } + + + companion object { + + @JvmStatic + @Parameterized.Parameters(name = "{1}") + fun findClasses(): List> { + return ideaTcsReflections.getAll(Scanners.SubTypes) + .map { Class.forName(it) } + .filter { !it.isAnnotation } + .map { it.kotlin } + .filter { it.qualifiedName.orEmpty().startsWith(ideaTcsPackage) } + .map { clazz -> arrayOf(clazz, checkNotNull(clazz.displayName())) } + + } + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinObjectGraphTest.kt b/libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinModelObjectGraphTest.kt similarity index 83% rename from libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinObjectGraphTest.kt rename to libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinModelObjectGraphTest.kt index 88c136983fb..5d47175e754 100644 --- a/libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinObjectGraphTest.kt +++ b/libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinModelObjectGraphTest.kt @@ -5,26 +5,25 @@ package org.jetbrains.kotlin.gradle.idea.tcs +import org.jetbrains.kotlin.gradle.idea.tcs.ReflectionTestUtils.displayName +import org.jetbrains.kotlin.gradle.idea.tcs.ReflectionTestUtils.ideaTcsReflections +import org.jetbrains.kotlin.gradle.idea.tcs.ReflectionTestUtils.kotlinReflections import org.jetbrains.kotlin.tooling.core.AbstractExtras import org.jetbrains.kotlin.tooling.core.Extras import org.jetbrains.kotlin.tooling.core.MutableExtras import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.junit.runners.Parameterized.Parameters -import org.reflections.Reflections import org.reflections.scanners.Scanners import java.io.Serializable import java.lang.reflect.Field import java.lang.reflect.Modifier import kotlin.reflect.KClass import kotlin.reflect.full.memberProperties -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotNull -import kotlin.test.assertTrue +import kotlin.test.* @RunWith(Parameterized::class) -class IdeaKotlinObjectGraphTest(private val node: KClass<*>, private val clazzName: String) { +class IdeaKotlinModelObjectGraphTest(private val node: KClass<*>, private val clazzName: String) { @Test fun `test - node implements Serializable`() { @@ -76,8 +75,6 @@ class IdeaKotlinObjectGraphTest(private val node: KClass<*>, private val clazzNa companion object { - private val reflections = Reflections("org.jetbrains.kotlin") - private val ideaTcsReflections = Reflections("org.jetbrains.kotlin.gradle.idea.tcs") private val ignoredNodes = setOf( /* Extras interface and AbstractExtras are okay for now: @@ -95,8 +92,8 @@ class IdeaKotlinObjectGraphTest(private val node: KClass<*>, private val clazzNa resolveQueue += ideaTcsReflections.getAll(Scanners.SubTypes) .map { Class.forName(it) } - .filter { it.name.startsWith("org.jetbrains.kotlin.gradle.idea.tcs") } .map { it.kotlin } + .filter { it.isIdeaKotlinModel } while (resolveQueue.isNotEmpty()) { val next = resolveQueue.removeFirst() @@ -105,7 +102,7 @@ class IdeaKotlinObjectGraphTest(private val node: KClass<*>, private val clazzNa next.resolveReachableClasses().forEach { child -> resolveQueue.add(child) if (child.java.isInterface || Modifier.isAbstract(child.java.modifiers)) { - val subtypes = reflections.getSubTypesOf(child.java).map { it.kotlin } + val subtypes = kotlinReflections.getSubTypesOf(child.java).map { it.kotlin } assertTrue(subtypes.isNotEmpty(), "Missing implementations for $child") resolveQueue.addAll(subtypes) } @@ -118,13 +115,6 @@ class IdeaKotlinObjectGraphTest(private val node: KClass<*>, private val clazzNa } - private fun KClass<*>.displayName() = java.name - .removePrefix("org.jetbrains.kotlin") - .removePrefix(".gradle") - .removePrefix(".idea") - .removePrefix(".tcs") - .removePrefix(".") - private fun KClass<*>.resolveReachableClasses(): Set> { return this.memberProperties .map { member -> member.returnType } diff --git a/libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/ReflectionTestUtils.kt b/libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/ReflectionTestUtils.kt new file mode 100644 index 00000000000..3649202a741 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-idea/src/test/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/ReflectionTestUtils.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.idea.tcs + +import org.reflections.Reflections +import kotlin.reflect.KClass + +object ReflectionTestUtils { + + const val ideaTcsPackage = "org.jetbrains.kotlin.gradle.idea.tcs" + val ideaTcsReflections = Reflections(ideaTcsPackage) + + const val kotlinPackage = "org.jetbrains.kotlin" + val kotlinReflections = Reflections(kotlinPackage) + + fun KClass<*>.displayName() = java.name + .removePrefix("org.jetbrains.kotlin") + .removePrefix(".gradle") + .removePrefix(".idea") + .removePrefix(".tcs") + .removePrefix(".") +}