From 2dd0ac1cbd08ab2339fde45de08c0128811ba401 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Fri, 5 Apr 2024 16:05:11 -0700 Subject: [PATCH 01/64] set release branch to 1.0.21-release --- .github/workflows/auto-merge.yml | 4 ++-- .github/workflows/main.yml | 4 ++-- .github/workflows/nightly.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index da45ad20b4..fd5a21b5d3 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -21,7 +21,7 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - ref: 1.0.20-release + ref: 1.0.21-release - name: merge commits from main to release branch run: | @@ -109,7 +109,7 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - ref: 1.0.20-release + ref: 1.0.21-release - name: merge commits from main to release branch run: | diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3daf9f2568..f695b563d9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,9 +4,9 @@ name: CI on: push: - branches: [ main, 1.0.20-release, 1.0.19-release ] + branches: [ main, 1.0.20-release, 1.0.21-release ] pull_request: - branches: [ main, 1.0.20-release, 1.0.19-release ] + branches: [ main, 1.0.20-release, 1.0.21-release ] jobs: build-and-test: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 8c44d2755a..1389df42e0 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -7,7 +7,7 @@ jobs: strategy: fail-fast: false matrix: - branch: [ main, 1.0.19-release, 1.0.20-release ] + branch: [ main, 1.0.21-release, 1.0.20-release ] runs-on: windows-latest steps: - name: configure Pagefile From 6fe6e64c3d84c8e1a25ffb95752fb81398c54435 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Fri, 5 Apr 2024 16:40:03 -0700 Subject: [PATCH 02/64] UPDATE_KOTLIN_VERSION: 2.0.20-dev-715 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 3c3ad693c7..f3c46fa7ff 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # Copied from kotlinc org.gradle.jvmargs=-Duser.country=US -Dkotlin.daemon.jvm.options=-Xmx2200m -Dfile.encoding=UTF-8 -kotlinBaseVersion=2.0.0-dev-19480 +kotlinBaseVersion=2.0.20-dev-715 agpBaseVersion=7.2.0 intellijVersion=213.7172.25 junitVersion=4.13.1 From cf3b401c304e476344e3ff4777c3d5ed8ac68955 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Fri, 5 Apr 2024 16:40:18 -0700 Subject: [PATCH 03/64] UPDATE_AA_VERSION: 2.0.20-dev-715 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index f3c46fa7ff..37a3995c4a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ junit5Version=5.8.2 junitPlatformVersion=1.8.2 googleTruthVersion=1.1 -aaKotlinBaseVersion=2.0.0-dev-19480 +aaKotlinBaseVersion=2.0.20-dev-715 aaIntellijVersion=213.7172.25 aaGuavaVersion=29.0-jre aaAsmVersion=9.0 From c262051a05aa96ae4c8f1756554ded3f1b87d768 Mon Sep 17 00:00:00 2001 From: Zac Sweers Date: Wed, 17 Apr 2024 16:13:02 -0400 Subject: [PATCH 04/64] Implement Resolver.getModuleName API Resolves #1621 --- api/api.base | 1 + .../com/google/devtools/ksp/processing/Resolver.kt | 8 +++++++- .../devtools/ksp/processing/impl/ResolverImpl.kt | 6 +++++- .../com/google/devtools/ksp/gradle/KspAATask.kt | 4 ++-- .../com/google/devtools/ksp/test/PlaygroundIT.kt | 9 +++++++++ .../test-processor/src/main/kotlin/TestProcessor.kt | 5 +++++ .../devtools/ksp/impl/KotlinSymbolProcessing.kt | 4 +++- .../com/google/devtools/ksp/impl/ResolverAAImpl.kt | 11 ++++++++--- 8 files changed, 40 insertions(+), 8 deletions(-) diff --git a/api/api.base b/api/api.base index d5e0890062..65a9ebde82 100644 --- a/api/api.base +++ b/api/api.base @@ -170,6 +170,7 @@ package com.google.devtools.ksp.processing { method @Nullable @com.google.devtools.ksp.KspExperimental public String getJvmName(@NonNull com.google.devtools.ksp.symbol.KSFunctionDeclaration declaration); method @Nullable @com.google.devtools.ksp.KspExperimental public String getJvmName(@NonNull com.google.devtools.ksp.symbol.KSPropertyAccessor accessor); method @NonNull public com.google.devtools.ksp.symbol.KSName getKSNameFromString(@NonNull String name); + method @NonNull @com.google.devtools.ksp.KspExperimental public com.google.devtools.ksp.symbol.KSName getModuleName(); method @NonNull public kotlin.sequences.Sequence getNewFiles(); method @Nullable @com.google.devtools.ksp.KspExperimental public String getOwnerJvmClassName(@NonNull com.google.devtools.ksp.symbol.KSFunctionDeclaration declaration); method @Nullable @com.google.devtools.ksp.KspExperimental public String getOwnerJvmClassName(@NonNull com.google.devtools.ksp.symbol.KSPropertyDeclaration declaration); diff --git a/api/src/main/kotlin/com/google/devtools/ksp/processing/Resolver.kt b/api/src/main/kotlin/com/google/devtools/ksp/processing/Resolver.kt index 33d0f162b6..cdc3d899c7 100644 --- a/api/src/main/kotlin/com/google/devtools/ksp/processing/Resolver.kt +++ b/api/src/main/kotlin/com/google/devtools/ksp/processing/Resolver.kt @@ -310,12 +310,18 @@ interface Resolver { @KspExperimental fun getPackageAnnotations(packageName: String): Sequence - @KspExperimental /** * Returns name of packages with given annotation. * * @param annotationName name of the annotation to be queried. * @return a sequence of package names with corresponding annotation name. */ + @KspExperimental fun getPackagesWithAnnotation(annotationName: String): Sequence + + /** + * @return the name of the kotlin module this resolver is running on. + */ + @KspExperimental + fun getModuleName(): KSName } diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt index bff3a89699..533fb9181b 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt @@ -140,9 +140,10 @@ class ResolverImpl( private val functionAsMemberOfCache: MutableMap, KSFunction> private val propertyAsMemberOfCache: MutableMap, KSType> + private val moduleIdentifier = module.name.getNonSpecialIdentifier() private val typeMapper = KotlinTypeMapper( BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES, - module.name.getNonSpecialIdentifier(), + moduleIdentifier, KotlinTypeMapper.LANGUAGE_VERSION_SETTINGS_DEFAULT, // TODO use proper LanguageVersionSettings true ) @@ -1407,6 +1408,9 @@ class ResolverImpl( }.map { it.packageName.asString() } } + @KspExperimental + override fun getModuleName(): KSName = KSNameImpl.getCached(moduleIdentifier) + private val psiJavaFiles = allKSFiles.filterIsInstance().map { Pair(it.psi.virtualFile.path, it.psi) }.toMap() 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 bf97755051..3d73e033d6 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 @@ -163,7 +163,7 @@ abstract class KspAATask @Inject constructor( kspAATask.kspClasspath.from(kspAADepCfg) kspAATask.kspConfig.let { cfg -> cfg.processorClasspath.from(processorClasspath) - cfg.moduleName.value(kotlinCompilation.defaultSourceSet.name) + cfg.moduleName.value(project.name) val kotlinOutputDir = KspGradleSubplugin.getKspKotlinOutputDir(project, sourceSetName, target) val javaOutputDir = KspGradleSubplugin.getKspJavaOutputDir(project, sourceSetName, target) val filteredTasks = @@ -256,7 +256,7 @@ abstract class KspAATask @Inject constructor( cfg.jvmDefaultMode.value(jvmDefaultMode) val jvmTarget = project.provider { - (compilerOptions as KotlinJvmCompilerOptions).jvmTarget.get().target + compilerOptions.jvmTarget.get().target } cfg.jvmTarget.value(jvmTarget) } 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 5bb36cb844..4514d17d2d 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 @@ -381,6 +381,15 @@ class PlaygroundIT(val useKSP2: Boolean) { project.restore(buildFile.path) } + @Test + fun testModuleName() { + File(project.root, "workload/build.gradle.kts").createNewFile() + val gradleRunner = GradleRunner.create().withProjectDir(project.root) + gradleRunner.withArguments("build").build().let { result -> + Assert.assertTrue(result.output.contains("Module name is workload")) + } + } + companion object { @JvmStatic @Parameterized.Parameters(name = "KSP2={0}") diff --git a/integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/TestProcessor.kt index b9e1856428..2025a1ef49 100644 --- a/integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/TestProcessor.kt +++ b/integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/TestProcessor.kt @@ -1,3 +1,4 @@ +import com.google.devtools.ksp.KspExperimental import com.google.devtools.ksp.containingFile import com.google.devtools.ksp.processing.* import com.google.devtools.ksp.symbol.* @@ -6,6 +7,7 @@ import java.io.OutputStream class TestProcessor : SymbolProcessor { lateinit var codeGenerator: CodeGenerator lateinit var file: OutputStream + lateinit var logger: KSPLogger var invoked = false fun emit(s: String, indent: String) { @@ -18,6 +20,7 @@ class TestProcessor : SymbolProcessor { codeGenerator: CodeGenerator, logger: KSPLogger ) { + this.logger = logger logger.warn("This is a harmless warning.") this.codeGenerator = codeGenerator file = codeGenerator.createNewFile(Dependencies(false), "", "TestProcessor", "log") @@ -27,7 +30,9 @@ class TestProcessor : SymbolProcessor { javaFile.appendText("class Generated {}") } + @OptIn(KspExperimental::class) override fun process(resolver: Resolver): List { + logger.warn("Module name is ${resolver.getModuleName().asString()}") if (invoked) { return emptyList() } 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 b7b405aec3..67414a6430 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 @@ -74,6 +74,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getFirResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLibrarySymbolProviderFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLSealedInheritorsProvider import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule 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 @@ -448,7 +449,8 @@ class KotlinSymbolProcessing( val psiManager = PsiManager.getInstance(project) val providers: List = symbolProcessorProviders - ResolverAAImpl.ktModule = modules.single() + // KspModuleBuilder ensures this is always a KtSourceModule + ResolverAAImpl.ktModule = modules.single() as KtSourceModule // Initializing environments val allKSFiles = prepareAllKSFiles(kotlinCoreProjectEnvironment, modules, compilerConfiguration) 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 10c7da4df8..393e4afbd4 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 @@ -62,7 +62,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtTypeAliasSymbol import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getFirResolveSession -import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCliJavaFileManagerImpl import org.jetbrains.kotlin.fir.types.isRaw @@ -88,13 +88,13 @@ class ResolverAAImpl( ) : Resolver { companion object { val instance_prop: ThreadLocal = ThreadLocal() - private val ktModule_prop: ThreadLocal = ThreadLocal() + private val ktModule_prop: ThreadLocal = ThreadLocal() var instance get() = instance_prop.get() set(value) { instance_prop.set(value) } - var ktModule: KtModule + var ktModule: KtSourceModule get() = ktModule_prop.get() set(value) { ktModule_prop.set(value) @@ -621,6 +621,11 @@ class ResolverAAImpl( }.map { it.packageName.asString() } } + @KspExperimental + override fun getModuleName(): KSName { + return KSNameImpl.getCached((ktModule.stableModuleName ?: ktModule.moduleName).removeSurrounding("<", ">")) + } + @KspExperimental override fun mapJavaNameToKotlin(javaName: KSName): KSName? { return JavaToKotlinClassMap.mapJavaToKotlin(FqName(javaName.asString()))?.toKSName() From eddff984b586d39d3e6844768cc75d292be07feb Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Mon, 22 Apr 2024 18:09:45 -0700 Subject: [PATCH 05/64] UPDATE_AA_VERSION: 2.0.20-dev-1634 (cherry picked from commit 4601333a4c7259b6789941f43de20ee30f98a526) --- gradle.properties | 2 +- .../devtools/ksp/impl/KotlinSymbolProcessing.kt | 16 +++++++++++++--- .../impl/symbol/kotlin/KSValueParameterImpl.kt | 2 +- .../devtools/ksp/impl/symbol/kotlin/util.kt | 2 +- .../KspStandaloneDirectInheritorsProvider.kt | 3 +-- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/gradle.properties b/gradle.properties index 37a3995c4a..8b11124d2d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ junit5Version=5.8.2 junitPlatformVersion=1.8.2 googleTruthVersion=1.1 -aaKotlinBaseVersion=2.0.20-dev-715 +aaKotlinBaseVersion=2.0.20-dev-1634 aaIntellijVersion=213.7172.25 aaGuavaVersion=29.0-jre aaAsmVersion=9.0 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 67414a6430..c4deab33ad 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 @@ -164,7 +164,7 @@ class KotlinSymbolProcessing( ) val application: Application = kotlinCoreProjectEnvironment.environment.application - val project: Project = kotlinCoreProjectEnvironment.project + val project: MockProject = kotlinCoreProjectEnvironment.project val configLanguageVersionSettings = compilerConfiguration[CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS] CoreApplicationEnvironment.registerExtensionPoint( @@ -248,7 +248,6 @@ class KotlinSymbolProcessing( val libraryRoots = StandaloneProjectFactory.getAllBinaryRoots(modules, kotlinCoreProjectEnvironment) val createPackagePartProvider = StandaloneProjectFactory.createPackagePartsProvider( - project as MockProject, libraryRoots, ) registerProjectServices( @@ -665,7 +664,6 @@ private fun reinitJavaFileManager( rootsIndex, listOf( StandaloneProjectFactory.createPackagePartsProvider( - project, libraryRoots + jdkRoots, LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST) ).invoke(ProjectScope.getLibrariesScope(project)) @@ -704,8 +702,20 @@ fun String?.toKotlinVersion(): KotlinVersion { // Workaround for ShadowJar's minimize, whose configuration isn't very flexible. internal val DEAR_SHADOW_JAR_PLEASE_DO_NOT_REMOVE_THESE = listOf( + org.jetbrains.kotlin.analysis.api.impl.base.java.source.JavaElementSourceWithSmartPointerFactory::class.java, + org.jetbrains.kotlin.analysis.api.impl.base.references.HLApiReferenceProviderService::class.java, + org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSessionProvider::class.java, + org.jetbrains.kotlin.analysis.api.fir.references.ReadWriteAccessCheckerFirImpl::class.java, + org.jetbrains.kotlin.analysis.api.standalone.base.providers.KotlinStandaloneDirectInheritorsProvider::class.java, + 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.stubBased.deserialization.LLStubBasedLibrarySymbolProviderFactory::class.java, + org.jetbrains.kotlin.analysis.providers.impl.KotlinProjectMessageBusProvider::class.java, + org.jetbrains.kotlin.idea.references.KotlinFirReferenceContributor::class.java, + org.jetbrains.kotlin.light.classes.symbol.SymbolKotlinAsJavaSupport::class.java, org.jetbrains.kotlin.load.java.ErasedOverridabilityCondition::class.java, org.jetbrains.kotlin.load.java.FieldOverridabilityCondition::class.java, + org.jetbrains.kotlin.plugin.references.SimpleNameReferenceExtension::class.java, org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInsLoaderImpl::class.java, com.fasterxml.aalto.AaltoInputProperties::class.java, com.google.errorprone.annotations.CheckReturnValue::class.java, 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 6d041d61b1..696a9cf357 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 @@ -54,7 +54,7 @@ class KSValueParameterImpl private constructor( ((ktValueParameterSymbol as KtFirValueParameterSymbol).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) + it.returnTypeRef.resolveIfJavaType(it.moduleData.session, JavaTypeParameterStack.EMPTY, null) } } (ktValueParameterSymbol.psiIfSource() as? KtParameter)?.typeReference 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 8ec6ded653..5d7c2bf952 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 @@ -461,7 +461,7 @@ internal fun KtValueParameterSymbol.getDefaultValue(): KtAnnotationValue? { val symbolBuilder = it.builder val expectedTypeRef = it.firSymbol.fir.returnTypeRef val expression = defaultValue - ?.toFirExpression(firSession, JavaTypeParameterStack.EMPTY, expectedTypeRef) + ?.toFirExpression(firSession, JavaTypeParameterStack.EMPTY, expectedTypeRef, null) expression?.let { FirAnnotationValueConverter.toConstantValue(expression, symbolBuilder) } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspStandaloneDirectInheritorsProvider.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspStandaloneDirectInheritorsProvider.kt index f64a720a91..3f114bfaf3 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspStandaloneDirectInheritorsProvider.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspStandaloneDirectInheritorsProvider.kt @@ -3,7 +3,6 @@ package com.google.devtools.ksp.standalone import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analysis.api.fir.utils.isSubClassOf -import org.jetbrains.kotlin.analysis.api.standalone.base.providers.KotlinStandaloneDirectInheritorsProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirInternals import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionCache import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule @@ -30,7 +29,7 @@ class KspStandaloneDirectInheritorsProvider(private val project: Project) : Kotl (KotlinDeclarationProviderFactory.getInstance(project) as? IncrementalKotlinDeclarationProviderFactory) ?.staticFactory as? KotlinStaticDeclarationProviderFactory ) ?: error( - "`${KotlinStandaloneDirectInheritorsProvider::class.simpleName}" + + "KotlinStandaloneDirectInheritorsProvider" + "` expects the following declaration provider factory to be" + " registered: `${KotlinStaticDeclarationProviderFactory::class.simpleName}`" ) From 4a277d8dc1eafece32f28c2f227fee133e5b3f1c Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Mon, 22 Apr 2024 18:09:07 -0700 Subject: [PATCH 06/64] UPDATE_KOTLIN_VERSION: 2.0.20-dev-1634 (cherry picked from commit acb5c5136747ef0b5637b1c385687e91f774b557) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 8b11124d2d..3063257796 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # Copied from kotlinc org.gradle.jvmargs=-Duser.country=US -Dkotlin.daemon.jvm.options=-Xmx2200m -Dfile.encoding=UTF-8 -kotlinBaseVersion=2.0.20-dev-715 +kotlinBaseVersion=2.0.20-dev-1634 agpBaseVersion=7.2.0 intellijVersion=213.7172.25 junitVersion=4.13.1 From aedcde69dec26935380c25706ebf9f62656458ea Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Tue, 30 Apr 2024 19:22:08 -0700 Subject: [PATCH 07/64] UPDATE_KOTLIN_VERSION: 2.0.20-dev-2651 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 3063257796..56b9f6679d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # Copied from kotlinc org.gradle.jvmargs=-Duser.country=US -Dkotlin.daemon.jvm.options=-Xmx2200m -Dfile.encoding=UTF-8 -kotlinBaseVersion=2.0.20-dev-1634 +kotlinBaseVersion=2.0.20-dev-2651 agpBaseVersion=7.2.0 intellijVersion=213.7172.25 junitVersion=4.13.1 From 524997e1e17879b9e7dd41efd5b8d1a8413aa835 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Tue, 30 Apr 2024 19:21:51 -0700 Subject: [PATCH 08/64] UPDATE_AA_VERSION: 2.0.20-dev-2651 --- gradle.properties | 2 +- .../devtools/ksp/impl/KotlinSymbolProcessing.kt | 3 ++- .../ksp/impl/symbol/java/KSAnnotationJavaImpl.kt | 5 ++++- .../ksp/impl/symbol/kotlin/KSAnnotationImpl.kt | 6 +++++- .../ksp/impl/symbol/kotlin/KSValueArgumentImpl.kt | 14 +++----------- .../kotlin/synthetic/KSSyntheticAnnotations.kt | 5 ++++- .../google/devtools/ksp/impl/symbol/kotlin/util.kt | 5 ++--- kotlin-analysis-api/testData/errorTypes.kt | 2 +- kotlin-analysis-api/testData/getPackage.kt | 4 ++-- .../com/google/devtools/ksp/test/KSPAATest.kt | 1 + 10 files changed, 25 insertions(+), 22 deletions(-) diff --git a/gradle.properties b/gradle.properties index 56b9f6679d..da3d8bfd5b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ junit5Version=5.8.2 junitPlatformVersion=1.8.2 googleTruthVersion=1.1 -aaKotlinBaseVersion=2.0.20-dev-1634 +aaKotlinBaseVersion=2.0.20-dev-2651 aaIntellijVersion=213.7172.25 aaGuavaVersion=29.0-jre aaAsmVersion=9.0 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 c4deab33ad..85569f3236 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 @@ -709,7 +709,8 @@ internal val DEAR_SHADOW_JAR_PLEASE_DO_NOT_REMOVE_THESE = listOf( org.jetbrains.kotlin.analysis.api.standalone.base.providers.KotlinStandaloneDirectInheritorsProvider::class.java, 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.stubBased.deserialization.LLStubBasedLibrarySymbolProviderFactory::class.java, + org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased + .deserialization.LLStubBasedLibrarySymbolProviderFactory::class.java, org.jetbrains.kotlin.analysis.providers.impl.KotlinProjectMessageBusProvider::class.java, org.jetbrains.kotlin.idea.references.KotlinFirReferenceContributor::class.java, org.jetbrains.kotlin.light.classes.symbol.SymbolKotlinAsJavaSupport::class.java, diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt index 55964933ed..f2ac92889b 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt @@ -38,6 +38,7 @@ import com.intellij.psi.PsiType import com.intellij.psi.impl.source.PsiAnnotationMethodImpl import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue import org.jetbrains.kotlin.analysis.api.components.buildClassType +import org.jetbrains.kotlin.analysis.api.lifetime.KtAlwaysAccessibleLifetimeToken import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin import org.jetbrains.kotlin.analysis.api.types.KtType @@ -107,7 +108,9 @@ class KSAnnotationJavaImpl private constructor(private val psi: PsiAnnotation, o valueParameterSymbol.getDefaultValue()?.let { constantValue -> KSValueArgumentImpl.getCached( KtNamedAnnotationValue( - valueParameterSymbol.name, constantValue, + valueParameterSymbol.name, + constantValue, + KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project!!) ), Origin.SYNTHETIC ) diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt index 4c8cd340aa..c582557c30 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt @@ -20,6 +20,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.impl.KSNameImpl +import com.google.devtools.ksp.impl.ResolverAAImpl import com.google.devtools.ksp.impl.symbol.java.KSValueArgumentLiteImpl import com.google.devtools.ksp.impl.symbol.java.calcValue import com.google.devtools.ksp.impl.symbol.kotlin.resolved.KSTypeReferenceResolvedImpl @@ -29,6 +30,7 @@ import com.intellij.psi.PsiClass import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationWithArgumentsInfo import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue import org.jetbrains.kotlin.analysis.api.components.buildClassType +import org.jetbrains.kotlin.analysis.api.lifetime.KtAlwaysAccessibleLifetimeToken import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.* import org.jetbrains.kotlin.psi.KtAnnotationEntry @@ -88,7 +90,9 @@ class KSAnnotationImpl private constructor( valueParameterSymbol.getDefaultValue()?.let { constantValue -> KSValueArgumentImpl.getCached( KtNamedAnnotationValue( - valueParameterSymbol.name, constantValue, + valueParameterSymbol.name, + constantValue, + KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project!!) ), Origin.SYNTHETIC ) 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 4d3878c610..23e86432e3 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 @@ -76,18 +76,10 @@ class KSValueArgumentImpl private constructor( } } } ?: KSErrorType + // TODO: handle local classes. is KtKClassAnnotationValue -> { - val classDeclaration = when (this) { - is KtKClassAnnotationValue.KtNonLocalKClassAnnotationValue -> analyze { - (this@toValue.classId.toKtClassSymbol())?.let { KSClassDeclarationImpl.getCached(it) } - } - is KtKClassAnnotationValue.KtLocalKClassAnnotationValue -> analyze { - this@toValue.ktClass.getNamedClassOrObjectSymbol()?.let { - KSClassDeclarationImpl.getCached(it) - } - } - is KtKClassAnnotationValue.KtErrorClassAnnotationValue -> null - } + val classDeclaration = + (this@toValue.classId?.toKtClassSymbol())?.let { KSClassDeclarationImpl.getCached(it) } classDeclaration?.asStarProjectedType() ?: KSErrorType } is KtConstantAnnotationValue -> this.constantValue.value diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/synthetic/KSSyntheticAnnotations.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/synthetic/KSSyntheticAnnotations.kt index 2b7c03ec9c..42c4939000 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/synthetic/KSSyntheticAnnotations.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/synthetic/KSSyntheticAnnotations.kt @@ -1,6 +1,8 @@ package com.google.devtools.ksp.impl.symbol.kotlin.synthetic +import com.google.devtools.ksp.impl.ResolverAAImpl import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationWithArgumentsInfo +import org.jetbrains.kotlin.analysis.api.lifetime.KtAlwaysAccessibleLifetimeToken import org.jetbrains.kotlin.name.ClassId fun getExtensionFunctionTypeAnnotation(index: Int) = KtAnnotationApplicationWithArgumentsInfo( @@ -9,5 +11,6 @@ fun getExtensionFunctionTypeAnnotation(index: Int) = KtAnnotationApplicationWith null, emptyList(), index, - null + null, + KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project!!) ) 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 5d7c2bf952..355d11abe4 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 @@ -121,9 +121,8 @@ internal fun KtAnnotationValue.render(): String { is KtArrayAnnotationValue -> values.joinToString(",", "{", "}") { it.render() } is KtConstantAnnotationValue -> constantValue.renderAsKotlinConstant() is KtEnumEntryAnnotationValue -> callableId.toString() - is KtKClassAnnotationValue.KtErrorClassAnnotationValue -> "" - is KtKClassAnnotationValue.KtLocalKClassAnnotationValue -> "$ktClass::class" - is KtKClassAnnotationValue.KtNonLocalKClassAnnotationValue -> "$classId::class" + // TODO: handle error classes. + is KtKClassAnnotationValue -> "$classId::class" is KtUnsupportedAnnotationValue -> throw IllegalStateException("Unsupported annotation value: $this") } } diff --git a/kotlin-analysis-api/testData/errorTypes.kt b/kotlin-analysis-api/testData/errorTypes.kt index d2b8c0829f..ce1159044f 100644 --- a/kotlin-analysis-api/testData/errorTypes.kt +++ b/kotlin-analysis-api/testData/errorTypes.kt @@ -22,7 +22,7 @@ // kotlin.collections.Map // kotlin.String // ERROR TYPE -// errorInComponent is assignable from errorAtTop: true +// errorInComponent is assignable from errorAtTop: false // errorInComponent is assignable from class C: false // Any is assignable from errorInComponent: true // class C is assignable from errorInComponent: false diff --git a/kotlin-analysis-api/testData/getPackage.kt b/kotlin-analysis-api/testData/getPackage.kt index b474205fce..2339d6a79c 100644 --- a/kotlin-analysis-api/testData/getPackage.kt +++ b/kotlin-analysis-api/testData/getPackage.kt @@ -20,18 +20,18 @@ // symbols from package lib1 // lib1.propInSource KOTLIN // lib1.funcFoo KOTLIN_LIB -// lib1.Foo KOTLIN_LIB // lib1.FooInSource KOTLIN // lib1.Bar JAVA_LIB +// lib1.Foo KOTLIN_LIB // symbols from package lib2 // lib2.a KOTLIN_LIB // lib2.Foo KOTLIN_LIB // lib2.FooTypeAlias KOTLIN_LIB // symbols from package main.test // main.test.KotlinMain KOTLIN -// main.test.C JAVA // main.test.D JAVA // main.test.L JAVA +// main.test.C JAVA // symbols from package non.exist // END diff --git a/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt b/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt index f5ba4e124c..6585458eca 100644 --- a/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt +++ b/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt @@ -91,6 +91,7 @@ class KSPAATest : AbstractKSPAATest() { runTest("../kotlin-analysis-api/testData/annotationValue/java.kt") } + @Disabled @TestMetadata("annotationValue_kt.kt") @Test fun testAnnotationValue_kt() { From 4f19ddd635c492dc45ca941db1afd41cc80e2e7e Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Tue, 23 Apr 2024 21:20:59 -0700 Subject: [PATCH 09/64] Patch AA service files in renamed uber jar FQNs starting with `com.intellij` and `org.jetbrains.kotlin` need to be prefixed by `ksp.`, like what ShadowJar does to classes. --- .../build.gradle.kts | 68 ++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/symbol-processing-aa-embeddable/build.gradle.kts b/symbol-processing-aa-embeddable/build.gradle.kts index 0311dc3a49..1dab9668fc 100644 --- a/symbol-processing-aa-embeddable/build.gradle.kts +++ b/symbol-processing-aa-embeddable/build.gradle.kts @@ -1,5 +1,9 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext import org.gradle.jvm.tasks.Jar +import shadow.org.apache.tools.zip.ZipEntry +import shadow.org.apache.tools.zip.ZipOutputStream +import java.io.InputStreamReader import java.util.zip.ZipFile evaluationDependsOn(":kotlin-analysis-api") @@ -58,17 +62,79 @@ val prefixesToRelocate = listOf( Pair(it, "ksp." + it) } +class AAServiceTransformer : com.github.jengelman.gradle.plugins.shadow.transformers.Transformer { + private val entries = HashMap() + + // Names of extension points needs to be relocated, because ShadowJar does that, too. + private val regex = Regex("\"((org\\.jetbrains\\.kotlin\\.|com\\.intellij\\.).+)\"") + + override fun canTransformResource(element: FileTreeElement): Boolean { + return element.name.startsWith("META-INF/analysis-api/") || + element.name == "META-INF/extensions/compiler.xml" + } + + override fun getName(): String { + return "AAServiceTransformer" + } + + override fun hasTransformedResource(): Boolean { + return entries.size > 0 + } + + override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { + fun putOneEntry(path: String, content: String) { + val entry = ZipEntry(path) + entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) + os.putNextEntry(entry) + os.write(content.toByteArray()) + os.closeEntry() + } + + entries.forEach { path, original -> + val patched = original.replace(regex, "\"ksp.$1\"") + when { + path.startsWith("META-INF/analysis-api/") -> { + val more = patched.replace( + "\"/META-INF/extensions/compiler.xml\"", + "\"/META-INF/extensions/ksp_compiler.xml\"" + ) + putOneEntry(path, more) + } + path == "META-INF/extensions/compiler.xml" -> { + // Keep compiler.xml the same, and patch ksp_compiler.xml. + putOneEntry(path, original) + putOneEntry("META-INF/extensions/ksp_compiler.xml", patched) + } + else -> { + putOneEntry(path, patched) + } + } + } + } + + override fun transform(context: TransformerContext) { + val path = context.path + val content = InputStreamReader(context.`is`).readText() + entries.put(path, content) + } +} + tasks.withType { archiveClassifier.set("") // ShadowJar picks up the `compile` configuration by default and pulls stdlib in. // Therefore, specifying another configuration instead. configurations = listOf(packedJars) prefixesToRelocate.forEach { (f, t) -> - relocate(f, t) + relocate(f, t) { + // Do not rename this hardcoded string in XmlReader. + exclude("com.intellij.projectService") + } } mergeServiceFiles() exclude("META-INF/compiler.version") + this.transform(AAServiceTransformer()) + // All bundled dependencies should be renamed. doLast { val violatingFiles = mutableListOf() From f690aea6661436ca7c0fda7dc07d086090a406e9 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Tue, 23 Apr 2024 21:21:19 -0700 Subject: [PATCH 10/64] Exclude *.kotlin_module in renamed uber jar --- symbol-processing-aa-embeddable/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/symbol-processing-aa-embeddable/build.gradle.kts b/symbol-processing-aa-embeddable/build.gradle.kts index 1dab9668fc..d5bc242d4c 100644 --- a/symbol-processing-aa-embeddable/build.gradle.kts +++ b/symbol-processing-aa-embeddable/build.gradle.kts @@ -132,6 +132,7 @@ tasks.withType { } mergeServiceFiles() exclude("META-INF/compiler.version") + exclude("META-INF/*.kotlin_module") this.transform(AAServiceTransformer()) From e625afc6a8ea664ddebf06b6b99bca103224b2d2 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Fri, 3 May 2024 16:41:37 -0700 Subject: [PATCH 11/64] fix annotation default value parsing for arrays and class literals. --- .../impl/symbol/java/KSAnnotationJavaImpl.kt | 10 +++- .../impl/symbol/kotlin/KSAnnotationImpl.kt | 14 ++++- .../impl/symbol/kotlin/KSValueArgumentImpl.kt | 4 +- .../devtools/ksp/impl/symbol/kotlin/util.kt | 56 ++++++++++++++++++- .../com/google/devtools/ksp/test/KSPAATest.kt | 2 - 5 files changed, 74 insertions(+), 12 deletions(-) diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt index f2ac92889b..d46c4bdf08 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt @@ -96,9 +96,17 @@ class KSAnnotationJavaImpl private constructor(private val psi: PsiAnnotation, o (symbol.psi as PsiClass).allMethods.filterIsInstance() .mapNotNull { annoMethod -> annoMethod.defaultValue?.let { + val value = it + val calculatedValue: Any? = if (value is PsiArrayInitializerMemberValue) { + value.initializers.map { + calcValue(it) + } + } else { + calcValue(it) + } KSValueArgumentLiteImpl.getCached( KSNameImpl.getCached(annoMethod.name), - calcValue(it), + calculatedValue, Origin.SYNTHETIC ) } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt index c582557c30..a84c04b5d0 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt @@ -26,6 +26,7 @@ import com.google.devtools.ksp.impl.symbol.java.calcValue import com.google.devtools.ksp.impl.symbol.kotlin.resolved.KSTypeReferenceResolvedImpl import com.google.devtools.ksp.symbol.* import com.intellij.psi.PsiAnnotationMethod +import com.intellij.psi.PsiArrayInitializerMemberValue import com.intellij.psi.PsiClass import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationWithArgumentsInfo import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue @@ -76,10 +77,17 @@ class KSAnnotationImpl private constructor( if (symbol.origin == KtSymbolOrigin.JAVA && symbol.psi != null) { (symbol.psi as PsiClass).allMethods.filterIsInstance() .mapNotNull { annoMethod -> - annoMethod.defaultValue?.let { + annoMethod.defaultValue?.let { value -> + val calculatedValue: Any? = if (value is PsiArrayInitializerMemberValue) { + value.initializers.map { + calcValue(it) + } + } else { + calcValue(value) + } KSValueArgumentLiteImpl.getCached( KSNameImpl.getCached(annoMethod.name), - calcValue(it), + calculatedValue, Origin.SYNTHETIC ) } @@ -92,7 +100,7 @@ class KSAnnotationImpl private constructor( KtNamedAnnotationValue( valueParameterSymbol.name, constantValue, - KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project!!) + KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project) ), Origin.SYNTHETIC ) 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 23e86432e3..f981f4fa7a 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 @@ -78,9 +78,7 @@ class KSValueArgumentImpl private constructor( } ?: KSErrorType // TODO: handle local classes. is KtKClassAnnotationValue -> { - val classDeclaration = - (this@toValue.classId?.toKtClassSymbol())?.let { KSClassDeclarationImpl.getCached(it) } - classDeclaration?.asStarProjectedType() ?: KSErrorType + KSTypeImpl.getCached(this@toValue.type) } is KtConstantAnnotationValue -> this.constantValue.value is KtUnsupportedAnnotationValue -> null 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 355d11abe4..55be27508b 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 @@ -16,6 +16,8 @@ */ @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +@file:OptIn(KtAnalysisApiInternals::class, KtAnalysisApiInternals::class) + package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.ExceptionMessage @@ -29,6 +31,7 @@ import com.google.devtools.ksp.impl.symbol.util.getDocString import com.google.devtools.ksp.symbol.* import com.intellij.psi.PsiElement import com.intellij.psi.PsiJavaFile +import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.KtStarTypeProjection import org.jetbrains.kotlin.analysis.api.KtTypeArgumentWithVariance @@ -38,6 +41,7 @@ import org.jetbrains.kotlin.analysis.api.annotations.* import org.jetbrains.kotlin.analysis.api.components.KtSubstitutorBuilder import org.jetbrains.kotlin.analysis.api.components.buildClassType import org.jetbrains.kotlin.analysis.api.components.buildTypeParameterType +import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirAnnotationValueConverter import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirValueParameterSymbol import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType @@ -50,9 +54,20 @@ import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.java.JavaVisibilities +import org.jetbrains.kotlin.fir.declarations.getTargetType +import org.jetbrains.kotlin.fir.expressions.FirAnnotation +import org.jetbrains.kotlin.fir.expressions.FirArrayLiteral +import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack import org.jetbrains.kotlin.fir.java.toFirExpression +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.symbols.SymbolInternals +import org.jetbrains.kotlin.fir.types.ConeClassLikeType +import org.jetbrains.kotlin.fir.types.ConeErrorType +import org.jetbrains.kotlin.fir.types.ConeFlexibleType +import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType +import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.isAny import org.jetbrains.kotlin.load.java.structure.JavaAnnotationArgument import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl @@ -416,6 +431,43 @@ internal inline fun KSNode.findParentOfType(): KSNode? { @OptIn(SymbolInternals::class) internal fun KtValueParameterSymbol.getDefaultValue(): KtAnnotationValue? { + fun FirExpression.toValue(builder: KtSymbolByFirBuilder): KtAnnotationValue? { + if (this is FirAnnotation) { + return KtAnnotationApplicationValue( + KtAnnotationApplicationWithArgumentsInfo( + ClassId.fromString((annotationTypeRef.coneType as? ConeLookupTagBasedType)?.lookupTag.toString()), + null, + null, + emptyList(), + 0, + null, + KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project) + ), + KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project) + ) + } + if (this is FirArrayLiteral) { + return KtArrayAnnotationValue(argumentList.arguments.mapNotNull { it.toValue(builder) }, null, token) + } + return if (this is FirGetClassCall) { + var coneType = this.getTargetType()?.fullyExpandedType(builder.rootSession) + // FirAnnotationValueConverter expects fir type, while the type parsed from libraries are modeled + // as flexible type, for it to be used in argument of KClass values, it needs to be unwrapped. + if (coneType is ConeFlexibleType) { + coneType = coneType.lowerBound + } + + if (coneType is ConeClassLikeType && coneType !is ConeErrorType) { + val classId = coneType.lookupTag.classId + val type = builder.typeBuilder.buildKtType(coneType) + KtKClassAnnotationValue(type, classId, null, token) + } else { + null + } + } else { + FirAnnotationValueConverter.toConstantValue(this, builder) + } + } return this.psi.let { when (it) { is KtParameter -> analyze { @@ -461,9 +513,7 @@ internal fun KtValueParameterSymbol.getDefaultValue(): KtAnnotationValue? { val expectedTypeRef = it.firSymbol.fir.returnTypeRef val expression = defaultValue ?.toFirExpression(firSession, JavaTypeParameterStack.EMPTY, expectedTypeRef, null) - expression?.let { - FirAnnotationValueConverter.toConstantValue(expression, symbolBuilder) - } + expression?.toValue(symbolBuilder) } } else -> throw IllegalStateException("Unhandled default value type ${it.javaClass}") diff --git a/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt b/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt index 6585458eca..165c05e09c 100644 --- a/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt +++ b/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt @@ -65,7 +65,6 @@ class KSPAATest : AbstractKSPAATest() { runTest("../kotlin-analysis-api/testData/allFunctions_kt_inherits_java.kt") } - @Disabled @TestMetadata("annotationInDependencies.kt") @Test fun testAnnotationsInDependencies() { @@ -78,7 +77,6 @@ class KSPAATest : AbstractKSPAATest() { runTest("../test-utils/testData/api/annotationOnConstructorParameter.kt") } - @Disabled @TestMetadata("annotationWithArbitraryClassValue.kt") @Test fun testAnnotationWithArbitraryClassValue() { From 486e13178dd79c82fbc4ae2becfaac7efe905ca1 Mon Sep 17 00:00:00 2001 From: Kuan-Ying Chou Date: Tue, 9 Apr 2024 15:03:32 +0100 Subject: [PATCH 12/64] Test package for functions (cherry picked from commit ab47eacdfc681ea4f5070b7581a54fe42e1595f1) --- .../ksp/processor/FunctionTypeProcessor.kt | 2 +- test-utils/testData/api/functionTypes.kt | 36 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeProcessor.kt index f361599b5a..4daa9695e7 100644 --- a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeProcessor.kt +++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeProcessor.kt @@ -37,7 +37,7 @@ open class FunctionTypeProcessor : AbstractTestProcessor() { val type = property.type.resolve() val propertyName = property.simpleName.asString() val typeName = type.declaration.simpleName.asString() - results.add("$propertyName: $typeName : ${type.isFunctionType}, ${type.isSuspendFunctionType}") + results.add("$propertyName: $typeName : ${type.isFunctionType}, ${type.isSuspendFunctionType}, ${type.declaration.qualifiedName!!.asString()}, ${type.declaration.packageName.asString()}") } }, Unit diff --git a/test-utils/testData/api/functionTypes.kt b/test-utils/testData/api/functionTypes.kt index 69f8366f98..b167da5003 100644 --- a/test-utils/testData/api/functionTypes.kt +++ b/test-utils/testData/api/functionTypes.kt @@ -18,24 +18,24 @@ // WITH_RUNTIME // TEST PROCESSOR: FunctionTypeProcessor // EXPECTED: -// a: Function0 : true, false -// b: Function1 : true, false -// c: Function0 : true, false -// d: Function2 : true, false -// e: KFunction0 : true, false -// f: KSuspendFunction0 : false, true -// g: KFunction1 : true, false -// h: KSuspendFunction1 : false, true -// i: Function1 : true, false -// j: SuspendFunction1 : false, true -// k: SuspendFunction0 : false, true -// l: SuspendFunction1 : false, true -// m: SuspendFunction0 : false, true -// n: SuspendFunction2 : false, true -// o: KFunction0 : true, false -// p: KSuspendFunction0 : false, true -// vbar: KSuspendFunction0 : false, true -// vfoo: KFunction0 : true, false +// a: Function0 : true, false, kotlin.Function0, kotlin +// b: Function1 : true, false, kotlin.Function1, kotlin +// c: Function0 : true, false, kotlin.Function0, kotlin +// d: Function2 : true, false, kotlin.Function2, kotlin +// e: KFunction0 : true, false, kotlin.reflect.KFunction0, kotlin.reflect +// f: KSuspendFunction0 : false, true, kotlin.reflect.KSuspendFunction0, kotlin.reflect +// g: KFunction1 : true, false, kotlin.reflect.KFunction1, kotlin.reflect +// h: KSuspendFunction1 : false, true, kotlin.reflect.KSuspendFunction1, kotlin.reflect +// i: Function1 : true, false, kotlin.Function1, kotlin +// j: SuspendFunction1 : false, true, kotlin.coroutines.SuspendFunction1, kotlin.coroutines +// k: SuspendFunction0 : false, true, kotlin.coroutines.SuspendFunction0, kotlin.coroutines +// l: SuspendFunction1 : false, true, kotlin.coroutines.SuspendFunction1, kotlin.coroutines +// m: SuspendFunction0 : false, true, kotlin.coroutines.SuspendFunction0, kotlin.coroutines +// n: SuspendFunction2 : false, true, kotlin.coroutines.SuspendFunction2, kotlin.coroutines +// o: KFunction0 : true, false, kotlin.reflect.KFunction0, kotlin.reflect +// p: KSuspendFunction0 : false, true, kotlin.reflect.KSuspendFunction0, kotlin.reflect +// vbar: KSuspendFunction0 : false, true, kotlin.reflect.KSuspendFunction0, kotlin.reflect +// vfoo: KFunction0 : true, false, kotlin.reflect.KFunction0, kotlin.reflect // END @file:Suppress("Boolean", "Byte", "Int", "Short", "Double", "Float", "Unit", "Suppress", "C") From 6b8a9ed1e0dfe92bfb2ab1386ea2f9b9a58c74ee Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Mon, 6 May 2024 17:10:53 -0700 Subject: [PATCH 13/64] fix package name for library based symbols --- .../impl/symbol/kotlin/AbstractKSDeclarationImpl.kt | 13 ++++++++----- .../devtools/ksp/processor/FunctionTypeProcessor.kt | 6 +++++- 2 files changed, 13 insertions(+), 6 deletions(-) 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 16d65ac08c..b20a960e5f 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 @@ -79,16 +79,19 @@ abstract class AbstractKSDeclarationImpl(val ktDeclarationSymbol: KtDeclarationS override val packageName: KSName by lazy { // source - containingFile?.packageName + if (origin == Origin.KOTLIN || origin == Origin.JAVA) { + containingFile!!.packageName + } else { // top level declaration - ?: when (ktDeclarationSymbol) { + when (ktDeclarationSymbol) { is KtClassLikeSymbol -> ktDeclarationSymbol.classIdIfNonLocal?.packageFqName?.asString() is KtCallableSymbol -> ktDeclarationSymbol.callableIdIfNonLocal?.packageName?.asString() else -> null }?.let { KSNameImpl.getCached(it) } - // null -> non top level declaration, find in parent - ?: ktDeclarationSymbol.getContainingKSSymbol()?.packageName - ?: throw IllegalStateException("failed to find package name for $this") + // null -> non top level declaration, find in parent + ?: ktDeclarationSymbol.getContainingKSSymbol()?.packageName + ?: throw IllegalStateException("failed to find package name for $this") + } } override val typeParameters: List by lazy { diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeProcessor.kt index 4daa9695e7..f1de05ab74 100644 --- a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeProcessor.kt +++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeProcessor.kt @@ -37,7 +37,11 @@ open class FunctionTypeProcessor : AbstractTestProcessor() { val type = property.type.resolve() val propertyName = property.simpleName.asString() val typeName = type.declaration.simpleName.asString() - results.add("$propertyName: $typeName : ${type.isFunctionType}, ${type.isSuspendFunctionType}, ${type.declaration.qualifiedName!!.asString()}, ${type.declaration.packageName.asString()}") + results.add( + "$propertyName: $typeName : ${type.isFunctionType}, " + + "${type.isSuspendFunctionType}, ${type.declaration.qualifiedName!!.asString()}, " + + "${type.declaration.packageName.asString()}" + ) } }, Unit From 2338e70cfa6868aa9ae33dc0364a219be98adae5 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Sat, 4 May 2024 22:00:44 -0700 Subject: [PATCH 14/64] Do not index classpath in declaration provider It was a workaround where symbol provider depended on declaration provider. It is no longer needed after KT-66689 was fixed. --- .../com/google/devtools/ksp/impl/KotlinSymbolProcessing.kt | 7 +------ .../ksp/standalone/IncrementalKotlinDeclarationProvider.kt | 7 ++----- 2 files changed, 3 insertions(+), 11 deletions(-) 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 85569f3236..74c23360b0 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 @@ -370,12 +370,7 @@ class KotlinSymbolProcessing( project.getService( KotlinDeclarationProviderFactory::class.java ) as IncrementalKotlinDeclarationProviderFactory - ) - .update( - ktFiles, - StandaloneProjectFactory.getAllBinaryRoots(modules, kotlinCoreProjectEnvironment).map { it.file } + - listOfNotNull(VirtualFileManager.getInstance().findFileByNioPath(kspConfig.classOutputDir.toPath())) - ) + ).update(ktFiles) ( project.getService( KotlinPackageProviderFactory::class.java diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProvider.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProvider.kt index 74caa1145b..005209fab8 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProvider.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProvider.kt @@ -1,7 +1,6 @@ package com.google.devtools.ksp.standalone import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider @@ -94,11 +93,9 @@ class IncrementalKotlinDeclarationProviderFactory( } } - fun update(files: Collection, moduleRoots: List) { + fun update(files: Collection) { this.files = files - this.staticFactory = KotlinStaticDeclarationProviderFactory( - project, files, sharedBinaryRoots = moduleRoots, shouldBuildStubsForBinaryLibraries = true - ) + this.staticFactory = KotlinStaticDeclarationProviderFactory(project, files) provider?.let { it.del = createDelegateProvider() } From 4aef6e1fb064feea3935b1cab03ec39805562078 Mon Sep 17 00:00:00 2001 From: Kuan-Ying Chou Date: Wed, 24 Apr 2024 17:43:32 +0100 Subject: [PATCH 15/64] Test functional interface (cherry picked from commit 67afc258feefb2d16e67122ea63d8dde46ac134f) --- kotlin-analysis-api/testData/javaModifiers.kt | 8 ++++++++ .../devtools/ksp/processor/JavaModifierProcessor.kt | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/kotlin-analysis-api/testData/javaModifiers.kt b/kotlin-analysis-api/testData/javaModifiers.kt index bd59392548..de0cd0b0bb 100644 --- a/kotlin-analysis-api/testData/javaModifiers.kt +++ b/kotlin-analysis-api/testData/javaModifiers.kt @@ -102,6 +102,10 @@ // OuterKotlinClass: OPEN : PUBLIC // END // MODULE: module1 +// FILE: ALib.kt +fun interface ALib { + fun test(): Boolean +} // FILE: DependencyOuterJavaClass.java public class DependencyOuterJavaClass { public class DependencyInnerJavaClass {} @@ -152,6 +156,10 @@ open class DependencyOuterKotlinClass { fun synchronizedFun(): String = "" } // MODULE: main(module1) +// FILE: ASrc.kt +fun interface ASrc { + fun test(): Boolean +} // FILE: a.kt annotation class Test diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt index 4b03742721..8ac070fe5e 100644 --- a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt +++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt @@ -18,6 +18,7 @@ package com.google.devtools.ksp.processor import com.google.devtools.ksp.KspExperimental +import com.google.devtools.ksp.getClassDeclarationByName import com.google.devtools.ksp.processing.Resolver import com.google.devtools.ksp.symbol.* import com.google.devtools.ksp.symbol.KSPropertyDeclaration @@ -31,6 +32,12 @@ class JavaModifierProcessor : AbstractTestProcessor() { } override fun process(resolver: Resolver): List { + listOf("ALib", "ASrc").forEach { clsName -> + resolver.getClassDeclarationByName(clsName)!!.let { cls -> + println(cls.modifiers.contains(Modifier.FUN)) + } + } + resolver.getSymbolsWithAnnotation("Test") .map { it as KSClassDeclaration From aa11a68c0f5bea129387f04d26518dc31708f4a2 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Mon, 6 May 2024 14:36:41 -0700 Subject: [PATCH 16/64] check functional interface for modifiers --- .../ksp/impl/symbol/kotlin/KSClassDeclarationImpl.kt | 3 +++ .../devtools/ksp/processor/JavaModifierProcessor.kt | 2 +- test-utils/testData/api/javaModifiers.kt | 8 ++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) 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 e5161bb546..06fef7653d 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 @@ -211,6 +211,9 @@ internal fun KtClassOrObjectSymbol.toModifiers(): Set { if (visibility != JavaVisibilities.PackageVisibility) { result.add(visibility.toModifier()) } + if (isFun) { + result.add(Modifier.FUN) + } if (isInline) { result.add(Modifier.INLINE) } diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt index 8ac070fe5e..97442d7641 100644 --- a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt +++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt @@ -34,7 +34,7 @@ class JavaModifierProcessor : AbstractTestProcessor() { override fun process(resolver: Resolver): List { listOf("ALib", "ASrc").forEach { clsName -> resolver.getClassDeclarationByName(clsName)!!.let { cls -> - println(cls.modifiers.contains(Modifier.FUN)) + assert(cls.modifiers.contains(Modifier.FUN)) } } diff --git a/test-utils/testData/api/javaModifiers.kt b/test-utils/testData/api/javaModifiers.kt index 7254b7629f..cd458f23dc 100644 --- a/test-utils/testData/api/javaModifiers.kt +++ b/test-utils/testData/api/javaModifiers.kt @@ -102,6 +102,10 @@ // OuterKotlinClass: OPEN : PUBLIC // END // MODULE: module1 +// FILE: ALib.kt +fun interface ALib { + fun test(): Boolean +} // FILE: DependencyOuterJavaClass.java public class DependencyOuterJavaClass { public class DependencyInnerJavaClass {} @@ -152,6 +156,10 @@ open class DependencyOuterKotlinClass { fun synchronizedFun(): String = "" } // MODULE: main(module1) +// FILE: ASrc.kt +fun interface ASrc { + fun test(): Boolean +} // FILE: a.kt annotation class Test From d432b52b8fa53bf212b02e80386dd306362bc666 Mon Sep 17 00:00:00 2001 From: Kuan-Ying Chou Date: Thu, 11 Apr 2024 14:57:28 +0100 Subject: [PATCH 17/64] Test default annotation values (cherry picked from commit 207b8aad243bdd81d8a3165ed9b5b8b127274d5c) --- .../testData/annotationValue/java.kt | 18 +++++++++++++++++- .../processor/AnnotationArgumentProcessor.kt | 8 ++++++++ .../testData/api/annotationValue_java.kt | 16 ++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/kotlin-analysis-api/testData/annotationValue/java.kt b/kotlin-analysis-api/testData/annotationValue/java.kt index 323b3d92a6..4768a61c0d 100644 --- a/kotlin-analysis-api/testData/annotationValue/java.kt +++ b/kotlin-analysis-api/testData/annotationValue/java.kt @@ -31,8 +31,24 @@ // 31 // [warning1, warning 2] // END -// FILE: a.kt +// MODULE: module1 +// FILE: placeholder.kt +// FILE: TestLib.java +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; +@Target({ElementType.TYPE, ElementType.TYPE_USE}) +@interface MyAnnotation { + String stringParam() default "1"; + String stringParam2() default "1"; + String[] stringArrayParam() default {"3", "5", "7"}; +} +interface MyInterface {} +@MyAnnotation(stringParam = "2") class MyClassInLib implements MyInterface {} +// MODULE: main(module1) +// FILE: Test.java +@MyAnnotation(stringParam = "2") class MyClass implements MyInterface {} +// FILE: a.kt enum class RGB { R, G, B } diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArgumentProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArgumentProcessor.kt index 68e263c641..951f6170dc 100644 --- a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArgumentProcessor.kt +++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArgumentProcessor.kt @@ -29,6 +29,14 @@ class AnnotationArgumentProcessor : AbstractTestProcessor() { val visitor = ArgumentVisitor() override fun process(resolver: Resolver): List { + listOf("MyClass", "MyClassInLib").forEach { clsName -> + resolver.getClassDeclarationByName(clsName)!!.let { cls -> + cls.annotations.single().arguments.forEach { + println("${clsName}: ${it.name!!.asString()} = ${it.value}") + } + } + } + resolver.getSymbolsWithAnnotation("Bar", true).forEach { it.annotations.forEach { it.arguments.forEach { it.accept(visitor, Unit) } } } diff --git a/test-utils/testData/api/annotationValue_java.kt b/test-utils/testData/api/annotationValue_java.kt index 448ea5e0ec..65fcb630ee 100644 --- a/test-utils/testData/api/annotationValue_java.kt +++ b/test-utils/testData/api/annotationValue_java.kt @@ -31,6 +31,22 @@ // 31 // [warning1, warning 2] // END +// MODULE: module1 +// FILE: placeholder.kt +// FILE: TestLib.java +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; +@Target({ElementType.TYPE, ElementType.TYPE_USE}) +@interface MyAnnotation { + String stringParam() default "1"; + String stringParam2() default "1"; + String[] stringArrayParam() default {"3", "5", "7"}; +} +interface MyInterface {} +@MyAnnotation(stringParam = "2") class MyClassInLib implements MyInterface {} +// MODULE: main(module1) +// FILE: Test.java +@MyAnnotation(stringParam = "2") class MyClass implements MyInterface {} // FILE: a.kt enum class RGB { From 90fd8c709e7b589ed35993bffd7c05a7744702b2 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Tue, 7 May 2024 13:57:14 -0700 Subject: [PATCH 18/64] fix instance filtering for java annotation default value checking --- .../devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt | 4 ++-- kotlin-analysis-api/testData/annotationValue/java.kt | 6 ++++++ .../devtools/ksp/processor/AnnotationArgumentProcessor.kt | 4 ++-- test-utils/testData/api/annotationValue_java.kt | 6 ++++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt index d46c4bdf08..83e3b79b44 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt @@ -27,6 +27,7 @@ import com.intellij.lang.jvm.JvmClassKind import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiAnnotation import com.intellij.psi.PsiAnnotationMemberValue +import com.intellij.psi.PsiAnnotationMethod import com.intellij.psi.PsiArrayInitializerMemberValue import com.intellij.psi.PsiArrayType import com.intellij.psi.PsiClass @@ -35,7 +36,6 @@ import com.intellij.psi.PsiLiteralValue import com.intellij.psi.PsiPrimitiveType import com.intellij.psi.PsiReference import com.intellij.psi.PsiType -import com.intellij.psi.impl.source.PsiAnnotationMethodImpl import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue import org.jetbrains.kotlin.analysis.api.components.buildClassType import org.jetbrains.kotlin.analysis.api.lifetime.KtAlwaysAccessibleLifetimeToken @@ -93,7 +93,7 @@ class KSAnnotationJavaImpl private constructor(private val psi: PsiAnnotation, o (type.classifierSymbol() as KtClassOrObjectSymbol).getMemberScope().getConstructors().singleOrNull() ?.let { symbol -> if (symbol.origin == KtSymbolOrigin.JAVA && symbol.psi != null) { - (symbol.psi as PsiClass).allMethods.filterIsInstance() + (symbol.psi as PsiClass).allMethods.filterIsInstance() .mapNotNull { annoMethod -> annoMethod.defaultValue?.let { val value = it diff --git a/kotlin-analysis-api/testData/annotationValue/java.kt b/kotlin-analysis-api/testData/annotationValue/java.kt index 4768a61c0d..5c88bacb37 100644 --- a/kotlin-analysis-api/testData/annotationValue/java.kt +++ b/kotlin-analysis-api/testData/annotationValue/java.kt @@ -18,6 +18,12 @@ // WITH_RUNTIME // TEST PROCESSOR: AnnotationArgumentProcessor // EXPECTED: +// MyClass: stringParam = 2 +// MyClass: stringParam2 = 1 +// MyClass: stringArrayParam = [3, 5, 7] +// MyClassInLib: stringParam = 2 +// MyClassInLib: stringParam2 = 1 +// MyClassInLib: stringArrayParam = [3, 5, 7] // Str // 42 // Foo diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArgumentProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArgumentProcessor.kt index 951f6170dc..54366407cb 100644 --- a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArgumentProcessor.kt +++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArgumentProcessor.kt @@ -30,9 +30,9 @@ class AnnotationArgumentProcessor : AbstractTestProcessor() { override fun process(resolver: Resolver): List { listOf("MyClass", "MyClassInLib").forEach { clsName -> - resolver.getClassDeclarationByName(clsName)!!.let { cls -> + resolver.getClassDeclarationByName(clsName)?.let { cls -> cls.annotations.single().arguments.forEach { - println("${clsName}: ${it.name!!.asString()} = ${it.value}") + results.add("$clsName: ${it.name!!.asString()} = ${it.value}") } } } diff --git a/test-utils/testData/api/annotationValue_java.kt b/test-utils/testData/api/annotationValue_java.kt index 65fcb630ee..c611fe10dc 100644 --- a/test-utils/testData/api/annotationValue_java.kt +++ b/test-utils/testData/api/annotationValue_java.kt @@ -18,6 +18,12 @@ // WITH_RUNTIME // TEST PROCESSOR: AnnotationArgumentProcessor // EXPECTED: +// MyClass: stringParam = 2 +// MyClass: stringParam2 = 1 +// MyClass: stringArrayParam = [3, 5, 7] +// MyClassInLib: stringParam = 2 +// MyClassInLib: stringParam2 = 1 +// MyClassInLib: stringArrayParam = [3, 5, 7] // Str // 42 // Foo From 6b244f64d4b6daa66ae3d5c920116752e4f247a6 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Wed, 8 May 2024 18:44:11 -0700 Subject: [PATCH 19/64] fix type parameter bounds --- .../impl/symbol/kotlin/KSTypeParameterImpl.kt | 25 ++----------------- .../testData/typeParameterVariance.kt | 8 +++--- .../TypeParameterVarianceProcessor.kt | 3 ++- 3 files changed, 9 insertions(+), 27 deletions(-) diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeParameterImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeParameterImpl.kt index 98b2648fc2..ef758f16fe 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeParameterImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeParameterImpl.kt @@ -24,8 +24,6 @@ import com.google.devtools.ksp.impl.ResolverAAImpl import com.google.devtools.ksp.impl.symbol.kotlin.resolved.KSTypeReferenceResolvedImpl import com.google.devtools.ksp.symbol.* import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol -import org.jetbrains.kotlin.psi.KtTypeParameter -import org.jetbrains.kotlin.psi.KtTypeParameterListOwner class KSTypeParameterImpl private constructor(internal val ktTypeParameterSymbol: KtTypeParameterSymbol) : KSTypeParameter, @@ -51,27 +49,8 @@ class KSTypeParameterImpl private constructor(internal val ktTypeParameterSymbol override val isReified: Boolean = ktTypeParameterSymbol.isReified override val bounds: Sequence by lazy { - when (val psi = ktTypeParameterSymbol.psi) { - is KtTypeParameter -> { - val owner = (parentDeclaration as? AbstractKSDeclarationImpl) - ?.ktDeclarationSymbol?.psi as? KtTypeParameterListOwner - val list = sequenceOf(psi.extendsBound) - if (owner != null) { - list.plus( - owner.typeConstraints - .filter { - it.subjectTypeParameterName!!.getReferencedName() == psi.nameAsSafeName.asString() - } - .map { it.boundTypeReference } - ) - } - list.filterNotNull().map { KSTypeReferenceImpl.getCached(it, this) } - } - else -> { - ktTypeParameterSymbol.upperBounds.asSequence().mapIndexed { index, type -> - KSTypeReferenceResolvedImpl.getCached(type, this@KSTypeParameterImpl, index) - } - } + ktTypeParameterSymbol.upperBounds.asSequence().mapIndexed { index, type -> + KSTypeReferenceResolvedImpl.getCached(type, this@KSTypeParameterImpl, index) }.ifEmpty { sequenceOf( KSTypeReferenceSyntheticImpl.getCached(ResolverAAImpl.instance.builtIns.anyType.makeNullable(), this) diff --git a/kotlin-analysis-api/testData/typeParameterVariance.kt b/kotlin-analysis-api/testData/typeParameterVariance.kt index 0f7bf361d6..d692c6c68f 100644 --- a/kotlin-analysis-api/testData/typeParameterVariance.kt +++ b/kotlin-analysis-api/testData/typeParameterVariance.kt @@ -17,9 +17,10 @@ // TEST PROCESSOR: TypeParameterVarianceProcessor // EXPECTED: -// Bar INVARIANT T -// BarIn CONTRAVARIANT T -// BarOut COVARIANT T +// Bar INVARIANT T Any? +// BarIn CONTRAVARIANT T Any? +// BarOut COVARIANT T Any? +// BarBounds INVARIANT T Bar, BarIn // END // FILE: main.kt @@ -28,3 +29,4 @@ interface Bar interface BarIn interface BarOut +interface BarBounds where T: Bar, T: BarIn diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterVarianceProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterVarianceProcessor.kt index 4275b24462..77f735bc99 100644 --- a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterVarianceProcessor.kt +++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterVarianceProcessor.kt @@ -14,7 +14,7 @@ class TypeParameterVarianceProcessor : AbstractTestProcessor() { override fun process(resolver: Resolver): List { fun KSDeclaration.printTypeParams(): String { val params = typeParameters.joinToString { - "${it.variance} ${it.name.asString()}" + "${it.variance} ${it.name.asString()} ${it.bounds.joinToString { it.resolve().toString() }}" } return "${simpleName.asString()} $params" } @@ -22,6 +22,7 @@ class TypeParameterVarianceProcessor : AbstractTestProcessor() { results.add(resolver.getClassDeclarationByName("Bar")!!.printTypeParams()) results.add(resolver.getClassDeclarationByName("BarIn")!!.printTypeParams()) results.add(resolver.getClassDeclarationByName("BarOut")!!.printTypeParams()) + results.add(resolver.getClassDeclarationByName("BarBounds")!!.printTypeParams()) return emptyList() } From 3f9d72c856d83e233a7cf6604c7983d267d24150 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Fri, 10 May 2024 14:35:37 -0700 Subject: [PATCH 20/64] Add command line parser --- build.gradle.kts | 2 +- cmdline-parser-gen/build.gradle.kts | 8 ++ .../src/main/kotlin/CmdlineParserGenerator.kt | 132 ++++++++++++++++++ ...ols.ksp.processing.SymbolProcessorProvider | 1 + common-deps/build.gradle.kts | 4 + .../com/google/devtools/ksp/KSPConfig.kt | 52 +++++++ .../devtools/ksp/CommandLineArgParserTest.kt | 51 +++++++ settings.gradle.kts | 1 + 8 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 cmdline-parser-gen/build.gradle.kts create mode 100644 cmdline-parser-gen/src/main/kotlin/CmdlineParserGenerator.kt create mode 100644 cmdline-parser-gen/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider create mode 100644 common-deps/src/test/kotlin/com/google/devtools/ksp/CommandLineArgParserTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 43ba936dc5..2635729638 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,7 +20,7 @@ repositories { } plugins { - kotlin("jvm") version "1.9.0" + kotlin("jvm") version "1.9.23" id("io.github.gradle-nexus.publish-plugin") version "1.1.0" // Adding plugins used in multiple places to the classpath for centralized version control diff --git a/cmdline-parser-gen/build.gradle.kts b/cmdline-parser-gen/build.gradle.kts new file mode 100644 index 0000000000..65ac567607 --- /dev/null +++ b/cmdline-parser-gen/build.gradle.kts @@ -0,0 +1,8 @@ +plugins { + kotlin("jvm") +} + +dependencies { + implementation(kotlin("stdlib")) + implementation(project(":api")) +} diff --git a/cmdline-parser-gen/src/main/kotlin/CmdlineParserGenerator.kt b/cmdline-parser-gen/src/main/kotlin/CmdlineParserGenerator.kt new file mode 100644 index 0000000000..cb4d2b43c5 --- /dev/null +++ b/cmdline-parser-gen/src/main/kotlin/CmdlineParserGenerator.kt @@ -0,0 +1,132 @@ +import com.google.devtools.ksp.processing.* +import com.google.devtools.ksp.symbol.* +import java.io.OutputStream + +private fun OutputStream.appendText(str: String) { + this.write(str.toByteArray()) +} + +private fun OutputStream.appendLine(str: String = "") { + appendText(str + System.lineSeparator()) +} + +// modueName => -module-name +private fun String.camelToOptionName(): String = fold(StringBuilder()) { acc, c -> + acc.let { + val lower = c.lowercase() + acc.append(if (acc.isEmpty() || c.isUpperCase()) "-$lower" else lower) + } +}.toString() + +class CmdlineParserGenerator( + val codeGenerator: CodeGenerator, + val logger: KSPLogger, + val options: Map +) : SymbolProcessor { + override fun process(resolver: Resolver): List { + val annotationName = "com.google.devtools.ksp.processing.KSPArgParserGen" + val kspConfigBuilders = + resolver.getSymbolsWithAnnotation(annotationName) + + kspConfigBuilders.filterIsInstance().forEach { builderClass -> + val parserName = builderClass.annotations.single { + it.annotationType.resolve().declaration.qualifiedName?.asString() == annotationName + }.arguments.single().value as String + val configClass = builderClass.parentDeclaration as KSClassDeclaration + val builderName = "${configClass.simpleName.asString()}.${builderClass.simpleName.asString()}" + codeGenerator.createNewFile( + Dependencies(false, builderClass.containingFile!!), + builderClass.packageName.asString(), + parserName + ).use { os -> + os.appendLine("package ${builderClass.packageName.asString()}") + os.appendLine() + os.appendLine( + "fun $parserName(args: Array): Pair<${configClass.simpleName.asString()}, List> {" + ) + os.appendLine(" val processorClasspath = mutableListOf()") + os.appendLine(" return Pair($builderName().apply {") + os.appendLine(" var i = 0") + os.appendLine(" while (i < args.size) {") + os.appendLine(" val arg = args[i++]") + os.appendLine(" when {") + + builderClass.getAllProperties().filter { it.setter != null }.forEach { prop -> + val type = prop.type.resolve() + val typeName = type.declaration.simpleName.asString() + val propName = prop.simpleName.asString() + val optionName = propName.camelToOptionName() + val optionNameLen = optionName.length + when (typeName) { + "String", "Boolean", "File" -> { + os.appendLine( + " arg == \"$optionName\" -> " + + "$propName = parse$typeName(getArg(args, i++))" + ) + os.appendLine( + " arg.startsWith(\"$optionName=\") -> " + + "$propName = parse$typeName(arg.substring(${optionNameLen + 1}))" + ) + } + "List", "Map" -> { + val elementTypeName = + type.arguments.last().type!!.resolve().declaration.simpleName.asString() + os.appendLine( + " arg == \"$optionName\" -> " + + "$propName = parse$typeName(getArg(args, i++), ::parse$elementTypeName)" + ) + os.appendLine( + " arg.startsWith(\"$optionName=\") -> " + + "$propName = parse$typeName(arg.substring(${optionNameLen + 1}), " + + "::parse$elementTypeName)" + ) + } + else -> { + throw IllegalArgumentException("Unknown type of option `$propName: ${prop.type}`") + } + } + } + + // Free args are processor classpath + os.appendLine(" else -> {") + os.appendLine(" processorClasspath.addAll(parseList(arg, ::parseString))") + os.appendLine(" }") + os.appendLine(" }") + os.appendLine(" }") + os.appendLine(" }.build(), processorClasspath)") + os.appendLine("}") + } + + codeGenerator.createNewFile( + Dependencies(false, builderClass.containingFile!!), + builderClass.packageName.asString(), + parserName + "Help" + ).use { os -> + os.appendLine("package ${builderClass.packageName.asString()}") + os.appendLine() + os.appendLine( + "fun ${parserName}Help(): String = \"\"\"" + ) + builderClass.getAllProperties().filter { it.setter != null }.forEach { prop -> + val type = prop.type.resolve() + val typeName = type.toString() + val propName = prop.simpleName.asString() + val optionName = propName.camelToOptionName() + val prefix = if (Modifier.LATEINIT in prop.modifiers) "*" else " " + os.appendLine("$prefix $optionName=$typeName") + } + os.appendLine("* ") + os.appendLine("\"\"\"") + } + } + return emptyList() + } +} + +class CmdlineParserGeneratorProvider : SymbolProcessorProvider { + override fun create( + environment: SymbolProcessorEnvironment + ): SymbolProcessor { + return CmdlineParserGenerator(environment.codeGenerator, environment.logger, environment.options) + } +} diff --git a/cmdline-parser-gen/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/cmdline-parser-gen/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider new file mode 100644 index 0000000000..244b31079a --- /dev/null +++ b/cmdline-parser-gen/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider @@ -0,0 +1 @@ +CmdlineParserGeneratorProvider diff --git a/common-deps/build.gradle.kts b/common-deps/build.gradle.kts index b6b457126c..492b9af066 100644 --- a/common-deps/build.gradle.kts +++ b/common-deps/build.gradle.kts @@ -18,10 +18,14 @@ plugins { `maven-publish` signing id("org.jetbrains.dokka") + id("com.google.devtools.ksp") version "1.9.23-1.0.20" } dependencies { compileOnly(project(":api")) + testImplementation("junit:junit:$junitVersion") + + ksp(project(":cmdline-parser-gen")) } tasks { diff --git a/common-deps/src/main/kotlin/com/google/devtools/ksp/KSPConfig.kt b/common-deps/src/main/kotlin/com/google/devtools/ksp/KSPConfig.kt index 53f3968035..cc2ee40959 100644 --- a/common-deps/src/main/kotlin/com/google/devtools/ksp/KSPConfig.kt +++ b/common-deps/src/main/kotlin/com/google/devtools/ksp/KSPConfig.kt @@ -3,6 +3,8 @@ package com.google.devtools.ksp.processing import java.io.File import java.io.Serializable +private annotation class KSPArgParserGen(val name: String) + abstract class KSPConfig( val moduleName: String, val sourceRoots: List, @@ -121,6 +123,7 @@ class KSPJvmConfig( allWarningsAsErrors, mapAnnotationArgumentsInJava, ) { + @KSPArgParserGen(name = "kspJvmArgParser") class Builder : KSPConfig.Builder(), Serializable { var javaSourceRoots: List = emptyList() lateinit var javaOutputDir: File @@ -222,6 +225,7 @@ class KSPNativeConfig( allWarningsAsErrors, mapAnnotationArgumentsInJava, ) { + @KSPArgParserGen(name = "kspNativeArgParser") class Builder : KSPConfig.Builder(), Serializable { lateinit var target: String @@ -314,6 +318,7 @@ class KSPJsConfig( allWarningsAsErrors, mapAnnotationArgumentsInJava, ) { + @KSPArgParserGen(name = "kspJsArgParser") class Builder : KSPConfig.Builder(), Serializable { lateinit var backend: String @@ -411,6 +416,7 @@ class KSPCommonConfig( allWarningsAsErrors, mapAnnotationArgumentsInJava, ) { + @KSPArgParserGen(name = "kspCommonArgParser") class Builder : KSPConfig.Builder(), Serializable { lateinit var targets: List @@ -446,3 +452,49 @@ class KSPCommonConfig( } } } + +fun parseString(arg: String): String { + if (arg.length > 0 && arg[0] == '-') + throw IllegalArgumentException("expecting a String arguemnt but got $arg") + return arg +} + +fun parseBoolean(arg: String): Boolean { + if (arg.length > 0 && arg[0] == '-') + throw IllegalArgumentException("expecting a Boolean arguemnt but got $arg") + return arg.toBoolean() +} + +fun parseFile(arg: String): File { + if (arg.length > 0 && arg[0] == '-') + throw IllegalArgumentException("expecting a File arguemnt but got $arg") + // FIXME: AA isn't happy relative paths for source roots. + return File(arg).absoluteFile +} + +fun parseList(arg: String, transform: (String) -> T): List { + if (arg.length > 0 && arg[0] == '-') + throw IllegalArgumentException("expecting a List but got $arg") + return arg.split(':').map { transform(it) } +} + +fun parseMap(arg: String, transform: (String) -> T): Map { + if (arg.length > 0 && arg[0] == '-') + throw IllegalArgumentException("expecting a Map but got $arg") + return arg.split(':').map { + val (k, v) = it.split('=') + k to transform(v) + }.toMap() +} + +fun parseTarget(arg: String): Target { + if (arg.length > 0 && arg[0] == '-') + throw IllegalArgumentException("expecting a target but got $arg") + return Target(arg, emptyMap()) +} + +fun getArg(args: Array, i: Int): String { + if (i >= args.size || args[i].startsWith("-")) + throw IllegalArgumentException("Expecting an argument") + return args[i] +} diff --git a/common-deps/src/test/kotlin/com/google/devtools/ksp/CommandLineArgParserTest.kt b/common-deps/src/test/kotlin/com/google/devtools/ksp/CommandLineArgParserTest.kt new file mode 100644 index 0000000000..0b160eec66 --- /dev/null +++ b/common-deps/src/test/kotlin/com/google/devtools/ksp/CommandLineArgParserTest.kt @@ -0,0 +1,51 @@ +package com.google.devtools.ksp + +import com.google.devtools.ksp.processing.kspJvmArgParser +import com.google.devtools.ksp.processing.kspJvmArgParserHelp +import org.junit.Assert +import org.junit.Test +import java.io.File + +class CommandLineArgParserTest { + @Test + fun testJvm() { + val args = arrayListOf( + "-module-name=MyModule", + "-source-roots", "/path/to/A:/path/to/B", + "/path/to/processorA.jar", + "-kotlin-output-dir=/path/to/output/kotlin", + "-java-output-dir=/path/to/output/java", + "-class-output-dir=/path/to/output/class", + "-resource-output-dir=/path/to/output/resource", + "-language-version=2.0", + "-api-version=2.0", + "-jvm-target", "21", + "-project-base-dir", "/path/to/base", + "-output-base-dir", "/path/to/output", + "-caches-dir", "/path/to/caches", + "/path/to/processorB.jar:rel/to/processorC.jar", + ).toTypedArray() + val (config, classpath) = kspJvmArgParser(args) + Assert.assertEquals( + listOf("/path/to/A", "/path/to/B").map(::File), + config.sourceRoots + ) + Assert.assertEquals( + "MyModule", + config.moduleName + ) + Assert.assertEquals( + listOf("/path/to/processorA.jar", "/path/to/processorB.jar", "rel/to/processorC.jar"), + classpath + ) + } + + @Test + fun testJvmHelp() { + val helpMsg = kspJvmArgParserHelp() + Assert.assertTrue("* -java-output-dir=File" in helpMsg) + Assert.assertTrue(" -libraries=List" in helpMsg) + Assert.assertTrue("* " in helpMsg) + println(helpMsg) + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 8096e5a8ba..9d447b763b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,3 +19,4 @@ include("symbol-processing-cmdline") include("integration-tests") include("kotlin-analysis-api") include("symbol-processing-aa-embeddable") +include("cmdline-parser-gen") From 9418d446c2ba906c5364b5730ee1673675a7e15b Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Fri, 10 May 2024 16:53:35 -0700 Subject: [PATCH 21/64] Add command line entry points --- .../devtools/ksp/cmdline/KSPCommonMain.kt | 17 +++++++ .../google/devtools/ksp/cmdline/KSPJsMain.kt | 17 +++++++ .../google/devtools/ksp/cmdline/KSPJvmMain.kt | 46 +++++++++++++++++++ .../devtools/ksp/cmdline/KSPNativeMain.kt | 17 +++++++ 4 files changed, 97 insertions(+) create mode 100644 kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPCommonMain.kt create mode 100644 kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPJsMain.kt create mode 100644 kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPJvmMain.kt create mode 100644 kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPNativeMain.kt diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPCommonMain.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPCommonMain.kt new file mode 100644 index 0000000000..e23e23778e --- /dev/null +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPCommonMain.kt @@ -0,0 +1,17 @@ +package com.google.devtools.ksp.cmdline + +import com.google.devtools.ksp.processing.kspCommonArgParser +import com.google.devtools.ksp.processing.kspCommonArgParserHelp + +class KSPCommonMain { + companion object { + @JvmStatic + fun main(args: Array) { + if ("-h" in args || "--help" in args) { + printHelpMsg(kspCommonArgParserHelp()) + } else { + runWithArgs(args, ::kspCommonArgParser) + } + } + } +} diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPJsMain.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPJsMain.kt new file mode 100644 index 0000000000..c4e6236b48 --- /dev/null +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPJsMain.kt @@ -0,0 +1,17 @@ +package com.google.devtools.ksp.cmdline + +import com.google.devtools.ksp.processing.kspJsArgParser +import com.google.devtools.ksp.processing.kspJsArgParserHelp + +class KSPJsMain { + companion object { + @JvmStatic + fun main(args: Array) { + if ("-h" in args || "--help" in args) { + printHelpMsg(kspJsArgParserHelp()) + } else { + runWithArgs(args, ::kspJsArgParser) + } + } + } +} diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPJvmMain.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPJvmMain.kt new file mode 100644 index 0000000000..c2560dfc7b --- /dev/null +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPJvmMain.kt @@ -0,0 +1,46 @@ +package com.google.devtools.ksp.cmdline + +import com.google.devtools.ksp.impl.KotlinSymbolProcessing +import com.google.devtools.ksp.processing.KSPConfig +import com.google.devtools.ksp.processing.KspGradleLogger +import com.google.devtools.ksp.processing.SymbolProcessorProvider +import com.google.devtools.ksp.processing.kspJvmArgParser +import com.google.devtools.ksp.processing.kspJvmArgParserHelp +import java.io.File +import java.net.URLClassLoader +import java.util.ServiceLoader + +class KSPJvmMain { + companion object { + @JvmStatic + fun main(args: Array) { + if ("-h" in args || "--help" in args) { + printHelpMsg(kspJvmArgParserHelp()) + } else { + runWithArgs(args, ::kspJvmArgParser) + } + } + } +} + +internal fun printHelpMsg(optionsList: String) { + println("Available options:") + println(optionsList) + println("where:") + println(" * is required") + println(" List is colon separated. E.g., arg1:arg2:arg3") + println(" Map is in the form key1=value1:key2=value2") +} + +internal fun runWithArgs(args: Array, parse: (Array) -> Pair>) { + val logger = KspGradleLogger(KspGradleLogger.LOGGING_LEVEL_WARN) + val (config, classpath) = parse(args) + val processorClassloader = URLClassLoader(classpath.map { File(it).toURI().toURL() }.toTypedArray()) + + val processorProviders = ServiceLoader.load( + processorClassloader.loadClass("com.google.devtools.ksp.processing.SymbolProcessorProvider"), + processorClassloader + ).toList() as List + + KotlinSymbolProcessing(config, processorProviders, logger).execute() +} diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPNativeMain.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPNativeMain.kt new file mode 100644 index 0000000000..861837e4d0 --- /dev/null +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/cmdline/KSPNativeMain.kt @@ -0,0 +1,17 @@ +package com.google.devtools.ksp.cmdline + +import com.google.devtools.ksp.processing.kspNativeArgParser +import com.google.devtools.ksp.processing.kspNativeArgParserHelp + +class KSPNativeMain { + companion object { + @JvmStatic + fun main(args: Array) { + if ("-h" in args || "--help" in args) { + printHelpMsg(kspNativeArgParserHelp()) + } else { + runWithArgs(args, ::kspNativeArgParser) + } + } + } +} From 51c8e7b18062cb113b15f14b7ccf3929b4c26ccc Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Tue, 14 May 2024 10:54:10 -0700 Subject: [PATCH 22/64] KSP2: Fix support of wasm --- .../google/devtools/ksp/gradle/KspAATask.kt | 2 +- .../devtools/ksp/test/KMPImplementedIT.kt | 24 +++++++++++++++++ .../kmp/annotations/build.gradle.kts | 4 +++ .../test/resources/kmp/settings.gradle.kts | 1 + .../kmp/workload-wasm/build.gradle.kts | 26 +++++++++++++++++++ .../src/wasmJsMain/kotlin/com/example/Bar.kt | 5 ++++ .../src/wasmJsMain/kotlin/com/example/Baz.kt | 5 ++++ .../kotlin/com/example/ToBeValidated.kt | 9 +++++++ .../resources/kmp/workload/build.gradle.kts | 4 +++ .../kmp/workload/src/wasmJsMain/kotlin/Bar.kt | 5 ++++ .../kmp/workload/src/wasmJsMain/kotlin/Baz.kt | 5 ++++ .../ksp/impl/KotlinSymbolProcessing.kt | 2 +- 12 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 integration-tests/src/test/resources/kmp/workload-wasm/build.gradle.kts create mode 100644 integration-tests/src/test/resources/kmp/workload-wasm/src/wasmJsMain/kotlin/com/example/Bar.kt create mode 100644 integration-tests/src/test/resources/kmp/workload-wasm/src/wasmJsMain/kotlin/com/example/Baz.kt create mode 100644 integration-tests/src/test/resources/kmp/workload-wasm/src/wasmJsMain/kotlin/com/example/ToBeValidated.kt create mode 100644 integration-tests/src/test/resources/kmp/workload/src/wasmJsMain/kotlin/Bar.kt create mode 100644 integration-tests/src/test/resources/kmp/workload/src/wasmJsMain/kotlin/Baz.kt 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 3d73e033d6..4b1c93a8ba 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 @@ -475,7 +475,7 @@ abstract class KspAAWorkerAction : WorkAction { KotlinPlatformType.js, KotlinPlatformType.wasm -> { KSPJsConfig.Builder().apply { this.setupSuper() - backend = if (platformType == KotlinPlatformType.js) "JS" else "Wasm" + backend = if (platformType == KotlinPlatformType.js) "JS" else "WASM" }.build() } diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt index a17fcb4680..a97ab87f2f 100644 --- a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt +++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt @@ -108,6 +108,30 @@ class KMPImplementedIT(useKSP2: Boolean) { } } + @Test + fun testWasm() { + Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) + val gradleRunner = GradleRunner.create().withProjectDir(project.root) + + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + "clean", + ":workload-wasm:build" + ).build().let { + Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-wasm:build")?.outcome) + verify( + "workload-wasm/build/libs/workload-wasm-wasm-js-1.0-SNAPSHOT.klib", + listOf( + "default/ir/types.knt" + ) + ) + Assert.assertFalse(it.output.contains("kotlin scripting plugin:")) + Assert.assertTrue(it.output.contains("w: [ksp] platforms: [wasm-js")) + Assert.assertTrue(it.output.contains("w: [ksp] List has superTypes: true")) + checkExecutionOptimizations(it.output) + } + } + @Test fun testJsErrorLog() { Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) diff --git a/integration-tests/src/test/resources/kmp/annotations/build.gradle.kts b/integration-tests/src/test/resources/kmp/annotations/build.gradle.kts index 14fae99b71..9e264acf83 100644 --- a/integration-tests/src/test/resources/kmp/annotations/build.gradle.kts +++ b/integration-tests/src/test/resources/kmp/annotations/build.gradle.kts @@ -12,6 +12,10 @@ kotlin { browser() nodejs() } + wasmJs { + browser() + binaries.executable() + } linuxX64() { } androidNativeX64() { diff --git a/integration-tests/src/test/resources/kmp/settings.gradle.kts b/integration-tests/src/test/resources/kmp/settings.gradle.kts index 651619e4fc..4c542b3917 100644 --- a/integration-tests/src/test/resources/kmp/settings.gradle.kts +++ b/integration-tests/src/test/resources/kmp/settings.gradle.kts @@ -19,6 +19,7 @@ include(":annotations") include(":workload") include(":workload-jvm") include(":workload-js") +include(":workload-wasm") include(":workload-linuxX64") include(":workload-androidNative") include(":test-processor") diff --git a/integration-tests/src/test/resources/kmp/workload-wasm/build.gradle.kts b/integration-tests/src/test/resources/kmp/workload-wasm/build.gradle.kts new file mode 100644 index 0000000000..49160dbb72 --- /dev/null +++ b/integration-tests/src/test/resources/kmp/workload-wasm/build.gradle.kts @@ -0,0 +1,26 @@ +plugins { + kotlin("multiplatform") + id("com.google.devtools.ksp") +} + +version = "1.0-SNAPSHOT" + +kotlin { + wasmJs { + binaries.executable() + browser() + } + sourceSets { + val wasmJsMain by getting { + dependencies { + implementation(project(":annotations")) + } + } + } +} + +dependencies { + add("kspCommonMainMetadata", project(":test-processor")) + add("kspWasmJs", project(":test-processor")) + add("kspWasmJsTest", project(":test-processor")) +} diff --git a/integration-tests/src/test/resources/kmp/workload-wasm/src/wasmJsMain/kotlin/com/example/Bar.kt b/integration-tests/src/test/resources/kmp/workload-wasm/src/wasmJsMain/kotlin/com/example/Bar.kt new file mode 100644 index 0000000000..480d3cb24e --- /dev/null +++ b/integration-tests/src/test/resources/kmp/workload-wasm/src/wasmJsMain/kotlin/com/example/Bar.kt @@ -0,0 +1,5 @@ +package com.example + +class Bar { + val baz = Foo().baz +} diff --git a/integration-tests/src/test/resources/kmp/workload-wasm/src/wasmJsMain/kotlin/com/example/Baz.kt b/integration-tests/src/test/resources/kmp/workload-wasm/src/wasmJsMain/kotlin/com/example/Baz.kt new file mode 100644 index 0000000000..830155982a --- /dev/null +++ b/integration-tests/src/test/resources/kmp/workload-wasm/src/wasmJsMain/kotlin/com/example/Baz.kt @@ -0,0 +1,5 @@ +package com.example + +class Baz { + val bar = Foo().bar +} diff --git a/integration-tests/src/test/resources/kmp/workload-wasm/src/wasmJsMain/kotlin/com/example/ToBeValidated.kt b/integration-tests/src/test/resources/kmp/workload-wasm/src/wasmJsMain/kotlin/com/example/ToBeValidated.kt new file mode 100644 index 0000000000..05497afbc9 --- /dev/null +++ b/integration-tests/src/test/resources/kmp/workload-wasm/src/wasmJsMain/kotlin/com/example/ToBeValidated.kt @@ -0,0 +1,9 @@ +package com.example + +// https://github.com/google/ksp/issues/632 +@MyAnnotation +@ExperimentalMultiplatform +class ToBeValidated { + // https://github.com/google/ksp/issues/574 + val ToBeInferred = listOf("string") +} diff --git a/integration-tests/src/test/resources/kmp/workload/build.gradle.kts b/integration-tests/src/test/resources/kmp/workload/build.gradle.kts index b555a4d3fd..09127e9ef2 100644 --- a/integration-tests/src/test/resources/kmp/workload/build.gradle.kts +++ b/integration-tests/src/test/resources/kmp/workload/build.gradle.kts @@ -13,6 +13,10 @@ kotlin { browser() nodejs() } + wasmJs { + browser() + binaries.executable() + } linuxX64() { binaries { executable() diff --git a/integration-tests/src/test/resources/kmp/workload/src/wasmJsMain/kotlin/Bar.kt b/integration-tests/src/test/resources/kmp/workload/src/wasmJsMain/kotlin/Bar.kt new file mode 100644 index 0000000000..480d3cb24e --- /dev/null +++ b/integration-tests/src/test/resources/kmp/workload/src/wasmJsMain/kotlin/Bar.kt @@ -0,0 +1,5 @@ +package com.example + +class Bar { + val baz = Foo().baz +} diff --git a/integration-tests/src/test/resources/kmp/workload/src/wasmJsMain/kotlin/Baz.kt b/integration-tests/src/test/resources/kmp/workload/src/wasmJsMain/kotlin/Baz.kt new file mode 100644 index 0000000000..830155982a --- /dev/null +++ b/integration-tests/src/test/resources/kmp/workload/src/wasmJsMain/kotlin/Baz.kt @@ -0,0 +1,5 @@ +package com.example + +class Baz { + val bar = Foo().bar +} 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 74c23360b0..c3d9a7ad15 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 @@ -182,7 +182,7 @@ class KotlinSymbolProcessing( JvmPlatforms.jvmPlatformByTargetVersion(jvmTarget) } is KSPJsConfig -> when (kspConfig.backend) { - "WASM" -> WasmPlatforms.Default + "WASM" -> WasmPlatforms.wasmJs "JS" -> JsPlatforms.defaultJsPlatform else -> throw IllegalArgumentException("Unknown JS backend: ${kspConfig.backend}") } From c59f7bb3f96cae524ed7bd30345b54928a6edd2e Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Thu, 9 May 2024 17:23:19 -0700 Subject: [PATCH 23/64] Return KSClassDeclarationEnumEntryImpl for enum entry annotation values. --- .../devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt | 6 ++---- .../impl/symbol/kotlin/KSClassDeclarationEnumEntryImpl.kt | 6 +++--- kotlin-analysis-api/testData/annotationValue/java.kt | 4 ++-- .../test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt | 1 - 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt index 83e3b79b44..1730461fe5 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt @@ -4,6 +4,7 @@ import com.google.devtools.ksp.common.KSObjectCache import com.google.devtools.ksp.common.impl.KSNameImpl import com.google.devtools.ksp.getClassDeclarationByName import com.google.devtools.ksp.impl.ResolverAAImpl +import com.google.devtools.ksp.impl.symbol.kotlin.KSClassDeclarationEnumEntryImpl import com.google.devtools.ksp.impl.symbol.kotlin.KSErrorType import com.google.devtools.ksp.impl.symbol.kotlin.KSValueArgumentImpl import com.google.devtools.ksp.impl.symbol.kotlin.analyze @@ -202,10 +203,7 @@ fun calcValue(value: PsiAnnotationMemberValue?): Any? { }?.declarations?.find { it is KSClassDeclaration && it.classKind == ClassKind.ENUM_ENTRY && it.simpleName.asString() == result.name - }?.let { (it as KSClassDeclaration).asStarProjectedType() } - ?.let { - return it - } + } as? KSClassDeclarationEnumEntryImpl } else { 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 4fb19707c0..26237027c5 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 @@ -102,10 +102,10 @@ class KSClassDeclarationEnumEntryImpl private constructor(private val ktEnumEntr ktEnumEntrySymbol.psi.toLocation() } - override val parent: KSNode? by lazy { + override val parent: KSNode by lazy { analyze { - (ktEnumEntrySymbol.getContainingSymbol() as? KtNamedClassOrObjectSymbol) - ?.let { KSClassDeclarationImpl.getCached(it) } + (ktEnumEntrySymbol.getContainingSymbol() as KtNamedClassOrObjectSymbol) + .let { KSClassDeclarationImpl.getCached(it) } } } diff --git a/kotlin-analysis-api/testData/annotationValue/java.kt b/kotlin-analysis-api/testData/annotationValue/java.kt index 5c88bacb37..4a1735e5b7 100644 --- a/kotlin-analysis-api/testData/annotationValue/java.kt +++ b/kotlin-analysis-api/testData/annotationValue/java.kt @@ -32,8 +32,8 @@ // Array // @Foo // @Suppress -// RGB -// JavaEnum +// G +// ONE // 31 // [warning1, warning 2] // END diff --git a/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt b/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt index 165c05e09c..5ca58fb6d3 100644 --- a/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt +++ b/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt @@ -89,7 +89,6 @@ class KSPAATest : AbstractKSPAATest() { runTest("../kotlin-analysis-api/testData/annotationValue/java.kt") } - @Disabled @TestMetadata("annotationValue_kt.kt") @Test fun testAnnotationValue_kt() { From a046228d4d6109ea66a961db215564fc738fb765 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Tue, 14 May 2024 10:23:38 -0700 Subject: [PATCH 24/64] improve enum entry toString() --- .../kotlin/com/google/devtools/ksp/utils.kt | 2 + .../kotlin/KSClassDeclarationEnumEntryImpl.kt | 4 + .../testData/annotationValue/java.kt | 4 +- .../testData/annotationValue/kotlin.kt | 96 +++++++++++++++++++ kotlin-analysis-api/testData/parent.kt | 26 ++--- .../com/google/devtools/ksp/test/KSPAATest.kt | 2 +- 6 files changed, 118 insertions(+), 16 deletions(-) create mode 100644 kotlin-analysis-api/testData/annotationValue/kotlin.kt diff --git a/api/src/main/kotlin/com/google/devtools/ksp/utils.kt b/api/src/main/kotlin/com/google/devtools/ksp/utils.kt index d0e4207a6e..15a4cac39a 100644 --- a/api/src/main/kotlin/com/google/devtools/ksp/utils.kt +++ b/api/src/main/kotlin/com/google/devtools/ksp/utils.kt @@ -494,6 +494,8 @@ private fun Any.asEnum(returnType: Class): T = null, if (this is KSType) { this.declaration.simpleName.getShortName() + } else if (this is KSClassDeclaration) { + this.simpleName.getShortName() } else { this.toString() } 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 26237027c5..6946d5ed97 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 @@ -120,6 +120,10 @@ class KSClassDeclarationEnumEntryImpl private constructor(private val ktEnumEntr emptySequence() } + override fun toString(): String { + return "$parent.${simpleName.asString()}" + } + override fun defer(): Restorable? { return ktEnumEntrySymbol.defer(Companion::getCached) } diff --git a/kotlin-analysis-api/testData/annotationValue/java.kt b/kotlin-analysis-api/testData/annotationValue/java.kt index 4a1735e5b7..c5bd2a3e37 100644 --- a/kotlin-analysis-api/testData/annotationValue/java.kt +++ b/kotlin-analysis-api/testData/annotationValue/java.kt @@ -32,8 +32,8 @@ // Array // @Foo // @Suppress -// G -// ONE +// RGB.G +// JavaEnum.ONE // 31 // [warning1, warning 2] // END diff --git a/kotlin-analysis-api/testData/annotationValue/kotlin.kt b/kotlin-analysis-api/testData/annotationValue/kotlin.kt new file mode 100644 index 0000000000..cb62ad2b65 --- /dev/null +++ b/kotlin-analysis-api/testData/annotationValue/kotlin.kt @@ -0,0 +1,96 @@ +/* + * 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. + */ + +// WITH_RUNTIME +// TEST PROCESSOR: AnnotationArgumentProcessor +// EXPECTED: +// defaultInNested +// SomeClass$WithDollarSign +// Str +// 42 +// Foo +// File +// Local +// Array +// Error type synthetic declaration +// [, Foo] +// @Foo +// @Suppress +// RGB.G +// JavaEnum.ONE +// 31 +// Throws +// END +// FILE: a.kt + +enum class RGB { + R, G, B +} + +class ThrowsClass { + @Throws(Exception::class) + protected open fun throwsException() { + } +} + +annotation class Foo(val s: Int) { + annotation class Nested(val nestedDefault:String = "defaultInNested") +} +class `SomeClass$WithDollarSign` + +annotation class MyAnnotation(val clazz: KClass<*>) + + +annotation class Bar( + val argStr: String, + val argInt: Int, + val argClsUser: kotlin.reflect.KClass<*>, + val argClsLib: kotlin.reflect.KClass<*>, + val argClsLocal: kotlin.reflect.KClass<*>, + val argClsArray: kotlin.reflect.KClass<*>, + val argClsMissing: kotlin.reflect.KClass<*>, + val argClsMissingInArray: Array>, + val argAnnoUser: Foo, + val argAnnoLib: Suppress, + val argEnum: RGB, + val argJavaNum: JavaEnum, + val argDef: Int = 31 +) + +fun Fun() { + @Foo.Nested + @MyAnnotation(`SomeClass$WithDollarSign`::class) + @Bar( + "Str", + 40 + 2, + Foo::class, + java.io.File::class, + Local::class, + Array::class, + Missing::class, + [Missing::class, Foo::class], + Foo(17), + Suppress("name1", "name2"), + RGB.G, + JavaEnum.ONE + ) + class Local +} + +// FILE: JavaEnum.java + +enum JavaEnum { ONE, TWO, THREE } diff --git a/kotlin-analysis-api/testData/parent.kt b/kotlin-analysis-api/testData/parent.kt index 06bf77a3bf..b84b04480e 100644 --- a/kotlin-analysis-api/testData/parent.kt +++ b/kotlin-analysis-api/testData/parent.kt @@ -50,9 +50,9 @@ // parent of Enum: Enum<(RGB..RGB?)> // parent of Enum<(RGB..RGB?)>: RGB // parent of RGB: File: B.java -// parent of R: RGB -// parent of G: RGB -// parent of B: RGB +// parent of RGB.R: RGB +// parent of RGB.G: RGB +// parent of RGB.B: RGB // parent of Array: values // parent of values: RGB // parent of String: value @@ -156,10 +156,10 @@ // parent of CMYK: File: a.kt // parent of CMYK: synthetic constructor for CMYK // parent of synthetic constructor for CMYK: CMYK -// parent of C: CMYK -// parent of M: CMYK -// parent of Y: CMYK -// parent of K: CMYK +// parent of CMYK.C: CMYK +// parent of CMYK.M: CMYK +// parent of CMYK.Y: CMYK +// parent of CMYK.K: CMYK // parent of Array: values // parent of values: CMYK // parent of String: value @@ -179,9 +179,9 @@ // parent of YUV: YUV // parent of YUV: // parent of : YUV -// parent of Y: YUV -// parent of U: YUV -// parent of V: YUV +// parent of YUV.Y: YUV +// parent of YUV.U: YUV +// parent of YUV.V: YUV // parent of YUV: YUV // parent of YUV: INVARIANT YUV // parent of INVARIANT YUV: Array @@ -215,9 +215,9 @@ // parent of HSV: HSV // parent of HSV: // parent of : HSV -// parent of H: HSV -// parent of S: HSV -// parent of V: HSV +// parent of HSV.H: HSV +// parent of HSV.S: HSV +// parent of HSV.V: HSV // parent of Array: values // parent of values: HSV // parent of String: value diff --git a/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt b/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt index 5ca58fb6d3..f5e7249f19 100644 --- a/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt +++ b/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt @@ -92,7 +92,7 @@ class KSPAATest : AbstractKSPAATest() { @TestMetadata("annotationValue_kt.kt") @Test fun testAnnotationValue_kt() { - runTest("../test-utils/testData/api/annotationValue_kt.kt") + runTest("../kotlin-analysis-api/testData/annotationValue/kotlin.kt") } @TestMetadata("annotationWithArrayValue.kt") From ca7b06cbb69fb4d86ac3ab24cd0694d3a40553c5 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Wed, 15 May 2024 10:39:55 -0700 Subject: [PATCH 25/64] Reuse Kotlin indexes in incremental providers Also simplify finding Java sources. --- .../ksp/impl/KotlinSymbolProcessing.kt | 89 +++++++++++---- .../IncrementalKotlinDeclarationProvider.kt | 107 ------------------ ...ementalKotlinDeclarationProviderFactory.kt | 42 +++++++ .../IncrementalKotlinPackageProvider.kt | 73 ------------ ...IncrementalKotlinPackageProviderFactory.kt | 25 ++++ .../KspStandaloneDirectInheritorsProvider.kt | 20 ++-- 6 files changed, 140 insertions(+), 216 deletions(-) delete mode 100644 kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProvider.kt create mode 100644 kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProviderFactory.kt delete mode 100644 kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinPackageProvider.kt create mode 100644 kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinPackageProviderFactory.kt 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 c3d9a7ad15..bea08c36b6 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 @@ -50,7 +50,6 @@ import com.intellij.openapi.roots.PackageIndex import com.intellij.openapi.util.Disposer import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.VirtualFile -import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.PsiFileSystemItem import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiManager @@ -125,7 +124,6 @@ import org.jetbrains.kotlin.platform.konan.NativePlatforms import org.jetbrains.kotlin.platform.wasm.WasmPlatforms import org.jetbrains.kotlin.psi.KtFile import java.io.File -import java.nio.file.Files import java.nio.file.Path class KotlinSymbolProcessing( @@ -356,11 +354,10 @@ class KotlinSymbolProcessing( compilerConfiguration: CompilerConfiguration ): List { val project = kotlinCoreProjectEnvironment.project - val psiManager = PsiManager.getInstance(project) val ktFiles = createSourceFilesFromSourceRoots( compilerConfiguration, project, compilerConfiguration.kotlinSourceRoots ).toSet().toList() - val psiFiles = getPsiFilesFromPaths( + val allJavaFiles = getPsiFilesFromPaths( project, getSourceFilePaths(compilerConfiguration, includeDirectoryRoot = true) ) @@ -378,21 +375,47 @@ class KotlinSymbolProcessing( ).update(ktFiles) // Update Java providers for newly generated source files. - reinitJavaFileManager(kotlinCoreProjectEnvironment, modules, psiFiles) - - val localFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL) - val javaFiles = if (kspConfig is KSPJvmConfig) { - val javaRoots = kspConfig.javaSourceRoots + kspConfig.javaOutputDir - // Get non-symbolic paths first - javaRoots.sortedBy { Files.isSymbolicLink(it.toPath()) } - .flatMap { root -> root.walk().filter { it.isFile && it.extension == "java" }.toList() } - // This time is for .java files - .sortedBy { Files.isSymbolicLink(it.toPath()) } - .distinctBy { it.canonicalPath } - .mapNotNull { localFileSystem.findFileByPath(it.path)?.let { psiManager.findFile(it) } as? PsiJavaFile } - } else { - emptyList() - } + reinitJavaFileManager(kotlinCoreProjectEnvironment, modules, allJavaFiles) + + return ktFiles.map { analyze { KSFileImpl.getCached(it.getFileSymbol()) } } + + allJavaFiles.map { KSFileJavaImpl.getCached(it) } + } + + private fun prepareNewKSFiles( + kotlinCoreProjectEnvironment: KotlinCoreProjectEnvironment, + modules: List, + compilerConfiguration: CompilerConfiguration, + newKotlinFiles: List, + newJavaFiles: List, + ): List { + val project = kotlinCoreProjectEnvironment.project + val ktFiles = getPsiFilesFromPaths( + project, + newKotlinFiles.map { it.toPath() }.toSet() + ) + val javaFiles = getPsiFilesFromPaths( + project, + newJavaFiles.map { it.toPath() }.toSet() + ) + val allJavaFiles = getPsiFilesFromPaths( + project, + getSourceFilePaths(compilerConfiguration, includeDirectoryRoot = true) + ) + + // Update Kotlin providers for newly generated source files. + ( + project.getService( + KotlinDeclarationProviderFactory::class.java + ) as IncrementalKotlinDeclarationProviderFactory + ).update(ktFiles) + ( + project.getService( + KotlinPackageProviderFactory::class.java + ) as IncrementalKotlinPackageProviderFactory + ).update(ktFiles) + + // Update Java providers for newly generated source files. + reinitJavaFileManager(kotlinCoreProjectEnvironment, modules, allJavaFiles) return ktFiles.map { analyze { KSFileImpl.getCached(it.getFileSymbol()) } } + javaFiles.map { KSFileJavaImpl.getCached(it) } @@ -533,7 +556,7 @@ class KotlinSymbolProcessing( } // Drop caches - KotlinGlobalModificationService.getInstance(project).publishGlobalModuleStateModification() + KotlinGlobalModificationService.getInstance(project).publishGlobalSourceModuleStateModification() KtAnalysisSessionProvider.getInstance(project).clearCaches() psiManager.dropResolveCaches() psiManager.dropPsiCaches() @@ -542,10 +565,26 @@ class KotlinSymbolProcessing( val newFilePaths = codeGenerator.generatedFile.filter { it.extension == "kt" || it.extension == "java" } .map { it.canonicalPath }.toSet() - allDirtyKSFiles = prepareAllKSFiles(kotlinCoreProjectEnvironment, modules, compilerConfiguration).filter { - it.filePath !in allCleanFilePaths - } - newKSFiles = allDirtyKSFiles.filter { it.filePath in newFilePaths } + newKSFiles = prepareNewKSFiles( + kotlinCoreProjectEnvironment, + modules, + compilerConfiguration, + newFilePaths.filter { it.endsWith(".kt") }.map { File(it) }.toList(), + newFilePaths.filter { it.endsWith(".java") }.map { File(it) }.toList(), + ) + // Now that caches are dropped, KtSymbols and KS* are invalid. They need to be re-created from PSI. + allDirtyKSFiles = allDirtyKSFiles.map { + when (it) { + is KSFileImpl -> { + val ktFile = it.ktFileSymbol.psi!! as KtFile + analyze { KSFileImpl.getCached(ktFile.getFileSymbol()) } + } + is KSFileJavaImpl -> { + KSFileJavaImpl.getCached(it.psi) + } + else -> throw IllegalArgumentException("Unknown KSFile implementation: $it") + } + } + newKSFiles incrementalContext.registerGeneratedFiles(newKSFiles) codeGenerator.closeFiles() } @@ -612,7 +651,7 @@ class DirectoriesScope( private fun reinitJavaFileManager( environment: KotlinCoreProjectEnvironment, modules: List, - sourceFiles: List, + sourceFiles: List, ) { val project = environment.project val javaFileManager = project.getService(JavaFileManager::class.java) as KotlinCliJavaFileManagerImpl diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProvider.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProvider.kt deleted file mode 100644 index 005209fab8..0000000000 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProvider.kt +++ /dev/null @@ -1,107 +0,0 @@ -package com.google.devtools.ksp.standalone - -import com.intellij.openapi.project.Project -import com.intellij.psi.search.GlobalSearchScope -import org.jetbrains.kotlin.analysis.project.structure.KtModule -import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider -import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProviderFactory -import org.jetbrains.kotlin.analysis.providers.impl.KotlinStaticDeclarationProviderFactory -import org.jetbrains.kotlin.name.CallableId -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.KtClassLikeDeclaration -import org.jetbrains.kotlin.psi.KtClassOrObject -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtNamedFunction -import org.jetbrains.kotlin.psi.KtProperty -import org.jetbrains.kotlin.psi.KtScript -import org.jetbrains.kotlin.psi.KtTypeAlias - -class IncrementalKotlinDeclarationProvider(var del: KotlinDeclarationProvider) : KotlinDeclarationProvider() { - override val hasSpecificCallablePackageNamesComputation: Boolean - get() = del.hasSpecificCallablePackageNamesComputation - override val hasSpecificClassifierPackageNamesComputation: Boolean - get() = del.hasSpecificClassifierPackageNamesComputation - - override fun findFilesForFacade(facadeFqName: FqName): Collection { - return del.findFilesForFacade(facadeFqName) - } - - override fun findFilesForFacadeByPackage(packageFqName: FqName): Collection { - return del.findFilesForFacadeByPackage(packageFqName) - } - - override fun findFilesForScript(scriptFqName: FqName): Collection { - return del.findFilesForScript(scriptFqName) - } - - override fun findInternalFilesForFacade(facadeFqName: FqName): Collection { - return del.findInternalFilesForFacade(facadeFqName) - } - - override fun getAllClassesByClassId(classId: ClassId): Collection { - return del.getAllClassesByClassId(classId) - } - - override fun getAllTypeAliasesByClassId(classId: ClassId): Collection { - return del.getAllTypeAliasesByClassId(classId) - } - - override fun getClassLikeDeclarationByClassId(classId: ClassId): KtClassLikeDeclaration? { - return del.getClassLikeDeclarationByClassId(classId) - } - - override fun getTopLevelCallableFiles(callableId: CallableId): Collection { - return del.getTopLevelCallableFiles(callableId) - } - - override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set { - return del.getTopLevelCallableNamesInPackage(packageFqName) - } - - override fun getTopLevelFunctions(callableId: CallableId): Collection { - return del.getTopLevelFunctions(callableId) - } - - override fun getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName: FqName): Set { - return del.getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName) - } - - override fun getTopLevelProperties(callableId: CallableId): Collection { - return del.getTopLevelProperties(callableId) - } -} - -class IncrementalKotlinDeclarationProviderFactory( - private val project: Project, -) : KotlinDeclarationProviderFactory() { - var provider: IncrementalKotlinDeclarationProvider? = null - private lateinit var scope: GlobalSearchScope - private var contextualModule: KtModule? = null - private var files: Collection = emptyList() - lateinit var staticFactory: KotlinDeclarationProviderFactory - - override fun createDeclarationProvider( - scope: GlobalSearchScope, - contextualModule: KtModule? - ): KotlinDeclarationProvider { - this.scope = scope - this.contextualModule = contextualModule - return IncrementalKotlinDeclarationProvider(createDelegateProvider()).also { - provider = it - } - } - - fun update(files: Collection) { - this.files = files - this.staticFactory = KotlinStaticDeclarationProviderFactory(project, files) - provider?.let { - it.del = createDelegateProvider() - } - } - - private fun createDelegateProvider(): KotlinDeclarationProvider { - return staticFactory.createDeclarationProvider(scope, contextualModule) - } -} diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProviderFactory.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProviderFactory.kt new file mode 100644 index 0000000000..4cf534b207 --- /dev/null +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProviderFactory.kt @@ -0,0 +1,42 @@ +package com.google.devtools.ksp.standalone + +import com.intellij.openapi.project.Project +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider +import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProviderFactory +import org.jetbrains.kotlin.analysis.providers.impl.KotlinStaticDeclarationProviderFactory +import org.jetbrains.kotlin.analysis.providers.impl.declarationProviders.CompositeKotlinDeclarationProvider +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtTypeAlias + +class IncrementalKotlinDeclarationProviderFactory( + private val project: Project, +) : KotlinDeclarationProviderFactory() { + private val staticFactories: MutableList = mutableListOf() + + override fun createDeclarationProvider( + scope: GlobalSearchScope, + contextualModule: KtModule? + ): KotlinDeclarationProvider { + val providers = staticFactories.map { it.createDeclarationProvider(scope, contextualModule) } + return CompositeKotlinDeclarationProvider.create(providers) + } + + fun update(files: Collection) { + val staticFactory = KotlinStaticDeclarationProviderFactory(project, files) + staticFactories.add(staticFactory) + } + + fun getDirectInheritorCandidates(baseClassName: Name): Set = + staticFactories.flatMapTo(mutableSetOf()) { + it.getDirectInheritorCandidates(baseClassName) + } + + fun getInheritableTypeAliases(aliasedName: Name): Set = + staticFactories.flatMapTo(mutableSetOf()) { + it.getInheritableTypeAliases(aliasedName) + } +} diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinPackageProvider.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinPackageProvider.kt deleted file mode 100644 index 947354d083..0000000000 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinPackageProvider.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.google.devtools.ksp.standalone - -import com.intellij.openapi.project.Project -import com.intellij.psi.search.GlobalSearchScope -import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider -import org.jetbrains.kotlin.analysis.providers.KotlinPackageProviderFactory -import org.jetbrains.kotlin.analysis.providers.impl.KotlinStaticPackageProviderFactory -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.platform.TargetPlatform -import org.jetbrains.kotlin.psi.KtFile - -class IncrementalKotlinPackageProvider(var del: KotlinPackageProvider) : KotlinPackageProvider() { - override fun doesKotlinOnlyPackageExist(packageFqName: FqName): Boolean { - return del.doesKotlinOnlyPackageExist(packageFqName) - } - - override fun doesPackageExist(packageFqName: FqName, platform: TargetPlatform): Boolean { - return del.doesPackageExist(packageFqName, platform) - } - - override fun doesPlatformSpecificPackageExist(packageFqName: FqName, platform: TargetPlatform): Boolean { - return del.doesPlatformSpecificPackageExist(packageFqName, platform) - } - - override fun getKotlinOnlySubPackagesFqNames(packageFqName: FqName, nameFilter: (Name) -> Boolean): Set { - return del.getKotlinOnlySubPackagesFqNames(packageFqName, nameFilter) - } - - override fun getPlatformSpecificSubPackagesFqNames( - packageFqName: FqName, - platform: TargetPlatform, - nameFilter: (Name) -> Boolean - ): Set { - return del.getPlatformSpecificSubPackagesFqNames(packageFqName, platform, nameFilter) - } - - override fun getSubPackageFqNames( - packageFqName: FqName, - platform: TargetPlatform, - nameFilter: (Name) -> Boolean - ): Set { - return del.getSubPackageFqNames(packageFqName, platform, nameFilter) - } -} - -class IncrementalKotlinPackageProviderFactory( - private val project: Project, -) : KotlinPackageProviderFactory() { - private var provider: IncrementalKotlinPackageProvider? = null - private lateinit var scope: GlobalSearchScope - private var files: Collection = emptyList() - private lateinit var staticFactory: KotlinPackageProviderFactory - - override fun createPackageProvider(searchScope: GlobalSearchScope): KotlinPackageProvider { - this.scope = searchScope - return IncrementalKotlinPackageProvider(createDelegateProvider()).also { - provider = it - } - } - - fun update(files: Collection) { - this.files = files - this.staticFactory = KotlinStaticPackageProviderFactory(project, files) - provider?.let { - it.del = createDelegateProvider() - } - } - - private fun createDelegateProvider(): KotlinPackageProvider { - return staticFactory.createPackageProvider(scope) - } -} 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 new file mode 100644 index 0000000000..81b2658672 --- /dev/null +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinPackageProviderFactory.kt @@ -0,0 +1,25 @@ +package com.google.devtools.ksp.standalone + +import com.intellij.openapi.project.Project +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider +import org.jetbrains.kotlin.analysis.providers.KotlinPackageProviderFactory +import org.jetbrains.kotlin.analysis.providers.impl.KotlinStaticPackageProviderFactory +import org.jetbrains.kotlin.analysis.providers.impl.packageProviders.CompositeKotlinPackageProvider +import org.jetbrains.kotlin.psi.KtFile + +class IncrementalKotlinPackageProviderFactory( + private val project: Project, +) : KotlinPackageProviderFactory() { + private val staticFactories: MutableList = mutableListOf() + + override fun createPackageProvider(searchScope: GlobalSearchScope): KotlinPackageProvider { + val providers = staticFactories.map { it.createPackageProvider(searchScope) } + return CompositeKotlinPackageProvider.create(providers) + } + + fun update(files: Collection) { + val staticFactory = KotlinStaticPackageProviderFactory(project, files) + staticFactories.add(staticFactory) + } +} diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspStandaloneDirectInheritorsProvider.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspStandaloneDirectInheritorsProvider.kt index 3f114bfaf3..c8dec4c9b9 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspStandaloneDirectInheritorsProvider.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/KspStandaloneDirectInheritorsProvider.kt @@ -24,15 +24,13 @@ import org.jetbrains.kotlin.psi.psiUtil.contains // TODO: copied from upstream as a workaround, remove after upstream fixes standalone session builder for KSP. @OptIn(LLFirInternals::class, SymbolInternals::class) class KspStandaloneDirectInheritorsProvider(private val project: Project) : KotlinDirectInheritorsProvider { - private val staticDeclarationProviderFactory by lazy { - ( - (KotlinDeclarationProviderFactory.getInstance(project) as? IncrementalKotlinDeclarationProviderFactory) - ?.staticFactory as? KotlinStaticDeclarationProviderFactory - ) ?: error( - "KotlinStandaloneDirectInheritorsProvider" + - "` expects the following declaration provider factory to be" + - " registered: `${KotlinStaticDeclarationProviderFactory::class.simpleName}`" - ) + private val declarationProviderFactory by lazy { + (KotlinDeclarationProviderFactory.getInstance(project) as? IncrementalKotlinDeclarationProviderFactory) + ?: error( + "KotlinStandaloneDirectInheritorsProvider" + + "` expects the following declaration provider factory to be" + + " registered: `${KotlinStaticDeclarationProviderFactory::class.simpleName}`" + ) } override fun getDirectKotlinInheritors( @@ -45,7 +43,7 @@ class KspStandaloneDirectInheritorsProvider(private val project: Project) : Kotl val aliases = mutableSetOf(classId.shortClassName) calculateAliases(classId.shortClassName, aliases) - val possibleInheritors = aliases.flatMap { staticDeclarationProviderFactory.getDirectInheritorCandidates(it) } + val possibleInheritors = aliases.flatMap { declarationProviderFactory.getDirectInheritorCandidates(it) } if (possibleInheritors.isEmpty()) { return emptyList() @@ -71,7 +69,7 @@ class KspStandaloneDirectInheritorsProvider(private val project: Project) : Kotl } private fun calculateAliases(aliasedName: Name, aliases: MutableSet) { - staticDeclarationProviderFactory.getInheritableTypeAliases(aliasedName).forEach { alias -> + declarationProviderFactory.getInheritableTypeAliases(aliasedName).forEach { alias -> val aliasName = alias.nameAsSafeName val isNewAliasName = aliases.add(aliasName) if (isNewAliasName) { From 4785305754bdbdff31aebd7c75e48e988fac16a6 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Thu, 16 May 2024 15:14:31 -0700 Subject: [PATCH 26/64] special handling for java property accessors override checking --- .../impl/symbol/kotlin/KSFunctionDeclarationImpl.kt | 6 +++++- .../symbol/kotlin/KSPropertyDeclarationJavaImpl.kt | 10 +--------- .../kotlin/com/google/devtools/ksp/test/KSPAATest.kt | 1 - 3 files changed, 6 insertions(+), 11 deletions(-) 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 2079cfe6eb..b64c299f6b 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 @@ -107,7 +107,11 @@ class KSFunctionDeclarationImpl private constructor(internal val ktFunctionSymbo } recordLookupForPropertyOrMethod(this) return analyze { - ktFunctionSymbol.getDirectlyOverriddenSymbols().firstOrNull()?.unwrapFakeOverrides?.toKSDeclaration() + if (ktFunctionSymbol is KtPropertyAccessorSymbol) { + (parentDeclaration as? KSPropertyDeclarationImpl)?.ktPropertySymbol + } else { + ktFunctionSymbol + }?.getDirectlyOverriddenSymbols()?.firstOrNull()?.unwrapFakeOverrides?.toKSDeclaration() }?.also { recordLookupForPropertyOrMethod(it) } } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationJavaImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationJavaImpl.kt index d93f16b7db..6e9e77b5d0 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationJavaImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationJavaImpl.kt @@ -1,11 +1,8 @@ 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.impl.ResolverAAImpl -import com.google.devtools.ksp.impl.recordLookupForPropertyOrMethod -import com.google.devtools.ksp.impl.recordLookupWithSupertypes import com.google.devtools.ksp.impl.symbol.kotlin.resolved.KSTypeReferenceResolvedImpl import com.google.devtools.ksp.symbol.* import org.jetbrains.kotlin.analysis.api.symbols.KtJavaFieldSymbol @@ -44,12 +41,7 @@ class KSPropertyDeclarationJavaImpl private constructor(val ktJavaFieldSymbol: K } override fun findOverridee(): KSPropertyDeclaration? { - closestClassDeclaration()?.asStarProjectedType()?.let { - recordLookupWithSupertypes((it as KSTypeImpl).type) - } - recordLookupForPropertyOrMethod(this) - TODO("Not yet implemented") - // ?.also { recordLookupForPropertyOrMethod(it) } + return null } override fun asMemberOf(containing: KSType): KSType { diff --git a/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt b/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt index f5e7249f19..ef4f0008a3 100644 --- a/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt +++ b/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt @@ -409,7 +409,6 @@ class KSPAATest : AbstractKSPAATest() { runTest("../test-utils/testData/api/overridee/conflictingOverride.kt") } - @Disabled @TestMetadata("javaAccessor.kt") @Test fun testJavaAccessor() { From 760fe28f64cb545c6184cc10f4b58424afa51671 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Thu, 16 May 2024 15:24:02 -0700 Subject: [PATCH 27/64] KSP2: Reuse Java indexes --- .../ksp/impl/KotlinSymbolProcessing.kt | 109 ++----------- .../standalone/IncrementalJavaFileManager.kt | 149 ++++++++++++++++++ 2 files changed, 159 insertions(+), 99 deletions(-) create mode 100644 kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalJavaFileManager.kt 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 bea08c36b6..748ff82bb1 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 @@ -31,6 +31,7 @@ import com.google.devtools.ksp.impl.symbol.kotlin.KSFileJavaImpl import com.google.devtools.ksp.impl.symbol.kotlin.Restorable import com.google.devtools.ksp.impl.symbol.kotlin.analyze import com.google.devtools.ksp.processing.* +import com.google.devtools.ksp.standalone.IncrementalJavaFileManager import com.google.devtools.ksp.standalone.IncrementalKotlinDeclarationProviderFactory import com.google.devtools.ksp.standalone.IncrementalKotlinPackageProviderFactory import com.google.devtools.ksp.standalone.KspStandaloneDirectInheritorsProvider @@ -40,13 +41,10 @@ import com.google.devtools.ksp.symbol.KSFile import com.google.devtools.ksp.symbol.KSNode import com.google.devtools.ksp.symbol.Origin import com.intellij.core.CoreApplicationEnvironment -import com.intellij.core.CorePackageIndex -import com.intellij.ide.highlighter.JavaFileType import com.intellij.mock.MockProject import com.intellij.openapi.Disposable import com.intellij.openapi.application.Application import com.intellij.openapi.project.Project -import com.intellij.openapi.roots.PackageIndex import com.intellij.openapi.util.Disposer import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.VirtualFile @@ -55,10 +53,8 @@ import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiManager import com.intellij.psi.PsiTreeChangeAdapter import com.intellij.psi.PsiTreeChangeListener -import com.intellij.psi.impl.file.impl.JavaFileManager import com.intellij.psi.search.DelegatingGlobalSearchScope import com.intellij.psi.search.GlobalSearchScope -import com.intellij.psi.search.ProjectScope import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenProvider import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider @@ -83,24 +79,15 @@ import org.jetbrains.kotlin.analysis.providers.impl.* import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCliJavaFileManagerImpl import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreApplicationEnvironmentMode import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment -import org.jetbrains.kotlin.cli.jvm.compiler.computeDefaultRootModules import org.jetbrains.kotlin.cli.jvm.compiler.createSourceFilesFromSourceRoots -import org.jetbrains.kotlin.cli.jvm.compiler.getJavaModuleRoots import org.jetbrains.kotlin.cli.jvm.compiler.setupIdeaStandaloneExecution import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoot import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoots import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots import org.jetbrains.kotlin.cli.jvm.config.jvmModularRoots -import org.jetbrains.kotlin.cli.jvm.index.JavaRoot -import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesDynamicCompoundIndex -import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndexImpl -import org.jetbrains.kotlin.cli.jvm.index.SingleJavaFileRootsIndex -import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleFinder -import org.jetbrains.kotlin.cli.jvm.modules.JavaModuleGraph import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration @@ -351,7 +338,8 @@ class KotlinSymbolProcessing( private fun prepareAllKSFiles( kotlinCoreProjectEnvironment: KotlinCoreProjectEnvironment, modules: List, - compilerConfiguration: CompilerConfiguration + compilerConfiguration: CompilerConfiguration, + javaFileManager: IncrementalJavaFileManager, ): List { val project = kotlinCoreProjectEnvironment.project val ktFiles = createSourceFilesFromSourceRoots( @@ -375,7 +363,7 @@ class KotlinSymbolProcessing( ).update(ktFiles) // Update Java providers for newly generated source files. - reinitJavaFileManager(kotlinCoreProjectEnvironment, modules, allJavaFiles) + javaFileManager.initialize(modules, allJavaFiles) return ktFiles.map { analyze { KSFileImpl.getCached(it.getFileSymbol()) } } + allJavaFiles.map { KSFileJavaImpl.getCached(it) } @@ -383,8 +371,7 @@ class KotlinSymbolProcessing( private fun prepareNewKSFiles( kotlinCoreProjectEnvironment: KotlinCoreProjectEnvironment, - modules: List, - compilerConfiguration: CompilerConfiguration, + javaFileManager: IncrementalJavaFileManager, newKotlinFiles: List, newJavaFiles: List, ): List { @@ -397,10 +384,6 @@ class KotlinSymbolProcessing( project, newJavaFiles.map { it.toPath() }.toSet() ) - val allJavaFiles = getPsiFilesFromPaths( - project, - getSourceFilePaths(compilerConfiguration, includeDirectoryRoot = true) - ) // Update Kotlin providers for newly generated source files. ( @@ -415,7 +398,7 @@ class KotlinSymbolProcessing( ).update(ktFiles) // Update Java providers for newly generated source files. - reinitJavaFileManager(kotlinCoreProjectEnvironment, modules, allJavaFiles) + javaFileManager.add(javaFiles) return ktFiles.map { analyze { KSFileImpl.getCached(it.getFileSymbol()) } } + javaFiles.map { KSFileJavaImpl.getCached(it) } @@ -470,7 +453,9 @@ class KotlinSymbolProcessing( ResolverAAImpl.ktModule = modules.single() as KtSourceModule // Initializing environments - val allKSFiles = prepareAllKSFiles(kotlinCoreProjectEnvironment, modules, compilerConfiguration) + val javaFileManager = IncrementalJavaFileManager(kotlinCoreProjectEnvironment) + val allKSFiles = + prepareAllKSFiles(kotlinCoreProjectEnvironment, modules, compilerConfiguration, javaFileManager) val anyChangesWildcard = AnyChanges(kspConfig.projectBaseDir) val codeGenerator = CodeGeneratorImpl( kspConfig.classOutputDir, @@ -499,7 +484,6 @@ class KotlinSymbolProcessing( var allDirtyKSFiles = incrementalContext.calcDirtyFiles(allKSFiles).toList() var newKSFiles = allDirtyKSFiles val initialDirtySet = allDirtyKSFiles.toSet() - val allCleanFilePaths = allKSFiles.filterNot { it in initialDirtySet }.map { it.filePath }.toSet() val targetPlatform = ResolverAAImpl.ktModule.platform val symbolProcessorEnvironment = SymbolProcessorEnvironment( @@ -567,8 +551,7 @@ class KotlinSymbolProcessing( .map { it.canonicalPath }.toSet() newKSFiles = prepareNewKSFiles( kotlinCoreProjectEnvironment, - modules, - compilerConfiguration, + javaFileManager, newFilePaths.filter { it.endsWith(".kt") }.map { File(it) }.toList(), newFilePaths.filter { it.endsWith(".java") }.map { File(it) }.toList(), ) @@ -648,78 +631,6 @@ class DirectoriesScope( override fun toString() = "All files under: $directories" } -private fun reinitJavaFileManager( - environment: KotlinCoreProjectEnvironment, - modules: List, - sourceFiles: List, -) { - val project = environment.project - val javaFileManager = project.getService(JavaFileManager::class.java) as KotlinCliJavaFileManagerImpl - val javaModuleFinder = CliJavaModuleFinder(null, null, javaFileManager, project, null) - 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 rootsWithSingleJavaFileRoots = buildList { - addAll(libraryRoots) - addAll(allSourceFileRoots) - addAll(jdkRoots) - } - - val (roots, singleJavaFileRoots) = rootsWithSingleJavaFileRoots.partition { (file) -> - file.isDirectory || file.extension != JavaFileType.DEFAULT_EXTENSION - } - - val corePackageIndex = project.getService(PackageIndex::class.java) as CorePackageIndex - val rootsIndex = JvmDependenciesDynamicCompoundIndex().apply { - addIndex(JvmDependenciesIndexImpl(roots)) - indexedRoots.forEach { javaRoot -> - if (javaRoot.file.isDirectory) { - if (javaRoot.type == JavaRoot.RootType.SOURCE) { - // NB: [JavaCoreProjectEnvironment#addSourcesToClasspath] calls: - // 1) [CoreJavaFileManager#addToClasspath], which is used to look up Java roots; - // 2) [CorePackageIndex#addToClasspath], which populates [PackageIndex]; and - // 3) [FileIndexFacade#addLibraryRoot], which conflicts with this SOURCE root when generating a library scope. - // Thus, here we manually call first two, which are used to: - // 1) create [PsiPackage] as a package resolution result; and - // 2) find directories by package name. - // With both supports, annotations defined in package-info.java can be properly propagated. - javaFileManager.addToClasspath(javaRoot.file) - corePackageIndex.addToClasspath(javaRoot.file) - } else { - environment.addSourcesToClasspath(javaRoot.file) - } - } - } - } - - javaFileManager.initialize( - rootsIndex, - listOf( - StandaloneProjectFactory.createPackagePartsProvider( - libraryRoots + jdkRoots, - LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST) - ).invoke(ProjectScope.getLibrariesScope(project)) - ), - SingleJavaFileRootsIndex(singleJavaFileRoots), - true - ) -} - -private fun getDefaultJdkModuleRoots( - javaModuleFinder: CliJavaModuleFinder, - javaModuleGraph: JavaModuleGraph -): List { - // In contrast to `ClasspathRootsResolver.addModularRoots`, we do not need to handle automatic Java modules because JDK modules - // aren't automatic. - return javaModuleGraph.getAllDependencies(javaModuleFinder.computeDefaultRootModules()).flatMap { moduleName -> - val module = javaModuleFinder.findModule(moduleName) ?: return@flatMap emptyList() - val result = module.getJavaModuleRoots() - result - } -} - fun String?.toKotlinVersion(): KotlinVersion { if (this == null) return KotlinVersion.CURRENT 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 new file mode 100644 index 0000000000..48f04aae82 --- /dev/null +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalJavaFileManager.kt @@ -0,0 +1,149 @@ +package com.google.devtools.ksp.standalone + +import com.intellij.core.CorePackageIndex +import com.intellij.ide.highlighter.JavaFileType +import com.intellij.openapi.roots.PackageIndex +import com.intellij.psi.PsiJavaFile +import com.intellij.psi.impl.file.impl.JavaFileManager +import com.intellij.psi.search.ProjectScope +import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCliJavaFileManagerImpl +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment +import org.jetbrains.kotlin.cli.jvm.compiler.computeDefaultRootModules +import org.jetbrains.kotlin.cli.jvm.compiler.getJavaModuleRoots +import org.jetbrains.kotlin.cli.jvm.index.JavaRoot +import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesDynamicCompoundIndex +import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndexImpl +import org.jetbrains.kotlin.cli.jvm.index.SingleJavaFileRootsIndex +import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleFinder +import org.jetbrains.kotlin.cli.jvm.modules.JavaModuleGraph +import org.jetbrains.kotlin.config.ApiVersion +import org.jetbrains.kotlin.config.LanguageVersion +import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl + +class IncrementalJavaFileManager(val environment: KotlinCoreProjectEnvironment) { + lateinit var rootsIndex: JvmDependenciesDynamicCompoundIndex + lateinit var packagePartProviders: List + val singleJavaFileRoots = mutableListOf() + + fun initialize( + modules: List, + sourceFiles: List, + ) { + val project = environment.project + val javaFileManager = project.getService(JavaFileManager::class.java) as KotlinCliJavaFileManagerImpl + val javaModuleFinder = CliJavaModuleFinder(null, null, javaFileManager, project, null) + 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 rootsWithSingleJavaFileRoots = buildList { + addAll(libraryRoots) + addAll(allSourceFileRoots) + addAll(jdkRoots) + } + + val (roots, newSingleJavaFileRoots) = rootsWithSingleJavaFileRoots.partition { (file) -> + file.isDirectory || file.extension != JavaFileType.DEFAULT_EXTENSION + } + + singleJavaFileRoots.addAll(newSingleJavaFileRoots) + + rootsIndex = JvmDependenciesDynamicCompoundIndex().apply { + addIndex(JvmDependenciesIndexImpl(roots)) + } + + val corePackageIndex = project.getService(PackageIndex::class.java) as CorePackageIndex + roots.forEach { javaRoot -> + if (javaRoot.file.isDirectory) { + if (javaRoot.type == JavaRoot.RootType.SOURCE) { + // NB: [JavaCoreProjectEnvironment#addSourcesToClasspath] calls: + // 1) [CoreJavaFileManager#addToClasspath], which is used to look up Java roots; + // 2) [CorePackageIndex#addToClasspath], which populates [PackageIndex]; and + // 3) [FileIndexFacade#addLibraryRoot], which conflicts with this SOURCE root when generating a library scope. + // Thus, here we manually call first two, which are used to: + // 1) create [PsiPackage] as a package resolution result; and + // 2) find directories by package name. + // With both supports, annotations defined in package-info.java can be properly propagated. + javaFileManager.addToClasspath(javaRoot.file) + corePackageIndex.addToClasspath(javaRoot.file) + } else { + environment.addSourcesToClasspath(javaRoot.file) + } + } + } + + packagePartProviders = listOf( + StandaloneProjectFactory.createPackagePartsProvider( + libraryRoots + jdkRoots, + LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST) + ).invoke(ProjectScope.getLibrariesScope(project)) + ) + + javaFileManager.initialize( + rootsIndex, + packagePartProviders, + SingleJavaFileRootsIndex(singleJavaFileRoots), + true + ) + } + + fun add(sourceFiles: List) { + val project = environment.project + val javaFileManager = project.getService(JavaFileManager::class.java) as KotlinCliJavaFileManagerImpl + val allSourceFileRoots = sourceFiles.map { JavaRoot(it.virtualFile, JavaRoot.RootType.SOURCE) } + + val (roots, newSingleJavaFileRoots) = allSourceFileRoots.partition { (file) -> + file.isDirectory || file.extension != JavaFileType.DEFAULT_EXTENSION + } + + singleJavaFileRoots.addAll(newSingleJavaFileRoots) + + rootsIndex.apply { + addIndex(JvmDependenciesIndexImpl(roots)) + } + + val corePackageIndex = project.getService(PackageIndex::class.java) as CorePackageIndex + roots.forEach { javaRoot -> + if (javaRoot.file.isDirectory) { + if (javaRoot.type == JavaRoot.RootType.SOURCE) { + // NB: [JavaCoreProjectEnvironment#addSourcesToClasspath] calls: + // 1) [CoreJavaFileManager#addToClasspath], which is used to look up Java roots; + // 2) [CorePackageIndex#addToClasspath], which populates [PackageIndex]; and + // 3) [FileIndexFacade#addLibraryRoot], which conflicts with this SOURCE root when generating a library scope. + // Thus, here we manually call first two, which are used to: + // 1) create [PsiPackage] as a package resolution result; and + // 2) find directories by package name. + // With both supports, annotations defined in package-info.java can be properly propagated. + javaFileManager.addToClasspath(javaRoot.file) + corePackageIndex.addToClasspath(javaRoot.file) + } else { + environment.addSourcesToClasspath(javaRoot.file) + } + } + } + + javaFileManager.initialize( + rootsIndex, + packagePartProviders, + SingleJavaFileRootsIndex(singleJavaFileRoots), + true + ) + } +} + +private fun getDefaultJdkModuleRoots( + javaModuleFinder: CliJavaModuleFinder, + javaModuleGraph: JavaModuleGraph +): List { + // In contrast to `ClasspathRootsResolver.addModularRoots`, we do not need to handle automatic Java modules because JDK modules + // aren't automatic. + return javaModuleGraph.getAllDependencies(javaModuleFinder.computeDefaultRootModules()).flatMap { moduleName -> + val module = javaModuleFinder.findModule(moduleName) ?: return@flatMap emptyList() + val result = module.getJavaModuleRoots() + result + } +} From e593074998bdf6d393282321c94e9112175e600a Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Thu, 16 May 2024 14:28:46 -0700 Subject: [PATCH 28/64] Incremental: fix roots from getSealedSubclasses by just including the files that contain the sealed class / interface. Their subclasses will be invalidated during dirtiness propagation. --- .../com/google/devtools/ksp/common/IncrementalContextBase.kt | 4 +--- .../com/google/devtools/ksp/test/GetSealedSubclassesIncIT.kt | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt index 1bb3add83f..148d4324db 100644 --- a/common-util/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt +++ b/common-util/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt @@ -234,9 +234,7 @@ abstract class IncrementalContextBase( symbolLookupCache.get(it).map { File(it) } } - val dirtyFilesBySealed = sealedMap.keys.flatMap { sealedMap[it]!! }.flatMap { - symbolLookupCache.get(it).map { File(it) } - } + val dirtyFilesBySealed = sealedMap.keys // Calculate dirty files by dirty classes in CP. val dirtyFilesByCP = changedClasses.flatMap { fqn -> diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/GetSealedSubclassesIncIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/GetSealedSubclassesIncIT.kt index d9cfa04dba..3610aba833 100644 --- a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/GetSealedSubclassesIncIT.kt +++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/GetSealedSubclassesIncIT.kt @@ -2,7 +2,6 @@ package com.google.devtools.ksp.test import org.gradle.testkit.runner.GradleRunner import org.junit.Assert -import org.junit.Assume import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -17,7 +16,6 @@ class GetSealedSubclassesIncIT(val useKSP2: Boolean) { @Test fun testGetSealedSubclassesInc() { - Assume.assumeFalse(useKSP2) val gradleRunner = GradleRunner.create().withProjectDir(project.root) val expected2 = listOf( From ce91ec4c27116bbc15231e8adfa29e83a4ac806d Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Thu, 16 May 2024 14:32:44 -0700 Subject: [PATCH 29/64] KSP2: Keep debug classes of coroutine --- .../com/google/devtools/ksp/impl/KotlinSymbolProcessing.kt | 1 + 1 file changed, 1 insertion(+) 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 748ff82bb1..2a629e2c12 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 @@ -647,6 +647,7 @@ fun String?.toKotlinVersion(): KotlinVersion { // Workaround for ShadowJar's minimize, whose configuration isn't very flexible. internal val DEAR_SHADOW_JAR_PLEASE_DO_NOT_REMOVE_THESE = listOf( + kotlinx.coroutines.debug.internal.DebugProbesImpl::class.java, org.jetbrains.kotlin.analysis.api.impl.base.java.source.JavaElementSourceWithSmartPointerFactory::class.java, org.jetbrains.kotlin.analysis.api.impl.base.references.HLApiReferenceProviderService::class.java, org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSessionProvider::class.java, From def3bc03b96ae674d4c9ea101cd8e8bfab290dd1 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Mon, 20 May 2024 16:52:29 -0700 Subject: [PATCH 30/64] use safe cast for annotation type to declaration resolution --- .../devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt index 1730461fe5..6e3f3ee85d 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt @@ -67,7 +67,7 @@ class KSAnnotationJavaImpl private constructor(private val psi: PsiAnnotation, o override val arguments: List by lazy { val annotationConstructor = analyze { - (type.classifierSymbol() as KtClassOrObjectSymbol).getMemberScope().getConstructors().singleOrNull() + (type.classifierSymbol() as? KtClassOrObjectSymbol)?.getMemberScope()?.getConstructors()?.singleOrNull() } val presentArgs = psi.parameterList.attributes.mapIndexed { index, it -> val name = it.name ?: annotationConstructor?.valueParameters?.getOrNull(index)?.name?.asString() @@ -91,7 +91,7 @@ class KSAnnotationJavaImpl private constructor(private val psi: PsiAnnotation, o override val defaultArguments: List by lazy { analyze { - (type.classifierSymbol() as KtClassOrObjectSymbol).getMemberScope().getConstructors().singleOrNull() + (type.classifierSymbol() as? KtClassOrObjectSymbol)?.getMemberScope()?.getConstructors()?.singleOrNull() ?.let { symbol -> if (symbol.origin == KtSymbolOrigin.JAVA && symbol.psi != null) { (symbol.psi as PsiClass).allMethods.filterIsInstance() From ace32f269c035f822183398de51163045b298882 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Tue, 21 May 2024 13:29:58 -0700 Subject: [PATCH 31/64] 1.0.22-release branch cleanup work. * downgrade kotlin version to 2.0.0 * disable KSPAATest --- gradle.properties | 2 +- .../src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index da3d8bfd5b..daed36e609 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # Copied from kotlinc org.gradle.jvmargs=-Duser.country=US -Dkotlin.daemon.jvm.options=-Xmx2200m -Dfile.encoding=UTF-8 -kotlinBaseVersion=2.0.20-dev-2651 +kotlinBaseVersion=2.0.0 agpBaseVersion=7.2.0 intellijVersion=213.7172.25 junitVersion=4.13.1 diff --git a/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt b/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt index ef4f0008a3..249e2f3d44 100644 --- a/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt +++ b/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt @@ -25,6 +25,7 @@ import org.junit.jupiter.api.condition.OS import org.junit.jupiter.api.parallel.Execution import org.junit.jupiter.api.parallel.ExecutionMode +@Disabled @Execution(ExecutionMode.SAME_THREAD) @DisabledOnOs(OS.WINDOWS) class KSPAATest : AbstractKSPAATest() { From bda7ae0a7bbbda2f1420072e97149ca004f0aa65 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Tue, 21 May 2024 12:04:27 -0700 Subject: [PATCH 32/64] Docs for KSP2 (cherry picked from commit 15aa34a6a005365879af4262ab26b4ef2ba361e6) --- README.md | 6 ++- docs/ksp2.md | 67 +++++++++++++++++++++++++++++ docs/ksp2api.md | 95 +++++++++++++++++++++++++++++++++++++++++ docs/ksp2cmdline.md | 72 +++++++++++++++++++++++++++++++ docs/ksp2entrypoints.md | 37 ++++++++++++++++ 5 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 docs/ksp2.md create mode 100644 docs/ksp2api.md create mode 100644 docs/ksp2cmdline.md create mode 100644 docs/ksp2entrypoints.md diff --git a/README.md b/README.md index 158fc97cd6..0cecafb0b5 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,10 @@ Most of the documentation of KSP can be found on [kotlinlang.org](https://kotlin For debugging and testing processors, as well as KSP itself, please check [DEVELOPMENT.md](DEVELOPMENT.md) +## KSP2 is in Beta! +KSP2 is a new implementation of the KSP API. It will be faster and easier to use than KSP 1.x. Please refer to the +[KSP2 introduction](docs/ksp2.md) for more details. + ## Feedback and Bug Reporting [Please let us know what you think about KSP by filing a Github issue](https://github.com/google/ksp/issues) @@ -35,8 +39,6 @@ If you are interested in sending PRs, please also check out the [Contributor gui ## Ongoing and Future Works Here are some planned features that have not yet been completely implemented: -* Support [new Kotlin compiler](https://kotlinlang.org/docs/roadmap.html) * Improve support to multiplatform. E.g., running KSP on a subset of targets / sharing computations between targets * Improve performance. There are a bunch of optimizations to be done! -* Make the IDE aware of the generated code * Keep fixing bugs! diff --git a/docs/ksp2.md b/docs/ksp2.md new file mode 100644 index 0000000000..4cb30cd5eb --- /dev/null +++ b/docs/ksp2.md @@ -0,0 +1,67 @@ +# Introduction to KSP2 (Beta) + +KSP2 is a new implementation of the KSP API. Unlike KSP 1.x, it is no longer a compiler plugin and is built on the same +set of Kotlin compiler APIs shared with IntelliJ IDEA, Android Lint, etc. Compared to the compiler-plugin approach, this +allows a finer control of the program life cycle, simplifies KSP’s implementation and is more efficient. It is also a +response to the compiler migration to K2, whose compiler plugin API is different from the one KSP1 uses. + +Not being a compiler plugin and having a better control of the program life cycles means that it’s straightforward to +provide an entry point that can be called by other programs. This is especially convenient for processors in their test +codes. KSP2 also provides a new command line tool that has its own main function, instead of being part of the compiler +invocation. + +With the new implementation, it is also a great opportunity to introduce some refinements in the API behavior so that +developers building on KSP will be more productive, have better debuggability and error recovery. For example, when +resolving `Map`, KSP1 simply returns an error type. In KSP2, `Map` will be +returned instead. + +## API Changes +Please refer to [KSP2 API Changes](ksp2api.md) to see more details. + +## Using KSP 2 in Gradle +With KSP 1.0.21 and above, KSP2 Beta can be enabled with a flag in gradle.properties: + +``` +ksp.useKSP2=true +``` + +Unlike KSP1, which runs in `KotlinCompileDaemon`, KSP2 runs in Gradle daemon. This has 2 implications: +1. Gradle daemon usually has a lower default heap limit. You may need to increase it by the following Gradle property, +for example: `org.gradle.jvmargs=-Xmx4096M -XX:MaxMetaspaceSize=1024m` +2. The debug flags now need to be passed to Gradle rather than `KotlinCompileDaemon`. To debug KSP2 and/or processors, + pass the system property `-Dorg.gradle.debug=true` in the Gradle command line. + +## Transitioning from KSP1 to KSP2 +KSP1 and KSP2 are supported by an unified KSP Gradle plugin. The current versioning scheme, +`-`, will remain at least until KSP1 is deprecated. This allows switching between KSP1 and +KSP2 easily with a single `ksp.useKSP2=` property in Gradle projects. + +### KSP1 Deprecation Schedule +Because KSP1 is built on top of the old Kotlin compiler, theoretically it won’t be able to support language version +2.0+. Fortunately, Kotlin language 2.0 is designed to be fully compatible with language version 1.9, so KSP1 will still +be compatible with Kotlin 2.0. **KSP1 will not support Kotlin 2.1**. Please plan transitioning from KSP1 to KSP2 during +Kotlin 2.0. + +Because KSP2 is no longer a compiler plugin, there is no strong dependency to the Kotlin compiler. After KSP1 is +deprecated, it may get rid of the Kotlin prefix in its version, and become simply `KSP-2.1.0` for example. + +## Using KSP 2 from command line and in program +Please refer to [Using KSP2 command line](ksp2cmdline.md) and [Calling KSP2 in program](ksp2entrypoints.md). + +## Known Issues +The main gaps between KSP2 Beta and KSP2 Stable are: +* Support of mangled (for `inline` and `internal`) JVM names in `Resolver.getJvmWildcard` and + `Resolver.mapToJvmSignature` +* Support of synthesized Java getters and setters for Kotlin properties in `Resolver.findOverridee` and + `Resolver.asMemberOf`. +* Performance and memory footage are not fully taken care of yet. +* Some type of annotation values are not supported (e.g. nested annotations) + +Please check the KSP [2.0](https://github.com/google/ksp/issues?q=is%3Aopen+is%3Aissue+milestone%3A2.0) and +[2.1](https://github.com/google/ksp/issues?q=is%3Aopen+is%3Aissue+milestone%3A2.1) milestones on github for the complete +lists of known issues. + +## Feedback +If you find any bugs that are not included in the above milestones, or if you have any concerns or ideas on API changes, +[please let us know](https://github.com/google/ksp/issues)! + diff --git a/docs/ksp2api.md b/docs/ksp2api.md new file mode 100644 index 0000000000..5efe411c9d --- /dev/null +++ b/docs/ksp2api.md @@ -0,0 +1,95 @@ +# KSP2 API Changes + +While KSP2 is binary compatible with processors written for KSP1, there are some changes in the return values. The +differences are listed below: + +##### Resolve implicit type from function call: val error = mutableMapOf() +* KSP1: The whole type will be an error type due to failed type resolution. +* KSP2: It will successfully resolve the container type, and for the non-existent type in the type argument, it will + correctly report errors on the specific type argument. + +##### Unbounded type parameter +* KSP1: No bounds +* KSP2: An upper bound of `Any?` is always inserted for consistency + +##### Resolving references to type aliases in function types and annotations +* KSP1: Expanded to the underlying, non-alias type +* KSP2: Not expanded, like uses in other places + +##### Fully qualified names +* KSP1: Constructors have FQN if the constructor is from source, but not if the constructor is from a library. +* KSP2: Constructors do not have FQN + +##### Type arguments of inner types +* KSP1: Inner types has arguments from outer types +* KSP2: Inner types has no arguments from outer types + +##### Type arguments of star projections +* KSP1: Star projections have type arguments that are expanded to the effective variances according to the declaration + sites. +* KSP2: No expansion. Star projections have nulls in their type arguments. + +##### Variance of Java Array +* KSP1: Java Array has a invariant upper bound +* KSP2: Java Array has a covariant upper bound + +##### Type of Enum Entries +* KSP1: Each enum entry has itsown type +* KSP2: All enum entries share the same type with the enclosing enum class + +##### Evaluation of Enum Entries in Annotation Arguments +* KSP1: An annotation argument that is an enum entry is evaluated as a `KSType` of the corresponding enum entry +* KSP2: An annotation argument that is an enum entry is evaluated directly as the corresponding `KSClassDeclaration` + of the enum entry + +##### Multi-override scenario +For example +``` +interface GrandBaseInterface1 { + fun foo(): Unit +} + +interface GrandBaseInterface2 { + fun foo(): Unit +} + +interface BaseInterface1 : GrandBaseInterface1 { +} + +interface BaseInterface2 : GrandBaseInterface2 { +} + +class OverrideOrder1 : BaseInterface1, GrandBaseInterface2 { + override fun foo() = TODO() +} +class OverrideOrder2 : BaseInterface2, GrandBaseInterface1 { + override fun foo() = TODO() +} +``` + +* KSP1: Find overridden symbols in BFS order, first super type found on direct super type list that contains overridden + symbol is returned. For the example, KSP will say `OverrideOrder1.foo()` overrides `GrandBaseInterface2.foo()` + and `OverrideOrder2.foo()` overrides `GrandBaseInterface1.foo()`. +* KSP2: DFS order, first super type found overridden symbols (with recursive super type look up) in direct super type + list is returned. For the example, KSP will say `OverrideOrder1.foo()` overrides `GrandBaseInterface1.foo()` + and `OverrideOrder2.foo()` overrides `GrandBaseInterface2.foo()`. + +##### Java modifier +* KSP1: Transient/volatile fields are final by default +* KSP2: Transient/volatile fields are open by default + +##### Type annotations +* KSP1: Type annotations on a type argument is only reflected on the type argument symbol +* 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 + +##### Synthesized members of Enums +* KSP1: `values` and `valueOf` are missing if the enum is defined in Kotlin sources +* KSP2: `values` and `valueOf` are always present + +##### Synthesized members of data classes +* KSP1: `componentN` and `copy` are missing if the data class is defined in Kotlin sources +* KSP2: `componentN` and `copy` are always present diff --git a/docs/ksp2cmdline.md b/docs/ksp2cmdline.md new file mode 100644 index 0000000000..a4324b94e9 --- /dev/null +++ b/docs/ksp2cmdline.md @@ -0,0 +1,72 @@ +# Using KSP2 from Command Line + +KSP2 has 4 main classes, one for each platform: `KSPJvmMain`, `KSPJsMain`, `KSPNativeMain`, `KSPCommonMain`. They reside +in the same jars from the +[artifacts.zip](https://github.com/google/ksp/releases/download/2.0.0-1.0.21/artifacts.zip) in the +[release page](https://github.com/google/ksp/releases/tag/2.0.0-1.0.21): +* `symbol-processing-aa-2.0.0-1.0.21.jar` + +and depend on: +* `symbol-processing-common-deps-2.0.0-1.0.21.jar` + +You’ll also need the Kotlin runtime: +* `kotlin-stdlib-2.0.0.jar` + +Taking `KSPJvmMain` for example, + +``` +java -cp \ +kotlin-analysis-api-2.0.0-1.0.21.jar:common-deps-2.0.0-1.0.21.jar:symbol-processing-api-2.0.0-1.0.21.jar:kotlin-stdlib-2.0.0.jar \ +com.google.devtools.ksp.cmdline.KSPJvmMain \ +-jvm-target 11 \ +-module-name=main \ +-source-roots project_dir/src/kotlin/main \ +-project-base-dir project_dir/ \ +-output-base-dir=project_dir/build/ \ +-caches-dir=project_dir/build/caches/ \ +-class-output-dir=project_dir/build/out/main/classes \ +-kotlin-output-dir=project_dir/build/out/main/kotlin/ \ +-java-output-dir project_dir/build/out/main/java/ \ +-resource-output-dir project_dir/build/out/main/res/ \ +-language-version=2.0 \ +-api-version=2.0 \ +path/to/processor.jar +``` + +A comprehensive options list can be obtained with `-h`: + +``` +Available options: + + -java-source-roots=List +* -java-output-dir=File + -jdk-home=File? +* -jvm-target=String + -jvm-default-mode=String +* -module-name=String +* -source-roots=List + -common-source-roots=List + -libraries=List + -processor-options=Map +* -project-base-dir=File +* -output-base-dir=File +* -caches-dir=File +* -class-output-dir=File +* -kotlin-output-dir=File +* -resource-output-dir=File + -incremental=Boolean + -incremental-log=Boolean + -modified-sources=List + -removed-sources=List + -changed-classes=List +* -language-version=String +* -api-version=String + -all-warnings-as-errors=Boolean + -map-annotation-arguments-in-java=Boolean +* + +where: +* is required + List is colon separated. E.g., arg1:arg2:arg3 + Map is in the form key1=value1:key2=value2 +``` \ No newline at end of file diff --git a/docs/ksp2entrypoints.md b/docs/ksp2entrypoints.md new file mode 100644 index 0000000000..9895c8bfca --- /dev/null +++ b/docs/ksp2entrypoints.md @@ -0,0 +1,37 @@ +# Calling KSP2 In Programs + +There are two flavors of KSP2 artifacts: `symbol-processing-aa` and `symbol-processing-aa-embeddable`. They are both +uber jars that include almost all runtime dependencies except `kotlin-stdlib` and `symbol-processing-common-deps`. +The `-embeddable` version is the regular version with all the runtime dependencies renamed, so that it can be used with +a Kotlin compiler in the same classpath without name clash. When in doubt, use `symbol-processing-aa-embeddable`. + +Calling KSP2 consists of just 4 steps: +1. Load processors +2. Provide an implementation of `KSPLogger`, or use `KspGradleLogger`, which currently simply writes to stdout. +3. Fill `KSPConfig` +4. Call `KotlinSymbolProcessing(kspConfig, processors, kspLogger).execute()` + + +``` +// Implement a logger or use KspGradleLogger +val logger = KspGradleLogger(KspGradleLogger.LOGGING_LEVEL_WARN) + +// Load processors +val processorClassloader = URLClassLoader(classpath.map { File(it).toURI().toURL() }.toTypedArray()) +val processorProviders = ServiceLoader.load( + processorClassloader.loadClass("com.google.devtools.ksp.processing.SymbolProcessorProvider"), + processorClassloader +).toList() as List + +// Fill the config +val kspConfig = KSPJvmConfig.Builder().apply { + // All configurations happen here. See KSPConfig.kt for all available options. + moduleName = "main" + sourceRoots = listOf(File("/path/to/src1), File("/path/to/src2")) + kotlinOutputDir = File("/path/to/kotlin/out") + ... +}.build() + +// Run! +val exitCode = KotlinSymbolProcessing(kspConfig, listOfProcessors, kspLoggerImpl).execute() +``` \ No newline at end of file From 97c2a3d54c3721967f5baae46bed734e0e1cb56f Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Tue, 21 May 2024 13:28:14 -0700 Subject: [PATCH 33/64] set release branch to 1.0.22-release (cherry picked from commit 06a1a588c63ab73a4dc41f4cf4cf6857b8cce1a2) --- .github/workflows/auto-merge.yml | 4 ++-- .github/workflows/main.yml | 4 ++-- .github/workflows/nightly.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index fd5a21b5d3..f684fd5c83 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -21,7 +21,7 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - ref: 1.0.21-release + ref: 1.0.22-release - name: merge commits from main to release branch run: | @@ -109,7 +109,7 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - ref: 1.0.21-release + ref: 1.0.22-release - name: merge commits from main to release branch run: | diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f695b563d9..3fc5efa584 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,9 +4,9 @@ name: CI on: push: - branches: [ main, 1.0.20-release, 1.0.21-release ] + branches: [ main, 1.0.22-release, 1.0.21-release ] pull_request: - branches: [ main, 1.0.20-release, 1.0.21-release ] + branches: [ main, 1.0.22-release, 1.0.21-release ] jobs: build-and-test: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 1389df42e0..f64052fe60 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -7,7 +7,7 @@ jobs: strategy: fail-fast: false matrix: - branch: [ main, 1.0.21-release, 1.0.20-release ] + branch: [ main, 1.0.21-release, 1.0.22-release ] runs-on: windows-latest steps: - name: configure Pagefile From d769ef4cb696c933c61e9bc89ad84f0a304cefe1 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Tue, 21 May 2024 14:40:58 -0700 Subject: [PATCH 34/64] Documentation: super type of enum classes changed to Enum in KSP2 (cherry picked from commit 225126a930c1a6b58f355fa351c649e3c8e04e5e) --- docs/ksp2api.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/ksp2api.md b/docs/ksp2api.md index 5efe411c9d..7b0606d80a 100644 --- a/docs/ksp2api.md +++ b/docs/ksp2api.md @@ -93,3 +93,7 @@ class OverrideOrder2 : BaseInterface2, GrandBaseInterface1 { ##### Synthesized members of data classes * KSP1: `componentN` and `copy` are missing if the data class is defined in Kotlin sources * KSP2: `componentN` and `copy` are always present + +##### Super type of Enum classes +* KSP1: The super type of Enum classes is `Any` +* KSP2: The super type of Enum classes is `Enum` \ No newline at end of file From eadc4ce851dc33f7ad13ab773a48ca76e6e02454 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Thu, 16 May 2024 23:03:50 -0700 Subject: [PATCH 35/64] Do not run testWasm on release branch (cherry picked from commit 6bba35bbc97b5f3df058c3d6d9ce8cb24f689b6f) --- .../test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt index a97ab87f2f..a4d82f5d7a 100644 --- a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt +++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt @@ -110,6 +110,7 @@ class KMPImplementedIT(useKSP2: Boolean) { @Test fun testWasm() { + Assume.assumeTrue(project.useKSP2) Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) val gradleRunner = GradleRunner.create().withProjectDir(project.root) From 423c1fd2a8a62df2f36dc8d06569c6ff900b6903 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Wed, 22 May 2024 16:05:05 -0700 Subject: [PATCH 36/64] UPDATE_AA_VERSION: 2.0.20-dev-3728 (cherry picked from commit 17aadc06699090ffc5bd9449afb91ee2721927cf) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index daed36e609..2e427e475d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ junit5Version=5.8.2 junitPlatformVersion=1.8.2 googleTruthVersion=1.1 -aaKotlinBaseVersion=2.0.20-dev-2651 +aaKotlinBaseVersion=2.0.20-dev-3728 aaIntellijVersion=213.7172.25 aaGuavaVersion=29.0-jre aaAsmVersion=9.0 From bac86838db7fd1bfb795957ba1ac95cdff2519c9 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Thu, 23 May 2024 11:03:35 -0700 Subject: [PATCH 37/64] Move versions of build/runtime dependencies into gradle.properties (cherry picked from commit 0944e12a4accb32fbb9c827c337409b867d1ac55) --- build.gradle.kts | 2 +- common-deps/build.gradle.kts | 2 +- gradle.properties | 4 ++++ settings.gradle.kts | 8 ++++++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 2635729638..0b162f118f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,7 +20,7 @@ repositories { } plugins { - kotlin("jvm") version "1.9.23" + kotlin("jvm") id("io.github.gradle-nexus.publish-plugin") version "1.1.0" // Adding plugins used in multiple places to the classpath for centralized version control diff --git a/common-deps/build.gradle.kts b/common-deps/build.gradle.kts index 492b9af066..88f0418b39 100644 --- a/common-deps/build.gradle.kts +++ b/common-deps/build.gradle.kts @@ -18,7 +18,7 @@ plugins { `maven-publish` signing id("org.jetbrains.dokka") - id("com.google.devtools.ksp") version "1.9.23-1.0.20" + id("com.google.devtools.ksp") } dependencies { diff --git a/gradle.properties b/gradle.properties index 2e427e475d..1c37fc9afa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,3 +21,7 @@ aaStreamexVersion=0.7.2 compilerTestEnabled=false kotlin.jvm.target.validation.mode=warning + +# Build or runtime dependencies of this project +buildKotlinVersion=1.9.23 +buildKspVersion=1.9.23-1.0.20 \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 9d447b763b..3b01c53916 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,14 @@ rootProject.name = "ksp" pluginManagement { + val buildKotlinVersion: String by settings + val buildKspVersion: String by settings + + plugins { + kotlin("jvm") version buildKotlinVersion apply false + id("com.google.devtools.ksp") version buildKspVersion apply false + } + repositories { gradlePluginPortal() maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/") From 87ec9a62715283487e1a20fb81d4e3b4f0e29a4b Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Thu, 23 May 2024 11:04:03 -0700 Subject: [PATCH 38/64] Fix stdlib versions in KSP2 pom files (cherry picked from commit cdf8f1cb98423bbe4231428fa4ac7ae95335a839) --- kotlin-analysis-api/build.gradle.kts | 6 ++++-- symbol-processing-aa-embeddable/build.gradle.kts | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/kotlin-analysis-api/build.gradle.kts b/kotlin-analysis-api/build.gradle.kts index b13460bd59..b7e5bb2638 100644 --- a/kotlin-analysis-api/build.gradle.kts +++ b/kotlin-analysis-api/build.gradle.kts @@ -6,6 +6,8 @@ description = "Kotlin Symbol Processing implementation using Kotlin Analysis API val signingKey: String? by project val signingPassword: String? by project +val kotlinBaseVersion: String by project + val aaKotlinBaseVersion: String by project val aaIntellijVersion: String by project val aaGuavaVersion: String by project @@ -95,7 +97,7 @@ dependencies { testImplementation(kotlin("stdlib", aaKotlinBaseVersion)) - depJarsForCheck("org.jetbrains.kotlin", "kotlin-stdlib", aaKotlinBaseVersion) + depJarsForCheck("org.jetbrains.kotlin", "kotlin-stdlib", kotlinBaseVersion) depJarsForCheck(project(":api")) depJarsForCheck(project(":common-deps")) } @@ -203,7 +205,7 @@ publishing { } asNode().appendNode("dependencies").apply { - addDependency("org.jetbrains.kotlin", "kotlin-stdlib", aaKotlinBaseVersion) + addDependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlinBaseVersion) addDependency("com.google.devtools.ksp", "symbol-processing-api", version) addDependency("com.google.devtools.ksp", "symbol-processing-common-deps", version) } diff --git a/symbol-processing-aa-embeddable/build.gradle.kts b/symbol-processing-aa-embeddable/build.gradle.kts index d5bc242d4c..a8c70ac5bc 100644 --- a/symbol-processing-aa-embeddable/build.gradle.kts +++ b/symbol-processing-aa-embeddable/build.gradle.kts @@ -11,6 +11,8 @@ evaluationDependsOn(":kotlin-analysis-api") val signingKey: String? by project val signingPassword: String? by project +val kotlinBaseVersion: String by project + val aaKotlinBaseVersion: String by project val aaIntellijVersion: String by project @@ -255,7 +257,7 @@ publishing { } asNode().appendNode("dependencies").apply { - addDependency("org.jetbrains.kotlin", "kotlin-stdlib", aaKotlinBaseVersion) + addDependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlinBaseVersion) addDependency("com.google.devtools.ksp", "symbol-processing-api", version) addDependency("com.google.devtools.ksp", "symbol-processing-common-deps", version) } From 1cb6368d3885d5f8bdf28de6ed70fe6879b0e97e Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Thu, 23 May 2024 15:08:49 -0700 Subject: [PATCH 39/64] Replace DirectoriesScope with IncrementalGlobalSearchScope (cherry picked from commit e1d1e8657e93954bcf5f70af0f27fb9f9ed9fc6f) --- .../com/google/devtools/ksp/KSPConfig.kt | 3 +- .../ksp/impl/KotlinSymbolProcessing.kt | 67 ++++++------------- .../ksp/standalone/KspSourceModuleBuilder.kt | 26 +++++-- 3 files changed, 43 insertions(+), 53 deletions(-) diff --git a/common-deps/src/main/kotlin/com/google/devtools/ksp/KSPConfig.kt b/common-deps/src/main/kotlin/com/google/devtools/ksp/KSPConfig.kt index cc2ee40959..dee5e69efd 100644 --- a/common-deps/src/main/kotlin/com/google/devtools/ksp/KSPConfig.kt +++ b/common-deps/src/main/kotlin/com/google/devtools/ksp/KSPConfig.kt @@ -468,8 +468,7 @@ fun parseBoolean(arg: String): Boolean { fun parseFile(arg: String): File { if (arg.length > 0 && arg[0] == '-') throw IllegalArgumentException("expecting a File arguemnt but got $arg") - // FIXME: AA isn't happy relative paths for source roots. - return File(arg).absoluteFile + return File(arg) } fun parseList(arg: String, transform: (String) -> T): List { 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 2a629e2c12..99f3cac109 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 @@ -31,6 +31,7 @@ import com.google.devtools.ksp.impl.symbol.kotlin.KSFileJavaImpl import com.google.devtools.ksp.impl.symbol.kotlin.Restorable import com.google.devtools.ksp.impl.symbol.kotlin.analyze import com.google.devtools.ksp.processing.* +import com.google.devtools.ksp.standalone.IncrementalGlobalSearchScope import com.google.devtools.ksp.standalone.IncrementalJavaFileManager import com.google.devtools.ksp.standalone.IncrementalKotlinDeclarationProviderFactory import com.google.devtools.ksp.standalone.IncrementalKotlinPackageProviderFactory @@ -47,13 +48,11 @@ import com.intellij.openapi.application.Application import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer import com.intellij.openapi.vfs.StandardFileSystems -import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiFileSystemItem import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiManager import com.intellij.psi.PsiTreeChangeAdapter import com.intellij.psi.PsiTreeChangeListener -import com.intellij.psi.search.DelegatingGlobalSearchScope import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenProvider @@ -73,17 +72,13 @@ import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule 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.analysis.project.structure.impl.getSourceFilePaths +import org.jetbrains.kotlin.analysis.project.structure.impl.KtSourceModuleImpl import org.jetbrains.kotlin.analysis.providers.* import org.jetbrains.kotlin.analysis.providers.impl.* -import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots -import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreApplicationEnvironmentMode import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment -import org.jetbrains.kotlin.cli.jvm.compiler.createSourceFilesFromSourceRoots import org.jetbrains.kotlin.cli.jvm.compiler.setupIdeaStandaloneExecution -import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoot import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoots import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots @@ -207,10 +202,8 @@ class KotlinSymbolProcessing( val roots = mutableListOf() roots.addAll(kspConfig.sourceRoots) roots.addAll(kspConfig.commonSourceRoots) - roots.add(kspConfig.kotlinOutputDir) if (kspConfig is KSPJvmConfig) { roots.addAll(kspConfig.javaSourceRoots) - roots.add(kspConfig.javaOutputDir) } roots.forEach { it.mkdirs() @@ -338,17 +331,19 @@ class KotlinSymbolProcessing( private fun prepareAllKSFiles( kotlinCoreProjectEnvironment: KotlinCoreProjectEnvironment, modules: List, - compilerConfiguration: CompilerConfiguration, javaFileManager: IncrementalJavaFileManager, ): List { val project = kotlinCoreProjectEnvironment.project - val ktFiles = createSourceFilesFromSourceRoots( - compilerConfiguration, project, compilerConfiguration.kotlinSourceRoots - ).toSet().toList() - val allJavaFiles = getPsiFilesFromPaths( - project, - getSourceFilePaths(compilerConfiguration, includeDirectoryRoot = true) - ) + val ktFiles = mutableListOf() + val javaFiles = mutableListOf() + modules.filterIsInstance().forEach { + it.sourceRoots.forEach { + when (it) { + is KtFile -> ktFiles.add(it) + is PsiJavaFile -> javaFiles.add(it) + } + } + } // Update Kotlin providers for newly generated source files. ( @@ -363,10 +358,10 @@ class KotlinSymbolProcessing( ).update(ktFiles) // Update Java providers for newly generated source files. - javaFileManager.initialize(modules, allJavaFiles) + javaFileManager.initialize(modules, javaFiles) return ktFiles.map { analyze { KSFileImpl.getCached(it.getFileSymbol()) } } + - allJavaFiles.map { KSFileJavaImpl.getCached(it) } + javaFiles.map { KSFileJavaImpl.getCached(it) } } private fun prepareNewKSFiles( @@ -385,6 +380,11 @@ class KotlinSymbolProcessing( newJavaFiles.map { it.toPath() }.toSet() ) + // Add new files to content scope. + val contentScope = ResolverAAImpl.ktModule.contentScope as IncrementalGlobalSearchScope + contentScope.addAll(ktFiles.map { it.virtualFile }) + contentScope.addAll(javaFiles.map { it.virtualFile }) + // Update Kotlin providers for newly generated source files. ( project.getService( @@ -410,10 +410,8 @@ class KotlinSymbolProcessing( // TODO: CompilerConfiguration is deprecated. val compilerConfiguration: CompilerConfiguration = CompilerConfiguration().apply { addKotlinSourceRoots(kspConfig.sourceRoots.map { it.path }) - addKotlinSourceRoot(kspConfig.kotlinOutputDir.path) if (kspConfig is KSPJvmConfig) { addJavaSourceRoots(kspConfig.javaSourceRoots) - addJavaSourceRoot(kspConfig.javaOutputDir) kspConfig.jdkHome?.let { put(JVMConfigurationKeys.JDK_HOME, it) } @@ -455,7 +453,7 @@ class KotlinSymbolProcessing( // Initializing environments val javaFileManager = IncrementalJavaFileManager(kotlinCoreProjectEnvironment) val allKSFiles = - prepareAllKSFiles(kotlinCoreProjectEnvironment, modules, compilerConfiguration, javaFileManager) + prepareAllKSFiles(kotlinCoreProjectEnvironment, modules, javaFileManager) val anyChangesWildcard = AnyChanges(kspConfig.projectBaseDir) val codeGenerator = CodeGeneratorImpl( kspConfig.classOutputDir, @@ -547,13 +545,11 @@ class KotlinSymbolProcessing( KSObjectCacheManager.clear() - val newFilePaths = codeGenerator.generatedFile.filter { it.extension == "kt" || it.extension == "java" } - .map { it.canonicalPath }.toSet() newKSFiles = prepareNewKSFiles( kotlinCoreProjectEnvironment, javaFileManager, - newFilePaths.filter { it.endsWith(".kt") }.map { File(it) }.toList(), - newFilePaths.filter { it.endsWith(".java") }.map { File(it) }.toList(), + codeGenerator.generatedFile.filter { it.extension.lowercase() == "kt" }, + codeGenerator.generatedFile.filter { it.extension.lowercase() == "java" }, ) // Now that caches are dropped, KtSymbols and KS* are invalid. They need to be re-created from PSI. allDirtyKSFiles = allDirtyKSFiles.map { @@ -612,25 +608,6 @@ private inline fun getPsiFilesFromPaths( } } -class DirectoriesScope( - project: Project, - private val directories: Set -) : DelegatingGlobalSearchScope(GlobalSearchScope.allScope(project)) { - private val fileSystems = directories.mapTo(hashSetOf(), VirtualFile::getFileSystem) - - override fun contains(file: VirtualFile): Boolean { - if (file.fileSystem !in fileSystems) return false - - var parent: VirtualFile = file - while (true) { - if (parent in directories) return true - parent = parent.parent ?: return false - } - } - - override fun toString() = "All files under: $directories" -} - fun String?.toKotlinVersion(): KotlinVersion { if (this == null) return KotlinVersion.CURRENT 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 af20fbc3ef..09444cfff5 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,9 +18,11 @@ @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") package com.google.devtools.ksp.standalone -import com.google.devtools.ksp.impl.DirectoriesScope +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiManager +import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.analysis.project.structure.builder.KtModuleBuilder import org.jetbrains.kotlin.analysis.project.structure.builder.KtModuleBuilderDsl @@ -38,7 +40,6 @@ import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.io.path.isDirectory -import kotlin.io.path.pathString @KtModuleBuilderDsl class KspModuleBuilder( @@ -62,10 +63,7 @@ class KspModuleBuilder( val virtualFiles = collectVirtualFilesByRoots() val psiManager = PsiManager.getInstance(kotlinCoreProjectEnvironment.project) val psiFiles = virtualFiles.mapNotNull { psiManager.findFile(it) } - val project = kotlinCoreProjectEnvironment.project - val fs = kotlinCoreProjectEnvironment.environment.localFileSystem - val contentScope = - DirectoriesScope(project, sourceRoots.mapNotNull { fs.findFileByPath(it.pathString) }.toSet()) + val contentScope = IncrementalGlobalSearchScope(kotlinCoreProjectEnvironment.project, virtualFiles) return KtSourceModuleImpl( directRegularDependencies, directDependsOnDependencies, @@ -97,6 +95,22 @@ class KspModuleBuilder( } } +class IncrementalGlobalSearchScope( + project: Project, + initialSet: Collection = emptyList(), +) : GlobalSearchScope(project) { + // TODO: optimize space with trie. + val files = mutableSetOf().apply { addAll(initialSet) } + + fun addAll(files: Collection) = this.files.addAll(files) + + override fun contains(file: VirtualFile): Boolean = file in files + + override fun isSearchInLibraries(): Boolean = false + + override fun isSearchInModuleContent(aModule: Module): Boolean = true +} + @OptIn(ExperimentalContracts::class) public inline fun KtModuleProviderBuilder.buildKspSourceModule( init: KspModuleBuilder.() -> Unit From 37fa5e95a6ffb4d75bef28475b6015d5218e1a07 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Fri, 24 May 2024 12:19:48 -0700 Subject: [PATCH 40/64] Skip Java files when platform isn't JVM (cherry picked from commit ee445e1317721f3db7ff3c156acd040d5a393fbd) --- .../ksp/impl/KotlinSymbolProcessing.kt | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) 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 99f3cac109..2e6741a277 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 @@ -331,7 +331,7 @@ class KotlinSymbolProcessing( private fun prepareAllKSFiles( kotlinCoreProjectEnvironment: KotlinCoreProjectEnvironment, modules: List, - javaFileManager: IncrementalJavaFileManager, + javaFileManager: IncrementalJavaFileManager?, ): List { val project = kotlinCoreProjectEnvironment.project val ktFiles = mutableListOf() @@ -340,7 +340,7 @@ class KotlinSymbolProcessing( it.sourceRoots.forEach { when (it) { is KtFile -> ktFiles.add(it) - is PsiJavaFile -> javaFiles.add(it) + is PsiJavaFile -> if (javaFileManager != null) javaFiles.add(it) } } } @@ -358,7 +358,7 @@ class KotlinSymbolProcessing( ).update(ktFiles) // Update Java providers for newly generated source files. - javaFileManager.initialize(modules, javaFiles) + javaFileManager?.initialize(modules, javaFiles) return ktFiles.map { analyze { KSFileImpl.getCached(it.getFileSymbol()) } } + javaFiles.map { KSFileJavaImpl.getCached(it) } @@ -366,7 +366,7 @@ class KotlinSymbolProcessing( private fun prepareNewKSFiles( kotlinCoreProjectEnvironment: KotlinCoreProjectEnvironment, - javaFileManager: IncrementalJavaFileManager, + javaFileManager: IncrementalJavaFileManager?, newKotlinFiles: List, newJavaFiles: List, ): List { @@ -375,10 +375,12 @@ class KotlinSymbolProcessing( project, newKotlinFiles.map { it.toPath() }.toSet() ) - val javaFiles = getPsiFilesFromPaths( - project, - newJavaFiles.map { it.toPath() }.toSet() - ) + val javaFiles = if (javaFileManager != null) { + getPsiFilesFromPaths( + project, + newJavaFiles.map { it.toPath() }.toSet() + ) + } else emptyList() // Add new files to content scope. val contentScope = ResolverAAImpl.ktModule.contentScope as IncrementalGlobalSearchScope @@ -398,7 +400,7 @@ class KotlinSymbolProcessing( ).update(ktFiles) // Update Java providers for newly generated source files. - javaFileManager.add(javaFiles) + javaFileManager?.add(javaFiles) return ktFiles.map { analyze { KSFileImpl.getCached(it.getFileSymbol()) } } + javaFiles.map { KSFileJavaImpl.getCached(it) } @@ -451,7 +453,10 @@ class KotlinSymbolProcessing( ResolverAAImpl.ktModule = modules.single() as KtSourceModule // Initializing environments - val javaFileManager = IncrementalJavaFileManager(kotlinCoreProjectEnvironment) + val javaFileManager = if (kspConfig is KSPJvmConfig) { + IncrementalJavaFileManager(kotlinCoreProjectEnvironment) + } else null + val allKSFiles = prepareAllKSFiles(kotlinCoreProjectEnvironment, modules, javaFileManager) val anyChangesWildcard = AnyChanges(kspConfig.projectBaseDir) From fbdf428f64c9deb8b2492ab5b1c78d15bc9c4b81 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Fri, 24 May 2024 12:56:53 -0700 Subject: [PATCH 41/64] Avoid duplicated sources (cherry picked from commit 2e6bacc92c35b5b8d61060e204ff2e094b8f1188) --- .../devtools/ksp/impl/KotlinSymbolProcessing.kt | 11 +++++------ .../ksp/standalone/IncrementalJavaFileManager.kt | 4 ++-- .../devtools/ksp/standalone/KspSourceModuleBuilder.kt | 6 +++--- 3 files changed, 10 insertions(+), 11 deletions(-) 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 2e6741a277..347a1b03cd 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 @@ -334,8 +334,8 @@ class KotlinSymbolProcessing( javaFileManager: IncrementalJavaFileManager?, ): List { val project = kotlinCoreProjectEnvironment.project - val ktFiles = mutableListOf() - val javaFiles = mutableListOf() + val ktFiles = mutableSetOf() + val javaFiles = mutableSetOf() modules.filterIsInstance().forEach { it.sourceRoots.forEach { when (it) { @@ -357,7 +357,6 @@ class KotlinSymbolProcessing( ) as IncrementalKotlinPackageProviderFactory ).update(ktFiles) - // Update Java providers for newly generated source files. javaFileManager?.initialize(modules, javaFiles) return ktFiles.map { analyze { KSFileImpl.getCached(it.getFileSymbol()) } } + @@ -374,13 +373,13 @@ class KotlinSymbolProcessing( val ktFiles = getPsiFilesFromPaths( project, newKotlinFiles.map { it.toPath() }.toSet() - ) + ).toSet() val javaFiles = if (javaFileManager != null) { getPsiFilesFromPaths( project, newJavaFiles.map { it.toPath() }.toSet() - ) - } else emptyList() + ).toSet() + } else emptySet() // Add new files to content scope. val contentScope = ResolverAAImpl.ktModule.contentScope as IncrementalGlobalSearchScope 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 48f04aae82..fed119ab34 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 @@ -30,7 +30,7 @@ class IncrementalJavaFileManager(val environment: KotlinCoreProjectEnvironment) fun initialize( modules: List, - sourceFiles: List, + sourceFiles: Set, ) { val project = environment.project val javaFileManager = project.getService(JavaFileManager::class.java) as KotlinCliJavaFileManagerImpl @@ -91,7 +91,7 @@ class IncrementalJavaFileManager(val environment: KotlinCoreProjectEnvironment) ) } - fun add(sourceFiles: List) { + fun add(sourceFiles: Set) { val project = environment.project val javaFileManager = project.getService(JavaFileManager::class.java) as KotlinCliJavaFileManagerImpl val allSourceFileRoots = sourceFiles.map { JavaRoot(it.virtualFile, JavaRoot.RootType.SOURCE) } 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 09444cfff5..5b75d55151 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 @@ -49,7 +49,7 @@ class KspModuleBuilder( public var languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST) - private val sourceRoots: MutableList = mutableListOf() + private val sourceRoots: MutableSet = mutableSetOf() fun addSourceRoot(path: Path) { sourceRoots.add(path) @@ -77,9 +77,9 @@ class KspModuleBuilder( ) } - private fun collectVirtualFilesByRoots(): List { + private fun collectVirtualFilesByRoots(): Set { val localFileSystem = kotlinCoreProjectEnvironment.environment.localFileSystem - return buildList { + return buildSet { for (root in sourceRoots) { val files = when { root.isDirectory() -> collectSourceFilePaths(root) From 4668ed3374215d86d0fff02b48cf7f587e96bf4e Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Fri, 24 May 2024 17:18:49 -0700 Subject: [PATCH 42/64] More tests for KSP2 command line tool (cherry picked from commit 319e095d1ad61a89f621ba116ea2bd3d5b034372) --- integration-tests/build.gradle.kts | 1 + .../devtools/ksp/test/KSPCmdLineOptionsIT.kt | 117 ++++++++++++++++++ .../src/main/kotlin/TestProcessor.kt | 5 + 3 files changed, 123 insertions(+) diff --git a/integration-tests/build.gradle.kts b/integration-tests/build.gradle.kts index b227018d71..38572e5de0 100644 --- a/integration-tests/build.gradle.kts +++ b/integration-tests/build.gradle.kts @@ -31,6 +31,7 @@ tasks.withType { dependsOn(":symbol-processing:publishAllPublicationsToTestRepository") dependsOn(":symbol-processing-cmdline:publishAllPublicationsToTestRepository") dependsOn(":kotlin-analysis-api:publishAllPublicationsToTestRepository") + dependsOn(":symbol-processing-aa-embeddable:publishAllPublicationsToTestRepository") // JDK_9 environment property is required. // To add a custom location (if not detected automatically) follow https://docs.gradle.org/current/userguide/toolchains.html#sec:custom_loc diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KSPCmdLineOptionsIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KSPCmdLineOptionsIT.kt index bb6dcc6804..02296d34c4 100644 --- a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KSPCmdLineOptionsIT.kt +++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KSPCmdLineOptionsIT.kt @@ -12,6 +12,8 @@ import org.junit.runners.Parameterized import java.io.ByteArrayOutputStream import java.io.File import java.io.PrintStream +import java.lang.reflect.InvocationTargetException +import java.lang.reflect.Method import java.net.URLClassLoader data class CompileResult(val exitCode: ExitCode, val output: String) @@ -92,6 +94,121 @@ class KSPCmdLineOptionsIT(val useKSP2: Boolean) { ) } + private fun getKsp2Main(mainClassName: String): Method { + val repoPath = "../build/repos/test/com/google/devtools/ksp/" + + val commonDepsJar = File("$repoPath/symbol-processing-common-deps/2.0.255-SNAPSHOT").listFiles()!!.filter { + it.name.matches(Regex(".*-\\d.jar")) + }.maxByOrNull { it.lastModified() }!! + val kspMainJar = File("$repoPath/symbol-processing-aa-embeddable/2.0.255-SNAPSHOT").listFiles()!!.filter { + it.name.matches(Regex(".*-\\d.jar")) + }.maxByOrNull { it.lastModified() }!! + val kspApiJar = File("$repoPath/symbol-processing-api/2.0.255-SNAPSHOT").listFiles()!!.filter { + it.name.matches(Regex(".*-\\d.jar")) + }.maxByOrNull { it.lastModified() }!! + + val kspClasspath = listOf( + commonDepsJar, kspMainJar, kspApiJar + ).map { it.toURI().toURL() }.toTypedArray() + val classLoader = URLClassLoader(kspClasspath) + val kspMainClass = classLoader.loadClass(mainClassName) + + return kspMainClass.getMethod( + "main", + Array::class.java, + ) + } + + private fun getKsp2SharedArgs(): List { + val outDir = "${project.root.path}/build/out" + val srcDir = "${project.root.path}/workload/src/" + + return listOf( + "-module-name=main", + "-project-base-dir", project.root.path, + "-source-roots", srcDir, + "-output-base-dir=$outDir", + "-caches-dir=$outDir", + "-class-output-dir=$outDir", + "-kotlin-output-dir=$outDir", + "-resource-output-dir", outDir, + "-language-version=2.0", + "-api-version=2.0", + ) + } + + fun testKsp2(mainClassName: String, platformArgs: List) { + Assume.assumeTrue(useKSP2) + + val sharedArgs = getKsp2SharedArgs() + val kspMain = getKsp2Main(mainClassName) + + val gradleRunner = GradleRunner.create().withProjectDir(project.root) + gradleRunner.withArguments("clean", ":processors:build").build() + val processorJar = File(project.root, "processors/build/libs/processors-1.0-SNAPSHOT.jar").absolutePath + + val outDir = "${project.root.path}/build/out" + val args = sharedArgs + platformArgs + listOf(processorJar) + + kspMain.invoke(null, args.toTypedArray()) + + val status = File(outDir, "Status.log") + Assert.assertTrue(status.exists() && status.readText() == "OK") + + val args2 = args + listOf("-processor-options", "error=true") + Assert.assertThrows(IllegalStateException::class.java) { + try { + kspMain.invoke(null, args2.toTypedArray()) + } catch (e: InvocationTargetException) { + Assert.assertTrue(e.targetException is IllegalStateException) + Assert.assertTrue(e.targetException.message == "Error on request") + throw e.targetException + } + } + } + + @Test + fun testKSPJvmMain() { + val outDir = "${project.root.path}/build/out" + testKsp2( + "com.google.devtools.ksp.cmdline.KSPJvmMain", + listOf( + "-java-output-dir", outDir, + "-jvm-target", "11", + ) + ) + } + + @Test + fun testKSPCommonMain() { + testKsp2( + "com.google.devtools.ksp.cmdline.KSPCommonMain", + listOf( + "-targets=common", + ) + ) + } + + @Test + fun testKSPJsMain() { + testKsp2( + "com.google.devtools.ksp.cmdline.KSPJsMain", + listOf( + "-backend=JS", + ) + ) + } + + @Test + fun testKSPNativeMain() { + testKsp2( + "com.google.devtools.ksp.cmdline.KSPNativeMain", + listOf( + "-target=LinuxX64" + ) + ) + } + companion object { @JvmStatic @Parameterized.Parameters(name = "KSP2={0}") diff --git a/integration-tests/src/test/resources/cmd-options/processors/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/cmd-options/processors/src/main/kotlin/TestProcessor.kt index c38d2298ea..1ef3968d55 100644 --- a/integration-tests/src/test/resources/cmd-options/processors/src/main/kotlin/TestProcessor.kt +++ b/integration-tests/src/test/resources/cmd-options/processors/src/main/kotlin/TestProcessor.kt @@ -22,6 +22,11 @@ class TestProcessor : SymbolProcessor { if (options.containsKey("error")) { throw IllegalStateException("Error on request") } + if (rounds++ == 0) { + codeGenerator.createNewFile(Dependencies.ALL_FILES, "", "Status", "log").use { + it.write("OK".toByteArray()) + } + } return emptyList() } } From 83b5740afbe1b0c2091e1aa7a305a3bdb40051b3 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Fri, 24 May 2024 17:21:03 -0700 Subject: [PATCH 43/64] Simplify exception handling in KspAATask (cherry picked from commit e479a7e3917e6947f6690af64c18c38d11c2292f) --- .../main/kotlin/com/google/devtools/ksp/gradle/KspAATask.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 4b1c93a8ba..9700eee296 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 @@ -527,8 +527,7 @@ abstract class KspAAWorkerAction : WorkAction { gradleCfg.logLevel.get().ordinal ) as Int ExitCode.values()[returnCode] - } catch (e: Exception) { - require(e is InvocationTargetException) + } catch (e: InvocationTargetException) { kspGradleLogger.exception(e.targetException) throw e.targetException } From c01df1b9e33c97ca132a09ae770d57bfb9f9490b Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Tue, 28 May 2024 10:55:35 -0700 Subject: [PATCH 44/64] Increase Gradle heap size to 4GB. (cherry picked from commit d0b01b548328a0df4380c32ee42c755ffaabff5c) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1c37fc9afa..66fddb2d9d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Copied from kotlinc -org.gradle.jvmargs=-Duser.country=US -Dkotlin.daemon.jvm.options=-Xmx2200m -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Duser.country=US -Dkotlin.daemon.jvm.options=-Xmx4096m -Dfile.encoding=UTF-8 kotlinBaseVersion=2.0.0 agpBaseVersion=7.2.0 From db2f3f5384b9a3f48ab420dbd897cc55917581e9 Mon Sep 17 00:00:00 2001 From: Henrik Persson Date: Fri, 24 May 2024 10:11:34 +0200 Subject: [PATCH 45/64] Fix doc typo (cherry picked from commit df1a1afed59a8136f37c2e3304bab7fd30553957) --- api/src/main/kotlin/com/google/devtools/ksp/utils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/kotlin/com/google/devtools/ksp/utils.kt b/api/src/main/kotlin/com/google/devtools/ksp/utils.kt index 15a4cac39a..42bd9fb9e9 100644 --- a/api/src/main/kotlin/com/google/devtools/ksp/utils.kt +++ b/api/src/main/kotlin/com/google/devtools/ksp/utils.kt @@ -73,7 +73,7 @@ fun Resolver.getPropertyDeclarationByName(name: String, includeTopLevel: Boolean /** * Find the containing file of a KSNode. * @return KSFile if the given KSNode has a containing file. - * exmample of symbols without a containing file: symbols from class files, synthetic symbols craeted by user. + * exmample of symbols without a containing file: symbols from class files, synthetic symbols created by user. */ val KSNode.containingFile: KSFile? get() { From 1c3757e816e9856e52295eda7e3d561ba84ba7f6 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Tue, 28 May 2024 13:40:43 -0700 Subject: [PATCH 46/64] docs: information about nightly builds (cherry picked from commit ccc6fb9463e6b17150aba4b7461a2d1f45582e42) --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 0cecafb0b5..08c6f3d726 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,14 @@ For debugging and testing processors, as well as KSP itself, please check [DEVEL KSP2 is a new implementation of the KSP API. It will be faster and easier to use than KSP 1.x. Please refer to the [KSP2 introduction](docs/ksp2.md) for more details. +### Nightly Builds +Nightly builds of KSP for the latest Kotlin stable releases are published +[here](https://oss.sonatype.org/content/repositories/snapshots/com/google/devtools/ksp/). + +``` +maven("https://oss.sonatype.org/content/repositories/snapshots") +``` + ## Feedback and Bug Reporting [Please let us know what you think about KSP by filing a Github issue](https://github.com/google/ksp/issues) From 74c346993af4d6a14b582a5f3f1208137191a253 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Tue, 28 May 2024 13:04:57 -0700 Subject: [PATCH 47/64] Bump Guava version to 33.2.0. (cherry picked from commit 3f13a8effb41ea0572166e425de419994260bbeb) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 66fddb2d9d..48059a2b88 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ googleTruthVersion=1.1 aaKotlinBaseVersion=2.0.20-dev-3728 aaIntellijVersion=213.7172.25 -aaGuavaVersion=29.0-jre +aaGuavaVersion=33.2.0-jre aaAsmVersion=9.0 aaFastutilVersion=8.5.4-9 aaStax2Version=4.2.1 From a131866021b59daa29cb175a89850d9767690e58 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Thu, 30 May 2024 10:36:18 -0700 Subject: [PATCH 48/64] KSP2 embeddable: rename javax.annotation which is introduced by newer Guava as a transitive dependency. It is not exposed to callers and therefore safe to rename. (cherry picked from commit 8e99202e56d3ac836dc3bc3a15575160cf831157) --- symbol-processing-aa-embeddable/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/symbol-processing-aa-embeddable/build.gradle.kts b/symbol-processing-aa-embeddable/build.gradle.kts index a8c70ac5bc..9ef9914465 100644 --- a/symbol-processing-aa-embeddable/build.gradle.kts +++ b/symbol-processing-aa-embeddable/build.gradle.kts @@ -48,6 +48,7 @@ val prefixesToRelocate = listOf( "it.unimi.dsi.", "javaslang.", "javax.inject.", + "javax.annotation.", "kotlinx.collections.immutable.", "kotlinx.coroutines.", "org.apache.log4j.", From f2424ee5259dd1e919d8c22e360b3b03695f49d4 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Tue, 28 May 2024 19:34:10 -0700 Subject: [PATCH 49/64] optimize annotation default value evaluation. Annotation values without a default value should still be returned in default arguments to ensure consistency. (cherry picked from commit efa9491a6f07def59d545cc229c914f2253906f3) --- .../impl/symbol/java/KSAnnotationJavaImpl.kt | 22 ++++++++--- .../impl/symbol/kotlin/KSAnnotationImpl.kt | 15 +++++-- .../impl/symbol/kotlin/KSValueArgumentImpl.kt | 28 ------------- .../devtools/ksp/impl/symbol/kotlin/util.kt | 39 ++++++++++++++++--- .../testData/annotationValue/java.kt | 9 +++++ .../testData/annotationValue/kotlin.kt | 15 +++++++ 6 files changed, 86 insertions(+), 42 deletions(-) diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt index 6e3f3ee85d..10ef120458 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt @@ -37,7 +37,10 @@ import com.intellij.psi.PsiLiteralValue import com.intellij.psi.PsiPrimitiveType import com.intellij.psi.PsiReference import com.intellij.psi.PsiType +import com.intellij.psi.impl.compiled.ClsClassImpl +import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue +import org.jetbrains.kotlin.analysis.api.annotations.KtUnsupportedAnnotationValue import org.jetbrains.kotlin.analysis.api.components.buildClassType import org.jetbrains.kotlin.analysis.api.lifetime.KtAlwaysAccessibleLifetimeToken import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol @@ -89,11 +92,13 @@ class KSAnnotationJavaImpl private constructor(private val psi: PsiAnnotation, o presentArgs + defaultArguments.filter { it.name?.asString() !in presentValueArgumentNames } } + @OptIn(KtAnalysisApiInternals::class) override val defaultArguments: List by lazy { analyze { (type.classifierSymbol() as? KtClassOrObjectSymbol)?.getMemberScope()?.getConstructors()?.singleOrNull() ?.let { symbol -> - if (symbol.origin == KtSymbolOrigin.JAVA && symbol.psi != null) { + // ClsClassImpl means psi is decompiled psi. + if (symbol.origin == KtSymbolOrigin.JAVA && symbol.psi != null && symbol.psi !is ClsClassImpl) { (symbol.psi as PsiClass).allMethods.filterIsInstance() .mapNotNull { annoMethod -> annoMethod.defaultValue?.let { @@ -113,13 +118,20 @@ class KSAnnotationJavaImpl private constructor(private val psi: PsiAnnotation, o } } } else { - symbol.valueParameters.mapNotNull { valueParameterSymbol -> - valueParameterSymbol.getDefaultValue()?.let { constantValue -> + symbol.valueParameters.map { valueParameterSymbol -> + valueParameterSymbol.getDefaultValue().let { constantValue -> KSValueArgumentImpl.getCached( KtNamedAnnotationValue( valueParameterSymbol.name, - constantValue, - KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project!!) + // null will be returned as the `constantValue` for non array annotation values. + // fallback to unsupported annotation value to indicate such use cases. + // when seeing unsupported annotation value we return `null` for the value. + // which might still be incorrect but there might not be a perfect way. + constantValue + ?: KtUnsupportedAnnotationValue( + KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project) + ), + KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project) ), Origin.SYNTHETIC ) diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt index a84c04b5d0..fc9798264c 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt @@ -28,8 +28,11 @@ import com.google.devtools.ksp.symbol.* import com.intellij.psi.PsiAnnotationMethod import com.intellij.psi.PsiArrayInitializerMemberValue import com.intellij.psi.PsiClass +import com.intellij.psi.impl.compiled.ClsClassImpl +import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationWithArgumentsInfo import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue +import org.jetbrains.kotlin.analysis.api.annotations.KtUnsupportedAnnotationValue import org.jetbrains.kotlin.analysis.api.components.buildClassType import org.jetbrains.kotlin.analysis.api.lifetime.KtAlwaysAccessibleLifetimeToken import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin @@ -71,10 +74,11 @@ class KSAnnotationImpl private constructor( presentArgs + absentArgs } + @OptIn(KtAnalysisApiInternals::class) override val defaultArguments: List by lazy { analyze { annotationApplication.classId?.toKtClassSymbol()?.let { symbol -> - if (symbol.origin == KtSymbolOrigin.JAVA && symbol.psi != null) { + if (symbol.origin == KtSymbolOrigin.JAVA && symbol.psi != null && symbol.psi !is ClsClassImpl) { (symbol.psi as PsiClass).allMethods.filterIsInstance() .mapNotNull { annoMethod -> annoMethod.defaultValue?.let { value -> @@ -94,12 +98,15 @@ class KSAnnotationImpl private constructor( } } else { symbol.getMemberScope().getConstructors().singleOrNull()?.let { - it.valueParameters.mapNotNull { valueParameterSymbol -> - valueParameterSymbol.getDefaultValue()?.let { constantValue -> + it.valueParameters.map { valueParameterSymbol -> + valueParameterSymbol.getDefaultValue().let { constantValue -> KSValueArgumentImpl.getCached( KtNamedAnnotationValue( valueParameterSymbol.name, - constantValue, + constantValue + ?: KtUnsupportedAnnotationValue( + KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project) + ), KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project) ), Origin.SYNTHETIC 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 f981f4fa7a..f07636784e 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 @@ -20,14 +20,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.symbol.* -import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationValue -import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationValue -import org.jetbrains.kotlin.analysis.api.annotations.KtArrayAnnotationValue -import org.jetbrains.kotlin.analysis.api.annotations.KtConstantAnnotationValue -import org.jetbrains.kotlin.analysis.api.annotations.KtEnumEntryAnnotationValue -import org.jetbrains.kotlin.analysis.api.annotations.KtKClassAnnotationValue import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue -import org.jetbrains.kotlin.analysis.api.annotations.KtUnsupportedAnnotationValue class KSValueArgumentImpl private constructor( private val namedAnnotationValue: KtNamedAnnotationValue, @@ -63,26 +56,5 @@ class KSValueArgumentImpl private constructor( return "${name?.asString() ?: ""}:$value" } - private fun KtAnnotationValue.toValue(): Any? = when (this) { - is KtArrayAnnotationValue -> this.values.map { it.toValue() } - is KtAnnotationApplicationValue -> KSAnnotationImpl.getCached(this.annotationValue) - // TODO: Enum entry should return a type, use declaration as a placeholder. - is KtEnumEntryAnnotationValue -> this.callableId?.classId?.let { - analyze { - it.toKtClassSymbol()?.let { - it.declarations().filterIsInstance().singleOrNull { - it.simpleName.asString() == this@toValue.callableId?.callableName?.asString() - } - } - } - } ?: KSErrorType - // TODO: handle local classes. - is KtKClassAnnotationValue -> { - KSTypeImpl.getCached(this@toValue.type) - } - is KtConstantAnnotationValue -> this.constantValue.value - is KtUnsupportedAnnotationValue -> null - } - override fun defer(): Restorable = Restorable { getCached(namedAnnotationValue, origin) } } 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 55be27508b..7ac911ef75 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 @@ -31,6 +31,7 @@ import com.google.devtools.ksp.impl.symbol.util.getDocString import com.google.devtools.ksp.symbol.* import com.intellij.psi.PsiElement import com.intellij.psi.PsiJavaFile +import com.intellij.psi.impl.compiled.ClsMemberImpl import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.KtStarTypeProjection @@ -71,6 +72,7 @@ import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.isAny import org.jetbrains.kotlin.load.java.structure.JavaAnnotationArgument import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl +import org.jetbrains.kotlin.load.java.structure.impl.JavaUnknownAnnotationArgumentImpl import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryClassSignatureParser import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaAnnotationVisitor import org.jetbrains.kotlin.load.java.structure.impl.classFiles.ClassifierResolutionContext @@ -429,6 +431,26 @@ internal inline fun KSNode.findParentOfType(): KSNode? { return result } +internal fun KtAnnotationValue.toValue(): Any? = when (this) { + is KtArrayAnnotationValue -> this.values.map { it.toValue() } + is KtAnnotationApplicationValue -> KSAnnotationImpl.getCached(this.annotationValue) + // TODO: Enum entry should return a type, use declaration as a placeholder. + is KtEnumEntryAnnotationValue -> this.callableId?.classId?.let { + analyze { + it.toKtClassSymbol()?.let { + it.declarations().filterIsInstance().singleOrNull { + it.simpleName.asString() == this@toValue.callableId?.callableName?.asString() + } + } + } + } ?: KSErrorType + is KtKClassAnnotationValue -> { + KSTypeImpl.getCached(this@toValue.type) + } + is KtConstantAnnotationValue -> this.constantValue.value + is KtUnsupportedAnnotationValue -> null +} + @OptIn(SymbolInternals::class) internal fun KtValueParameterSymbol.getDefaultValue(): KtAnnotationValue? { fun FirExpression.toValue(builder: KtSymbolByFirBuilder): KtAnnotationValue? { @@ -473,7 +495,8 @@ internal fun KtValueParameterSymbol.getDefaultValue(): KtAnnotationValue? { is KtParameter -> analyze { it.defaultValue?.evaluateAsAnnotationValue() } - null -> { + // ClsMethodImpl means the psi is decompiled psi. + null, is ClsMemberImpl<*> -> { val fileManager = ResolverAAImpl.instance.javaFileManager val parentClass = this.getContainingKSSymbol()!!.findParentOfType() val classId = (parentClass as KSClassDeclarationImpl).ktClassOrObjectSymbol.classIdIfNonLocal!! @@ -511,12 +534,18 @@ internal fun KtValueParameterSymbol.getDefaultValue(): KtAnnotationValue? { val firSession = it.firSymbol.fir.moduleData.session val symbolBuilder = it.builder val expectedTypeRef = it.firSymbol.fir.returnTypeRef - val expression = defaultValue - ?.toFirExpression(firSession, JavaTypeParameterStack.EMPTY, expectedTypeRef, null) - expression?.toValue(symbolBuilder) + // when no default value is declared in the class file, ideally users should + // apply a value for such property at use site, therefore value obtained here should not be + // returned. In case of a user failed to do so, we try our best to return values + // to ensure no annotation argument is missing from KSP side. + // Supplying `JavaUnknownAnnotationArgumentImpl` as the expression base + // will produce empty array for array type values and `null` for the rest of value types. + val expression = (defaultValue ?: JavaUnknownAnnotationArgumentImpl(null)) + .toFirExpression(firSession, JavaTypeParameterStack.EMPTY, expectedTypeRef, null) + expression.toValue(symbolBuilder) } } - else -> throw IllegalStateException("Unhandled default value type ${it.javaClass}") + else -> throw IllegalStateException("Unhandled default value type ${it?.javaClass}") } } } diff --git a/kotlin-analysis-api/testData/annotationValue/java.kt b/kotlin-analysis-api/testData/annotationValue/java.kt index c5bd2a3e37..b8859d32f3 100644 --- a/kotlin-analysis-api/testData/annotationValue/java.kt +++ b/kotlin-analysis-api/testData/annotationValue/java.kt @@ -24,6 +24,8 @@ // MyClassInLib: stringParam = 2 // MyClassInLib: stringParam2 = 1 // MyClassInLib: stringArrayParam = [3, 5, 7] +// [] +// null // Str // 42 // Foo @@ -48,6 +50,12 @@ import java.lang.annotation.Target; String stringParam2() default "1"; String[] stringArrayParam() default {"3", "5", "7"}; } + +@interface Default { + Class[] value(); + int value1(); +} + interface MyInterface {} @MyAnnotation(stringParam = "2") class MyClassInLib implements MyInterface {} // MODULE: main(module1) @@ -82,6 +90,7 @@ class C { } // FILE: JavaAnnotated.java +@Default @Bar(argStr = "Str", argInt = 40 + 2, argClsUser = Foo.class, diff --git a/kotlin-analysis-api/testData/annotationValue/kotlin.kt b/kotlin-analysis-api/testData/annotationValue/kotlin.kt index cb62ad2b65..6b55577c2b 100644 --- a/kotlin-analysis-api/testData/annotationValue/kotlin.kt +++ b/kotlin-analysis-api/testData/annotationValue/kotlin.kt @@ -19,6 +19,10 @@ // TEST PROCESSOR: AnnotationArgumentProcessor // EXPECTED: // defaultInNested +// [] +// null +// null +// null // SomeClass$WithDollarSign // Str // 42 @@ -35,6 +39,16 @@ // 31 // Throws // END +// MODULE: module1 +// FILE: placeholder.kt +// FILE: TestLib.java +@interface Default { + Class[] value(); + int value1(); + String value2(); + Class value3(); +} +// MODULE: main(module1) // FILE: a.kt enum class RGB { @@ -73,6 +87,7 @@ annotation class Bar( fun Fun() { @Foo.Nested + @Default @MyAnnotation(`SomeClass$WithDollarSign`::class) @Bar( "Str", From c9a10f397636f33d9043b69500155de26ef56bc9 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Wed, 15 May 2024 23:02:49 -0700 Subject: [PATCH 50/64] handle internal names and JvmName annotations for name mangling. (cherry picked from commit 4b50035c2202bbe8e15ee3da647a5138080b5b6a) --- .../devtools/ksp/impl/ResolverAAImpl.kt | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) 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 393e4afbd4..18ac2faa69 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 @@ -63,10 +63,12 @@ import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getFirResolveSession import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule +import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCliJavaFileManagerImpl import org.jetbrains.kotlin.fir.types.isRaw import org.jetbrains.kotlin.fir.types.typeContext +import org.jetbrains.kotlin.light.classes.symbol.methods.SymbolLightSimpleMethod import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.load.kotlin.getOptimalModeForReturnType @@ -75,6 +77,7 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.org.objectweb.asm.Opcodes @@ -480,8 +483,18 @@ class ResolverAAImpl( } } - // TODO: handle @JvmName annotations, mangled names + // TODO: handle library symbols override fun getJvmName(accessor: KSPropertyAccessor): String? { + ( + (accessor.receiver.closestClassDeclaration() as? KSClassDeclarationImpl) + ?.ktClassOrObjectSymbol?.psi as? KtClassOrObject + )?.toLightClass()?.allMethods?.filterIsInstance() + ?.singleOrNull { + (it.parameters.isNotEmpty() xor (accessor is KSPropertyGetter)) && + it.kotlinOrigin == (accessor.receiver as? KSPropertyDeclarationImpl)?.ktPropertySymbol?.psi + }?.let { + return it.name + } if (accessor.receiver.closestClassDeclaration()?.classKind == ClassKind.ANNOTATION_CLASS) { return accessor.receiver.simpleName.asString() } @@ -490,12 +503,25 @@ class ResolverAAImpl( } else { "set" } - return "${prefix}${accessor.receiver.simpleName.asString().capitalize()}" + val mangledName = if (accessor.modifiers.contains(Modifier.INTERNAL)) { + "\$${ktModule.moduleName}" + } else "" + return "${prefix}${accessor.receiver.simpleName.asString().capitalize()}$mangledName" } - // TODO: handle @JvmName annotations, mangled names + // TODO: handle library symbols override fun getJvmName(declaration: KSFunctionDeclaration): String? { - return declaration.simpleName.asString() + (declaration.closestClassDeclaration() as? KSClassDeclarationImpl)?.ktDeclarationSymbol?.psi?.let { + (it as? KtClassOrObject)?.toLightClass() + }?.allMethods?.filterIsInstance()?.singleOrNull { + it.kotlinOrigin == (declaration as KSFunctionDeclarationImpl).ktFunctionSymbol.psi + }?.let { + return it.name + } + val mangledName = if (declaration.modifiers.contains(Modifier.INTERNAL)) { + "\$${ktModule.moduleName}" + } else "" + return declaration.simpleName.asString() + mangledName } override fun getKSNameFromString(name: String): KSName { From e2b608619c782b6e3d19d9e060a48b6ded898187 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Thu, 30 May 2024 11:36:41 -0700 Subject: [PATCH 51/64] CI: remove nightly and no slow targets on PR The former is getting too slow. (cherry picked from commit 5491eac96cb1302bf481dc719fa64292c5662663) --- .github/workflows/main.yml | 17 ++++++++- .github/workflows/nightly.yml | 72 ----------------------------------- 2 files changed, 15 insertions(+), 74 deletions(-) delete mode 100644 .github/workflows/nightly.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3fc5efa584..f9a4ce83c5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,12 +13,25 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest] + os: [ ubuntu-latest, macos-latest, windows-latest ] + is_pull_request: + - ${{ github.event_name == 'pull_request' }} + exclude: + # Don't run slow targets on pull request. + - is_pull_request: true + os: macos-latest # The type of runner that the job will run on runs-on: ${{ matrix.os }} steps: + - name: configure Pagefile + if: matrix.os == 'windows-latest' + uses: al-cheb/configure-pagefile-action@v1.2 + with: + minimum-size: 8 + maximum-size: 16 + disk-root: "D:" - name: Setup Java 9 uses: actions/setup-java@v1.4.3 with: @@ -72,7 +85,7 @@ jobs: if: always() uses: actions/upload-artifact@v3 with: - name: test-reports-${{ matrix.os }} + name: test-reports-${{ matrix.branch }}-${{ matrix.os }} path: | compiler-plugin/build/reports integration-tests/build/reports diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml deleted file mode 100644 index f64052fe60..0000000000 --- a/.github/workflows/nightly.yml +++ /dev/null @@ -1,72 +0,0 @@ -on: - # runs on 4:30 AM PST or 5:30 AM PDT - schedule: - - cron: '30 12 * * *' -jobs: - build-and-test: - strategy: - fail-fast: false - matrix: - branch: [ main, 1.0.21-release, 1.0.22-release ] - runs-on: windows-latest - steps: - - name: configure Pagefile - uses: al-cheb/configure-pagefile-action@v1.2 - with: - minimum-size: 8 - maximum-size: 16 - disk-root: "D:" - - name: Setup Java 9 - uses: actions/setup-java@v1.4.3 - with: - java-version: '9' - java-package: jdk - architecture: x64 - - name: set JDK_9 environment variable for kotlin compiler - shell: bash - env: - ACTIONS_ALLOW_UNSECURE_COMMANDS: true - run: echo ::set-env name=JDK_9::$(echo $JAVA_HOME) - - name: Setup Java 11 - uses: actions/setup-java@v1.4.3 - with: - java-version: '11' - java-package: jdk - architecture: x64 - - # Checkout - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - ref: ${{ matrix.branch }} - - # Build cache - - name: Cache Gradle Cache - uses: actions/cache@v2 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}-${{ hashFiles('**/gradle.properties') }} - # An ordered list of keys to use for restoring the cache if no cache hit occurred for key - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache gradle wrapper - uses: actions/cache@v2 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} - - # Run tests - - name: test - shell: bash - run: ./gradlew --stacktrace --info test - - name: Upload test results - if: always() - uses: actions/upload-artifact@v3 - with: - name: test-reports-windows-latest - path: | - compiler-plugin/build/reports - integration-tests/build/reports - gradle-plugin/build/reports - common-util/build/reports - kotlin-analysis-api/build/reports From 9beb51d788ea5a696eb25cb00d229f1665b530f9 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Thu, 30 May 2024 13:19:19 -0700 Subject: [PATCH 52/64] CI: simplify auto-merger Only test on ubuntu-latest (cherry picked from commit 5945177e8e915db4ef35994f9fca71ab8e96ce08) --- .github/workflows/auto-merge.yml | 150 ++++++++++++------------------- 1 file changed, 56 insertions(+), 94 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index f684fd5c83..c28ea52c01 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -7,110 +7,20 @@ on: branches: [ main ] jobs: - build-and-test: + pick-test-push: strategy: fail-fast: false - matrix: - os: [ ubuntu-latest, macos-latest ] # The type of runner that the job will run on - runs-on: ${{ matrix.os }} - - steps: - # Checkout - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - ref: 1.0.22-release - - - name: merge commits from main to release branch - run: | - # Cherry pick new changes from main, except for version bumps. - # A commit is a version bump IFF it touches third_party/prebuilt/repo - DONT_PICK=$(cat <=0;) print a[j--] }') - echo Picking $TO_PICK - if [ -n "$TO_PICK" ]; then git cherry-pick -x $TO_PICK; fi - - - name: Setup Java 9 - uses: actions/setup-java@v1.4.3 - with: - java-version: '9' - java-package: jdk - architecture: x64 - - name: set JDK_9 environment variable for kotlin compiler - env: - ACTIONS_ALLOW_UNSECURE_COMMANDS: true - run: echo ::set-env name=JDK_9::$(echo $JAVA_HOME) - - name: Setup Java 11 - uses: actions/setup-java@v1.4.3 - with: - java-version: '11' - java-package: jdk - architecture: x64 - - # Build cache - - name: Cache Gradle Cache - uses: actions/cache@v2 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}-${{ hashFiles('**/gradle.properties') }} - # An ordered list of keys to use for restoring the cache if no cache hit occurred for key - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache gradle wrapper - uses: actions/cache@v2 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} - - # Check API compatibility - - name: API compatibility check - run: ./gradlew :api:checkApi - - # Run ksp generated tests - - name: test - run: ./gradlew --stacktrace --info test - - - name: Upload test results - if: always() - uses: actions/upload-artifact@v3 - with: - name: test-reports - path: | - compiler-plugin/build/reports - integration-tests/build/reports - gradle-plugin/build/reports - common-util/build/reports - kotlin-analysis-api/build/reports - - pick-and-push: - needs: build-and-test runs-on: ubuntu-latest steps: - # Checkout + # Checkout - uses: actions/checkout@v2 with: fetch-depth: 0 ref: 1.0.22-release - + - name: merge commits from main to release branch run: | # Cherry pick new changes from main, except for version bumps. @@ -132,10 +42,62 @@ jobs: CANDIDATES=$(git log --pretty=%H $MERGE_BASE..origin/main) PICKED=$(git log $MERGE_BASE..HEAD | sed -n "s/^[ ]*(cherry picked from commit \([a-z0-9]*\))$/\1/p") VERSION_BUMPS=$(git log $MERGE_BASE..origin/main --pretty=%H --grep UPDATE_KOTLIN_VERSION) - TO_PICK=$(grep -Fxv -f <(echo "$PICKED"; echo "$VERSION_BUMPS"; echo "$DONT_PICK") <(echo "$CANDIDATES") | tac) + TO_PICK=$(grep -Fxv -f <(echo "$PICKED"; echo "$VERSION_BUMPS"; echo "$DONT_PICK") <(echo "$CANDIDATES") | awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }') echo Picking $TO_PICK if [ -n "$TO_PICK" ]; then git cherry-pick -x $TO_PICK; fi + + - name: Setup Java 9 + uses: actions/setup-java@v1.4.3 + with: + java-version: '9' + java-package: jdk + architecture: x64 + - name: set JDK_9 environment variable for kotlin compiler + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + run: echo ::set-env name=JDK_9::$(echo $JAVA_HOME) + - name: Setup Java 11 + uses: actions/setup-java@v1.4.3 + with: + java-version: '11' + java-package: jdk + architecture: x64 + + # Build cache + - name: Cache Gradle Cache + uses: actions/cache@v2 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}-${{ hashFiles('**/gradle.properties') }} + # An ordered list of keys to use for restoring the cache if no cache hit occurred for key + restore-keys: | + ${{ runner.os }}-gradle- + - name: Cache gradle wrapper + uses: actions/cache@v2 + with: + path: ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} + + # Check API compatibility + - name: API compatibility check + run: ./gradlew :api:checkApi + + # Run ksp generated tests + - name: test + run: ./gradlew --stacktrace --info test - name: push to release branch + if: success() run: git push origin + - name: Upload test results + if: always() + uses: actions/upload-artifact@v3 + with: + name: test-reports + path: | + compiler-plugin/build/reports + integration-tests/build/reports + gradle-plugin/build/reports + common-util/build/reports + kotlin-analysis-api/build/reports From 2445534946c74821b74b17e92d5e0d1e87f8e0fc Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Thu, 30 May 2024 14:48:28 -0700 Subject: [PATCH 53/64] Disable commandline test on Windows. (cherry picked from commit 7ef20d452841aeebc9b6a139d302757a31e16f3d) --- .../kotlin/com/google/devtools/ksp/test/KSPCmdLineOptionsIT.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KSPCmdLineOptionsIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KSPCmdLineOptionsIT.kt index 02296d34c4..0186dfc4d1 100644 --- a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KSPCmdLineOptionsIT.kt +++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KSPCmdLineOptionsIT.kt @@ -139,6 +139,7 @@ class KSPCmdLineOptionsIT(val useKSP2: Boolean) { fun testKsp2(mainClassName: String, platformArgs: List) { Assume.assumeTrue(useKSP2) + Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) val sharedArgs = getKsp2SharedArgs() val kspMain = getKsp2Main(mainClassName) From bcc7460f2c650a44fb4cdba78a4fe67d552995b8 Mon Sep 17 00:00:00 2001 From: riQQ Date: Thu, 30 May 2024 22:15:54 +0200 Subject: [PATCH 54/64] Editorial improvements in ksp2.md - fix typo - fix capitalization of the word *GitHub* (cherry picked from commit d8efe453f331f0568ffc8c3f2f64a1cbbd951a81) --- docs/ksp2.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ksp2.md b/docs/ksp2.md index 4cb30cd5eb..e198b86fb7 100644 --- a/docs/ksp2.md +++ b/docs/ksp2.md @@ -32,7 +32,7 @@ for example: `org.gradle.jvmargs=-Xmx4096M -XX:MaxMetaspaceSize=1024m` pass the system property `-Dorg.gradle.debug=true` in the Gradle command line. ## Transitioning from KSP1 to KSP2 -KSP1 and KSP2 are supported by an unified KSP Gradle plugin. The current versioning scheme, +KSP1 and KSP2 are supported by a unified KSP Gradle plugin. The current versioning scheme, `-`, will remain at least until KSP1 is deprecated. This allows switching between KSP1 and KSP2 easily with a single `ksp.useKSP2=` property in Gradle projects. @@ -58,7 +58,7 @@ The main gaps between KSP2 Beta and KSP2 Stable are: * Some type of annotation values are not supported (e.g. nested annotations) Please check the KSP [2.0](https://github.com/google/ksp/issues?q=is%3Aopen+is%3Aissue+milestone%3A2.0) and -[2.1](https://github.com/google/ksp/issues?q=is%3Aopen+is%3Aissue+milestone%3A2.1) milestones on github for the complete +[2.1](https://github.com/google/ksp/issues?q=is%3Aopen+is%3Aissue+milestone%3A2.1) milestones on GitHub for the complete lists of known issues. ## Feedback From c77e1702f7ba931f49b767dcb98dfc84f57540b4 Mon Sep 17 00:00:00 2001 From: Fedor Ihnatkevich Date: Fri, 31 May 2024 14:13:52 +0200 Subject: [PATCH 55/64] #1232: Include type hint into KSErrorType. This CL makes `KSErrorType` a class with a string "hint", that by convention should be a "simpleName" of an unresolved type. `KSErrorTypeClassDeclaration` is also no longer a singleton and references a corresponding `KSErrorType`. The implementation consists of extracting the available info on the unresolved type on the best effort basis. (cherry picked from commit 1e8486ea80b3d966a9c645c30156924c48c39750) --- .../ksp/processing/impl/ResolverImpl.kt | 23 +++--- .../impl/binary/KSAnnotationDescriptorImpl.kt | 21 +++-- .../KSClassDeclarationDescriptorImpl.kt | 2 +- .../KSClassDeclarationJavaEnumEntryImpl.kt | 2 +- .../impl/java/KSClassDeclarationJavaImpl.kt | 4 +- .../impl/java/KSTypeReferenceJavaImpl.kt | 12 +-- .../impl/java/KSTypeReferenceLiteJavaImpl.kt | 5 +- .../impl/kotlin/KSClassDeclarationImpl.kt | 2 +- .../ksp/symbol/impl/kotlin/KSErrorType.kt | 76 ++++++++++++++++--- .../symbol/impl/kotlin/KSFunctionErrorImpl.kt | 7 +- .../impl/kotlin/KSPropertyDeclarationImpl.kt | 2 +- .../ksp/symbol/impl/kotlin/KSTypeImpl.kt | 12 +-- .../impl/kotlin/KSValueParameterImpl.kt | 2 +- .../synthetic/KSErrorTypeClassDeclaration.kt | 74 ++++++++++++------ .../devtools/ksp/impl/ResolverAAImpl.kt | 6 +- .../impl/symbol/java/KSAnnotationJavaImpl.kt | 16 ++-- .../symbol/kotlin/KSClassDeclarationImpl.kt | 2 +- .../ksp/impl/symbol/kotlin/KSErrorType.kt | 34 ++++++--- .../kotlin/KSErrorTypeClassDeclaration.kt | 73 ++++++++++++------ .../impl/symbol/kotlin/KSFunctionErrorImpl.kt | 7 +- .../ksp/impl/symbol/kotlin/KSTypeImpl.kt | 10 +-- .../impl/symbol/kotlin/KSValueArgumentImpl.kt | 39 ++++++++++ .../resolved/KSTypeReferenceResolvedImpl.kt | 9 ++- .../devtools/ksp/impl/symbol/kotlin/util.kt | 27 ++++++- .../testData/annotationValue/java.kt | 2 +- .../testData/annotationValue/kotlin.kt | 4 +- .../testData/replaceWithErrorTypeArgs.kt | 16 ++-- .../testData/api/annotationValue_java.kt | 2 +- test-utils/testData/api/annotationValue_kt.kt | 4 +- test-utils/testData/api/asMemberOf.kt | 10 +-- test-utils/testData/api/multipleround.kt | 24 +++--- test-utils/testData/api/parameterTypes.kt | 4 +- 32 files changed, 368 insertions(+), 165 deletions(-) diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt index 533fb9181b..cb6640a66c 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt @@ -692,7 +692,8 @@ class ResolverImpl( builtIns.arrayType.replace(typeArgs) } else -> { - getClassDeclarationByName(psiType.canonicalText)?.asStarProjectedType() ?: KSErrorType + getClassDeclarationByName(psiType.canonicalText)?.asStarProjectedType() + ?: KSErrorType(psiType.canonicalText) } } } @@ -1054,7 +1055,7 @@ class ResolverImpl( } } // if substitution fails, fallback to the type from the property - return KSErrorType + return KSErrorType.fromReferenceBestEffort(property.type) } internal fun asMemberOf( @@ -1247,7 +1248,7 @@ class ResolverImpl( } // Convert type arguments for Java wildcard, recursively. - private fun KotlinType.toWildcard(mode: TypeMappingMode): KotlinType? { + private fun KotlinType.toWildcard(mode: TypeMappingMode): KotlinType { val parameters = constructor.parameters val arguments = arguments @@ -1258,8 +1259,10 @@ class ResolverImpl( argument.projectionKind != org.jetbrains.kotlin.types.Variance.INVARIANT ) { // conflicting variances - // TODO: error message - return null + throw IllegalArgumentException( + "Conflicting variance: variance '${parameter.variance.label}' vs projection " + + "'${argument.projectionKind.label}'" + ) } val argMode = mode.updateFromAnnotations(argument.type) @@ -1267,7 +1270,7 @@ class ResolverImpl( val genericMode = argMode.toGenericArgumentMode( getEffectiveVariance(parameter.variance, argument.projectionKind) ) - TypeProjectionImpl(variance, argument.type.toWildcard(genericMode) ?: return null) + TypeProjectionImpl(variance, argument.type.toWildcard(genericMode)) } return replace(wildcardArguments) @@ -1369,19 +1372,17 @@ class ResolverImpl( if (position == RefPosition.SUPER_TYPE && argument.projectionKind != org.jetbrains.kotlin.types.Variance.INVARIANT ) { - // Type projection isn't allowed in immediate arguments to supertypes. - // TODO: error message - return KSTypeReferenceSyntheticImpl.getCached(KSErrorType, null) + throw IllegalArgumentException("Type projection isn't allowed in immediate arguments to supertypes") } } - val wildcardType = kotlinType.toWildcard(typeMappingMode)?.let { + val wildcardType = kotlinType.toWildcard(typeMappingMode).let { var candidate: KotlinType = it for (i in indexes.reversed()) { candidate = candidate.arguments[i].type } getKSTypeCached(candidate) - } ?: KSErrorType + } return KSTypeReferenceSyntheticImpl.getCached(wildcardType, null) } diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSAnnotationDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSAnnotationDescriptorImpl.kt index 4df03abc8e..4ebb7fbc34 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSAnnotationDescriptorImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSAnnotationDescriptorImpl.kt @@ -62,7 +62,9 @@ import org.jetbrains.kotlin.load.kotlin.getContainingKotlinJvmBinaryClass import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtClassLiteralExpression import org.jetbrains.kotlin.psi.KtCollectionLiteralExpression +import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.resolve.AnnotationResolverImpl import org.jetbrains.kotlin.resolve.BindingContext @@ -161,7 +163,7 @@ private fun ConstantValue.toValue(parent: KSNode): Any? = when (this) { } else classValue.classId.findKSType() is KClassValue.Value.LocalClass -> getKSTypeCached(classValue.type) } - is ErrorValue -> KSErrorType + is ErrorValue -> KSErrorType(toString()) is NullValue -> null else -> value } @@ -211,7 +213,7 @@ fun LazyAnnotationDescriptor.getValueArguments(): Map> { } else if (resolvedArgument is DefaultValueArgument) { valueParameter.name to DefaultConstantValue } else { - c.annotationResolver.getAnnotationArgumentValue(c.trace, valueParameter, resolvedArgument)?.let { value -> + c.annotationResolver.getAnnotationArgumentValue(c.trace, valueParameter, resolvedArgument).let { value -> val argExp = resolvedArgument.arguments.lastOrNull()?.getArgumentExpression() // When some elements are not available, the expected and actual size of an array argument will // be different. In such case, we need to reconstruct the array. @@ -224,17 +226,22 @@ fun LazyAnnotationDescriptor.getValueArguments(): Map> { val bc = ResolverImpl.instance!!.bindingTrace.bindingContext val args = argExp.innerExpressions.map { bc.get(BindingContext.COMPILE_TIME_VALUE, it)?.toConstantValue(value.type) - ?: ErrorValue.create("") + ?: it.asErrorValue() } valueParameter.name to TypedArrayValue(args, value.type) } else { - valueParameter.name to value + valueParameter.name to (value ?: argExp?.asErrorValue() ?: ErrorValue.create("ERROR VALUE")) } - } ?: (valueParameter.name to ErrorValue.create("")) + } } }.toMap() } +private fun KtExpression.asErrorValue(): ErrorValue { + val reprExpr = (this as? KtClassLiteralExpression)?.receiverExpression ?: this + return ErrorValue.create(reprExpr.text) +} + fun AnnotationDescriptor.createKSValueArguments(ownerAnnotation: KSAnnotation): List { val allValueArgs = if (this is LazyAnnotationDescriptor) { this.getValueArguments() @@ -419,14 +426,14 @@ fun ValueParameterDescriptor.getDefaultValue(ownerAnnotation: KSAnnotation): Any if (!this.type.isError) { defaultValue?.convert(this.type)?.toValue(ownerAnnotation) } else { - KSErrorType + KSErrorType.fromKtErrorType(type) } } } is KtParameter -> if (!this.type.isError) { ResolverImpl.instance!!.evaluateConstant(psi.defaultValue, this.type)?.toValue(ownerAnnotation) } else { - KSErrorType + KSErrorType.fromKtErrorType(type) } is PsiAnnotationMethod -> { when (psi.defaultValue) { diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt index e771bddb71..f1cb2c74bb 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt @@ -153,7 +153,7 @@ class KSClassDeclarationDescriptorImpl private constructor(val descriptor: Class override fun asType(typeArguments: List): KSType = descriptor.defaultType.replaceTypeArguments(typeArguments)?.let { getKSTypeCached(it, typeArguments) - } ?: KSErrorType + } ?: KSErrorType() override fun asStarProjectedType(): KSType { return getKSTypeCached(descriptor.defaultType.replaceArgumentsWithStarProjections()) diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt index 7f74e0a912..337ce251b7 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt @@ -97,7 +97,7 @@ class KSClassDeclarationJavaEnumEntryImpl private constructor(val psi: PsiEnumCo // Enum can't have type parameters. override fun asType(typeArguments: List): KSType { if (typeArguments.isNotEmpty()) - return KSErrorType + return KSErrorType() return asStarProjectedType() } diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt index 2eb4d01466..2a0481dea4 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt @@ -157,13 +157,13 @@ class KSClassDeclarationJavaImpl private constructor(val psi: PsiClass) : it.defaultType.replaceTypeArguments(typeArguments)?.let { getKSTypeCached(it, typeArguments) } - } ?: KSErrorType + } ?: KSErrorType() } override fun asStarProjectedType(): KSType { return descriptor?.let { getKSTypeCached(it.defaultType.replaceArgumentsWithStarProjections()) - } ?: KSErrorType + } ?: KSErrorType() } override fun accept(visitor: KSVisitor, data: D): R { diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeReferenceJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeReferenceJavaImpl.kt index de33ac5da2..ebd6f0c2b9 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeReferenceJavaImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeReferenceJavaImpl.kt @@ -124,11 +124,13 @@ class KSTypeReferenceJavaImpl private constructor(val psi: PsiType, override val .mapNotNull { (it.annotationType.resolve() as? KSTypeImpl)?.kotlinType?.constructor?.declarationDescriptor?.fqNameSafe } - val resolved = if ((resolvedType.declaration as? KSClassDeclarationDescriptorImpl) - ?.descriptor is NotFoundClasses.MockClassDescriptor - ) { - KSErrorType - } else resolvedType + val resolved = when (val declaration = resolvedType.declaration) { + is KSClassDeclarationDescriptorImpl -> when (val descriptor = declaration.descriptor) { + is NotFoundClasses.MockClassDescriptor -> KSErrorType(descriptor.name.asString()) + else -> resolvedType + } + else -> resolvedType + } val hasNotNull = relatedAnnotations.any { it in NOT_NULL_ANNOTATIONS } val hasNullable = relatedAnnotations.any { it in NULLABLE_ANNOTATIONS } return if (hasNullable && !hasNotNull) { diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeReferenceLiteJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeReferenceLiteJavaImpl.kt index a62747a618..b5fab32173 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeReferenceLiteJavaImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeReferenceLiteJavaImpl.kt @@ -47,13 +47,14 @@ class KSTypeReferenceLiteJavaImpl private constructor(val psiElement: PsiElement val type: KSType by lazy { when (psiElement) { is PsiAnnotation -> { - val psiClass = psiElement.nameReferenceElement!!.resolve() as? PsiClass + val nameReferenceElement = psiElement.nameReferenceElement!! + val psiClass = nameReferenceElement.resolve() as? PsiClass psiClass?.let { (psiElement.containingFile as? PsiJavaFile)?.let { ResolverImpl.instance!!.incrementalContext.recordLookup(it, psiClass.qualifiedName!!) } KSClassDeclarationJavaImpl.getCached(psiClass).asStarProjectedType() - } ?: KSErrorType + } ?: KSErrorType(nameReferenceElement.text) } is PsiMethod -> { KSClassDeclarationJavaImpl.getCached(psiElement.containingClass!!).asStarProjectedType() diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt index 340020fdac..393a679469 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt @@ -124,7 +124,7 @@ class KSClassDeclarationImpl private constructor(val ktClassOrObject: KtClassOrO override fun asType(typeArguments: List): KSType { return descriptor.defaultType.replaceTypeArguments(typeArguments)?.let { getKSTypeCached(it, typeArguments) - } ?: KSErrorType + } ?: KSErrorType() } override fun asStarProjectedType(): KSType { diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt index 8cf66385e4..c911474b02 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt @@ -19,17 +19,28 @@ package com.google.devtools.ksp.symbol.impl.kotlin import com.google.devtools.ksp.symbol.* import com.google.devtools.ksp.symbol.impl.synthetic.KSErrorTypeClassDeclaration +import org.jetbrains.kotlin.types.FlexibleType +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.error.ErrorType +import org.jetbrains.kotlin.types.error.ErrorTypeKind -object KSErrorType : KSType { - override val annotations: Sequence = emptySequence() +class KSErrorType( + val nameHint: String? = null, +) : KSType { + override val annotations: Sequence + get() = emptySequence() - override val arguments: List = emptyList() + override val arguments: List + get() = emptyList() - override val declaration: KSDeclaration = KSErrorTypeClassDeclaration + override val declaration: KSDeclaration + get() = KSErrorTypeClassDeclaration(this) - override val isError: Boolean = true + override val isError: Boolean + get() = true - override val nullability: Nullability = Nullability.NULLABLE + override val nullability: Nullability + get() = Nullability.NULLABLE override fun isAssignableFrom(that: KSType): Boolean { return false @@ -51,7 +62,8 @@ object KSErrorType : KSType { return this } - override val isMarkedNullable: Boolean = false + override val isMarkedNullable: Boolean + get() = false override fun replace(arguments: List): KSType { return this @@ -61,11 +73,51 @@ object KSErrorType : KSType { return this } - override fun toString(): String { - return "" - } + override fun toString(): String = nameHint?.let { "" } ?: "" + + override val isFunctionType: Boolean + get() = false + + override val isSuspendFunctionType: Boolean + get() = false - override val isFunctionType: Boolean = false + override fun hashCode() = nameHint.hashCode() - override val isSuspendFunctionType: Boolean = false + override fun equals(other: Any?): Boolean { + return this === other || other is KSErrorType && other.nameHint == nameHint + } + + companion object { + fun fromReferenceBestEffort(reference: KSTypeReference?): KSErrorType { + return when (val type = reference?.resolve()) { + is KSErrorType -> type + null -> KSErrorType(reference?.element?.toString()) + else -> KSErrorType(type.toString()) + } + } + + fun fromKtErrorType(ktType: KotlinType): KSErrorType { + // Logic is in sync with `KotlinType.isError` + val errorType: ErrorType = when (val unwrapped = ktType.unwrap()) { + is ErrorType -> unwrapped + is FlexibleType -> unwrapped.delegate as? ErrorType + else -> null + } ?: throw IllegalArgumentException("Not an error type: $ktType") + + val hint = when (errorType.kind) { + // Handle "Unresolved types" group + ErrorTypeKind.UNRESOLVED_TYPE, + ErrorTypeKind.UNRESOLVED_CLASS_TYPE, + ErrorTypeKind.UNRESOLVED_JAVA_CLASS, + ErrorTypeKind.UNRESOLVED_DECLARATION, + ErrorTypeKind.UNRESOLVED_KCLASS_CONSTANT_VALUE, + ErrorTypeKind.UNRESOLVED_TYPE_ALIAS -> errorType.formatParams.first() + + // TODO: Handle more ErrorTypeKinds where it's possible to extract a name for the error type. + else -> errorType.debugMessage + } + + return KSErrorType(hint) + } + } } diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionErrorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionErrorImpl.kt index 5100e367e8..c1f9ee6a05 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionErrorImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionErrorImpl.kt @@ -29,18 +29,19 @@ class KSFunctionErrorImpl( ) : KSFunction { override val isError: Boolean = true - override val returnType: KSType = KSErrorType + override val returnType: KSType + get() = KSErrorType.fromReferenceBestEffort(declaration.returnType) override val parameterTypes: List get() = declaration.parameters.map { - KSErrorType + KSErrorType.fromReferenceBestEffort(it.type) } override val typeParameters: List get() = emptyList() override val extensionReceiverType: KSType? get() = declaration.extensionReceiver?.let { - KSErrorType + KSErrorType.fromReferenceBestEffort(it) } override fun equals(other: Any?): Boolean { diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt index 2aa8ff1b43..0ea15def59 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt @@ -97,7 +97,7 @@ class KSPropertyDeclarationImpl private constructor(val ktProperty: KtProperty) KSTypeReferenceDeferredImpl.getCached(this) { val desc = propertyDescriptor as? VariableDescriptorWithAccessors if (desc == null) { - KSErrorType + KSErrorType() } else { getKSTypeCached(desc.type) } diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt index d4724f06ca..62f8b90cb1 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt @@ -97,7 +97,7 @@ class KSTypeImpl private constructor( override fun replace(arguments: List): KSType { return kotlinType.replaceTypeArguments(arguments)?.let { getKSTypeCached(it, arguments, annotations) - } ?: KSErrorType + } ?: KSErrorType() } override fun starProjection(): KSType { @@ -136,10 +136,12 @@ fun getKSTypeCached( ksTypeArguments: List? = null, annotations: Sequence = sequenceOf() ): KSType { - return if (kotlinType.isError || - kotlinType.constructor.declarationDescriptor is NotFoundClasses.MockClassDescriptor - ) { - KSErrorType + if (kotlinType.isError) { + return KSErrorType.fromKtErrorType(kotlinType) + } + val descriptor = kotlinType.constructor.declarationDescriptor + return if (descriptor is NotFoundClasses.MockClassDescriptor) { + KSErrorType(descriptor.name.asString()) } else { KSTypeImpl.getCached( kotlinType, diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt index 7dca3f70ca..5e95a12904 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt @@ -112,7 +112,7 @@ class KSValueParameterImpl private constructor(val ktParameter: KtParameter) : K override val type: KSTypeReference by lazy { ktParameter.typeReference?.let { KSTypeReferenceImpl.getCached(it) } - ?: findPropertyForAccessor()?.type ?: KSTypeReferenceSyntheticImpl.getCached(KSErrorType, this) + ?: findPropertyForAccessor()?.type ?: KSTypeReferenceSyntheticImpl.getCached(KSErrorType(), this) } override val hasDefault: Boolean = ktParameter.hasDefaultValue() diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSErrorTypeClassDeclaration.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSErrorTypeClassDeclaration.kt index 400a03b55d..db96c789ad 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSErrorTypeClassDeclaration.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSErrorTypeClassDeclaration.kt @@ -18,54 +18,73 @@ package com.google.devtools.ksp.symbol.impl.synthetic import com.google.devtools.ksp.common.impl.KSNameImpl -import com.google.devtools.ksp.processing.impl.ResolverImpl import com.google.devtools.ksp.symbol.* +import com.google.devtools.ksp.symbol.impl.kotlin.KSErrorType -object KSErrorTypeClassDeclaration : KSClassDeclaration { - override val annotations: Sequence = emptySequence() +class KSErrorTypeClassDeclaration( + private val type: KSErrorType, +) : KSClassDeclaration { + override val annotations: Sequence + get() = emptySequence() - override val classKind: ClassKind = ClassKind.CLASS + override val classKind: ClassKind + get() = ClassKind.CLASS - override val containingFile: KSFile? = null + override val containingFile: KSFile? + get() = null - override val declarations: Sequence = emptySequence() + override val declarations: Sequence + get() = emptySequence() - override val isActual: Boolean = false + override val isActual: Boolean + get() = false - override val isExpect: Boolean = false + override val isExpect: Boolean + get() = false - override val isCompanionObject: Boolean = false + override val isCompanionObject: Boolean + get() = false - override val location: Location = NonExistLocation + override val location: Location + get() = NonExistLocation - override val parent: KSNode? = null + override val parent: KSNode? + get() = null - override val modifiers: Set = emptySet() + override val modifiers: Set + get() = emptySet() - override val origin: Origin = Origin.SYNTHETIC + override val origin: Origin + get() = Origin.SYNTHETIC - override val packageName: KSName = KSNameImpl.getCached("") + override val packageName: KSName + get() = KSNameImpl.getCached("") - override val parentDeclaration: KSDeclaration? = null + override val parentDeclaration: KSDeclaration? + get() = null - override val primaryConstructor: KSFunctionDeclaration? = null + override val primaryConstructor: KSFunctionDeclaration? + get() = null - override val qualifiedName: KSName? = null + override val qualifiedName: KSName? + get() = null - override val simpleName: KSName = KSNameImpl.getCached("") + override val simpleName: KSName = KSNameImpl.getCached(type.toString()) - override val superTypes: Sequence = emptySequence() + override val superTypes: Sequence + get() = emptySequence() - override val typeParameters: List = emptyList() + override val typeParameters: List + get() = emptyList() override fun getSealedSubclasses(): Sequence = emptySequence() override fun asStarProjectedType(): KSType { - return ResolverImpl.instance!!.builtIns.nothingType + return type } override fun asType(typeArguments: List): KSType { - return ResolverImpl.instance!!.builtIns.nothingType + return type } override fun findActuals(): Sequence { @@ -89,8 +108,15 @@ object KSErrorTypeClassDeclaration : KSClassDeclaration { } override fun toString(): String { - return "Error type synthetic declaration" + return simpleName.asString() } - override val docString = null + override fun equals(other: Any?): Boolean { + return this === other || other is KSErrorTypeClassDeclaration && other.type == type + } + + override fun hashCode(): Int = type.hashCode() + + override val docString + get() = null } 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 18ac2faa69..04e0ed55cb 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 @@ -416,14 +416,14 @@ class ResolverAAImpl( }.updateFromParents(ref) } return analyze { - ktType.toWildcard(mode)?.let { + ktType.toWildcard(mode).let { var candidate: KtType = it for (i in indexes.reversed()) { candidate = candidate.typeArguments()[i].type!! } KSTypeReferenceSyntheticImpl.getCached(KSTypeImpl.getCached(candidate), null) } - } ?: reference + } } override fun getJvmCheckedException(accessor: KSPropertyAccessor): Sequence { @@ -832,7 +832,7 @@ class ResolverAAImpl( } } } else { - KSErrorType + return if (resolved.isError) resolved else KSErrorType(resolved.toString()) } } } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt index 10ef120458..dca4868a32 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt @@ -179,18 +179,19 @@ fun calcValue(value: PsiAnnotationMemberValue?): Any? { is PsiPrimitiveType -> { result.boxedTypeName?.let { ResolverAAImpl.instance - .getClassDeclarationByName(result.boxedTypeName!!)?.asStarProjectedType() ?: KSErrorType - } + .getClassDeclarationByName(it)?.asStarProjectedType() + } ?: KSErrorType(result.boxedTypeName) } is PsiArrayType -> { val componentType = when (val component = result.componentType) { - is PsiPrimitiveType -> component.boxedTypeName?.let { + is PsiPrimitiveType -> component.boxedTypeName?.let { boxedTypeName -> ResolverAAImpl.instance - .getClassDeclarationByName(component.boxedTypeName!!)?.asStarProjectedType() - } ?: KSErrorType + .getClassDeclarationByName(boxedTypeName)?.asStarProjectedType() + } ?: KSErrorType(component.boxedTypeName) else -> { ResolverAAImpl.instance - .getClassDeclarationByName(component.canonicalText)?.asStarProjectedType() ?: KSErrorType + .getClassDeclarationByName(component.canonicalText)?.asStarProjectedType() + ?: KSErrorType(component.canonicalText) } } val componentTypeRef = ResolverAAImpl.instance.createKSTypeReferenceFromKSType(componentType) @@ -200,7 +201,8 @@ fun calcValue(value: PsiAnnotationMemberValue?): Any? { } is PsiType -> { ResolverAAImpl.instance - .getClassDeclarationByName(result.canonicalText)?.asStarProjectedType() ?: KSErrorType + .getClassDeclarationByName(result.canonicalText)?.asStarProjectedType() + ?: KSErrorType(result.canonicalText) } is PsiLiteralValue -> { result.value 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 06fef7653d..6311ec3e0a 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 @@ -125,7 +125,7 @@ class KSClassDeclarationImpl private constructor(internal val ktClassOrObjectSym override fun asType(typeArguments: List): KSType { if (typeArguments.isNotEmpty() && typeArguments.size != asStarProjectedType().arguments.size) { - return KSErrorType + return KSErrorType() } return analyze { if (typeArguments.isEmpty()) { diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorType.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorType.kt index 1fae54507f..24dbfb7236 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorType.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorType.kt @@ -16,15 +16,13 @@ */ package com.google.devtools.ksp.impl.symbol.kotlin -import com.google.devtools.ksp.symbol.KSAnnotation -import com.google.devtools.ksp.symbol.KSDeclaration -import com.google.devtools.ksp.symbol.KSType -import com.google.devtools.ksp.symbol.KSTypeArgument -import com.google.devtools.ksp.symbol.Nullability +import com.google.devtools.ksp.symbol.* -object KSErrorType : KSType { +class KSErrorType( + private val hint: String? = null, +) : KSType { override val declaration: KSDeclaration - get() = KSErrorTypeClassDeclaration + get() = KSErrorTypeClassDeclaration(this) override val nullability: Nullability get() = Nullability.NULLABLE @@ -57,7 +55,25 @@ object KSErrorType : KSType { override val isSuspendFunctionType: Boolean = false - override fun toString(): String { - return "" + override fun toString(): String = hint?.let { "" } ?: "" + + override fun hashCode() = hint.hashCode() + + override fun equals(other: Any?): Boolean { + return this === other || other is KSErrorType && other.hint == hint + } + + companion object { + // As KSTypeImpl can also be `isError`, this function returns a KSType + // TODO: Make return exclusively KSErrorType + fun fromReferenceBestEffort(reference: KSTypeReference?): KSType { + return when (val type = reference?.resolve()) { + is KSErrorType -> type + null -> KSErrorType(hint = reference?.element?.toString()) + else -> { + type.takeIf { it.isError } ?: KSErrorType(hint = type.toString()) + } + } + } } } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorTypeClassDeclaration.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorTypeClassDeclaration.kt index a37498c955..ffc26dca3a 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorTypeClassDeclaration.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorTypeClassDeclaration.kt @@ -18,54 +18,72 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.common.impl.KSNameImpl -import com.google.devtools.ksp.impl.ResolverAAImpl import com.google.devtools.ksp.symbol.* -object KSErrorTypeClassDeclaration : KSClassDeclaration { - override val annotations: Sequence = emptySequence() +class KSErrorTypeClassDeclaration( + private val type: KSType, +) : KSClassDeclaration { + override val annotations: Sequence + get() = emptySequence() - override val classKind: ClassKind = ClassKind.CLASS + override val classKind: ClassKind + get() = ClassKind.CLASS - override val containingFile: KSFile? = null + override val containingFile: KSFile? + get() = null - override val declarations: Sequence = emptySequence() + override val declarations: Sequence + get() = emptySequence() - override val isActual: Boolean = false + override val isActual: Boolean + get() = false - override val isExpect: Boolean = false + override val isExpect: Boolean + get() = false - override val isCompanionObject: Boolean = false + override val isCompanionObject: Boolean + get() = false - override val location: Location = NonExistLocation + override val location: Location + get() = NonExistLocation - override val parent: KSNode? = null + override val parent: KSNode? + get() = null - override val modifiers: Set = emptySet() + override val modifiers: Set + get() = emptySet() - override val origin: Origin = Origin.SYNTHETIC + override val origin: Origin + get() = Origin.SYNTHETIC - override val packageName: KSName = KSNameImpl.getCached("") + override val packageName: KSName + get() = KSNameImpl.getCached("") - override val parentDeclaration: KSDeclaration? = null + override val parentDeclaration: KSDeclaration? + get() = null - override val primaryConstructor: KSFunctionDeclaration? = null + override val primaryConstructor: KSFunctionDeclaration? + get() = null - override val qualifiedName: KSName? = null + override val qualifiedName: KSName? + get() = null - override val simpleName: KSName = KSNameImpl.getCached("") + override val simpleName: KSName = KSNameImpl.getCached(type.toString()) - override val superTypes: Sequence = emptySequence() + override val superTypes: Sequence + get() = emptySequence() - override val typeParameters: List = emptyList() + override val typeParameters: List + get() = emptyList() override fun getSealedSubclasses(): Sequence = emptySequence() override fun asStarProjectedType(): KSType { - return ResolverAAImpl.instance.builtIns.nothingType + return type } override fun asType(typeArguments: List): KSType { - return ResolverAAImpl.instance.builtIns.nothingType + return type } override fun findActuals(): Sequence { @@ -89,8 +107,15 @@ object KSErrorTypeClassDeclaration : KSClassDeclaration { } override fun toString(): String { - return "Error type synthetic declaration" + return simpleName.asString() } - override val docString = null + override fun equals(other: Any?): Boolean { + return this === other || other is KSErrorTypeClassDeclaration && other.type == type + } + + override fun hashCode(): Int = type.hashCode() + + override val docString + get() = null } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFunctionErrorImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFunctionErrorImpl.kt index 6dc2f9b94f..d73bc653b8 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFunctionErrorImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFunctionErrorImpl.kt @@ -10,18 +10,19 @@ class KSFunctionErrorImpl( ) : KSFunction { override val isError: Boolean = true - override val returnType: KSType = KSErrorType + override val returnType: KSType + get() = KSErrorType.fromReferenceBestEffort(declaration.returnType) override val parameterTypes: List get() = declaration.parameters.map { - KSErrorType + KSErrorType.fromReferenceBestEffort(it.type) } override val typeParameters: List get() = emptyList() override val extensionReceiverType: KSType? get() = declaration.extensionReceiver?.let { - KSErrorType + KSErrorType.fromReferenceBestEffort(it) } override fun equals(other: Any?): Boolean { 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 1460a2668f..0a4ee80c07 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 @@ -51,11 +51,11 @@ class KSTypeImpl private constructor(internal val type: KtType) : KSType { } } is KtTypeParameterType -> KSTypeParameterImpl.getCached(symbol) - is KtClassErrorType -> KSErrorTypeClassDeclaration + is KtClassErrorType -> KSErrorTypeClassDeclaration(this@KSTypeImpl) is KtFlexibleType -> type.lowerBoundIfFlexible().toDeclaration() is KtDefinitelyNotNullType -> this@toDeclaration.original.toDeclaration() - else -> KSErrorTypeClassDeclaration + else -> KSErrorTypeClassDeclaration(this@KSTypeImpl) } } } @@ -110,12 +110,12 @@ class KSTypeImpl private constructor(internal val type: KtType) : KSType { } override fun replace(arguments: List): KSType { - return type.replace(arguments.map { it.toKtTypeProjection() })?.let { getCached(it) } ?: KSErrorType + return type.replace(arguments.map { it.toKtTypeProjection() })?.let { getCached(it) } ?: KSErrorType() } override fun starProjection(): KSType { return type.replace(List(type.typeArguments().size) { KtStarTypeProjection(type.token) }) - ?.let { getCached(it) } ?: KSErrorType + ?.let { getCached(it) } ?: KSErrorType() } override fun makeNullable(): KSType { @@ -134,7 +134,7 @@ class KSTypeImpl private constructor(internal val type: KtType) : KSType { get() = type.nullability == KtTypeNullability.NULLABLE override val isError: Boolean - get() = type is KtClassErrorType + get() = type is KtErrorType override val isFunctionType: Boolean get() = type is KtFunctionalType && !type.isSuspend 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 f07636784e..d3c3315752 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 @@ -55,6 +55,45 @@ class KSValueArgumentImpl private constructor( override fun toString(): String { return "${name?.asString() ?: ""}:$value" } +// +// private fun KtAnnotationValue.toValue(): Any? = when (this) { +// is KtArrayAnnotationValue -> this.values.map { it.toValue() } +// is KtAnnotationApplicationValue -> KSAnnotationImpl.getCached(this.annotationValue) +// // TODO: Enum entry should return a type, use declaration as a placeholder. +// is KtEnumEntryAnnotationValue -> this.callableId?.classId?.let { +// analyze { +// it.toKtClassSymbol()?.let { +// it.declarations().filterIsInstance().singleOrNull { +// it.simpleName.asString() == this@toValue.callableId?.callableName?.asString() +// } +// } +// } +// } ?: KSErrorType(callableId?.toString()) +// is KtKClassAnnotationValue -> { +// val classDeclaration = when (this) { +// is KtKClassAnnotationValue.KtNonLocalKClassAnnotationValue -> analyze { +// (this@toValue.classId.toKtClassSymbol())?.let { KSClassDeclarationImpl.getCached(it) } +// } +// is KtKClassAnnotationValue.KtLocalKClassAnnotationValue -> analyze { +// this@toValue.ktClass.getNamedClassOrObjectSymbol()?.let { +// KSClassDeclarationImpl.getCached(it) +// } +// } +// is KtKClassAnnotationValue.KtErrorClassAnnotationValue -> null +// } +// classDeclaration?.asStarProjectedType() ?: KSErrorType( +// when (this) { +// is KtKClassAnnotationValue.KtErrorClassAnnotationValue -> unresolvedQualifierName +// is KtKClassAnnotationValue.KtLocalKClassAnnotationValue -> ktClass.run { +// fqName?.asString() ?: name +// } +// is KtKClassAnnotationValue.KtNonLocalKClassAnnotationValue -> classId.asFqNameString() +// } ?: sourcePsi?.text +// ) +// } +// is KtConstantAnnotationValue -> this.constantValue.value +// is KtUnsupportedAnnotationValue -> null +// } override fun defer(): Restorable = Restorable { getCached(namedAnnotationValue, origin) } } 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 8302876cf5..c449f275ec 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 @@ -29,6 +29,7 @@ import com.google.devtools.ksp.impl.symbol.kotlin.Restorable import com.google.devtools.ksp.impl.symbol.kotlin.analyze import com.google.devtools.ksp.impl.symbol.kotlin.annotations import com.google.devtools.ksp.impl.symbol.kotlin.classifierSymbol +import com.google.devtools.ksp.impl.symbol.kotlin.getNameHint import com.google.devtools.ksp.impl.symbol.kotlin.render import com.google.devtools.ksp.impl.symbol.kotlin.toClassifierReference import com.google.devtools.ksp.impl.symbol.kotlin.toLocation @@ -66,7 +67,13 @@ class KSTypeReferenceResolvedImpl private constructor( ktType is KtClassErrorType || (ktType.classifierSymbol() == null) } ) { - KSErrorType + KSErrorType( + when (ktType) { + is KtClassErrorType -> ktType.getNameHint() + is KtTypeErrorType -> null // No info available + else -> ktType.render() + } + ) } else { KSTypeImpl.getCached(ktType) } 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 7ac911ef75..49fa2c0acd 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 @@ -62,6 +62,7 @@ import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack import org.jetbrains.kotlin.fir.java.toFirExpression +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedError import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.types.ConeClassLikeType @@ -138,12 +139,31 @@ internal fun KtAnnotationValue.render(): String { is KtArrayAnnotationValue -> values.joinToString(",", "{", "}") { it.render() } is KtConstantAnnotationValue -> constantValue.renderAsKotlinConstant() is KtEnumEntryAnnotationValue -> callableId.toString() - // TODO: handle error classes. - is KtKClassAnnotationValue -> "$classId::class" + is KtKClassAnnotationValue -> { + val type = KSTypeImpl.getCached(type) + // KSTypeImpl takes care of the error types, if applicable + if (type.isError) type.toString() else "$type::class" + } is KtUnsupportedAnnotationValue -> throw IllegalStateException("Unsupported annotation value: $this") } } +internal fun KtClassErrorType.getNameHint(): String { + return when (val coneType = (this as KtFirType).coneType) { + is ConeErrorType -> when (val diagnostic = coneType.diagnostic) { + is ConeUnresolvedError -> diagnostic.qualifier + else -> throw IllegalStateException("Unexpected diagnostic: ${diagnostic.reason}") + } + is ConeClassLikeType -> { + coneType.lookupTag.name.asString() + } + else -> { + // KtFirClassErrorType has `coneType: ConeClassLikeType`, so we're safe as long as that doesn't change + throw IllegalStateException("Unexpected coneType: $coneType") + } + } +} + internal fun KtType.render(inFunctionType: Boolean = false): String { return buildString { annotations.forEach { @@ -174,7 +194,8 @@ internal fun KtType.render(inFunctionType: Boolean = false): String { } } } - is KtClassErrorType, is KtTypeErrorType -> "" + is KtClassErrorType -> KSErrorType(getNameHint()).toString() + is KtTypeErrorType -> KSErrorType().toString() is KtCapturedType -> asStringForDebugging() is KtDefinitelyNotNullType -> original.render(inFunctionType) + " & Any" is KtDynamicType -> "" diff --git a/kotlin-analysis-api/testData/annotationValue/java.kt b/kotlin-analysis-api/testData/annotationValue/java.kt index b8859d32f3..738bd07443 100644 --- a/kotlin-analysis-api/testData/annotationValue/java.kt +++ b/kotlin-analysis-api/testData/annotationValue/java.kt @@ -30,7 +30,7 @@ // 42 // Foo // File -// Error type synthetic declaration +// // Array // @Foo // @Suppress diff --git a/kotlin-analysis-api/testData/annotationValue/kotlin.kt b/kotlin-analysis-api/testData/annotationValue/kotlin.kt index 6b55577c2b..277f593625 100644 --- a/kotlin-analysis-api/testData/annotationValue/kotlin.kt +++ b/kotlin-analysis-api/testData/annotationValue/kotlin.kt @@ -30,8 +30,8 @@ // File // Local // Array -// Error type synthetic declaration -// [, Foo] +// +// [, Foo] // @Foo // @Suppress // RGB.G diff --git a/kotlin-analysis-api/testData/replaceWithErrorTypeArgs.kt b/kotlin-analysis-api/testData/replaceWithErrorTypeArgs.kt index f0f76dd8da..20cb7f2e81 100644 --- a/kotlin-analysis-api/testData/replaceWithErrorTypeArgs.kt +++ b/kotlin-analysis-api/testData/replaceWithErrorTypeArgs.kt @@ -19,24 +19,24 @@ // TEST PROCESSOR: ReplaceWithErrorTypeArgsProcessor // EXPECTED: // KS.star.replace([INVARIANT Int, INVARIANT String]): KS -// KS.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): KS<, > +// KS.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): KS<, > // KS.asType([INVARIANT Int, INVARIANT String]): KS -// KS.asType([INVARIANT NotExist1, INVARIANT NotExist2]): KS<, > +// KS.asType([INVARIANT NotExist1, INVARIANT NotExist2]): KS<, > // KS.asType(emptyList()): KS // KL.star.replace([INVARIANT Int, INVARIANT String]): KL -// KL.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): KL<, > +// KL.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): KL<, > // KL.asType([INVARIANT Int, INVARIANT String]): KL -// KL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): KL<, > +// KL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): KL<, > // KL.asType(emptyList()): KL // JS.star.replace([INVARIANT Int, INVARIANT String]): JS -// JS.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): JS<, > +// JS.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): JS<, > // JS.asType([INVARIANT Int, INVARIANT String]): JS -// JS.asType([INVARIANT NotExist1, INVARIANT NotExist2]): JS<, > +// JS.asType([INVARIANT NotExist1, INVARIANT NotExist2]): JS<, > // JS.asType(emptyList()): JS // JL.star.replace([INVARIANT Int, INVARIANT String]): JL -// JL.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): JL<, > +// JL.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): JL<, > // JL.asType([INVARIANT Int, INVARIANT String]): JL -// JL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): JL<, > +// JL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): JL<, > // JL.asType(emptyList()): JL // KS1.star.replace([INVARIANT Int, INVARIANT String]): // KS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): diff --git a/test-utils/testData/api/annotationValue_java.kt b/test-utils/testData/api/annotationValue_java.kt index c611fe10dc..28e7f27af6 100644 --- a/test-utils/testData/api/annotationValue_java.kt +++ b/test-utils/testData/api/annotationValue_java.kt @@ -28,7 +28,7 @@ // 42 // Foo // File -// Error type synthetic declaration +// // Array // @Foo // @Suppress diff --git a/test-utils/testData/api/annotationValue_kt.kt b/test-utils/testData/api/annotationValue_kt.kt index 8d9bfd4916..00d93f0be9 100644 --- a/test-utils/testData/api/annotationValue_kt.kt +++ b/test-utils/testData/api/annotationValue_kt.kt @@ -26,8 +26,8 @@ // File // Local // Array -// Error type synthetic declaration -// [, Foo] +// +// [, Foo] // @Foo // @Suppress // G diff --git a/test-utils/testData/api/asMemberOf.kt b/test-utils/testData/api/asMemberOf.kt index d96346cccd..bbc4dc89b8 100644 --- a/test-utils/testData/api/asMemberOf.kt +++ b/test-utils/testData/api/asMemberOf.kt @@ -23,7 +23,7 @@ // baseTypeArg1: kotlin.Int!! // baseTypeArg2: kotlin.String? // typePair: kotlin.Pair!! -// errorType: ? +// errorType: ? // extensionProperty: kotlin.String? // returnInt: () -> kotlin.Int!! // returnArg1: () -> kotlin.Int!! @@ -40,7 +40,7 @@ // baseTypeArg1: kotlin.Any? // baseTypeArg2: kotlin.Any? // typePair: kotlin.Pair!! -// errorType: ? +// errorType: ? // extensionProperty: kotlin.Any? // returnInt: () -> kotlin.Int!! // returnArg1: () -> kotlin.Any? @@ -57,7 +57,7 @@ // baseTypeArg1: kotlin.String!! // baseTypeArg2: kotlin.String? // typePair: kotlin.Pair!! -// errorType: ? +// errorType: ? // extensionProperty: kotlin.String? // returnInt: () -> kotlin.Int!! // returnArg1: () -> kotlin.String!! @@ -96,7 +96,7 @@ // intType: kotlin.Int!! // typeArg1: kotlin.String // typeArg2: kotlin.Int -// errorType: ? +// errorType: ? // returnArg1: () -> kotlin.Int // receiveArgs: (kotlin.String, kotlin.Int, kotlin.Int!!) -> kotlin.Unit!! // methodArgType: (JavaBase.methodArgType.BaseTypeArg1, kotlin.Int) -> kotlin.Unit!! @@ -104,7 +104,7 @@ // fileLevelFunction: java.lang.IllegalArgumentException: Cannot call asMemberOf with a function that is not declared in a class or an interface // fileLevelExtensionFunction: java.lang.IllegalArgumentException: Cannot call asMemberOf with a function that is not declared in a class or an interface // fileLevelProperty: java.lang.IllegalArgumentException: Cannot call asMemberOf with a property that is not declared in a class or an interface -// errorType: (?) -> ? +// errorType: (?) -> ? // expected comparison failures // (Base.functionArgType.BaseTypeArg1?) -> kotlin.String? // () -> kotlin.Int!! diff --git a/test-utils/testData/api/multipleround.kt b/test-utils/testData/api/multipleround.kt index 1afec0cc26..e510eb5859 100644 --- a/test-utils/testData/api/multipleround.kt +++ b/test-utils/testData/api/multipleround.kt @@ -18,28 +18,28 @@ // TEST PROCESSOR: MultipleroundProcessor // EXPECTED: // Round 0: -// K : , , , , , -// J : , , , , , +// K : , , , , , +// J : , , , , , // +J.java, +K.kt // Round 1: -// K : I0, , , , , -// J : I0, , , , , +// K : I0, , , , , +// J : I0, , , , , // +I0.kt, J.java, K.kt // Round 2: -// K : I0, I1, , , , -// J : I0, I1, , , , +// K : I0, I1, , , , +// J : I0, I1, , , , // +I1.java, I0.kt, J.java, K.kt // Round 3: -// K : I0, I1, I2, , , -// J : I0, I1, I2, , , +// K : I0, I1, I2, , , +// J : I0, I1, I2, , , // +I2.kt, I0.kt, I1.java, J.java, K.kt // Round 4: -// K : I0, I1, I2, I3, , -// J : I0, I1, I2, I3, , +// K : I0, I1, I2, I3, , +// J : I0, I1, I2, I3, , // +I3.java, I0.kt, I1.java, I2.kt, J.java, K.kt // Round 5: -// K : I0, I1, I2, I3, I4, -// J : I0, I1, I2, I3, I4, +// K : I0, I1, I2, I3, I4, +// J : I0, I1, I2, I3, I4, // +I4.kt, I0.kt, I1.java, I2.kt, I3.java, J.java, K.kt // Round 6: // K : I0, I1, I2, I3, I4, I5 diff --git a/test-utils/testData/api/parameterTypes.kt b/test-utils/testData/api/parameterTypes.kt index 36fb2cdd8e..d102fbdcba 100644 --- a/test-utils/testData/api/parameterTypes.kt +++ b/test-utils/testData/api/parameterTypes.kt @@ -18,9 +18,9 @@ // TEST PROCESSOR: ParameterTypeProcessor // EXPECTED: // a: Int -// b: +// b: // c: -// errorValue: +// errorValue: // v: String // value: Int // END From 82871d85ebc79d0f1747384820379e45546691fb Mon Sep 17 00:00:00 2001 From: Fedor Ihnatkevich Date: Sat, 1 Jun 2024 12:48:08 +0200 Subject: [PATCH 56/64] Provide more hints for error types. Allow KSErrorType to receive a message as additional piece of information on why a valid type can't be provided. Cover `replace`/`asType` cases with a utility function `errorTypeOnInconsistentArguments` to get consistent error messages across implementations. Tweak KSTypeImpl.isError detection in AA, move TODO there. (cherry picked from commit 319ddffc791afc9e34e1d0b80d323635a6ef06c2) --- .../devtools/ksp/common/ErrorTypeUtils.kt | 24 ++++ .../ksp/processing/impl/ResolverImpl.kt | 26 ++-- .../KSClassDeclarationDescriptorImpl.kt | 4 +- .../KSClassDeclarationJavaEnumEntryImpl.kt | 7 +- .../impl/java/KSClassDeclarationJavaImpl.kt | 8 +- .../impl/kotlin/KSClassDeclarationImpl.kt | 4 +- .../ksp/symbol/impl/kotlin/KSErrorType.kt | 6 +- .../impl/kotlin/KSPropertyDeclarationImpl.kt | 2 +- .../ksp/symbol/impl/kotlin/KSTypeImpl.kt | 4 +- .../impl/kotlin/KSValueParameterImpl.kt | 3 +- .../google/devtools/ksp/symbol/impl/utils.kt | 21 +++- .../symbol/kotlin/KSClassDeclarationImpl.kt | 10 +- .../ksp/impl/symbol/kotlin/KSErrorType.kt | 6 +- .../kotlin/KSErrorTypeClassDeclaration.kt | 2 +- .../ksp/impl/symbol/kotlin/KSTypeImpl.kt | 15 ++- .../resolved/KSTypeReferenceResolvedImpl.kt | 20 +--- .../devtools/ksp/impl/symbol/kotlin/util.kt | 27 +---- .../testData/replaceWithErrorTypeArgs.kt | 96 +++++++-------- .../testData/api/replaceWithErrorTypeArgs.kt | 112 +++++++++--------- 19 files changed, 207 insertions(+), 190 deletions(-) create mode 100644 common-util/src/main/kotlin/com/google/devtools/ksp/common/ErrorTypeUtils.kt diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/common/ErrorTypeUtils.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/common/ErrorTypeUtils.kt new file mode 100644 index 0000000000..70b67fd8b6 --- /dev/null +++ b/common-util/src/main/kotlin/com/google/devtools/ksp/common/ErrorTypeUtils.kt @@ -0,0 +1,24 @@ +package com.google.devtools.ksp.common + +import com.google.devtools.ksp.symbol.KSType +import com.google.devtools.ksp.symbol.KSTypeArgument + +inline fun errorTypeOnInconsistentArguments( + arguments: List, + placeholdersProvider: () -> List, + withCorrectedArguments: (corrected: List) -> KSType, + errorType: (name: String, message: String) -> E, +): E? { + if (arguments.isNotEmpty()) { + val placeholders = placeholdersProvider() + val diff = arguments.size - placeholders.size + if (diff > 0) { + val wouldBeType = withCorrectedArguments(arguments.dropLast(diff)) + return errorType(wouldBeType.toString(), "Unexpected extra $diff type argument(s)") + } else if (diff < 0) { + val wouldBeType = withCorrectedArguments(arguments + placeholders.drop(arguments.size)) + return errorType(wouldBeType.toString(), "Missing ${-diff} type argument(s)") + } + } + return null +} diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt index cb6640a66c..9a24d49b66 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt @@ -1248,7 +1248,7 @@ class ResolverImpl( } // Convert type arguments for Java wildcard, recursively. - private fun KotlinType.toWildcard(mode: TypeMappingMode): KotlinType { + private fun KotlinType.toWildcard(mode: TypeMappingMode): Result { val parameters = constructor.parameters val arguments = arguments @@ -1258,10 +1258,11 @@ class ResolverImpl( parameter.variance != org.jetbrains.kotlin.types.Variance.INVARIANT && argument.projectionKind != org.jetbrains.kotlin.types.Variance.INVARIANT ) { - // conflicting variances - throw IllegalArgumentException( - "Conflicting variance: variance '${parameter.variance.label}' vs projection " + - "'${argument.projectionKind.label}'" + return Result.failure( + IllegalArgumentException( + "Conflicting variance: variance '${parameter.variance.label}' vs projection " + + "'${argument.projectionKind.label}'" + ) ) } @@ -1270,10 +1271,10 @@ class ResolverImpl( val genericMode = argMode.toGenericArgumentMode( getEffectiveVariance(parameter.variance, argument.projectionKind) ) - TypeProjectionImpl(variance, argument.type.toWildcard(genericMode)) + TypeProjectionImpl(variance, argument.type.toWildcard(genericMode).getOrElse { return Result.failure(it) }) } - return replace(wildcardArguments) + return Result.success(replace(wildcardArguments)) } private val JVM_SUPPRESS_WILDCARDS_NAME = KSNameImpl.getCached("kotlin.jvm.JvmSuppressWildcards") @@ -1372,12 +1373,19 @@ class ResolverImpl( if (position == RefPosition.SUPER_TYPE && argument.projectionKind != org.jetbrains.kotlin.types.Variance.INVARIANT ) { - throw IllegalArgumentException("Type projection isn't allowed in immediate arguments to supertypes") + val errorType = KSErrorType( + name = type.toString(), + message = "Type projection isn't allowed in immediate arguments to supertypes" + ) + return KSTypeReferenceSyntheticImpl.getCached(errorType, null) } } val wildcardType = kotlinType.toWildcard(typeMappingMode).let { - var candidate: KotlinType = it + var candidate: KotlinType = it.getOrElse { error -> + val errorType = KSErrorType(name = type.toString(), message = error.message) + return KSTypeReferenceSyntheticImpl.getCached(errorType, null) + } for (i in indexes.reversed()) { candidate = candidate.arguments[i].type } diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt index f1cb2c74bb..b0ca39976b 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt @@ -151,9 +151,7 @@ class KSClassDeclarationDescriptorImpl private constructor(val descriptor: Class } override fun asType(typeArguments: List): KSType = - descriptor.defaultType.replaceTypeArguments(typeArguments)?.let { - getKSTypeCached(it, typeArguments) - } ?: KSErrorType() + descriptor.defaultType.replaceTypeArguments(typeArguments) override fun asStarProjectedType(): KSType { return getKSTypeCached(descriptor.defaultType.replaceArgumentsWithStarProjections()) diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt index 337ce251b7..db0a43188f 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt @@ -17,6 +17,7 @@ package com.google.devtools.ksp.symbol.impl.java +import com.google.devtools.ksp.common.errorTypeOnInconsistentArguments import com.google.devtools.ksp.common.impl.KSNameImpl import com.google.devtools.ksp.common.toKSModifiers import com.google.devtools.ksp.processing.impl.KSObjectCache @@ -96,8 +97,10 @@ class KSClassDeclarationJavaEnumEntryImpl private constructor(val psi: PsiEnumCo // Enum can't have type parameters. override fun asType(typeArguments: List): KSType { - if (typeArguments.isNotEmpty()) - return KSErrorType() + errorTypeOnInconsistentArguments( + arguments = typeArguments, placeholdersProvider = ::emptyList, + withCorrectedArguments = ::asType, errorType = ::KSErrorType, + )?.let { error -> return error } return asStarProjectedType() } diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt index 2a0481dea4..b46bed8559 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt @@ -153,17 +153,13 @@ class KSClassDeclarationJavaImpl private constructor(val psi: PsiClass) : } override fun asType(typeArguments: List): KSType { - return descriptor?.let { - it.defaultType.replaceTypeArguments(typeArguments)?.let { - getKSTypeCached(it, typeArguments) - } - } ?: KSErrorType() + return descriptor?.defaultType?.replaceTypeArguments(typeArguments) ?: KSErrorType(psi.qualifiedName) } override fun asStarProjectedType(): KSType { return descriptor?.let { getKSTypeCached(it.defaultType.replaceArgumentsWithStarProjections()) - } ?: KSErrorType() + } ?: KSErrorType(psi.qualifiedName) } override fun accept(visitor: KSVisitor, data: D): R { diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt index 393a679469..3979da1a4b 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt @@ -122,9 +122,7 @@ class KSClassDeclarationImpl private constructor(val ktClassOrObject: KtClassOrO } override fun asType(typeArguments: List): KSType { - return descriptor.defaultType.replaceTypeArguments(typeArguments)?.let { - getKSTypeCached(it, typeArguments) - } ?: KSErrorType() + return descriptor.defaultType.replaceTypeArguments(typeArguments) } override fun asStarProjectedType(): KSType { diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt index c911474b02..9c5e6ef508 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt @@ -25,8 +25,12 @@ import org.jetbrains.kotlin.types.error.ErrorType import org.jetbrains.kotlin.types.error.ErrorTypeKind class KSErrorType( - val nameHint: String? = null, + val nameHint: String?, ) : KSType { + constructor(name: String, message: String?) : this( + nameHint = listOfNotNull(name, message).takeIf { it.isNotEmpty() }?.joinToString(" % ") + ) + override val annotations: Sequence get() = emptySequence() diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt index 0ea15def59..8094ab1ced 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt @@ -97,7 +97,7 @@ class KSPropertyDeclarationImpl private constructor(val ktProperty: KtProperty) KSTypeReferenceDeferredImpl.getCached(this) { val desc = propertyDescriptor as? VariableDescriptorWithAccessors if (desc == null) { - KSErrorType() + KSErrorType(null /* no info available */) } else { getKSTypeCached(desc.type) } diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt index 62f8b90cb1..5fff631c6a 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt @@ -95,9 +95,7 @@ class KSTypeImpl private constructor( } override fun replace(arguments: List): KSType { - return kotlinType.replaceTypeArguments(arguments)?.let { - getKSTypeCached(it, arguments, annotations) - } ?: KSErrorType() + return kotlinType.replaceTypeArguments(arguments, annotations) } override fun starProjection(): KSType { diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt index 5e95a12904..5a2d0853bf 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt @@ -112,7 +112,8 @@ class KSValueParameterImpl private constructor(val ktParameter: KtParameter) : K override val type: KSTypeReference by lazy { ktParameter.typeReference?.let { KSTypeReferenceImpl.getCached(it) } - ?: findPropertyForAccessor()?.type ?: KSTypeReferenceSyntheticImpl.getCached(KSErrorType(), this) + ?: findPropertyForAccessor()?.type + ?: KSTypeReferenceSyntheticImpl.getCached(KSErrorType(null /* no info available */), this) } override val hasDefault: Boolean = ktParameter.hasDefaultValue() diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/utils.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/utils.kt index e8ab1fb8ac..47cdb9c256 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/utils.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/utils.kt @@ -18,6 +18,7 @@ package com.google.devtools.ksp.symbol.impl import com.google.devtools.ksp.ExceptionMessage import com.google.devtools.ksp.KspExperimental +import com.google.devtools.ksp.common.errorTypeOnInconsistentArguments import com.google.devtools.ksp.common.impl.KSNameImpl import com.google.devtools.ksp.processing.impl.ResolverImpl import com.google.devtools.ksp.symbol.* @@ -136,10 +137,18 @@ fun org.jetbrains.kotlin.types.Variance.toKSVariance(): Variance { private fun KSTypeReference.toKotlinType() = (resolve() as? KSTypeImpl)?.kotlinType -// returns null if error -internal fun KotlinType.replaceTypeArguments(newArguments: List): KotlinType? { - if (newArguments.isNotEmpty() && this.arguments.size != newArguments.size) - return null +// returns KSErrorType if error +internal fun KotlinType.replaceTypeArguments( + newArguments: List, + annotations: Sequence = emptySequence(), +): KSType { + errorTypeOnInconsistentArguments( + arguments = newArguments, + placeholdersProvider = { arguments.map { KSTypeArgumentDescriptorImpl.getCached(it, Origin.SYNTHETIC, null) } }, + withCorrectedArguments = ::replaceTypeArguments, + errorType = ::KSErrorType, + )?.let { error -> return error } + return replace( newArguments.mapIndexed { index, ksTypeArgument -> val variance = when (ksTypeArgument.variance) { @@ -155,11 +164,11 @@ internal fun KotlinType.replaceTypeArguments(newArguments: List) else -> throw IllegalStateException( "Unexpected psi for type argument: ${ksTypeArgument.javaClass}, $ExceptionMessage" ) - }.toKotlinType() ?: return null + }.let { it.toKotlinType() ?: return KSErrorType.fromReferenceBestEffort(it) } TypeProjectionImpl(variance, type) } - ) + ).let { KSTypeImpl.getCached(it, newArguments, annotations) } } internal fun FunctionDescriptor.toKSDeclaration(): KSDeclaration { 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 6311ec3e0a..0030d5f088 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 @@ -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.errorTypeOnInconsistentArguments import com.google.devtools.ksp.common.impl.KSNameImpl import com.google.devtools.ksp.common.impl.KSTypeReferenceSyntheticImpl import com.google.devtools.ksp.impl.ResolverAAImpl @@ -124,9 +125,12 @@ class KSClassDeclarationImpl private constructor(internal val ktClassOrObjectSym } override fun asType(typeArguments: List): KSType { - if (typeArguments.isNotEmpty() && typeArguments.size != asStarProjectedType().arguments.size) { - return KSErrorType() - } + errorTypeOnInconsistentArguments( + arguments = typeArguments, + placeholdersProvider = { asStarProjectedType().arguments }, + withCorrectedArguments = ::asType, + errorType = ::KSErrorType, + )?.let { error -> return error } return analyze { if (typeArguments.isEmpty()) { typeParameters.map { buildTypeParameterType((it as KSTypeParameterImpl).ktTypeParameterSymbol) } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorType.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorType.kt index 24dbfb7236..83e40c4700 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorType.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorType.kt @@ -19,8 +19,12 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.symbol.* class KSErrorType( - private val hint: String? = null, + private val hint: String?, ) : KSType { + constructor(name: String, message: String?) : this( + hint = listOfNotNull(name, message).takeIf { it.isNotEmpty() }?.joinToString(" % ") + ) + override val declaration: KSDeclaration get() = KSErrorTypeClassDeclaration(this) diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorTypeClassDeclaration.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorTypeClassDeclaration.kt index ffc26dca3a..1831ce1bd7 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorTypeClassDeclaration.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorTypeClassDeclaration.kt @@ -114,7 +114,7 @@ class KSErrorTypeClassDeclaration( return this === other || other is KSErrorTypeClassDeclaration && other.type == type } - override fun hashCode(): Int = type.hashCode() + override fun hashCode(): Int = type.hashCode() * 2 override val docString get() = null 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 0a4ee80c07..4a9b8a3de1 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 @@ -19,6 +19,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.errorTypeOnInconsistentArguments import com.google.devtools.ksp.impl.ResolverAAImpl import com.google.devtools.ksp.impl.recordLookupWithSupertypes import com.google.devtools.ksp.impl.symbol.kotlin.resolved.KSTypeArgumentResolvedImpl @@ -110,12 +111,17 @@ class KSTypeImpl private constructor(internal val type: KtType) : KSType { } override fun replace(arguments: List): KSType { - return type.replace(arguments.map { it.toKtTypeProjection() })?.let { getCached(it) } ?: KSErrorType() + errorTypeOnInconsistentArguments( + arguments = arguments, + placeholdersProvider = { type.typeArguments().map { KSTypeArgumentResolvedImpl.getCached(it) } }, + withCorrectedArguments = ::replace, + errorType = ::KSErrorType, + )?.let { error -> return error } + return getCached(type.replace(arguments.map { it.toKtTypeProjection() })) } override fun starProjection(): KSType { - return type.replace(List(type.typeArguments().size) { KtStarTypeProjection(type.token) }) - ?.let { getCached(it) } ?: KSErrorType() + return getCached(type.replace(List(type.typeArguments().size) { KtStarTypeProjection(type.token) })) } override fun makeNullable(): KSType { @@ -134,7 +140,8 @@ class KSTypeImpl private constructor(internal val type: KtType) : KSType { get() = type.nullability == KtTypeNullability.NULLABLE override val isError: Boolean - get() = type is KtErrorType + // TODO: non exist type returns KtNonErrorClassType, check upstream for KtClassErrorType usage. + get() = type is KtErrorType || type.classifierSymbol() == null override val isFunctionType: Boolean get() = type is KtFunctionalType && !type.isSuspend 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 c449f275ec..c1473d2a89 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 @@ -22,14 +22,11 @@ import com.google.devtools.ksp.common.KSObjectCache 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 -import com.google.devtools.ksp.impl.symbol.kotlin.KSErrorType import com.google.devtools.ksp.impl.symbol.kotlin.KSTypeImpl import com.google.devtools.ksp.impl.symbol.kotlin.KSTypeParameterImpl import com.google.devtools.ksp.impl.symbol.kotlin.Restorable import com.google.devtools.ksp.impl.symbol.kotlin.analyze import com.google.devtools.ksp.impl.symbol.kotlin.annotations -import com.google.devtools.ksp.impl.symbol.kotlin.classifierSymbol -import com.google.devtools.ksp.impl.symbol.kotlin.getNameHint import com.google.devtools.ksp.impl.symbol.kotlin.render import com.google.devtools.ksp.impl.symbol.kotlin.toClassifierReference import com.google.devtools.ksp.impl.symbol.kotlin.toLocation @@ -61,22 +58,7 @@ class KSTypeReferenceResolvedImpl private constructor( override fun resolve(): KSType { analyze { recordLookup(ktType, parent) } - // TODO: non exist type returns KtNonErrorClassType, check upstream for KtClassErrorType usage. - return if ( - analyze { - ktType is KtClassErrorType || (ktType.classifierSymbol() == null) - } - ) { - KSErrorType( - when (ktType) { - is KtClassErrorType -> ktType.getNameHint() - is KtTypeErrorType -> null // No info available - else -> ktType.render() - } - ) - } else { - KSTypeImpl.getCached(ktType) - } + return KSTypeImpl.getCached(ktType) } override val annotations: Sequence by lazy { 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 49fa2c0acd..177aeeacf3 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 @@ -62,7 +62,6 @@ import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack import org.jetbrains.kotlin.fir.java.toFirExpression -import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedError import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.types.ConeClassLikeType @@ -148,22 +147,6 @@ internal fun KtAnnotationValue.render(): String { } } -internal fun KtClassErrorType.getNameHint(): String { - return when (val coneType = (this as KtFirType).coneType) { - is ConeErrorType -> when (val diagnostic = coneType.diagnostic) { - is ConeUnresolvedError -> diagnostic.qualifier - else -> throw IllegalStateException("Unexpected diagnostic: ${diagnostic.reason}") - } - is ConeClassLikeType -> { - coneType.lookupTag.name.asString() - } - else -> { - // KtFirClassErrorType has `coneType: ConeClassLikeType`, so we're safe as long as that doesn't change - throw IllegalStateException("Unexpected coneType: $coneType") - } - } -} - internal fun KtType.render(inFunctionType: Boolean = false): String { return buildString { annotations.forEach { @@ -194,8 +177,8 @@ internal fun KtType.render(inFunctionType: Boolean = false): String { } } } - is KtClassErrorType -> KSErrorType(getNameHint()).toString() - is KtTypeErrorType -> KSErrorType().toString() + is KtClassErrorType -> KSErrorType(qualifiers.joinToString(".") { it.name.asString() }).toString() + is KtTypeErrorType -> KSErrorType(tryRenderAsNonErrorType()).toString() is KtCapturedType -> asStringForDebugging() is KtDefinitelyNotNullType -> original.render(inFunctionType) + " & Any" is KtDynamicType -> "" @@ -661,10 +644,8 @@ internal fun KtType.isAssignableFrom(that: KtType): Boolean { } // TODO: fix flexible type creation once upstream available. -internal fun KtType.replace(newArgs: List): KtType? { - if (newArgs.isNotEmpty() && newArgs.size != this.typeArguments().size) { - return null - } +internal fun KtType.replace(newArgs: List): KtType { + require(newArgs.isEmpty() || newArgs.size == this.typeArguments().size) return analyze { when (val symbol = classifierSymbol()) { is KtClassLikeSymbol -> analysisSession.buildClassType(symbol) { diff --git a/kotlin-analysis-api/testData/replaceWithErrorTypeArgs.kt b/kotlin-analysis-api/testData/replaceWithErrorTypeArgs.kt index 20cb7f2e81..36a715e32a 100644 --- a/kotlin-analysis-api/testData/replaceWithErrorTypeArgs.kt +++ b/kotlin-analysis-api/testData/replaceWithErrorTypeArgs.kt @@ -38,65 +38,65 @@ // JL.asType([INVARIANT Int, INVARIANT String]): JL // JL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): JL<, > // JL.asType(emptyList()): JL -// KS1.star.replace([INVARIANT Int, INVARIANT String]): -// KS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KS1.asType([INVARIANT Int, INVARIANT String]): -// KS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KS1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> +// KS1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> // KS1.asType(emptyList()): KS1 -// KL1.star.replace([INVARIANT Int, INVARIANT String]): -// KL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KL1.asType([INVARIANT Int, INVARIANT String]): -// KL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KL1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> +// KL1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> // KL1.asType(emptyList()): KL1 -// JS1.star.replace([INVARIANT Int, INVARIANT String]): -// JS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JS1.asType([INVARIANT Int, INVARIANT String]): -// JS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JS1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> +// JS1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> // JS1.asType(emptyList()): JS1 -// JL1.star.replace([INVARIANT Int, INVARIANT String]): -// JL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JL1.asType([INVARIANT Int, INVARIANT String]): -// JL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JL1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> +// JL1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): > % Unexpected extra 1 type argument(s)> // JL1.asType(emptyList()): JL1 -// JSE.star.replace([INVARIANT Int, INVARIANT String]): -// JSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JSE.asType([INVARIANT Int, INVARIANT String]): -// JSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.star.replace([INVARIANT Int, INVARIANT String]): +// JSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.asType([INVARIANT Int, INVARIANT String]): +// JSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JSE.asType(emptyList()): JSE -// JSE.E.star.replace([INVARIANT Int, INVARIANT String]): -// JSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JSE.E.asType([INVARIANT Int, INVARIANT String]): -// JSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.E.star.replace([INVARIANT Int, INVARIANT String]): +// JSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.E.asType([INVARIANT Int, INVARIANT String]): +// JSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JSE.E.asType(emptyList()): JSE -// JLE.star.replace([INVARIANT Int, INVARIANT String]): -// JLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JLE.asType([INVARIANT Int, INVARIANT String]): -// JLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.star.replace([INVARIANT Int, INVARIANT String]): +// JLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.asType([INVARIANT Int, INVARIANT String]): +// JLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JLE.asType(emptyList()): JLE -// JLE.E.star.replace([INVARIANT Int, INVARIANT String]): -// JLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JLE.E.asType([INVARIANT Int, INVARIANT String]): -// JLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.E.star.replace([INVARIANT Int, INVARIANT String]): +// JLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.E.asType([INVARIANT Int, INVARIANT String]): +// JLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JLE.E.asType(emptyList()): JLE -// KSE.star.replace([INVARIANT Int, INVARIANT String]): -// KSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KSE.asType([INVARIANT Int, INVARIANT String]): -// KSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.star.replace([INVARIANT Int, INVARIANT String]): +// KSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.asType([INVARIANT Int, INVARIANT String]): +// KSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KSE.asType(emptyList()): KSE -// KSE.E.star.replace([INVARIANT Int, INVARIANT String]): -// KSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KSE.E.asType([INVARIANT Int, INVARIANT String]): -// KSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.E.star.replace([INVARIANT Int, INVARIANT String]): +// KSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.E.asType([INVARIANT Int, INVARIANT String]): +// KSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KSE.E.asType(emptyList()): KSE -// KLE.star.replace([INVARIANT Int, INVARIANT String]): -// KLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KLE.asType([INVARIANT Int, INVARIANT String]): -// KLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.star.replace([INVARIANT Int, INVARIANT String]): +// KLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.asType([INVARIANT Int, INVARIANT String]): +// KLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KLE.asType(emptyList()): KLE -// KLE.E.star.replace([INVARIANT Int, INVARIANT String]): -// KLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KLE.E.asType([INVARIANT Int, INVARIANT String]): -// KLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.E.star.replace([INVARIANT Int, INVARIANT String]): +// KLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.E.asType([INVARIANT Int, INVARIANT String]): +// KLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KLE.E.asType(emptyList()): KLE // default type:A // flexible type star:T diff --git a/test-utils/testData/api/replaceWithErrorTypeArgs.kt b/test-utils/testData/api/replaceWithErrorTypeArgs.kt index 1ac869ae4b..58555c0c1d 100644 --- a/test-utils/testData/api/replaceWithErrorTypeArgs.kt +++ b/test-utils/testData/api/replaceWithErrorTypeArgs.kt @@ -19,84 +19,84 @@ // TEST PROCESSOR: ReplaceWithErrorTypeArgsProcessor // EXPECTED: // KS.star.replace([INVARIANT Int, INVARIANT String]): KS -// KS.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KS.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): // KS.asType([INVARIANT Int, INVARIANT String]): KS -// KS.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KS.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KS.asType(emptyList()): KS // KL.star.replace([INVARIANT Int, INVARIANT String]): KL -// KL.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KL.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): // KL.asType([INVARIANT Int, INVARIANT String]): KL -// KL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KL.asType(emptyList()): KL // JS.star.replace([INVARIANT Int, INVARIANT String]): JS -// JS.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JS.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): // JS.asType([INVARIANT Int, INVARIANT String]): JS -// JS.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JS.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JS.asType(emptyList()): JS // JL.star.replace([INVARIANT Int, INVARIANT String]): JL -// JL.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JL.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): // JL.asType([INVARIANT Int, INVARIANT String]): JL -// JL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JL.asType(emptyList()): JL -// KS1.star.replace([INVARIANT Int, INVARIANT String]): -// KS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KS1.asType([INVARIANT Int, INVARIANT String]): -// KS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KS1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> +// KS1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> // KS1.asType(emptyList()): KS1 -// KL1.star.replace([INVARIANT Int, INVARIANT String]): -// KL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KL1.asType([INVARIANT Int, INVARIANT String]): -// KL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KL1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> +// KL1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// KL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> // KL1.asType(emptyList()): KL1 -// JS1.star.replace([INVARIANT Int, INVARIANT String]): -// JS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JS1.asType([INVARIANT Int, INVARIANT String]): -// JS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JS1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> +// JS1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> // JS1.asType(emptyList()): JS1 -// JL1.star.replace([INVARIANT Int, INVARIANT String]): -// JL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JL1.asType([INVARIANT Int, INVARIANT String]): -// JL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JL1.star.replace([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> +// JL1.asType([INVARIANT Int, INVARIANT String]): % Unexpected extra 1 type argument(s)> +// JL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): % Unexpected extra 1 type argument(s)> // JL1.asType(emptyList()): JL1 -// JSE.star.replace([INVARIANT Int, INVARIANT String]): -// JSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JSE.asType([INVARIANT Int, INVARIANT String]): -// JSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.star.replace([INVARIANT Int, INVARIANT String]): +// JSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.asType([INVARIANT Int, INVARIANT String]): +// JSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JSE.asType(emptyList()): JSE -// JSE.E.star.replace([INVARIANT Int, INVARIANT String]): -// JSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JSE.E.asType([INVARIANT Int, INVARIANT String]): -// JSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.E.star.replace([INVARIANT Int, INVARIANT String]): +// JSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JSE.E.asType([INVARIANT Int, INVARIANT String]): +// JSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JSE.E.asType(emptyList()): JSE.E -// JLE.star.replace([INVARIANT Int, INVARIANT String]): -// JLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JLE.asType([INVARIANT Int, INVARIANT String]): -// JLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.star.replace([INVARIANT Int, INVARIANT String]): +// JLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.asType([INVARIANT Int, INVARIANT String]): +// JLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JLE.asType(emptyList()): JLE -// JLE.E.star.replace([INVARIANT Int, INVARIANT String]): -// JLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// JLE.E.asType([INVARIANT Int, INVARIANT String]): -// JLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.E.star.replace([INVARIANT Int, INVARIANT String]): +// JLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// JLE.E.asType([INVARIANT Int, INVARIANT String]): +// JLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // JLE.E.asType(emptyList()): JLE.E -// KSE.star.replace([INVARIANT Int, INVARIANT String]): -// KSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KSE.asType([INVARIANT Int, INVARIANT String]): -// KSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.star.replace([INVARIANT Int, INVARIANT String]): +// KSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.asType([INVARIANT Int, INVARIANT String]): +// KSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KSE.asType(emptyList()): KSE -// KSE.E.star.replace([INVARIANT Int, INVARIANT String]): -// KSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KSE.E.asType([INVARIANT Int, INVARIANT String]): -// KSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.E.star.replace([INVARIANT Int, INVARIANT String]): +// KSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KSE.E.asType([INVARIANT Int, INVARIANT String]): +// KSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KSE.E.asType(emptyList()): E -// KLE.star.replace([INVARIANT Int, INVARIANT String]): -// KLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KLE.asType([INVARIANT Int, INVARIANT String]): -// KLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.star.replace([INVARIANT Int, INVARIANT String]): +// KLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.asType([INVARIANT Int, INVARIANT String]): +// KLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KLE.asType(emptyList()): KLE -// KLE.E.star.replace([INVARIANT Int, INVARIANT String]): -// KLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): -// KLE.E.asType([INVARIANT Int, INVARIANT String]): -// KLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.E.star.replace([INVARIANT Int, INVARIANT String]): +// KLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): +// KLE.E.asType([INVARIANT Int, INVARIANT String]): +// KLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): // KLE.E.asType(emptyList()): KLE.E // default type:A // flexible type star:(T..T?) From e34a635819d236913cff2677033a44b6ffc5a17a Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Mon, 3 Jun 2024 16:10:03 -0700 Subject: [PATCH 57/64] fix property accessor modifier logic (cherry picked from commit e649b3bb8864fb6f44e663f0205d07134df9efe2) --- .../symbol/kotlin/KSFunctionDeclarationImpl.kt | 8 ++++++++ .../impl/symbol/kotlin/KSPropertyAccessorImpl.kt | 8 +++++++- .../ksp/processor/LateinitPropertiesProcessor.kt | 2 ++ test-utils/testData/api/lateinitProperties.kt | 16 ++++++++++++++-- 4 files changed, 31 insertions(+), 3 deletions(-) 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 b64c299f6b..5faaacf5da 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 @@ -238,6 +238,14 @@ internal fun KtFunctionLikeSymbol.toModifiers(): Set { result.add(Modifier.OVERRIDE) } } + is KtPropertyAccessorSymbol -> { + if (visibility != JavaVisibilities.PackageVisibility) { + result.add(visibility.toModifier()) + } + if (modality != Modality.OPEN) { + result.add(modality.toModifier()) + } + } else -> Unit } return result 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 d5f93d2387..2bd8b64c4b 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 @@ -50,7 +50,13 @@ abstract class KSPropertyAccessorImpl( } override val modifiers: Set by lazy { - ((ktPropertyAccessorSymbol.psi as? KtModifierListOwner)?.toKSModifiers() ?: emptySet()).let { + ( + if (origin == Origin.JAVA_LIB || origin == Origin.KOTLIN_LIB || origin == Origin.SYNTHETIC) { + (ktPropertyAccessorSymbol.toModifiers()) + } else { + (ktPropertyAccessorSymbol.psi as? KtModifierListOwner)?.toKSModifiers() ?: emptySet() + } + ).let { if (origin == Origin.SYNTHETIC && (receiver.parentDeclaration as? KSClassDeclaration)?.classKind == ClassKind.INTERFACE ) { diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LateinitPropertiesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LateinitPropertiesProcessor.kt index 25c2546cc3..c20f8699b7 100644 --- a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LateinitPropertiesProcessor.kt +++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LateinitPropertiesProcessor.kt @@ -31,6 +31,8 @@ class LateinitPropertiesProcessor : AbstractTestProcessor() { } override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) { + lateinitPropertiesNames.add("setter, ${property.setter?.modifiers?.sorted()}, $property") + lateinitPropertiesNames.add("getter, ${property.getter?.modifiers?.sorted()}, $property") if (Modifier.LATEINIT in property.modifiers) { lateinitPropertiesNames += property.simpleName.asString() } diff --git a/test-utils/testData/api/lateinitProperties.kt b/test-utils/testData/api/lateinitProperties.kt index af98f76610..bbebd2da18 100644 --- a/test-utils/testData/api/lateinitProperties.kt +++ b/test-utils/testData/api/lateinitProperties.kt @@ -18,19 +18,31 @@ // WITH_RUNTIME // TEST PROCESSOR: LateinitPropertiesProcessor // EXPECTED: +// getter, [PRIVATE, FINAL], prop1 +// getter, [PRIVATE, FINAL], propSource1 +// getter, [PUBLIC, FINAL], prop2 +// getter, [PUBLIC, FINAL], prop3 +// getter, [PUBLIC, FINAL], propSource2 +// getter, [PUBLIC, FINAL], propSource3 // prop1 // prop2 // prop3 // propSource1 // propSource2 // propSource3 +// setter, [PRIVATE, FINAL], prop1 +// setter, [PRIVATE, FINAL], propSource1 +// setter, [PUBLIC, FINAL], prop2 +// setter, [PUBLIC, FINAL], prop3 +// setter, [PUBLIC, FINAL], propSource2 +// setter, [PUBLIC, FINAL], propSource3 // END // MODULE: lib // FILE: compiledProperties.kt package test.compiled open class Foo { - lateinit var prop1: Any + lateinit private var prop1: Any companion object { lateinit var prop2: Any } @@ -45,7 +57,7 @@ object Bar : Foo() { package test.source open class FooSource { - lateinit var propSource1: Any + lateinit private var propSource1: Any companion object { lateinit var propSource2: Any } From 76bf45dacece9c0e3afa518d0ab070ebff7175cf Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Mon, 3 Jun 2024 17:24:49 -0700 Subject: [PATCH 58/64] Make originalAnnotations lazy Otherwise all annotations are resolved unconditionally when we index KSFiles. (cherry picked from commit 1884e537d47de331158b31f7c59e6525b1745e3f) --- .../impl/symbol/kotlin/AbstractKSDeclarationImpl.kt | 12 +++++++----- .../ksp/impl/symbol/kotlin/KSPropertyAccessorImpl.kt | 4 +++- 2 files changed, 10 insertions(+), 6 deletions(-) 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 b20a960e5f..9da1f5a741 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 @@ -119,10 +119,12 @@ abstract class AbstractKSDeclarationImpl(val ktDeclarationSymbol: KtDeclarationS override val docString: String? get() = ktDeclarationSymbol.toDocString() - internal val originalAnnotations = if (ktDeclarationSymbol.psi is KtElement || ktDeclarationSymbol.psi == null) { - ktDeclarationSymbol.annotations(this) - } else { - (ktDeclarationSymbol.psi as PsiJvmModifiersOwner) - .annotations.map { KSAnnotationJavaImpl.getCached(it, this) }.asSequence() + internal val originalAnnotations: Sequence by lazy { + if (ktDeclarationSymbol.psi is KtElement || ktDeclarationSymbol.psi == null) { + ktDeclarationSymbol.annotations(this) + } else { + (ktDeclarationSymbol.psi as PsiJvmModifiersOwner) + .annotations.map { KSAnnotationJavaImpl.getCached(it, this) }.asSequence() + } } } 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 2bd8b64c4b..d133d35e7f 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 @@ -43,7 +43,9 @@ abstract class KSPropertyAccessorImpl( .plus(findAnnotationFromUseSiteTarget()) } - internal val originalAnnotations = ktPropertyAccessorSymbol.annotations(this) + internal val originalAnnotations: Sequence by lazy { + ktPropertyAccessorSymbol.annotations(this) + } override val location: Location by lazy { ktPropertyAccessorSymbol.psi?.toLocation() ?: NonExistLocation From f08bc85a0243c66e6dcf3d2f3efd93085bb8c1b0 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Mon, 3 Jun 2024 17:40:40 -0700 Subject: [PATCH 59/64] DeclarationProvider: skip builtins when possible. (cherry picked from commit 459890f6f8a55e2aa634fc6bb673c7c8be29617b) --- .../standalone/IncrementalKotlinDeclarationProviderFactory.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProviderFactory.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProviderFactory.kt index 4cf534b207..6c83ca7b7d 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProviderFactory.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/standalone/IncrementalKotlinDeclarationProviderFactory.kt @@ -26,7 +26,8 @@ class IncrementalKotlinDeclarationProviderFactory( } fun update(files: Collection) { - val staticFactory = KotlinStaticDeclarationProviderFactory(project, files) + val skipBuiltIns = staticFactories.isNotEmpty() + val staticFactory = KotlinStaticDeclarationProviderFactory(project, files, skipBuiltins = skipBuiltIns) staticFactories.add(staticFactory) } From 0c639834ce9489218539c920a32c0dc153673231 Mon Sep 17 00:00:00 2001 From: Eduardo Fonseca Date: Tue, 4 Jun 2024 22:55:43 -0300 Subject: [PATCH 60/64] Update ksp2entrypoints.md (cherry picked from commit 1041213478287fc5458c7ef1153d3d3eb6acdf85) --- docs/ksp2entrypoints.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/ksp2entrypoints.md b/docs/ksp2entrypoints.md index 9895c8bfca..d207fa2b56 100644 --- a/docs/ksp2entrypoints.md +++ b/docs/ksp2entrypoints.md @@ -12,7 +12,7 @@ Calling KSP2 consists of just 4 steps: 4. Call `KotlinSymbolProcessing(kspConfig, processors, kspLogger).execute()` -``` +```kotlin // Implement a logger or use KspGradleLogger val logger = KspGradleLogger(KspGradleLogger.LOGGING_LEVEL_WARN) @@ -27,11 +27,11 @@ val processorProviders = ServiceLoader.load( val kspConfig = KSPJvmConfig.Builder().apply { // All configurations happen here. See KSPConfig.kt for all available options. moduleName = "main" - sourceRoots = listOf(File("/path/to/src1), File("/path/to/src2")) + sourceRoots = listOf(File("/path/to/src1"), File("/path/to/src2")) kotlinOutputDir = File("/path/to/kotlin/out") - ... + // ... }.build() // Run! val exitCode = KotlinSymbolProcessing(kspConfig, listOfProcessors, kspLoggerImpl).execute() -``` \ No newline at end of file +``` From 893a784a9917a153022827295029469290ecd59d Mon Sep 17 00:00:00 2001 From: Eduardo Fonseca Date: Tue, 4 Jun 2024 22:59:03 -0300 Subject: [PATCH 61/64] Update ksp2entrypoints.md (cherry picked from commit 41914b36b7c9174ad14371ac81945ebbaa00a2f0) --- docs/ksp2entrypoints.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ksp2entrypoints.md b/docs/ksp2entrypoints.md index d207fa2b56..6c3ec89570 100644 --- a/docs/ksp2entrypoints.md +++ b/docs/ksp2entrypoints.md @@ -33,5 +33,5 @@ val kspConfig = KSPJvmConfig.Builder().apply { }.build() // Run! -val exitCode = KotlinSymbolProcessing(kspConfig, listOfProcessors, kspLoggerImpl).execute() +val exitCode = KotlinSymbolProcessing(kspConfig, processorProviders, kspLoggerImpl).execute() ``` From eaf9f7a74ecddcdbd89112c2a3aa83bb1c2c67c5 Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Tue, 4 Jun 2024 18:01:25 -0700 Subject: [PATCH 62/64] map java types to kotlin types when parsing annotation class reference values (cherry picked from commit 386fe4743268194c9278e1239ba55c4f340020d0) --- .../devtools/ksp/impl/symbol/kotlin/util.kt | 11 ++++++-- .../annotationValue/defaultKClassValue.kt | 20 +++++++++++++ .../processor/DefaultKClassValueProcessor.kt | 28 +++++++++++++++++++ .../com/google/devtools/ksp/test/KSPAATest.kt | 6 ++++ 4 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 kotlin-analysis-api/testData/annotationValue/defaultKClassValue.kt create mode 100644 test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DefaultKClassValueProcessor.kt 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 177aeeacf3..998eb1eb36 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 @@ -461,7 +461,11 @@ internal fun KtValueParameterSymbol.getDefaultValue(): KtAnnotationValue? { if (this is FirAnnotation) { return KtAnnotationApplicationValue( KtAnnotationApplicationWithArgumentsInfo( - ClassId.fromString((annotationTypeRef.coneType as? ConeLookupTagBasedType)?.lookupTag.toString()), + JavaToKotlinClassMap.mapJavaToKotlinIncludingClassMapping( + ClassId.fromString( + (annotationTypeRef.coneType as? ConeLookupTagBasedType)?.lookupTag.toString() + ).asSingleFqName() + ), null, null, emptyList(), @@ -484,8 +488,9 @@ internal fun KtValueParameterSymbol.getDefaultValue(): KtAnnotationValue? { } if (coneType is ConeClassLikeType && coneType !is ConeErrorType) { - val classId = coneType.lookupTag.classId - val type = builder.typeBuilder.buildKtType(coneType) + val classId = JavaToKotlinClassMap + .mapJavaToKotlinIncludingClassMapping(coneType.lookupTag.classId.asSingleFqName()) + val type = builder.typeBuilder.buildKtType(coneType).convertToKotlinType() KtKClassAnnotationValue(type, classId, null, token) } else { null diff --git a/kotlin-analysis-api/testData/annotationValue/defaultKClassValue.kt b/kotlin-analysis-api/testData/annotationValue/defaultKClassValue.kt new file mode 100644 index 0000000000..83e6a6603d --- /dev/null +++ b/kotlin-analysis-api/testData/annotationValue/defaultKClassValue.kt @@ -0,0 +1,20 @@ +// TEST PROCESSOR: DefaultKClassValueProcessor +// EXPECTED: +// kotlin.String +// kotlin.String +// kotlin.String +// kotlin.Int +// END +// MODULE: lib1 +// FILE: lib1.kt +annotation class ExampleAnnotation(val value: kotlin.reflect.KClass<*> = java.lang.String::class) + +// MODULE: main(lib1) +// FILE: a.kt + +@ExampleAnnotation(String::class) +class Example + +@ExampleAnnotation(Int::class) +class Example2 + diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DefaultKClassValueProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DefaultKClassValueProcessor.kt new file mode 100644 index 0000000000..dade2a25b7 --- /dev/null +++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DefaultKClassValueProcessor.kt @@ -0,0 +1,28 @@ +package com.google.devtools.ksp.processor + +import com.google.devtools.ksp.getClassDeclarationByName +import com.google.devtools.ksp.impl.symbol.kotlin.KSTypeImpl +import com.google.devtools.ksp.processing.Resolver +import com.google.devtools.ksp.symbol.KSAnnotated + +class DefaultKClassValueProcessor : AbstractTestProcessor() { + val results = mutableListOf() + + override fun toResult(): List { + return results + } + + override fun process(resolver: Resolver): List { + val example1 = resolver.getClassDeclarationByName("Example")!!.annotations.first() + val example2 = resolver.getClassDeclarationByName("Example2")!!.annotations.first() + val arg1 = (example1.arguments.single().value as KSTypeImpl).declaration.qualifiedName!! + val defaultArg1 = (example1.defaultArguments.single().value as KSTypeImpl).declaration.qualifiedName!! + results.add(defaultArg1.asString()) + results.add(arg1.asString()) + val arg2 = (example2.arguments.single().value as KSTypeImpl).declaration.qualifiedName!! + val defaultArg2 = (example2.defaultArguments.single().value as KSTypeImpl).declaration.qualifiedName!! + results.add(defaultArg2.asString()) + results.add(arg2.asString()) + return emptyList() + } +} diff --git a/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt b/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt index 249e2f3d44..e7a564806a 100644 --- a/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt +++ b/test-utils/src/test/kotlin/com/google/devtools/ksp/test/KSPAATest.kt @@ -84,6 +84,12 @@ class KSPAATest : AbstractKSPAATest() { runTest("../test-utils/testData/api/annotationWithArbitraryClassValue.kt") } + @TestMetadata("defaultKClassValue.kt") + @Test + fun testAnnotationValue_defaultKClassValue() { + runTest("../kotlin-analysis-api/testData/annotationValue/defaultKClassValue.kt") + } + @TestMetadata("annotationValue_java.kt") @Test fun testAnnotationValue_java() { From 414d37a6731c9cb869d53a51b80ca81c10e86a4a Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Wed, 5 Jun 2024 11:00:54 -0700 Subject: [PATCH 63/64] CI: enable manual trigger (cherry picked from commit d02b90fc1300061fee6bd1fe1fbe49091d6026d2) --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f9a4ce83c5..de58417f8e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,6 +7,8 @@ on: branches: [ main, 1.0.22-release, 1.0.21-release ] pull_request: branches: [ main, 1.0.22-release, 1.0.21-release ] + workflow_dispatch: + branches: [ main, 1.0.22-release, 1.0.21-release ] jobs: build-and-test: From 1ac3fd8f8915c9674e520709033e92d3df0b94f2 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Wed, 5 Jun 2024 11:02:26 -0700 Subject: [PATCH 64/64] CI: auto-merge: rebase again before push (cherry picked from commit 9b858b21e0efa859fb9d257270398353e7098ee7) --- .github/workflows/auto-merge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index c28ea52c01..e5094e5d01 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -88,7 +88,7 @@ jobs: - name: push to release branch if: success() - run: git push origin + run: git fetch && git rebase && git push origin - name: Upload test results if: always()