diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 8aa94ede06..bf280e51c9 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -14,12 +14,15 @@ jobs: # The type of runner that the job will run on runs-on: ubuntu-latest + permissions: + contents: write + steps: # Checkout - uses: actions/checkout@v2 with: fetch-depth: 0 - ref: 1.0.31-release + ref: 2.0.0-release - name: merge commits from main to release branch run: | @@ -50,7 +53,7 @@ jobs: # Build cache - name: Cache Gradle Cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}-${{ hashFiles('**/gradle.properties') }} @@ -58,7 +61,7 @@ jobs: restore-keys: | ${{ runner.os }}-gradle- - name: Cache gradle wrapper - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} @@ -69,7 +72,7 @@ jobs: # Run ksp generated tests - name: test - run: ./gradlew --stacktrace --info test + run: ./gradlew --stacktrace --info check - name: push to release branch if: success() diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c935d14e52..3912274d8f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -46,7 +46,7 @@ jobs: # Build cache - name: Cache Gradle Cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}-${{ hashFiles('**/gradle.properties') }} @@ -54,14 +54,10 @@ jobs: restore-keys: | ${{ runner.os }}-gradle- - name: Cache gradle wrapper - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} - # Run ktlint - - name: lint - if: matrix.os == 'ubuntu-latest' - run: ./gradlew ktlint # Check API compatibility - name: API compatibility check @@ -71,7 +67,7 @@ jobs: # Run tests - name: test shell: bash - run: ./gradlew --stacktrace --info test + run: ./gradlew --stacktrace --info check - name: Upload test results if: always() uses: actions/upload-artifact@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3cd0deef4a..8310d0e089 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,6 +12,9 @@ jobs: # The type of runner that the job will run on runs-on: ubuntu-latest + permissions: + contents: write + steps: - name: Setup Java 17 uses: actions/setup-java@v1.4.3 @@ -25,7 +28,7 @@ jobs: # Build cache - name: Cache Gradle Cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}-${{ hashFiles('**/gradle.properties') }} @@ -33,7 +36,7 @@ jobs: restore-keys: | ${{ runner.os }}-gradle- - name: Cache gradle wrapper - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} @@ -41,7 +44,7 @@ jobs: # Run tests - name: test shell: bash - run: ./gradlew --stacktrace --info test + run: ./gradlew --stacktrace --info check - name: Upload test results if: always() uses: actions/upload-artifact@v4 diff --git a/buildSrc/src/main/kotlin/com/google/devtools/ksp/ApiCheck.kt b/buildSrc/src/main/kotlin/com/google/devtools/ksp/ApiCheck.kt index c0053cee98..767809caba 100644 --- a/buildSrc/src/main/kotlin/com/google/devtools/ksp/ApiCheck.kt +++ b/buildSrc/src/main/kotlin/com/google/devtools/ksp/ApiCheck.kt @@ -87,8 +87,7 @@ private fun JavaExec.configureCommonMetalavaArgs( private fun Project.getCompileClasspath(): String = configurations.findByName("compileClasspath")!!.files - .map { it.toRelativeString(projectDir) } - .joinToString(File.pathSeparator) + .joinToString(File.pathSeparator) { it.relativeToOrSelf(projectDir).path } private fun Project.getMetalavaConfiguration(): Configuration { return configurations.findByName("metalava") ?: configurations.create("metalava") { diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/common/visitor/CollectAnnotatedSymbolsVisitor.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/common/visitor/CollectAnnotatedSymbolsVisitor.kt index 9cb3ec5b98..f9063b08db 100644 --- a/common-util/src/main/kotlin/com/google/devtools/ksp/common/visitor/CollectAnnotatedSymbolsVisitor.kt +++ b/common-util/src/main/kotlin/com/google/devtools/ksp/common/visitor/CollectAnnotatedSymbolsVisitor.kt @@ -44,8 +44,7 @@ class CollectAnnotatedSymbolsVisitor(private val inDepth: Boolean) : KSVisitorVo } override fun visitTypeAlias(typeAlias: KSTypeAlias, data: Unit) { - if (typeAlias.annotations.any()) - symbols.add(typeAlias) + visitAnnotated(typeAlias, data) } override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) { diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt index a0888f7daf..2c044d6752 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt @@ -46,8 +46,6 @@ import com.google.devtools.ksp.symbol.Visibility import com.google.devtools.ksp.symbol.impl.java.KSFileJavaImpl import com.google.devtools.ksp.symbol.impl.kotlin.KSFileImpl import com.intellij.openapi.Disposable -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer import com.intellij.openapi.vfs.StandardFileSystems @@ -55,7 +53,6 @@ import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiManager import com.intellij.psi.impl.file.impl.JavaFileManager -import com.intellij.util.ui.EDT import org.jetbrains.kotlin.analyzer.AnalysisResult import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCliJavaFileManagerImpl @@ -167,10 +164,8 @@ abstract class AbstractKotlinSymbolProcessingExtension( logger.logging("round $rounds of processing") val psiManager = PsiManager.getInstance(project) if (initialized) { - maybeRunInWriteAction { - psiManager.dropPsiCaches() - psiManager.dropResolveCaches() - } + psiManager.dropPsiCaches() + psiManager.dropResolveCaches() invalidateKotlinCliJavaFileManagerCache(project) } else { // In case of broken builds. @@ -534,20 +529,3 @@ private fun invalidateKotlinCliJavaFileManagerCache(project: Project): Boolean { (privateCacheField.get(javaFileManager) as? MutableMap<*, *>)?.clear() ?: return false return true } - -private fun maybeRunInWriteAction(f: () -> R) { - synchronized(EDT::class.java) { - if (!EDT.isCurrentThreadEdt()) { - val edt = EDT::class.java.getDeclaredField("myEventDispatchThread") - edt.isAccessible = true - edt.set(null, Thread.currentThread()) - } - if (ApplicationManager.getApplication() != null) { - runWriteAction { - f() - } - } else { - f() - } - } -} diff --git a/compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/AbstractKSPTest.kt b/compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/AbstractKSPTest.kt index 7faa9ccfaf..6e65f4dc9c 100644 --- a/compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/AbstractKSPTest.kt +++ b/compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/AbstractKSPTest.kt @@ -24,7 +24,6 @@ import com.intellij.openapi.util.Disposer import com.intellij.testFramework.TestDataFile import org.jetbrains.kotlin.analysis.test.framework.services.TargetPlatformDirectives import org.jetbrains.kotlin.analysis.test.framework.services.TargetPlatformProviderForAnalysisApiTests -import org.jetbrains.kotlin.cli.common.disposeRootInWriteAction import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoot @@ -61,13 +60,13 @@ abstract class DisposableTest { protected val disposable: Disposable get() = _disposable!! @BeforeEach - fun initDisposable(testInfo: TestInfo) { + private fun initDisposable(testInfo: TestInfo) { _disposable = Disposer.newDisposable("disposable for ${testInfo.displayName}") } @AfterEach - fun disposeDisposable() { - _disposable?.let { disposeRootInWriteAction(it) } + private fun disposeDisposable() { + _disposable?.let { Disposer.dispose(it) } _disposable = null } } diff --git a/compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/KSPCompilerPluginTest.kt b/compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/KSPCompilerPluginTest.kt index c8794fbff5..6a7a1df319 100644 --- a/compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/KSPCompilerPluginTest.kt +++ b/compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/KSPCompilerPluginTest.kt @@ -80,6 +80,12 @@ class KSPCompilerPluginTest : AbstractKSPCompilerPluginTest() { runTest("../test-utils/testData/api/annotationsRepeatable.kt") } + @TestMetadata("annotationTargets.kt") + @Test + fun testAnnotationTargets() { + runTest("../test-utils/testData/api/annotationTargets.kt") + } + @TestMetadata("annotationWithArbitraryClassValue.kt") @Test fun testAnnotationWithArbitraryClassValue() { diff --git a/docs/ksp2api.md b/docs/ksp2api.md index 7b0606d80a..3cdb4110ea 100644 --- a/docs/ksp2api.md +++ b/docs/ksp2api.md @@ -83,8 +83,8 @@ class OverrideOrder2 : BaseInterface2, GrandBaseInterface1 { * KSP2: Type annotations on a type argument now present in the resolved type as well ##### vararg parameters -* KSP1: Considered as an `Array` type -* KSP2: Not considered as an `Array` type +* KSP1: Considered as an `Array` type when it is from Java sources. +* KSP2: Not considered as an `Array` type. KSValueParameter returns the declared type consistently. ##### Synthesized members of Enums * KSP1: `values` and `valueOf` are missing if the enum is defined in Kotlin sources diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/AndroidPluginIntegration.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/AndroidPluginIntegration.kt index 345978a9c6..c9fab8e1c4 100644 --- a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/AndroidPluginIntegration.kt +++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/AndroidPluginIntegration.kt @@ -86,7 +86,7 @@ object AndroidPluginIntegration { } when (task) { is KspTaskJvm -> { - task.setSource(filteredSources) + task.source(filteredSources) task.dependsOn(filteredSources) } diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspAATask.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspAATask.kt index 3b4c0be83a..c925081c20 100644 --- a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspAATask.kt +++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspAATask.kt @@ -91,27 +91,30 @@ abstract class KspAATask @Inject constructor( } val changedClasses = if (kspConfig.incremental.get()) { - if (kspConfig.platformType.get() == KotlinPlatformType.jvm) { - getCPChanges( - inputChanges, - listOf( - kspConfig.sourceRoots, - kspConfig.javaSourceRoots, - kspConfig.commonSourceRoots, + when (kspConfig.platformType.get()) { + KotlinPlatformType.jvm, KotlinPlatformType.androidJvm -> { + getCPChanges( + inputChanges, + listOf( + kspConfig.sourceRoots, + kspConfig.javaSourceRoots, + kspConfig.commonSourceRoots, + kspConfig.classpathStructure, + ), + kspConfig.cachesDir.asFile.get(), kspConfig.classpathStructure, - ), - kspConfig.cachesDir.asFile.get(), - kspConfig.classpathStructure, - kspConfig.libraries, - kspConfig.processorClasspath, - ) - } else { - if ( - !inputChanges.isIncremental || - inputChanges.getFileChanges(kspConfig.nonJvmLibraries).iterator().hasNext() - ) - kspConfig.cachesDir.get().asFile.deleteRecursively() - emptyList() + kspConfig.libraries, + kspConfig.processorClasspath, + ) + } + else -> { + if ( + !inputChanges.isIncremental || + inputChanges.getFileChanges(kspConfig.nonJvmLibraries).iterator().hasNext() + ) + kspConfig.cachesDir.get().asFile.deleteRecursively() + emptyList() + } } } else { kspConfig.cachesDir.get().asFile.deleteRecursively() @@ -191,12 +194,14 @@ abstract class KspAATask @Inject constructor( if (kotlinCompilation is KotlinJvmAndroidCompilation) { // Workaround of a dependency resolution issue of AGP. // FIXME: figure out how to filter or set variant attributes correctly. + val kaptGeneratedClassesDir = getKaptGeneratedClassesDir(project, sourceSetName) val kspOutputDir = KspGradleSubplugin.getKspOutputDir(project, sourceSetName, target) cfg.libraries.from( project.files( Callable { kotlinCompileProvider.get().libraries.filter { !kspOutputDir.isParentOf(it) && + !kaptGeneratedClassesDir.isParentOf(it) && !(it.isDirectory && it.listFiles()?.isEmpty() == true) } } diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspExtension.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspExtension.kt index 96f62d0627..400e457bbd 100644 --- a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspExtension.kt +++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspExtension.kt @@ -28,7 +28,7 @@ import javax.inject.Inject abstract class KspExtension @Inject constructor(project: Project) { /** - * Enables or disables KSP 2, defaults to the `ksp.useKsp2` gradle property or `false` if that's not set. + * Enables or disables KSP 2, defaults to the `ksp.useKSP2` gradle property or `true` if that's not set. * * This API is temporary and will be removed once KSP1 is removed. */ @@ -65,7 +65,7 @@ abstract class KspExtension @Inject constructor(project: Project) { commandLineArgumentProviders.add(arg) } - @Deprecated("KSP will stop supporting other compiler plugins in KSP's Gradle tasks after 1.0.8.") + @Deprecated("No-op. KSP no longer reads this property") open var blockOtherCompilerPlugins: Boolean = true // Instruct KSP to pickup sources from compile tasks, instead of source sets. diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspSubplugin.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspSubplugin.kt index 99b5832aee..2e05036502 100644 --- a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspSubplugin.kt +++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspSubplugin.kt @@ -42,6 +42,7 @@ import org.gradle.work.InputChanges import org.jetbrains.kotlin.buildtools.api.SourcesChanges import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.gradle.dsl.KotlinVersion +import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin import org.jetbrains.kotlin.gradle.internal.kapt.incremental.CLASS_STRUCTURE_ARTIFACT_TYPE import org.jetbrains.kotlin.gradle.internal.kapt.incremental.ClasspathSnapshot import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptClasspathChanges @@ -214,7 +215,7 @@ class KspGradleSubplugin @Inject internal constructor(private val registry: Tool target.providers .gradleProperty("ksp.useKSP2") .map { it.toBoolean() } - .orElse(false) + .orElse(true) ) kspConfigurations = KspConfigurations(target) registry.register(KspModelBuilder()) @@ -351,7 +352,7 @@ class KspGradleSubplugin @Inject internal constructor(private val registry: Tool fun setSource(source: FileCollection) { // kspTask.setSource(source) would create circular dependency. // Therefore we need to manually extract input deps, filter them, and tell kspTask. - kspTask.setSource(project.provider { source.files }) + kspTask.source(project.provider { source.files }) kspTask.dependsOn(project.provider { source.nonSelfDeps(kspTaskName) }) } @@ -371,7 +372,7 @@ class KspGradleSubplugin @Inject internal constructor(private val registry: Tool val filteredTasks = kspExtension.excludedSources.buildDependencies.getDependencies(null).map { it.name } kotlinCompilation.allKotlinSourceSetsObservable.forAll { sourceSet -> - kspTask.setSource( + kspTask.source( sourceSet.kotlin.srcDirs.filter { !kotlinOutputDir.isParentOf(it) && !javaOutputDir.isParentOf(it) && it !in kspExtension.excludedSources @@ -383,6 +384,7 @@ class KspGradleSubplugin @Inject internal constructor(private val registry: Tool if (kotlinCompilation is KotlinJvmAndroidCompilation) { // Workaround of a dependency resolution issue of AGP. + val kaptGeneratedClassesDir = getKaptGeneratedClassesDir(project, sourceSetName) kspTask.libraries.setFrom( project.files( Callable { @@ -390,7 +392,9 @@ class KspGradleSubplugin @Inject internal constructor(private val registry: Tool // manually exclude KAPT generated class folder from class path snapshot. // TODO: remove in 1.9.0. - !kspOutputDir.isParentOf(it) && !(it.isDirectory && it.listFiles()?.isEmpty() == true) + !kspOutputDir.isParentOf(it) && + !kaptGeneratedClassesDir.isParentOf(it) && + !(it.isDirectory && it.listFiles()?.isEmpty() == true) } } ) @@ -405,11 +409,9 @@ class KspGradleSubplugin @Inject internal constructor(private val registry: Tool (kspTask as? AbstractKotlinCompile<*>)?.incremental = false } - fun maybeBlockOtherPlugins(kspTask: BaseKotlinCompile) { - if (kspExtension.blockOtherCompilerPlugins) { - kspTask.pluginClasspath.setFrom(kspClasspathCfg) - kspTask.pluginOptions.set(emptyList()) - } + fun blockOtherPlugins(kspTask: BaseKotlinCompile) { + kspTask.pluginClasspath.setFrom(kspClasspathCfg) + kspTask.pluginOptions.set(emptyList()) } fun configurePluginOptions(kspTask: BaseKotlinCompile) { @@ -474,7 +476,7 @@ class KspGradleSubplugin @Inject internal constructor(private val registry: Tool KotlinFactories.registerKotlinJvmCompileTask(project, kspTaskName, kotlinCompilation).also { it.configure { kspTask -> val kotlinCompileTask = kotlinCompileProvider.get() as KotlinCompile - maybeBlockOtherPlugins(kspTask as BaseKotlinCompile) + blockOtherPlugins(kspTask as BaseKotlinCompile) configureAsKspTask(kspTask, isIncremental) configureAsAbstractKotlinCompileTool(kspTask as AbstractKotlinCompileTool<*>) configurePluginOptions(kspTask) @@ -509,7 +511,7 @@ class KspGradleSubplugin @Inject internal constructor(private val registry: Tool KotlinPlatformType.js, KotlinPlatformType.wasm -> { KotlinFactories.registerKotlinJSCompileTask(project, kspTaskName, kotlinCompilation).also { it.configure { kspTask -> - maybeBlockOtherPlugins(kspTask as BaseKotlinCompile) + blockOtherPlugins(kspTask as BaseKotlinCompile) configureAsKspTask(kspTask, isIncremental) configureAsAbstractKotlinCompileTool(kspTask as AbstractKotlinCompileTool<*>) configurePluginOptions(kspTask) @@ -532,7 +534,7 @@ class KspGradleSubplugin @Inject internal constructor(private val registry: Tool KotlinPlatformType.common -> { KotlinFactories.registerKotlinMetadataCompileTask(project, kspTaskName, kotlinCompilation).also { it.configure { kspTask -> - maybeBlockOtherPlugins(kspTask as BaseKotlinCompile) + blockOtherPlugins(kspTask as BaseKotlinCompile) configureAsKspTask(kspTask, isIncremental) configureAsAbstractKotlinCompileTool(kspTask as AbstractKotlinCompileTool<*>) configurePluginOptions(kspTask) @@ -570,13 +572,7 @@ class KspGradleSubplugin @Inject internal constructor(private val registry: Tool kspClasspathCfgNonEmbeddable } // KotlinNativeCompile computes -Xplugin=... from compilerPluginClasspath. - if (kspExtension.blockOtherCompilerPlugins) { - kspTask.compilerPluginClasspath = classpathCfg - } else { - kspTask.compilerPluginClasspath = - classpathCfg + kotlinCompileTask.compilerPluginClasspath!! - kspTask.compilerPluginOptions.addPluginArgument(kotlinCompileTask.compilerPluginOptions) - } + kspTask.compilerPluginClasspath = classpathCfg kspTask.commonSources.from(kotlinCompileTask.commonSources) kspTask.options.add( FileCollectionSubpluginOption.create( @@ -932,3 +928,6 @@ internal fun FileCollection.nonSelfDeps(selfTaskName: String): List = buildDependencies.getDependencies(null).filterNot { it.name == selfTaskName } + +internal fun getKaptGeneratedClassesDir(project: Project, sourceSetName: String) = + Kapt3GradleSubplugin.getKaptGeneratedClassesDir(project, sourceSetName) diff --git a/gradle.properties b/gradle.properties index 0017c6ddc9..c81d26c3f7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,15 +1,15 @@ # Copied from kotlinc org.gradle.jvmargs=-Duser.country=US -Dkotlin.daemon.jvm.options=-Xmx4096m -Dfile.encoding=UTF-8 -kotlinBaseVersion=2.2.0-dev-745 +kotlinBaseVersion=2.1.20 agpBaseVersion=8.10.0-alpha03 -intellijVersion=241.19416.19 +intellijVersion=233.13135.128 junitVersion=4.13.1 junit5Version=5.8.2 junitPlatformVersion=1.8.2 googleTruthVersion=1.1 -aaKotlinBaseVersion=2.2.0-dev-745 +aaKotlinBaseVersion=2.2.0-dev-12941 aaIntellijVersion=241.19416.19 aaGuavaVersion=33.2.0-jre aaAsmVersion=9.0 @@ -24,5 +24,5 @@ compilerTestEnabled=false kotlin.jvm.target.validation.mode=warning # Build or runtime dependencies of this project -buildKotlinVersion=2.0.20 -buildKspVersion=2.0.20-1.0.25 \ No newline at end of file +buildKotlinVersion=2.1.20 +buildKspVersion=2.1.20-1.0.32 diff --git a/integration-tests/build.gradle.kts b/integration-tests/build.gradle.kts index 58be3b0802..762eeb790c 100644 --- a/integration-tests/build.gradle.kts +++ b/integration-tests/build.gradle.kts @@ -58,7 +58,7 @@ val agpCompatibilityTest by tasks.registering(Test::class) { configureCommonSettings() } -tasks.named("test") { +tasks.test { maxParallelForks = max(1, Runtime.getRuntime().availableProcessors() / 2) // Exclude test classes from agpCompatibilityTest @@ -67,7 +67,11 @@ tasks.named("test") { // Apply common settings configureCommonSettings() - // Ensure that 'test' depends on 'compatibilityTest' + // Ensure that 'test' runs after 'compatibilityTest' + mustRunAfter(agpCompatibilityTest) +} + +tasks.check { dependsOn(agpCompatibilityTest) } diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIncrementalIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIncrementalIT.kt index 8fec8c7064..c7cdb0af86 100644 --- a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIncrementalIT.kt +++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIncrementalIT.kt @@ -69,11 +69,6 @@ class AndroidIncrementalIT(useKSP2: Boolean) { testWithExtraFlags() } - @Test - fun testPlaygroundAndroidUseClasspathSnapshotFalse() { - testWithExtraFlags("-Pkotlin.incremental.useClasspathSnapshot=false") - } - companion object { @JvmStatic @Parameterized.Parameters(name = "KSP2={0}") diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/PlaygroundIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/PlaygroundIT.kt index d775a049c2..956c9a4245 100644 --- a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/PlaygroundIT.kt +++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/PlaygroundIT.kt @@ -250,7 +250,7 @@ class PlaygroundIT(val useKSP2: Boolean) { """ kotlin { compilerOptions { - apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_6) + apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_8) languageVersion.set(compilerOptions.apiVersion) } } @@ -260,8 +260,8 @@ class PlaygroundIT(val useKSP2: Boolean) { val kotlinVersion = System.getProperty("kotlinVersion").split('-').first() val gradleRunner = GradleRunner.create().withProjectDir(project.root) gradleRunner.buildAndCheck("clean", "build") { result -> - Assert.assertTrue(result.output.contains("language version: 1.6")) - Assert.assertTrue(result.output.contains("api version: 1.6")) + Assert.assertTrue(result.output.contains("language version: 1.8")) + Assert.assertTrue(result.output.contains("api version: 1.8")) if (!useKSP2) { // In case KSP 1 and KSP 2 uses different compiler versions, ignore this test for KSP 2 for now. Assert.assertTrue(result.output.contains("compiler version: $kotlinVersion")) @@ -352,14 +352,19 @@ class PlaygroundIT(val useKSP2: Boolean) { """ kotlin { compilerOptions { - allWarningsAsErrors.value(true) progressiveMode.value(true) } } """.trimIndent() ) val gradleRunner = GradleRunner.create().withProjectDir(project.root).withGradleVersion("8.0") - gradleRunner.withArguments("clean", "build").build() + gradleRunner.withArguments("clean", "build").build().let { + Assert.assertFalse( + it.output.contains( + "'-progressive' is meaningful only for the latest language version" + ) + ) + } project.restore(buildFile.path) } diff --git a/integration-tests/src/test/resources/playground/workload/build.gradle.kts b/integration-tests/src/test/resources/playground/workload/build.gradle.kts index baa316f8a2..57cf9bcae9 100644 --- a/integration-tests/src/test/resources/playground/workload/build.gradle.kts +++ b/integration-tests/src/test/resources/playground/workload/build.gradle.kts @@ -32,5 +32,5 @@ tasks.register("copyG") { into(layout.buildDirectory.file("generatedSources")) }.let { // Magic. `map` creates a provider to propagate task dependency. - compileKotlin.setSource(it.map { it.destinationDir }) + compileKotlin.source(it.map { it.destinationDir }) } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt index f94d7b5661..83fde1db14 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt @@ -17,7 +17,6 @@ package com.google.devtools.ksp.common -import com.google.devtools.ksp.isPrivate import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSDeclaration import com.google.devtools.ksp.symbol.KSDeclarationContainer @@ -35,9 +34,6 @@ object SymbolCollector : KSDefaultVisitor<(LookupSymbolWrapper) -> Unit, Unit>() override fun defaultHandler(node: KSNode, data: (LookupSymbolWrapper) -> Unit) = Unit override fun visitDeclaration(declaration: KSDeclaration, data: (LookupSymbolWrapper) -> Unit) { - if (declaration.isPrivate()) - return - val name = declaration.simpleName.asString() val scope = declaration.qualifiedName?.asString()?.let { it.substring(0, Math.max(it.length - name.length - 1, 0)) } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/common/PsiUtils.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/common/PsiUtils.kt index a760f3340d..347f391239 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/common/PsiUtils.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/common/PsiUtils.kt @@ -94,3 +94,11 @@ inline fun PsiElement.findParentOfType(): T? { } fun Sequence.memoized() = MemoizedSequence(this) + +inline fun lazyMemoizedSequence(crossinline initializer: () -> Sequence): Lazy> = lazy { + val value = initializer() + if (value is MemoizedSequence) + value + else + value.memoized() +} diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KotlinSymbolProcessing.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KotlinSymbolProcessing.kt index f3e6715b5d..bffc6d1210 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KotlinSymbolProcessing.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KotlinSymbolProcessing.kt @@ -37,6 +37,7 @@ import com.google.devtools.ksp.standalone.IncrementalKotlinDeclarationProviderFa import com.google.devtools.ksp.standalone.IncrementalKotlinPackageProviderFactory import com.google.devtools.ksp.standalone.KspStandaloneDirectInheritorsProvider import com.google.devtools.ksp.standalone.buildKspLibraryModule +import com.google.devtools.ksp.standalone.buildKspSdkModule import com.google.devtools.ksp.standalone.buildKspSourceModule import com.google.devtools.ksp.symbol.KSFile import com.google.devtools.ksp.symbol.KSNode @@ -57,6 +58,7 @@ import com.intellij.psi.PsiTreeChangeListener import com.intellij.psi.search.GlobalSearchScope import com.intellij.util.ui.EDT import org.jetbrains.kotlin.analysis.api.KaExperimentalApi +import org.jetbrains.kotlin.analysis.api.KaIdeApi import org.jetbrains.kotlin.analysis.api.KaImplementationDetail import org.jetbrains.kotlin.analysis.api.platform.KotlinMessageBusProvider import org.jetbrains.kotlin.analysis.api.platform.KotlinPlatformSettings @@ -64,13 +66,12 @@ import org.jetbrains.kotlin.analysis.api.platform.KotlinProjectMessageBusProvide import org.jetbrains.kotlin.analysis.api.platform.declarations.* import org.jetbrains.kotlin.analysis.api.platform.lifetime.KotlinAlwaysAccessibleLifetimeTokenFactory import org.jetbrains.kotlin.analysis.api.platform.lifetime.KotlinLifetimeTokenFactory -import org.jetbrains.kotlin.analysis.api.platform.modification.KotlinGlobalModificationService import org.jetbrains.kotlin.analysis.api.platform.modification.KotlinModificationTrackerFactory +import org.jetbrains.kotlin.analysis.api.platform.modification.publishGlobalModuleStateModificationEvent import org.jetbrains.kotlin.analysis.api.platform.packages.KotlinPackagePartProviderFactory import org.jetbrains.kotlin.analysis.api.platform.packages.KotlinPackageProviderFactory import org.jetbrains.kotlin.analysis.api.platform.permissions.KotlinAnalysisPermissionOptions -import org.jetbrains.kotlin.analysis.api.platform.projectStructure.KotlinByModulesResolutionScopeProvider -import org.jetbrains.kotlin.analysis.api.platform.projectStructure.KotlinResolutionScopeProvider +import org.jetbrains.kotlin.analysis.api.platform.resolution.KaResolutionActivityTracker import org.jetbrains.kotlin.analysis.api.projectStructure.KaModule import org.jetbrains.kotlin.analysis.api.projectStructure.KaSourceModule import org.jetbrains.kotlin.analysis.api.resolve.extensions.KaResolveExtensionProvider @@ -80,16 +81,15 @@ import org.jetbrains.kotlin.analysis.api.standalone.StandaloneAnalysisAPISession import org.jetbrains.kotlin.analysis.api.standalone.base.KotlinStandalonePlatformSettings import org.jetbrains.kotlin.analysis.api.standalone.base.declarations.KotlinStandaloneAnnotationsResolverFactory import org.jetbrains.kotlin.analysis.api.standalone.base.declarations.KotlinStandaloneDeclarationProviderMerger -import org.jetbrains.kotlin.analysis.api.standalone.base.modification.KotlinStandaloneGlobalModificationService import org.jetbrains.kotlin.analysis.api.standalone.base.modification.KotlinStandaloneModificationTrackerFactory import org.jetbrains.kotlin.analysis.api.standalone.base.permissions.KotlinStandaloneAnalysisPermissionOptions import org.jetbrains.kotlin.analysis.api.standalone.base.projectStructure.FirStandaloneServiceRegistrar import org.jetbrains.kotlin.analysis.api.standalone.base.projectStructure.StandaloneProjectFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getFirResolveSession +import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirResolutionActivityTracker import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLSealedInheritorsProvider import org.jetbrains.kotlin.analysis.project.structure.builder.KtModuleBuilder import org.jetbrains.kotlin.analysis.project.structure.builder.KtModuleProviderBuilder -import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSdkModule import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreApplicationEnvironmentMode import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment @@ -150,7 +150,7 @@ class KotlinSymbolProcessing( setupIdeaStandaloneExecution() } - @OptIn(KaExperimentalApi::class, KaImplementationDetail::class) + @OptIn(KaExperimentalApi::class, KaImplementationDetail::class, KaIdeApi::class) private fun createAASession( compilerConfiguration: CompilerConfiguration, projectDisposable: Disposable, @@ -172,7 +172,9 @@ class KotlinSymbolProcessing( ) // replaces buildKtModuleProviderByCompilerConfiguration(compilerConfiguration) - val projectStructureProvider = KtModuleProviderBuilder(kotlinCoreProjectEnvironment).apply { + val projectStructureProvider = KtModuleProviderBuilder( + kotlinCoreProjectEnvironment.environment, project + ).apply { val compilerConfig = compilerConfiguration val platform = when (kspConfig) { is KSPJvmConfig -> { @@ -200,7 +202,7 @@ class KotlinSymbolProcessing( ) compilerConfig.get(JVMConfigurationKeys.JDK_HOME)?.let { jdkHome -> addRegularDependency( - buildKtSdkModule { + buildKspSdkModule { this.platform = platform addBinaryRootsFromJdkHome(jdkHome.toPath(), isJre = false) libraryName = "JDK for $moduleName" @@ -238,7 +240,7 @@ class KotlinSymbolProcessing( projectStructureProvider, ) val ktFiles = allSourceFiles.filterIsInstance() - val libraryRoots = StandaloneProjectFactory.getAllBinaryRoots(modules, kotlinCoreProjectEnvironment) + val libraryRoots = StandaloneProjectFactory.getAllBinaryRoots(modules, kotlinCoreProjectEnvironment.environment) val createPackagePartProvider = StandaloneProjectFactory.createPackagePartsProvider( libraryRoots, @@ -252,6 +254,10 @@ class KotlinSymbolProcessing( KotlinAnalysisPermissionOptions::class.java, KotlinStandaloneAnalysisPermissionOptions::class.java ) + kotlinCoreProjectEnvironment.registerApplicationServices( + KaResolutionActivityTracker::class.java, + LLFirResolutionActivityTracker::class.java + ) registerProjectServices( kotlinCoreProjectEnvironment, @@ -311,10 +317,6 @@ class KotlinSymbolProcessing( KotlinModificationTrackerFactory::class.java, KotlinStandaloneModificationTrackerFactory::class.java ) - registerService( - KotlinGlobalModificationService::class.java, - KotlinStandaloneGlobalModificationService::class.java - ) registerService( KotlinLifetimeTokenFactory::class.java, KotlinAlwaysAccessibleLifetimeTokenFactory::class.java @@ -325,10 +327,6 @@ class KotlinSymbolProcessing( KotlinAnnotationsResolverFactory::class.java, KotlinStandaloneAnnotationsResolverFactory(project, ktFiles) ) - registerService( - KotlinResolutionScopeProvider::class.java, - KotlinByModulesResolutionScopeProvider::class.java - ) registerService( KotlinDeclarationProviderFactory::class.java, IncrementalKotlinDeclarationProviderFactory(this) @@ -543,7 +541,7 @@ class KotlinSymbolProcessing( fun dropCaches() { maybeRunInWriteAction { - KotlinGlobalModificationService.getInstance(project).publishGlobalSourceModuleStateModification() + project.publishGlobalModuleStateModificationEvent() KaSessionProvider.getInstance(project).clearCaches() psiManager.dropResolveCaches() psiManager.dropPsiCaches() @@ -687,9 +685,12 @@ internal val DEAR_SHADOW_JAR_PLEASE_DO_NOT_REMOVE_THESE = listOf( org.jetbrains.kotlin.analysis.low.level.api.fir.services.LLRealFirElementByPsiElementChooser::class.java, org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionInvalidationService::class.java, org.jetbrains.kotlin.analysis.low.level.api.fir.symbolProviders.factories.LLStubOriginLibrarySymbolProviderFactory::class.java, + org.jetbrains.kotlin.analysis.api.impl.base.java.KaBaseJavaModuleResolver::class.java, + org.jetbrains.kotlin.analysis.api.impl.base.java.KaBaseKotlinJavaPsiFacade::class.java, org.jetbrains.kotlin.analysis.api.impl.base.permissions.KaBaseAnalysisPermissionChecker::class.java, org.jetbrains.kotlin.analysis.api.impl.base.permissions.KaBaseAnalysisPermissionRegistry::class.java, - org.jetbrains.kotlin.analysis.api.impl.base.symbols.pointers.KaBasePsiSymbolPointerCreator::class.java, + org.jetbrains.kotlin.analysis.api.impl.base.projectStructure.KaBaseContentScopeProvider::class.java, + org.jetbrains.kotlin.analysis.api.impl.base.projectStructure.KaBaseResolutionScopeProvider::class.java, org.jetbrains.kotlin.analysis.api.permissions.KaAnalysisPermissionRegistry::class.java, org.jetbrains.kotlin.analysis.api.platform.KotlinProjectMessageBusProvider::class.java, org.jetbrains.kotlin.analysis.api.platform.permissions.KaAnalysisPermissionChecker::class.java, diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/ResolverAAImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/ResolverAAImpl.kt index 29772cc156..e947617f06 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/ResolverAAImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/ResolverAAImpl.kt @@ -89,8 +89,8 @@ class ResolverAAImpl( lateinit var functionAsMemberOfCache: MutableMap, KSFunction> val javaFileManager = project.getService(JavaFileManager::class.java) as KotlinCliJavaFileManagerImpl private val classBinaryCache = ClsKotlinBinaryClassCache() - private val packageInfoFiles by lazy { - allKSFiles.filter { it.fileName == "package-info.java" }.asSequence().memoized() + private val packageInfoFiles by lazyMemoizedSequence { + allKSFiles.filter { it.fileName == "package-info.java" }.asSequence() } // TODO: fix in upstream for builtin types. @@ -544,15 +544,10 @@ class ResolverAAImpl( } val realAnnotationName = expandedIfAlias ?: annotationName - fun checkAnnotated(annotated: KSAnnotated): Boolean { - return annotated.annotations.any { - val kaType = (it.annotationType.resolve() as? KSTypeImpl)?.type ?: return@any false - kaType.fullyExpand().symbol?.classId?.asFqNameString() == realAnnotationName - } - } - - val newSymbols = if (inDepth) newAnnotatedSymbolsWithLocals else newAnnotatedSymbols - return (newSymbols + deferredSymbolsRestored).asSequence().filter(::checkAnnotated) + return if (inDepth) + annotationToSymbolsMapWithLocals[realAnnotationName]?.asSequence() ?: emptySequence() + else + annotationToSymbolsMap[realAnnotationName]?.asSequence() ?: emptySequence() } private fun collectAnnotatedSymbols(inDepth: Boolean): Collection { @@ -565,16 +560,30 @@ class ResolverAAImpl( return visitor.symbols } - private val deferredSymbolsRestored: Set by lazy { - deferredSymbols.values.flatten().mapNotNull { it.restore() }.toSet() + private val annotationToSymbolsMap: Map> by lazy { + mapAnnotatedSymbols(false) + } + + private val annotationToSymbolsMapWithLocals: Map> by lazy { + mapAnnotatedSymbols(true) } - private val newAnnotatedSymbols: Collection by lazy { - collectAnnotatedSymbols(false) + private fun mapAnnotatedSymbols(inDepth: Boolean): Map> { + val newSymbols = collectAnnotatedSymbols(inDepth) + val withDeferred = newSymbols + deferredSymbolsRestored + return mutableMapOf>().apply { + withDeferred.forEach { annotated -> + for (annotation in annotated.annotations) { + val kaType = (annotation.annotationType.resolve() as? KSTypeImpl)?.type ?: continue + val annotationFqN = kaType.fullyExpand().symbol?.classId?.asFqNameString() ?: continue + getOrPut(annotationFqN, ::mutableSetOf).add(annotated) + } + } + } } - private val newAnnotatedSymbolsWithLocals: Collection by lazy { - collectAnnotatedSymbols(true) + private val deferredSymbolsRestored: Set by lazy { + deferredSymbols.values.flatten().mapNotNull { it.restore() }.toSet() } override fun getTypeArgument(typeRef: KSTypeReference, variance: Variance): KSTypeArgument { diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/AbstractKSDeclarationImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/AbstractKSDeclarationImpl.kt index cbfb6a8e3d..527fadaaeb 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/AbstractKSDeclarationImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/AbstractKSDeclarationImpl.kt @@ -17,6 +17,7 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.common.impl.KSNameImpl +import com.google.devtools.ksp.common.lazyMemoizedSequence import com.google.devtools.ksp.common.toKSModifiers import com.google.devtools.ksp.impl.symbol.java.KSAnnotationJavaImpl import com.google.devtools.ksp.impl.symbol.util.toKSModifiers @@ -52,9 +53,8 @@ abstract class AbstractKSDeclarationImpl(val ktDeclarationSymbol: KaDeclarationS KSNameImpl.getCached((ktDeclarationSymbol as? KaNamedSymbol)?.name?.asString() ?: "") } - override val annotations: Sequence by lazy { - originalAnnotations - } + override val annotations: Sequence + get() = originalAnnotations override val modifiers: Set by lazy { if (origin == Origin.JAVA_LIB || origin == Origin.KOTLIN_LIB || origin == Origin.SYNTHETIC) { @@ -122,7 +122,7 @@ abstract class AbstractKSDeclarationImpl(val ktDeclarationSymbol: KaDeclarationS override val docString: String? get() = ktDeclarationSymbol.toDocString() - internal open val originalAnnotations: Sequence by lazy { + internal open val originalAnnotations: Sequence by lazyMemoizedSequence { if (ktDeclarationSymbol.psi is KtAnnotated) { (ktDeclarationSymbol.psi as KtAnnotated).annotations(ktDeclarationSymbol, this) } else if (ktDeclarationSymbol.origin == KaSymbolOrigin.JAVA_SOURCE && ktDeclarationSymbol.psi != null) { diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationEnumEntryImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationEnumEntryImpl.kt index d9ef961c95..d9b4441675 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationEnumEntryImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationEnumEntryImpl.kt @@ -112,10 +112,8 @@ class KSClassDeclarationEnumEntryImpl private constructor(private val ktEnumEntr return visitor.visitClassDeclaration(this, data) } - override val declarations: Sequence by lazy { - // TODO: fix after .getDeclaredMemberScope() works for enum entry with no initializer. - emptySequence() - } + // TODO: fix after .getDeclaredMemberScope() works for enum entry with no initializer. + override val declarations: Sequence = emptySequence() override fun toString(): String { return "$parent.${simpleName.asString()}" diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationImpl.kt index 5d6b4da8a0..a55a89ec29 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationImpl.kt @@ -21,6 +21,7 @@ import com.google.devtools.ksp.common.KSObjectCache import com.google.devtools.ksp.common.errorTypeOnInconsistentArguments import com.google.devtools.ksp.common.impl.KSNameImpl import com.google.devtools.ksp.common.impl.KSTypeReferenceSyntheticImpl +import com.google.devtools.ksp.common.lazyMemoizedSequence import com.google.devtools.ksp.impl.ResolverAAImpl import com.google.devtools.ksp.impl.recordGetSealedSubclasses import com.google.devtools.ksp.impl.recordLookup @@ -70,7 +71,7 @@ class KSClassDeclarationImpl private constructor(internal val ktClassOrObjectSym } } - override val superTypes: Sequence by lazy { + override val superTypes: Sequence by lazyMemoizedSequence { (ktClassOrObjectSymbol.psiIfSource() as? KtClassOrObject)?.let { classOrObject -> if (classKind == ClassKind.ANNOTATION_CLASS || classKind == ClassKind.ENUM_CLASS) { null @@ -178,31 +179,21 @@ class KSClassDeclarationImpl private constructor(internal val ktClassOrObjectSym return visitor.visitClassDeclaration(this, data) } - override val declarations: Sequence by lazy { + override val declarations: Sequence by lazyMemoizedSequence { val decls = ktClassOrObjectSymbol.declarations() if (origin == Origin.JAVA && classKind != ClassKind.ANNOTATION_CLASS) { - buildList { - decls.forEach { decl -> - if (decl is KSPropertyDeclarationImpl && decl.ktPropertySymbol is KaSyntheticJavaPropertySymbol) { - decl.getter?.let { - add( - KSFunctionDeclarationImpl.getCached( - (it as KSPropertyAccessorImpl).ktPropertyAccessorSymbol - ) - ) - } - decl.setter?.let { - add( - KSFunctionDeclarationImpl.getCached( - (it as KSPropertyAccessorImpl).ktPropertyAccessorSymbol - ) - ) - } - } else { - add(decl) + decls.flatMap { decl -> + if (decl is KSPropertyDeclarationImpl && decl.ktPropertySymbol is KaSyntheticJavaPropertySymbol) { + sequenceOf(decl.getter, decl.setter).mapNotNull { accessor -> + KSFunctionDeclarationImpl.getCached( + (accessor as? KSPropertyAccessorImpl)?.ktPropertyAccessorSymbol + ?: return@mapNotNull null + ) } + } else { + sequenceOf(decl) } - }.asSequence() + } } else decls } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileImpl.kt index 67bf356696..8b5235d363 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileImpl.kt @@ -19,6 +19,7 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.common.KSObjectCache import com.google.devtools.ksp.common.impl.KSNameImpl +import com.google.devtools.ksp.common.lazyMemoizedSequence import com.google.devtools.ksp.symbol.KSAnnotation import com.google.devtools.ksp.symbol.KSDeclaration import com.google.devtools.ksp.symbol.KSFile @@ -58,7 +59,7 @@ class KSFileImpl private constructor(internal val ktFileSymbol: KaFileSymbol) : psi.virtualFile.path } - override val declarations: Sequence by lazy { + override val declarations: Sequence by lazyMemoizedSequence { analyze { ktFileSymbol.fileScope.declarations.map { when (it) { @@ -84,7 +85,7 @@ class KSFileImpl private constructor(internal val ktFileSymbol: KaFileSymbol) : return visitor.visitFile(this, data) } - override val annotations: Sequence by lazy { + override val annotations: Sequence by lazyMemoizedSequence { (ktFileSymbol.psi as? KtFile)?.annotations(ktFileSymbol) ?: ktFileSymbol.annotations(this) } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileJavaImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileJavaImpl.kt index a46934e983..f58808cdfe 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileJavaImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileJavaImpl.kt @@ -19,6 +19,7 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.common.KSObjectCache import com.google.devtools.ksp.common.impl.KSNameImpl +import com.google.devtools.ksp.common.lazyMemoizedSequence import com.google.devtools.ksp.symbol.KSAnnotation import com.google.devtools.ksp.symbol.KSDeclaration import com.google.devtools.ksp.symbol.KSFile @@ -34,13 +35,15 @@ class KSFileJavaImpl private constructor(val psi: PsiJavaFile) : KSFile, Deferra fun getCached(psi: PsiJavaFile) = cache.getOrPut(psi) { KSFileJavaImpl(psi) } } - override val packageName: KSName = KSNameImpl.getCached(psi.packageName) + override val packageName: KSName by lazy { + KSNameImpl.getCached(psi.packageName) + } override val fileName: String = psi.name override val filePath: String = psi.virtualFile.path - override val declarations: Sequence by lazy { + override val declarations: Sequence by lazyMemoizedSequence { psi.classes.asSequence().mapNotNull { psi -> analyze { psi.namedClassSymbol?.let { KSClassDeclarationImpl.getCached(it) } @@ -50,7 +53,9 @@ class KSFileJavaImpl private constructor(val psi: PsiJavaFile) : KSFile, Deferra override val origin: Origin = Origin.JAVA - override val location: Location = psi.toLocation() + override val location: Location by lazy { + psi.toLocation() + } override val parent: KSNode? = null diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFunctionDeclarationImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFunctionDeclarationImpl.kt index 6c35287b76..a2078aaec9 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFunctionDeclarationImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFunctionDeclarationImpl.kt @@ -20,6 +20,7 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.* import com.google.devtools.ksp.common.KSObjectCache import com.google.devtools.ksp.common.impl.KSNameImpl +import com.google.devtools.ksp.common.lazyMemoizedSequence import com.google.devtools.ksp.impl.ResolverAAImpl import com.google.devtools.ksp.impl.recordLookupForPropertyOrMethod import com.google.devtools.ksp.impl.recordLookupWithSupertypes @@ -146,8 +147,8 @@ class KSFunctionDeclarationImpl private constructor(internal val ktFunctionSymbo return visitor.visitFunctionDeclaration(this, data) } - override val declarations: Sequence by lazy { - val psi = ktFunctionSymbol.psi as? KtFunction ?: return@lazy emptySequence() + override val declarations: Sequence by lazyMemoizedSequence { + val psi = ktFunctionSymbol.psi as? KtFunction ?: return@lazyMemoizedSequence emptySequence() if (!psi.hasBlockBody()) { emptySequence() } else { @@ -178,13 +179,12 @@ class KSFunctionDeclarationImpl private constructor(internal val ktFunctionSymbo ) } - override val annotations: Sequence by lazy { - if (isSyntheticConstructor()) { + override val annotations: Sequence + get() = if (isSyntheticConstructor()) { emptySequence() } else { super.annotations } - } override fun toString(): String { // TODO: fix origin for implicit Java constructor in AA diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyAccessorImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyAccessorImpl.kt index 0edd57cdcf..5a8be449c1 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyAccessorImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyAccessorImpl.kt @@ -18,6 +18,7 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.common.KSObjectCache +import com.google.devtools.ksp.common.lazyMemoizedSequence import com.google.devtools.ksp.impl.symbol.kotlin.resolved.KSAnnotationResolvedImpl import com.google.devtools.ksp.impl.symbol.kotlin.resolved.KSTypeReferenceResolvedImpl import com.google.devtools.ksp.impl.symbol.util.toKSModifiers @@ -37,7 +38,7 @@ abstract class KSPropertyAccessorImpl( override val receiver: KSPropertyDeclaration ) : KSPropertyAccessor, Deferrable { - override val annotations: Sequence by lazy { + override val annotations: Sequence by lazyMemoizedSequence { // (ktPropertyAccessorSymbol.psi as? KtPropertyAccessor)?.annotations(ktPropertyAccessorSymbol, this) ?: ktPropertyAccessorSymbol.annotations.asSequence() .filter { it.useSiteTarget != AnnotationUseSiteTarget.SETTER_PARAMETER } @@ -45,7 +46,7 @@ abstract class KSPropertyAccessorImpl( .plus(findAnnotationFromUseSiteTarget()) } - internal val originalAnnotations: Sequence by lazy { + internal val originalAnnotations: Sequence by lazyMemoizedSequence { // (ktPropertyAccessorSymbol.psi as? KtPropertyAccessor)?.annotations(ktPropertyAccessorSymbol, this) ?: ktPropertyAccessorSymbol.annotations(this) } @@ -84,8 +85,8 @@ abstract class KSPropertyAccessorImpl( override val parent: KSNode? get() = ktPropertyAccessorSymbol.getContainingKSSymbol() - override val declarations: Sequence by lazy { - val psi = ktPropertyAccessorSymbol.psi as? KtPropertyAccessor ?: return@lazy emptySequence() + override val declarations: Sequence by lazyMemoizedSequence { + val psi = ktPropertyAccessorSymbol.psi as? KtPropertyAccessor ?: return@lazyMemoizedSequence emptySequence() if (!psi.hasBlockBody()) { emptySequence() } else { diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationImpl.kt index f0a58865e8..5cab393671 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationImpl.kt @@ -22,6 +22,7 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.closestClassDeclaration import com.google.devtools.ksp.common.KSObjectCache import com.google.devtools.ksp.common.impl.KSNameImpl +import com.google.devtools.ksp.common.lazyMemoizedSequence import com.google.devtools.ksp.impl.ResolverAAImpl import com.google.devtools.ksp.impl.recordLookupForPropertyOrMethod import com.google.devtools.ksp.impl.recordLookupWithSupertypes @@ -58,27 +59,19 @@ class KSPropertyDeclarationImpl private constructor(internal val ktPropertySymbo override val originalAnnotations: Sequence get() = annotations - override val annotations: Sequence by lazy { + override val annotations: Sequence by lazyMemoizedSequence { ktPropertySymbol.annotations.asSequence() .filter { !it.isUseSiteTargetAnnotation() } .map { KSAnnotationResolvedImpl.getCached(it, this) } .plus( if (ktPropertySymbol.isFromPrimaryConstructor) { - (parentDeclaration as? KSClassDeclaration)?.primaryConstructor?.parameters - ?.singleOrNull { it.name == simpleName }?.annotations ?: emptySequence() + (parentDeclaration as? KSClassDeclaration)?.primaryConstructor?.parameters?.singleOrNull { + it.name == simpleName + }?.annotations?.filter { it.isValidOnProperty() } ?: emptySequence() } else { emptySequence() } - ).filterNot { valueParameterAnnotation -> - valueParameterAnnotation.annotationType.resolve().declaration.annotations.any { metaAnnotation -> - metaAnnotation.annotationType.resolve().declaration.qualifiedName - ?.asString() == "kotlin.annotation.Target" && - (metaAnnotation.arguments.singleOrNull()?.value as? ArrayList<*>)?.any { - (it as? KSClassDeclaration)?.qualifiedName - ?.asString() == "kotlin.annotation.AnnotationTarget.VALUE_PARAMETER" - } ?: false - } - }.plus( + ).plus( // TODO: optimize for psi ktPropertySymbol.backingFieldSymbol?.annotations ?.map { KSAnnotationResolvedImpl.getCached(it, this@KSPropertyDeclarationImpl) } ?: emptyList() @@ -203,6 +196,7 @@ internal fun KaAnnotation.isUseSiteTargetAnnotation(): Boolean { it == AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER } ?: false } + internal fun KtAnnotationEntry.isUseSiteTargetAnnotation(): Boolean { return this.useSiteTarget?.getAnnotationUseSiteTarget()?.let { it == AnnotationUseSiteTarget.PROPERTY_GETTER || @@ -212,6 +206,7 @@ internal fun KtAnnotationEntry.isUseSiteTargetAnnotation(): Boolean { it == AnnotationUseSiteTarget.FIELD } ?: false } + internal fun KaPropertySymbol.toModifiers(): Set { val result = mutableSetOf() if (visibility != KaSymbolVisibility.PACKAGE_PRIVATE) { @@ -239,3 +234,11 @@ internal fun KaPropertySymbol.toModifiers(): Set { } return result } + +internal fun KSAnnotation.isValidOnProperty(): Boolean = + annotationType.resolve().declaration.annotations.none { metaAnnotation -> + metaAnnotation.annotationType.resolve().declaration.qualifiedName?.asString() == "kotlin.annotation.Target" && + (metaAnnotation.arguments.singleOrNull()?.value as? ArrayList<*>)?.none { + (it as? KSClassDeclaration)?.qualifiedName?.asString() == "kotlin.annotation.AnnotationTarget.PROPERTY" + } ?: false + } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeImpl.kt index 84b985354d..a3444b9b3b 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeImpl.kt @@ -17,7 +17,7 @@ package com.google.devtools.ksp.impl.symbol.kotlin -import com.google.devtools.ksp.common.IdKeyPair +import com.google.devtools.ksp.common.IdKey import com.google.devtools.ksp.common.KSObjectCache import com.google.devtools.ksp.common.errorTypeOnInconsistentArguments import com.google.devtools.ksp.impl.ResolverAAImpl @@ -31,14 +31,13 @@ import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.symbol.KSTypeArgument import com.google.devtools.ksp.symbol.Nullability import org.jetbrains.kotlin.analysis.api.KaImplementationDetail -import org.jetbrains.kotlin.analysis.api.annotations.KaAnnotationList import org.jetbrains.kotlin.analysis.api.impl.base.types.KaBaseStarTypeProjection import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.api.types.* class KSTypeImpl private constructor(internal val type: KaType) : KSType { - companion object : KSObjectCache, KSTypeImpl>() { - fun getCached(type: KaType): KSTypeImpl = cache.getOrPut(IdKeyPair(type, type.annotations)) { + companion object : KSObjectCache, KSTypeImpl>() { + fun getCached(type: KaType): KSTypeImpl = cache.getOrPut(IdKey(type)) { KSTypeImpl(type) } } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeReferenceImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeReferenceImpl.kt index 6eebc92e07..588bc1ba4f 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeReferenceImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeReferenceImpl.kt @@ -18,6 +18,7 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.common.IdKeyPair import com.google.devtools.ksp.common.KSObjectCache +import com.google.devtools.ksp.common.lazyMemoizedSequence import com.google.devtools.ksp.impl.recordLookup import com.google.devtools.ksp.impl.symbol.util.toKSModifiers import com.google.devtools.ksp.symbol.KSAnnotation @@ -76,7 +77,7 @@ class KSTypeReferenceImpl( return KSTypeImpl.getCached(ktType) } - override val annotations: Sequence by lazy { + override val annotations: Sequence by lazyMemoizedSequence { val innerAnnotations = mutableListOf>() visitNullableType { innerAnnotations.add(it.annotationEntries.asSequence()) diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueArgumentImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueArgumentImpl.kt index ed72a9930d..0be29b14ce 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueArgumentImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueArgumentImpl.kt @@ -40,7 +40,9 @@ class KSValueArgumentImpl private constructor( override val isSpread: Boolean = false - override val value: Any? = namedAnnotationValue.expression.toValue() + override val value: Any? by lazy { + namedAnnotationValue.expression.toValue() + } override val annotations: Sequence = emptySequence() diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueParameterImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueParameterImpl.kt index 53a318d7ed..a374d74477 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueParameterImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueParameterImpl.kt @@ -20,16 +20,16 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.common.KSObjectCache import com.google.devtools.ksp.common.impl.KSNameImpl +import com.google.devtools.ksp.common.lazyMemoizedSequence import com.google.devtools.ksp.impl.symbol.kotlin.resolved.KSTypeReferenceResolvedImpl import com.google.devtools.ksp.symbol.* -import org.jetbrains.kotlin.analysis.api.fir.symbols.KaFirValueParameterSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KaClassSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KaConstructorSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KaPropertySymbol +import org.jetbrains.kotlin.analysis.api.symbols.KaSymbolOrigin import org.jetbrains.kotlin.analysis.api.symbols.KaValueParameterSymbol import org.jetbrains.kotlin.analysis.api.types.abbreviationOrSelf -import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack -import org.jetbrains.kotlin.fir.java.declarations.FirJavaValueParameter -import org.jetbrains.kotlin.fir.java.resolveIfJavaType import org.jetbrains.kotlin.fir.symbols.SymbolInternals -import org.jetbrains.kotlin.psi.KtParameter class KSValueParameterImpl private constructor( private val ktValueParameterSymbol: KaValueParameterSymbol, @@ -50,20 +50,14 @@ class KSValueParameterImpl private constructor( @OptIn(SymbolInternals::class) override val type: KSTypeReference by lazy { - // FIXME: temporary workaround before upstream fixes java type refs. - if (origin == Origin.JAVA || origin == Origin.JAVA_LIB) { - ((ktValueParameterSymbol as KaFirValueParameterSymbol).firSymbol.fir as? FirJavaValueParameter)?.let { - // can't get containing class for FirJavaValueParameter, using empty stack for now. - it.returnTypeRef = - it.returnTypeRef.resolveIfJavaType(it.moduleData.session, JavaTypeParameterStack.EMPTY, null) - } - } - (ktValueParameterSymbol.psiIfSource() as? KtParameter)?.typeReference - ?.let { KSTypeReferenceImpl.getCached(it, this) } - ?: KSTypeReferenceResolvedImpl.getCached( - ktValueParameterSymbol.returnType.abbreviationOrSelf, - this@KSValueParameterImpl - ) + // TODO: avoid eager resolution by using PSI. + // KaFirValueParameterSymbol extracts and returns the element type of a vararg. + // That logic needs to be replicated if we resolve the PSI via + // analyze { KtTypeReference.type }. + KSTypeReferenceResolvedImpl.getCached( + ktValueParameterSymbol.returnType.abbreviationOrSelf, + this@KSValueParameterImpl + ) } override val isVararg: Boolean by lazy { @@ -76,17 +70,32 @@ class KSValueParameterImpl private constructor( override val isCrossInline: Boolean get() = ktValueParameterSymbol.isCrossinline + private val KaValueParameterSymbol.primaryConstructorProperty: KaPropertySymbol? by lazy { + when (ktValueParameterSymbol.origin) { + // ktValueParameterSymbol.generatedPrimaryConstructorProperty is always null in libraries. + // TODO: fix in AA + KaSymbolOrigin.LIBRARY, KaSymbolOrigin.JAVA_LIBRARY -> analyze { + val cstr = ktValueParameterSymbol.containingDeclaration as? KaConstructorSymbol + val cls = cstr?.containingDeclaration as? KaClassSymbol + cls?.declaredMemberScope?.declarations?.filterIsInstance() + ?.firstOrNull { it.name == ktValueParameterSymbol.name } + } + + else -> ktValueParameterSymbol.generatedPrimaryConstructorProperty + } + } + override val isVal: Boolean - get() = (ktValueParameterSymbol.psi as? KtParameter)?.let { it.hasValOrVar() && !it.isMutable } ?: false + get() = ktValueParameterSymbol.primaryConstructorProperty?.isVal == true override val isVar: Boolean - get() = (ktValueParameterSymbol.psi as? KtParameter)?.let { it.hasValOrVar() && it.isMutable } ?: false + get() = ktValueParameterSymbol.primaryConstructorProperty?.isVal == false override val hasDefault: Boolean by lazy { ktValueParameterSymbol.hasDefaultValue } - override val annotations: Sequence by lazy { + override val annotations: Sequence by lazyMemoizedSequence { ktValueParameterSymbol.annotations(this).plus(findAnnotationFromUseSiteTarget()) } override val origin: Origin by lazy { diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/resolved/KSTypeArgumentResolvedImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/resolved/KSTypeArgumentResolvedImpl.kt index d5b240957f..b2bb1a32c5 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/resolved/KSTypeArgumentResolvedImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/resolved/KSTypeArgumentResolvedImpl.kt @@ -19,6 +19,7 @@ package com.google.devtools.ksp.impl.symbol.kotlin.resolved import com.google.devtools.ksp.common.IdKeyPair import com.google.devtools.ksp.common.KSObjectCache +import com.google.devtools.ksp.common.lazyMemoizedSequence import com.google.devtools.ksp.impl.symbol.kotlin.Deferrable import com.google.devtools.ksp.impl.symbol.kotlin.Restorable import com.google.devtools.ksp.impl.symbol.kotlin.annotations @@ -59,7 +60,7 @@ class KSTypeArgumentResolvedImpl private constructor( kaType?.let { KSTypeReferenceResolvedImpl.getCached(it, this@KSTypeArgumentResolvedImpl) } } - override val annotations: Sequence by lazy { + override val annotations: Sequence by lazyMemoizedSequence { kaType?.annotations(this) ?: emptySequence() } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/resolved/KSTypeReferenceResolvedImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/resolved/KSTypeReferenceResolvedImpl.kt index cfca2e837a..6f01f8fd94 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/resolved/KSTypeReferenceResolvedImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/resolved/KSTypeReferenceResolvedImpl.kt @@ -19,6 +19,7 @@ package com.google.devtools.ksp.impl.symbol.kotlin.resolved import com.google.devtools.ksp.common.IdKeyTriple import com.google.devtools.ksp.common.KSObjectCache +import com.google.devtools.ksp.common.lazyMemoizedSequence import com.google.devtools.ksp.impl.recordLookup import com.google.devtools.ksp.impl.symbol.kotlin.Deferrable import com.google.devtools.ksp.impl.symbol.kotlin.KSClassDeclarationImpl @@ -71,7 +72,7 @@ class KSTypeReferenceResolvedImpl private constructor( return KSTypeImpl.getCached(ktType) } - override val annotations: Sequence by lazy { + override val annotations: Sequence by lazyMemoizedSequence { ktType.annotations(this) + additionalAnnotations.asSequence().map { KSAnnotationResolvedImpl.getCached(it, this) } } @@ -115,7 +116,7 @@ class KSTypeReferenceResolvedImpl private constructor( } override fun toString(): String { - return ktType.render() + return ktType.abbreviationOrSelf.render() } override fun defer(): Restorable? { diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/util.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/util.kt index cf45dfd07e..9e84125012 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/util.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/util.kt @@ -21,7 +21,6 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.ExceptionMessage import com.google.devtools.ksp.common.impl.KSNameImpl -import com.google.devtools.ksp.common.memoized import com.google.devtools.ksp.impl.KSPCoreEnvironment import com.google.devtools.ksp.impl.ResolverAAImpl import com.google.devtools.ksp.impl.symbol.kotlin.resolved.KSAnnotationResolvedImpl @@ -264,7 +263,7 @@ internal fun KaDeclarationContainerSymbol.declarations(): Sequence KSPropertyDeclarationJavaImpl.getCached(symbol) else -> throw IllegalStateException() } - }.memoized() + } } } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalJavaFileManager.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalJavaFileManager.kt index e8d5d08066..4c87b137ed 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalJavaFileManager.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalJavaFileManager.kt @@ -38,7 +38,7 @@ class IncrementalJavaFileManager(val environment: KotlinCoreProjectEnvironment) val javaModuleGraph = JavaModuleGraph(javaModuleFinder) val allSourceFileRoots = sourceFiles.map { JavaRoot(it.virtualFile, JavaRoot.RootType.SOURCE) } val jdkRoots = getDefaultJdkModuleRoots(javaModuleFinder, javaModuleGraph) - val libraryRoots = StandaloneProjectFactory.getAllBinaryRoots(modules, environment) + val libraryRoots = StandaloneProjectFactory.getAllBinaryRoots(modules, environment.environment) val rootsWithSingleJavaFileRoots = buildList { addAll(libraryRoots) @@ -87,7 +87,7 @@ class IncrementalJavaFileManager(val environment: KotlinCoreProjectEnvironment) rootsIndex, packagePartProviders, SingleJavaFileRootsIndex(singleJavaFileRoots), - true + true, null ) } @@ -130,7 +130,7 @@ class IncrementalJavaFileManager(val environment: KotlinCoreProjectEnvironment) rootsIndex, packagePartProviders, SingleJavaFileRootsIndex(singleJavaFileRoots), - true + true, null ) } } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinPackageProviderFactory.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinPackageProviderFactory.kt index 935a8c3db1..f81a692a52 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinPackageProviderFactory.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinPackageProviderFactory.kt @@ -1,6 +1,8 @@ package com.google.devtools.ksp.standalone +import com.intellij.openapi.Disposable import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Disposer import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analysis.api.platform.packages.KotlinCompositePackageProvider import org.jetbrains.kotlin.analysis.api.platform.packages.KotlinPackageProvider @@ -10,7 +12,7 @@ import org.jetbrains.kotlin.psi.KtFile class IncrementalKotlinPackageProviderFactory( private val project: Project, -) : KotlinPackageProviderFactory { +) : KotlinPackageProviderFactory, Disposable { private val staticFactories: MutableList = mutableListOf() override fun createPackageProvider(searchScope: GlobalSearchScope): KotlinPackageProvider { @@ -20,6 +22,10 @@ class IncrementalKotlinPackageProviderFactory( fun update(files: Collection) { val staticFactory = KotlinStandalonePackageProviderFactory(project, files) + Disposer.register(this, staticFactory) staticFactories.add(staticFactory) } + + override fun dispose() { + } } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspLibraryModuleBuilder.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspLibraryModuleBuilder.kt index 862e9a7d0c..d01f8fb875 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspLibraryModuleBuilder.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspLibraryModuleBuilder.kt @@ -18,42 +18,58 @@ @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") package com.google.devtools.ksp.standalone -import com.intellij.psi.search.ProjectScope +import com.intellij.core.CoreApplicationEnvironment +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analysis.api.KaExperimentalApi +import org.jetbrains.kotlin.analysis.api.KaImplementationDetail +import org.jetbrains.kotlin.analysis.api.impl.base.util.LibraryUtils import org.jetbrains.kotlin.analysis.api.projectStructure.KaLibraryModule import org.jetbrains.kotlin.analysis.api.projectStructure.KaLibrarySourceModule +import org.jetbrains.kotlin.analysis.api.standalone.base.projectStructure.StandaloneProjectFactory import org.jetbrains.kotlin.analysis.project.structure.builder.KtBinaryModuleBuilder import org.jetbrains.kotlin.analysis.project.structure.builder.KtModuleBuilderDsl import org.jetbrains.kotlin.analysis.project.structure.builder.KtModuleProviderBuilder import org.jetbrains.kotlin.analysis.project.structure.impl.KaLibraryModuleImpl -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment +import java.nio.file.Path import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @KtModuleBuilderDsl -class KspLibraryModuleBuilder( - private val kotlinCoreProjectEnvironment: KotlinCoreProjectEnvironment +open class KspLibraryModuleBuilder( + private val coreApplicationEnvironment: CoreApplicationEnvironment, + private val project: Project, ) : KtBinaryModuleBuilder() { public lateinit var libraryName: String public var librarySources: KaLibrarySourceModule? = null + override fun build(): KaLibraryModule = build(isSdk = false) + @OptIn(KaExperimentalApi::class) - override fun build(): KaLibraryModule { + fun build(isSdk: Boolean): KaLibraryModule { val binaryRoots = getBinaryRoots() - val contentScope = ProjectScope.getLibrariesScope(kotlinCoreProjectEnvironment.project) + val binaryVirtualFiles = getBinaryVirtualFiles() + val contentScope = LibraryRootsSearchScope( + StandaloneProjectFactory.getVirtualFilesForLibraryRoots( + binaryRoots, + coreApplicationEnvironment, + ) + binaryVirtualFiles + ) return KaLibraryModuleImpl( directRegularDependencies, directDependsOnDependencies, directFriendDependencies, contentScope, platform, - kotlinCoreProjectEnvironment.project, + project, binaryRoots, - emptyList(), + binaryVirtualFiles, libraryName, librarySources, - false + isSdk ) } } @@ -63,5 +79,68 @@ inline fun KtModuleProviderBuilder.buildKspLibraryModule(init: KspLibraryModuleB contract { callsInPlace(init, InvocationKind.EXACTLY_ONCE) } - return KspLibraryModuleBuilder(kotlinCoreProjectEnvironment).apply(init).build() + return KspLibraryModuleBuilder(coreApplicationEnvironment, project).apply(init).build() +} + +internal class SimpleTrie(paths: List) { + class TrieNode { + var isTerminal: Boolean = false + } + + val root = TrieNode() + + private val m = mutableMapOf, TrieNode>().apply { + paths.forEach { path -> + var p = root + for (d in path.trim('/').split('/')) { + p = getOrPut(Pair(p, d)) { TrieNode() } + } + p.isTerminal = true + } + } + + fun contains(s: String): Boolean { + var p = root + for (d in s.trim('/').split('/')) { + p = m.get(Pair(p, d))?.also { + if (it.isTerminal) + return true + } ?: return false + } + return false + } +} + +internal class LibraryRootsSearchScope(roots: List) : GlobalSearchScope() { + val trie: SimpleTrie = SimpleTrie(roots.map { it.path }) + + override fun contains(file: VirtualFile): Boolean { + return trie.contains(file.path) + } + + override fun isSearchInModuleContent(aModule: Module): Boolean = false + + override fun isSearchInLibraries(): Boolean = true +} + +@KtModuleBuilderDsl +public class KspSdkModuleBuilder( + coreApplicationEnvironment: CoreApplicationEnvironment, + project: Project, +) : KspLibraryModuleBuilder(coreApplicationEnvironment, project) { + @OptIn(KaImplementationDetail::class) + public fun addBinaryRootsFromJdkHome(jdkHome: Path, isJre: Boolean) { + val jdkRoots = LibraryUtils.findClassesFromJdkHome(jdkHome, isJre) + addBinaryRoots(jdkRoots) + } + + override fun build(): KaLibraryModule = build(isSdk = true) +} + +@OptIn(ExperimentalContracts::class) +public inline fun KtModuleProviderBuilder.buildKspSdkModule(init: KspSdkModuleBuilder.() -> Unit): KaLibraryModule { + contract { + callsInPlace(init, InvocationKind.EXACTLY_ONCE) + } + return KspSdkModuleBuilder(coreApplicationEnvironment, project).apply(init).build() } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspSourceModuleBuilder.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspSourceModuleBuilder.kt index 77d1c4c1b7..a79067f677 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspSourceModuleBuilder.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspSourceModuleBuilder.kt @@ -18,6 +18,7 @@ @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") package com.google.devtools.ksp.standalone +import com.intellij.core.CoreApplicationEnvironment import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile @@ -28,7 +29,6 @@ import org.jetbrains.kotlin.analysis.project.structure.builder.KtModuleBuilder import org.jetbrains.kotlin.analysis.project.structure.builder.KtModuleBuilderDsl import org.jetbrains.kotlin.analysis.project.structure.builder.KtModuleProviderBuilder import org.jetbrains.kotlin.analysis.project.structure.impl.KaSourceModuleImpl -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.LanguageVersion import org.jetbrains.kotlin.config.LanguageVersionSettings @@ -40,7 +40,8 @@ import kotlin.contracts.contract @KtModuleBuilderDsl class KspModuleBuilder( - private val kotlinCoreProjectEnvironment: KotlinCoreProjectEnvironment, + private val coreApplicationEnvironment: CoreApplicationEnvironment, + private val project: Project ) : KtModuleBuilder() { public lateinit var moduleName: String public var languageVersionSettings: LanguageVersionSettings = @@ -58,16 +59,16 @@ class KspModuleBuilder( override fun build(): KaSourceModule { val virtualFiles = collectVirtualFilesByRoots() - val psiManager = PsiManager.getInstance(kotlinCoreProjectEnvironment.project) + val psiManager = PsiManager.getInstance(project) val psiFiles = virtualFiles.mapNotNull { psiManager.findFile(it) } - val contentScope = IncrementalGlobalSearchScope(kotlinCoreProjectEnvironment.project, virtualFiles) + val contentScope = IncrementalGlobalSearchScope(project, virtualFiles) return KaSourceModuleImpl( directRegularDependencies, directDependsOnDependencies, directFriendDependencies, contentScope, platform, - kotlinCoreProjectEnvironment.project, + project, moduleName, languageVersionSettings, psiFiles, @@ -77,7 +78,7 @@ class KspModuleBuilder( val analyzableExtensions = setOf("kt", "java", "kts") private fun collectVirtualFilesByRoots(): Set { - val localFileSystem = kotlinCoreProjectEnvironment.environment.localFileSystem + val localFileSystem = coreApplicationEnvironment.localFileSystem return buildSet { for (root in sourceRoots) { val files = root.toFile().walk().filter { @@ -115,5 +116,5 @@ public inline fun KtModuleProviderBuilder.buildKspSourceModule( contract { callsInPlace(init, InvocationKind.EXACTLY_ONCE) } - return KspModuleBuilder(kotlinCoreProjectEnvironment).apply(init).build() + return KspModuleBuilder(coreApplicationEnvironment, project).apply(init).build() } diff --git a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/ValueParameterProcessor.kt b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/ValueParameterProcessor.kt new file mode 100644 index 0000000000..315056fe40 --- /dev/null +++ b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/ValueParameterProcessor.kt @@ -0,0 +1,23 @@ +package com.google.devtools.ksp.processor + +import com.google.devtools.ksp.getClassDeclarationByName +import com.google.devtools.ksp.processing.Resolver +import com.google.devtools.ksp.symbol.KSAnnotated + +class ValueParameterProcessor : AbstractTestProcessor() { + val results = mutableListOf() + + override fun toResult(): List { + return results + } + + override fun process(resolver: Resolver): List { + for (clsName in listOf("MyClassSrc", "MyClassLib")) { + val clsDecl = resolver.getClassDeclarationByName(clsName)!! + clsDecl.primaryConstructor!!.parameters.sortedBy { it.name!!.asString() }.forEach { + results.add("$clsName.${it.name!!.asString()}: isVal: ${it.isVal}, isVar: ${it.isVar}") + } + } + return emptyList() + } +} diff --git a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt index 84ed95c61a..c272082993 100644 --- a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt +++ b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt @@ -88,6 +88,12 @@ class KSPAATest : AbstractKSPAATest() { runTest("../kotlin-analysis-api/testData/annotationsRepeatable.kt") } + @TestMetadata("annotationTargets.kt") + @Test + fun testAnnotationTargets() { + runTest("../test-utils/testData/api/annotationTargets.kt") + } + @TestMetadata("annotationWithArbitraryClassValue.kt") @Test fun testAnnotationWithArbitraryClassValue() { @@ -678,6 +684,12 @@ class KSPAATest : AbstractKSPAATest() { runTest("../kotlin-analysis-api/testData/typeParameterVariance.kt") } + @TestMetadata("valueParameter.kt") + @Test + fun testValueParameter() { + runTest("../kotlin-analysis-api/testData/valueParameter.kt") + } + @TestMetadata("varianceTypeCheck.kt") @Test fun testVarianceTypeCheck() { @@ -690,6 +702,12 @@ class KSPAATest : AbstractKSPAATest() { runTest("../test-utils/testData/api/validateTypes.kt") } + @TestMetadata("vararg.kt") + @Test + fun testVararg() { + runTest("../test-utils/testData/api/vararg.kt") + } + @TestMetadata("visibilities.kt") @Test fun testVisibilities() { diff --git a/kotlin-analysis-api/testData/annotationWithDefault.kt b/kotlin-analysis-api/testData/annotationWithDefault.kt index aed1f0e5cd..5d4d6624c8 100644 --- a/kotlin-analysis-api/testData/annotationWithDefault.kt +++ b/kotlin-analysis-api/testData/annotationWithDefault.kt @@ -22,8 +22,8 @@ // JavaAnnotation2 -> y:y-kotlin:false,x:x-kotlin:false,z:z-default:true // KotlinAnnotation2 -> y:y-kotlin:false,x:x-kotlin:false,z:z-default:true,kotlinEnumVal:KotlinEnum.VALUE_1:true // KotlinAnnotationLib -> a:debugLibKt:false,b:defaultInLib:true,kClassValue:OtherKotlinAnnotation:true,topLevelProp:bar:true -// JavaAnnotationWithDefaults -> stringVal:foo:true,stringArrayVal:[x, y]:true,typeVal:HashMap<(Any..Any?), (Any..Any?)>:true,typeArrayVal:[LinkedHashMap<(Any..Any?), (Any..Any?)>]:true,intVal:3:true,intArrayVal:[1, 3, 5]:true,enumVal:JavaEnum.DEFAULT:true,enumArrayVal:[JavaEnum.VAL1, JavaEnum.VAL2]:true,localEnumVal:LocalEnum.LOCAL1:true,otherAnnotationVal:@OtherAnnotation:true,otherAnnotationArrayVal:[@OtherAnnotation]:true,kotlinAnnotationLibVal:@OtherKotlinAnnotation:true -// KotlinAnnotationWithDefaults -> stringVal:foo:false,stringArrayVal:[x, y]:true,typeVal:HashMap<(Any..Any?), (Any..Any?)>:true,typeArrayVal:[LinkedHashMap<(Any..Any?), (Any..Any?)>]:true,intVal:3:true,intArrayVal:[1, 3, 5]:true,enumVal:JavaEnum.DEFAULT:true,enumArrayVal:[JavaEnum.VAL1, JavaEnum.VAL2]:true,otherAnnotationVal:@OtherAnnotation:true,otherAnnotationArrayVal:[@OtherAnnotation]:true,kotlinAnnotationLibVal:@OtherKotlinAnnotation:true +// JavaAnnotationWithDefaults -> stringVal:foo:true,stringArrayVal:[x, y]:true,typeVal:HashMap<*, *>:true,typeArrayVal:[LinkedHashMap<*, *>]:true,intVal:3:true,intArrayVal:[1, 3, 5]:true,enumVal:JavaEnum.DEFAULT:true,enumArrayVal:[JavaEnum.VAL1, JavaEnum.VAL2]:true,localEnumVal:LocalEnum.LOCAL1:true,otherAnnotationVal:@OtherAnnotation:true,otherAnnotationArrayVal:[@OtherAnnotation]:true,kotlinAnnotationLibVal:@OtherKotlinAnnotation:true +// KotlinAnnotationWithDefaults -> stringVal:foo:false,stringArrayVal:[x, y]:true,typeVal:HashMap<*, *>:true,typeArrayVal:[LinkedHashMap<*, *>]:true,intVal:3:true,intArrayVal:[1, 3, 5]:true,enumVal:JavaEnum.DEFAULT:true,enumArrayVal:[JavaEnum.VAL1, JavaEnum.VAL2]:true,otherAnnotationVal:@OtherAnnotation:true,otherAnnotationArrayVal:[@OtherAnnotation]:true,kotlinAnnotationLibVal:@OtherKotlinAnnotation:true // KotlinAnnotation -> a:debugKt:false,b:default:true,kClassValue:Array>:true,topLevelProp:foo:true,companionProp:companion:true // JavaAnnotation -> debug:debugJava2:false,withDefaultValue:OK:true,nested:@Nested:true // JavaAnnotation2 -> y:y-java:false,x:x-java:false,z:z-default:true diff --git a/kotlin-analysis-api/testData/annotationWithDefaultValues.kt b/kotlin-analysis-api/testData/annotationWithDefaultValues.kt index 5dfabedbe3..0f76a9aacf 100644 --- a/kotlin-analysis-api/testData/annotationWithDefaultValues.kt +++ b/kotlin-analysis-api/testData/annotationWithDefaultValues.kt @@ -22,8 +22,8 @@ // JavaAnnotation2 -> x:x-default,y:y-default,z:z-default // KotlinAnnotation2 -> y:y-default,z:z-default,kotlinEnumVal:KotlinEnum.VALUE_1 // KotlinAnnotationLib -> b:defaultInLib,kClassValue:OtherKotlinAnnotation,topLevelProp:bar -// JavaAnnotationWithDefaults -> stringVal:foo,stringArrayVal:[x, y],typeVal:HashMap<(Any..Any?), (Any..Any?)>,typeArrayVal:[LinkedHashMap<(Any..Any?), (Any..Any?)>],intVal:3,intArrayVal:[1, 3, 5],enumVal:JavaEnum.DEFAULT,enumArrayVal:[JavaEnum.VAL1, JavaEnum.VAL2],localEnumVal:LocalEnum.LOCAL1,otherAnnotationVal:@OtherAnnotation,otherAnnotationArrayVal:[@OtherAnnotation],kotlinAnnotationLibVal:@OtherKotlinAnnotation -// KotlinAnnotationWithDefaults -> stringVal:foo,stringArrayVal:[x, y],typeVal:HashMap<(Any..Any?), (Any..Any?)>,typeArrayVal:[LinkedHashMap<(Any..Any?), (Any..Any?)>],intVal:3,intArrayVal:[1, 3, 5],enumVal:JavaEnum.DEFAULT,enumArrayVal:[JavaEnum.VAL1, JavaEnum.VAL2],otherAnnotationVal:@OtherAnnotation,otherAnnotationArrayVal:[@OtherAnnotation],kotlinAnnotationLibVal:@OtherKotlinAnnotation +// JavaAnnotationWithDefaults -> stringVal:foo,stringArrayVal:[x, y],typeVal:HashMap<*, *>,typeArrayVal:[LinkedHashMap<*, *>],intVal:3,intArrayVal:[1, 3, 5],enumVal:JavaEnum.DEFAULT,enumArrayVal:[JavaEnum.VAL1, JavaEnum.VAL2],localEnumVal:LocalEnum.LOCAL1,otherAnnotationVal:@OtherAnnotation,otherAnnotationArrayVal:[@OtherAnnotation],kotlinAnnotationLibVal:@OtherKotlinAnnotation +// KotlinAnnotationWithDefaults -> stringVal:foo,stringArrayVal:[x, y],typeVal:HashMap<*, *>,typeArrayVal:[LinkedHashMap<*, *>],intVal:3,intArrayVal:[1, 3, 5],enumVal:JavaEnum.DEFAULT,enumArrayVal:[JavaEnum.VAL1, JavaEnum.VAL2],otherAnnotationVal:@OtherAnnotation,otherAnnotationArrayVal:[@OtherAnnotation],kotlinAnnotationLibVal:@OtherKotlinAnnotation // KotlinAnnotation -> b:default,kClassValue:Array>,topLevelProp:foo,companionProp:companion // JavaAnnotation -> withDefaultValue:OK,stringArrayParam:[3, 5, 7],typeVal:HashMap<*, *>,nested:@Nested // JavaAnnotation2 -> x:x-default,y:y-default,z:z-default diff --git a/kotlin-analysis-api/testData/equivalentJavaWildcards.kt b/kotlin-analysis-api/testData/equivalentJavaWildcards.kt index 793e423850..267414f8a7 100644 --- a/kotlin-analysis-api/testData/equivalentJavaWildcards.kt +++ b/kotlin-analysis-api/testData/equivalentJavaWildcards.kt @@ -81,7 +81,7 @@ // - COVARIANT X : X -> X // v7 : B<*> -> B // v8 : B> -> B> -// - INVARIANT A : A -> A +// - INVARIANT A : A -> A // - - INVARIANT X : X -> X // - - COVARIANT Y : Y -> Y // foo : Unit -> Unit diff --git a/kotlin-analysis-api/testData/locations.kt b/kotlin-analysis-api/testData/locations.kt index 20bc8af3fe..76bf6608fa 100644 --- a/kotlin-analysis-api/testData/locations.kt +++ b/kotlin-analysis-api/testData/locations.kt @@ -24,7 +24,6 @@ // T:J.java:73 // T:J.java:73 // T:K.kt:54 -// T:K.kt:54 // f1:J.java:77 // f1:K.kt:61 // p1:K.kt:56 @@ -39,6 +38,7 @@ // v3:J.java:82 // END + // FILE: Location.kt annotation class Location diff --git a/kotlin-analysis-api/testData/valueParameter.kt b/kotlin-analysis-api/testData/valueParameter.kt new file mode 100644 index 0000000000..1f62f67a3f --- /dev/null +++ b/kotlin-analysis-api/testData/valueParameter.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2025 Google LLC + * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors. + * + * 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. + */ + +// TEST PROCESSOR: ValueParameterProcessor +// EXPECTED: +// MyClassSrc.field: isVal: false, isVar: false +// MyClassSrc.valField: isVal: true, isVar: false +// MyClassSrc.varField: isVal: false, isVar: true +// MyClassLib.field: isVal: false, isVar: false +// MyClassLib.valField: isVal: true, isVar: false +// MyClassLib.varField: isVal: false, isVar: true +// END + +// MODULE: lib +// FILE: lib.kt + +class MyClassLib( + field: String, + val valField: String, + var varField: String, +) + +// MODULE: main(lib) +// FILE: main.kt + +class MyClassSrc( + field: String, + val valField: String, + var varField: String, +) + diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationTargetsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationTargetsProcessor.kt new file mode 100644 index 0000000000..2d035bc3a8 --- /dev/null +++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationTargetsProcessor.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2020 Google LLC + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * + * 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 com.google.devtools.ksp.processor + +import com.google.devtools.ksp.processing.Resolver +import com.google.devtools.ksp.symbol.* + +class AnnotationTargetsProcessor : AbstractTestProcessor() { + val results = mutableListOf() + + override fun process(resolver: Resolver): List { + val myClassName = resolver.getKSNameFromString("com.example.MyClass") + val myClass: KSClassDeclaration = resolver.getClassDeclarationByName(myClassName)!! + val propForLib = myClass.getAllProperties().single { it.simpleName.asString() == "propForLib" } + val propForSrc = myClass.getAllProperties().single { it.simpleName.asString() == "propForSrc" } + results.add("$propForLib: ${propForLib.annotations.map { it.shortName.asString() }.toList()}") + results.add("$propForSrc: ${propForSrc.annotations.map { it.shortName.asString() }.toList()}") + return emptyList() + } + + override fun toResult(): List { + return results + } +} diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/VarargProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/VarargProcessor.kt new file mode 100644 index 0000000000..5554e57d98 --- /dev/null +++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/VarargProcessor.kt @@ -0,0 +1,28 @@ +package com.google.devtools.ksp.processor + +import com.google.devtools.ksp.getClassDeclarationByName +import com.google.devtools.ksp.getDeclaredFunctions +import com.google.devtools.ksp.processing.Resolver +import com.google.devtools.ksp.symbol.KSAnnotated + +class VarargProcessor : AbstractTestProcessor() { + val results = mutableListOf() + + override fun toResult(): List { + return results + } + + override fun process(resolver: Resolver): List { + for (clsName in listOf("s.K", "s.J", "l.K", "l.J")) { + val clsDecl = resolver.getClassDeclarationByName(clsName)!! + val func = clsDecl.getDeclaredFunctions().single { it.simpleName.asString() == "foo" } + val funcName = func.qualifiedName!!.asString() + val param = func.parameters.single() + val paramName = param.name!!.asString() + val paramType = param.type.resolve() + val isVararg = if (param.isVararg) "vararg " else "" + results.add("$funcName($isVararg$paramName: $paramType)") + } + return emptyList() + } +} diff --git a/test-utils/testData/api/annotationTargets.kt b/test-utils/testData/api/annotationTargets.kt new file mode 100644 index 0000000000..99ccb4e710 --- /dev/null +++ b/test-utils/testData/api/annotationTargets.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2020 Google LLC + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * + * 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. + */ + +// TEST PROCESSOR: AnnotationTargetsProcessor +// EXPECTED: +// propForLib: [MyAnnotationInLib] +// propForSrc: [MyAnnotationInSrc] +// END +// MODULE: Anno +// FILE: com/example/MyAnnotation.kt +package com.example + +@Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER) +public annotation class MyAnnotationInLib + +// MODULE: main(Anno) +// FILE: com/exampel/MyClass.kt +package com.example + +@Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER) +public annotation class MyAnnotationInSrc + +class MyClass { + @MyAnnotationInLib lateinit var propForLib: String + @MyAnnotationInSrc lateinit var propForSrc: String +} diff --git a/test-utils/testData/api/vararg.kt b/test-utils/testData/api/vararg.kt new file mode 100644 index 0000000000..385c0accea --- /dev/null +++ b/test-utils/testData/api/vararg.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2025 Google LLC + * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors. + * + * 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. + */ + +// TEST PROCESSOR: VarargProcessor +// EXPECTED: +// s.K.foo(vararg strings: String) +// s.J.foo(vararg strings: (String..String?)) +// l.K.foo(vararg strings: String) +// l.J.foo(vararg p0: (String..String?)) +// END + +// MODULE: lib +// FILE: l/K.kt +package l +class K { + fun foo(vararg strings: String) = 0 +} + +// FILE: l/J.java +package l; +public class J { + int foo(String... strings) { + return 0; + } +} + +// MODULE: main(lib) +// FILE: s/K.kt +package s +class K { + fun foo(vararg strings: String) = 0 +} + +// FILE: s/J.java +package s; +public class J { + int foo(String... strings) { + return 0; + } +} +