aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2023-04-24 03:40:48 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-04-24 03:40:48 +0000
commit2ff1c5a5fbd011d61d8d84553f69341b0e40322e (patch)
treeeb4f6ef1605d14946320f6652a41372d71d2e7ab
parent295843a05a00584ebc2e7f8154fb6a5bf182b3a2 (diff)
parent083ebb0f8b476baf522737a737a8d550f31c1522 (diff)
downloadksp-2ff1c5a5fbd011d61d8d84553f69341b0e40322e.tar.gz
Merge tag '1.8.10-1.0.9' am: 74434ab5e5 am: 083ebb0f8b
Original change: https://android-review.googlesource.com/c/platform/external/ksp/+/2536510 Change-Id: I7470a62937c03f39b1fcd1b0faace52537391d6e Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.editorconfig5
-rw-r--r--.github/workflows/auto-merge.yml138
-rw-r--r--.github/workflows/main.yml80
-rw-r--r--.github/workflows/nightly.yml71
-rw-r--r--.github/workflows/release.yml81
-rw-r--r--.gitignore13
-rw-r--r--CONTRIBUTING.md69
-rw-r--r--LICENSE202
-rw-r--r--README.md40
-rw-r--r--api/api.base728
-rw-r--r--api/build.gradle.kts58
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/KspExperimental.kt8
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/processing/CodeGenerator.kt170
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/processing/KSBuiltIns.kt41
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/processing/KSPLogger.kt29
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/processing/PlatformInfo.kt52
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/processing/Resolver.kt303
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/processing/SymbolProcessor.kt49
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/processing/SymbolProcessorEnvironment.kt73
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/processing/SymbolProcessorProvider.kt11
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/AnnotationUseSiteTarget.kt29
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/ClassKind.kt30
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/FunctionKind.kt24
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSAnnotated.kt28
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSAnnotation.kt49
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSCallableReference.kt41
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSClassDeclaration.kt77
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSClassifierReference.kt37
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDeclaration.kt58
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDeclarationContainer.kt27
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDefNonNullReference.kt13
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDynamicReference.kt22
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSExpectActual.kt48
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSFile.kt37
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSFunction.kt60
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSFunctionDeclaration.kt114
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSModifierListOwner.kt27
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSName.kt37
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSNode.kt27
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSParenthesizedReference.kt27
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSPropertyAccessor.kt43
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSPropertyDeclaration.kt118
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSReferenceElement.kt29
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSType.kt106
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeAlias.kt32
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeArgument.kt32
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeParameter.kt44
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeReference.kt35
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSValueArgument.kt41
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSValueParameter.kt62
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSVisitor.kt72
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/KSVisitorVoid.kt97
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/Location.kt23
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/Modifier.kt37
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/Nullability.kt27
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/Origin.kt25
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/Variance.kt28
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/symbol/Visibility.kt29
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/utils.kt519
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/visitor/KSDefaultVisitor.kt150
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/visitor/KSEmptyVisitor.kt126
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/visitor/KSTopDownVisitor.kt138
-rw-r--r--api/src/main/kotlin/com/google/devtools/ksp/visitor/KSValidateVisitor.kt114
-rwxr-xr-xbenchmark/TachiyomiExhaustive/build.sh28
-rw-r--r--benchmark/TachiyomiExhaustive/tachi.patch55
-rwxr-xr-xbenchmark/TachiyomiExhaustive/upload-benchmark-data.sh30
-rw-r--r--benchmark/build.gradle.kts43
-rwxr-xr-xbenchmark/build.sh28
-rw-r--r--benchmark/exhaustive-processor/.gitignore4
-rw-r--r--benchmark/exhaustive-processor/build.gradle.kts39
-rw-r--r--benchmark/exhaustive-processor/gradle.properties3
-rw-r--r--benchmark/exhaustive-processor/gradle/wrapper/gradle-wrapper.jarbin0 -> 59203 bytes
-rw-r--r--benchmark/exhaustive-processor/gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xbenchmark/exhaustive-processor/gradlew185
-rw-r--r--benchmark/exhaustive-processor/gradlew.bat89
-rw-r--r--benchmark/exhaustive-processor/processor/build.gradle.kts49
-rw-r--r--benchmark/exhaustive-processor/processor/src/main/kotlin/ExhaustiveProcessor.kt203
-rw-r--r--benchmark/exhaustive-processor/processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider1
-rw-r--r--benchmark/exhaustive-processor/settings.gradle.kts31
-rw-r--r--benchmark/gradle/wrapper/gradle-wrapper.jarbin0 -> 59536 bytes
-rw-r--r--benchmark/gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xbenchmark/gradlew185
-rwxr-xr-xbenchmark/runner/runner.sh70
-rw-r--r--benchmark/settings.gradle.kts17
-rw-r--r--benchmark/src/main/kotlin/com/google/devtools/ksp/BenchRunner.kt36
-rw-r--r--build.gradle.kts97
-rw-r--r--buildSrc/build.gradle.kts15
-rw-r--r--buildSrc/settings.gradle.kts6
-rw-r--r--buildSrc/src/main/kotlin/com/google/devtools/ksp/ApiCheck.kt84
-rw-r--r--buildSrc/src/main/kotlin/com/google/devtools/ksp/Ktlint.kt100
-rw-r--r--common-util/build.gradle.kts34
-rw-r--r--common-util/src/main/kotlin/com/google/devtools/ksp/DescriptorUtils.kt228
-rw-r--r--common-util/src/main/kotlin/com/google/devtools/ksp/IncrementalUtil.kt64
-rw-r--r--common-util/src/main/kotlin/com/google/devtools/ksp/KSObjectCacheManager.kt37
-rw-r--r--common-util/src/main/kotlin/com/google/devtools/ksp/KSPUtils.kt23
-rw-r--r--common-util/src/main/kotlin/com/google/devtools/ksp/KspOptions.kt343
-rw-r--r--common-util/src/main/kotlin/com/google/devtools/ksp/MemoizedSequence.kt48
-rw-r--r--common-util/src/main/kotlin/com/google/devtools/ksp/PsiUtils.kt175
-rw-r--r--common-util/src/main/kotlin/com/google/devtools/ksp/processing/impl/CodeGeneratorImpl.kt172
-rw-r--r--common-util/src/main/kotlin/com/google/devtools/ksp/processing/impl/KSNameImpl.kt22
-rw-r--r--common-util/src/main/kotlin/com/google/devtools/ksp/processing/impl/PlatformInfoImpl.kt49
-rw-r--r--common-util/src/main/kotlin/com/google/devtools/ksp/visitor/CollectAnnotatedSymbolsVisitor.kt90
-rw-r--r--common-util/src/test/kotlin/com/google/devtools/ksp/MemoizedSequenceTest.kt27
-rw-r--r--common-util/src/test/kotlin/com/google/devtools/ksp/processing/impl/CodeGeneratorImplTest.kt128
-rw-r--r--compiler-plugin/build.gradle.kts121
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/DualLookupTracker.kt46
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/Incremental.kt786
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt453
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingPlugin.kt96
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/JvmUtils.kt26
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/KSPCompilationError.kt6
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/MessageCollectorBasedKSPLogger.kt85
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt1613
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSAnnotationDescriptorImpl.kt347
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt203
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassifierReferenceDescriptorImpl.kt86
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSDeclarationDescriptorImpl.kt84
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSExpectActualDescriptorImpl.kt50
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSFunctionDeclarationDescriptorImpl.kt114
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSNodeDescriptorImpl.kt9
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertyAccessorDescriptorImpl.kt62
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertyDeclarationDescriptorImpl.kt124
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertyGetterDescriptorImpl.kt47
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertySetterDescriptorImpl.kt44
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeAliasDescriptorImpl.kt38
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeArgumentDescriptorImpl.kt65
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeParameterDescriptorImpl.kt74
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeReferenceDescriptorImpl.kt82
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSValueParameterDescriptorImpl.kt78
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSAnnotationJavaImpl.kt160
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt111
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt173
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassifierReferenceJavaImpl.kt66
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassifierReferenceLiteImplForJava.kt50
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSDeclarationJavaImpl.kt48
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSFileJavaImpl.kt62
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSFunctionDeclarationJavaImpl.kt125
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSNodeJavaImpl.kt12
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSPropertyDeclarationJavaImpl.kt101
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeArgumentJavaImpl.kt64
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeParameterJavaImpl.kt82
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeReferenceJavaImpl.kt148
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeReferenceLiteJavaImpl.kt90
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSValueArgumentJavaImpl.kt50
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSValueParameterJavaImpl.kt88
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSAnnotationImpl.kt120
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSCallableReferenceImpl.kt68
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt138
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassifierReferenceImpl.kt62
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSDeclarationImpl.kt96
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSDefNonNullReferenceImpl.kt41
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSDynamicReferenceImpl.kt43
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt71
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSExpectActualImpl.kt64
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSExpectActualNoImpl.kt31
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFileImpl.kt68
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionDeclarationImpl.kt123
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionErrorImpl.kt60
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionImpl.kt76
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSNodeKtImpl.kt12
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyAccessorImpl.kt66
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt129
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationParameterImpl.kt107
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyGetterImpl.kt53
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertySetterImpl.kt50
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeAliasImpl.kt44
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeArgumentImpl.kt83
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeArgumentLiteImpl.kt56
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt154
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeParameterImpl.kt93
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeReferenceDeferredImpl.kt69
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeReferenceImpl.kt129
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueArgumentImpl.kt70
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt131
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSConstructorSyntheticImpl.kt119
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSErrorTypeClassDeclaration.kt96
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSPropertyAccessorSyntheticImpl.kt41
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSPropertyGetterSyntheticImpl.kt59
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSPropertySetterSyntheticImpl.kt57
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSTypeReferenceSyntheticImpl.kt43
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSValueParameterSyntheticImpl.kt76
-rw-r--r--compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/utils.kt559
-rw-r--r--compiler-plugin/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor1
-rw-r--r--compiler-plugin/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar1
-rw-r--r--compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/AbstractKSPCompilerPluginTest.kt77
-rw-r--r--compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/KSPCompilerPluginTest.kt545
-rw-r--r--examples/multiplatform/.gitignore5
-rw-r--r--examples/multiplatform/build.gradle.kts14
-rw-r--r--examples/multiplatform/gradle.properties3
-rw-r--r--examples/multiplatform/gradle/wrapper/gradle-wrapper.jarbin0 -> 55618 bytes
-rw-r--r--examples/multiplatform/gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xexamples/multiplatform/gradlew172
-rw-r--r--examples/multiplatform/gradlew.bat84
-rw-r--r--examples/multiplatform/settings.gradle.kts17
-rw-r--r--examples/multiplatform/test-processor/build.gradle.kts22
-rw-r--r--examples/multiplatform/test-processor/src/main/kotlin/TestProcessor.kt52
-rw-r--r--examples/multiplatform/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider1
-rw-r--r--examples/multiplatform/workload/build.gradle.kts60
-rw-r--r--examples/multiplatform/workload/src/androidNativeArm64Main/kotlin/Main.kt7
-rw-r--r--examples/multiplatform/workload/src/androidNativeX64Main/kotlin/Main.kt7
-rw-r--r--examples/multiplatform/workload/src/commonMain/kotlin/com/example/Bar.kt5
-rw-r--r--examples/multiplatform/workload/src/commonMain/kotlin/com/example/Baz.kt5
-rw-r--r--examples/multiplatform/workload/src/linuxX64Main/kotlin/Main.kt7
-rw-r--r--examples/multiplatform/workload/src/linuxX64Test/kotlin/MyTest.kt1
-rw-r--r--examples/playground/.gitignore5
-rw-r--r--examples/playground/build.gradle.kts14
-rw-r--r--examples/playground/gradle.properties3
-rw-r--r--examples/playground/gradle/wrapper/gradle-wrapper.jarbin0 -> 58910 bytes
-rw-r--r--examples/playground/gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xexamples/playground/gradlew185
-rw-r--r--examples/playground/gradlew.bat104
-rw-r--r--examples/playground/settings.gradle.kts17
-rw-r--r--examples/playground/test-processor/build.gradle.kts19
-rw-r--r--examples/playground/test-processor/src/main/kotlin/Builder.kt4
-rw-r--r--examples/playground/test-processor/src/main/kotlin/BuilderProcessor.kt79
-rw-r--r--examples/playground/test-processor/src/main/kotlin/JavaBuilderProcessor.kt58
-rw-r--r--examples/playground/test-processor/src/main/kotlin/TestProcessor.kt259
-rw-r--r--examples/playground/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider2
-rw-r--r--examples/playground/test-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor1
-rw-r--r--examples/playground/workload/build.gradle.kts17
-rw-r--r--examples/playground/workload/src/main/java/com/example/A.kt19
-rw-r--r--examples/playground/workload/src/main/java/com/example/AClass.kt10
-rw-r--r--gradle-plugin/build.gradle.kts160
-rw-r--r--gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/AndroidPluginIntegration.kt85
-rw-r--r--gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KotlinFactories.kt284
-rw-r--r--gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspConfigurations.kt176
-rw-r--r--gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspExtension.kt56
-rw-r--r--gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspSubplugin.kt762
-rw-r--r--gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/model/Ksp.kt40
-rw-r--r--gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/model/builder/KspModelBuilder.kt43
-rw-r--r--gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/model/impl/KspImpl.kt35
-rw-r--r--gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/GradleCompilationTest.kt316
-rw-r--r--gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/ProcessorClasspathConfigurationsTest.kt130
-rw-r--r--gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/SourceSetConfigurationsTest.kt402
-rw-r--r--gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/model/builder/KspModelBuilderTest.kt32
-rw-r--r--gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/processor/TestSymbolProcessorProvider.kt29
-rw-r--r--gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/DependencyDeclaration.kt50
-rw-r--r--gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/KspIntegrationTestRule.kt152
-rw-r--r--gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/PluginDeclaration.kt46
-rw-r--r--gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/TestConfig.kt80
-rw-r--r--gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/TestModule.kt155
-rw-r--r--gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/TestProject.kt133
-rw-r--r--gradle.properties11
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin0 -> 59536 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xgradlew185
-rw-r--r--gradlew.bat89
-rw-r--r--integration-tests/build.gradle.kts24
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIT.kt84
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIncrementalIT.kt62
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/Artifact.kt24
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/BuildCacheIT.kt41
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/GeneratedRefsIncIT.kt69
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/GeneratedSrcsIncIT.kt34
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/GetSealedSubclassesIncIT.kt56
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/HmppIT.kt83
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalCPIT.kt130
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalIT.kt262
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalMultiChainIT.kt49
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalRemovalIT.kt35
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/InitPlusProviderIT.kt33
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/JavaNestedClassIT.kt22
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/JavaOnlyIT.kt34
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt369
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KSPCmdLineOptionsIT.kt85
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KotlinConstsInJavaIT.kt42
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/MapAnnotationArgumentsIT.kt40
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/MultiplatformIT.kt34
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OnErrorIT.kt111
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OnlyResourcesFileIT.kt21
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OutputDepsIt.kt157
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/PlaygroundIT.kt210
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/PsiCacheIT.kt18
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/TemporaryTestProject.kt41
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/VerboseIT.kt67
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/VersionCheckIT.kt42
-rw-r--r--integration-tests/src/test/kotlin/com/google/devtools/ksp/test/fixtures/BuildResultFixture.kt34
-rw-r--r--integration-tests/src/test/resources/buildcache/settings.gradle.kts27
-rw-r--r--integration-tests/src/test/resources/cmd-options/build.gradle.kts8
-rw-r--r--integration-tests/src/test/resources/cmd-options/gradle.properties0
-rw-r--r--integration-tests/src/test/resources/cmd-options/processors/build.gradle.kts23
-rw-r--r--integration-tests/src/test/resources/cmd-options/processors/src/main/kotlin/TestProcessor.kt37
-rw-r--r--integration-tests/src/test/resources/cmd-options/processors/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider1
-rw-r--r--integration-tests/src/test/resources/cmd-options/settings.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/cmd-options/workload/build.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/cmd-options/workload/src/main/kotlin/com/example/A.kt4
-rw-r--r--integration-tests/src/test/resources/hmpp/build.gradle.kts12
-rw-r--r--integration-tests/src/test/resources/hmpp/gradle.properties1
-rw-r--r--integration-tests/src/test/resources/hmpp/settings.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/hmpp/test-processor/build.gradle.kts22
-rw-r--r--integration-tests/src/test/resources/hmpp/test-processor/src/main/kotlin/EchoProcessor.kt27
-rw-r--r--integration-tests/src/test/resources/hmpp/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider1
-rw-r--r--integration-tests/src/test/resources/hmpp/workload/build.gradle.kts55
-rw-r--r--integration-tests/src/test/resources/hmpp/workload/src/commonMain/kotlin/CommonMain.kt1
-rw-r--r--integration-tests/src/test/resources/hmpp/workload/src/jsMain/kotlin/JsMain.kt1
-rw-r--r--integration-tests/src/test/resources/hmpp/workload/src/jvmJs/kotlin/JvmJs.kt1
-rw-r--r--integration-tests/src/test/resources/hmpp/workload/src/jvmLinuxX64/kotlin/JvmLinuxX64.kt1
-rw-r--r--integration-tests/src/test/resources/hmpp/workload/src/jvmMain/kotlin/JvmMain.kt1
-rw-r--r--integration-tests/src/test/resources/hmpp/workload/src/jvmOnly/kotlin/JvmOnly.kt1
-rw-r--r--integration-tests/src/test/resources/hmpp/workload/src/linuxX64Main/kotlin/LinuxX64Main.kt4
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/build.gradle.kts8
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/gradle.properties3
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/l1/build.gradle.kts18
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/l1/src/main/kotlin/p1/L1.kt3
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/l2/build.gradle.kts17
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/l2/src/main/kotlin/p1/L2.kt3
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/l3/build.gradle.kts17
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/l3/src/main/kotlin/p1/L3.kt3
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/l4/build.gradle.kts17
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/l4/src/main/kotlin/p1/L4.kt3
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/l5/build.gradle.kts17
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/l5/src/main/kotlin/p1/L5.kt3
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/settings.gradle.kts24
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/validator/build.gradle.kts24
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/validator/src/main/kotlin/Validator.kt79
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/validator/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider1
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/workload/build.gradle.kts26
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/workload/src/main/kotlin/p1/K1.kt5
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/workload/src/main/kotlin/p1/K2.kt5
-rw-r--r--integration-tests/src/test/resources/incremental-classpath/workload/src/main/kotlin/p1/K3.kt5
-rw-r--r--integration-tests/src/test/resources/incremental-multi-chain/build.gradle.kts8
-rw-r--r--integration-tests/src/test/resources/incremental-multi-chain/gradle.properties2
-rw-r--r--integration-tests/src/test/resources/incremental-multi-chain/processors/build.gradle.kts24
-rw-r--r--integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/Aggregator.kt46
-rw-r--r--integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/ImplGen.kt46
-rw-r--r--integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/Validator.kt36
-rw-r--r--integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider3
-rw-r--r--integration-tests/src/test/resources/incremental-multi-chain/settings.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/incremental-multi-chain/workload/build.gradle.kts24
-rw-r--r--integration-tests/src/test/resources/incremental-multi-chain/workload/src/main/kotlin/K1.kt2
-rw-r--r--integration-tests/src/test/resources/incremental-multi-chain/workload/src/main/kotlin/Main.kt8
-rw-r--r--integration-tests/src/test/resources/incremental-removal/build.gradle.kts8
-rw-r--r--integration-tests/src/test/resources/incremental-removal/gradle.properties2
-rw-r--r--integration-tests/src/test/resources/incremental-removal/settings.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/incremental-removal/validator/build.gradle.kts24
-rw-r--r--integration-tests/src/test/resources/incremental-removal/validator/src/main/kotlin/Validator.kt48
-rw-r--r--integration-tests/src/test/resources/incremental-removal/validator/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider1
-rw-r--r--integration-tests/src/test/resources/incremental-removal/workload/build.gradle.kts27
-rw-r--r--integration-tests/src/test/resources/incremental-removal/workload/src/main/kotlin/p1/K1.kt4
-rw-r--r--integration-tests/src/test/resources/incremental-removal/workload/src/main/kotlin/p1/Main.kt12
-rw-r--r--integration-tests/src/test/resources/incremental/build.gradle.kts8
-rw-r--r--integration-tests/src/test/resources/incremental/gradle.properties2
-rw-r--r--integration-tests/src/test/resources/incremental/settings.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/incremental/validator/build.gradle.kts24
-rw-r--r--integration-tests/src/test/resources/incremental/validator/src/main/kotlin/Validator.kt62
-rw-r--r--integration-tests/src/test/resources/incremental/validator/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider1
-rw-r--r--integration-tests/src/test/resources/incremental/workload/build.gradle.kts22
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/java/p1/J1.java3
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/java/p1/J2.java4
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/java/p1/TestJ2J.java11
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/java/p1/TestJ2K.java10
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/java/p2/J2.java4
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/java/p3/J1.java4
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/java/p3/J2.java4
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/java/p3/J3.java4
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/K1.kt3
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/K2.kt3
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/TestK2J.kt10
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/TestK2K.kt10
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p2/K2.kt3
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p3/K1.kt3
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p3/K2.kt3
-rw-r--r--integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p3/K3.kt3
-rw-r--r--integration-tests/src/test/resources/init-plus-provider/build.gradle.kts8
-rw-r--r--integration-tests/src/test/resources/init-plus-provider/provider-processor/build.gradle.kts24
-rw-r--r--integration-tests/src/test/resources/init-plus-provider/provider-processor/src/main/kotlin/TestProcessor.kt41
-rw-r--r--integration-tests/src/test/resources/init-plus-provider/provider-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider1
-rw-r--r--integration-tests/src/test/resources/init-plus-provider/settings.gradle.kts22
-rw-r--r--integration-tests/src/test/resources/init-plus-provider/workload/build.gradle.kts24
-rw-r--r--integration-tests/src/test/resources/init-plus-provider/workload/src/main/java/com/example/A.kt7
-rw-r--r--integration-tests/src/test/resources/java-only/test-processor/src/main/kotlin/TestProcessor.kt30
-rw-r--r--integration-tests/src/test/resources/java-only/workload/src/main/java/com/example/Foo.java4
-rw-r--r--integration-tests/src/test/resources/javaNestedClass/build.gradle.kts8
-rw-r--r--integration-tests/src/test/resources/javaNestedClass/settings.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/javaNestedClass/test-processor/build.gradle.kts25
-rw-r--r--integration-tests/src/test/resources/javaNestedClass/test-processor/src/main/kotlin/ValidateProcessor.kt38
-rw-r--r--integration-tests/src/test/resources/javaNestedClass/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider1
-rw-r--r--integration-tests/src/test/resources/javaNestedClass/workload/build.gradle.kts20
-rw-r--r--integration-tests/src/test/resources/javaNestedClass/workload/src/main/java/com/example/A.kt4
-rw-r--r--integration-tests/src/test/resources/javaNestedClass/workload/src/main/java/com/example/JavaClass.java22
-rw-r--r--integration-tests/src/test/resources/kmp/annotations/build.gradle.kts32
-rw-r--r--integration-tests/src/test/resources/kmp/annotations/src/commonMain/kotlin/com/example/MyAnnotation.kt3
-rw-r--r--integration-tests/src/test/resources/kmp/build.gradle.kts12
-rw-r--r--integration-tests/src/test/resources/kmp/gradle.properties1
-rw-r--r--integration-tests/src/test/resources/kmp/settings.gradle.kts24
-rw-r--r--integration-tests/src/test/resources/kmp/test-processor/build.gradle.kts22
-rw-r--r--integration-tests/src/test/resources/kmp/test-processor/src/main/kotlin/ErrorProcessor.kt61
-rw-r--r--integration-tests/src/test/resources/kmp/test-processor/src/main/kotlin/TestProcessor.kt74
-rw-r--r--integration-tests/src/test/resources/kmp/test-processor/src/main/kotlin/ValidateProcessor.kt29
-rw-r--r--integration-tests/src/test/resources/kmp/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider3
-rw-r--r--integration-tests/src/test/resources/kmp/workload-androidNative/build.gradle.kts41
-rw-r--r--integration-tests/src/test/resources/kmp/workload-androidNative/src/androidNativeArm64Main/kotlin/Main.kt7
-rw-r--r--integration-tests/src/test/resources/kmp/workload-androidNative/src/androidNativeX64Main/kotlin/Main.kt7
-rw-r--r--integration-tests/src/test/resources/kmp/workload-androidNative/src/commonMain/kotlin/com/example/Bar.kt5
-rw-r--r--integration-tests/src/test/resources/kmp/workload-androidNative/src/commonMain/kotlin/com/example/Baz.kt5
-rw-r--r--integration-tests/src/test/resources/kmp/workload-androidNative/src/commonMain/kotlin/com/example/ToBeValidated.kt9
-rw-r--r--integration-tests/src/test/resources/kmp/workload-js/build.gradle.kts30
-rw-r--r--integration-tests/src/test/resources/kmp/workload-js/src/commonMain/kotlin/com/example/Bar.kt5
-rw-r--r--integration-tests/src/test/resources/kmp/workload-js/src/commonMain/kotlin/com/example/Baz.kt5
-rw-r--r--integration-tests/src/test/resources/kmp/workload-js/src/commonMain/kotlin/com/example/ToBeValidated.kt9
-rw-r--r--integration-tests/src/test/resources/kmp/workload-jvm/build.gradle.kts25
-rw-r--r--integration-tests/src/test/resources/kmp/workload-jvm/src/commonMain/kotlin/com/example/Bar.kt5
-rw-r--r--integration-tests/src/test/resources/kmp/workload-jvm/src/commonMain/kotlin/com/example/Baz.kt5
-rw-r--r--integration-tests/src/test/resources/kmp/workload-jvm/src/commonMain/kotlin/com/example/ToBeValidated.kt9
-rw-r--r--integration-tests/src/test/resources/kmp/workload-linuxX64/build.gradle.kts40
-rw-r--r--integration-tests/src/test/resources/kmp/workload-linuxX64/src/commonMain/kotlin/com/example/Bar.kt5
-rw-r--r--integration-tests/src/test/resources/kmp/workload-linuxX64/src/commonMain/kotlin/com/example/Baz.kt5
-rw-r--r--integration-tests/src/test/resources/kmp/workload-linuxX64/src/commonMain/kotlin/com/example/ToBeValidated.kt9
-rw-r--r--integration-tests/src/test/resources/kmp/workload-linuxX64/src/linuxX64Main/kotlin/Main.kt7
-rw-r--r--integration-tests/src/test/resources/kmp/workload-linuxX64/src/linuxX64Main/kotlin/ToBeRemoved.kt1
-rw-r--r--integration-tests/src/test/resources/kmp/workload-linuxX64/src/linuxX64Test/kotlin/MyTest.kt3
-rw-r--r--integration-tests/src/test/resources/kmp/workload/build.gradle.kts66
-rw-r--r--integration-tests/src/test/resources/kmp/workload/src/androidNativeArm64Main/kotlin/Main.kt7
-rw-r--r--integration-tests/src/test/resources/kmp/workload/src/androidNativeX64Main/kotlin/Main.kt7
-rw-r--r--integration-tests/src/test/resources/kmp/workload/src/commonMain/kotlin/com/example/Bar.kt5
-rw-r--r--integration-tests/src/test/resources/kmp/workload/src/commonMain/kotlin/com/example/Baz.kt5
-rw-r--r--integration-tests/src/test/resources/kmp/workload/src/commonMain/kotlin/com/example/ToBeValidated.kt9
-rw-r--r--integration-tests/src/test/resources/kmp/workload/src/linuxX64Main/kotlin/Main.kt7
-rw-r--r--integration-tests/src/test/resources/kmp/workload/src/linuxX64Test/kotlin/MyTest.kt3
-rw-r--r--integration-tests/src/test/resources/kotlin-consts-in-java/build.gradle.kts8
-rw-r--r--integration-tests/src/test/resources/kotlin-consts-in-java/settings.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/kotlin-consts-in-java/test-processor/build.gradle.kts24
-rw-r--r--integration-tests/src/test/resources/kotlin-consts-in-java/test-processor/src/main/kotlin/TestProcessor.kt27
-rw-r--r--integration-tests/src/test/resources/kotlin-consts-in-java/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider1
-rw-r--r--integration-tests/src/test/resources/kotlin-consts-in-java/workload/build.gradle.kts20
-rw-r--r--integration-tests/src/test/resources/kotlin-consts-in-java/workload/src/main/java/com/example/JavaClass.java9
-rw-r--r--integration-tests/src/test/resources/kotlin-consts-in-java/workload/src/main/java/com/example/KotlinConsts.kt8
-rw-r--r--integration-tests/src/test/resources/kotlin-consts-in-java/workload/src/main/java/com/example/ann/MyAnn.kt3
-rw-r--r--integration-tests/src/test/resources/map-annotation-arguments/test-processor/src/main/kotlin/TestProcessor.kt36
-rw-r--r--integration-tests/src/test/resources/map-annotation-arguments/workload/src/main/java/com/example/AnnotationTest.java8
-rw-r--r--integration-tests/src/test/resources/map-annotation-arguments/workload/src/main/java/com/example/JavaAnnotation.java6
-rw-r--r--integration-tests/src/test/resources/on-error/build.gradle.kts8
-rw-r--r--integration-tests/src/test/resources/on-error/on-error-processor/build.gradle.kts23
-rw-r--r--integration-tests/src/test/resources/on-error/on-error-processor/src/main/kotlin/ErrorProcessor.kt70
-rw-r--r--integration-tests/src/test/resources/on-error/on-error-processor/src/main/kotlin/NormalProcessor.kt40
-rw-r--r--integration-tests/src/test/resources/on-error/on-error-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider2
-rw-r--r--integration-tests/src/test/resources/on-error/settings.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/on-error/workload/build.gradle.kts23
-rw-r--r--integration-tests/src/test/resources/on-error/workload/src/main/kotlin/com/example/A.kt11
-rw-r--r--integration-tests/src/test/resources/only-resources-file/build.gradle.kts12
-rw-r--r--integration-tests/src/test/resources/only-resources-file/settings.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/only-resources-file/test-processor/build.gradle.kts12
-rw-r--r--integration-tests/src/test/resources/only-resources-file/test-processor/src/main/kotlin/TestProcessor.kt24
-rw-r--r--integration-tests/src/test/resources/only-resources-file/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider1
-rw-r--r--integration-tests/src/test/resources/only-resources-file/workload/build.gradle.kts16
-rw-r--r--integration-tests/src/test/resources/only-resources-file/workload/src/commonMain/kotlin/MyStub.kt1
-rw-r--r--integration-tests/src/test/resources/output-deps/build.gradle.kts8
-rw-r--r--integration-tests/src/test/resources/output-deps/gradle.properties2
-rw-r--r--integration-tests/src/test/resources/output-deps/settings.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/output-deps/test-processor/build.gradle.kts24
-rw-r--r--integration-tests/src/test/resources/output-deps/test-processor/src/main/kotlin/TestProcessor.kt61
-rw-r--r--integration-tests/src/test/resources/output-deps/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider1
-rw-r--r--integration-tests/src/test/resources/output-deps/workload/build.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/output-deps/workload/src/main/java/p1/J1.java5
-rw-r--r--integration-tests/src/test/resources/output-deps/workload/src/main/java/p1/J2.java4
-rw-r--r--integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/Anno1.kt2
-rw-r--r--integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/Anno2.kt2
-rw-r--r--integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/K1.kt4
-rw-r--r--integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/K2.kt5
-rw-r--r--integration-tests/src/test/resources/playground-android-multi/application/build.gradle.kts30
-rw-r--r--integration-tests/src/test/resources/playground-android-multi/application/src/main/AndroidManifest.xml4
-rw-r--r--integration-tests/src/test/resources/playground-android-multi/application/src/main/java/com/example/application/Foo.kt3
-rw-r--r--integration-tests/src/test/resources/playground-android-multi/build.gradle.kts27
-rw-r--r--integration-tests/src/test/resources/playground-android-multi/gradle.properties1
-rw-r--r--integration-tests/src/test/resources/playground-android-multi/settings.gradle.kts26
-rw-r--r--integration-tests/src/test/resources/playground-android-multi/test-processor/build.gradle.kts25
-rw-r--r--integration-tests/src/test/resources/playground-android-multi/workload/build.gradle.kts35
-rw-r--r--integration-tests/src/test/resources/playground-android-multi/workload/src/main/AndroidManifest.xml4
-rw-r--r--integration-tests/src/test/resources/playground-android/build.gradle.kts20
-rw-r--r--integration-tests/src/test/resources/playground-android/gradle.properties1
-rw-r--r--integration-tests/src/test/resources/playground-android/settings.gradle.kts24
-rw-r--r--integration-tests/src/test/resources/playground-android/test-processor/build.gradle.kts25
-rw-r--r--integration-tests/src/test/resources/playground-android/workload/build.gradle.kts45
-rw-r--r--integration-tests/src/test/resources/playground-android/workload/proguard-rules.pro1
-rw-r--r--integration-tests/src/test/resources/playground-android/workload/src/main/AndroidManifest.xml4
-rw-r--r--integration-tests/src/test/resources/playground-mpp/build.gradle.kts12
-rw-r--r--integration-tests/src/test/resources/playground-mpp/settings.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/playground-mpp/test-processor/build.gradle.kts22
-rw-r--r--integration-tests/src/test/resources/playground-mpp/workload/build.gradle.kts39
-rw-r--r--integration-tests/src/test/resources/playground/build.gradle.kts8
-rw-r--r--integration-tests/src/test/resources/playground/settings.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/playground/test-processor/build.gradle.kts25
-rw-r--r--integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/Builder.kt3
-rw-r--r--integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/BuilderProcessor.kt104
-rw-r--r--integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/RewriteProcessor.kt30
-rw-r--r--integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/TestProcessor.kt283
-rw-r--r--integration-tests/src/test/resources/playground/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider2
-rw-r--r--integration-tests/src/test/resources/playground/workload/G.kt6
-rw-r--r--integration-tests/src/test/resources/playground/workload/build.gradle.kts36
-rw-r--r--integration-tests/src/test/resources/playground/workload/src/main/java/com/example/A.kt16
-rw-r--r--integration-tests/src/test/resources/playground/workload/src/main/java/com/example/AClass.kt17
-rw-r--r--integration-tests/src/test/resources/playground/workload/src/main/java/com/example/BClass.java14
-rw-r--r--integration-tests/src/test/resources/psi-cache/test-processor/src/main/kotlin/TestProcessor.kt40
-rw-r--r--integration-tests/src/test/resources/psi-cache/workload/src/main/java/com/example/Bar.kt6
-rw-r--r--integration-tests/src/test/resources/psi-cache/workload/src/main/java/com/example/Baz.java6
-rw-r--r--integration-tests/src/test/resources/refs-gen/test-processor/src/main/kotlin/TestProcessor.kt48
-rw-r--r--integration-tests/src/test/resources/refs-gen/workload/src/main/kotlin/com/example/Bar.kt3
-rw-r--r--integration-tests/src/test/resources/refs-gen/workload/src/main/kotlin/com/example/Baz.kt5
-rw-r--r--integration-tests/src/test/resources/sealed-subclasses/test-processor/src/main/kotlin/TestProcessor.kt28
-rw-r--r--integration-tests/src/test/resources/sealed-subclasses/workload/src/main/kotlin/com/example/Impl1.kt3
-rw-r--r--integration-tests/src/test/resources/sealed-subclasses/workload/src/main/kotlin/com/example/Impl2.kt3
-rw-r--r--integration-tests/src/test/resources/sealed-subclasses/workload/src/main/kotlin/com/example/Sealed.kt3
-rw-r--r--integration-tests/src/test/resources/srcs-gen/test-processor/src/main/kotlin/TestProcessor.kt54
-rw-r--r--integration-tests/src/test/resources/srcs-gen/workload/src/main/kotlin/com/example/Bar.kt3
-rw-r--r--integration-tests/src/test/resources/srcs-gen/workload/src/main/kotlin/com/example/Baz.kt3
-rw-r--r--integration-tests/src/test/resources/test-processor/build.gradle.kts8
-rw-r--r--integration-tests/src/test/resources/test-processor/settings.gradle.kts19
-rw-r--r--integration-tests/src/test/resources/test-processor/test-processor/build.gradle.kts24
-rw-r--r--integration-tests/src/test/resources/test-processor/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider1
-rw-r--r--integration-tests/src/test/resources/test-processor/workload/build.gradle.kts20
-rw-r--r--kotlin-analysis-api/build.gradle.kts121
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/CommandLineKSPLogger.kt45
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KSPCommandLineProcessor.kt53
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KSPCoreEnvironment.kt32
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KotlinSymbolProcessing.kt135
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/ResolverAAImpl.kt273
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/AbstractKSDeclarationImpl.kt103
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt117
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSCallableReferenceImpl.kt36
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationEnumEntryImpl.kt130
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationImpl.kt155
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassifierReferenceImpl.kt37
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSDynamicReferenceImpl.kt26
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorType.kt63
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorTypeClassDeclaration.kt96
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSExpectActualImpl.kt37
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileImpl.kt96
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileJavaImpl.kt66
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFunctionDeclarationImpl.kt187
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyAccessorImpl.kt115
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationImpl.kt138
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationJavaImpl.kt78
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationLocalVariableImpl.kt54
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeAliasImpl.kt56
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeArgumentImpl.kt77
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeArgumentLiteImpl.kt33
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeImpl.kt166
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeParameterImpl.kt63
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeReferenceImpl.kt118
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueArgumentImpl.kt97
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueParameterImpl.kt107
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueParameterLiteImpl.kt43
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/synthetic/KSSyntheticAnnotations.kt11
-rw-r--r--kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/util.kt354
-rw-r--r--kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/impl/test/AbstractKSPAATest.kt159
-rw-r--r--kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/impl/test/KSPAATest.kt584
-rw-r--r--kotlin-analysis-api/testData/innerTypes.kt51
-rw-r--r--settings.gradle.kts18
-rw-r--r--symbol-processing-cmdline/build.gradle.kts79
-rw-r--r--symbol-processing/build.gradle.kts83
-rw-r--r--test-utils/build.gradle.kts34
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractFunctionsProcessor.kt33
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractTestProcessor.kt28
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AllFunctionsProcessor.kt82
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotatedUtilProcessor.kt148
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArbitraryClassValueProcessor.kt70
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArgumentProcessor.kt62
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueProcessor.kt55
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValueProcessor.kt49
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValuesProcessor.kt48
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationJavaTypeValueProcessor.kt53
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationOnConstructorParameterProcessor.kt47
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationsInDependenciesProcessor.kt93
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AsMemberOfProcessor.kt235
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BackingFieldProcessor.kt62
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BaseVisitor.kt26
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BuiltInTypesProcessor.kt64
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CheckOverrideProcessor.kt115
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassKindsProcessor.kt59
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassWithCompanionProcessor.kt49
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstPropertiesProcessor.kt39
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstructorDeclarationsProcessor.kt89
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CrossModuleTypeAliasTestProcessor.kt53
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationInconsistencyProcessor.kt48
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationOrderProcessor.kt44
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationPackageNameProcessor.kt74
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationUtilProcessor.kt67
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclaredProcessor.kt25
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DefaultFunctionProcessor.kt116
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DocStringProcessor.kt47
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/EquivalentJavaWildcardProcessor.kt64
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ErrorTypeProcessor.kt83
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAliasProcessor.kt58
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAnnotationProcessor.kt36
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeProcessor.kt53
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetAnnotationByTypeProcessor.kt36
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetByNameProcessor.kt63
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetPackageProcessor.kt29
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetSymbolsFromAnnotationProcessor.kt35
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/HelloProcessor.kt51
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitElementProcessor.kt94
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitPropertyAccessorProcessor.kt26
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InheritedTypeAliasProcessor.kt60
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InnerTypeProcessor.kt71
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt74
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaNonNullProcessor.kt64
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaSubtypeProcessor.kt78
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaToKotlinMapProcessor.kt75
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaWildcard2Processor.kt66
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LateinitPropertiesProcessor.kt39
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LibOriginsProcessor.kt94
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MakeNullableProcessor.kt51
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MangledNamesProcessor.kt81
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MapSignatureProcessor.kt45
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MultiModuleTestProcessor.kt53
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NestedClassTypeProcessor.kt31
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NullableTypeProcessor.kt53
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/OverrideeProcessor.kt113
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParameterTypeProcessor.kt32
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParentProcessor.kt34
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/PlatformDeclarationProcessor.kt69
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RawTypesProcessor.kt48
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaAsMemberOfProcessor.kt66
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaGetAllMembersProcessor.kt54
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaOverridesProcessor.kt71
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaProcessor.kt50
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaSupertypesProcessor.kt51
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReferenceElementProcessor.kt96
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReplaceWithErrorTypeArgsProcessor.kt67
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ResolveJavaTypeProcessor.kt93
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SealedClassProcessor.kt54
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SuperTypesProcessor.kt79
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ThrowListProcessor.kt71
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TopLevelMemberProcessor.kt73
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasComparisonProcessor.kt65
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasProcessor.kt86
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComparisonProcessor.kt78
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComposureProcessor.kt87
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterEqualsProcessor.kt22
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterReferenceProcessor.kt63
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ValidateProcessor.kt60
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/VisibilityProcessor.kt83
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/testutils/AbstractKSPTest.kt228
-rw-r--r--test-utils/testData/api/abstractFunctions.kt58
-rw-r--r--test-utils/testData/api/allFunctions_java_inherits_kt.kt46
-rw-r--r--test-utils/testData/api/allFunctions_kotlin.kt72
-rw-r--r--test-utils/testData/api/allFunctions_kt_inherits_java.kt93
-rw-r--r--test-utils/testData/api/annotatedUtil.kt149
-rw-r--r--test-utils/testData/api/annotationInDependencies.kt202
-rw-r--r--test-utils/testData/api/annotationOnConstructorParameter.kt31
-rw-r--r--test-utils/testData/api/annotationValue_java.kt77
-rw-r--r--test-utils/testData/api/annotationValue_kt.kt73
-rw-r--r--test-utils/testData/api/annotationWithArbitraryClassValue.kt38
-rw-r--r--test-utils/testData/api/annotationWithArrayValue.kt65
-rw-r--r--test-utils/testData/api/annotationWithDefault.kt155
-rw-r--r--test-utils/testData/api/annotationWithDefaultValues.kt155
-rw-r--r--test-utils/testData/api/annotationWithJavaTypeValue.kt49
-rw-r--r--test-utils/testData/api/asMemberOf.kt188
-rw-r--r--test-utils/testData/api/backingFields.kt364
-rw-r--r--test-utils/testData/api/builtInTypes.kt54
-rw-r--r--test-utils/testData/api/checkOverride.kt189
-rw-r--r--test-utils/testData/api/classKinds.kt55
-rw-r--r--test-utils/testData/api/companion.kt31
-rw-r--r--test-utils/testData/api/constProperties.kt57
-rw-r--r--test-utils/testData/api/constructorDeclarations.kt349
-rw-r--r--test-utils/testData/api/crossModuleTypeAlias.kt42
-rw-r--r--test-utils/testData/api/declarationInconsistency.kt31
-rw-r--r--test-utils/testData/api/declarationOrder.kt156
-rw-r--r--test-utils/testData/api/declarationPackageName.kt98
-rw-r--r--test-utils/testData/api/declarationUtil.kt100
-rw-r--r--test-utils/testData/api/declared.kt46
-rw-r--r--test-utils/testData/api/docString.kt141
-rw-r--r--test-utils/testData/api/equivalentJavaWildcards.kt208
-rw-r--r--test-utils/testData/api/errorTypes.kt44
-rw-r--r--test-utils/testData/api/functionTypeAlias.kt41
-rw-r--r--test-utils/testData/api/functionTypeAnnotation.kt33
-rw-r--r--test-utils/testData/api/functionTypes.kt72
-rw-r--r--test-utils/testData/api/getAnnotationByTypeWithInnerDefault.kt42
-rw-r--r--test-utils/testData/api/getByName.kt77
-rw-r--r--test-utils/testData/api/getPackage.kt99
-rw-r--r--test-utils/testData/api/getSymbolsFromAnnotation.kt161
-rw-r--r--test-utils/testData/api/hello.kt116
-rw-r--r--test-utils/testData/api/implicitElements.kt69
-rw-r--r--test-utils/testData/api/implicitPropertyAccessors.kt34
-rw-r--r--test-utils/testData/api/inheritedTypeAlias.kt36
-rw-r--r--test-utils/testData/api/innerTypes.kt51
-rw-r--r--test-utils/testData/api/interfaceWithDefault.kt78
-rw-r--r--test-utils/testData/api/javaAnnotatedUtil.kt171
-rw-r--r--test-utils/testData/api/javaModifiers.kt244
-rw-r--r--test-utils/testData/api/javaNonNullTypes.kt78
-rw-r--r--test-utils/testData/api/javaSubtype.kt36
-rw-r--r--test-utils/testData/api/javaToKotlinMapper.kt32
-rw-r--r--test-utils/testData/api/javaTypes.kt34
-rw-r--r--test-utils/testData/api/javaTypes2.kt47
-rw-r--r--test-utils/testData/api/javaWildcards2.kt108
-rw-r--r--test-utils/testData/api/lateinitProperties.kt56
-rw-r--r--test-utils/testData/api/libOrigins.kt338
-rw-r--r--test-utils/testData/api/makeNullable.kt40
-rw-r--r--test-utils/testData/api/mangledNames.kt194
-rw-r--r--test-utils/testData/api/multipleModules.kt56
-rw-r--r--test-utils/testData/api/nestedClassType.kt41
-rw-r--r--test-utils/testData/api/nullableTypes.kt49
-rw-r--r--test-utils/testData/api/overridee.kt321
-rw-r--r--test-utils/testData/api/parameterTypes.kt41
-rw-r--r--test-utils/testData/api/parent.kt298
-rw-r--r--test-utils/testData/api/platformDeclaration.kt103
-rw-r--r--test-utils/testData/api/rawTypes.kt100
-rw-r--r--test-utils/testData/api/recordJavaAnnotationTypes.kt46
-rw-r--r--test-utils/testData/api/recordJavaAsMemberOf.kt47
-rw-r--r--test-utils/testData/api/recordJavaGetAllMembers.kt65
-rw-r--r--test-utils/testData/api/recordJavaOverrides.kt71
-rw-r--r--test-utils/testData/api/recordJavaResolutions.kt90
-rw-r--r--test-utils/testData/api/recordJavaSupertypes.kt42
-rw-r--r--test-utils/testData/api/referenceElement.kt75
-rw-r--r--test-utils/testData/api/replaceWithErrorTypeArgs.kt134
-rw-r--r--test-utils/testData/api/resolveJavaType.kt135
-rw-r--r--test-utils/testData/api/sealedClass.kt42
-rw-r--r--test-utils/testData/api/signatureMapper.kt53
-rw-r--r--test-utils/testData/api/superTypes.kt112
-rw-r--r--test-utils/testData/api/throwList.kt107
-rw-r--r--test-utils/testData/api/topLevelMembers.kt138
-rw-r--r--test-utils/testData/api/typeAlias.kt55
-rw-r--r--test-utils/testData/api/typeAliasComparison.kt46
-rw-r--r--test-utils/testData/api/typeComposure.kt127
-rw-r--r--test-utils/testData/api/typeParameterEquals.kt31
-rw-r--r--test-utils/testData/api/typeParameterReference.kt82
-rw-r--r--test-utils/testData/api/validateTypes.kt108
-rw-r--r--test-utils/testData/api/varianceTypeCheck.kt84
-rw-r--r--test-utils/testData/api/visibilities.kt125
719 files changed, 47151 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..09fdf0aa
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,5 @@
+[*.{kt,kts}]
+indent_size=4
+insert_final_newline=true
+max_line_length=120
+disabled_rules=no-wildcard-imports
diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml
new file mode 100644
index 00000000..975d4ab0
--- /dev/null
+++ b/.github/workflows/auto-merge.yml
@@ -0,0 +1,138 @@
+# Workflow to cherry-pick changes from main to release branch.
+
+name: auto-merge
+
+on:
+ push:
+ branches: [ main ]
+
+jobs:
+ build-and-test:
+ 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.10-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 <<EOF
+ 76ac8de5cd4769b2cfd7c80ad156309c5f27d52a
+ 9675c5de0f689cb8563a0b6e1142a78747e8675c
+ fc22e8f947fb533e3f728252882c9dbe3f4d810d
+ caa3e0843dd169dcc3486d1ac28d16489324d564
+ 1ed2d3b709adc53450eb1c09fffe33a50459cc88
+ f0647fd2acffa78454700eb4750bf77caab05076
+ EOF
+ )
+ git config --global user.email "kotlin-symbol-processing@google.com"
+ git config --global user.name "KSP Auto Pick"
+ MERGE_BASE=$(git merge-base HEAD origin/main)
+ 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)
+ AA_COMMITS=$(git log $MERGE_BASE..origin/main --pretty=%H kotlin-analysis-api)
+ TO_PICK=$(grep -Fxv -f <(echo "$PICKED"; echo "$VERSION_BUMPS"; echo "$DONT_PICK"; echo "$AA_COMMITS") <(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: 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
+
+ pick-and-push:
+ needs: build-and-test
+ runs-on: ubuntu-latest
+
+ steps:
+ # Checkout
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ ref: 1.0.9-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 <<EOF
+ 76ac8de5cd4769b2cfd7c80ad156309c5f27d52a
+ 9675c5de0f689cb8563a0b6e1142a78747e8675c
+ fc22e8f947fb533e3f728252882c9dbe3f4d810d
+ caa3e0843dd169dcc3486d1ac28d16489324d564
+ 1ed2d3b709adc53450eb1c09fffe33a50459cc88
+ f0647fd2acffa78454700eb4750bf77caab05076
+ EOF
+ )
+ git config --global user.email "kotlin-symbol-processing@google.com"
+ git config --global user.name "KSP Auto Pick"
+ MERGE_BASE=$(git merge-base HEAD origin/main)
+ 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)
+ AA_COMMITS=$(git log $MERGE_BASE..origin/main --pretty=%H kotlin-analysis-api)
+ TO_PICK=$(grep -Fxv -f <(echo "$PICKED"; echo "$VERSION_BUMPS"; echo "$DONT_PICK"; echo "$AA_COMMITS") <(echo "$CANDIDATES") | tac)
+ echo Picking $TO_PICK
+ if [ -n "$TO_PICK" ]; then git cherry-pick -x $TO_PICK; fi
+
+ - name: push to release branch
+ run: git push origin
+
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 00000000..747039b1
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,80 @@
+# Workflow to run tests
+
+name: CI
+
+on:
+ push:
+ branches: [ main, 1.0.10-release, 1.0.9-release ]
+ pull_request:
+ branches: [ main, 1.0.10-release, 1.0.9-release ]
+
+jobs:
+ build-and-test:
+ 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:
+ - 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
+
+ # 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 ktlint
+ - name: lint
+ if: matrix.os == 'ubuntu-latest'
+ run: ./gradlew ktlint
+
+ # Check API compatibility
+ - name: API compatibility check
+ if: matrix.os == 'ubuntu-latest'
+ run: ./gradlew :api:checkApi
+
+ # 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-${{ matrix.os }}
+ path: |
+ compiler-plugin/build/reports
+ integration-tests/build/reports
+ gradle-plugin/build/reports
+ common-util/build/reports
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
new file mode 100644
index 00000000..bb0e438c
--- /dev/null
+++ b/.github/workflows/nightly.yml
@@ -0,0 +1,71 @@
+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.9-release, 1.0.10-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
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 00000000..39120246
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,81 @@
+# Workflow to build release artifacts
+
+name: release artifacts
+
+on:
+ release:
+ types: [ created ]
+
+jobs:
+ build-and-test:
+
+ # The type of runner that the job will run on
+ runs-on: ubuntu-latest
+
+ steps:
+ - 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
+
+ # Checkout
+ - uses: actions/checkout@v2
+
+ # 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-${{ runner.os }}
+ path: |
+ compiler-plugin/build/reports
+ integration-tests/build/reports
+ gradle-plugin/build/reports
+ common-util/build/reports
+
+ # Build KSP artifacts
+ - name: build
+ run: |
+ REF=${{ github.ref }} # refs/tags/$KSP_VERSION
+ ./gradlew --info -PkspVersion=${REF:10} -PoutRepo=$(pwd)/build/repos/release publishAllPublicationsToMavenRepository
+ - name: pack
+ run: cd build/repos/release/ && zip -r ../../artifacts.zip .
+ - name: Upload Release Asset
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ github.event.release.upload_url }}
+ asset_path: ./build/artifacts.zip
+ asset_name: artifacts.zip
+ asset_content_type: application/zip
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..1e46ad6a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+.idea
+/local
+/tmp
+workspace.xml
+.gradle/
+build/
+!**/src/**/build
+!**/test/**/build
+*.iml
+!**/testData/**/*.iml
+local.properties
+compiler-plugin/dist
+kotlin-analysis-api/dist
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..a306c5ec
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,69 @@
+# How to Contribute
+
+We'd love to accept your patches and contributions to this project. There are
+just a few small guidelines you need to follow.
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement (CLA). You (or your employer) retain the copyright to your
+contribution; this simply gives us permission to use and redistribute your
+contributions as part of the project. Head over to
+<https://cla.developers.google.com/> to see your current agreements on file or
+to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## Code reviews
+
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose. Consult
+[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
+information on using pull requests.
+
+## Community Guidelines
+
+This project follows
+[Google's Open Source Community Guidelines](https://opensource.google/conduct/).
+
+## API verification
+
+For changes that involves API changes(new API, API signature change), please also update [api.base](./api/api.base) file. You can monitor api change with `./gradlew :api:apiCheck`, and`./gradlew :api:updateApi` to generate new api signature.
+
+## Testing
+For incoming PRs, we would like to request changes covered by tests for good practice.
+We do end-to-end test for KSP, which means you need to write a lightweight processor to be loaded with KSP for testing.
+The form of the test itself is flexible as long as the logic is being covered.
+
+Here are some [sample test processors](compiler-plugin/src/test/kotlin/com/google/devtools/ksp/processor) for your reference.
+
+#### Steps for writing a test
+* KSP needs to be built with JDK 11+, because of some test dependencies.
+* Create a test processor under the sample processor folder.
+it should be extending [AbstractTestProcessor](compiler-plugin/src/test/kotlin/com/google/devtools/ksp/processor/AbstractTestProcessor.kt)
+* Write your logic by overriding corresponding functions.
+ * Test is performed by running test processor and get a collection of test results in the form of List<String>.
+ * Make sure you override toResult() function to collect test result.
+ * Leverage visitors for easy traverse of the test case.
+ * To help with easy testing, you can create an annotation for test, and annotate the specific part of the code to avoid doing
+ excess filtering when traveling along the program.
+* Write your test case to work with test processor.
+ * Create a test kt file under [testData](compiler-plugin/testData/api) folder.
+ Every kt file under this folder corresponds to a test case.
+ * Inside the test file:
+ * [optional] Add ```// WITH_RUNTIME``` to the top if you need access to standard library.
+ * Add ```// TEST PROCESSOR:<Your test processor name>``` to provide the test processor for this test case. Processors can
+ be reused if necessary.
+ * Immediately after test processor line, start your expected result lines. Every line should start with
+ ```// ```(with a space after //)
+ * Add ```// END``` to indicate end of expected test result.
+ * Then follows virtual files section till the end of test file.
+ * You can use ```// FILE: <file name>``` to create files that will be available at run time of the test.
+ * E.g. ```// FILE: a.kt``` will result in a file named ```a.kt``` at run time.
+* Add new test to [test suite](compiler-plugin/src/test/java/com/google/devtools/ksp/test/KotlinKSPTestGenerated.java)
+* Run generated tests with ```:compiler-plugin:test``` gradle task.
+ * This will execute all tests in KSP test suite. To run your test only, specify the test name with
+ ```--tests "com.google.devtools.ksp.test.KotlinKSPTestGenerated.<name of your generated test>"```
+ * Make sure your change is not breaking any existing test as well :).
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..9c308d95
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2000-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.
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..5022c274
--- /dev/null
+++ b/README.md
@@ -0,0 +1,40 @@
+# Kotlin Symbol Processing API
+
+Welcome to KSP!
+
+Kotlin Symbol Processing (KSP) is an API that you can use to develop
+lightweight compiler plugins. KSP provides a simplified compiler plugin
+API that leverages the power of Kotlin while keeping the learning curve at
+a minimum. Compared to KAPT, annotation processors that use KSP can run up to 2x faster.
+
+Most of the documentation of KSP can be found on [kotlinlang.org](https://kotlinlang.org/docs/ksp-overview.html). Here are some handy links:
+
+* [Overview](https://kotlinlang.org/docs/ksp-overview.html)
+* [Quickstart](https://kotlinlang.org/docs/ksp-quickstart.html)
+* [Libraries that support KSP](https://kotlinlang.org/docs/ksp-overview.html#supported-libraries)
+* [Why KSP?](https://kotlinlang.org/docs/ksp-why-ksp.html)
+* [Examples](https://kotlinlang.org/docs/ksp-examples.html)
+* [How KSP models Kotlin code](https://kotlinlang.org/docs/ksp-additional-details.html)
+* [Reference for Java annotation processor authors](https://kotlinlang.org/docs/ksp-reference.html)
+* [Incremental processing notes](https://kotlinlang.org/docs/ksp-incremental.html)
+* [Multiple round processing notes](https://kotlinlang.org/docs/ksp-multi-round.html)
+* [KSP on multiplatform projects](https://kotlinlang.org/docs/ksp-multiplatform.html)
+* [Running KSP from command line](https://kotlinlang.org/docs/ksp-command-line.html)
+* [FAQ](https://kotlinlang.org/docs/ksp-faq.html)
+
+## Feedback and Bug Reporting
+
+[Please let us know what you think about KSP by filing a Github issue](https://github.com/google/ksp/issues)
+or connecting with our team in the `#ksp` channel in the
+[Kotlin Slack workspace](https://kotlinlang.slack.com/)!
+
+If you are interested in sending PRs, please also check out the [Contributor guide](CONTRIBUTING.md).
+
+## 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 a bunch of optimizations to be done!
+* Make the IDE aware of the generated code
+* Keep fixing bugs! \ No newline at end of file
diff --git a/api/api.base b/api/api.base
new file mode 100644
index 00000000..9884b771
--- /dev/null
+++ b/api/api.base
@@ -0,0 +1,728 @@
+// Signature format: 2.0
+package com.google.devtools.ksp {
+
+ @com.google.devtools.ksp.KspExperimental public final class KSTypeNotPresentException extends java.lang.RuntimeException {
+ ctor public KSTypeNotPresentException(@NonNull com.google.devtools.ksp.symbol.KSType ksType, @NonNull Throwable cause);
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getKsType();
+ property @NonNull public final com.google.devtools.ksp.symbol.KSType ksType;
+ }
+
+ @com.google.devtools.ksp.KspExperimental public final class KSTypesNotPresentException extends java.lang.RuntimeException {
+ ctor public KSTypesNotPresentException(@NonNull java.util.List<? extends com.google.devtools.ksp.symbol.KSType> ksTypes, @NonNull Throwable cause);
+ method @NonNull public java.util.List<com.google.devtools.ksp.symbol.KSType> getKsTypes();
+ property @NonNull public final java.util.List<com.google.devtools.ksp.symbol.KSType> ksTypes;
+ }
+
+ @kotlin.RequiresOptIn(message="This API is experimental." + "It may be changed in the future without notice or might be removed.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention) public @interface KspExperimental {
+ }
+
+ public final class UtilsKt {
+ method @Nullable public static com.google.devtools.ksp.symbol.KSClassDeclaration closestClassDeclaration(@NonNull com.google.devtools.ksp.symbol.KSDeclaration);
+ method @NonNull public static com.google.devtools.ksp.symbol.KSClassDeclaration findActualType(@NonNull com.google.devtools.ksp.symbol.KSTypeAlias);
+ method @NonNull public static kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSType> getAllSuperTypes(@NonNull com.google.devtools.ksp.symbol.KSClassDeclaration);
+ method @NonNull @com.google.devtools.ksp.KspExperimental public static <T extends java.lang.annotation.Annotation> kotlin.sequences.Sequence<T> getAnnotationsByType(@NonNull com.google.devtools.ksp.symbol.KSAnnotated, @NonNull kotlin.reflect.KClass<T> annotationKClass);
+ method @Nullable public static com.google.devtools.ksp.symbol.KSClassDeclaration getClassDeclarationByName(@NonNull com.google.devtools.ksp.processing.Resolver, @NonNull String name);
+ method public static inline <reified T> com.google.devtools.ksp.symbol.KSClassDeclaration getClassDeclarationByName(@NonNull com.google.devtools.ksp.processing.Resolver);
+ method @NonNull public static kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSFunctionDeclaration> getConstructors(@NonNull com.google.devtools.ksp.symbol.KSClassDeclaration);
+ method @Nullable public static com.google.devtools.ksp.symbol.KSFile getContainingFile(@NonNull com.google.devtools.ksp.symbol.KSNode);
+ method @NonNull public static kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSFunctionDeclaration> getDeclaredFunctions(@NonNull com.google.devtools.ksp.symbol.KSClassDeclaration);
+ method @NonNull public static kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSPropertyDeclaration> getDeclaredProperties(@NonNull com.google.devtools.ksp.symbol.KSClassDeclaration);
+ method @NonNull public static kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSFunctionDeclaration> getFunctionDeclarationsByName(@NonNull com.google.devtools.ksp.processing.Resolver, @NonNull String name, boolean includeTopLevel = false);
+ method @NonNull public static java.util.List<com.google.devtools.ksp.symbol.KSTypeArgument> getInnerArguments(@NonNull com.google.devtools.ksp.symbol.KSType);
+ method @Nullable @com.google.devtools.ksp.KspExperimental public static com.google.devtools.ksp.symbol.KSClassDeclaration getJavaClassByName(@NonNull com.google.devtools.ksp.processing.Resolver, @NonNull com.google.devtools.ksp.symbol.KSName name);
+ method @Nullable @com.google.devtools.ksp.KspExperimental public static com.google.devtools.ksp.symbol.KSClassDeclaration getJavaClassByName(@NonNull com.google.devtools.ksp.processing.Resolver, @NonNull String name);
+ method @Nullable @com.google.devtools.ksp.KspExperimental public static com.google.devtools.ksp.symbol.KSClassDeclaration getKotlinClassByName(@NonNull com.google.devtools.ksp.processing.Resolver, @NonNull com.google.devtools.ksp.symbol.KSName name);
+ method @Nullable @com.google.devtools.ksp.KspExperimental public static com.google.devtools.ksp.symbol.KSClassDeclaration getKotlinClassByName(@NonNull com.google.devtools.ksp.processing.Resolver, @NonNull String name);
+ method @Nullable public static com.google.devtools.ksp.symbol.KSType getOuterType(@NonNull com.google.devtools.ksp.symbol.KSType);
+ method @Nullable public static com.google.devtools.ksp.symbol.KSPropertyDeclaration getPropertyDeclarationByName(@NonNull com.google.devtools.ksp.processing.Resolver, @NonNull String name, boolean includeTopLevel = false);
+ method @NonNull public static com.google.devtools.ksp.symbol.Visibility getVisibility(@NonNull com.google.devtools.ksp.symbol.KSDeclaration);
+ method public static boolean isAbstract(@NonNull com.google.devtools.ksp.symbol.KSClassDeclaration);
+ method public static boolean isAbstract(@NonNull com.google.devtools.ksp.symbol.KSPropertyDeclaration);
+ method @com.google.devtools.ksp.KspExperimental public static <T extends java.lang.annotation.Annotation> boolean isAnnotationPresent(@NonNull com.google.devtools.ksp.symbol.KSAnnotated, @NonNull kotlin.reflect.KClass<T> annotationKClass);
+ method public static boolean isConstructor(@NonNull com.google.devtools.ksp.symbol.KSFunctionDeclaration);
+ method public static boolean isDefault(@NonNull com.google.devtools.ksp.symbol.KSValueArgument);
+ method public static boolean isInternal(@NonNull com.google.devtools.ksp.symbol.KSDeclaration);
+ method public static boolean isJavaPackagePrivate(@NonNull com.google.devtools.ksp.symbol.KSDeclaration);
+ method public static boolean isLocal(@NonNull com.google.devtools.ksp.symbol.KSDeclaration);
+ method public static boolean isOpen(@NonNull com.google.devtools.ksp.symbol.KSDeclaration);
+ method public static boolean isPrivate(@NonNull com.google.devtools.ksp.symbol.KSDeclaration);
+ method public static boolean isProtected(@NonNull com.google.devtools.ksp.symbol.KSDeclaration);
+ method public static boolean isPublic(@NonNull com.google.devtools.ksp.symbol.KSDeclaration);
+ method public static boolean isVisibleFrom(@NonNull com.google.devtools.ksp.symbol.KSDeclaration, @NonNull com.google.devtools.ksp.symbol.KSDeclaration other);
+ method public static boolean validate(@NonNull com.google.devtools.ksp.symbol.KSNode, @NonNull kotlin.jvm.functions.Function2<? super com.google.devtools.ksp.symbol.KSNode,? super com.google.devtools.ksp.symbol.KSNode,java.lang.Boolean> predicate = { _, _ -> return true });
+ field @NonNull public static final String ExceptionMessage = "please file a bug at https://github.com/google/ksp/issues/new";
+ }
+
+}
+
+package com.google.devtools.ksp.processing {
+
+ public interface CodeGenerator {
+ method public void associate(@NonNull java.util.List<? extends com.google.devtools.ksp.symbol.KSFile> sources, @NonNull String packageName, @NonNull String fileName, @NonNull String extensionName = "kt");
+ method public void associateByPath(@NonNull java.util.List<? extends com.google.devtools.ksp.symbol.KSFile> sources, @NonNull String path, @NonNull String extensionName = "kt");
+ method public void associateWithClasses(@NonNull java.util.List<? extends com.google.devtools.ksp.symbol.KSClassDeclaration> classes, @NonNull String packageName, @NonNull String fileName, @NonNull String extensionName = "kt");
+ method @NonNull public java.io.OutputStream createNewFile(@NonNull com.google.devtools.ksp.processing.Dependencies dependencies, @NonNull String packageName, @NonNull String fileName, @NonNull String extensionName = "kt");
+ method @NonNull public java.io.OutputStream createNewFileByPath(@NonNull com.google.devtools.ksp.processing.Dependencies dependencies, @NonNull String path, @NonNull String extensionName = "kt");
+ method @NonNull public java.util.Collection<java.io.File> getGeneratedFile();
+ property @NonNull public abstract java.util.Collection<java.io.File> generatedFile;
+ }
+
+ public final class Dependencies {
+ ctor public Dependencies(boolean aggregating, @NonNull com.google.devtools.ksp.symbol.KSFile... sources);
+ method public boolean getAggregating();
+ method @NonNull public java.util.List<com.google.devtools.ksp.symbol.KSFile> getOriginatingFiles();
+ method public boolean isAllSources();
+ property public final boolean aggregating;
+ property public final boolean isAllSources;
+ property @NonNull public final java.util.List<com.google.devtools.ksp.symbol.KSFile> originatingFiles;
+ field @NonNull public static final com.google.devtools.ksp.processing.Dependencies.Companion Companion;
+ }
+
+ public static final class Dependencies.Companion {
+ method @NonNull public com.google.devtools.ksp.processing.Dependencies getALL_FILES();
+ property @NonNull public final com.google.devtools.ksp.processing.Dependencies ALL_FILES;
+ }
+
+ public interface JsPlatformInfo extends com.google.devtools.ksp.processing.PlatformInfo {
+ }
+
+ public interface JvmPlatformInfo extends com.google.devtools.ksp.processing.PlatformInfo {
+ method @NonNull public String getJvmTarget();
+ property @NonNull public abstract String jvmTarget;
+ }
+
+ public interface KSBuiltIns {
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getAnnotationType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getAnyType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getArrayType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getBooleanType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getByteType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getCharType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getDoubleType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getFloatType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getIntType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getIterableType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getLongType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getNothingType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getNumberType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getShortType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getStringType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType getUnitType();
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType annotationType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType anyType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType arrayType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType booleanType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType byteType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType charType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType doubleType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType floatType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType intType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType iterableType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType longType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType nothingType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType numberType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType shortType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType stringType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSType unitType;
+ }
+
+ public interface KSPLogger {
+ method public void error(@NonNull String message, @Nullable com.google.devtools.ksp.symbol.KSNode symbol = null);
+ method public void exception(@NonNull Throwable e);
+ method public void info(@NonNull String message, @Nullable com.google.devtools.ksp.symbol.KSNode symbol = null);
+ method public void logging(@NonNull String message, @Nullable com.google.devtools.ksp.symbol.KSNode symbol = null);
+ method public void warn(@NonNull String message, @Nullable com.google.devtools.ksp.symbol.KSNode symbol = null);
+ }
+
+ public interface NativePlatformInfo extends com.google.devtools.ksp.processing.PlatformInfo {
+ method @NonNull public String getTargetName();
+ property @NonNull public abstract String targetName;
+ }
+
+ public interface PlatformInfo {
+ method @NonNull public String getPlatformName();
+ property @NonNull public abstract String platformName;
+ }
+
+ public interface Resolver {
+ method @NonNull public com.google.devtools.ksp.symbol.KSTypeReference createKSTypeReferenceFromKSType(@NonNull com.google.devtools.ksp.symbol.KSType type);
+ method @NonNull @com.google.devtools.ksp.KspExperimental public java.util.Set<com.google.devtools.ksp.symbol.Modifier> effectiveJavaModifiers(@NonNull com.google.devtools.ksp.symbol.KSDeclaration declaration);
+ method @NonNull public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSFile> getAllFiles();
+ method @NonNull public com.google.devtools.ksp.processing.KSBuiltIns getBuiltIns();
+ method @Nullable public com.google.devtools.ksp.symbol.KSClassDeclaration getClassDeclarationByName(@NonNull com.google.devtools.ksp.symbol.KSName name);
+ method @NonNull @com.google.devtools.ksp.KspExperimental public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSDeclaration> getDeclarationsFromPackage(@NonNull String packageName);
+ method @NonNull @com.google.devtools.ksp.KspExperimental public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSDeclaration> getDeclarationsInSourceOrder(@NonNull com.google.devtools.ksp.symbol.KSDeclarationContainer container);
+ method @NonNull public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSFunctionDeclaration> getFunctionDeclarationsByName(@NonNull com.google.devtools.ksp.symbol.KSName name, boolean includeTopLevel = false);
+ method @NonNull @com.google.devtools.ksp.KspExperimental public com.google.devtools.ksp.symbol.KSTypeReference getJavaWildcard(@NonNull com.google.devtools.ksp.symbol.KSTypeReference reference);
+ method @NonNull @com.google.devtools.ksp.KspExperimental public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSType> getJvmCheckedException(@NonNull com.google.devtools.ksp.symbol.KSFunctionDeclaration function);
+ method @NonNull @com.google.devtools.ksp.KspExperimental public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSType> getJvmCheckedException(@NonNull com.google.devtools.ksp.symbol.KSPropertyAccessor accessor);
+ 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 public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSFile> getNewFiles();
+ method @Nullable @com.google.devtools.ksp.KspExperimental public String getOwnerJvmClassName(@NonNull com.google.devtools.ksp.symbol.KSPropertyDeclaration declaration);
+ method @Nullable @com.google.devtools.ksp.KspExperimental public String getOwnerJvmClassName(@NonNull com.google.devtools.ksp.symbol.KSFunctionDeclaration declaration);
+ method @Nullable public com.google.devtools.ksp.symbol.KSPropertyDeclaration getPropertyDeclarationByName(@NonNull com.google.devtools.ksp.symbol.KSName name, boolean includeTopLevel = false);
+ method @NonNull public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSAnnotated> getSymbolsWithAnnotation(@NonNull String annotationName, boolean inDepth = false);
+ method @NonNull public com.google.devtools.ksp.symbol.KSTypeArgument getTypeArgument(@NonNull com.google.devtools.ksp.symbol.KSTypeReference typeRef, @NonNull com.google.devtools.ksp.symbol.Variance variance);
+ method @com.google.devtools.ksp.KspExperimental public boolean isJavaRawType(@NonNull com.google.devtools.ksp.symbol.KSType type);
+ method @Nullable @com.google.devtools.ksp.KspExperimental public com.google.devtools.ksp.symbol.KSName mapJavaNameToKotlin(@NonNull com.google.devtools.ksp.symbol.KSName javaName);
+ method @Nullable @com.google.devtools.ksp.KspExperimental public com.google.devtools.ksp.symbol.KSName mapKotlinNameToJava(@NonNull com.google.devtools.ksp.symbol.KSName kotlinName);
+ method @Nullable @com.google.devtools.ksp.KspExperimental public String mapToJvmSignature(@NonNull com.google.devtools.ksp.symbol.KSDeclaration declaration);
+ method public boolean overrides(@NonNull com.google.devtools.ksp.symbol.KSDeclaration overrider, @NonNull com.google.devtools.ksp.symbol.KSDeclaration overridee);
+ method public boolean overrides(@NonNull com.google.devtools.ksp.symbol.KSDeclaration overrider, @NonNull com.google.devtools.ksp.symbol.KSDeclaration overridee, @NonNull com.google.devtools.ksp.symbol.KSClassDeclaration containingClass);
+ property @NonNull public abstract com.google.devtools.ksp.processing.KSBuiltIns builtIns;
+ }
+
+ public interface SymbolProcessor {
+ method public default void finish();
+ method public default void onError();
+ method @NonNull public java.util.List<com.google.devtools.ksp.symbol.KSAnnotated> process(@NonNull com.google.devtools.ksp.processing.Resolver resolver);
+ }
+
+ public final class SymbolProcessorEnvironment {
+ ctor public SymbolProcessorEnvironment(@NonNull java.util.Map<java.lang.String,java.lang.String> options, @NonNull kotlin.KotlinVersion kotlinVersion, @NonNull com.google.devtools.ksp.processing.CodeGenerator codeGenerator, @NonNull com.google.devtools.ksp.processing.KSPLogger logger, @NonNull kotlin.KotlinVersion apiVersion, @NonNull kotlin.KotlinVersion compilerVersion, @NonNull java.util.List<? extends com.google.devtools.ksp.processing.PlatformInfo> platforms);
+ ctor public SymbolProcessorEnvironment(@NonNull java.util.Map<java.lang.String,java.lang.String> options, @NonNull kotlin.KotlinVersion kotlinVersion, @NonNull com.google.devtools.ksp.processing.CodeGenerator codeGenerator, @NonNull com.google.devtools.ksp.processing.KSPLogger logger);
+ method @NonNull public kotlin.KotlinVersion getApiVersion();
+ method @NonNull public com.google.devtools.ksp.processing.CodeGenerator getCodeGenerator();
+ method @NonNull public kotlin.KotlinVersion getCompilerVersion();
+ method @NonNull public kotlin.KotlinVersion getKotlinVersion();
+ method @NonNull public com.google.devtools.ksp.processing.KSPLogger getLogger();
+ method @NonNull public java.util.Map<java.lang.String,java.lang.String> getOptions();
+ method @NonNull public java.util.List<com.google.devtools.ksp.processing.PlatformInfo> getPlatforms();
+ property @NonNull public final kotlin.KotlinVersion apiVersion;
+ property @NonNull public final com.google.devtools.ksp.processing.CodeGenerator codeGenerator;
+ property @NonNull public final kotlin.KotlinVersion compilerVersion;
+ property @NonNull public final kotlin.KotlinVersion kotlinVersion;
+ property @NonNull public final com.google.devtools.ksp.processing.KSPLogger logger;
+ property @NonNull public final java.util.Map<java.lang.String,java.lang.String> options;
+ property @NonNull public final java.util.List<com.google.devtools.ksp.processing.PlatformInfo> platforms;
+ }
+
+ public fun interface SymbolProcessorProvider {
+ method @NonNull public com.google.devtools.ksp.processing.SymbolProcessor create(@NonNull com.google.devtools.ksp.processing.SymbolProcessorEnvironment environment);
+ }
+
+ public interface UnknownPlatformInfo extends com.google.devtools.ksp.processing.PlatformInfo {
+ }
+
+}
+
+package com.google.devtools.ksp.symbol {
+
+ public enum AnnotationUseSiteTarget {
+ enum_constant public static final com.google.devtools.ksp.symbol.AnnotationUseSiteTarget DELEGATE;
+ enum_constant public static final com.google.devtools.ksp.symbol.AnnotationUseSiteTarget FIELD;
+ enum_constant public static final com.google.devtools.ksp.symbol.AnnotationUseSiteTarget FILE;
+ enum_constant public static final com.google.devtools.ksp.symbol.AnnotationUseSiteTarget GET;
+ enum_constant public static final com.google.devtools.ksp.symbol.AnnotationUseSiteTarget PARAM;
+ enum_constant public static final com.google.devtools.ksp.symbol.AnnotationUseSiteTarget PROPERTY;
+ enum_constant public static final com.google.devtools.ksp.symbol.AnnotationUseSiteTarget RECEIVER;
+ enum_constant public static final com.google.devtools.ksp.symbol.AnnotationUseSiteTarget SET;
+ enum_constant public static final com.google.devtools.ksp.symbol.AnnotationUseSiteTarget SETPARAM;
+ }
+
+ public enum ClassKind {
+ method public final String getType();
+ property public final String type;
+ enum_constant public static final com.google.devtools.ksp.symbol.ClassKind ANNOTATION_CLASS;
+ enum_constant public static final com.google.devtools.ksp.symbol.ClassKind CLASS;
+ enum_constant public static final com.google.devtools.ksp.symbol.ClassKind ENUM_CLASS;
+ enum_constant public static final com.google.devtools.ksp.symbol.ClassKind ENUM_ENTRY;
+ enum_constant public static final com.google.devtools.ksp.symbol.ClassKind INTERFACE;
+ enum_constant public static final com.google.devtools.ksp.symbol.ClassKind OBJECT;
+ }
+
+ public final class FileLocation extends com.google.devtools.ksp.symbol.Location {
+ ctor public FileLocation(@NonNull String filePath, int lineNumber);
+ method @NonNull public String component1();
+ method public int component2();
+ method @NonNull public com.google.devtools.ksp.symbol.FileLocation copy(@NonNull String filePath, int lineNumber);
+ method @NonNull public String getFilePath();
+ method public int getLineNumber();
+ property @NonNull public final String filePath;
+ property public final int lineNumber;
+ }
+
+ public enum FunctionKind {
+ enum_constant public static final com.google.devtools.ksp.symbol.FunctionKind ANONYMOUS;
+ enum_constant public static final com.google.devtools.ksp.symbol.FunctionKind LAMBDA;
+ enum_constant public static final com.google.devtools.ksp.symbol.FunctionKind MEMBER;
+ enum_constant public static final com.google.devtools.ksp.symbol.FunctionKind STATIC;
+ enum_constant public static final com.google.devtools.ksp.symbol.FunctionKind TOP_LEVEL;
+ }
+
+ public interface KSAnnotated extends com.google.devtools.ksp.symbol.KSNode {
+ method @NonNull public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSAnnotation> getAnnotations();
+ property @NonNull public abstract kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSAnnotation> annotations;
+ }
+
+ public interface KSAnnotation extends com.google.devtools.ksp.symbol.KSNode {
+ method @NonNull public com.google.devtools.ksp.symbol.KSTypeReference getAnnotationType();
+ method @NonNull public java.util.List<com.google.devtools.ksp.symbol.KSValueArgument> getArguments();
+ method @NonNull public java.util.List<com.google.devtools.ksp.symbol.KSValueArgument> getDefaultArguments();
+ method @NonNull public com.google.devtools.ksp.symbol.KSName getShortName();
+ method @Nullable public com.google.devtools.ksp.symbol.AnnotationUseSiteTarget getUseSiteTarget();
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSTypeReference annotationType;
+ property @NonNull public abstract java.util.List<com.google.devtools.ksp.symbol.KSValueArgument> arguments;
+ property @NonNull public abstract java.util.List<com.google.devtools.ksp.symbol.KSValueArgument> defaultArguments;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSName shortName;
+ property @Nullable public abstract com.google.devtools.ksp.symbol.AnnotationUseSiteTarget useSiteTarget;
+ }
+
+ public interface KSCallableReference extends com.google.devtools.ksp.symbol.KSReferenceElement {
+ method public default <D, R> R accept(@NonNull com.google.devtools.ksp.symbol.KSVisitor<D,R> visitor, @Nullable D data);
+ method @NonNull public java.util.List<com.google.devtools.ksp.symbol.KSValueParameter> getFunctionParameters();
+ method @Nullable public com.google.devtools.ksp.symbol.KSTypeReference getReceiverType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSTypeReference getReturnType();
+ property @NonNull public abstract java.util.List<com.google.devtools.ksp.symbol.KSValueParameter> functionParameters;
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSTypeReference receiverType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSTypeReference returnType;
+ }
+
+ public interface KSClassDeclaration extends com.google.devtools.ksp.symbol.KSDeclaration com.google.devtools.ksp.symbol.KSDeclarationContainer {
+ method @NonNull public com.google.devtools.ksp.symbol.KSType asStarProjectedType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType asType(@NonNull java.util.List<? extends com.google.devtools.ksp.symbol.KSTypeArgument> typeArguments);
+ method @NonNull public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSFunctionDeclaration> getAllFunctions();
+ method @NonNull public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSPropertyDeclaration> getAllProperties();
+ method @NonNull public com.google.devtools.ksp.symbol.ClassKind getClassKind();
+ method @Nullable public com.google.devtools.ksp.symbol.KSFunctionDeclaration getPrimaryConstructor();
+ method @NonNull public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSClassDeclaration> getSealedSubclasses();
+ method @NonNull public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSTypeReference> getSuperTypes();
+ method public boolean isCompanionObject();
+ property @NonNull public abstract com.google.devtools.ksp.symbol.ClassKind classKind;
+ property public abstract boolean isCompanionObject;
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSFunctionDeclaration primaryConstructor;
+ property @NonNull public abstract kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSTypeReference> superTypes;
+ }
+
+ public interface KSClassifierReference extends com.google.devtools.ksp.symbol.KSReferenceElement {
+ method public default <D, R> R accept(@NonNull com.google.devtools.ksp.symbol.KSVisitor<D,R> visitor, @Nullable D data);
+ method @Nullable public com.google.devtools.ksp.symbol.KSClassifierReference getQualifier();
+ method @NonNull public String referencedName();
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSClassifierReference qualifier;
+ }
+
+ public interface KSDeclaration extends com.google.devtools.ksp.symbol.KSModifierListOwner com.google.devtools.ksp.symbol.KSAnnotated com.google.devtools.ksp.symbol.KSExpectActual {
+ method @Nullable public com.google.devtools.ksp.symbol.KSFile getContainingFile();
+ method @Nullable public String getDocString();
+ method @NonNull public com.google.devtools.ksp.symbol.KSName getPackageName();
+ method @Nullable public com.google.devtools.ksp.symbol.KSDeclaration getParentDeclaration();
+ method @Nullable public com.google.devtools.ksp.symbol.KSName getQualifiedName();
+ method @NonNull public com.google.devtools.ksp.symbol.KSName getSimpleName();
+ method @NonNull public java.util.List<com.google.devtools.ksp.symbol.KSTypeParameter> getTypeParameters();
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSFile containingFile;
+ property @Nullable public abstract String docString;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSName packageName;
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSDeclaration parentDeclaration;
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSName qualifiedName;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSName simpleName;
+ property @NonNull public abstract java.util.List<com.google.devtools.ksp.symbol.KSTypeParameter> typeParameters;
+ }
+
+ public interface KSDeclarationContainer extends com.google.devtools.ksp.symbol.KSNode {
+ method @NonNull public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSDeclaration> getDeclarations();
+ property @NonNull public abstract kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSDeclaration> declarations;
+ }
+
+ public interface KSDefNonNullReference extends com.google.devtools.ksp.symbol.KSReferenceElement {
+ method public default <D, R> R accept(@NonNull com.google.devtools.ksp.symbol.KSVisitor<D,R> visitor, @Nullable D data);
+ method @NonNull public com.google.devtools.ksp.symbol.KSClassifierReference getEnclosedType();
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSClassifierReference enclosedType;
+ }
+
+ public interface KSDynamicReference extends com.google.devtools.ksp.symbol.KSReferenceElement {
+ }
+
+ public interface KSExpectActual {
+ method @NonNull public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSDeclaration> findActuals();
+ method @NonNull public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSDeclaration> findExpects();
+ method public boolean isActual();
+ method public boolean isExpect();
+ property public abstract boolean isActual;
+ property public abstract boolean isExpect;
+ }
+
+ public interface KSFile extends com.google.devtools.ksp.symbol.KSDeclarationContainer com.google.devtools.ksp.symbol.KSAnnotated {
+ method @NonNull public String getFileName();
+ method @NonNull public String getFilePath();
+ method @NonNull public com.google.devtools.ksp.symbol.KSName getPackageName();
+ property @NonNull public abstract String fileName;
+ property @NonNull public abstract String filePath;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSName packageName;
+ }
+
+ public interface KSFunction {
+ method @Nullable public com.google.devtools.ksp.symbol.KSType getExtensionReceiverType();
+ method @NonNull public java.util.List<com.google.devtools.ksp.symbol.KSType> getParameterTypes();
+ method @Nullable public com.google.devtools.ksp.symbol.KSType getReturnType();
+ method @NonNull public java.util.List<com.google.devtools.ksp.symbol.KSTypeParameter> getTypeParameters();
+ method public boolean isError();
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSType extensionReceiverType;
+ property public abstract boolean isError;
+ property @NonNull public abstract java.util.List<com.google.devtools.ksp.symbol.KSType> parameterTypes;
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSType returnType;
+ property @NonNull public abstract java.util.List<com.google.devtools.ksp.symbol.KSTypeParameter> typeParameters;
+ }
+
+ public interface KSFunctionDeclaration extends com.google.devtools.ksp.symbol.KSDeclaration com.google.devtools.ksp.symbol.KSDeclarationContainer {
+ method @NonNull public com.google.devtools.ksp.symbol.KSFunction asMemberOf(@NonNull com.google.devtools.ksp.symbol.KSType containing);
+ method @Nullable public com.google.devtools.ksp.symbol.KSDeclaration findOverridee();
+ method @Nullable public com.google.devtools.ksp.symbol.KSTypeReference getExtensionReceiver();
+ method @NonNull public com.google.devtools.ksp.symbol.FunctionKind getFunctionKind();
+ method @NonNull public java.util.List<com.google.devtools.ksp.symbol.KSValueParameter> getParameters();
+ method @Nullable public com.google.devtools.ksp.symbol.KSTypeReference getReturnType();
+ method public boolean isAbstract();
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSTypeReference extensionReceiver;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.FunctionKind functionKind;
+ property public abstract boolean isAbstract;
+ property @NonNull public abstract java.util.List<com.google.devtools.ksp.symbol.KSValueParameter> parameters;
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSTypeReference returnType;
+ }
+
+ public interface KSModifierListOwner extends com.google.devtools.ksp.symbol.KSNode {
+ method @NonNull public java.util.Set<com.google.devtools.ksp.symbol.Modifier> getModifiers();
+ property @NonNull public abstract java.util.Set<com.google.devtools.ksp.symbol.Modifier> modifiers;
+ }
+
+ public interface KSName {
+ method @NonNull public String asString();
+ method @NonNull public String getQualifier();
+ method @NonNull public String getShortName();
+ }
+
+ public interface KSNode {
+ method public <D, R> R accept(@NonNull com.google.devtools.ksp.symbol.KSVisitor<D,R> visitor, @Nullable D data);
+ method @NonNull public com.google.devtools.ksp.symbol.Location getLocation();
+ method @NonNull public com.google.devtools.ksp.symbol.Origin getOrigin();
+ method @Nullable public com.google.devtools.ksp.symbol.KSNode getParent();
+ property @NonNull public abstract com.google.devtools.ksp.symbol.Location location;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.Origin origin;
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSNode parent;
+ }
+
+ public interface KSParenthesizedReference extends com.google.devtools.ksp.symbol.KSReferenceElement {
+ method @NonNull public com.google.devtools.ksp.symbol.KSReferenceElement getElement();
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSReferenceElement element;
+ }
+
+ public interface KSPropertyAccessor extends com.google.devtools.ksp.symbol.KSAnnotated com.google.devtools.ksp.symbol.KSModifierListOwner {
+ method @NonNull public com.google.devtools.ksp.symbol.KSPropertyDeclaration getReceiver();
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSPropertyDeclaration receiver;
+ }
+
+ public interface KSPropertyDeclaration extends com.google.devtools.ksp.symbol.KSDeclaration {
+ method @NonNull public com.google.devtools.ksp.symbol.KSType asMemberOf(@NonNull com.google.devtools.ksp.symbol.KSType containing);
+ method @Nullable public com.google.devtools.ksp.symbol.KSPropertyDeclaration findOverridee();
+ method @Nullable public com.google.devtools.ksp.symbol.KSTypeReference getExtensionReceiver();
+ method @Nullable public com.google.devtools.ksp.symbol.KSPropertyGetter getGetter();
+ method public boolean getHasBackingField();
+ method @Nullable public com.google.devtools.ksp.symbol.KSPropertySetter getSetter();
+ method @NonNull public com.google.devtools.ksp.symbol.KSTypeReference getType();
+ method public boolean isDelegated();
+ method public boolean isMutable();
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSTypeReference extensionReceiver;
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSPropertyGetter getter;
+ property public abstract boolean hasBackingField;
+ property public abstract boolean isMutable;
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSPropertySetter setter;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSTypeReference type;
+ }
+
+ public interface KSPropertyGetter extends com.google.devtools.ksp.symbol.KSPropertyAccessor {
+ method @Nullable public com.google.devtools.ksp.symbol.KSTypeReference getReturnType();
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSTypeReference returnType;
+ }
+
+ public interface KSPropertySetter extends com.google.devtools.ksp.symbol.KSPropertyAccessor {
+ method @NonNull public com.google.devtools.ksp.symbol.KSValueParameter getParameter();
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSValueParameter parameter;
+ }
+
+ public interface KSReferenceElement extends com.google.devtools.ksp.symbol.KSNode {
+ method @NonNull public java.util.List<com.google.devtools.ksp.symbol.KSTypeArgument> getTypeArguments();
+ property @NonNull public abstract java.util.List<com.google.devtools.ksp.symbol.KSTypeArgument> typeArguments;
+ }
+
+ public interface KSType {
+ method @NonNull public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSAnnotation> getAnnotations();
+ method @NonNull public java.util.List<com.google.devtools.ksp.symbol.KSTypeArgument> getArguments();
+ method @NonNull public com.google.devtools.ksp.symbol.KSDeclaration getDeclaration();
+ method @NonNull public com.google.devtools.ksp.symbol.Nullability getNullability();
+ method public boolean isAssignableFrom(@NonNull com.google.devtools.ksp.symbol.KSType that);
+ method public boolean isCovarianceFlexible();
+ method public boolean isError();
+ method public boolean isFunctionType();
+ method public boolean isMarkedNullable();
+ method public boolean isMutabilityFlexible();
+ method public boolean isSuspendFunctionType();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType makeNotNullable();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType makeNullable();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType replace(@NonNull java.util.List<? extends com.google.devtools.ksp.symbol.KSTypeArgument> arguments);
+ method @NonNull public com.google.devtools.ksp.symbol.KSType starProjection();
+ property @NonNull public abstract kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSAnnotation> annotations;
+ property @NonNull public abstract java.util.List<com.google.devtools.ksp.symbol.KSTypeArgument> arguments;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSDeclaration declaration;
+ property public abstract boolean isError;
+ property public abstract boolean isFunctionType;
+ property public abstract boolean isMarkedNullable;
+ property public abstract boolean isSuspendFunctionType;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.Nullability nullability;
+ }
+
+ public interface KSTypeAlias extends com.google.devtools.ksp.symbol.KSDeclaration {
+ method @NonNull public com.google.devtools.ksp.symbol.KSName getName();
+ method @NonNull public com.google.devtools.ksp.symbol.KSTypeReference getType();
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSName name;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSTypeReference type;
+ }
+
+ public interface KSTypeArgument extends com.google.devtools.ksp.symbol.KSAnnotated {
+ method @Nullable public com.google.devtools.ksp.symbol.KSTypeReference getType();
+ method @NonNull public com.google.devtools.ksp.symbol.Variance getVariance();
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSTypeReference type;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.Variance variance;
+ }
+
+ public interface KSTypeParameter extends com.google.devtools.ksp.symbol.KSDeclaration {
+ method @NonNull public kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSTypeReference> getBounds();
+ method @NonNull public com.google.devtools.ksp.symbol.KSName getName();
+ method @NonNull public com.google.devtools.ksp.symbol.Variance getVariance();
+ method public boolean isReified();
+ property @NonNull public abstract kotlin.sequences.Sequence<com.google.devtools.ksp.symbol.KSTypeReference> bounds;
+ property public abstract boolean isReified;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSName name;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.Variance variance;
+ }
+
+ public interface KSTypeReference extends com.google.devtools.ksp.symbol.KSAnnotated com.google.devtools.ksp.symbol.KSModifierListOwner {
+ method @Nullable public com.google.devtools.ksp.symbol.KSReferenceElement getElement();
+ method @NonNull public com.google.devtools.ksp.symbol.KSType resolve();
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSReferenceElement element;
+ }
+
+ public interface KSValueArgument extends com.google.devtools.ksp.symbol.KSAnnotated {
+ method @Nullable public com.google.devtools.ksp.symbol.KSName getName();
+ method @Nullable public Object getValue();
+ method public boolean isSpread();
+ property public abstract boolean isSpread;
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSName name;
+ property @Nullable public abstract Object value;
+ }
+
+ public interface KSValueParameter extends com.google.devtools.ksp.symbol.KSAnnotated {
+ method public boolean getHasDefault();
+ method @Nullable public com.google.devtools.ksp.symbol.KSName getName();
+ method @NonNull public com.google.devtools.ksp.symbol.KSTypeReference getType();
+ method public boolean isCrossInline();
+ method public boolean isNoInline();
+ method public boolean isVal();
+ method public boolean isVar();
+ method public boolean isVararg();
+ property public abstract boolean hasDefault;
+ property public abstract boolean isCrossInline;
+ property public abstract boolean isNoInline;
+ property public abstract boolean isVal;
+ property public abstract boolean isVar;
+ property public abstract boolean isVararg;
+ property @Nullable public abstract com.google.devtools.ksp.symbol.KSName name;
+ property @NonNull public abstract com.google.devtools.ksp.symbol.KSTypeReference type;
+ }
+
+ public interface KSVisitor<D, R> {
+ method public R visitAnnotated(@NonNull com.google.devtools.ksp.symbol.KSAnnotated annotated, @Nullable D data);
+ method public R visitAnnotation(@NonNull com.google.devtools.ksp.symbol.KSAnnotation annotation, @Nullable D data);
+ method public R visitCallableReference(@NonNull com.google.devtools.ksp.symbol.KSCallableReference reference, @Nullable D data);
+ method public R visitClassDeclaration(@NonNull com.google.devtools.ksp.symbol.KSClassDeclaration classDeclaration, @Nullable D data);
+ method public R visitClassifierReference(@NonNull com.google.devtools.ksp.symbol.KSClassifierReference reference, @Nullable D data);
+ method public R visitDeclaration(@NonNull com.google.devtools.ksp.symbol.KSDeclaration declaration, @Nullable D data);
+ method public R visitDeclarationContainer(@NonNull com.google.devtools.ksp.symbol.KSDeclarationContainer declarationContainer, @Nullable D data);
+ method public R visitDefNonNullReference(@NonNull com.google.devtools.ksp.symbol.KSDefNonNullReference reference, @Nullable D data);
+ method public R visitDynamicReference(@NonNull com.google.devtools.ksp.symbol.KSDynamicReference reference, @Nullable D data);
+ method public R visitFile(@NonNull com.google.devtools.ksp.symbol.KSFile file, @Nullable D data);
+ method public R visitFunctionDeclaration(@NonNull com.google.devtools.ksp.symbol.KSFunctionDeclaration function, @Nullable D data);
+ method public R visitModifierListOwner(@NonNull com.google.devtools.ksp.symbol.KSModifierListOwner modifierListOwner, @Nullable D data);
+ method public R visitNode(@NonNull com.google.devtools.ksp.symbol.KSNode node, @Nullable D data);
+ method public R visitParenthesizedReference(@NonNull com.google.devtools.ksp.symbol.KSParenthesizedReference reference, @Nullable D data);
+ method public R visitPropertyAccessor(@NonNull com.google.devtools.ksp.symbol.KSPropertyAccessor accessor, @Nullable D data);
+ method public R visitPropertyDeclaration(@NonNull com.google.devtools.ksp.symbol.KSPropertyDeclaration property, @Nullable D data);
+ method public R visitPropertyGetter(@NonNull com.google.devtools.ksp.symbol.KSPropertyGetter getter, @Nullable D data);
+ method public R visitPropertySetter(@NonNull com.google.devtools.ksp.symbol.KSPropertySetter setter, @Nullable D data);
+ method public R visitReferenceElement(@NonNull com.google.devtools.ksp.symbol.KSReferenceElement element, @Nullable D data);
+ method public R visitTypeAlias(@NonNull com.google.devtools.ksp.symbol.KSTypeAlias typeAlias, @Nullable D data);
+ method public R visitTypeArgument(@NonNull com.google.devtools.ksp.symbol.KSTypeArgument typeArgument, @Nullable D data);
+ method public R visitTypeParameter(@NonNull com.google.devtools.ksp.symbol.KSTypeParameter typeParameter, @Nullable D data);
+ method public R visitTypeReference(@NonNull com.google.devtools.ksp.symbol.KSTypeReference typeReference, @Nullable D data);
+ method public R visitValueArgument(@NonNull com.google.devtools.ksp.symbol.KSValueArgument valueArgument, @Nullable D data);
+ method public R visitValueParameter(@NonNull com.google.devtools.ksp.symbol.KSValueParameter valueParameter, @Nullable D data);
+ }
+
+ public class KSVisitorVoid implements com.google.devtools.ksp.symbol.KSVisitor<kotlin.Unit,kotlin.Unit> {
+ ctor public KSVisitorVoid();
+ method public void visitAnnotated(@NonNull com.google.devtools.ksp.symbol.KSAnnotated annotated, @NonNull kotlin.Unit data);
+ method public void visitAnnotation(@NonNull com.google.devtools.ksp.symbol.KSAnnotation annotation, @NonNull kotlin.Unit data);
+ method public void visitCallableReference(@NonNull com.google.devtools.ksp.symbol.KSCallableReference reference, @NonNull kotlin.Unit data);
+ method public void visitClassDeclaration(@NonNull com.google.devtools.ksp.symbol.KSClassDeclaration classDeclaration, @NonNull kotlin.Unit data);
+ method public void visitClassifierReference(@NonNull com.google.devtools.ksp.symbol.KSClassifierReference reference, @NonNull kotlin.Unit data);
+ method public void visitDeclaration(@NonNull com.google.devtools.ksp.symbol.KSDeclaration declaration, @NonNull kotlin.Unit data);
+ method public void visitDeclarationContainer(@NonNull com.google.devtools.ksp.symbol.KSDeclarationContainer declarationContainer, @NonNull kotlin.Unit data);
+ method public void visitDefNonNullReference(@NonNull com.google.devtools.ksp.symbol.KSDefNonNullReference reference, @NonNull kotlin.Unit data);
+ method public void visitDynamicReference(@NonNull com.google.devtools.ksp.symbol.KSDynamicReference reference, @NonNull kotlin.Unit data);
+ method public void visitFile(@NonNull com.google.devtools.ksp.symbol.KSFile file, @NonNull kotlin.Unit data);
+ method public void visitFunctionDeclaration(@NonNull com.google.devtools.ksp.symbol.KSFunctionDeclaration function, @NonNull kotlin.Unit data);
+ method public void visitModifierListOwner(@NonNull com.google.devtools.ksp.symbol.KSModifierListOwner modifierListOwner, @NonNull kotlin.Unit data);
+ method public void visitNode(@NonNull com.google.devtools.ksp.symbol.KSNode node, @NonNull kotlin.Unit data);
+ method public void visitParenthesizedReference(@NonNull com.google.devtools.ksp.symbol.KSParenthesizedReference reference, @NonNull kotlin.Unit data);
+ method public void visitPropertyAccessor(@NonNull com.google.devtools.ksp.symbol.KSPropertyAccessor accessor, @NonNull kotlin.Unit data);
+ method public void visitPropertyDeclaration(@NonNull com.google.devtools.ksp.symbol.KSPropertyDeclaration property, @NonNull kotlin.Unit data);
+ method public void visitPropertyGetter(@NonNull com.google.devtools.ksp.symbol.KSPropertyGetter getter, @NonNull kotlin.Unit data);
+ method public void visitPropertySetter(@NonNull com.google.devtools.ksp.symbol.KSPropertySetter setter, @NonNull kotlin.Unit data);
+ method public void visitReferenceElement(@NonNull com.google.devtools.ksp.symbol.KSReferenceElement element, @NonNull kotlin.Unit data);
+ method public void visitTypeAlias(@NonNull com.google.devtools.ksp.symbol.KSTypeAlias typeAlias, @NonNull kotlin.Unit data);
+ method public void visitTypeArgument(@NonNull com.google.devtools.ksp.symbol.KSTypeArgument typeArgument, @NonNull kotlin.Unit data);
+ method public void visitTypeParameter(@NonNull com.google.devtools.ksp.symbol.KSTypeParameter typeParameter, @NonNull kotlin.Unit data);
+ method public void visitTypeReference(@NonNull com.google.devtools.ksp.symbol.KSTypeReference typeReference, @NonNull kotlin.Unit data);
+ method public void visitValueArgument(@NonNull com.google.devtools.ksp.symbol.KSValueArgument valueArgument, @NonNull kotlin.Unit data);
+ method public void visitValueParameter(@NonNull com.google.devtools.ksp.symbol.KSValueParameter valueParameter, @NonNull kotlin.Unit data);
+ }
+
+ public abstract sealed class Location {
+ }
+
+ public enum Modifier {
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier ABSTRACT;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier ACTUAL;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier ANNOTATION;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier CONST;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier CROSSINLINE;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier DATA;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier ENUM;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier EXPECT;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier EXTERNAL;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier FINAL;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier FUN;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier IN;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier INFIX;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier INLINE;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier INNER;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier INTERNAL;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier JAVA_DEFAULT;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier JAVA_NATIVE;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier JAVA_STATIC;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier JAVA_STRICT;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier JAVA_SYNCHRONIZED;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier JAVA_TRANSIENT;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier JAVA_VOLATILE;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier LATEINIT;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier NOINLINE;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier OPEN;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier OPERATOR;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier OUT;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier OVERRIDE;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier PRIVATE;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier PROTECTED;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier PUBLIC;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier REIFIED;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier SEALED;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier SUSPEND;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier TAILREC;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier VALUE;
+ enum_constant public static final com.google.devtools.ksp.symbol.Modifier VARARG;
+ }
+
+ public final class NonExistLocation extends com.google.devtools.ksp.symbol.Location {
+ field @NonNull public static final com.google.devtools.ksp.symbol.NonExistLocation INSTANCE;
+ }
+
+ public enum Nullability {
+ enum_constant public static final com.google.devtools.ksp.symbol.Nullability NOT_NULL;
+ enum_constant public static final com.google.devtools.ksp.symbol.Nullability NULLABLE;
+ enum_constant public static final com.google.devtools.ksp.symbol.Nullability PLATFORM;
+ }
+
+ public enum Origin {
+ enum_constant public static final com.google.devtools.ksp.symbol.Origin JAVA;
+ enum_constant public static final com.google.devtools.ksp.symbol.Origin JAVA_LIB;
+ enum_constant public static final com.google.devtools.ksp.symbol.Origin KOTLIN;
+ enum_constant public static final com.google.devtools.ksp.symbol.Origin KOTLIN_LIB;
+ enum_constant public static final com.google.devtools.ksp.symbol.Origin SYNTHETIC;
+ }
+
+ public enum Variance {
+ method public final String getLabel();
+ property public final String label;
+ enum_constant public static final com.google.devtools.ksp.symbol.Variance CONTRAVARIANT;
+ enum_constant public static final com.google.devtools.ksp.symbol.Variance COVARIANT;
+ enum_constant public static final com.google.devtools.ksp.symbol.Variance INVARIANT;
+ enum_constant public static final com.google.devtools.ksp.symbol.Variance STAR;
+ }
+
+ public enum Visibility {
+ enum_constant public static final com.google.devtools.ksp.symbol.Visibility INTERNAL;
+ enum_constant public static final com.google.devtools.ksp.symbol.Visibility JAVA_PACKAGE;
+ enum_constant public static final com.google.devtools.ksp.symbol.Visibility LOCAL;
+ enum_constant public static final com.google.devtools.ksp.symbol.Visibility PRIVATE;
+ enum_constant public static final com.google.devtools.ksp.symbol.Visibility PROTECTED;
+ enum_constant public static final com.google.devtools.ksp.symbol.Visibility PUBLIC;
+ }
+
+}
+
+package com.google.devtools.ksp.visitor {
+
+ public abstract class KSDefaultVisitor<D, R> extends com.google.devtools.ksp.visitor.KSEmptyVisitor<D,R> {
+ ctor public KSDefaultVisitor();
+ }
+
+ public abstract class KSEmptyVisitor<D, R> implements com.google.devtools.ksp.symbol.KSVisitor<D,R> {
+ ctor public KSEmptyVisitor();
+ method public abstract R defaultHandler(@NonNull com.google.devtools.ksp.symbol.KSNode node, @Nullable D data);
+ method public R visitAnnotated(@NonNull com.google.devtools.ksp.symbol.KSAnnotated annotated, @Nullable D data);
+ method public R visitAnnotation(@NonNull com.google.devtools.ksp.symbol.KSAnnotation annotation, @Nullable D data);
+ method public R visitCallableReference(@NonNull com.google.devtools.ksp.symbol.KSCallableReference reference, @Nullable D data);
+ method public R visitClassDeclaration(@NonNull com.google.devtools.ksp.symbol.KSClassDeclaration classDeclaration, @Nullable D data);
+ method public R visitClassifierReference(@NonNull com.google.devtools.ksp.symbol.KSClassifierReference reference, @Nullable D data);
+ method public R visitDeclaration(@NonNull com.google.devtools.ksp.symbol.KSDeclaration declaration, @Nullable D data);
+ method public R visitDeclarationContainer(@NonNull com.google.devtools.ksp.symbol.KSDeclarationContainer declarationContainer, @Nullable D data);
+ method public R visitDefNonNullReference(@NonNull com.google.devtools.ksp.symbol.KSDefNonNullReference reference, @Nullable D data);
+ method public R visitDynamicReference(@NonNull com.google.devtools.ksp.symbol.KSDynamicReference reference, @Nullable D data);
+ method public R visitFile(@NonNull com.google.devtools.ksp.symbol.KSFile file, @Nullable D data);
+ method public R visitFunctionDeclaration(@NonNull com.google.devtools.ksp.symbol.KSFunctionDeclaration function, @Nullable D data);
+ method public R visitModifierListOwner(@NonNull com.google.devtools.ksp.symbol.KSModifierListOwner modifierListOwner, @Nullable D data);
+ method public R visitNode(@NonNull com.google.devtools.ksp.symbol.KSNode node, @Nullable D data);
+ method public R visitParenthesizedReference(@NonNull com.google.devtools.ksp.symbol.KSParenthesizedReference reference, @Nullable D data);
+ method public R visitPropertyAccessor(@NonNull com.google.devtools.ksp.symbol.KSPropertyAccessor accessor, @Nullable D data);
+ method public R visitPropertyDeclaration(@NonNull com.google.devtools.ksp.symbol.KSPropertyDeclaration property, @Nullable D data);
+ method public R visitPropertyGetter(@NonNull com.google.devtools.ksp.symbol.KSPropertyGetter getter, @Nullable D data);
+ method public R visitPropertySetter(@NonNull com.google.devtools.ksp.symbol.KSPropertySetter setter, @Nullable D data);
+ method public R visitReferenceElement(@NonNull com.google.devtools.ksp.symbol.KSReferenceElement element, @Nullable D data);
+ method public R visitTypeAlias(@NonNull com.google.devtools.ksp.symbol.KSTypeAlias typeAlias, @Nullable D data);
+ method public R visitTypeArgument(@NonNull com.google.devtools.ksp.symbol.KSTypeArgument typeArgument, @Nullable D data);
+ method public R visitTypeParameter(@NonNull com.google.devtools.ksp.symbol.KSTypeParameter typeParameter, @Nullable D data);
+ method public R visitTypeReference(@NonNull com.google.devtools.ksp.symbol.KSTypeReference typeReference, @Nullable D data);
+ method public R visitValueArgument(@NonNull com.google.devtools.ksp.symbol.KSValueArgument valueArgument, @Nullable D data);
+ method public R visitValueParameter(@NonNull com.google.devtools.ksp.symbol.KSValueParameter valueParameter, @Nullable D data);
+ }
+
+ public abstract class KSTopDownVisitor<D, R> extends com.google.devtools.ksp.visitor.KSDefaultVisitor<D,R> {
+ ctor public KSTopDownVisitor();
+ }
+
+ public class KSValidateVisitor extends com.google.devtools.ksp.visitor.KSDefaultVisitor<com.google.devtools.ksp.symbol.KSNode,java.lang.Boolean> {
+ ctor public KSValidateVisitor(@NonNull kotlin.jvm.functions.Function2<? super com.google.devtools.ksp.symbol.KSNode,? super com.google.devtools.ksp.symbol.KSNode,java.lang.Boolean> predicate);
+ method @NonNull public Boolean defaultHandler(@NonNull com.google.devtools.ksp.symbol.KSNode node, @Nullable com.google.devtools.ksp.symbol.KSNode data);
+ method @NonNull public Boolean visitAnnotated(@NonNull com.google.devtools.ksp.symbol.KSAnnotated annotated, @Nullable com.google.devtools.ksp.symbol.KSNode data);
+ method @NonNull public Boolean visitAnnotation(@NonNull com.google.devtools.ksp.symbol.KSAnnotation annotation, @Nullable com.google.devtools.ksp.symbol.KSNode data);
+ method @NonNull public Boolean visitClassDeclaration(@NonNull com.google.devtools.ksp.symbol.KSClassDeclaration classDeclaration, @Nullable com.google.devtools.ksp.symbol.KSNode data);
+ method @NonNull public Boolean visitDeclaration(@NonNull com.google.devtools.ksp.symbol.KSDeclaration declaration, @Nullable com.google.devtools.ksp.symbol.KSNode data);
+ method @NonNull public Boolean visitDeclarationContainer(@NonNull com.google.devtools.ksp.symbol.KSDeclarationContainer declarationContainer, @Nullable com.google.devtools.ksp.symbol.KSNode data);
+ method @NonNull public Boolean visitFunctionDeclaration(@NonNull com.google.devtools.ksp.symbol.KSFunctionDeclaration function, @Nullable com.google.devtools.ksp.symbol.KSNode data);
+ method @NonNull public Boolean visitPropertyDeclaration(@NonNull com.google.devtools.ksp.symbol.KSPropertyDeclaration property, @Nullable com.google.devtools.ksp.symbol.KSNode data);
+ method @NonNull public Boolean visitTypeParameter(@NonNull com.google.devtools.ksp.symbol.KSTypeParameter typeParameter, @Nullable com.google.devtools.ksp.symbol.KSNode data);
+ method @NonNull public Boolean visitTypeReference(@NonNull com.google.devtools.ksp.symbol.KSTypeReference typeReference, @Nullable com.google.devtools.ksp.symbol.KSNode data);
+ method @NonNull public Boolean visitValueArgument(@NonNull com.google.devtools.ksp.symbol.KSValueArgument valueArgument, @Nullable com.google.devtools.ksp.symbol.KSNode data);
+ method @NonNull public Boolean visitValueParameter(@NonNull com.google.devtools.ksp.symbol.KSValueParameter valueParameter, @Nullable com.google.devtools.ksp.symbol.KSNode data);
+ }
+
+}
+
diff --git a/api/build.gradle.kts b/api/build.gradle.kts
new file mode 100644
index 00000000..b3a2f6c6
--- /dev/null
+++ b/api/build.gradle.kts
@@ -0,0 +1,58 @@
+import com.google.devtools.ksp.configureMetalava
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+description = "Kotlin Symbol Processing API"
+
+val signingKey: String? by project
+val signingPassword: String? by project
+val kotlinBaseVersion: String by project
+
+tasks.withType<KotlinCompile> {
+ compilerOptions.freeCompilerArgs.add("-Xjvm-default=all-compatibility")
+}
+
+plugins {
+ kotlin("jvm")
+ `maven-publish`
+ signing
+ id("org.jetbrains.dokka") version ("1.7.20")
+}
+
+dependencies {
+ api(kotlin("stdlib", kotlinBaseVersion))
+}
+tasks {
+ val sourcesJar by creating(Jar::class) {
+ archiveClassifier.set("sources")
+ from(sourceSets.main.get().allSource)
+ }
+}
+
+val dokkaJavadocJar by tasks.register<Jar>("dokkaJavadocJar") {
+ dependsOn(tasks.dokkaJavadoc)
+ from(tasks.dokkaJavadoc.flatMap { it.outputDirectory })
+ archiveClassifier.set("javadoc")
+}
+
+publishing {
+ publications {
+ create<MavenPublication>("default") {
+ artifactId = "symbol-processing-api"
+ from(components["java"])
+ artifact(tasks["sourcesJar"])
+ artifact(tasks["dokkaJavadocJar"])
+ pom {
+ name.set("com.google.devtools.ksp:symbol-processing-api")
+ description.set("Symbol processing for Kotlin")
+ }
+ }
+ }
+}
+
+signing {
+ isRequired = hasProperty("signingKey")
+ useInMemoryPgpKeys(signingKey, signingPassword)
+ sign(extensions.getByType<PublishingExtension>().publications)
+}
+
+configureMetalava()
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/KspExperimental.kt b/api/src/main/kotlin/com/google/devtools/ksp/KspExperimental.kt
new file mode 100644
index 00000000..7e86b869
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/KspExperimental.kt
@@ -0,0 +1,8 @@
+package com.google.devtools.ksp
+
+@RequiresOptIn(
+ message = "This API is experimental." +
+ "It may be changed in the future without notice or might be removed."
+)
+@Retention(AnnotationRetention.BINARY)
+annotation class KspExperimental
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/processing/CodeGenerator.kt b/api/src/main/kotlin/com/google/devtools/ksp/processing/CodeGenerator.kt
new file mode 100644
index 00000000..fd5bc5b1
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/processing/CodeGenerator.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.processing
+
+import com.google.devtools.ksp.symbol.*
+import java.io.File
+import java.io.OutputStream
+
+/**
+ * [CodeGenerator] creates and manages files.
+ *
+ * Files created by [CodeGenerator] are considered in incremental processing.
+ * Kotlin and Java files will be compiled together with other source files in the module.
+ * Files created without using this API will not participate in incremental processing nor subsequent compilations.
+ */
+interface CodeGenerator {
+ /**
+ * Creates a file which is managed by [CodeGenerator]
+ *
+ * Sources of corresponding [KSNode]s which are obtained directly from [Resolver] need to be specified.
+ * Namely, the containing files of those [KSNode]s who are obtained from:
+ * * [Resolver.getAllFiles]
+ * * [Resolver.getSymbolsWithAnnotation]
+ * * [Resolver.getClassDeclarationByName]
+ *
+ * Instead of requiring processors to specify all source files which are relevant in generating the given output,
+ * KSP traces dependencies automatically and only needs to know those sources that only processors know what they
+ * are for. If a [KSFile] is indirectly obtained through other [KSNode]s, it hasn't to be specified for the given
+ * output, even if its contents contribute to the generation of the output.
+ *
+ * For example, a processor generates an output `O` after reading class `A` in `A.kt` and class `B` in `B.kt`,
+ * where `A` extends `B`. The processor got `A` by [Resolver.getSymbolsWithAnnotation] and then got `B` by
+ * [KSClassDeclaration.superTypes] from `A`. Because the inclusion of `B` is due to `A`, `B.kt` needn't to be
+ * specified in [dependencies] for `O`. Note that specifying `B.kt` in this case doesn't hurt, it is only unnecessary.
+ *
+ * @param dependencies are [KSFile]s from which this output is built. Only those that are obtained directly
+ * from [Resolver] are required.
+ * @param packageName corresponds to the relative path of the generated file; using either '.'or '/' as separator.
+ * @param fileName file name
+ * @param extensionName If "kt" or "java", this file will participate in subsequent compilation.
+ * Otherwise its creation is only considered in incremental processing.
+ * @return OutputStream for writing into files.
+ * @see [CodeGenerator] for more details.
+ */
+ fun createNewFile(
+ dependencies: Dependencies,
+ packageName: String,
+ fileName: String,
+ extensionName: String = "kt"
+ ): OutputStream
+
+ /**
+ * Creates a file which is managed by [CodeGenerator]
+ *
+ * Sources of corresponding [KSNode]s which are obtained directly from [Resolver] need to be specified.
+ * Namely, the containing files of those [KSNode]s who are obtained from:
+ * * [Resolver.getAllFiles]
+ * * [Resolver.getSymbolsWithAnnotation]
+ * * [Resolver.getClassDeclarationByName]
+ *
+ * Instead of requiring processors to specify all source files which are relevant in generating the given output,
+ * KSP traces dependencies automatically and only needs to know those sources that only processors know what they
+ * are for. If a [KSFile] is indirectly obtained through other [KSNode]s, it hasn't to be specified for the given
+ * output, even if its contents contribute to the generation of the output.
+ *
+ * For example, a processor generates an output `O` after reading class `A` in `A.kt` and class `B` in `B.kt`,
+ * where `A` extends `B`. The processor got `A` by [Resolver.getSymbolsWithAnnotation] and then got `B` by
+ * [KSClassDeclaration.superTypes] from `A`. Because the inclusion of `B` is due to `A`, `B.kt` needn't to be
+ * specified in [dependencies] for `O`. Note that specifying `B.kt` in this case doesn't hurt, it is only unnecessary.
+ *
+ * @param dependencies are [KSFile]s from which this output is built. Only those that are obtained directly
+ * from [Resolver] are required.
+ * @param path corresponds to the relative path of the generated file; includes the full file name
+ * @param fileType determines the target directory to store the file
+ * @return OutputStream for writing into files.
+ * @see [CodeGenerator] for more details.
+ */
+ fun createNewFileByPath(
+ dependencies: Dependencies,
+ path: String,
+ extensionName: String = "kt"
+ ): OutputStream
+
+ /**
+ * Associate [sources] to an output file.
+ *
+ * @param sources are [KSFile]s from which this output is built. Only those that are obtained directly
+ * from [Resolver] are required.
+ * @param packageName corresponds to the relative path of the generated file; using either '.'or '/' as separator.
+ * @param fileName file name
+ * @param extensionName If "kt" or "java", this file will participate in subsequent compilation.
+ * Otherwise its creation is only considered in incremental processing.
+ * @see [CodeGenerator] for more details.
+ */
+ fun associate(sources: List<KSFile>, packageName: String, fileName: String, extensionName: String = "kt")
+
+ /**
+ * Associate [sources] to an output file.
+ *
+ * @param sources are [KSFile]s from which this output is built. Only those that are obtained directly
+ * from [Resolver] are required.
+ * @param path corresponds to the relative path of the generated file; includes the full file name
+ * @param fileType determines the target directory where the file should exist
+ * @see [CodeGenerator] for more details.
+ */
+ fun associateByPath(sources: List<KSFile>, path: String, extensionName: String = "kt")
+
+ /**
+ * Associate [classes] to an output file.
+ *
+ * @param classes are [KSClassDeclaration]s from which this output is built. Only those that are obtained directly
+ * from [Resolver] are required.
+ * @param packageName corresponds to the relative path of the generated file; using either '.'or '/' as separator.
+ * @param fileName file name
+ * @param extensionName If "kt" or "java", this file will participate in subsequent compilation.
+ * Otherwise its creation is only considered in incremental processing.
+ * @see [CodeGenerator] for more details.
+ */
+ fun associateWithClasses(
+ classes: List<KSClassDeclaration>,
+ packageName: String,
+ fileName: String,
+ extensionName: String = "kt"
+ )
+
+ val generatedFile: Collection<File>
+}
+
+/**
+ * Dependencies of an output file.
+ */
+class Dependencies private constructor(
+ val isAllSources: Boolean,
+ val aggregating: Boolean,
+ val originatingFiles: List<KSFile>
+) {
+
+ /**
+ * Create a [Dependencies] to associate with an output.
+ *
+ * @param aggregating whether the output should be invalidated by a new source file or a change in any of the existing files.
+ * Namely, whenever there is new information.
+ * @param sources Sources for this output to depend on.
+ */
+ constructor(aggregating: Boolean, vararg sources: KSFile) : this(false, aggregating, sources.toList())
+
+ companion object {
+ /**
+ * A short-hand to all source files.
+ *
+ * Associating an output to [ALL_SOURCES] essentially disables incremental processing, as the tiniest change will clobber all files.
+ * This should not be used in processors which care about processing speed.
+ */
+ val ALL_FILES = Dependencies(true, true, emptyList())
+ }
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/processing/KSBuiltIns.kt b/api/src/main/kotlin/com/google/devtools/ksp/processing/KSBuiltIns.kt
new file mode 100644
index 00000000..95da7de3
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/processing/KSBuiltIns.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.processing
+
+import com.google.devtools.ksp.symbol.KSType
+
+interface KSBuiltIns {
+ /**
+ * Common Standard Library types. Use [Resolver.getClassDeclarationByName] for other types.
+ */
+ val anyType: KSType
+ val nothingType: KSType
+ val unitType: KSType
+ val numberType: KSType
+ val byteType: KSType
+ val shortType: KSType
+ val intType: KSType
+ val longType: KSType
+ val floatType: KSType
+ val doubleType: KSType
+ val charType: KSType
+ val booleanType: KSType
+ val stringType: KSType
+ val iterableType: KSType
+ val annotationType: KSType
+ val arrayType: KSType
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/processing/KSPLogger.kt b/api/src/main/kotlin/com/google/devtools/ksp/processing/KSPLogger.kt
new file mode 100644
index 00000000..3ca30a67
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/processing/KSPLogger.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.processing
+
+import com.google.devtools.ksp.symbol.KSNode
+
+interface KSPLogger {
+
+ fun logging(message: String, symbol: KSNode? = null)
+ fun info(message: String, symbol: KSNode? = null)
+ fun warn(message: String, symbol: KSNode? = null)
+ fun error(message: String, symbol: KSNode? = null)
+
+ fun exception(e: Throwable)
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/processing/PlatformInfo.kt b/api/src/main/kotlin/com/google/devtools/ksp/processing/PlatformInfo.kt
new file mode 100644
index 00000000..b6dde587
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/processing/PlatformInfo.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processing
+
+/**
+ * Platform specific information
+ */
+interface PlatformInfo {
+ val platformName: String
+}
+
+/*
+ * Platform information for JVM
+ */
+interface JvmPlatformInfo : PlatformInfo {
+ /**
+ * JVM target version. Correspond to `-jvm-target` to Kotlin compiler
+ */
+ val jvmTarget: String
+}
+
+/**
+ * Platform information for JS
+ */
+interface JsPlatformInfo : PlatformInfo
+
+/**
+ * Platform information for native platforms
+ */
+interface NativePlatformInfo : PlatformInfo {
+ val targetName: String
+}
+
+/**
+ * Unknown platform to KSP
+ */
+interface UnknownPlatformInfo : PlatformInfo
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
new file mode 100644
index 00000000..642b5c90
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/processing/Resolver.kt
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.processing
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.symbol.*
+
+/**
+ * [Resolver] provides [SymbolProcessor] with access to compiler details such as Symbols.
+ */
+interface Resolver {
+ /**
+ * Get all new files in the module / compilation unit.
+ *
+ * @return new files generated from last last round of processing in the module.
+ */
+ fun getNewFiles(): Sequence<KSFile>
+
+ /**
+ * Get all files in the module / compilation unit.
+ *
+ * @return all input files including generated files from previous rounds, note when incremental is enabled, only dirty files up for processing will be returned.
+ */
+ fun getAllFiles(): Sequence<KSFile>
+
+ /**
+ * Get all symbols with specified annotation.
+ * Note that in multiple round processing, only symbols from deferred symbols of last round and symbols from newly generated files will be returned in this function.
+ *
+ * @param annotationName is the fully qualified name of the annotation; using '.' as separator.
+ * @param inDepth whether to check symbols in depth, i.e. check symbols from local declarations. Operation can be expensive if true.
+ * @return Elements annotated with the specified annotation.
+ */
+ fun getSymbolsWithAnnotation(annotationName: String, inDepth: Boolean = false): Sequence<KSAnnotated>
+
+ /**
+ * Find a class in the compilation classpath for the given name.
+ *
+ * This returns the exact platform class when given a platform name. Note that java.lang.String isn't compatible
+ * with kotlin.String in the type system. Therefore, processors need to use mapJavaNameToKotlin() and mapKotlinNameToJava()
+ * explicitly to find the corresponding class names before calling getClassDeclarationByName if type checking
+ * is needed for the classes loaded by this.
+ *
+ * This behavior is limited to getClassDeclarationByName; When processors get a class or type from a Java source
+ * file, the conversion is done automatically. E.g., a java.lang.String in a Java source file is loaded as
+ * kotlin.String in KSP.
+ *
+ * @param name fully qualified name of the class to be loaded; using '.' as separator.
+ * @return a KSClassDeclaration, or null if not found.
+ */
+ fun getClassDeclarationByName(name: KSName): KSClassDeclaration?
+
+ /**
+ * Find functions in the compilation classpath for the given name.
+ *
+ * @param name fully qualified name of the function to be loaded; using '.' as separator.
+ * @param includeTopLevel a boolean value indicate if top level functions should be searched. Default false. Note if top level functions are included, this operation can be expensive.
+ * @return a Sequence of KSFunctionDeclaration
+ */
+ fun getFunctionDeclarationsByName(name: KSName, includeTopLevel: Boolean = false): Sequence<KSFunctionDeclaration>
+
+ /**
+ * Find a property in the compilation classpath for the given name.
+ *
+ * @param name fully qualified name of the property to be loaded; using '.' as separator.
+ * @param includeTopLevel a boolean value indicate if top level properties should be searched. Default false. Note if top level properties are included, this operation can be expensive.
+ * @return a KSPropertyDeclaration, or null if not found.
+ */
+ fun getPropertyDeclarationByName(name: KSName, includeTopLevel: Boolean = false): KSPropertyDeclaration?
+
+ /**
+ * Compose a type argument out of a type reference and a variance
+ *
+ * @param typeRef a type reference to be used in type argument
+ * @param variance specifies a use-site variance
+ * @return a type argument with use-site variance
+ */
+ fun getTypeArgument(typeRef: KSTypeReference, variance: Variance): KSTypeArgument
+
+ /**
+ * Get a [KSName] from a String.
+ */
+ fun getKSNameFromString(name: String): KSName
+
+ /**
+ * Create a [KSTypeReference] from a [KSType]
+ */
+ fun createKSTypeReferenceFromKSType(type: KSType): KSTypeReference
+
+ /**
+ * Provides built in types for convenience. For example, [KSBuiltins.anyType] is the KSType instance for class 'kotlin.Any'.
+ */
+ val builtIns: KSBuiltIns
+
+ /**
+ * map a declaration to jvm signature.
+ * This function might fail due to resolution error, in case of error, null is returned.
+ * Resolution error could be caused by bad code that could not be resolved by compiler, or KSP bugs.
+ * If you believe your code is correct, please file a bug at https://github.com/google/ksp/issues/new
+ */
+ @KspExperimental
+ fun mapToJvmSignature(declaration: KSDeclaration): String?
+
+ /**
+ * @param overrider the candidate overriding declaration being checked.
+ * @param overridee the candidate overridden declaration being checked.
+ * @return boolean value indicating whether [overrider] overrides [overridee]
+ * Calling [overrides] is expensive and should be avoided if possible.
+ */
+ fun overrides(overrider: KSDeclaration, overridee: KSDeclaration): Boolean
+
+ /**
+ * @param overrider the candidate overriding declaration being checked.
+ * @param overridee the candidate overridden declaration being checked.
+ * @param containingClass the containing class of candidate overriding and overridden declaration being checked.
+ * @return boolean value indicating whether [overrider] overrides [overridee]
+ * Calling [overrides] is expensive and should be avoided if possible.
+ */
+ fun overrides(overrider: KSDeclaration, overridee: KSDeclaration, containingClass: KSClassDeclaration): Boolean
+
+ /**
+ * Returns the jvm name of the given function.
+ * This function might fail due to resolution error, in case of error, null is returned.
+ * Resolution error could be caused by bad code that could not be resolved by compiler, or KSP bugs.
+ * If you believe your code is correct, please file a bug at https://github.com/google/ksp/issues/new
+ *
+ * The jvm name of a function might depend on the Kotlin Compiler version hence it is not guaranteed to be
+ * compatible between different compiler versions except for the rules outlined in the Java interoperability
+ * documentation: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html.
+ *
+ * If the [declaration] is annotated with [JvmName], that name will be returned from this function.
+ *
+ * Note that this might be different from the name declared in the Kotlin source code in two cases:
+ * a) If the function receives or returns an inline class, its name will be mangled according to
+ * https://kotlinlang.org/docs/reference/inline-classes.html#mangling.
+ * b) If the function is declared as internal, it will include a suffix with the module name.
+ *
+ * NOTE: As inline classes are an experimental feature, the result of this function might change based on the
+ * kotlin version used in the project.
+ */
+ @KspExperimental
+ fun getJvmName(declaration: KSFunctionDeclaration): String?
+
+ /**
+ * Returns the jvm name of the given property accessor.
+ * This function might fail due to resolution error, in case of error, null is returned.
+ * Resolution error could be caused by bad code that could not be resolved by compiler, or KSP bugs.
+ * If you believe your code is correct, please file a bug at https://github.com/google/ksp/issues/new
+ *
+ * The jvm name of an accessor might depend on the Kotlin Compiler version hence it is not guaranteed to be
+ * compatible between different compiler versions except for the rules outlined in the Java interoperability
+ * documentation: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html.
+ *
+ * If the [accessor] is annotated with [JvmName], that name will be returned from this function.
+ *
+ * By default, this name will match the name calculated according to
+ * https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#properties.
+ * Note that the result of this function might be different from that name in two cases:
+ * a) If the property's type is an internal class, accessor's name will be mangled according to
+ * https://kotlinlang.org/docs/reference/inline-classes.html#mangling.
+ * b) If the function is declared as internal, it will include a suffix with the module name.
+ *
+ * NOTE: As inline classes are an experimental feature, the result of this function might change based on the
+ * kotlin version used in the project.
+ * see: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#properties
+ */
+ @KspExperimental
+ fun getJvmName(accessor: KSPropertyAccessor): String?
+
+ /**
+ * Returns the [binary class name](https://asm.ow2.io/javadoc/org/objectweb/asm/Type.html#getClassName()) of the
+ * owner class in JVM for the given [KSPropertyDeclaration].
+ *
+ * For properties declared in classes / interfaces; this value is the binary class name of the declaring class.
+ *
+ * For top level properties, this is the binary class name of the synthetic class that is generated for the Kotlin
+ * file.
+ * see: https://kotlinlang.org/docs/java-to-kotlin-interop.html#package-level-functions
+ *
+ * Note that, for properties declared in companion objects, the returned owner class will be the Companion class.
+ * see: https://kotlinlang.org/docs/java-to-kotlin-interop.html#static-methods
+ */
+ @KspExperimental
+ fun getOwnerJvmClassName(declaration: KSPropertyDeclaration): String?
+
+ /**
+ * Returns the [binary class name](https://asm.ow2.io/javadoc/org/objectweb/asm/Type.html#getClassName()) of the
+ * owner class in JVM for the given [KSFunctionDeclaration].
+ *
+ * For functions declared in classes / interfaces; this value is the binary class name of the declaring class.
+ *
+ * For top level functions, this is the binary class name of the synthetic class that is generated for the Kotlin
+ * file.
+ * see: https://kotlinlang.org/docs/java-to-kotlin-interop.html#package-level-functions
+ *
+ * Note that, for functions declared in companion objects, the returned owner class will be the Companion class.
+ * see: https://kotlinlang.org/docs/java-to-kotlin-interop.html#static-methods
+ */
+ @KspExperimental
+ fun getOwnerJvmClassName(declaration: KSFunctionDeclaration): String?
+
+ /**
+ * Returns checked exceptions declared in a function's header.
+ * @return A sequence of [KSType] declared in `throws` statement for a Java method or in @Throws annotation for a Kotlin function.
+ * Checked exceptions from class files are not supported yet, an empty sequence will be returned instead.
+ */
+ @KspExperimental
+ fun getJvmCheckedException(function: KSFunctionDeclaration): Sequence<KSType>
+
+ /**
+ * Returns checked exceptions declared in a property accessor's header.
+ * @return A sequence of [KSType] declared @Throws annotation for a Kotlin property accessor.
+ * Checked exceptions from class files are not supported yet, an empty sequence will be returned instead.
+ */
+ @KspExperimental
+ fun getJvmCheckedException(accessor: KSPropertyAccessor): Sequence<KSType>
+
+ /**
+ * Returns declarations with the given package name.
+ * @param packageName the package name to look up.
+ * @return A sequence of [KSDeclaration] with matching package name.
+ * This will return declarations from both dependencies and source.
+ */
+ @KspExperimental
+ fun getDeclarationsFromPackage(packageName: String): Sequence<KSDeclaration>
+
+ /**
+ * Returns the corresponding Kotlin class with the given Java class.
+ *
+ * E.g.
+ * java.lang.String -> kotlin.String
+ * java.lang.Integer -> kotlin.Int
+ * java.util.List -> kotlin.List
+ * java.util.Map.Entry -> kotlin.Map.Entry
+ * java.lang.Void -> null
+ *
+ * @param javaName a Java class name
+ * @return corresponding Kotlin class name or null
+ */
+ @KspExperimental
+ fun mapJavaNameToKotlin(javaName: KSName): KSName?
+
+ /**
+ * Returns the corresponding Java class with the given Kotlin class.
+ *
+ * E.g.
+ * kotlin.Throwable -> java.lang.Throwable
+ * kotlin.Int -> java.lang.Integer
+ * kotlin.Nothing -> java.lang.Void
+ * kotlin.IntArray -> null
+ *
+ * @param kotlinName a Java class name
+ * @return corresponding Java class name or null
+ */
+ @KspExperimental
+ fun mapKotlinNameToJava(kotlinName: KSName): KSName?
+
+ /**
+ * Same as KSDeclarationContainer.declarations, but sorted by declaration order in the source.
+ *
+ * Note that this is SLOW. AVOID IF POSSIBLE.
+ */
+ @KspExperimental
+ fun getDeclarationsInSourceOrder(container: KSDeclarationContainer): Sequence<KSDeclaration>
+
+ /**
+ * Returns a set of effective Java modifiers, if declaration is being / was generated to Java bytecode.
+ */
+ @KspExperimental
+ fun effectiveJavaModifiers(declaration: KSDeclaration): Set<Modifier>
+
+ /**
+ * Compute the corresponding Java wildcard, from the given reference.
+ *
+ * @param reference the reference to the type usage
+ * @return an equivalent type reference from the Java wildcard's point of view
+ */
+ @KspExperimental
+ fun getJavaWildcard(reference: KSTypeReference): KSTypeReference
+
+ /**
+ * Tests a type if it was declared as legacy "raw" type in Java - a type with its type arguments fully omitted.
+ *
+ * @param type a type to check.
+ * @return True if the type is a "raw" type.
+ */
+ @KspExperimental
+ fun isJavaRawType(type: KSType): Boolean
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/processing/SymbolProcessor.kt b/api/src/main/kotlin/com/google/devtools/ksp/processing/SymbolProcessor.kt
new file mode 100644
index 00000000..a952ef13
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/processing/SymbolProcessor.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.processing
+
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+/**
+ * [SymbolProcessor] is the interface used by plugins to integrate into Kotlin Symbol Processing.
+ * SymbolProcessor supports multiple rounds of execution, a processor may return a list of deferred symbols at the end
+ * of every round, which will be passed to processors again in the next round, together with the newly generated symbols.
+ * On exceptions, KSP will try to distinguish between exceptions from KSP and exceptions from processors.
+ * Exceptions from processors will immediately terminate processing and be logged as an error in KSPLogger.
+ * Exceptions from KSP should be reported to KSP developers for further investigation.
+ * At the end of the round where exceptions or errors happened, all processors will invoke onError() function to do
+ * their own error handling.
+ */
+interface SymbolProcessor {
+ /**
+ * Called by Kotlin Symbol Processing to run the processing task.
+ *
+ * @param resolver provides [SymbolProcessor] with access to compiler details such as Symbols.
+ * @return A list of deferred symbols that the processor can't process. Only symbols that can't be processed at this round should be returned. Symbols in compiled code (libraries) are always valid and are ignored if returned in the deferral list.
+ */
+ fun process(resolver: Resolver): List<KSAnnotated>
+
+ /**
+ * Called by Kotlin Symbol Processing to finalize the processing of a compilation.
+ */
+ fun finish() {}
+
+ /**
+ * Called by Kotlin Symbol Processing to handle errors after a round of processing.
+ */
+ fun onError() {}
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/processing/SymbolProcessorEnvironment.kt b/api/src/main/kotlin/com/google/devtools/ksp/processing/SymbolProcessorEnvironment.kt
new file mode 100644
index 00000000..bbe47f8a
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/processing/SymbolProcessorEnvironment.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processing
+
+class SymbolProcessorEnvironment(
+ /**
+ * passed from command line, Gradle, etc.
+ */
+ val options: Map<String, String>,
+
+ /**
+ * language version of compilation environment.
+ */
+ val kotlinVersion: KotlinVersion,
+
+ /**
+ * creates managed files.
+ */
+ val codeGenerator: CodeGenerator,
+
+ /**
+ * for logging to build output.
+ */
+ val logger: KSPLogger,
+
+ /**
+ * Kotlin API version of compilation environment.
+ */
+ val apiVersion: KotlinVersion,
+
+ /**
+ * Kotlin compiler version of compilation environment.
+ */
+ val compilerVersion: KotlinVersion,
+
+ /**
+ * Information of target platforms
+ *
+ * There can be multiple platforms in a metadata compilation.
+ */
+ val platforms: List<PlatformInfo>,
+) {
+ // For compatibility with KSP 1.0.2 and earlier
+ constructor(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger
+ ) : this(
+ options,
+ kotlinVersion,
+ codeGenerator,
+ logger,
+ kotlinVersion,
+ kotlinVersion,
+ emptyList()
+ )
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/processing/SymbolProcessorProvider.kt b/api/src/main/kotlin/com/google/devtools/ksp/processing/SymbolProcessorProvider.kt
new file mode 100644
index 00000000..b9ab7a05
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/processing/SymbolProcessorProvider.kt
@@ -0,0 +1,11 @@
+package com.google.devtools.ksp.processing
+
+/**
+ * [SymbolProcessorProvider] is the interface used by plugins to integrate into Kotlin Symbol Processing.
+ */
+fun interface SymbolProcessorProvider {
+ /**
+ * Called by Kotlin Symbol Processing to create the processor.
+ */
+ fun create(environment: SymbolProcessorEnvironment): SymbolProcessor
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/AnnotationUseSiteTarget.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/AnnotationUseSiteTarget.kt
new file mode 100644
index 00000000..7c975e2f
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/AnnotationUseSiteTarget.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+enum class AnnotationUseSiteTarget {
+ FILE,
+ PROPERTY,
+ FIELD,
+ GET,
+ SET,
+ RECEIVER,
+ PARAM,
+ SETPARAM,
+ DELEGATE
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/ClassKind.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/ClassKind.kt
new file mode 100644
index 00000000..8ff55ad7
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/ClassKind.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * Kind of a class declaration.
+ * Interface, class, enum class and object are all considered a class declaration.
+ */
+enum class ClassKind(val type: String) {
+ INTERFACE("interface"),
+ CLASS("class"),
+ ENUM_CLASS("enum_class"),
+ ENUM_ENTRY("enum_entry"),
+ OBJECT("object"),
+ ANNOTATION_CLASS("annotation_class")
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/FunctionKind.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/FunctionKind.kt
new file mode 100644
index 00000000..d1cb8226
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/FunctionKind.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * Kind of a function declaration.
+ */
+enum class FunctionKind {
+ TOP_LEVEL, MEMBER, STATIC, ANONYMOUS, LAMBDA;
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSAnnotated.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSAnnotated.kt
new file mode 100644
index 00000000..3cfd551f
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSAnnotated.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A symbol that can be annotated with annotations.
+ */
+interface KSAnnotated : KSNode {
+
+ /**
+ * All annotations on this symbol.
+ */
+ val annotations: Sequence<KSAnnotation>
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSAnnotation.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSAnnotation.kt
new file mode 100644
index 00000000..d65656c8
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSAnnotation.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * Instance of a constructor-call-like annotation.
+ */
+interface KSAnnotation : KSNode {
+ /**
+ * Reference to the type of the annotation class declaration.
+ */
+ val annotationType: KSTypeReference
+
+ /**
+ * The arguments applied to the constructor call to construct this annotation.
+ * Must be compile time constants.
+ * @see [KSValueArgument] for operations on its values.
+ */
+ val arguments: List<KSValueArgument>
+
+ /**
+ * The default values of the annotation members
+ */
+ val defaultArguments: List<KSValueArgument>
+
+ /**
+ * Short name for this annotation, equivalent to the simple name of the declaration of the annotation class.
+ */
+ val shortName: KSName
+
+ /**
+ * Use site target of the annotation. Could be null if no annotation use site target is specified.
+ */
+ val useSiteTarget: AnnotationUseSiteTarget?
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSCallableReference.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSCallableReference.kt
new file mode 100644
index 00000000..7249b3bd
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSCallableReference.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A reference to a callable entity, such as a function or a property.
+ */
+interface KSCallableReference : KSReferenceElement {
+ /**
+ * A reference to the type of its receiver.
+ */
+ val receiverType: KSTypeReference?
+
+ /**
+ * Parameters to this callable.
+ */
+ val functionParameters: List<KSValueParameter>
+
+ /**
+ * A reference to its return type.
+ */
+ val returnType: KSTypeReference
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitCallableReference(this, data)
+ }
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSClassDeclaration.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSClassDeclaration.kt
new file mode 100644
index 00000000..d7de9eb7
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSClassDeclaration.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * Models class-like declarations, including class, interface and object.
+ */
+interface KSClassDeclaration : KSDeclaration, KSDeclarationContainer {
+
+ /**
+ * The Kind of the class declaration.
+ */
+ val classKind: ClassKind
+
+ /**
+ * Primary constructor of a class, secondary constructors can be obtained by filtering [declarations].
+ */
+ val primaryConstructor: KSFunctionDeclaration?
+
+ /**
+ * Sequence of supertypes of this class, containing both super class and implemented interfaces.
+ */
+ val superTypes: Sequence<KSTypeReference>
+
+ /**
+ * Determine whether this class declaration is a companion object.
+ * @see [https://kotlinlang.org/docs/tutorials/kotlin-for-py/objects-and-companion-objects.html#companion-objects]
+ */
+ val isCompanionObject: Boolean
+
+ /**
+ * @return a sequence of sealed subclasses of this class, if any.
+ * Calling [getSealedSubclasses] requires type resolution which is expensive and should be avoided if possible.
+ */
+ fun getSealedSubclasses(): Sequence<KSClassDeclaration>
+
+ /**
+ * Get all member functions of a class declaration, including declared and inherited.
+ * @return Sequence of function declarations from the class members.
+ * Calling [getAllFunctions] requires type resolution which is expensive and should be avoided if possible.
+ */
+ fun getAllFunctions(): Sequence<KSFunctionDeclaration>
+
+ /**
+ * Get all member properties of a class declaration, including declared and inherited.
+ * @return Sequence of properties declarations from the class members.
+ * Calling [getAllProperties] requires type resolution which is expensive and should be avoided if possible.
+ */
+ fun getAllProperties(): Sequence<KSPropertyDeclaration>
+
+ /**
+ * Create a type by applying a list of type arguments to this class' type parameters.
+ * @param typeArguments List of Type arguments to be applied.
+ * @return A type constructed from this class declaration with type parameters substituted with the type arguments.
+ */
+ fun asType(typeArguments: List<KSTypeArgument>): KSType
+
+ /**
+ * If this is a generic class, return the type where the type argument is applied with star projection at use-site.
+ * @return A type with all type parameters applied with star projection.
+ */
+ fun asStarProjectedType(): KSType
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSClassifierReference.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSClassifierReference.kt
new file mode 100644
index 00000000..a9748e81
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSClassifierReference.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * An application / reference to a user declared type such as class, interface and object.
+ */
+interface KSClassifierReference : KSReferenceElement {
+ /**
+ * The outer class of an inner class.
+ */
+ val qualifier: KSClassifierReference?
+
+ /**
+ * The text which appears in the reference. For example, it is "Int" in `val temperature: Int` or
+ * "kotlin.Any" in `val canBeAnything: kotlin.Any`
+ */
+ fun referencedName(): String
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitClassifierReference(this, data)
+ }
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDeclaration.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDeclaration.kt
new file mode 100644
index 00000000..5269ad96
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDeclaration.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A declaration, can be function declaration, clsss declaration and property declaration, or a type alias.
+ */
+interface KSDeclaration : KSModifierListOwner, KSAnnotated, KSExpectActual {
+ /**
+ * Simple name of this declaration, usually the name identifier at the declaration site.
+ */
+ val simpleName: KSName
+
+ /**
+ * Fully qualified name of this declaration, might not exist for some declarations like local declarations.
+ */
+ val qualifiedName: KSName?
+
+ /**
+ * List of [type parameters][KSTypeParameter] of the declaration.
+ */
+ val typeParameters: List<KSTypeParameter>
+
+ /**
+ * The name of the package at which this declaration is declared.
+ */
+ val packageName: KSName
+
+ /**
+ * Parent declaration of this declaration, i.e. the declaration that directly contains this declaration.
+ * File is not a declaration, so this property will be null for top level declarations.
+ */
+ val parentDeclaration: KSDeclaration?
+
+ /**
+ * The containing source file of this declaration, can be null if symbol does not come from a source file, i.e. from a class file.
+ */
+ val containingFile: KSFile?
+
+ /**
+ * The doc string enclosed by \/\*\* and \*\/
+ */
+ val docString: String?
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDeclarationContainer.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDeclarationContainer.kt
new file mode 100644
index 00000000..e9844df3
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDeclarationContainer.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A declaration container can have a list of declarations declared in it.
+ */
+interface KSDeclarationContainer : KSNode {
+ /**
+ * Declarations that are lexically declared inside the current container.
+ */
+ val declarations: Sequence<KSDeclaration>
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDefNonNullReference.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDefNonNullReference.kt
new file mode 100644
index 00000000..6230fe6a
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDefNonNullReference.kt
@@ -0,0 +1,13 @@
+package com.google.devtools.ksp.symbol
+
+interface KSDefNonNullReference : KSReferenceElement {
+ /**
+ * Enclosed reference element of the Definitely non null type.
+ * For a reference of `T & Any`, this returns `T`.
+ */
+ val enclosedType: KSClassifierReference
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitDefNonNullReference(this, data)
+ }
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDynamicReference.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDynamicReference.kt
new file mode 100644
index 00000000..7902b09e
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSDynamicReference.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * Models `dynamic` type for Kotlin/JS.
+ */
+interface KSDynamicReference : KSReferenceElement
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSExpectActual.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSExpectActual.kt
new file mode 100644
index 00000000..29b381f1
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSExpectActual.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * Classes, functions, properties and typealiases can be declared as `expect` in common modules and `actual` in platform modules.
+ *
+ * See https://kotlinlang.org/docs/reference/platform-specific-declarations.html for more information.
+ */
+interface KSExpectActual {
+ /**
+ * True if this is an `actual` implementation.
+ */
+ val isActual: Boolean
+
+ /**
+ * True if this is an `expect` declaration.
+ */
+ val isExpect: Boolean
+
+ /**
+ * Finds all corresponding `actual` implementations for `this`.
+ *
+ * @return a list of corresponding `actual` implementations, or an empty list if not applicable.
+ */
+ fun findActuals(): Sequence<KSDeclaration>
+
+ /**
+ * Finds all corresponding `expect` declarations for `this`.
+ *
+ * @return a list of corresponding `expect` implementations, or an empty list if not applicable.
+ */
+ fun findExpects(): Sequence<KSDeclaration>
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSFile.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSFile.kt
new file mode 100644
index 00000000..52a116b6
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSFile.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A Kotlin source file
+ */
+interface KSFile : KSDeclarationContainer, KSAnnotated {
+ /**
+ * The [KSName] representation of this file's package.
+ */
+ val packageName: KSName
+
+ /**
+ * File name of this source file.
+ */
+ val fileName: String
+
+ /**
+ * Absolute path of this source file.
+ */
+ val filePath: String
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSFunction.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSFunction.kt
new file mode 100644
index 00000000..d4139dbb
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSFunction.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+import com.google.devtools.ksp.processing.Resolver
+/**
+ * Holds the information for a [KSFunctionDeclaration] where type arguments are resolved as member
+ * of a specific [KSType].
+ *
+ * @see Resolver.asMemberOf
+ */
+interface KSFunction {
+ /**
+ * The return type of the function. Note that this might be `null` if an error happened when
+ * the type is resolved.
+ *
+ * @see KSFunctionDeclaration.returnType
+ */
+ val returnType: KSType?
+
+ /**
+ * The types of the value parameters of the function. Note that this list might have `null`
+ * values in it if the type of a parameter could not be resolved.
+ *
+ * @see KSFunctionDeclaration.parameters
+ */
+ val parameterTypes: List<KSType?>
+
+ /**
+ * The type parameters of the function.
+ *
+ * @see KSFunctionDeclaration.typeParameters
+ */
+ val typeParameters: List<KSTypeParameter>
+
+ /**
+ * The receiver type of the function.
+ *
+ * @see KSFunctionDeclaration.extensionReceiver
+ */
+ val extensionReceiverType: KSType?
+
+ /**
+ * True if the compiler couldn't resolve the function.
+ */
+ val isError: Boolean
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSFunctionDeclaration.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSFunctionDeclaration.kt
new file mode 100644
index 00000000..5731a10a
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSFunctionDeclaration.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+import com.google.devtools.ksp.processing.Resolver
+/**
+ * A function definition
+ *
+ * Dispatch receiver can be obtained through [parentDeclaration].
+ *
+ * To obtain the function signature where type arguments are resolved as member of a given [KSType],
+ * use [Resolver.asMemberOf].
+ *
+ * @see KSFunctionType
+ */
+interface KSFunctionDeclaration : KSDeclaration, KSDeclarationContainer {
+ /**
+ * Kind of this function.
+ */
+ val functionKind: FunctionKind
+
+ /**
+ * Whether this function is abstract.
+ */
+ val isAbstract: Boolean
+
+ /**
+ * Extension receiver of this function
+ * @see [https://kotlinlang.org/docs/reference/extensions.html#extension-functions]
+ */
+ val extensionReceiver: KSTypeReference?
+
+ /**
+ * Return type of this function.
+ * Can be null if an error occurred during resolution.
+ */
+ val returnType: KSTypeReference?
+
+ /**
+ * [value parameters][KSValueParameter] of this function.
+ */
+ val parameters: List<KSValueParameter>
+
+ /**
+ * Find the closest overridee of this function, if overriding.
+ *
+ * For the following input:
+ * ```
+ * abstract class A {
+ * open fun x() {}
+ * open fun y() {}
+ * }
+ * abstract class B : A() {
+ * override open fun x() {}
+ * }
+ * abstract class C : B() {
+ * override open fun x() {}
+ * override open fun y() {}
+ * }
+ * ```
+ * Calling `findOverridee` on `C.x` will return `B.x`.
+ * Calling `findOverridee` on `C.y` will return `A.y`.
+ *
+ * When there are multiple super interfaces implementing the function, the closest declaration
+ * to the current containing declaration is selected. If they are in the same level, the
+ * function of the first specified interface (in source) will be returned.
+ *
+ * @return [KSDeclaration] for the original declaration, if overriding, otherwise null.
+ * Calling [findOverridee] is expensive and should be avoided if possible.
+ */
+ fun findOverridee(): KSDeclaration?
+
+ /**
+ * Returns the type of the [function] when it is viewed as member of the [containing] type.
+ *
+ * For instance, for the following input:
+ * ```
+ * interface Base<T> {
+ * fun f(t:T?):T
+ * }
+ * val foo: Base<Int>
+ * val bar: Base<String>
+ * ```
+ * When `f()` is viewed as member of `foo`, this method will return a [KSFunction] where
+ * the [KSFunction.returnType] is `Int` and the parameter `t` is of type `Int?`.
+ * When `f()` is viewed as member of `bar`, this method will return a [KSFunction]
+ * where the [KSFunction.returnType] is `String` and the parameter `t` is of type `String?`.
+ *
+ * If the function has type parameters, they'll not be resolved and can be read from
+ * [KSFunction.typeParameters].
+ *
+ * If the substitution fails (e.g. if [containing] is an error type, a [KSFunction] with [KSFunction.isError] `true`
+ * is returned.
+ *
+ * @param containing The type that contains [function].
+ * @throws IllegalArgumentException Throws [IllegalArgumentException] when [containing] does not contain [function]
+ * or if the [function] is not declared in a class, object or interface.
+ */
+ fun asMemberOf(containing: KSType): KSFunction
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSModifierListOwner.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSModifierListOwner.kt
new file mode 100644
index 00000000..8d8b2013
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSModifierListOwner.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A [KSModifierListOwner] can have zero or more modifiers.
+ */
+interface KSModifierListOwner : KSNode {
+ /**
+ * The set of modifiers on this element.
+ */
+ val modifiers: Set<Modifier>
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSName.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSName.kt
new file mode 100644
index 00000000..1b89e59f
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSName.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * Kotlin Symbol Processing's representation of names. Can be simple or qualified names.
+ */
+interface KSName {
+ /**
+ * String representation of the name.
+ */
+ fun asString(): String
+
+ /**
+ * Qualifier of the name.
+ */
+ fun getQualifier(): String
+
+ /**
+ * If a qualified name, it is the last part. Otherwise it is the same as [asString]
+ */
+ fun getShortName(): String
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSNode.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSNode.kt
new file mode 100644
index 00000000..08e2d7df
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSNode.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * Base class of every visitable program elements.
+ */
+interface KSNode {
+ val origin: Origin
+ val location: Location
+ val parent: KSNode?
+ fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSParenthesizedReference.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSParenthesizedReference.kt
new file mode 100644
index 00000000..83b267d7
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSParenthesizedReference.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A reference within a parenthesis
+ */
+interface KSParenthesizedReference : KSReferenceElement {
+ /**
+ * The reference in this parenthesis
+ */
+ val element: KSReferenceElement
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSPropertyAccessor.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSPropertyAccessor.kt
new file mode 100644
index 00000000..c72b415f
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSPropertyAccessor.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * The common base of property getter and setter.
+ * Note that annotation use-site targets such as @get: @set: is not copied to accessor's annotations attribute.
+ * Use KSAnnotated.findAnnotationFromUseSiteTarget() to ensure annotations from parent is obtained.
+ */
+interface KSPropertyAccessor : KSAnnotated, KSModifierListOwner {
+ /**
+ * The owner of the property accessor.
+ */
+ val receiver: KSPropertyDeclaration
+}
+
+/**
+ * A property setter
+ */
+interface KSPropertySetter : KSPropertyAccessor {
+ val parameter: KSValueParameter
+}
+
+/**
+ * A property getter
+ */
+interface KSPropertyGetter : KSPropertyAccessor {
+ val returnType: KSTypeReference?
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSPropertyDeclaration.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSPropertyDeclaration.kt
new file mode 100644
index 00000000..1910e77c
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSPropertyDeclaration.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A property declaration, can also be used to denote a variable declaration.
+ */
+interface KSPropertyDeclaration : KSDeclaration {
+
+ /**
+ * Getter of the property.
+ * Note that when KSPropertyDeclaration is used to model a variable, getter is always null, as a variable can't have a getter.
+ */
+ val getter: KSPropertyGetter?
+
+ /**
+ * Setter of the property.
+ * Note that when KSPropertyDeclaration is used to model a variable, setter is always null, as a variable can't have a setter.
+ * If a property is immutable, setter is always null as well, as an immutable property can't have a setter.
+ */
+ val setter: KSPropertySetter?
+
+ /**
+ * Extension receiver if this declaration is an [extension property][https://kotlinlang.org/docs/reference/extensions.html#extension-properties].
+ * Dispatch receiver is [parentDeclaration], if any.
+ */
+ val extensionReceiver: KSTypeReference?
+
+ /**
+ * The type of this declaration.
+ */
+ val type: KSTypeReference
+
+ /**
+ * True if this property is mutable.
+ */
+ val isMutable: Boolean
+
+ /**
+ * True if this property has a backing field.
+ *
+ * Note that, this is specific to the current property and does not check for properties that are overridden by this
+ * property.
+ *
+ * https://kotlinlang.org/docs/properties.html#backing-fields
+ */
+ val hasBackingField: Boolean
+
+ /**
+ * Indicates whether this is a delegated property.
+ */
+ fun isDelegated(): Boolean
+
+ /**
+ * Find the closest overridee of this property, if overriding.
+ *
+ * For the following input:
+ * ```
+ * abstract class A {
+ * open val x:Int
+ * open val y:Int
+ * }
+ * abstract class B : A() {
+ * override val x:Int
+ * }
+ * abstract class C : B() {
+ * override val x:Int
+ * override val y:Int
+ * }
+ * ```
+ * Calling `findOverridee` on `C.x` will return `B.x`.
+ * Calling `findOverridee` on `C.y` will return `A.y`.
+ *
+ * When there are multiple super classes / interfaces with the property, the closest declaration
+ * to the current containing declaration is selected. If they are in the same level, the
+ * property of the first specified interface (in source) will be returned.
+ *
+ * @return [KSPropertyDeclaration] for the overridden property, if overriding, otherwise null.
+ * Calling [findOverridee] is expensive and should be avoided if possible.
+ */
+ fun findOverridee(): KSPropertyDeclaration?
+
+ /**
+ * Returns the type of the [property] when it is viewed as member of the [containing] type.
+ *
+ * For instance, for the following input:
+ * ```
+ * class Base<T>(val x:T)
+ * val foo: Base<Int>
+ * val bar: Base<String>
+ * ```
+ * When `x` is viewed as member of `foo`, this method will return the [KSType] for `Int`
+ * whereas when `x` is viewed as member of `bar`, this method will return the [KSType]
+ * representing `String`.
+ *
+ * If the substitution fails (e.g. if [containing] is an error type, a [KSType] with [KSType.isError] `true` is
+ * returned.
+ *
+ * @param containing The type that contains [property]
+ * @throws IllegalArgumentException Throws [IllegalArgumentException] when [containing] does not contain
+ * [property] or if the [property] is not declared in a class, object or interface.
+ */
+ fun asMemberOf(containing: KSType): KSType
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSReferenceElement.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSReferenceElement.kt
new file mode 100644
index 00000000..425036dc
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSReferenceElement.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * An application/reference to a type declared somewhere else.
+ *
+ * KSReferenceElement can specify, for example, a class, interface, or function, etc.
+ */
+interface KSReferenceElement : KSNode {
+ /**
+ * Type arguments in the type reference.
+ */
+ val typeArguments: List<KSTypeArgument>
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSType.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSType.kt
new file mode 100644
index 00000000..c8cd5d43
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSType.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * Represents a type in Kotlin's type system.
+ *
+ * Generally, a type is comprised of a declaration (e.g., class), corresponding type arguments, and other details like nullability.
+ * KSType is useful when doing type checking, finding the declaration, and so on. Some of the information,
+ * such as type annotations and type arguments, are often available in the corresponding type reference without resolution.
+ */
+interface KSType {
+ /**
+ * The declaration that generates this type.
+ */
+ val declaration: KSDeclaration
+
+ /**
+ * A type can be nullable, not nullable, or context-specific in the case of platform types.
+ */
+ val nullability: Nullability
+
+ /**
+ * Type arguments to the type.
+ */
+ val arguments: List<KSTypeArgument>
+
+ /**
+ * Type annotations to the type.
+ */
+ val annotations: Sequence<KSAnnotation>
+
+ /**
+ * Check whether this type is assign-compatible from another type.
+ *
+ * @param: that the other type being checked.
+ */
+ fun isAssignableFrom(that: KSType): Boolean
+
+ /**
+ * True if the type is a collection and can be both mutable and immutable, depending on the context.
+ */
+ fun isMutabilityFlexible(): Boolean
+
+ /**
+ * True if the type can be both invariant and covariant, depending on the context.
+ */
+ fun isCovarianceFlexible(): Boolean
+
+ /**
+ * Replace the type arguments
+ *
+ * @param arguemnts New type arguments
+ * @return A type with the arguments replaced.
+ */
+ fun replace(arguments: List<KSTypeArgument>): KSType
+
+ /**
+ * Returns the star projection of the type.
+ */
+ fun starProjection(): KSType
+
+ /**
+ * Make the type nullable
+ */
+ fun makeNullable(): KSType
+
+ /**
+ * Make the type not nullable
+ */
+ fun makeNotNullable(): KSType
+
+ /**
+ * True if the type is explicitly marked as nullable type, i.e. has question mark in type declaration.
+ */
+ val isMarkedNullable: Boolean
+
+ /**
+ * True if the type is an error type, which means the type can't be resolved by compiler.
+ */
+ val isError: Boolean
+
+ /**
+ * True if the type is a function type. Note that a suspend function will return false here.
+ */
+ val isFunctionType: Boolean
+
+ /**
+ * True if the type is a suspend function
+ */
+ val isSuspendFunctionType: Boolean
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeAlias.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeAlias.kt
new file mode 100644
index 00000000..66310243
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeAlias.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A type alias
+ */
+interface KSTypeAlias : KSDeclaration {
+ /**
+ * The name of the type alias
+ */
+ val name: KSName
+
+ /**
+ * The reference to the aliased type.
+ */
+ val type: KSTypeReference
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeArgument.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeArgument.kt
new file mode 100644
index 00000000..b0dd9787
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeArgument.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A type argument
+ */
+interface KSTypeArgument : KSAnnotated {
+ /**
+ * The use-site variance, or namely type projection
+ */
+ val variance: Variance
+
+ /**
+ * The reference to the type
+ */
+ val type: KSTypeReference?
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeParameter.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeParameter.kt
new file mode 100644
index 00000000..26970d6b
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeParameter.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A type parameter
+ */
+interface KSTypeParameter : KSDeclaration {
+ /**
+ * Name of the type parameter
+ *
+ * For example, in `class Foo<T>`, the name value is "T"
+ */
+ val name: KSName
+
+ /**
+ * Declaration-site variance
+ */
+ val variance: Variance
+
+ /**
+ * True if it is reified, i.e., has the reified modifier.
+ */
+ val isReified: Boolean
+
+ /**
+ * Upper bounds of the type parameter.
+ */
+ val bounds: Sequence<KSTypeReference>
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeReference.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeReference.kt
new file mode 100644
index 00000000..f7d2864c
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSTypeReference.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A [KSTypeReference] combines a [KSReferenceElement] with annotations and modifiers.
+ */
+interface KSTypeReference : KSAnnotated, KSModifierListOwner {
+
+ /**
+ * Underlying element of this type reference, without annotations and modifiers.
+ */
+ val element: KSReferenceElement?
+
+ /**
+ * Resolves to the original declaration site.
+ * @return A type resolved from this type reference.
+ * Calling [resolve] is expensive and should be avoided if possible.
+ */
+ fun resolve(): KSType
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSValueArgument.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSValueArgument.kt
new file mode 100644
index 00000000..f303bfe7
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSValueArgument.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A value argument to function / constructor calls.
+ *
+ * Currently, only appears in annotation arguments.
+ */
+interface KSValueArgument : KSAnnotated {
+ /**
+ * The name for the named argument, or null otherwise.
+ *
+ * For example, in `ignore(name=123456)`, the name value is "name"
+ */
+ val name: KSName?
+
+ /**
+ * True if it is a spread argument (i.e., has a "*" in front of the argument).
+ */
+ val isSpread: Boolean
+
+ /**
+ * The value of the argument.
+ */
+ val value: Any?
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSValueParameter.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSValueParameter.kt
new file mode 100644
index 00000000..f6e5a23e
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSValueParameter.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A value parameter
+ */
+interface KSValueParameter : KSAnnotated {
+ /**
+ * Name of the parameter
+ */
+ val name: KSName?
+
+ /**
+ * The reference to the type of the parameter.
+ */
+ val type: KSTypeReference
+
+ /**
+ * True if it is a vararg.
+ */
+ val isVararg: Boolean
+
+ /**
+ * True if it has the `noinline` modifier
+ */
+ val isNoInline: Boolean
+
+ /**
+ * True if it has the `crossinline` modifier
+ */
+ val isCrossInline: Boolean
+
+ /**
+ * True if it is a value
+ */
+ val isVal: Boolean
+
+ /**
+ * True if it is a variable
+ */
+ val isVar: Boolean
+
+ /**
+ * True if it has a default value
+ */
+ val hasDefault: Boolean
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSVisitor.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSVisitor.kt
new file mode 100644
index 00000000..6ec4ca1f
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSVisitor.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A visitor for program elements
+ */
+interface KSVisitor<D, R> {
+ fun visitNode(node: KSNode, data: D): R
+
+ fun visitAnnotated(annotated: KSAnnotated, data: D): R
+
+ fun visitAnnotation(annotation: KSAnnotation, data: D): R
+
+ fun visitModifierListOwner(modifierListOwner: KSModifierListOwner, data: D): R
+
+ fun visitDeclaration(declaration: KSDeclaration, data: D): R
+
+ fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: D): R
+
+ fun visitDynamicReference(reference: KSDynamicReference, data: D): R
+
+ fun visitFile(file: KSFile, data: D): R
+
+ fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: D): R
+
+ fun visitCallableReference(reference: KSCallableReference, data: D): R
+
+ fun visitParenthesizedReference(reference: KSParenthesizedReference, data: D): R
+
+ fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: D): R
+
+ fun visitPropertyAccessor(accessor: KSPropertyAccessor, data: D): R
+
+ fun visitPropertyGetter(getter: KSPropertyGetter, data: D): R
+
+ fun visitPropertySetter(setter: KSPropertySetter, data: D): R
+
+ fun visitReferenceElement(element: KSReferenceElement, data: D): R
+
+ fun visitTypeAlias(typeAlias: KSTypeAlias, data: D): R
+
+ fun visitTypeArgument(typeArgument: KSTypeArgument, data: D): R
+
+ fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: D): R
+
+ fun visitTypeParameter(typeParameter: KSTypeParameter, data: D): R
+
+ fun visitTypeReference(typeReference: KSTypeReference, data: D): R
+
+ fun visitValueParameter(valueParameter: KSValueParameter, data: D): R
+
+ fun visitValueArgument(valueArgument: KSValueArgument, data: D): R
+
+ fun visitClassifierReference(reference: KSClassifierReference, data: D): R
+
+ fun visitDefNonNullReference(reference: KSDefNonNullReference, data: D): R
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSVisitorVoid.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSVisitorVoid.kt
new file mode 100644
index 00000000..1e729d95
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/KSVisitorVoid.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * A visitor that doesn't pass or return anything.
+ */
+open class KSVisitorVoid : KSVisitor<Unit, Unit> {
+ override fun visitNode(node: KSNode, data: Unit) {
+ }
+
+ override fun visitAnnotated(annotated: KSAnnotated, data: Unit) {
+ }
+
+ override fun visitAnnotation(annotation: KSAnnotation, data: Unit) {
+ }
+
+ override fun visitModifierListOwner(modifierListOwner: KSModifierListOwner, data: Unit) {
+ }
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: Unit) {
+ }
+
+ override fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: Unit) {
+ }
+
+ override fun visitDynamicReference(reference: KSDynamicReference, data: Unit) {
+ }
+
+ override fun visitFile(file: KSFile, data: Unit) {
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ }
+
+ override fun visitCallableReference(reference: KSCallableReference, data: Unit) {
+ }
+
+ override fun visitParenthesizedReference(reference: KSParenthesizedReference, data: Unit) {
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ }
+
+ override fun visitPropertyAccessor(accessor: KSPropertyAccessor, data: Unit) {
+ }
+
+ override fun visitPropertyGetter(getter: KSPropertyGetter, data: Unit) {
+ }
+
+ override fun visitPropertySetter(setter: KSPropertySetter, data: Unit) {
+ }
+
+ override fun visitClassifierReference(reference: KSClassifierReference, data: Unit) {
+ }
+
+ override fun visitReferenceElement(element: KSReferenceElement, data: Unit) {
+ }
+
+ override fun visitTypeAlias(typeAlias: KSTypeAlias, data: Unit) {
+ }
+
+ override fun visitTypeArgument(typeArgument: KSTypeArgument, data: Unit) {
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ }
+
+ override fun visitTypeParameter(typeParameter: KSTypeParameter, data: Unit) {
+ }
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: Unit) {
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: Unit) {
+ }
+
+ override fun visitValueArgument(valueArgument: KSValueArgument, data: Unit) {
+ }
+
+ override fun visitDefNonNullReference(reference: KSDefNonNullReference, data: Unit) {
+ }
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/Location.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/Location.kt
new file mode 100644
index 00000000..7167dc88
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/Location.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+sealed class Location
+
+data class FileLocation(val filePath: String, val lineNumber: Int) : Location()
+
+object NonExistLocation : Location()
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/Modifier.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/Modifier.kt
new file mode 100644
index 00000000..d38053f0
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/Modifier.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * All possible modifiers presented in the Kotlin grammar.
+ * Modifiers you can get from a declaration are explict modifiers as they are declared in source code.
+ * Same modifier can be semantically different in different languages, therefore you should only rely on modifiers if you have a good
+ * understanding of what it means in specific cases, otherwise you should rely on helper functions like isOpen() for modifier related logic.
+ * Modifiers prefixed with "JAVA_" are java only modifiers.
+ */
+enum class Modifier {
+ PUBLIC, PRIVATE, INTERNAL, PROTECTED,
+ IN, OUT,
+ OVERRIDE, LATEINIT,
+ ENUM, SEALED, ANNOTATION, DATA, INNER, FUN, VALUE,
+ SUSPEND, TAILREC, OPERATOR, INFIX, INLINE, EXTERNAL,
+ ABSTRACT, FINAL, OPEN, CONST,
+ VARARG, NOINLINE, CROSSINLINE,
+ REIFIED,
+ EXPECT, ACTUAL,
+ JAVA_DEFAULT, JAVA_NATIVE, JAVA_STATIC, JAVA_STRICT, JAVA_SYNCHRONIZED, JAVA_TRANSIENT, JAVA_VOLATILE
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/Nullability.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/Nullability.kt
new file mode 100644
index 00000000..39a594e5
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/Nullability.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * Nullability of types
+ * PLATFORM types can be nullable or not nullable, depending on context.
+ */
+enum class Nullability {
+ NULLABLE,
+ NOT_NULL,
+ PLATFORM
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/Origin.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/Origin.kt
new file mode 100644
index 00000000..ac301a7d
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/Origin.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+enum class Origin {
+ KOTLIN,
+ KOTLIN_LIB,
+ JAVA,
+ JAVA_LIB,
+ SYNTHETIC
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/Variance.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/Variance.kt
new file mode 100644
index 00000000..daf525cd
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/Variance.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * Represents both declaration-site and use-site variance.
+ * STAR is only used and valid in use-site variance, while others can be used in both.
+ */
+enum class Variance(val label: String) {
+ STAR("*"),
+ INVARIANT(""),
+ COVARIANT("out"),
+ CONTRAVARIANT("in");
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/symbol/Visibility.kt b/api/src/main/kotlin/com/google/devtools/ksp/symbol/Visibility.kt
new file mode 100644
index 00000000..76afecdb
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/symbol/Visibility.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol
+
+/**
+ * Visibility of the element
+ */
+enum class Visibility {
+ PUBLIC,
+ PRIVATE,
+ PROTECTED,
+ INTERNAL,
+ LOCAL,
+ JAVA_PACKAGE,
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/utils.kt b/api/src/main/kotlin/com/google/devtools/ksp/utils.kt
new file mode 100644
index 00000000..bdbd7934
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/utils.kt
@@ -0,0 +1,519 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSValidateVisitor
+import java.lang.reflect.InvocationHandler
+import java.lang.reflect.Method
+import java.lang.reflect.Proxy
+import java.util.concurrent.ConcurrentHashMap
+import kotlin.reflect.KClass
+
+/**
+ * Try to resolve the [KSClassDeclaration] for a class using its fully qualified name.
+ *
+ * @param T The class to resolve a [KSClassDeclaration] for.
+ * @return Resolved [KSClassDeclaration] if found, `null` otherwise.
+ *
+ * @see [Resolver.getClassDeclarationByName]
+ */
+inline fun <reified T> Resolver.getClassDeclarationByName(): KSClassDeclaration? {
+ return T::class.qualifiedName?.let { fqcn ->
+ getClassDeclarationByName(getKSNameFromString(fqcn))
+ }
+}
+
+/**
+ * Find a class in the compilation classpath for the given name.
+ *
+ * @param name fully qualified name of the class to be loaded; using '.' as separator.
+ * @return a KSClassDeclaration, or null if not found.
+ */
+fun Resolver.getClassDeclarationByName(name: String): KSClassDeclaration? =
+ getClassDeclarationByName(getKSNameFromString(name))
+
+/**
+ * Find functions in the compilation classpath for the given name.
+ *
+ * @param name fully qualified name of the function to be loaded; using '.' as separator.
+ * @param includeTopLevel a boolean value indicate if top level functions should be searched. Default false. Note if top level functions are included, this operation can be expensive.
+ * @return a Sequence of KSFunctionDeclaration.
+ */
+fun Resolver.getFunctionDeclarationsByName(
+ name: String,
+ includeTopLevel: Boolean = false
+): Sequence<KSFunctionDeclaration> = getFunctionDeclarationsByName(getKSNameFromString(name), includeTopLevel)
+
+/**
+ * Find a property in the compilation classpath for the given name.
+ *
+ * @param name fully qualified name of the property to be loaded; using '.' as separator.
+ * @param includeTopLevel a boolean value indicate if top level properties should be searched. Default false. Note if top level properties are included, this operation can be expensive.
+ * @return a KSPropertyDeclaration, or null if not found.
+ */
+fun Resolver.getPropertyDeclarationByName(name: String, includeTopLevel: Boolean = false): KSPropertyDeclaration? =
+ getPropertyDeclarationByName(getKSNameFromString(name), includeTopLevel)
+
+/**
+ * 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.
+ */
+val KSNode.containingFile: KSFile?
+ get() {
+ var parent = this.parent
+ while (parent != null && parent !is KSFile) {
+ parent = parent.parent
+ }
+ return parent as? KSFile?
+ }
+
+/**
+ * Get functions directly declared inside the class declaration.
+ *
+ * What are included: member functions, constructors, extension functions declared inside it, etc.
+ * What are NOT included: inherited functions, extension functions declared outside it.
+ */
+fun KSClassDeclaration.getDeclaredFunctions(): Sequence<KSFunctionDeclaration> {
+ return this.declarations.filterIsInstance<KSFunctionDeclaration>()
+}
+
+/**
+ * Get properties directly declared inside the class declaration.
+ *
+ * What are included: member properties, extension properties declared inside it, etc.
+ * What are NOT included: inherited properties, extension properties declared outside it.
+ */
+fun KSClassDeclaration.getDeclaredProperties(): Sequence<KSPropertyDeclaration> {
+ return this.declarations.filterIsInstance<KSPropertyDeclaration>()
+}
+
+fun KSClassDeclaration.getConstructors(): Sequence<KSFunctionDeclaration> {
+ return getDeclaredFunctions().filter {
+ it.isConstructor()
+ }
+}
+
+/**
+ * Check whether this is a local declaration, or namely, declared in a function.
+ */
+fun KSDeclaration.isLocal(): Boolean {
+ return this.parentDeclaration != null && this.parentDeclaration !is KSClassDeclaration
+}
+
+/**
+ * Perform a validation on a given symbol to check if all interested types in symbols enclosed scope are valid, i.e. resolvable.
+ * @param predicate: A lambda for filtering interested symbols for performance purpose. Default checks all.
+ */
+fun KSNode.validate(predicate: (KSNode?, KSNode) -> Boolean = { _, _ -> true }): Boolean {
+ return this.accept(KSValidateVisitor(predicate), null)
+}
+
+/**
+ * Find the KSClassDeclaration that the alias points to recursively.
+ */
+fun KSTypeAlias.findActualType(): KSClassDeclaration {
+ val resolvedType = this.type.resolve().declaration
+ return if (resolvedType is KSTypeAlias) {
+ resolvedType.findActualType()
+ } else {
+ resolvedType as KSClassDeclaration
+ }
+}
+
+/**
+ * Determine [Visibility] of a [KSDeclaration].
+ */
+fun KSDeclaration.getVisibility(): Visibility {
+ return when {
+ this.modifiers.contains(Modifier.PUBLIC) -> Visibility.PUBLIC
+ this.modifiers.contains(Modifier.OVERRIDE) -> {
+ when (this) {
+ is KSFunctionDeclaration -> this.findOverridee()?.getVisibility()
+ is KSPropertyDeclaration -> this.findOverridee()?.getVisibility()
+ else -> null
+ } ?: Visibility.PUBLIC
+ }
+ this.isLocal() -> Visibility.LOCAL
+ this.modifiers.contains(Modifier.PRIVATE) -> Visibility.PRIVATE
+ this.modifiers.contains(Modifier.PROTECTED) ||
+ this.modifiers.contains(Modifier.OVERRIDE) -> Visibility.PROTECTED
+ this.modifiers.contains(Modifier.INTERNAL) -> Visibility.INTERNAL
+ else -> if (this.origin != Origin.JAVA && this.origin != Origin.JAVA_LIB)
+ Visibility.PUBLIC else Visibility.JAVA_PACKAGE
+ }
+}
+
+/**
+ * get all super types for a class declaration
+ * Calling [getAllSuperTypes] requires type resolution therefore is expensive and should be avoided if possible.
+ */
+fun KSClassDeclaration.getAllSuperTypes(): Sequence<KSType> {
+
+ fun KSTypeParameter.getTypesUpperBound(): Sequence<KSClassDeclaration> =
+ this.bounds.asSequence().flatMap {
+ when (val resolvedDeclaration = it.resolve().declaration) {
+ is KSClassDeclaration -> sequenceOf(resolvedDeclaration)
+ is KSTypeAlias -> sequenceOf(resolvedDeclaration.findActualType())
+ is KSTypeParameter -> resolvedDeclaration.getTypesUpperBound()
+ else -> throw IllegalStateException("unhandled type parameter bound, $ExceptionMessage")
+ }
+ }
+
+ return this.superTypes
+ .asSequence()
+ .map { it.resolve() }
+ .plus(
+ this.superTypes
+ .asSequence()
+ .mapNotNull { it.resolve().declaration }
+ .flatMap {
+ when (it) {
+ is KSClassDeclaration -> it.getAllSuperTypes()
+ is KSTypeAlias -> it.findActualType().getAllSuperTypes()
+ is KSTypeParameter -> it.getTypesUpperBound().flatMap { it.getAllSuperTypes() }
+ else -> throw IllegalStateException("unhandled super type kind, $ExceptionMessage")
+ }
+ }
+ )
+ .distinct()
+}
+
+fun KSClassDeclaration.isAbstract() =
+ this.classKind == ClassKind.INTERFACE || this.modifiers.contains(Modifier.ABSTRACT)
+
+fun KSPropertyDeclaration.isAbstract(): Boolean {
+ if (modifiers.contains(Modifier.ABSTRACT)) {
+ return true
+ }
+ val parentClass = parentDeclaration as? KSClassDeclaration ?: return false
+ if (parentClass.classKind != ClassKind.INTERFACE) return false
+ // this is abstract if it does not have setter/getter or setter/getter have abstract modifiers
+ return (getter?.modifiers?.contains(Modifier.ABSTRACT) ?: true) &&
+ (setter?.modifiers?.contains(Modifier.ABSTRACT) ?: true)
+}
+
+fun KSDeclaration.isOpen() = !this.isLocal() &&
+ (
+ (this as? KSClassDeclaration)?.classKind == ClassKind.INTERFACE ||
+ this.modifiers.contains(Modifier.OVERRIDE) ||
+ this.modifiers.contains(Modifier.ABSTRACT) ||
+ this.modifiers.contains(Modifier.OPEN) ||
+ this.modifiers.contains(Modifier.SEALED) ||
+ (
+ this !is KSClassDeclaration &&
+ (this.parentDeclaration as? KSClassDeclaration)?.classKind == ClassKind.INTERFACE
+ ) ||
+ (!this.modifiers.contains(Modifier.FINAL) && this.origin == Origin.JAVA)
+ )
+
+fun KSDeclaration.isPublic() = this.getVisibility() == Visibility.PUBLIC
+
+fun KSDeclaration.isProtected() = this.getVisibility() == Visibility.PROTECTED
+
+fun KSDeclaration.isInternal() = this.modifiers.contains(Modifier.INTERNAL)
+
+fun KSDeclaration.isPrivate() = this.modifiers.contains(Modifier.PRIVATE)
+
+fun KSDeclaration.isJavaPackagePrivate() = this.getVisibility() == Visibility.JAVA_PACKAGE
+
+fun KSDeclaration.closestClassDeclaration(): KSClassDeclaration? {
+ return if (this is KSClassDeclaration) {
+ this
+ } else {
+ this.parentDeclaration?.closestClassDeclaration()
+ }
+}
+
+// TODO: cross module visibility is not handled
+fun KSDeclaration.isVisibleFrom(other: KSDeclaration): Boolean {
+ fun KSDeclaration.isSamePackage(other: KSDeclaration): Boolean =
+ this.packageName == other.packageName
+
+ // lexical scope for local declaration.
+ fun KSDeclaration.parentDeclarationsForLocal(): List<KSDeclaration> {
+ val parents = mutableListOf<KSDeclaration>()
+
+ var parentDeclaration = this.parentDeclaration!!
+
+ while (parentDeclaration.isLocal()) {
+ parents.add(parentDeclaration)
+ parentDeclaration = parentDeclaration.parentDeclaration!!
+ }
+
+ parents.add(parentDeclaration)
+
+ return parents
+ }
+
+ fun KSDeclaration.isVisibleInPrivate(other: KSDeclaration) =
+ (other.isLocal() && other.parentDeclarationsForLocal().contains(this.parentDeclaration)) ||
+ this.parentDeclaration == other.parentDeclaration ||
+ this.parentDeclaration == other || (
+ this.parentDeclaration == null &&
+ other.parentDeclaration == null &&
+ this.containingFile == other.containingFile
+ )
+
+ return when {
+ // locals are limited to lexical scope
+ this.isLocal() -> this.parentDeclarationsForLocal().contains(other)
+ // file visibility or member
+ // TODO: address nested class.
+ this.isPrivate() -> this.isVisibleInPrivate(other)
+ this.isPublic() -> true
+ this.isInternal() && other.containingFile != null && this.containingFile != null -> true
+ this.isJavaPackagePrivate() -> this.isSamePackage(other)
+ this.isProtected() -> this.isVisibleInPrivate(other) || this.isSamePackage(other) ||
+ other.closestClassDeclaration()?.let {
+ this.closestClassDeclaration()!!.asStarProjectedType().isAssignableFrom(it.asStarProjectedType())
+ } ?: false
+ else -> false
+ }
+}
+
+/**
+ * Returns `true` if this is a constructor function.
+ */
+fun KSFunctionDeclaration.isConstructor() = this.simpleName.asString() == "<init>"
+
+const val ExceptionMessage = "please file a bug at https://github.com/google/ksp/issues/new"
+
+val KSType.outerType: KSType?
+ get() {
+ if (Modifier.INNER !in declaration.modifiers)
+ return null
+ val outerDecl = declaration.parentDeclaration as? KSClassDeclaration ?: return null
+ return outerDecl.asType(arguments.subList(declaration.typeParameters.size, arguments.size))
+ }
+
+val KSType.innerArguments: List<KSTypeArgument>
+ get() = arguments.subList(0, declaration.typeParameters.size)
+
+@KspExperimental
+fun Resolver.getKotlinClassByName(name: KSName): KSClassDeclaration? {
+ val kotlinName = mapJavaNameToKotlin(name) ?: name
+ return getClassDeclarationByName(kotlinName)
+}
+
+@KspExperimental
+fun Resolver.getKotlinClassByName(name: String): KSClassDeclaration? =
+ getKotlinClassByName(getKSNameFromString(name))
+
+@KspExperimental
+fun Resolver.getJavaClassByName(name: KSName): KSClassDeclaration? {
+ val javaName = mapKotlinNameToJava(name) ?: name
+ return getClassDeclarationByName(javaName)
+}
+
+@KspExperimental
+fun Resolver.getJavaClassByName(name: String): KSClassDeclaration? =
+ getJavaClassByName(getKSNameFromString(name))
+
+@KspExperimental
+fun <T : Annotation> KSAnnotated.getAnnotationsByType(annotationKClass: KClass<T>): Sequence<T> {
+ return this.annotations.filter {
+ it.shortName.getShortName() == annotationKClass.simpleName && it.annotationType.resolve().declaration
+ .qualifiedName?.asString() == annotationKClass.qualifiedName
+ }.map { it.toAnnotation(annotationKClass.java) }
+}
+
+@KspExperimental
+fun <T : Annotation> KSAnnotated.isAnnotationPresent(annotationKClass: KClass<T>): Boolean =
+ getAnnotationsByType(annotationKClass).firstOrNull() != null
+
+@KspExperimental
+@Suppress("UNCHECKED_CAST")
+private fun <T : Annotation> KSAnnotation.toAnnotation(annotationClass: Class<T>): T {
+ return Proxy.newProxyInstance(
+ annotationClass.classLoader,
+ arrayOf(annotationClass),
+ createInvocationHandler(annotationClass)
+ ) as T
+}
+
+@KspExperimental
+@Suppress("TooGenericExceptionCaught")
+private fun KSAnnotation.createInvocationHandler(clazz: Class<*>): InvocationHandler {
+ val cache = ConcurrentHashMap<Pair<Class<*>, Any>, Any>(arguments.size)
+ return InvocationHandler { proxy, method, _ ->
+ if (method.name == "toString" && arguments.none { it.name?.asString() == "toString" }) {
+ clazz.canonicalName +
+ arguments.map { argument: KSValueArgument ->
+ // handles default values for enums otherwise returns null
+ val methodName = argument.name?.asString()
+ val value = proxy.javaClass.methods.find { m -> m.name == methodName }?.invoke(proxy)
+ "$methodName=$value"
+ }.toList()
+ } else {
+ val argument = arguments.first { it.name?.asString() == method.name }
+ when (val result = argument.value ?: method.defaultValue) {
+ is Proxy -> result
+ is List<*> -> {
+ val value = { result.asArray(method, clazz) }
+ cache.getOrPut(Pair(method.returnType, result), value)
+ }
+ else -> {
+ when {
+ method.returnType.isEnum -> {
+ val value = { result.asEnum(method.returnType) }
+ cache.getOrPut(Pair(method.returnType, result), value)
+ }
+ method.returnType.isAnnotation -> {
+ val value = { (result as KSAnnotation).asAnnotation(method.returnType) }
+ cache.getOrPut(Pair(method.returnType, result), value)
+ }
+ method.returnType.name == "java.lang.Class" -> {
+ cache.getOrPut(Pair(method.returnType, result)) {
+ when (result) {
+ is KSType -> result.asClass(clazz)
+ // Handles com.intellij.psi.impl.source.PsiImmediateClassType using reflection
+ // since api doesn't contain a reference to this
+ else -> Class.forName(
+ result.javaClass.methods
+ .first { it.name == "getCanonicalText" }
+ .invoke(result, false) as String
+ )
+ }
+ }
+ }
+ method.returnType.name == "byte" -> {
+ val value = { result.asByte() }
+ cache.getOrPut(Pair(method.returnType, result), value)
+ }
+ method.returnType.name == "short" -> {
+ val value = { result.asShort() }
+ cache.getOrPut(Pair(method.returnType, result), value)
+ }
+ method.returnType.name == "long" -> {
+ val value = { result.asLong() }
+ cache.getOrPut(Pair(method.returnType, result), value)
+ }
+ method.returnType.name == "float" -> {
+ val value = { result.asFloat() }
+ cache.getOrPut(Pair(method.returnType, result), value)
+ }
+ method.returnType.name == "double" -> {
+ val value = { result.asDouble() }
+ cache.getOrPut(Pair(method.returnType, result), value)
+ }
+ else -> result // original value
+ }
+ }
+ }
+ }
+ }
+}
+
+@KspExperimental
+@Suppress("UNCHECKED_CAST")
+private fun KSAnnotation.asAnnotation(
+ annotationInterface: Class<*>,
+): Any {
+ return Proxy.newProxyInstance(
+ annotationInterface.classLoader, arrayOf(annotationInterface),
+ this.createInvocationHandler(annotationInterface)
+ ) as Proxy
+}
+
+@KspExperimental
+@Suppress("UNCHECKED_CAST")
+private fun List<*>.asArray(method: Method, proxyClass: Class<*>) =
+ when (method.returnType.componentType.name) {
+ "boolean" -> (this as List<Boolean>).toBooleanArray()
+ "byte" -> (this as List<Byte>).toByteArray()
+ "short" -> (this as List<Short>).toShortArray()
+ "char" -> (this as List<Char>).toCharArray()
+ "double" -> (this as List<Double>).toDoubleArray()
+ "float" -> (this as List<Float>).toFloatArray()
+ "int" -> (this as List<Int>).toIntArray()
+ "long" -> (this as List<Long>).toLongArray()
+ "java.lang.Class" -> (this as List<KSType>).asClasses(proxyClass).toTypedArray()
+ "java.lang.String" -> (this as List<String>).toTypedArray()
+ else -> { // arrays of enums or annotations
+ when {
+ method.returnType.componentType.isEnum -> {
+ this.toArray(method) { result -> result.asEnum(method.returnType.componentType) }
+ }
+ method.returnType.componentType.isAnnotation -> {
+ this.toArray(method) { result ->
+ (result as KSAnnotation).asAnnotation(method.returnType.componentType)
+ }
+ }
+ else -> throw IllegalStateException("Unable to process type ${method.returnType.componentType.name}")
+ }
+ }
+ }
+
+@Suppress("UNCHECKED_CAST")
+private fun List<*>.toArray(method: Method, valueProvider: (Any) -> Any): Array<Any?> {
+ val array: Array<Any?> = java.lang.reflect.Array.newInstance(
+ method.returnType.componentType,
+ this.size
+ ) as Array<Any?>
+ for (r in 0 until this.size) {
+ array[r] = this[r]?.let { valueProvider.invoke(it) }
+ }
+ return array
+}
+
+@Suppress("UNCHECKED_CAST")
+private fun <T> Any.asEnum(returnType: Class<T>): T =
+ returnType.getDeclaredMethod("valueOf", String::class.java)
+ .invoke(
+ null,
+ if (this is KSType) {
+ this.declaration.simpleName.getShortName()
+ } else {
+ this.toString()
+ }
+ ) as T
+
+private fun Any.asByte(): Byte = if (this is Int) this.toByte() else this as Byte
+
+private fun Any.asShort(): Short = if (this is Int) this.toShort() else this as Short
+
+private fun Any.asLong(): Long = if (this is Int) this.toLong() else this as Long
+
+private fun Any.asFloat(): Float = if (this is Int) this.toFloat() else this as Float
+
+private fun Any.asDouble(): Double = if (this is Int) this.toDouble() else this as Double
+
+// for Class/KClass member
+@KspExperimental
+class KSTypeNotPresentException(val ksType: KSType, cause: Throwable) : RuntimeException(cause)
+// for Class[]/Array<KClass<*>> member.
+@KspExperimental
+class KSTypesNotPresentException(val ksTypes: List<KSType>, cause: Throwable) : RuntimeException(cause)
+
+@KspExperimental
+private fun KSType.asClass(proxyClass: Class<*>) = try {
+ Class.forName(this.declaration.qualifiedName!!.asString(), true, proxyClass.classLoader)
+} catch (e: Exception) {
+ throw KSTypeNotPresentException(this, e)
+}
+
+@KspExperimental
+private fun List<KSType>.asClasses(proxyClass: Class<*>) = try {
+ this.map { type -> type.asClass(proxyClass) }
+} catch (e: Exception) {
+ throw KSTypesNotPresentException(this, e)
+}
+
+fun KSValueArgument.isDefault() = origin == Origin.SYNTHETIC
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/visitor/KSDefaultVisitor.kt b/api/src/main/kotlin/com/google/devtools/ksp/visitor/KSDefaultVisitor.kt
new file mode 100644
index 00000000..19ea484f
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/visitor/KSDefaultVisitor.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.visitor
+
+import com.google.devtools.ksp.symbol.*
+
+/**
+ * A visitor that delegates to super types for methods that are not overridden.
+ */
+abstract class KSDefaultVisitor<D, R> : KSEmptyVisitor<D, R>() {
+ override fun visitDynamicReference(reference: KSDynamicReference, data: D): R {
+ this.visitReferenceElement(reference, data)
+ return super.visitDynamicReference(reference, data)
+ }
+
+ override fun visitFile(file: KSFile, data: D): R {
+ this.visitAnnotated(file, data)
+ this.visitDeclarationContainer(file, data)
+ return super.visitFile(file, data)
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: D): R {
+ this.visitDeclaration(function, data)
+ this.visitDeclarationContainer(function, data)
+ return super.visitFunctionDeclaration(function, data)
+ }
+
+ override fun visitCallableReference(reference: KSCallableReference, data: D): R {
+ this.visitReferenceElement(reference, data)
+ return super.visitCallableReference(reference, data)
+ }
+
+ override fun visitParenthesizedReference(reference: KSParenthesizedReference, data: D): R {
+ this.visitReferenceElement(reference, data)
+ return super.visitParenthesizedReference(reference, data)
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: D): R {
+ this.visitDeclaration(property, data)
+ return super.visitPropertyDeclaration(property, data)
+ }
+
+ override fun visitPropertyAccessor(accessor: KSPropertyAccessor, data: D): R {
+ this.visitModifierListOwner(accessor, data)
+ this.visitAnnotated(accessor, data)
+ return super.visitPropertyAccessor(accessor, data)
+ }
+
+ override fun visitPropertyGetter(getter: KSPropertyGetter, data: D): R {
+ this.visitPropertyAccessor(getter, data)
+ return super.visitPropertyGetter(getter, data)
+ }
+
+ override fun visitPropertySetter(setter: KSPropertySetter, data: D): R {
+ this.visitPropertyAccessor(setter, data)
+ return super.visitPropertySetter(setter, data)
+ }
+
+ override fun visitTypeAlias(typeAlias: KSTypeAlias, data: D): R {
+ this.visitDeclaration(typeAlias, data)
+ return super.visitTypeAlias(typeAlias, data)
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: D): R {
+ this.visitDeclaration(classDeclaration, data)
+ this.visitDeclarationContainer(classDeclaration, data)
+ return super.visitClassDeclaration(classDeclaration, data)
+ }
+
+ override fun visitTypeParameter(typeParameter: KSTypeParameter, data: D): R {
+ this.visitDeclaration(typeParameter, data)
+ return super.visitTypeParameter(typeParameter, data)
+ }
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: D): R {
+ this.visitAnnotated(typeReference, data)
+ this.visitModifierListOwner(typeReference, data)
+ return super.visitTypeReference(typeReference, data)
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: D): R {
+ this.visitAnnotated(valueParameter, data)
+ return super.visitValueParameter(valueParameter, data)
+ }
+
+ override fun visitValueArgument(valueArgument: KSValueArgument, data: D): R {
+ this.visitAnnotated(valueArgument, data)
+ return super.visitValueArgument(valueArgument, data)
+ }
+
+ override fun visitClassifierReference(reference: KSClassifierReference, data: D): R {
+ this.visitReferenceElement(reference, data)
+ return super.visitClassifierReference(reference, data)
+ }
+
+ override fun visitDefNonNullReference(reference: KSDefNonNullReference, data: D): R {
+ this.visitReferenceElement(reference, data)
+ return super.visitDefNonNullReference(reference, data)
+ }
+
+ override fun visitTypeArgument(typeArgument: KSTypeArgument, data: D): R {
+ this.visitAnnotated(typeArgument, data)
+ return super.visitTypeArgument(typeArgument, data)
+ }
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: D): R {
+ this.visitAnnotated(declaration, data)
+ this.visitModifierListOwner(declaration, data)
+ return super.visitDeclaration(declaration, data)
+ }
+
+ override fun visitAnnotated(annotated: KSAnnotated, data: D): R {
+ this.visitNode(annotated, data)
+ return super.visitAnnotated(annotated, data)
+ }
+
+ override fun visitAnnotation(annotation: KSAnnotation, data: D): R {
+ this.visitNode(annotation, data)
+ return super.visitAnnotation(annotation, data)
+ }
+
+ override fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: D): R {
+ this.visitNode(declarationContainer, data)
+ return super.visitDeclarationContainer(declarationContainer, data)
+ }
+
+ override fun visitModifierListOwner(modifierListOwner: KSModifierListOwner, data: D): R {
+ this.visitNode(modifierListOwner, data)
+ return super.visitModifierListOwner(modifierListOwner, data)
+ }
+
+ override fun visitReferenceElement(element: KSReferenceElement, data: D): R {
+ this.visitNode(element, data)
+ return super.visitReferenceElement(element, data)
+ }
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/visitor/KSEmptyVisitor.kt b/api/src/main/kotlin/com/google/devtools/ksp/visitor/KSEmptyVisitor.kt
new file mode 100644
index 00000000..4704f81e
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/visitor/KSEmptyVisitor.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.visitor
+
+import com.google.devtools.ksp.symbol.*
+
+/**
+ * A visitor that methods fall back to [defaultHandler] if not overridden.
+ */
+abstract class KSEmptyVisitor<D, R> : KSVisitor<D, R> {
+ abstract fun defaultHandler(node: KSNode, data: D): R
+
+ override fun visitNode(node: KSNode, data: D): R {
+ return defaultHandler(node, data)
+ }
+
+ override fun visitAnnotated(annotated: KSAnnotated, data: D): R {
+ return defaultHandler(annotated, data)
+ }
+
+ override fun visitAnnotation(annotation: KSAnnotation, data: D): R {
+ return defaultHandler(annotation, data)
+ }
+
+ override fun visitModifierListOwner(modifierListOwner: KSModifierListOwner, data: D): R {
+ return defaultHandler(modifierListOwner, data)
+ }
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: D): R {
+ return defaultHandler(declaration, data)
+ }
+
+ override fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: D): R {
+ return defaultHandler(declarationContainer, data)
+ }
+
+ override fun visitDynamicReference(reference: KSDynamicReference, data: D): R {
+ return defaultHandler(reference, data)
+ }
+
+ override fun visitFile(file: KSFile, data: D): R {
+ return defaultHandler(file, data)
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: D): R {
+ return defaultHandler(function, data)
+ }
+
+ override fun visitCallableReference(reference: KSCallableReference, data: D): R {
+ return defaultHandler(reference, data)
+ }
+
+ override fun visitParenthesizedReference(reference: KSParenthesizedReference, data: D): R {
+ return defaultHandler(reference, data)
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: D): R {
+ return defaultHandler(property, data)
+ }
+
+ override fun visitPropertyAccessor(accessor: KSPropertyAccessor, data: D): R {
+ return defaultHandler(accessor, data)
+ }
+
+ override fun visitPropertyGetter(getter: KSPropertyGetter, data: D): R {
+ return defaultHandler(getter, data)
+ }
+
+ override fun visitPropertySetter(setter: KSPropertySetter, data: D): R {
+ return defaultHandler(setter, data)
+ }
+
+ override fun visitClassifierReference(reference: KSClassifierReference, data: D): R {
+ return defaultHandler(reference, data)
+ }
+
+ override fun visitDefNonNullReference(reference: KSDefNonNullReference, data: D): R {
+ return defaultHandler(reference, data)
+ }
+
+ override fun visitReferenceElement(element: KSReferenceElement, data: D): R {
+ return defaultHandler(element, data)
+ }
+
+ override fun visitTypeAlias(typeAlias: KSTypeAlias, data: D): R {
+ return defaultHandler(typeAlias, data)
+ }
+
+ override fun visitTypeArgument(typeArgument: KSTypeArgument, data: D): R {
+ return defaultHandler(typeArgument, data)
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: D): R {
+ return defaultHandler(classDeclaration, data)
+ }
+
+ override fun visitTypeParameter(typeParameter: KSTypeParameter, data: D): R {
+ return defaultHandler(typeParameter, data)
+ }
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: D): R {
+ return defaultHandler(typeReference, data)
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: D): R {
+ return defaultHandler(valueParameter, data)
+ }
+
+ override fun visitValueArgument(valueArgument: KSValueArgument, data: D): R {
+ return defaultHandler(valueArgument, data)
+ }
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/visitor/KSTopDownVisitor.kt b/api/src/main/kotlin/com/google/devtools/ksp/visitor/KSTopDownVisitor.kt
new file mode 100644
index 00000000..23c9736c
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/visitor/KSTopDownVisitor.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.visitor
+
+import com.google.devtools.ksp.symbol.*
+
+/**
+ * Visit all elements recursively.
+ *
+ * For subclasses overriding a function, remember to call the corresponding super method.
+ */
+abstract class KSTopDownVisitor<D, R> : KSDefaultVisitor<D, R>() {
+ private fun Sequence<KSNode>.accept(data: D) {
+ forEach { it.accept(this@KSTopDownVisitor, data) }
+ }
+ private fun List<KSNode>.accept(data: D) {
+ forEach { it.accept(this@KSTopDownVisitor, data) }
+ }
+
+ private fun KSNode.accept(data: D) = accept(this@KSTopDownVisitor, data)
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: D): R {
+ property.type.accept(data)
+ property.extensionReceiver?.accept(data)
+ property.getter?.accept(data)
+ property.setter?.accept(data)
+ return super.visitPropertyDeclaration(property, data)
+ }
+
+ override fun visitAnnotated(annotated: KSAnnotated, data: D): R {
+ annotated.annotations.accept(data)
+ return super.visitAnnotated(annotated, data)
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: D): R {
+ classDeclaration.superTypes.accept(data)
+ return super.visitClassDeclaration(classDeclaration, data)
+ }
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: D): R {
+ declaration.typeParameters.accept(data)
+ return super.visitDeclaration(declaration, data)
+ }
+
+ override fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: D): R {
+ declarationContainer.declarations.accept(data)
+ return super.visitDeclarationContainer(declarationContainer, data)
+ }
+
+ override fun visitAnnotation(annotation: KSAnnotation, data: D): R {
+ annotation.annotationType.accept(data)
+ annotation.arguments.accept(data)
+ return super.visitAnnotation(annotation, data)
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: D): R {
+ function.extensionReceiver?.accept(data)
+ function.parameters.accept(data)
+ function.returnType?.accept(data)
+ return super.visitFunctionDeclaration(function, data)
+ }
+
+ override fun visitCallableReference(reference: KSCallableReference, data: D): R {
+ reference.functionParameters.accept(data)
+ reference.receiverType?.accept(data)
+ reference.returnType.accept(data)
+ return super.visitCallableReference(reference, data)
+ }
+
+ override fun visitParenthesizedReference(reference: KSParenthesizedReference, data: D): R {
+ reference.element.accept(data)
+ return super.visitParenthesizedReference(reference, data)
+ }
+
+ override fun visitPropertyGetter(getter: KSPropertyGetter, data: D): R {
+ getter.returnType?.accept(data)
+ return super.visitPropertyGetter(getter, data)
+ }
+
+ override fun visitPropertySetter(setter: KSPropertySetter, data: D): R {
+ setter.parameter.accept(data)
+ return super.visitPropertySetter(setter, data)
+ }
+
+ override fun visitReferenceElement(element: KSReferenceElement, data: D): R {
+ element.typeArguments.accept(data)
+ return super.visitReferenceElement(element, data)
+ }
+
+ override fun visitTypeAlias(typeAlias: KSTypeAlias, data: D): R {
+ typeAlias.type.accept(data)
+ return super.visitTypeAlias(typeAlias, data)
+ }
+
+ override fun visitTypeArgument(typeArgument: KSTypeArgument, data: D): R {
+ typeArgument.type?.accept(data)
+ return super.visitTypeArgument(typeArgument, data)
+ }
+
+ override fun visitTypeParameter(typeParameter: KSTypeParameter, data: D): R {
+ typeParameter.bounds.accept(data)
+ return super.visitTypeParameter(typeParameter, data)
+ }
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: D): R {
+ typeReference.element?.accept(data)
+ return super.visitTypeReference(typeReference, data)
+ }
+
+ override fun visitClassifierReference(reference: KSClassifierReference, data: D): R {
+ reference.qualifier?.accept(data)
+ return super.visitClassifierReference(reference, data)
+ }
+
+ override fun visitDefNonNullReference(reference: KSDefNonNullReference, data: D): R {
+ reference.enclosedType.accept(data)
+ return super.visitDefNonNullReference(reference, data)
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: D): R {
+ valueParameter.type?.accept(data)
+ return super.visitValueParameter(valueParameter, data)
+ }
+}
diff --git a/api/src/main/kotlin/com/google/devtools/ksp/visitor/KSValidateVisitor.kt b/api/src/main/kotlin/com/google/devtools/ksp/visitor/KSValidateVisitor.kt
new file mode 100644
index 00000000..4947a41f
--- /dev/null
+++ b/api/src/main/kotlin/com/google/devtools/ksp/visitor/KSValidateVisitor.kt
@@ -0,0 +1,114 @@
+package com.google.devtools.ksp.visitor
+
+import com.google.devtools.ksp.symbol.*
+
+open class KSValidateVisitor(
+ private val predicate: (KSNode?, KSNode) -> Boolean
+) : KSDefaultVisitor<KSNode?, Boolean>() {
+ private fun validateType(type: KSType): Boolean {
+ return !type.isError && !type.arguments.any { it.type?.accept(this, null) == false }
+ }
+
+ override fun defaultHandler(node: KSNode, data: KSNode?): Boolean {
+ return true
+ }
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: KSNode?): Boolean {
+ if (!predicate(data, declaration)) {
+ return true
+ }
+ if (declaration.typeParameters.any { !it.accept(this, declaration) }) {
+ return false
+ }
+ return this.visitAnnotated(declaration, data)
+ }
+
+ override fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: KSNode?): Boolean {
+ return declarationContainer.declarations.all {
+ !predicate(declarationContainer, it) || it.accept(
+ this,
+ declarationContainer
+ )
+ }
+ }
+
+ override fun visitTypeParameter(typeParameter: KSTypeParameter, data: KSNode?): Boolean {
+ return !predicate(data, typeParameter) || typeParameter.bounds.all { it.accept(this, typeParameter) }
+ }
+
+ override fun visitAnnotated(annotated: KSAnnotated, data: KSNode?): Boolean {
+ return !predicate(data, annotated) || annotated.annotations.all { it.accept(this, annotated) }
+ }
+
+ override fun visitAnnotation(annotation: KSAnnotation, data: KSNode?): Boolean {
+ if (!predicate(data, annotation)) {
+ return true
+ }
+ if (!annotation.annotationType.accept(this, annotation)) {
+ return false
+ }
+ if (annotation.arguments.any { !it.accept(this, it) }) {
+ return false
+ }
+ return true
+ }
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: KSNode?): Boolean {
+ return validateType(typeReference.resolve())
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: KSNode?): Boolean {
+ if (classDeclaration.asStarProjectedType().isError) {
+ return false
+ }
+ if (!classDeclaration.superTypes.all { it.accept(this, classDeclaration) }) {
+ return false
+ }
+ if (!this.visitDeclaration(classDeclaration, data)) {
+ return false
+ }
+ if (!this.visitDeclarationContainer(classDeclaration, data)) {
+ return false
+ }
+ return true
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: KSNode?): Boolean {
+ if (function.returnType != null &&
+ predicate(function, function.returnType!!) && !function.returnType!!.accept(this, data)
+ ) {
+ return false
+ }
+ if (!function.parameters.all { it.accept(this, function) }) {
+ return false
+ }
+ if (!this.visitDeclaration(function, data)) {
+ return false
+ }
+ return true
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: KSNode?): Boolean {
+ if (predicate(property, property.type) && !property.type.accept(this, data)) {
+ return false
+ }
+ if (!this.visitDeclaration(property, data)) {
+ return false
+ }
+ return true
+ }
+
+ override fun visitValueArgument(valueArgument: KSValueArgument, data: KSNode?): Boolean {
+ fun visitValue(value: Any?): Boolean = when (value) {
+ is KSType -> this.validateType(value)
+ is KSAnnotation -> this.visitAnnotation(value, data)
+ is List<*> -> value.all { visitValue(it) }
+ else -> true
+ }
+ return visitValue(valueArgument.value)
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: KSNode?): Boolean {
+ return valueParameter.type.accept(this, valueParameter)
+ }
+}
diff --git a/benchmark/TachiyomiExhaustive/build.sh b/benchmark/TachiyomiExhaustive/build.sh
new file mode 100755
index 00000000..cadbfa03
--- /dev/null
+++ b/benchmark/TachiyomiExhaustive/build.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Copyright 2022 Google LLC
+#
+# 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.
+#
+
+set -e
+SCRIPT_DIR=$(dirname "$(realpath $0)")
+ROOT=$SCRIPT_DIR/../..
+cd $SCRIPT_DIR
+rm -rf tachiyomi
+git clone https://github.com/inorichi/tachiyomi.git
+cd tachiyomi
+git checkout 938339690eecdfe309d83264b6a89aff3c767687
+git apply $SCRIPT_DIR/tachi.patch
+./gradlew :app:copyDepsDevDebug
+mkdir -p $SCRIPT_DIR/lib && cp app/build/output/devDebug/lib/* $SCRIPT_DIR/lib
diff --git a/benchmark/TachiyomiExhaustive/tachi.patch b/benchmark/TachiyomiExhaustive/tachi.patch
new file mode 100644
index 00000000..0b74d267
--- /dev/null
+++ b/benchmark/TachiyomiExhaustive/tachi.patch
@@ -0,0 +1,55 @@
+diff --git a/app/build.gradle.kts b/app/build.gradle.kts
+index c7d59c166..f8941dbfa 100644
+--- a/app/build.gradle.kts
++++ b/app/build.gradle.kts
+@@ -137,6 +137,7 @@ android {
+ }
+
+ dependencies {
++ implementation("org.jetbrains.kotlin:kotlin-compiler:1.8.0-dev-1390")
+ implementation(kotlin("reflect", version = BuildPluginsVersion.KOTLIN))
+
+ val coroutinesVersion = "1.6.0"
+@@ -350,3 +351,29 @@ fun runCommand(command: String): String {
+ }
+ return String(byteOut.toByteArray()).trim()
+ }
++android.applicationVariants.all {
++ task("copyDeps${name.capitalize()}") {
++ outputs.upToDateWhen { false }
++ doLast {
++ compileConfiguration.forEach {
++ val src = it.absolutePath
++ val jar = if (src.endsWith(".aar")) {
++ zipTree(src).files.single { it.name == "classes.jar" }
++ } else src
++ val dest = "$buildDir/output/${this@all.name}/lib/"
++ copy {
++ from(jar)
++ into(dest)
++ rename { fileName ->
++ if (fileName == "classes.jar") {
++ it.name.dropLastWhile { it != '.' } + "jar"
++ } else if (fileName.contains("-dev-")) {
++ fileName.replace("-1.8.0-dev-1390", "")
++ }
++ else fileName
++ }
++ }
++ }
++ }
++ }
++}
+\ No newline at end of file
+diff --git a/build.gradle.kts b/build.gradle.kts
+index c5607aa82..e274b0455 100644
+--- a/build.gradle.kts
++++ b/build.gradle.kts
+@@ -10,6 +10,7 @@ allprojects {
+ repositories {
+ mavenCentral()
+ google()
++ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ maven { setUrl("https://www.jitpack.io") }
+ }
+ }
diff --git a/benchmark/TachiyomiExhaustive/upload-benchmark-data.sh b/benchmark/TachiyomiExhaustive/upload-benchmark-data.sh
new file mode 100755
index 00000000..b3eba05e
--- /dev/null
+++ b/benchmark/TachiyomiExhaustive/upload-benchmark-data.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# Copyright 2022 Google LLC
+#
+# 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.
+#
+
+set -e
+SCRIPT_DIR=$(dirname "$(realpath $0)")
+cd $SCRIPT_DIR
+TEMP_DIR=$(mktemp -d)
+BUNDLE=$TEMP_DIR/tachiyomi-exhaustive.tar.gz
+tar cfz $BUNDLE tachiyomi lib
+BUNDLE_HASH_AND_NAME=$(sha256sum $BUNDLE)
+BUNDLE_HASH=$(echo $BUNDLE_HASH_AND_NAME | cut -d " " -f 1)
+BUNDLE_UPLOAD_LOCATION=gs://r8-deps/ksp-bench/$BUNDLE_HASH.tar.gz
+BUNDLE_DOWNLOAD_LOCATION=http://storage.googleapis.com/r8-deps/ksp-bench/$BUNDLE_HASH.tar.gz
+echo Uploading to: $BUNDLE_UPLOAD_LOCATION
+gsutil.py cp -a public-read $BUNDLE $BUNDLE_UPLOAD_LOCATION
+echo Available for download at: $BUNDLE_DOWNLOAD_LOCATION
diff --git a/benchmark/build.gradle.kts b/benchmark/build.gradle.kts
new file mode 100644
index 00000000..c4c104fe
--- /dev/null
+++ b/benchmark/build.gradle.kts
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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.
+ */
+import org.gradle.jvm.tasks.Jar
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+ kotlin("jvm") version "1.6.10"
+ application
+}
+repositories {
+ mavenCentral()
+}
+dependencies {
+ implementation(kotlin("stdlib-jdk8"))
+ implementation(kotlin("compiler"))
+}
+application {
+ applicationName = "BenchRunner"
+ group = "com.google.devtools.ksp"
+ mainClassName = "com.google.devtools.ksp.BenchRunner"
+}
+tasks.withType<KotlinCompile> {
+ kotlinOptions.jvmTarget = "1.8"
+}
+tasks.withType<Jar> {
+ manifest {
+ attributes(mapOf("Main-Class" to application.mainClassName))
+ }
+}
diff --git a/benchmark/build.sh b/benchmark/build.sh
new file mode 100755
index 00000000..c7e98f7a
--- /dev/null
+++ b/benchmark/build.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Copyright 2022 Google LLC
+#
+# 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.
+
+set -e
+SCRIPT_DIR=$(dirname "$(realpath $0)")
+ROOT=$SCRIPT_DIR/..
+cd $SCRIPT_DIR
+rm -rf runner/out runner/processor-1.0-SNAPSHOT.jar
+./gradlew :jar
+cd $SCRIPT_DIR/exhaustive-processor
+./gradlew build
+cp processor/build/libs/processor-1.0-SNAPSHOT.jar ../runner/
+cd $ROOT
+./gradlew -PkspVersion=2.0.255 clean publishAllPublicationsToTestRepository
+cp -a build/repos/test/. $ROOT/benchmark/runner
diff --git a/benchmark/exhaustive-processor/.gitignore b/benchmark/exhaustive-processor/.gitignore
new file mode 100644
index 00000000..24184407
--- /dev/null
+++ b/benchmark/exhaustive-processor/.gitignore
@@ -0,0 +1,4 @@
+.gradle/
+.idea/
+build/
+*/build/ \ No newline at end of file
diff --git a/benchmark/exhaustive-processor/build.gradle.kts b/benchmark/exhaustive-processor/build.gradle.kts
new file mode 100644
index 00000000..d9cfe00f
--- /dev/null
+++ b/benchmark/exhaustive-processor/build.gradle.kts
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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.
+ */
+val kspVersion: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.squareup:javapoet:1.12.1")
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
+
diff --git a/benchmark/exhaustive-processor/gradle.properties b/benchmark/exhaustive-processor/gradle.properties
new file mode 100644
index 00000000..40e5ad78
--- /dev/null
+++ b/benchmark/exhaustive-processor/gradle.properties
@@ -0,0 +1,3 @@
+kotlin.code.style=official
+kotlinVersion=1.6.10
+kspVersion=1.6.10-1.0.2 \ No newline at end of file
diff --git a/benchmark/exhaustive-processor/gradle/wrapper/gradle-wrapper.jar b/benchmark/exhaustive-processor/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..e708b1c0
--- /dev/null
+++ b/benchmark/exhaustive-processor/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/benchmark/exhaustive-processor/gradle/wrapper/gradle-wrapper.properties b/benchmark/exhaustive-processor/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..2e6e5897
--- /dev/null
+++ b/benchmark/exhaustive-processor/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/benchmark/exhaustive-processor/gradlew b/benchmark/exhaustive-processor/gradlew
new file mode 100755
index 00000000..4f906e0c
--- /dev/null
+++ b/benchmark/exhaustive-processor/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://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.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/benchmark/exhaustive-processor/gradlew.bat b/benchmark/exhaustive-processor/gradlew.bat
new file mode 100644
index 00000000..ac1b06f9
--- /dev/null
+++ b/benchmark/exhaustive-processor/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/benchmark/exhaustive-processor/processor/build.gradle.kts b/benchmark/exhaustive-processor/processor/build.gradle.kts
new file mode 100644
index 00000000..6adcd47a
--- /dev/null
+++ b/benchmark/exhaustive-processor/processor/build.gradle.kts
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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.
+ */
+plugins {
+ kotlin("jvm")
+ `maven-publish`
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ mavenCentral()
+ google()
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.google.devtools.ksp:symbol-processing-api:1.5.20-1.0.0-beta04")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
+
+publishing {
+ publications {
+ create<MavenPublication>("default") {
+ artifactId = "exhaustive-processor"
+ from(components["java"])
+ }
+ }
+ repositories {
+ mavenLocal()
+ }
+}
diff --git a/benchmark/exhaustive-processor/processor/src/main/kotlin/ExhaustiveProcessor.kt b/benchmark/exhaustive-processor/processor/src/main/kotlin/ExhaustiveProcessor.kt
new file mode 100644
index 00000000..81b29b2f
--- /dev/null
+++ b/benchmark/exhaustive-processor/processor/src/main/kotlin/ExhaustiveProcessor.kt
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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.
+ */
+import com.google.devtools.ksp.isLocal
+import com.google.devtools.ksp.processing.CodeGenerator
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
+import com.google.devtools.ksp.processing.SymbolProcessorProvider
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+import java.io.File
+
+class ExhaustiveProcessor(
+ val codeGenerator: CodeGenerator,
+ val options: Map<String, String>
+) : SymbolProcessor {
+ val file: File? = null
+ override fun finish() {
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ file?.writeText("")
+ val visitor = ExhaustiveVisitor()
+ resolver.getAllFiles().forEach { it.accept(visitor, Unit) }
+ file?.appendText(visitor.collectedNodes.joinToString("\n"))
+ return emptyList()
+ }
+
+ inner class ExhaustiveVisitor : KSTopDownVisitor<Unit, Unit>() {
+ val collectedNodes = mutableListOf<String>()
+
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ file?.appendText("--- visiting ${node.location} ---\n")
+ }
+
+ override fun visitAnnotated(annotated: KSAnnotated, data: Unit) {
+ super.visitAnnotated(annotated, data)
+ }
+
+ override fun visitAnnotation(annotation: KSAnnotation, data: Unit) {
+ file?.appendText("ANNO: ${annotation.shortName}")
+ annotation.shortName
+ annotation.useSiteTarget
+ super.visitAnnotation(annotation, data)
+ }
+
+ override fun visitCallableReference(reference: KSCallableReference, data: Unit) {
+ super.visitCallableReference(reference, data)
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ classDeclaration.classKind
+ classDeclaration.primaryConstructor?.accept(this, Unit)
+ classDeclaration.isCompanionObject
+ classDeclaration.getAllFunctions().map { it.accept(this, Unit) }
+ classDeclaration.getAllProperties().map { it.accept(this, Unit) }
+ classDeclaration.asStarProjectedType()
+ if (classDeclaration.origin != Origin.KOTLIN_LIB && classDeclaration.origin != Origin.JAVA_LIB) {
+ classDeclaration.superTypes.map { it.accept(this, Unit) }
+ }
+ return super.visitClassDeclaration(classDeclaration, data)
+ }
+
+ override fun visitClassifierReference(reference: KSClassifierReference, data: Unit) {
+ reference.referencedName()
+ super.visitClassifierReference(reference, data)
+ }
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: Unit) {
+ declaration.containingFile
+ declaration.packageName
+ declaration.qualifiedName
+ declaration.simpleName
+ declaration.parentDeclaration
+ super.visitDeclaration(declaration, data)
+ }
+
+ override fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: Unit) {
+ super.visitDeclarationContainer(declarationContainer, data)
+ }
+
+ override fun visitDynamicReference(reference: KSDynamicReference, data: Unit) {
+ super.visitDynamicReference(reference, data)
+ }
+
+ override fun visitFile(file: KSFile, data: Unit) {
+ file.fileName
+ file.packageName
+ file.filePath
+ super.visitFile(file, data)
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ function.functionKind
+ function.isAbstract
+ function.findOverridee()
+ super.visitFunctionDeclaration(function, data)
+ }
+
+ override fun visitModifierListOwner(modifierListOwner: KSModifierListOwner, data: Unit) {
+ modifierListOwner.modifiers
+ super.visitModifierListOwner(modifierListOwner, data)
+ }
+
+ override fun visitNode(node: KSNode, data: Unit) {
+ collectedNodes.add(node.origin.toString())
+ collectedNodes.add(node.location.toString())
+ super.visitNode(node, data)
+ }
+
+ override fun visitParenthesizedReference(reference: KSParenthesizedReference, data: Unit) {
+ super.visitParenthesizedReference(reference, data)
+ }
+
+ override fun visitPropertyAccessor(accessor: KSPropertyAccessor, data: Unit) {
+ accessor.receiver
+ super.visitPropertyAccessor(accessor, data)
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ if (!property.isLocal()) {
+ property.isMutable
+ property.findOverridee()
+ property.isDelegated()
+ }
+ super.visitPropertyDeclaration(property, data)
+ }
+
+ override fun visitPropertyGetter(getter: KSPropertyGetter, data: Unit) {
+ super.visitPropertyGetter(getter, data)
+ }
+
+ override fun visitPropertySetter(setter: KSPropertySetter, data: Unit) {
+ super.visitPropertySetter(setter, data)
+ }
+
+ override fun visitReferenceElement(element: KSReferenceElement, data: Unit) {
+ super.visitReferenceElement(element, data)
+ }
+
+ override fun visitTypeAlias(typeAlias: KSTypeAlias, data: Unit) {
+ typeAlias.name
+ super.visitTypeAlias(typeAlias, data)
+ }
+
+ override fun visitTypeArgument(typeArgument: KSTypeArgument, data: Unit) {
+ typeArgument.variance
+ super.visitTypeArgument(typeArgument, data)
+ }
+
+ override fun visitTypeParameter(typeParameter: KSTypeParameter, data: Unit) {
+ typeParameter.name
+ typeParameter.variance
+ typeParameter.isReified
+ super.visitTypeParameter(typeParameter, data)
+ }
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: Unit) {
+ typeReference.resolve()
+ super.visitTypeReference(typeReference, data)
+ }
+
+ override fun visitValueArgument(valueArgument: KSValueArgument, data: Unit) {
+ valueArgument.name
+ valueArgument.isSpread
+ valueArgument.value
+ super.visitValueArgument(valueArgument, data)
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: Unit) {
+ valueParameter.name
+ valueParameter.isCrossInline
+ valueParameter.isNoInline
+ valueParameter.isVal
+ valueParameter.isVar
+ valueParameter.isVararg
+ valueParameter.hasDefault
+ super.visitValueParameter(valueParameter, data)
+ }
+ }
+}
+
+class ExhaustiveProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return ExhaustiveProcessor(env.codeGenerator, env.options)
+ }
+}
diff --git a/benchmark/exhaustive-processor/processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/benchmark/exhaustive-processor/processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..bba311cd
--- /dev/null
+++ b/benchmark/exhaustive-processor/processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+ExhaustiveProcessorProvider \ No newline at end of file
diff --git a/benchmark/exhaustive-processor/settings.gradle.kts b/benchmark/exhaustive-processor/settings.gradle.kts
new file mode 100644
index 00000000..24f4734a
--- /dev/null
+++ b/benchmark/exhaustive-processor/settings.gradle.kts
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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.
+ */
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ gradlePluginPortal()
+ }
+}
+
+rootProject.name = "exhaustive-processor"
+
+include(":processor")
diff --git a/benchmark/gradle/wrapper/gradle-wrapper.jar b/benchmark/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..7454180f
--- /dev/null
+++ b/benchmark/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/benchmark/gradle/wrapper/gradle-wrapper.properties b/benchmark/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..2e6e5897
--- /dev/null
+++ b/benchmark/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/benchmark/gradlew b/benchmark/gradlew
new file mode 100755
index 00000000..744e882e
--- /dev/null
+++ b/benchmark/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://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.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MSYS* | MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/benchmark/runner/runner.sh b/benchmark/runner/runner.sh
new file mode 100755
index 00000000..70a25a4e
--- /dev/null
+++ b/benchmark/runner/runner.sh
@@ -0,0 +1,70 @@
+#!/bin/bash
+
+# Copyright 2022 Google LLC
+#
+# 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.
+
+set -e
+
+SCRIPT_DIR=$(dirname "$(realpath $0)")
+BENCHMARK_DIR=$1
+PREFIX=$2
+
+if [ -z $PREFIX ]
+then
+ PREFIX=..
+fi
+
+JAVA_ARG=$3
+
+if [ -z $JAVA_ARG ]
+then
+ JAVA=java
+else
+ JAVA=$(realpath $SCRIPT_DIR/$JAVA_ARG)
+fi
+
+BENCHMARK_DATA_DIR=$(realpath $SCRIPT_DIR/$PREFIX/$BENCHMARK_DIR)
+
+echo Running benchmark: $BENCHMARK_DIR
+echo With benchmark data directory: $BENCHMARK_DATA_DIR
+echo Using java: $JAVA
+
+cd $SCRIPT_DIR
+CP=../build/libs/benchmark.jar:$(echo $BENCHMARK_DATA_DIR/lib/*.jar | tr ' ' ':')
+KSP_PLUGIN_ID=com.google.devtools.ksp.symbol-processing
+KSP_PLUGIN_OPT=plugin:$KSP_PLUGIN_ID
+
+KSP_PLUGIN_JAR=./com/google/devtools/ksp/symbol-processing-cmdline/2.0.255/symbol-processing-cmdline-2.0.255.jar
+KSP_API_JAR=./com/google/devtools/ksp/symbol-processing-api/2.0.255/symbol-processing-api-2.0.255.jar
+
+AP=processor-1.0-SNAPSHOT.jar
+
+mkdir -p out
+find $BENCHMARK_DATA_DIR -name "*.kt" | xargs $JAVA -cp $CP com.google.devtools.ksp.BenchRunnerKt $BENCHMARK_DIR\
+ -kotlin-home . \
+ -Xplugin=$KSP_PLUGIN_JAR \
+ -Xplugin=$KSP_API_JAR \
+ -Xallow-no-source-files \
+ -P $KSP_PLUGIN_OPT:apclasspath=$AP \
+ -P $KSP_PLUGIN_OPT:projectBaseDir=. \
+ -P $KSP_PLUGIN_OPT:classOutputDir=./out \
+ -P $KSP_PLUGIN_OPT:javaOutputDir=./out \
+ -P $KSP_PLUGIN_OPT:kotlinOutputDir=./out \
+ -P $KSP_PLUGIN_OPT:resourceOutputDir=./out \
+ -P $KSP_PLUGIN_OPT:kspOutputDir=./out \
+ -P $KSP_PLUGIN_OPT:cachesDir=./out \
+ -P $KSP_PLUGIN_OPT:incremental=false \
+ -P $KSP_PLUGIN_OPT:apoption=key1=value1 \
+ -P $KSP_PLUGIN_OPT:apoption=key2=value2 \
+ -cp $CP
diff --git a/benchmark/settings.gradle.kts b/benchmark/settings.gradle.kts
new file mode 100644
index 00000000..5bb6df0d
--- /dev/null
+++ b/benchmark/settings.gradle.kts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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.
+ */
+rootProject.name = "benchmark"
diff --git a/benchmark/src/main/kotlin/com/google/devtools/ksp/BenchRunner.kt b/benchmark/src/main/kotlin/com/google/devtools/ksp/BenchRunner.kt
new file mode 100644
index 00000000..277c6c15
--- /dev/null
+++ b/benchmark/src/main/kotlin/com/google/devtools/ksp/BenchRunner.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp
+
+import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
+import kotlin.system.measureNanoTime
+
+fun main(args: Array<String>) {
+ val runs = 3
+ val warmup = 3
+ val benchName = args[0]
+ val compilerArgs = args.drop(1).toTypedArray()
+ val cold = measureNanoTime{
+ K2JVMCompiler.main(compilerArgs)
+ } / 1000000L
+ for (i in 1..warmup) {
+ K2JVMCompiler.main(compilerArgs)
+ }
+ val hot = (1..runs).map { measureNanoTime{K2JVMCompiler.main(compilerArgs)} / 1000000L }
+ println("$benchName.Cold(RunTimeRaw): $cold ms")
+ println("$benchName.Hot(RunTimeRaw): ${hot.minOrNull()!!} ms")
+}
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 00000000..ccd8d354
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,97 @@
+import com.google.devtools.ksp.configureKtlint
+import com.google.devtools.ksp.configureKtlintApplyToIdea
+
+val sonatypeUserName: String? by project
+val sonatypePassword: String? by project
+
+val kotlinBaseVersion: String? by project
+if (extra.has("kspOnlyVersion") && kotlinBaseVersion != null) {
+ val kspOnlyVersion = extra.get("kspOnlyVersion") as String
+ extra.set("kspVersion", "$kotlinBaseVersion-$kspOnlyVersion")
+}
+
+if (!extra.has("kspVersion")) {
+ extra.set("kspVersion", "2.0.255-SNAPSHOT")
+}
+
+repositories {
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+plugins {
+ kotlin("jvm") version "1.8.0"
+ id("io.github.gradle-nexus.publish-plugin") version "1.1.0"
+}
+
+nexusPublishing {
+ packageGroup.set("com.google.devtools.ksp")
+ repositories {
+ sonatype {
+ username.set(sonatypeUserName)
+ password.set(sonatypePassword)
+ }
+ }
+}
+
+version = rootProject.extra.get("kspVersion") as String
+
+project.configureKtlintApplyToIdea()
+subprojects {
+ group = "com.google.devtools.ksp"
+ version = rootProject.extra.get("kspVersion") as String
+ this.configureKtlint()
+ repositories {
+ mavenCentral()
+ google()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ maven("https://www.jetbrains.com/intellij-repository/snapshots")
+ }
+ pluginManager.withPlugin("maven-publish") {
+ val publishExtension = extensions.getByType<PublishingExtension>()
+ publishExtension.repositories {
+ if (extra.has("outRepo")) {
+ val outRepo = extra.get("outRepo") as String
+ maven {
+ url = File(outRepo).toURI()
+ }
+ } else {
+ mavenLocal()
+ }
+ maven {
+ name = "test"
+ url = uri("${rootProject.buildDir}/repos/test")
+ }
+ }
+ publishExtension.publications.whenObjectAdded {
+ check(this is MavenPublication) {
+ "unexpected publication $this"
+ }
+ val publication = this
+ publication.pom {
+ url.set("https://goo.gle/ksp")
+ licenses {
+ license {
+ name.set("The Apache License, Version 2.0")
+ url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
+ }
+ }
+ developers {
+ developer {
+ name.set("KSP Team")
+ }
+ }
+ scm {
+ connection.set("scm:git:https://github.com/google/ksp.git")
+ developerConnection.set("scm:git:https://github.com/google/ksp.git")
+ url.set("https://github.com/google/ksp")
+ }
+ }
+ }
+ }
+
+ tasks.withType<JavaCompile>().configureEach {
+ sourceCompatibility = JavaVersion.VERSION_1_8.toString()
+ targetCompatibility = JavaVersion.VERSION_1_8.toString()
+ }
+}
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
new file mode 100644
index 00000000..030b5af2
--- /dev/null
+++ b/buildSrc/build.gradle.kts
@@ -0,0 +1,15 @@
+
+plugins {
+ kotlin("jvm") version "1.8.0"
+}
+
+kotlin {
+ jvmToolchain {
+ languageVersion.set(JavaLanguageVersion.of(11))
+ }
+}
+
+repositories {
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts
new file mode 100644
index 00000000..d3daef0f
--- /dev/null
+++ b/buildSrc/settings.gradle.kts
@@ -0,0 +1,6 @@
+pluginManagement {
+ repositories {
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
diff --git a/buildSrc/src/main/kotlin/com/google/devtools/ksp/ApiCheck.kt b/buildSrc/src/main/kotlin/com/google/devtools/ksp/ApiCheck.kt
new file mode 100644
index 00000000..cb4f0f88
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com/google/devtools/ksp/ApiCheck.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp
+
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.tasks.JavaExec
+
+val API_BASE_FILE="api.base"
+
+/**
+ * Adapted from ktlint
+ */
+fun Project.configureMetalava() {
+ val checkProvider = tasks.register("checkApi", JavaExec::class.java) { task ->
+ task.configureCommonMetalavaArgs(this@configureMetalava)
+ task.description = "Check API compatibility."
+ task.group = "Verification"
+ task.args = listOf("--check-compatibility:api:released", API_BASE_FILE) + task.args!!
+ }
+
+ afterEvaluate {
+ // check task is not available yet, which is why we use afterEvaluate
+ project.tasks.named("check").configure { checkTask ->
+ checkTask.dependsOn(checkProvider)
+ }
+ }
+
+ tasks.register("updateApi", JavaExec::class.java) { task ->
+ task.configureCommonMetalavaArgs(this@configureMetalava)
+ task.description = "Update API base file."
+ task.group = "formatting"
+ task.args = listOf("--api", API_BASE_FILE) + task.args!!
+ }
+}
+
+/**
+ * Configures common Metalava parameters
+ */
+private fun JavaExec.configureCommonMetalavaArgs(
+ project: Project
+) {
+ val jdkHome = org.gradle.internal.jvm.Jvm.current().getJavaHome().absolutePath
+ val compileClasspath = project.getCompileClasspath()
+ val apiFiles = project.fileTree(project.projectDir).also {
+ it.include("**/*.kt")
+ it.include("**/*.java")
+ it.exclude("**/testData/**")
+ it.exclude("**/build/**")
+ it.exclude("**/.*/**")
+ }
+ inputs.files(apiFiles)
+ classpath = project.getMetalavaConfiguration()
+ mainClass.set("com.android.tools.metalava.Driver")
+ args = listOf(
+ "--jdk-home", jdkHome,
+ "--classpath", compileClasspath,
+ "--source-files",
+ ) + apiFiles.files.map { it.absolutePath }
+}
+
+private fun Project.getCompileClasspath(): String =
+ configurations.findByName("compileClasspath")!!.files.map { it.absolutePath }.joinToString(":")
+
+private fun Project.getMetalavaConfiguration(): Configuration {
+ return configurations.findByName("metalava") ?: configurations.create("metalava") {
+ val dependency = dependencies.create("com.android.tools.metalava:metalava:1.0.0-alpha04")
+ it.dependencies.add(dependency)
+ }
+}
diff --git a/buildSrc/src/main/kotlin/com/google/devtools/ksp/Ktlint.kt b/buildSrc/src/main/kotlin/com/google/devtools/ksp/Ktlint.kt
new file mode 100644
index 00000000..b45534fa
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com/google/devtools/ksp/Ktlint.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp
+
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.tasks.JavaExec
+
+// This file is mostly ported from AndroidX with minor modifications.
+// https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:buildSrc/src/main/kotlin/androidx/build/Ktlint.kt
+
+/**
+ * Adds a ktlintApplyToIdea task that updates the local .idea files to match the ktlint style.
+ */
+fun Project.configureKtlintApplyToIdea() {
+ if (this.rootProject !== this) {
+ throw IllegalArgumentException("Can only use root project for applyToIdea task")
+ }
+ tasks.register("ktlintApplyToIdea", JavaExec::class.java) { task ->
+ task.description = "Apply ktlint style to idea"
+ task.group = "Tooling"
+ task.classpath = getKtlintConfiguration()
+ task.mainClass.set("com.pinterest.ktlint.Main")
+ task.args = listOf(
+ "applyToIDEAProject",
+ "-y"
+ )
+ }
+}
+
+/**
+ * Configures a "ktlint" task for the project to check formatting and `ktlintFormat` task
+ * to fix formatting.
+ */
+fun Project.configureKtlint() {
+ val lintProvider = tasks.register("ktlint", JavaExec::class.java) { task ->
+ task.configureCommonKtlintParams(this@configureKtlint)
+ task.description = "Check Kotlin code style."
+ task.group = "Verification"
+ }
+
+ afterEvaluate {
+ // check task is not available yet, which is why we use afterEvaluate
+ project.tasks.named("check").configure { checkTask ->
+ checkTask.dependsOn(lintProvider)
+ }
+ }
+
+ tasks.register("ktlintFormat", JavaExec::class.java) { task ->
+ task.configureCommonKtlintParams(this@configureKtlint)
+ task.description = "Fix Kotlin code style deviations."
+ task.group = "formatting"
+ task.args = listOf("-F") + task.args!!
+ }
+}
+
+/**
+ * Configures common ktlint parameters for ktlint tasks
+ */
+private fun JavaExec.configureCommonKtlintParams(
+ project: Project
+) {
+ val ktlintInputFiles = project.fileTree(project.projectDir).also {
+ it.include("**/*.kt")
+ it.include("**/*.kts")
+ it.exclude("**/testData/**")
+ it.exclude("**/build/**")
+ it.exclude("**/.*/**")
+ }
+ val outputFile = project.buildDir.resolve("reports/ktlint/ktlint-checkstyle-report.xml")
+ inputs.files(ktlintInputFiles)
+ classpath = project.getKtlintConfiguration()
+ mainClass.set("com.pinterest.ktlint.Main")
+ outputs.file(outputFile)
+ args = listOf(
+ "--reporter=plain",
+ "--reporter=checkstyle,output=$outputFile",
+ ) + ktlintInputFiles.files.map { it.absolutePath }
+}
+
+private fun Project.getKtlintConfiguration(): Configuration {
+ return configurations.findByName("ktlint") ?: configurations.create("ktlint") {
+ val dependency = dependencies.create("com.pinterest:ktlint:0.40.0")
+ it.dependencies.add(dependency)
+ }
+}
diff --git a/common-util/build.gradle.kts b/common-util/build.gradle.kts
new file mode 100644
index 00000000..cf991902
--- /dev/null
+++ b/common-util/build.gradle.kts
@@ -0,0 +1,34 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+evaluationDependsOn(":api")
+
+description = "Kotlin Symbol Processing Util"
+
+val kotlinBaseVersion: String by project
+val intellijVersion: String by project
+
+tasks.withType<KotlinCompile> {
+ compilerOptions.freeCompilerArgs.add("-Xjvm-default=all-compatibility")
+}
+
+plugins {
+ kotlin("jvm")
+ id("org.jetbrains.intellij") version "0.6.4"
+ id("org.jetbrains.dokka") version ("1.7.20")
+}
+
+intellij {
+ version = intellijVersion
+}
+
+dependencies {
+ implementation(kotlin("stdlib", kotlinBaseVersion))
+ implementation("org.jetbrains.kotlin:kotlin-compiler:$kotlinBaseVersion")
+ implementation(project(":api"))
+}
+
+val dokkaJavadocJar by tasks.register<Jar>("dokkaJavadocJar") {
+ dependsOn(tasks.dokkaJavadoc)
+ from(tasks.dokkaJavadoc.flatMap { it.outputDirectory })
+ archiveClassifier.set("javadoc")
+}
diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/DescriptorUtils.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/DescriptorUtils.kt
new file mode 100644
index 00000000..f6f7ec8b
--- /dev/null
+++ b/common-util/src/main/kotlin/com/google/devtools/ksp/DescriptorUtils.kt
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp
+
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.symbol.Variance
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.descriptors.MemberDescriptor
+import org.jetbrains.kotlin.descriptors.Modality
+import org.jetbrains.kotlin.descriptors.PropertyDescriptor
+import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
+import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
+import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
+import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass
+import org.jetbrains.kotlin.load.kotlin.getContainingKotlinJvmBinaryClass
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.psi.KtDeclarationWithInitializer
+import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject
+import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
+import org.jetbrains.kotlin.resolve.source.getPsi
+import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
+import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
+import org.jetbrains.org.objectweb.asm.ClassReader
+import org.jetbrains.org.objectweb.asm.ClassVisitor
+import org.jetbrains.org.objectweb.asm.FieldVisitor
+import org.jetbrains.org.objectweb.asm.MethodVisitor
+import org.jetbrains.org.objectweb.asm.Opcodes
+
+fun MemberDescriptor.toKSModifiers(): Set<Modifier> {
+ val modifiers = mutableSetOf<Modifier>()
+ if (this.isActual) {
+ modifiers.add(Modifier.ACTUAL)
+ }
+ if (this.isExpect) {
+ modifiers.add(Modifier.EXPECT)
+ }
+ if (this.isExternal) {
+ modifiers.add(Modifier.EXTERNAL)
+ }
+ // we are not checking for JVM_STATIC annotation here intentionally
+ // see: https://github.com/google/ksp/issues/378
+ val isStatic = (this.containingDeclaration as? ClassDescriptor)?.let { containingClass ->
+ containingClass.staticScope.getContributedDescriptors(
+ nameFilter = {
+ it == this.name
+ }
+ ).any {
+ it == this
+ }
+ } ?: false
+ if (isStatic) {
+ modifiers.add(Modifier.JAVA_STATIC)
+ }
+ when (this.modality) {
+ Modality.SEALED -> modifiers.add(Modifier.SEALED)
+ Modality.FINAL -> modifiers.add(Modifier.FINAL)
+ Modality.OPEN -> {
+ if (!isStatic && this.visibility != DescriptorVisibilities.PRIVATE) {
+ // private methods still show up as OPEN
+ modifiers.add(Modifier.OPEN)
+ }
+ }
+ Modality.ABSTRACT -> modifiers.add(Modifier.ABSTRACT)
+ }
+ when (this.visibility) {
+ DescriptorVisibilities.PUBLIC -> modifiers.add(Modifier.PUBLIC)
+ DescriptorVisibilities.PROTECTED,
+ JavaDescriptorVisibilities.PROTECTED_AND_PACKAGE,
+ JavaDescriptorVisibilities.PROTECTED_STATIC_VISIBILITY,
+ -> modifiers.add(Modifier.PROTECTED)
+ DescriptorVisibilities.PRIVATE, DescriptorVisibilities.LOCAL -> modifiers.add(Modifier.PRIVATE)
+ DescriptorVisibilities.INTERNAL -> modifiers.add(Modifier.INTERNAL)
+ // Since there is no modifier for package-private, use No modifier to tell if a symbol from binary is package private.
+ JavaDescriptorVisibilities.PACKAGE_VISIBILITY, JavaDescriptorVisibilities.PROTECTED_STATIC_VISIBILITY -> Unit
+ else -> throw IllegalStateException("unhandled visibility: ${this.visibility}")
+ }
+
+ return modifiers
+}
+
+fun FunctionDescriptor.toFunctionKSModifiers(): Set<Modifier> {
+ val modifiers = mutableSetOf<Modifier>()
+ if (this.isSuspend) {
+ modifiers.add(Modifier.SUSPEND)
+ }
+ if (this.isTailrec) {
+ modifiers.add(Modifier.TAILREC)
+ }
+ if (this.isInline) {
+ modifiers.add(Modifier.INLINE)
+ }
+ if (this.isInfix) {
+ modifiers.add(Modifier.INFIX)
+ }
+ if (this.isOperator) {
+ modifiers.add(Modifier.OPERATOR)
+ }
+ if (this.overriddenDescriptors.isNotEmpty()) {
+ modifiers.add(Modifier.OVERRIDE)
+ }
+
+ return modifiers
+}
+
+fun org.jetbrains.kotlin.types.Variance.toKSVariance(): Variance {
+ return when (this) {
+ org.jetbrains.kotlin.types.Variance.IN_VARIANCE -> Variance.CONTRAVARIANT
+ org.jetbrains.kotlin.types.Variance.OUT_VARIANCE -> Variance.COVARIANT
+ org.jetbrains.kotlin.types.Variance.INVARIANT -> Variance.INVARIANT
+ else -> throw IllegalStateException("Unexpected variance value $this, $ExceptionMessage")
+ }
+}
+
+/**
+ * Custom check for backing fields of descriptors that support properties coming from .class files.
+ * The compiler API always returns true for them even when they don't have backing fields.
+ */
+fun PropertyDescriptor.hasBackingFieldWithBinaryClassSupport(): Boolean {
+ // partially take from https://github.com/JetBrains/kotlin/blob/master/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt#L104
+ return when {
+ extensionReceiverParameter != null -> false // extension properties do not have backing fields
+ compileTimeInitializer != null -> true // compile time initialization requires backing field
+ isLateInit -> true // lateinit requires property, faster than parsing class declaration
+ modality == Modality.ABSTRACT -> false // abstract means false, faster than parsing class declaration
+ this is DeserializedPropertyDescriptor -> this.hasBackingFieldInBinaryClass() // kotlin class, check binary
+ this.source is KotlinSourceElement -> this.declaresDefaultValue // kotlin source
+ else -> true // Java source or class
+ }
+}
+
+data class BinaryClassInfo(
+ val fieldAccFlags: Map<String, Int>,
+ val methodAccFlags: Map<String, Int>
+)
+
+/**
+ * Lookup cache for field names names for deserialized classes.
+ * To check if a field has backing field, we need to look for binary field names, hence they are cached here.
+ */
+object BinaryClassInfoCache : KSObjectCache<ClassId, BinaryClassInfo>() {
+ fun getCached(
+ kotlinJvmBinaryClass: KotlinJvmBinaryClass,
+ ) = cache.getOrPut(kotlinJvmBinaryClass.classId) {
+ val virtualFileContent = (kotlinJvmBinaryClass as? VirtualFileKotlinClass)?.file?.contentsToByteArray()
+ val fieldAccFlags = mutableMapOf<String, Int>()
+ val methodAccFlags = mutableMapOf<String, Int>()
+ ClassReader(virtualFileContent).accept(
+ object : ClassVisitor(Opcodes.API_VERSION) {
+ override fun visitField(
+ access: Int,
+ name: String?,
+ descriptor: String?,
+ signature: String?,
+ value: Any?
+ ): FieldVisitor? {
+ if (name != null) {
+ fieldAccFlags.put(name, access)
+ }
+ return null
+ }
+
+ override fun visitMethod(
+ access: Int,
+ name: String?,
+ descriptor: String?,
+ signature: String?,
+ exceptions: Array<out String>?
+ ): MethodVisitor? {
+ if (name != null) {
+ methodAccFlags.put(name + descriptor, access)
+ }
+ return null
+ }
+ },
+ ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES
+ )
+ BinaryClassInfo(fieldAccFlags, methodAccFlags)
+ }
+}
+
+/**
+ * Workaround for backingField in deserialized descriptors.
+ * They always return non-null for backing field even when they don't have a backing field.
+ */
+private fun DeserializedPropertyDescriptor.hasBackingFieldInBinaryClass(): Boolean {
+ val kotlinJvmBinaryClass = if (containingDeclaration.isCompanionObject()) {
+ // Companion objects have backing fields in containing classes.
+ // https://kotlinlang.org/docs/java-to-kotlin-interop.html#static-fields
+ val container = containingDeclaration.containingDeclaration as? DeserializedClassDescriptor
+ (container?.source as? KotlinJvmBinarySourceElement)?.binaryClass
+ } else {
+ this.getContainingKotlinJvmBinaryClass()
+ } ?: return false
+ return BinaryClassInfoCache.getCached(kotlinJvmBinaryClass).fieldAccFlags.containsKey(name.asString())
+}
+
+// from: https://github.com/JetBrains/kotlin/blob/92d200e093c693b3c06e53a39e0b0973b84c7ec5/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt#L45
+private val PropertyDescriptor.declaresDefaultValue: Boolean
+ get() = when (val declaration = this.source.getPsi()) {
+ is KtDeclarationWithInitializer -> declaration.initializer != null
+ is KtParameter -> declaration.defaultValue != null
+ else -> false
+ }
+
+fun KSAnnotated.hasAnnotation(fqn: String): Boolean =
+ annotations.any {
+ fqn.endsWith(it.shortName.asString()) &&
+ it.annotationType.resolve().declaration.qualifiedName?.asString() == fqn
+ }
diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/IncrementalUtil.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/IncrementalUtil.kt
new file mode 100644
index 00000000..f0c94dc7
--- /dev/null
+++ b/common-util/src/main/kotlin/com/google/devtools/ksp/IncrementalUtil.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp
+
+import com.google.devtools.ksp.symbol.*
+import java.io.File
+
+abstract class KSVirtualFile(val baseDir: File, val name: String) : KSFile {
+ override val annotations: Sequence<KSAnnotation>
+ get() = throw Exception("$name should not be used.")
+
+ override val declarations: Sequence<KSDeclaration>
+ get() = throw Exception("$name should not be used.")
+
+ override val fileName: String
+ get() = "<$name is a virtual file; DO NOT USE.>"
+
+ override val filePath: String
+ get() = File(baseDir, fileName).path
+
+ override val packageName: KSName
+ get() = throw Exception("$name should not be used.")
+
+ override val origin: Origin
+ get() = throw Exception("$name should not be used.")
+
+ override val location: Location
+ get() = throw Exception("$name should not be used.")
+
+ override val parent: KSNode?
+ get() = throw Exception("$name should not be used.")
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ throw Exception("$name should not be used.")
+ }
+}
+
+/**
+ * Used when an output potentially depends on new information.
+ */
+class AnyChanges(baseDir: File) : KSVirtualFile(baseDir, "AnyChanges")
+
+/**
+ * Used for classes from classpath, i.e., classes without source files.
+ */
+class NoSourceFile(baseDir: File, val fqn: String) : KSVirtualFile(baseDir, "NoSourceFile") {
+ override val fileName: String
+ get() = "<NoSourceFile for $fqn is a virtual file; DO NOT USE.>"
+}
diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/KSObjectCacheManager.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/KSObjectCacheManager.kt
new file mode 100644
index 00000000..08a8bd7f
--- /dev/null
+++ b/common-util/src/main/kotlin/com/google/devtools/ksp/KSObjectCacheManager.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp
+
+class KSObjectCacheManager {
+ companion object {
+ val caches = arrayListOf<KSObjectCache<*, *>>()
+
+ fun register(cache: KSObjectCache<*, *>) = caches.add(cache)
+ fun clear() = caches.forEach { it.clear() }
+ }
+}
+
+abstract class KSObjectCache<K, V> {
+ val cache = mutableMapOf<K, V>()
+
+ init {
+ KSObjectCacheManager.register(this)
+ }
+
+ open fun clear() = cache.clear()
+}
diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/KSPUtils.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/KSPUtils.kt
new file mode 100644
index 00000000..31707e58
--- /dev/null
+++ b/common-util/src/main/kotlin/com/google/devtools/ksp/KSPUtils.kt
@@ -0,0 +1,23 @@
+package com.google.devtools.ksp
+
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import org.jetbrains.kotlin.name.ClassId
+
+class IdKey<T>(private val k: T) {
+ override fun equals(other: Any?): Boolean = if (other is IdKey<*>) k === other.k else false
+ override fun hashCode(): Int = k.hashCode()
+}
+
+class IdKeyPair<T, P>(private val k1: T, private val k2: P) {
+ override fun equals(other: Any?): Boolean = if (other is IdKeyPair<*, *>) k1 === other.k1 &&
+ k2 === other.k2 else false
+ override fun hashCode(): Int = k1.hashCode() * 31 + k2.hashCode()
+}
+
+class IdKeyTriple<T, P, Q>(private val k1: T, private val k2: P, private val k3: Q) {
+ override fun equals(other: Any?): Boolean = if (other is IdKeyTriple<*, *, *>) k1 === other.k1 &&
+ k2 === other.k2 && k3 === other.k3 else false
+ override fun hashCode(): Int = k1.hashCode() * 31 * 31 + k2.hashCode() * 31 + k3.hashCode()
+}
+
+fun ClassId.toKSName() = KSNameImpl.getCached(asSingleFqName().toString())
diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/KspOptions.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/KspOptions.kt
new file mode 100644
index 00000000..c6538aab
--- /dev/null
+++ b/common-util/src/main/kotlin/com/google/devtools/ksp/KspOptions.kt
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp
+
+import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption
+import org.jetbrains.kotlin.config.ApiVersion
+import org.jetbrains.kotlin.config.LanguageVersion
+import org.jetbrains.kotlin.config.toKotlinVersion
+import java.io.File
+
+class KspOptions(
+ val projectBaseDir: File,
+ val compileClasspath: List<File>,
+ val javaSourceRoots: List<File>,
+
+ val classOutputDir: File,
+ val javaOutputDir: File,
+ val kotlinOutputDir: File,
+ val resourceOutputDir: File,
+
+ val processingClasspath: List<File>,
+ val processors: List<String>,
+
+ val processingOptions: Map<String, String>,
+
+ val knownModified: List<File>,
+ val knownRemoved: List<File>,
+
+ val cachesDir: File,
+ val kspOutputDir: File,
+ val incremental: Boolean,
+ val incrementalLog: Boolean,
+ val allWarningsAsErrors: Boolean,
+ val withCompilation: Boolean,
+ val returnOkOnError: Boolean,
+ val changedClasses: List<String>,
+
+ val languageVersion: KotlinVersion,
+ val apiVersion: KotlinVersion,
+ val compilerVersion: KotlinVersion,
+
+ val commonSources: List<File>,
+
+ val excludedProcessors: Set<String>,
+ val mapAnnotationArgumentsInJava: Boolean,
+) {
+ class Builder {
+ var projectBaseDir: File? = null
+ val compileClasspath: MutableList<File> = mutableListOf()
+ val javaSourceRoots: MutableList<File> = mutableListOf()
+
+ var classOutputDir: File? = null
+ var javaOutputDir: File? = null
+ var kotlinOutputDir: File? = null
+ var resourceOutputDir: File? = null
+
+ val processingClasspath: MutableList<File> = mutableListOf()
+ val processors: MutableList<String> = mutableListOf()
+
+ val processingOptions: MutableMap<String, String> = mutableMapOf()
+
+ val knownModified: MutableList<File> = mutableListOf()
+ val knownRemoved: MutableList<File> = mutableListOf()
+
+ var cachesDir: File? = null
+ var kspOutputDir: File? = null
+ var incremental: Boolean = false
+ var incrementalLog: Boolean = false
+ var allWarningsAsErrors: Boolean = false
+ var withCompilation: Boolean = false
+ // Default is false. It can be turned on to workaround KT-30172.
+ var returnOkOnError: Boolean = false
+ var changedClasses: MutableList<String> = mutableListOf()
+
+ var languageVersion: KotlinVersion = LanguageVersion.LATEST_STABLE.toKotlinVersion()
+ var apiVersion: KotlinVersion = ApiVersion.LATEST_STABLE.toKotlinVersion()
+ var compilerVersion: KotlinVersion = KotlinVersion.CURRENT
+
+ var commonSources: MutableList<File> = mutableListOf()
+
+ var excludedProcessors: MutableSet<String> = mutableSetOf()
+ var mapAnnotationArgumentsInJava: Boolean = false
+
+ fun build(): KspOptions {
+ return KspOptions(
+ requireNotNull(projectBaseDir) { "A non-null projectBaseDir must be provided" },
+ compileClasspath,
+ javaSourceRoots,
+ requireNotNull(classOutputDir) { "A non-null classOutputDir must be provided" },
+ requireNotNull(javaOutputDir) { "A non-null javaOutputDir must be provided" },
+ requireNotNull(kotlinOutputDir) { "A non-null kotlinOutputDir must be provided" },
+ requireNotNull(resourceOutputDir) { "A non-null resourceOutputDir must be provided" },
+ processingClasspath,
+ processors,
+ processingOptions,
+ knownModified,
+ knownRemoved,
+ requireNotNull(cachesDir) { "A non-null cachesDir must be provided" },
+ requireNotNull(kspOutputDir) { "A non-null kspOutputDir must be provided" },
+ incremental,
+ incrementalLog,
+ allWarningsAsErrors,
+ withCompilation,
+ returnOkOnError,
+ changedClasses,
+ languageVersion,
+ apiVersion,
+ compilerVersion,
+ commonSources,
+ excludedProcessors,
+ mapAnnotationArgumentsInJava,
+ )
+ }
+ }
+}
+
+fun String?.toKotlinVersion(): KotlinVersion {
+ if (this == null)
+ return KotlinVersion.CURRENT
+
+ return split('-').first().split('.').map { it.toInt() }.let {
+ when (it.size) {
+ 1 -> KotlinVersion(it[0], 0, 0)
+ 2 -> KotlinVersion(it[0], it[1], 0)
+ 3 -> KotlinVersion(it[0], it[1], it[2])
+ else -> KotlinVersion.CURRENT
+ }
+ }
+}
+
+fun ApiVersion.toKotlinVersion(): KotlinVersion = version.canonical.toKotlinVersion()
+
+enum class KspCliOption(
+ override val optionName: String,
+ override val valueDescription: String,
+ override val description: String,
+ override val required: Boolean = false,
+ override val allowMultipleOccurrences: Boolean = false
+) : AbstractCliOption {
+ CLASS_OUTPUT_DIR_OPTION(
+ "classOutputDir",
+ "<classOutputDir>",
+ "Dir of generated classes",
+ false
+ ),
+
+ JAVA_OUTPUT_DIR_OPTION(
+ "javaOutputDir",
+ "<javaOutputDir>",
+ "Dir of generated Java sources",
+ false
+ ),
+
+ KOTLIN_OUTPUT_DIR_OPTION(
+ "kotlinOutputDir",
+ "<kotlinOutputDir>",
+ "Dir of generated Kotlin sources",
+ false
+ ),
+
+ RESOURCE_OUTPUT_DIR_OPTION(
+ "resourceOutputDir",
+ "<resourceOutputDir>",
+ "Dir of generated resources",
+ false
+ ),
+
+ CACHES_DIR_OPTION(
+ "cachesDir",
+ "<cachesDir>",
+ "Dir of caches",
+ false
+ ),
+
+ PROJECT_BASE_DIR_OPTION(
+ "projectBaseDir",
+ "<projectBaseDir>",
+ "path to gradle project",
+ false
+ ),
+
+ KSP_OUTPUT_DIR_OPTION(
+ "kspOutputDir",
+ "<kspOutputDir>",
+ "root of ksp output dirs",
+ false
+ ),
+
+ PROCESSING_OPTIONS_OPTION(
+ "apoption",
+ "<apOption>",
+ "processor defined option",
+ false,
+ true
+ ),
+
+ PROCESSOR_CLASSPATH_OPTION(
+ "apclasspath",
+ "<classpath>",
+ "processor classpath",
+ false
+ ),
+
+ PROCESSOR_NAME_OPTION(
+ "processorNames",
+ "<processorNames>",
+ "only executes following processor(s)",
+ false
+ ),
+
+ KNOWN_MODIFIED_OPTION(
+ "knownModified",
+ "<knownModified>",
+ "known modified files",
+ false,
+ false
+ ),
+
+ KNOWN_REMOVED_OPTION(
+ "knownRemoved",
+ "<knownRemoved>",
+ "known removed fiels",
+ false,
+ false
+ ),
+
+ INCREMENTAL_OPTION(
+ "incremental",
+ "<incremental>",
+ "processing incrementally",
+ false,
+ false
+ ),
+
+ INCREMENTAL_LOG_OPTION(
+ "incrementalLog",
+ "<incrementalLog>",
+ "log dirty files",
+ false,
+ false
+ ),
+
+ ALL_WARNINGS_AS_ERRORS_OPTION(
+ "allWarningsAsErrors",
+ "<allWarningsAsErrors>",
+ "treat all warnings as errors",
+ false,
+ false
+ ),
+
+ WITH_COMPILATION_OPTION(
+ "withCompilation",
+ "<withCompilation>",
+ "Run processors and compilation in a single compiler invocation",
+ false,
+ false
+ ),
+
+ CHANGED_CLASSES_OPTION(
+ "changedClasses",
+ "<changedClasses>",
+ "canonical / dot-separated names of dirty classes in classpath",
+ false,
+ false
+ ),
+
+ RETURN_OK_ON_ERROR_OPTION(
+ "returnOkOnError",
+ "<returnOkOnError>",
+ "Return OK even if there are errors",
+ false,
+ false
+ ),
+
+ COMMON_SOURCES_OPTION(
+ "commonSources",
+ "<commonSources>",
+ "common sources",
+ false,
+ true
+ ),
+
+ EXCLUDED_PROCESSORS_OPTION(
+ "excludedProcessors",
+ "<excludedProcessors>",
+ "exclude providers by fqn",
+ false,
+ true
+ ),
+
+ MAP_ANNOTATION_ARGUMENTS_IN_JAVA_OPTION(
+ "mapAnnotationArgumentsInJava",
+ "<mapAnnotationArgumentsInJava>",
+ "Map types in annotation arguments in Java sources",
+ false,
+ false
+ ),
+}
+
+@Suppress("IMPLICIT_CAST_TO_ANY")
+fun KspOptions.Builder.processOption(option: KspCliOption, value: String) = when (option) {
+ KspCliOption.PROCESSOR_CLASSPATH_OPTION -> processingClasspath += value.split(File.pathSeparator).map {
+ File(it)
+ }
+ KspCliOption.PROCESSOR_NAME_OPTION -> processors += value.split(File.pathSeparator)
+ KspCliOption.CLASS_OUTPUT_DIR_OPTION -> classOutputDir = File(value)
+ KspCliOption.JAVA_OUTPUT_DIR_OPTION -> javaOutputDir = File(value)
+ KspCliOption.KOTLIN_OUTPUT_DIR_OPTION -> kotlinOutputDir = File(value)
+ KspCliOption.RESOURCE_OUTPUT_DIR_OPTION -> resourceOutputDir = File(value)
+ KspCliOption.CACHES_DIR_OPTION -> cachesDir = File(value)
+ KspCliOption.KSP_OUTPUT_DIR_OPTION -> kspOutputDir = File(value)
+ KspCliOption.PROJECT_BASE_DIR_OPTION -> projectBaseDir = File(value)
+ KspCliOption.PROCESSING_OPTIONS_OPTION -> {
+ val (k, v) = value.split('=', ignoreCase = false, limit = 2)
+ processingOptions.put(k, v)
+ }
+ KspCliOption.KNOWN_MODIFIED_OPTION -> knownModified.addAll(value.split(File.pathSeparator).map { File(it) })
+ KspCliOption.KNOWN_REMOVED_OPTION -> knownRemoved.addAll(value.split(File.pathSeparator).map { File(it) })
+ KspCliOption.INCREMENTAL_OPTION -> incremental = value.toBoolean()
+ KspCliOption.INCREMENTAL_LOG_OPTION -> incrementalLog = value.toBoolean()
+ KspCliOption.ALL_WARNINGS_AS_ERRORS_OPTION -> allWarningsAsErrors = value.toBoolean()
+ KspCliOption.WITH_COMPILATION_OPTION -> withCompilation = value.toBoolean()
+ KspCliOption.CHANGED_CLASSES_OPTION -> changedClasses.addAll(value.split(':'))
+ KspCliOption.RETURN_OK_ON_ERROR_OPTION -> returnOkOnError = value.toBoolean()
+ KspCliOption.COMMON_SOURCES_OPTION -> commonSources.addAll(value.split(File.pathSeparator).map { File(it) })
+ KspCliOption.EXCLUDED_PROCESSORS_OPTION -> excludedProcessors.addAll(value.split(":"))
+ KspCliOption.MAP_ANNOTATION_ARGUMENTS_IN_JAVA_OPTION -> mapAnnotationArgumentsInJava = value.toBoolean()
+}
diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/MemoizedSequence.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/MemoizedSequence.kt
new file mode 100644
index 00000000..be7a05d6
--- /dev/null
+++ b/common-util/src/main/kotlin/com/google/devtools/ksp/MemoizedSequence.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp
+
+// TODO: garbage collect underlying sequence after exhaust.
+class MemoizedSequence<T>(sequence: Sequence<T>) : Sequence<T> {
+
+ private val cache = arrayListOf<T>()
+
+ private val iter: Iterator<T> by lazy {
+ sequence.iterator()
+ }
+
+ private inner class CachedIterator() : Iterator<T> {
+ var idx = 0
+ override fun hasNext(): Boolean {
+ return idx < cache.size || iter.hasNext()
+ }
+
+ override fun next(): T {
+ if (idx == cache.size) {
+ cache.add(iter.next())
+ }
+ val value = cache[idx]
+ idx += 1
+ return value
+ }
+ }
+
+ override fun iterator(): Iterator<T> {
+ return CachedIterator()
+ }
+}
diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/PsiUtils.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/PsiUtils.kt
new file mode 100644
index 00000000..9003a7fe
--- /dev/null
+++ b/common-util/src/main/kotlin/com/google/devtools/ksp/PsiUtils.kt
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp
+
+import com.google.devtools.ksp.symbol.*
+import com.intellij.lang.jvm.JvmModifier
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiComment
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import com.intellij.psi.PsiModifierListOwner
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtClass
+import org.jetbrains.kotlin.psi.KtClassOrObject
+import org.jetbrains.kotlin.psi.KtEnumEntry
+import org.jetbrains.kotlin.psi.KtModifierList
+import org.jetbrains.kotlin.psi.KtModifierListOwner
+import org.jetbrains.kotlin.psi.KtObjectDeclaration
+import org.jetbrains.kotlin.psi.psiUtil.siblings
+
+val jvmModifierMap = mapOf(
+ JvmModifier.PUBLIC to Modifier.PUBLIC,
+ JvmModifier.PRIVATE to Modifier.PRIVATE,
+ JvmModifier.ABSTRACT to Modifier.ABSTRACT,
+ JvmModifier.FINAL to Modifier.FINAL,
+ JvmModifier.PROTECTED to Modifier.PROTECTED,
+ JvmModifier.STATIC to Modifier.JAVA_STATIC,
+ JvmModifier.STRICTFP to Modifier.JAVA_STRICT,
+ JvmModifier.NATIVE to Modifier.JAVA_NATIVE,
+ JvmModifier.SYNCHRONIZED to Modifier.JAVA_SYNCHRONIZED,
+ JvmModifier.TRANSIENT to Modifier.JAVA_TRANSIENT,
+ JvmModifier.VOLATILE to Modifier.JAVA_VOLATILE
+)
+
+val javaModifiers = setOf(
+ Modifier.ABSTRACT,
+ Modifier.FINAL,
+ Modifier.JAVA_DEFAULT,
+ Modifier.JAVA_NATIVE,
+ Modifier.JAVA_STATIC,
+ Modifier.JAVA_STRICT,
+ Modifier.JAVA_SYNCHRONIZED,
+ Modifier.JAVA_TRANSIENT,
+ Modifier.JAVA_VOLATILE,
+ Modifier.PRIVATE,
+ Modifier.PROTECTED,
+ Modifier.PUBLIC,
+)
+
+val modifierMap = mapOf(
+ KtTokens.PUBLIC_KEYWORD to Modifier.PUBLIC,
+ KtTokens.PRIVATE_KEYWORD to Modifier.PRIVATE,
+ KtTokens.INTERNAL_KEYWORD to Modifier.INTERNAL,
+ KtTokens.PROTECTED_KEYWORD to Modifier.PROTECTED,
+ KtTokens.IN_KEYWORD to Modifier.IN,
+ KtTokens.OUT_KEYWORD to Modifier.OUT,
+ KtTokens.OVERRIDE_KEYWORD to Modifier.OVERRIDE,
+ KtTokens.LATEINIT_KEYWORD to Modifier.LATEINIT,
+ KtTokens.ENUM_KEYWORD to Modifier.ENUM,
+ KtTokens.SEALED_KEYWORD to Modifier.SEALED,
+ KtTokens.ANNOTATION_KEYWORD to Modifier.ANNOTATION,
+ KtTokens.DATA_KEYWORD to Modifier.DATA,
+ KtTokens.INNER_KEYWORD to Modifier.INNER,
+ KtTokens.FUN_KEYWORD to Modifier.FUN,
+ KtTokens.VALUE_KEYWORD to Modifier.VALUE,
+ KtTokens.SUSPEND_KEYWORD to Modifier.SUSPEND,
+ KtTokens.TAILREC_KEYWORD to Modifier.TAILREC,
+ KtTokens.OPERATOR_KEYWORD to Modifier.OPERATOR,
+ KtTokens.INFIX_KEYWORD to Modifier.INFIX,
+ KtTokens.INLINE_KEYWORD to Modifier.INLINE,
+ KtTokens.EXTERNAL_KEYWORD to Modifier.EXTERNAL,
+ KtTokens.ABSTRACT_KEYWORD to Modifier.ABSTRACT,
+ KtTokens.FINAL_KEYWORD to Modifier.FINAL,
+ KtTokens.OPEN_KEYWORD to Modifier.OPEN,
+ KtTokens.VARARG_KEYWORD to Modifier.VARARG,
+ KtTokens.NOINLINE_KEYWORD to Modifier.NOINLINE,
+ KtTokens.CROSSINLINE_KEYWORD to Modifier.CROSSINLINE,
+ KtTokens.REIFIED_KEYWORD to Modifier.REIFIED,
+ KtTokens.EXPECT_KEYWORD to Modifier.EXPECT,
+ KtTokens.ACTUAL_KEYWORD to Modifier.ACTUAL,
+ KtTokens.CONST_KEYWORD to Modifier.CONST
+)
+
+fun KtModifierList?.toKSModifiers(): Set<Modifier> {
+ if (this == null)
+ return emptySet()
+ val modifiers = mutableSetOf<Modifier>()
+ modifiers.addAll(
+ modifierMap.entries
+ .filter { hasModifier(it.key) }
+ .map { it.value }
+ )
+ return modifiers
+}
+
+fun KtModifierListOwner.toKSModifiers(): Set<Modifier> {
+ val modifierList = this.modifierList
+ return modifierList.toKSModifiers()
+}
+
+fun PsiModifierListOwner.toKSModifiers(): Set<Modifier> {
+ val modifiers = mutableSetOf<Modifier>()
+ modifiers.addAll(
+ jvmModifierMap.entries.filter { this.hasModifier(it.key) }
+ .map { it.value }
+ .toSet()
+ )
+ if (this.modifierList?.hasExplicitModifier("default") == true) {
+ modifiers.add(Modifier.JAVA_DEFAULT)
+ }
+ return modifiers
+}
+
+fun Project.findLocationString(file: PsiFile, offset: Int): String {
+ val psiDocumentManager = PsiDocumentManager.getInstance(this)
+ val document = psiDocumentManager.getDocument(file) ?: return "<unknown>"
+ val lineNumber = document.getLineNumber(offset)
+ val offsetInLine = offset - document.getLineStartOffset(lineNumber)
+ return "${file.virtualFile.path}: (${lineNumber + 1}, ${offsetInLine + 1})"
+}
+
+private fun parseDocString(raw: String): String? {
+ val t1 = raw.trim()
+ if (!t1.startsWith("/**") || !t1.endsWith("*/"))
+ return null
+ val lineSep = t1.findAnyOf(listOf("\r\n", "\n", "\r"))?.second ?: ""
+ return t1.trim('/').trim('*').lines().joinToString(lineSep) {
+ it.trimStart().trimStart('*')
+ }
+}
+
+fun PsiElement.getDocString(): String? =
+ this.firstChild.siblings().firstOrNull { it is PsiComment }?.let {
+ parseDocString(it.text)
+ }
+
+fun KtClassOrObject.getClassType(): ClassKind {
+ return when (this) {
+ is KtObjectDeclaration -> ClassKind.OBJECT
+ is KtEnumEntry -> ClassKind.ENUM_ENTRY
+ is KtClass -> when {
+ this.isEnum() -> ClassKind.ENUM_CLASS
+ this.isInterface() -> ClassKind.INTERFACE
+ this.isAnnotation() -> ClassKind.ANNOTATION_CLASS
+ else -> ClassKind.CLASS
+ }
+ else -> throw IllegalStateException("Unexpected psi type ${this.javaClass}, $ExceptionMessage")
+ }
+}
+
+inline fun <reified T> PsiElement.findParentOfType(): T? {
+ var parent = this.parent
+ while (parent != null && parent !is T) {
+ parent = parent.parent
+ }
+ return parent as? T
+}
+
+fun <T> Sequence<T>.memoized() = MemoizedSequence(this)
diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/processing/impl/CodeGeneratorImpl.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/processing/impl/CodeGeneratorImpl.kt
new file mode 100644
index 00000000..f9293bc6
--- /dev/null
+++ b/common-util/src/main/kotlin/com/google/devtools/ksp/processing/impl/CodeGeneratorImpl.kt
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processing.impl
+
+import com.google.devtools.ksp.NoSourceFile
+import com.google.devtools.ksp.processing.CodeGenerator
+import com.google.devtools.ksp.processing.Dependencies
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSFile
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+import java.io.OutputStream
+
+class CodeGeneratorImpl(
+ private val classDir: File,
+ private val javaDir: File,
+ private val kotlinDir: File,
+ private val resourcesDir: File,
+ private val projectBase: File,
+ private val anyChangesWildcard: KSFile,
+ private val allSources: List<KSFile>,
+ private val isIncremental: Boolean
+) : CodeGenerator {
+ private val fileMap = mutableMapOf<String, File>()
+ private val fileOutputStreamMap = mutableMapOf<String, FileOutputStream>()
+
+ private val separator = File.separator
+
+ val sourceToOutputs: MutableMap<File, MutableSet<File>> = mutableMapOf()
+
+ // This function will also clear `fileOutputStreamMap` which will change the result of `generatedFile`
+ fun closeFiles() {
+ fileOutputStreamMap.keys.forEach {
+ fileOutputStreamMap[it]!!.close()
+ }
+ fileOutputStreamMap.clear()
+ }
+
+ fun pathOf(packageName: String, fileName: String, extensionName: String): String {
+ val packageDirs = if (packageName != "") "${packageName.split(".").joinToString(separator)}$separator" else ""
+ val extension = if (extensionName != "") ".$extensionName" else ""
+ return "$packageDirs$fileName$extension"
+ }
+
+ override fun createNewFile(
+ dependencies: Dependencies,
+ packageName: String,
+ fileName: String,
+ extensionName: String
+ ): OutputStream {
+ return createNewFile(
+ dependencies,
+ pathOf(packageName, fileName, extensionName),
+ extensionToDirectory(extensionName)
+ )
+ }
+
+ override fun createNewFileByPath(dependencies: Dependencies, path: String, extensionName: String): OutputStream {
+ val extension = if (extensionName != "") ".$extensionName" else ""
+ return createNewFile(dependencies, path + extension, extensionToDirectory(extensionName))
+ }
+
+ override fun associate(sources: List<KSFile>, packageName: String, fileName: String, extensionName: String) {
+ associate(sources, pathOf(packageName, fileName, extensionName), extensionToDirectory(extensionName))
+ }
+
+ override fun associateByPath(sources: List<KSFile>, path: String, extensionName: String) {
+ val extension = if (extensionName != "") ".$extensionName" else ""
+ associate(sources, path + extension, extensionToDirectory(extensionName))
+ }
+
+ override fun associateWithClasses(
+ classes: List<KSClassDeclaration>,
+ packageName: String,
+ fileName: String,
+ extensionName: String
+ ) {
+ val path = pathOf(packageName, fileName, extensionName)
+ val files = classes.map {
+ it.containingFile ?: NoSourceFile(projectBase, it.qualifiedName?.asString().toString())
+ }
+ associate(files, path, extensionToDirectory(extensionName))
+ }
+
+ private fun extensionToDirectory(extensionName: String): File {
+ return when (extensionName) {
+ "class" -> classDir
+ "java" -> javaDir
+ "kt" -> kotlinDir
+ else -> resourcesDir
+ }
+ }
+
+ private fun createNewFile(dependencies: Dependencies, path: String, baseDir: File): OutputStream {
+ val file = File(baseDir, path)
+ if (!isWithinBaseDir(baseDir, file)) {
+ throw IllegalStateException("requested path is outside the bounds of the required directory")
+ }
+ val absolutePath = file.absolutePath
+ if (absolutePath in fileMap) {
+ throw FileAlreadyExistsException(file)
+ }
+ val parentFile = file.parentFile
+ if (!parentFile.exists() && !parentFile.mkdirs()) {
+ throw IllegalStateException("failed to make parent directories.")
+ }
+ file.writeText("")
+ fileMap[absolutePath] = file
+ val sources = if (dependencies.isAllSources) {
+ allSources + anyChangesWildcard
+ } else {
+ if (dependencies.aggregating) {
+ dependencies.originatingFiles + anyChangesWildcard
+ } else {
+ dependencies.originatingFiles
+ }
+ }
+ associate(sources, file)
+ fileOutputStreamMap[absolutePath] = fileMap[absolutePath]!!.outputStream()
+ return fileOutputStreamMap[absolutePath]!!
+ }
+
+ private fun isWithinBaseDir(baseDir: File, file: File): Boolean {
+ val base = baseDir.toPath().normalize()
+ return try {
+ val relativePath = file.toPath().normalize()
+ relativePath.startsWith(base)
+ } catch (e: IOException) {
+ false
+ }
+ }
+
+ private fun associate(sources: List<KSFile>, path: String, baseDir: File) {
+ val file = File(baseDir, path)
+ if (!isWithinBaseDir(baseDir, file)) {
+ throw IllegalStateException("requested path is outside the bounds of the required directory")
+ }
+ associate(sources, file)
+ }
+
+ private fun associate(sources: List<KSFile>, outputPath: File) {
+ if (!isIncremental)
+ return
+
+ val output = outputPath.relativeTo(projectBase)
+ sources.forEach { source ->
+ sourceToOutputs.getOrPut(File(source.filePath).relativeTo(projectBase)) { mutableSetOf() }.add(output)
+ }
+ }
+
+ val outputs: Set<File>
+ get() = fileMap.values.mapTo(mutableSetOf()) { it.relativeTo(projectBase) }
+
+ override val generatedFile: Collection<File>
+ get() = fileOutputStreamMap.keys.map { fileMap[it]!! }
+}
diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/processing/impl/KSNameImpl.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/processing/impl/KSNameImpl.kt
new file mode 100644
index 00000000..8697eaa2
--- /dev/null
+++ b/common-util/src/main/kotlin/com/google/devtools/ksp/processing/impl/KSNameImpl.kt
@@ -0,0 +1,22 @@
+package com.google.devtools.ksp.processing.impl
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.KSName
+
+class KSNameImpl private constructor(val name: String) : KSName {
+ companion object : KSObjectCache<String, KSNameImpl>() {
+ fun getCached(name: String) = cache.getOrPut(name) { KSNameImpl(name) }
+ }
+
+ override fun asString(): String {
+ return name
+ }
+
+ override fun getQualifier(): String {
+ return name.split(".").dropLast(1).joinToString(".")
+ }
+
+ override fun getShortName(): String {
+ return name.split(".").last()
+ }
+}
diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/processing/impl/PlatformInfoImpl.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/processing/impl/PlatformInfoImpl.kt
new file mode 100644
index 00000000..cccae381
--- /dev/null
+++ b/common-util/src/main/kotlin/com/google/devtools/ksp/processing/impl/PlatformInfoImpl.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processing.impl
+
+import com.google.devtools.ksp.processing.JsPlatformInfo
+import com.google.devtools.ksp.processing.JvmPlatformInfo
+import com.google.devtools.ksp.processing.NativePlatformInfo
+import com.google.devtools.ksp.processing.UnknownPlatformInfo
+
+class JvmPlatformInfoImpl(
+ override val platformName: String,
+ override val jvmTarget: String
+) : JvmPlatformInfo {
+ override fun toString() = "$platformName ($jvmTarget)"
+}
+
+class JsPlatformInfoImpl(
+ override val platformName: String
+) : JsPlatformInfo {
+ override fun toString() = platformName
+}
+
+class NativePlatformInfoImpl(
+ override val platformName: String,
+ override val targetName: String
+) : NativePlatformInfo {
+ override fun toString() = "$platformName ($targetName)"
+}
+
+class UnknownPlatformInfoImpl(
+ override val platformName: String
+) : UnknownPlatformInfo {
+ override fun toString() = platformName
+}
diff --git a/common-util/src/main/kotlin/com/google/devtools/ksp/visitor/CollectAnnotatedSymbolsVisitor.kt b/common-util/src/main/kotlin/com/google/devtools/ksp/visitor/CollectAnnotatedSymbolsVisitor.kt
new file mode 100644
index 00000000..02d9fabb
--- /dev/null
+++ b/common-util/src/main/kotlin/com/google/devtools/ksp/visitor/CollectAnnotatedSymbolsVisitor.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.visitor
+
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSFile
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSPropertyGetter
+import com.google.devtools.ksp.symbol.KSPropertySetter
+import com.google.devtools.ksp.symbol.KSTypeAlias
+import com.google.devtools.ksp.symbol.KSTypeParameter
+import com.google.devtools.ksp.symbol.KSValueParameter
+import com.google.devtools.ksp.symbol.KSVisitorVoid
+
+// TODO: Make visitor a generator
+class CollectAnnotatedSymbolsVisitor(private val inDepth: Boolean) : KSVisitorVoid() {
+ val symbols = arrayListOf<KSAnnotated>()
+
+ override fun visitAnnotated(annotated: KSAnnotated, data: Unit) {
+ if (annotated.annotations.any())
+ symbols.add(annotated)
+ }
+
+ override fun visitFile(file: KSFile, data: Unit) {
+ visitAnnotated(file, data)
+ file.declarations.forEach { it.accept(this, data) }
+ }
+
+ override fun visitTypeAlias(typeAlias: KSTypeAlias, data: Unit) {
+ if (typeAlias.annotations.any())
+ symbols.add(typeAlias)
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ visitAnnotated(classDeclaration, data)
+ classDeclaration.typeParameters.forEach { it.accept(this, data) }
+ classDeclaration.declarations.forEach { it.accept(this, data) }
+ }
+
+ override fun visitPropertyGetter(getter: KSPropertyGetter, data: Unit) {
+ visitAnnotated(getter, data)
+ }
+
+ override fun visitPropertySetter(setter: KSPropertySetter, data: Unit) {
+ setter.parameter.accept(this, data)
+ visitAnnotated(setter, data)
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ visitAnnotated(function, data)
+ function.typeParameters.forEach { it.accept(this, data) }
+ function.parameters.forEach { it.accept(this, data) }
+ if (inDepth) {
+ function.declarations.forEach { it.accept(this, data) }
+ }
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ visitAnnotated(property, data)
+ property.typeParameters.forEach { it.accept(this, data) }
+ property.getter?.accept(this, data)
+ property.setter?.accept(this, data)
+ }
+
+ override fun visitTypeParameter(typeParameter: KSTypeParameter, data: Unit) {
+ visitAnnotated(typeParameter, data)
+ super.visitTypeParameter(typeParameter, data)
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: Unit) {
+ visitAnnotated(valueParameter, data)
+ }
+}
diff --git a/common-util/src/test/kotlin/com/google/devtools/ksp/MemoizedSequenceTest.kt b/common-util/src/test/kotlin/com/google/devtools/ksp/MemoizedSequenceTest.kt
new file mode 100644
index 00000000..52ac4b2a
--- /dev/null
+++ b/common-util/src/test/kotlin/com/google/devtools/ksp/MemoizedSequenceTest.kt
@@ -0,0 +1,27 @@
+package com.google.devtools.ksp
+
+import org.junit.Assert
+import org.junit.Test
+
+class MemoizedSequenceTest {
+ @Test
+ fun testConcurrentRead() {
+ val memoized = MemoizedSequence(
+ sequenceOf(1, 2, 3, 4, 5, 6)
+ )
+ val s1 = memoized.iterator()
+ val s2 = memoized.iterator()
+ val s1read = mutableListOf<Int>()
+ val s2read = mutableListOf<Int>()
+ while (s1.hasNext() || s2.hasNext()) {
+ if (s1.hasNext()) {
+ s1read.add(s1.next())
+ }
+ if (s2.hasNext()) {
+ s2read.add(s2.next())
+ }
+ }
+ Assert.assertEquals(listOf(1, 2, 3, 4, 5, 6), s1read)
+ Assert.assertEquals(listOf(1, 2, 3, 4, 5, 6), s2read)
+ }
+}
diff --git a/common-util/src/test/kotlin/com/google/devtools/ksp/processing/impl/CodeGeneratorImplTest.kt b/common-util/src/test/kotlin/com/google/devtools/ksp/processing/impl/CodeGeneratorImplTest.kt
new file mode 100644
index 00000000..cd958f97
--- /dev/null
+++ b/common-util/src/test/kotlin/com/google/devtools/ksp/processing/impl/CodeGeneratorImplTest.kt
@@ -0,0 +1,128 @@
+package com.google.devtools.ksp.processing.impl
+
+import com.google.devtools.ksp.AnyChanges
+import com.google.devtools.ksp.processing.Dependencies
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Test
+import java.io.File
+import java.nio.file.Files
+
+class CodeGeneratorImplTest {
+
+ lateinit var codeGenerator: CodeGeneratorImpl
+ lateinit var baseDir: File
+
+ @Before
+ fun setup() {
+ baseDir = Files.createTempDirectory("project").toFile()
+ val classesDir = File(baseDir, "classes")
+ classesDir.mkdir()
+ val javaDir = File(baseDir, "java")
+ javaDir.mkdir()
+ val kotlinDir = File(baseDir, "kotlin")
+ kotlinDir.mkdir()
+ val resourcesDir = File(baseDir, "resources")
+ resourcesDir.mkdir()
+ codeGenerator = CodeGeneratorImpl(
+ classesDir,
+ javaDir,
+ kotlinDir,
+ resourcesDir,
+ baseDir,
+ AnyChanges(baseDir),
+ emptyList(),
+ true
+ )
+ }
+
+ @Test
+ fun testCreatingAFile() {
+ codeGenerator.createNewFile(Dependencies.ALL_FILES, "a.b.c", "Test", "java")
+ codeGenerator.createNewFile(Dependencies.ALL_FILES, "a.b.c", "Test", "kt")
+ codeGenerator.createNewFile(Dependencies.ALL_FILES, "a.b.c", "Test", "class")
+ codeGenerator.createNewFile(Dependencies.ALL_FILES, "a.b.c", "Test", "")
+
+ val files = codeGenerator.generatedFile.toList()
+ Assert.assertEquals(File(baseDir, "java/a/b/c/Test.java"), files[0])
+ Assert.assertEquals(File(baseDir, "kotlin/a/b/c/Test.kt"), files[1])
+ Assert.assertEquals(File(baseDir, "classes/a/b/c/Test.class"), files[2])
+ Assert.assertEquals(File(baseDir, "resources/a/b/c/Test"), files[3])
+
+ try {
+ codeGenerator.outputs
+ } catch (e: Exception) {
+ Assert.fail("Failed to get outputs: ${e.message}")
+ }
+ }
+
+ @Test
+ fun testCreatingAFileWithSlash() {
+ codeGenerator.createNewFile(Dependencies.ALL_FILES, "a/b/c", "Test", "java")
+ codeGenerator.createNewFile(Dependencies.ALL_FILES, "a/b/c", "Test", "kt")
+ codeGenerator.createNewFile(Dependencies.ALL_FILES, "a/b/c", "Test", "class")
+ codeGenerator.createNewFile(Dependencies.ALL_FILES, "a/b/c", "Test", "")
+
+ val files = codeGenerator.generatedFile.toList()
+ Assert.assertEquals(File(baseDir, "java/a/b/c/Test.java"), files[0])
+ Assert.assertEquals(File(baseDir, "kotlin/a/b/c/Test.kt"), files[1])
+ Assert.assertEquals(File(baseDir, "classes/a/b/c/Test.class"), files[2])
+ Assert.assertEquals(File(baseDir, "resources/a/b/c/Test"), files[3])
+
+ try {
+ codeGenerator.outputs
+ } catch (e: Exception) {
+ Assert.fail("Failed to get outputs: ${e.message}")
+ }
+ }
+
+ @Test
+ fun testCreatingAFileWithPath() {
+ codeGenerator.createNewFileByPath(Dependencies.ALL_FILES, "a/b/c/Test", "java")
+ codeGenerator.createNewFileByPath(Dependencies.ALL_FILES, "a/b/c/Test")
+ codeGenerator.createNewFileByPath(Dependencies.ALL_FILES, "a/b/c/Test", "class")
+ codeGenerator.createNewFileByPath(Dependencies.ALL_FILES, "a/b/c/Test", "")
+
+ val files = codeGenerator.generatedFile.toList()
+ Assert.assertEquals(File(baseDir, "java/a/b/c/Test.java"), files[0])
+ Assert.assertEquals(File(baseDir, "kotlin/a/b/c/Test.kt"), files[1])
+ Assert.assertEquals(File(baseDir, "classes/a/b/c/Test.class"), files[2])
+ Assert.assertEquals(File(baseDir, "resources/a/b/c/Test"), files[3])
+
+ try {
+ codeGenerator.outputs
+ } catch (e: Exception) {
+ Assert.fail("Failed to get outputs: ${e.message}")
+ }
+ }
+
+ @Test
+ fun testCreatingAFileWithPathAndDots() {
+ codeGenerator.createNewFileByPath(Dependencies.ALL_FILES, "a/b/c/dir.with.dot/Test", "java")
+ codeGenerator.createNewFileByPath(Dependencies.ALL_FILES, "a/b/c/dir.with.dot/Test")
+ codeGenerator.createNewFileByPath(Dependencies.ALL_FILES, "a/b/c/dir.with.dot/Test", "class")
+ codeGenerator.createNewFileByPath(Dependencies.ALL_FILES, "a/b/c/dir.with.dot/Test", "")
+
+ val files = codeGenerator.generatedFile.toList()
+ Assert.assertEquals(File(baseDir, "java/a/b/c/dir.with.dot/Test.java"), files[0])
+ Assert.assertEquals(File(baseDir, "kotlin/a/b/c/dir.with.dot/Test.kt"), files[1])
+ Assert.assertEquals(File(baseDir, "classes/a/b/c/dir.with.dot/Test.class"), files[2])
+ Assert.assertEquals(File(baseDir, "resources/a/b/c/dir.with.dot/Test"), files[3])
+
+ try {
+ codeGenerator.outputs
+ } catch (e: Exception) {
+ Assert.fail("Failed to get outputs: ${e.message}")
+ }
+ }
+
+ @Test
+ fun testCreatingAFileByPathWithInvalidPath() {
+ try {
+ codeGenerator.createNewFileByPath(Dependencies.ALL_FILES, "../../b/c/Test", "java")
+ Assert.fail()
+ } catch (e: java.lang.IllegalStateException) {
+ Assert.assertEquals(e.message, "requested path is outside the bounds of the required directory")
+ }
+ }
+}
diff --git a/compiler-plugin/build.gradle.kts b/compiler-plugin/build.gradle.kts
new file mode 100644
index 00000000..47d18317
--- /dev/null
+++ b/compiler-plugin/build.gradle.kts
@@ -0,0 +1,121 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+evaluationDependsOn(":common-util")
+
+description = "Kotlin Symbol Processing"
+
+val intellijVersion: String by project
+val kotlinBaseVersion: String by project
+
+val libsForTesting by configurations.creating
+
+tasks.withType<KotlinCompile> {
+ compilerOptions.freeCompilerArgs.add("-Xjvm-default=all-compatibility")
+}
+
+plugins {
+ kotlin("jvm")
+ id("org.jetbrains.intellij") version "0.6.4"
+ id("org.jetbrains.dokka") version ("1.7.20")
+}
+
+intellij {
+ version = intellijVersion
+}
+
+tasks {
+ val sourcesJar by creating(Jar::class) {
+ archiveClassifier.set("sources")
+ from(sourceSets.main.get().allSource)
+ from(project(":common-util").sourceSets.main.get().allSource)
+ }
+}
+
+fun ModuleDependency.includeJars(vararg names: String) {
+ names.forEach {
+ artifact {
+ name = it
+ type = "jar"
+ extension = "jar"
+ }
+ }
+}
+
+// WARNING: remember to update the dependencies in symbol-processing as well.
+dependencies {
+ implementation(kotlin("stdlib", kotlinBaseVersion))
+ implementation("org.jetbrains.kotlin:kotlin-compiler:$kotlinBaseVersion")
+
+ implementation(project(":api"))
+ implementation(project(":common-util"))
+
+ testImplementation(kotlin("stdlib", kotlinBaseVersion))
+ testImplementation("org.jetbrains.kotlin:kotlin-compiler:$kotlinBaseVersion")
+ testImplementation("org.jetbrains.kotlin:kotlin-compiler-internal-test-framework:$kotlinBaseVersion")
+ testImplementation("org.jetbrains.kotlin:kotlin-scripting-compiler:$kotlinBaseVersion")
+
+ testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-params:5.8.2")
+ testRuntimeOnly("org.junit.platform:junit-platform-suite:1.8.2")
+
+ testImplementation(project(":api"))
+ testImplementation(project(":common-util"))
+ testImplementation(project(":test-utils"))
+
+ libsForTesting(kotlin("stdlib", kotlinBaseVersion))
+ libsForTesting(kotlin("test", kotlinBaseVersion))
+ libsForTesting(kotlin("script-runtime", kotlinBaseVersion))
+}
+
+tasks.register<Copy>("CopyLibsForTesting") {
+ from(configurations.get("libsForTesting"))
+ into("dist/kotlinc/lib")
+ val escaped = Regex.escape(kotlinBaseVersion)
+ rename("(.+)-$escaped\\.jar", "$1.jar")
+}
+
+fun Project.javaPluginConvention(): JavaPluginConvention = the()
+val JavaPluginConvention.testSourceSet: SourceSet
+ get() = sourceSets.getByName("test")
+val Project.testSourceSet: SourceSet
+ get() = javaPluginConvention().testSourceSet
+
+tasks.test {
+ dependsOn("CopyLibsForTesting")
+ maxHeapSize = "2g"
+
+ useJUnitPlatform()
+
+ systemProperty("idea.is.unit.test", "true")
+ systemProperty("idea.home.path", buildDir)
+ systemProperty("java.awt.headless", "true")
+ environment("NO_FS_ROOTS_ACCESS_CHECK", "true")
+ environment("PROJECT_CLASSES_DIRS", testSourceSet.output.classesDirs.asPath)
+ environment("PROJECT_BUILD_DIR", buildDir)
+ testLogging {
+ events("passed", "skipped", "failed")
+ }
+
+ var tempTestDir: File? = null
+ doFirst {
+ tempTestDir = createTempDir()
+ systemProperty("java.io.tmpdir", tempTestDir.toString())
+ }
+
+ doLast {
+ tempTestDir?.let { delete(it) }
+ }
+}
+
+repositories {
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ maven("https://www.jetbrains.com/intellij-repository/snapshots")
+}
+
+val dokkaJavadocJar by tasks.register<Jar>("dokkaJavadocJar") {
+ dependsOn(tasks.dokkaJavadoc)
+ from(tasks.dokkaJavadoc.flatMap { it.outputDirectory })
+ from(project(":common-util").tasks.dokkaJavadoc.flatMap { it.outputDirectory })
+ archiveClassifier.set("javadoc")
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/DualLookupTracker.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/DualLookupTracker.kt
new file mode 100644
index 00000000..86acaf60
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/DualLookupTracker.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp
+
+import org.jetbrains.kotlin.incremental.LookupTrackerImpl
+import org.jetbrains.kotlin.incremental.components.LookupTracker
+import org.jetbrains.kotlin.incremental.components.Position
+import org.jetbrains.kotlin.incremental.components.ScopeKind
+
+class DualLookupTracker : LookupTracker {
+ val symbolTracker = LookupTrackerImpl(LookupTracker.DO_NOTHING)
+ val classTracker = LookupTrackerImpl(LookupTracker.DO_NOTHING)
+
+ override val requiresPosition: Boolean
+ get() = symbolTracker.requiresPosition || classTracker.requiresPosition
+
+ override fun record(filePath: String, position: Position, scopeFqName: String, scopeKind: ScopeKind, name: String) {
+ symbolTracker.record(filePath, position, scopeFqName, scopeKind, name)
+ if (scopeKind == ScopeKind.CLASSIFIER) {
+ val className = scopeFqName.substringAfterLast('.')
+ val outerScope = scopeFqName.substringBeforeLast('.', "<anonymous>")
+ // DO NOT USE: ScopeKind is meaningless
+ classTracker.record(filePath, position, outerScope, scopeKind, className)
+ }
+ }
+
+ override fun clear() {
+ // Do not clear symbolTracker and classTracker.
+ // LookupTracker.clear() is called in repeatAnalysisIfNeeded, but we need records across all rounds.
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/Incremental.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/Incremental.kt
new file mode 100644
index 00000000..ed528641
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/Incremental.kt
@@ -0,0 +1,786 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp
+
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.findPsi
+import com.google.devtools.ksp.symbol.impl.java.KSFunctionDeclarationJavaImpl
+import com.google.devtools.ksp.symbol.impl.java.KSPropertyDeclarationJavaImpl
+import com.google.devtools.ksp.visitor.KSDefaultVisitor
+import com.intellij.psi.*
+import com.intellij.psi.impl.source.PsiClassReferenceType
+import com.intellij.util.containers.MultiMap
+import com.intellij.util.io.DataExternalizer
+import com.intellij.util.io.IOUtil
+import com.intellij.util.io.KeyDescriptor
+import org.jetbrains.kotlin.container.ComponentProvider
+import org.jetbrains.kotlin.container.get
+import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.incremental.*
+import org.jetbrains.kotlin.incremental.components.LookupTracker
+import org.jetbrains.kotlin.incremental.components.Position
+import org.jetbrains.kotlin.incremental.components.ScopeKind
+import org.jetbrains.kotlin.incremental.storage.BasicMap
+import org.jetbrains.kotlin.incremental.storage.CollectionExternalizer
+import org.jetbrains.kotlin.incremental.storage.FileToPathConverter
+import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.typeUtil.supertypes
+import java.io.DataInput
+import java.io.DataOutput
+import java.io.File
+import java.nio.file.Files
+import java.nio.file.StandardCopyOption
+import java.util.*
+
+abstract class PersistentMap<K : Comparable<K>, V>(
+ storageFile: File,
+ keyDescriptor: KeyDescriptor<K>,
+ valueExternalizer: DataExternalizer<V>,
+) : BasicMap<K, V>(storageFile, keyDescriptor, valueExternalizer) {
+ abstract operator fun get(key: K): V?
+ abstract operator fun set(key: K, value: V)
+ abstract fun remove(key: K)
+}
+
+class FileToSymbolsMap(storageFile: File) : PersistentMap<File, Collection<LookupSymbol>>(
+ storageFile,
+ FileKeyDescriptor,
+ CollectionExternalizer(LookupSymbolExternalizer, { HashSet() })
+) {
+ override fun dumpKey(key: File): String = key.toString()
+
+ override fun dumpValue(value: Collection<LookupSymbol>): String = value.toString()
+
+ fun add(file: File, symbol: LookupSymbol) {
+ storage.append(file, listOf(symbol))
+ }
+
+ override operator fun get(key: File): Collection<LookupSymbol>? = storage[key]
+
+ override operator fun set(key: File, symbols: Collection<LookupSymbol>) {
+ storage[key] = symbols
+ }
+
+ override fun remove(key: File) {
+ storage.remove(key)
+ }
+
+ val keys: Collection<File>
+ get() = storage.keys
+}
+
+object FileKeyDescriptor : KeyDescriptor<File> {
+ override fun read(input: DataInput): File {
+ return File(IOUtil.readString(input))
+ }
+
+ override fun save(output: DataOutput, value: File) {
+ IOUtil.writeString(value.path, output)
+ }
+
+ override fun getHashCode(value: File): Int = value.hashCode()
+
+ override fun isEqual(val1: File, val2: File): Boolean = val1 == val2
+}
+
+object LookupSymbolExternalizer : DataExternalizer<LookupSymbol> {
+ override fun read(input: DataInput): LookupSymbol = LookupSymbol(IOUtil.readString(input), IOUtil.readString(input))
+
+ override fun save(output: DataOutput, value: LookupSymbol) {
+ IOUtil.writeString(value.name, output)
+ IOUtil.writeString(value.scope, output)
+ }
+}
+
+object FileExternalizer : DataExternalizer<File> {
+ override fun read(input: DataInput): File = File(IOUtil.readString(input))
+
+ override fun save(output: DataOutput, value: File) {
+ IOUtil.writeString(value.path, output)
+ }
+}
+
+class FileToFilesMap(storageFile: File) : PersistentMap<File, Collection<File>>(
+ storageFile,
+ FileKeyDescriptor,
+ CollectionExternalizer(FileExternalizer, { HashSet() })
+) {
+
+ override operator fun get(key: File): Collection<File>? = storage[key]
+
+ override operator fun set(key: File, value: Collection<File>) {
+ storage[key] = value
+ }
+
+ override fun dumpKey(key: File): String = key.path
+
+ override fun dumpValue(value: Collection<File>) =
+ value.dumpCollection()
+
+ override fun remove(key: File) {
+ storage.remove(key)
+ }
+
+ val keys: Collection<File>
+ get() = storage.keys
+}
+
+object symbolCollector : KSDefaultVisitor<(LookupSymbol) -> Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: (LookupSymbol) -> Unit) = Unit
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: (LookupSymbol) -> Unit) {
+ if (declaration.isPrivate())
+ return
+
+ val name = declaration.simpleName.asString()
+ val scope =
+ declaration.qualifiedName?.asString()?.let { it.substring(0, Math.max(it.length - name.length - 1, 0)) }
+ ?: return
+ data(LookupSymbol(name, scope))
+ }
+
+ override fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: (LookupSymbol) -> Unit) {
+ // Local declarations aren't visible to other files / classes.
+ if (declarationContainer is KSFunctionDeclaration)
+ return
+
+ declarationContainer.declarations.forEach {
+ it.accept(this, data)
+ }
+ }
+}
+
+internal class RelativeFileToPathConverter(val baseDir: File) : FileToPathConverter {
+ override fun toPath(file: File): String = file.path
+ override fun toFile(path: String): File = File(path).relativeTo(baseDir)
+}
+
+class IncrementalContext(
+ private val options: KspOptions,
+ private val componentProvider: ComponentProvider,
+ private val anyChangesWildcard: File,
+) {
+ // Symbols defined in changed files. This is used to update symbolsMap in the end.
+ private val updatedSymbols = MultiMap.createSet<File, LookupSymbol>()
+
+ // Sealed classes / interfaces on which `getSealedSubclasses` is invoked.
+ // This is used to update sealedMap in the end.
+ private val updatedSealed = MultiMap.createSet<File, LookupSymbol>()
+
+ // Sealed classes / interfaces on which `getSealedSubclasses` is invoked.
+ // This is saved across processing.
+ private val sealedMap = FileToSymbolsMap(File(options.cachesDir, "sealed"))
+
+ // Symbols defined in each file. This is saved across processing.
+ private val symbolsMap = FileToSymbolsMap(File(options.cachesDir, "symbols"))
+
+ private val cachesUpToDateFile = File(options.cachesDir, "caches.uptodate")
+ private val rebuild = !cachesUpToDateFile.exists()
+
+ private val baseDir = options.projectBaseDir
+
+ private val logsDir = File(options.cachesDir, "logs").apply { mkdirs() }
+ private val buildTime = Date().time
+
+ private val modified = options.knownModified.map { it.relativeTo(baseDir) }.toSet()
+ private val removed = options.knownRemoved.map { it.relativeTo(baseDir) }.toSet()
+
+ private val lookupTracker: LookupTracker = componentProvider.get()
+
+ // Disable incremental processing if somehow DualLookupTracker failed to be registered.
+ // This may happen when a platform hasn't support incremental compilation yet. E.g, Common / Metadata.
+ private val isIncremental = options.incremental && lookupTracker is DualLookupTracker
+ private val PATH_CONVERTER = RelativeFileToPathConverter(baseDir)
+
+ private val symbolLookupTracker = (lookupTracker as? DualLookupTracker)?.symbolTracker ?: LookupTracker.DO_NOTHING
+ private val symbolLookupCacheDir = File(options.cachesDir, "symbolLookups")
+ private val symbolLookupCache = LookupStorage(symbolLookupCacheDir, PATH_CONVERTER)
+
+ // TODO: rewrite LookupStorage to share file-to-id, etc.
+ private val classLookupTracker = (lookupTracker as? DualLookupTracker)?.classTracker ?: LookupTracker.DO_NOTHING
+ private val classLookupCacheDir = File(options.cachesDir, "classLookups")
+ private val classLookupCache = LookupStorage(classLookupCacheDir, PATH_CONVERTER)
+
+ private val sourceToOutputsMap = FileToFilesMap(File(options.cachesDir, "sourceToOutputs"))
+
+ private fun String.toRelativeFile() = File(this).relativeTo(baseDir)
+ private val KSFile.relativeFile
+ get() = filePath.toRelativeFile()
+
+ private fun collectDefinedSymbols(ksFiles: Collection<KSFile>) {
+ ksFiles.forEach { file ->
+ file.accept(symbolCollector) {
+ updatedSymbols.putValue(file.relativeFile, it)
+ }
+ }
+ }
+
+ private val removedOutputsKey = File("<This is a virtual key for removed outputs; DO NOT USE>")
+
+ private fun updateFromRemovedOutputs() {
+ val removedOutputs = sourceToOutputsMap.get(removedOutputsKey) ?: return
+
+ symbolLookupCache.removeLookupsFrom(removedOutputs.asSequence())
+ classLookupCache.removeLookupsFrom(removedOutputs.asSequence())
+ removedOutputs.forEach {
+ symbolsMap.remove(it)
+ sealedMap.remove(it)
+ }
+
+ sourceToOutputsMap.remove(removedOutputsKey)
+ }
+
+ private fun updateLookupCache(dirtyFiles: Collection<File>) {
+ symbolLookupCache.update(symbolLookupTracker, dirtyFiles, options.knownRemoved)
+ symbolLookupCache.flush(false)
+ symbolLookupCache.close()
+
+ classLookupCache.update(classLookupTracker, dirtyFiles, options.knownRemoved)
+ classLookupCache.flush(false)
+ classLookupCache.close()
+ }
+
+ private fun logSourceToOutputs(outputs: Set<File>, sourceToOutputs: Map<File, Set<File>>) {
+ if (!options.incrementalLog)
+ return
+
+ val logFile = File(logsDir, "kspSourceToOutputs.log")
+ logFile.appendText("=== Build $buildTime ===\n")
+ logFile.appendText("Accumulated source to outputs map\n")
+ sourceToOutputsMap.keys.forEach { source ->
+ logFile.appendText(" $source:\n")
+ sourceToOutputsMap[source]!!.forEach { output ->
+ logFile.appendText(" $output\n")
+ }
+ }
+ logFile.appendText("\n")
+
+ logFile.appendText("Reprocessed sources and their outputs\n")
+ sourceToOutputs.forEach { (source, outputs) ->
+ logFile.appendText(" $source:\n")
+ outputs.forEach {
+ logFile.appendText(" $it\n")
+ }
+ }
+ logFile.appendText("\n")
+
+ // Can be larger than the union of the above, because some outputs may have no source.
+ logFile.appendText("All reprocessed outputs\n")
+ outputs.forEach {
+ logFile.appendText(" $it\n")
+ }
+ logFile.appendText("\n")
+ }
+
+ private fun logDirtyFiles(
+ files: Collection<KSFile>,
+ allFiles: Collection<KSFile>,
+ removedOutputs: Collection<File> = emptyList(),
+ dirtyFilesByCP: Collection<File> = emptyList(),
+ dirtyFilesByNewSyms: Collection<File> = emptyList(),
+ dirtyFilesBySealed: Collection<File> = emptyList(),
+ ) {
+ if (!options.incrementalLog)
+ return
+
+ val logFile = File(logsDir, "kspDirtySet.log")
+ logFile.appendText("=== Build $buildTime ===\n")
+ logFile.appendText("All Files\n")
+ allFiles.forEach { logFile.appendText(" ${it.relativeFile}\n") }
+ logFile.appendText("Modified\n")
+ modified.forEach { logFile.appendText(" $it\n") }
+ logFile.appendText("Removed\n")
+ removed.forEach { logFile.appendText(" $it\n") }
+ logFile.appendText("Disappeared Outputs\n")
+ removedOutputs.forEach { logFile.appendText(" $it\n") }
+ logFile.appendText("Affected By CP\n")
+ dirtyFilesByCP.forEach { logFile.appendText(" $it\n") }
+ logFile.appendText("Affected By new syms\n")
+ dirtyFilesByNewSyms.forEach { logFile.appendText(" $it\n") }
+ logFile.appendText("Affected By sealed\n")
+ dirtyFilesBySealed.forEach { logFile.appendText(" $it\n") }
+ logFile.appendText("CP changes\n")
+ options.changedClasses.forEach { logFile.appendText(" $it\n") }
+ logFile.appendText("Dirty:\n")
+ files.forEach {
+ logFile.appendText(" ${it.relativeFile}\n")
+ }
+ val percentage = "%.2f".format(files.size.toDouble() / allFiles.size.toDouble() * 100)
+ logFile.appendText("\nDirty / All: $percentage%\n\n")
+ }
+
+ // Beware: no side-effects here; Caches should only be touched in updateCaches.
+ fun calcDirtyFiles(ksFiles: List<KSFile>): Collection<KSFile> = closeFilesOnException {
+ if (!isIncremental) {
+ return ksFiles
+ }
+
+ if (rebuild) {
+ collectDefinedSymbols(ksFiles)
+ logDirtyFiles(ksFiles, ksFiles)
+ return ksFiles
+ }
+
+ val newSyms = mutableSetOf<LookupSymbol>()
+
+ // Parse and add newly defined symbols in modified files.
+ ksFiles.filter { it.relativeFile in modified }.forEach { file ->
+ file.accept(symbolCollector) {
+ updatedSymbols.putValue(file.relativeFile, it)
+ newSyms.add(it)
+ }
+ }
+
+ val dirtyFilesByNewSyms = newSyms.flatMap {
+ symbolLookupCache.get(it).map { File(it) }
+ }
+
+ val dirtyFilesBySealed = sealedMap.keys.flatMap { sealedMap[it]!! }.flatMap {
+ symbolLookupCache.get(it).map { File(it) }
+ }
+
+ // Calculate dirty files by dirty classes in CP.
+ val dirtyFilesByCP = options.changedClasses.flatMap { fqn ->
+ val name = fqn.substringAfterLast('.')
+ val scope = fqn.substringBeforeLast('.', "<anonymous>")
+ classLookupCache.get(LookupSymbol(name, scope)).map { File(it) } +
+ symbolLookupCache.get(LookupSymbol(name, scope)).map { File(it) }
+ }.toSet()
+
+ // output files that exist in CURR~2 but not in CURR~1
+ val removedOutputs = sourceToOutputsMap.get(removedOutputsKey) ?: emptyList()
+
+ val noSourceFiles = options.changedClasses.map { fqn ->
+ NoSourceFile(baseDir, fqn).filePath.toRelativeFile()
+ }.toSet()
+
+ val initialSet = mutableSetOf<File>()
+ initialSet.addAll(modified)
+ initialSet.addAll(removed)
+ initialSet.addAll(removedOutputs)
+ initialSet.addAll(dirtyFilesByCP)
+ initialSet.addAll(dirtyFilesByNewSyms)
+ initialSet.addAll(dirtyFilesBySealed)
+ initialSet.addAll(noSourceFiles)
+
+ // modified can be seen as removed + new. Therefore the following check doesn't work:
+ // if (modified.any { it !in sourceToOutputsMap.keys }) ...
+ if (modified.isNotEmpty() || options.changedClasses.isNotEmpty()) {
+ initialSet.add(anyChangesWildcard)
+ }
+
+ val dirtyFiles = DirtinessPropagator(
+ symbolLookupCache,
+ symbolsMap,
+ sourceToOutputsMap,
+ anyChangesWildcard,
+ removedOutputsKey
+ ).propagate(initialSet)
+
+ updateFromRemovedOutputs()
+
+ logDirtyFiles(
+ ksFiles.filter { it.relativeFile in dirtyFiles },
+ ksFiles,
+ removedOutputs,
+ dirtyFilesByCP,
+ dirtyFilesByNewSyms,
+ dirtyFilesBySealed
+ )
+ return ksFiles.filter { it.relativeFile in dirtyFiles }
+ }
+
+ private fun updateSourceToOutputs(
+ dirtyFiles: Collection<File>,
+ outputs: Set<File>,
+ sourceToOutputs: Map<File, Set<File>>,
+ removedOutputs: List<File>,
+ ) {
+ // Prune deleted sources in source-to-outputs map.
+ removed.forEach {
+ sourceToOutputsMap.remove(it)
+ }
+
+ dirtyFiles.filterNot { sourceToOutputs.containsKey(it) }.forEach {
+ sourceToOutputsMap.remove(it)
+ }
+
+ removedOutputs.forEach {
+ sourceToOutputsMap.remove(it)
+ }
+ sourceToOutputsMap[removedOutputsKey] = removedOutputs
+
+ // Update source-to-outputs map from those reprocessed.
+ sourceToOutputs.forEach { src, outs ->
+ sourceToOutputsMap[src] = outs
+ }
+
+ logSourceToOutputs(outputs, sourceToOutputs)
+
+ sourceToOutputsMap.flush(false)
+ }
+
+ private fun updateOutputs(outputs: Set<File>, cleanOutputs: Collection<File>) {
+ val outRoot = options.kspOutputDir
+ val bakRoot = File(options.cachesDir, "backups")
+
+ fun File.abs() = File(baseDir, path)
+ fun File.bak() = File(bakRoot, abs().toRelativeString(outRoot))
+
+ // Copy recursively, including last-modified-time of file and its parent dirs.
+ //
+ // `java.nio.file.Files.copy(path1, path2, options...)` keeps last-modified-time (if supported) according to
+ // https://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html
+ fun copy(src: File, dst: File, overwrite: Boolean) {
+ if (!dst.parentFile.exists())
+ copy(src.parentFile, dst.parentFile, false)
+ if (overwrite) {
+ Files.copy(
+ src.toPath(),
+ dst.toPath(),
+ StandardCopyOption.COPY_ATTRIBUTES,
+ StandardCopyOption.REPLACE_EXISTING
+ )
+ } else {
+ Files.copy(src.toPath(), dst.toPath(), StandardCopyOption.COPY_ATTRIBUTES)
+ }
+ }
+
+ // Backing up outputs is necessary for two reasons:
+ //
+ // 1. Currently, outputs are always cleaned up in gradle plugin before compiler is called.
+ // Untouched outputs need to be restore.
+ //
+ // TODO: need a change in upstream to not clean files in gradle plugin.
+ // Not cleaning files in gradle plugin has potentially fewer copies when processing succeeds.
+ //
+ // 2. Even if outputs are left from last compilation / processing, processors can still
+ // fail and the outputs will need to be restored.
+
+ // Backup
+ outputs.forEach { generated ->
+ copy(generated.abs(), generated.bak(), true)
+ }
+
+ // Restore non-dirty outputs
+ cleanOutputs.forEach { dst ->
+ if (dst !in outputs) {
+ copy(dst.bak(), dst.abs(), false)
+ }
+ }
+ }
+
+ private fun updateCaches(dirtyFiles: Collection<File>, outputs: Set<File>, sourceToOutputs: Map<File, Set<File>>) {
+ // dirtyFiles may contain new files, which are unknown to sourceToOutputsMap.
+ val oldOutputs = dirtyFiles.flatMap { sourceToOutputsMap[it] ?: emptyList() }.distinct()
+ val removedOutputs = oldOutputs.filterNot { it in outputs }
+ updateSourceToOutputs(dirtyFiles, outputs, sourceToOutputs, removedOutputs)
+ updateLookupCache(dirtyFiles)
+
+ // Update symbolsMap
+ fun <K : Comparable<K>, V> update(m: PersistentMap<K, Collection<V>>, u: MultiMap<K, V>) {
+ // Update symbol caches from modified files.
+ u.keySet().forEach {
+ m.set(it, u[it].toSet())
+ }
+ }
+
+ fun <K : Comparable<K>, V> remove(m: PersistentMap<K, Collection<V>>, removedKeys: Collection<K>) {
+ // Remove symbol caches from removed files.
+ removedKeys.forEach {
+ m.remove(it)
+ }
+ }
+
+ if (!rebuild) {
+ update(sealedMap, updatedSealed)
+ remove(sealedMap, removed)
+
+ update(symbolsMap, updatedSymbols)
+ remove(symbolsMap, removed)
+ } else {
+ symbolsMap.clean()
+ update(symbolsMap, updatedSymbols)
+
+ sealedMap.clean()
+ update(sealedMap, updatedSealed)
+ }
+ symbolsMap.flush(false)
+ symbolsMap.close()
+ sealedMap.flush(false)
+ sealedMap.close()
+ }
+
+ fun registerGeneratedFiles(newFiles: Collection<KSFile>) = closeFilesOnException {
+ if (!isIncremental)
+ return@closeFilesOnException
+
+ collectDefinedSymbols(newFiles)
+ }
+
+ private inline fun <T> closeFilesOnException(f: () -> T): T {
+ try {
+ return f()
+ } catch (e: Exception) {
+ symbolsMap.close()
+ sealedMap.close()
+ symbolLookupCache.close()
+ classLookupCache.close()
+ sourceToOutputsMap.close()
+ throw e
+ }
+ }
+
+ // TODO: add a wildcard for outputs with no source and get rid of the outputs parameter.
+ fun updateCachesAndOutputs(
+ dirtyFiles: Collection<KSFile>,
+ outputs: Set<File>,
+ sourceToOutputs: Map<File, Set<File>>,
+ ) = closeFilesOnException {
+ if (!isIncremental)
+ return
+
+ cachesUpToDateFile.delete()
+ assert(!cachesUpToDateFile.exists())
+
+ val dirtyFilePaths = dirtyFiles.map { it.relativeFile }
+
+ updateCaches(dirtyFilePaths, outputs, sourceToOutputs)
+
+ val cleanOutputs = mutableSetOf<File>()
+ sourceToOutputsMap.keys.forEach { source ->
+ if (source !in dirtyFilePaths && source != anyChangesWildcard && source != removedOutputsKey)
+ cleanOutputs.addAll(sourceToOutputsMap[source]!!)
+ }
+ sourceToOutputsMap.close()
+ updateOutputs(outputs, cleanOutputs)
+
+ cachesUpToDateFile.createNewFile()
+ assert(cachesUpToDateFile.exists())
+ }
+
+ // Insert Java file -> names lookup records.
+ fun recordLookup(psiFile: PsiJavaFile, fqn: String) {
+ val path = psiFile.virtualFile.path
+ val name = fqn.substringAfterLast('.')
+ val scope = fqn.substringBeforeLast('.', "<anonymous>")
+
+ // Java types are classes. Therefore lookups only happen in packages.
+ fun record(scope: String, name: String) =
+ symbolLookupTracker.record(path, Position.NO_POSITION, scope, ScopeKind.PACKAGE, name)
+
+ record(scope, name)
+
+ // If a resolved name is from some * import, it is overridable by some out-of-file changes.
+ // Therefore, the potential providers all need to be inserted. They are
+ // 1. definition of the name in the same package
+ // 2. other * imports
+ val onDemandImports =
+ psiFile.getOnDemandImports(false, false).mapNotNull { (it as? PsiPackage)?.qualifiedName }
+ if (scope in onDemandImports) {
+ record(psiFile.packageName, name)
+ onDemandImports.forEach {
+ record(it, name)
+ }
+ }
+ }
+
+ // Record a *leaf* type reference. This doesn't address type arguments.
+ private fun recordLookup(ref: PsiClassReferenceType, def: PsiClass) {
+ val psiFile = ref.reference.containingFile as? PsiJavaFile ?: return
+ // A type parameter doesn't have qualified name.
+ //
+ // Note that bounds of type parameters, or other references in classes,
+ // are not addressed recursively here. They are recorded in other places
+ // with more contexts, when necessary.
+ def.qualifiedName?.let { recordLookup(psiFile, it) }
+ }
+
+ // Record a type reference, including its type arguments.
+ fun recordLookup(ref: PsiType) {
+ when (ref) {
+ is PsiArrayType -> recordLookup(ref.componentType)
+ is PsiClassReferenceType -> {
+ val def = ref.resolve() ?: return
+ recordLookup(ref, def)
+ // in case the corresponding KotlinType is passed through ways other than KSTypeReferenceJavaImpl
+ ref.typeArguments().forEach {
+ if (it is PsiType) {
+ recordLookup(it)
+ }
+ }
+ }
+ is PsiWildcardType -> ref.bound?.let { recordLookup(it) }
+ }
+ }
+
+ // Record all references to super types (if they are written in Java) of a given type,
+ // in its type hierarchy.
+ fun recordLookupWithSupertypes(kotlinType: KotlinType) {
+ (listOf(kotlinType) + kotlinType.supertypes()).mapNotNull {
+ it.constructor.declarationDescriptor?.findPsi() as? PsiClass
+ }.forEach {
+ it.superTypes.forEach {
+ recordLookup(it)
+ }
+ }
+ }
+
+ // Record all type references in a Java field.
+ private fun recordLookupForJavaField(psi: PsiField) {
+ recordLookup(psi.type)
+ }
+
+ // Record all type references in a Java method.
+ private fun recordLookupForJavaMethod(psi: PsiMethod) {
+ psi.parameterList.parameters.forEach {
+ recordLookup(it.type)
+ }
+ psi.returnType?.let { recordLookup(it) }
+ psi.typeParameters.forEach {
+ it.bounds.mapNotNull { it as? PsiType }.forEach {
+ recordLookup(it)
+ }
+ }
+ }
+
+ // Record all type references in a KSDeclaration
+ fun recordLookupForDeclaration(declaration: KSDeclaration) {
+ when (declaration) {
+ is KSPropertyDeclarationJavaImpl -> recordLookupForJavaField(declaration.psi)
+ is KSFunctionDeclarationJavaImpl -> recordLookupForJavaMethod(declaration.psi)
+ }
+ }
+
+ // Record all type references in a CallableMemberDescriptor
+ fun recordLookupForCallableMemberDescriptor(descriptor: CallableMemberDescriptor) {
+ val psi = descriptor.findPsi()
+ when (psi) {
+ is PsiMethod -> recordLookupForJavaMethod(psi)
+ is PsiField -> recordLookupForJavaField(psi)
+ }
+ }
+
+ // Record references from all declared functions in the type hierarchy of the given class.
+ // TODO: optimization: filter out inaccessible members
+ fun recordLookupForGetAllFunctions(descriptor: ClassDescriptor) {
+ recordLookupForGetAll(descriptor) {
+ it.methods.forEach {
+ recordLookupForJavaMethod(it)
+ }
+ }
+ }
+
+ // Record references from all declared fields in the type hierarchy of the given class.
+ // TODO: optimization: filter out inaccessible members
+ fun recordLookupForGetAllProperties(descriptor: ClassDescriptor) {
+ recordLookupForGetAll(descriptor) {
+ it.fields.forEach {
+ recordLookupForJavaField(it)
+ }
+ }
+ }
+
+ fun recordLookupForGetAll(descriptor: ClassDescriptor, doChild: (PsiClass) -> Unit) {
+ (descriptor.getAllSuperclassesWithoutAny() + descriptor).mapNotNull {
+ it.findPsi() as? PsiClass
+ }.forEach { psiClass ->
+ psiClass.superTypes.forEach {
+ recordLookup(it)
+ }
+ doChild(psiClass)
+ }
+ }
+
+ fun recordGetSealedSubclasses(classDeclaration: KSClassDeclaration) {
+ val name = classDeclaration.simpleName.asString()
+ val scope = classDeclaration.qualifiedName?.asString()
+ ?.let { it.substring(0, Math.max(it.length - name.length - 1, 0)) } ?: return
+ updatedSealed.putValue(classDeclaration.containingFile!!.relativeFile, LookupSymbol(name, scope))
+ }
+
+ // Debugging and testing only.
+ fun dumpLookupRecords(): Map<String, List<String>> {
+ val map = mutableMapOf<String, List<String>>()
+ (symbolLookupTracker as LookupTrackerImpl).lookups.entrySet().forEach { e ->
+ val key = "${e.key.scope}.${e.key.name}"
+ map[key] = e.value.map { PATH_CONVERTER.toFile(it).path }
+ }
+ return map
+ }
+}
+
+internal class DirtinessPropagator(
+ private val lookupCache: LookupStorage,
+ private val symbolsMap: FileToSymbolsMap,
+ private val sourceToOutputs: FileToFilesMap,
+ private val anyChangesWildcard: File,
+ private val removedOutputsKey: File
+) {
+ private val visitedFiles = mutableSetOf<File>()
+ private val visitedSyms = mutableSetOf<LookupSymbol>()
+
+ private val outputToSources = mutableMapOf<File, MutableSet<File>>().apply {
+ sourceToOutputs.keys.forEach { source ->
+ if (source != anyChangesWildcard && source != removedOutputsKey) {
+ sourceToOutputs[source]!!.forEach { output ->
+ getOrPut(output) { mutableSetOf() }.add(source)
+ }
+ }
+ }
+ }
+
+ private fun visit(sym: LookupSymbol) {
+ if (sym in visitedSyms)
+ return
+ visitedSyms.add(sym)
+
+ lookupCache.get(sym).forEach {
+ visit(File(it))
+ }
+ }
+
+ private fun visit(file: File) {
+ if (file in visitedFiles)
+ return
+ visitedFiles.add(file)
+
+ // Propagate by dependencies
+ symbolsMap[file]?.forEach {
+ visit(it)
+ }
+
+ // Propagate by input-output relations
+ // Given (..., I, ...) -> O:
+ // 1) if I is dirty, then O is dirty.
+ // 2) if O is dirty, then O must be regenerated, which requires all of its inputs to be reprocessed.
+ sourceToOutputs[file]?.forEach {
+ visit(it)
+ }
+ outputToSources[file]?.forEach {
+ visit(it)
+ }
+ }
+
+ fun propagate(initialSet: Collection<File>): Set<File> {
+ initialSet.forEach { visit(it) }
+ return visitedFiles
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt
new file mode 100644
index 00000000..f0dd1e46
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt
@@ -0,0 +1,453 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp
+
+import com.google.devtools.ksp.processing.KSPLogger
+import com.google.devtools.ksp.processing.PlatformInfo
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
+import com.google.devtools.ksp.processing.SymbolProcessorProvider
+import com.google.devtools.ksp.processing.impl.CodeGeneratorImpl
+import com.google.devtools.ksp.processing.impl.JsPlatformInfoImpl
+import com.google.devtools.ksp.processing.impl.JvmPlatformInfoImpl
+import com.google.devtools.ksp.processing.impl.KSPCompilationError
+import com.google.devtools.ksp.processing.impl.MessageCollectorBasedKSPLogger
+import com.google.devtools.ksp.processing.impl.NativePlatformInfoImpl
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.processing.impl.UnknownPlatformInfoImpl
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSDeclarationContainer
+import com.google.devtools.ksp.symbol.KSFile
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSVisitorVoid
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.Visibility
+import com.google.devtools.ksp.symbol.impl.java.KSFileJavaImpl
+import com.google.devtools.ksp.symbol.impl.kotlin.KSFileImpl
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.vfs.StandardFileSystems
+import com.intellij.openapi.vfs.VirtualFileManager
+import com.intellij.psi.PsiJavaFile
+import com.intellij.psi.PsiManager
+import org.jetbrains.kotlin.analyzer.AnalysisResult
+import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
+import org.jetbrains.kotlin.container.ComponentProvider
+import org.jetbrains.kotlin.context.ProjectContext
+import org.jetbrains.kotlin.descriptors.ModuleDescriptor
+import org.jetbrains.kotlin.load.java.components.FilesByFacadeFqNameIndexer
+import org.jetbrains.kotlin.platform.js.JsPlatform
+import org.jetbrains.kotlin.platform.jvm.JdkPlatform
+import org.jetbrains.kotlin.platform.konan.NativePlatform
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.BindingTrace
+import org.jetbrains.kotlin.resolve.extensions.AnalysisHandlerExtension
+import org.jetbrains.kotlin.util.ServiceLoaderLite
+import java.io.File
+import java.io.PrintWriter
+import java.io.StringWriter
+import java.net.URLClassLoader
+import java.nio.file.Files
+
+class KotlinSymbolProcessingExtension(
+ options: KspOptions,
+ logger: KSPLogger,
+ val testProcessor: SymbolProcessorProvider? = null,
+) : AbstractKotlinSymbolProcessingExtension(options, logger, testProcessor != null) {
+ override fun loadProviders(): List<SymbolProcessorProvider> {
+ if (!initialized) {
+ providers = if (testProcessor != null) {
+ listOf(testProcessor)
+ } else {
+ val processingClasspath = options.processingClasspath
+ val classLoader =
+ URLClassLoader(processingClasspath.map { it.toURI().toURL() }.toTypedArray(), javaClass.classLoader)
+
+ ServiceLoaderLite.loadImplementations(SymbolProcessorProvider::class.java, classLoader).filter {
+ (options.processors.isEmpty() && it.javaClass.name !in options.excludedProcessors) ||
+ it.javaClass.name in options.processors
+ }
+ }
+ if (providers.isEmpty()) {
+ logger.error("No providers found in processor classpath.")
+ } else {
+ logger.info(
+ "loaded provider(s): " +
+ "${providers.joinToString(separator = ", ", prefix = "[", postfix = "]") { it.javaClass.name }}"
+ )
+ }
+ }
+ return providers
+ }
+}
+
+abstract class AbstractKotlinSymbolProcessingExtension(
+ val options: KspOptions,
+ val logger: KSPLogger,
+ val testMode: Boolean,
+) :
+ AnalysisHandlerExtension {
+ var initialized = false
+ var finished = false
+ val deferredSymbols = mutableMapOf<SymbolProcessor, List<KSAnnotated>>()
+ lateinit var providers: List<SymbolProcessorProvider>
+ lateinit var processors: List<SymbolProcessor>
+ lateinit var incrementalContext: IncrementalContext
+ lateinit var dirtyFiles: Set<KSFile>
+ lateinit var cleanFilenames: Set<String>
+ lateinit var codeGenerator: CodeGeneratorImpl
+ var newFileNames: Collection<String> = emptySet()
+ var rounds = 0
+
+ companion object {
+ private const val KSP_PACKAGE_NAME = "com.google.devtools.ksp"
+ private const val KOTLIN_PACKAGE_NAME = "org.jetbrains.kotlin"
+ private const val MULTI_ROUND_THRESHOLD = 100
+ }
+
+ override fun doAnalysis(
+ project: Project,
+ module: ModuleDescriptor,
+ projectContext: ProjectContext,
+ files: Collection<KtFile>,
+ bindingTrace: BindingTrace,
+ componentProvider: ComponentProvider,
+ ): AnalysisResult? {
+ // with `withCompilation == true`:
+ // * KSP returns AnalysisResult.RetryWithAdditionalRoots in last round of processing, to notify compiler the generated sources.
+ // * This function will be called again, and returning null tells compiler to fall through with normal compilation.
+ if (finished) {
+ if (!options.withCompilation)
+ throw IllegalStateException("KSP is re-entered unexpectedly.")
+ if (!options.returnOkOnError && logger.hasError()) {
+ return AnalysisResult.compilationError(BindingContext.EMPTY)
+ }
+ return null
+ }
+
+ rounds++
+ if (rounds > MULTI_ROUND_THRESHOLD) {
+ logger.warn("Current processing rounds exceeds 100, check processors for potential infinite rounds")
+ }
+ logger.logging("round $rounds of processing")
+ val psiManager = PsiManager.getInstance(project)
+ if (initialized) {
+ psiManager.dropPsiCaches()
+ }
+
+ val localFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
+ val javaSourceRoots =
+ if (initialized) options.javaSourceRoots + options.javaOutputDir else options.javaSourceRoots
+ val javaFiles = javaSourceRoots
+ .sortedBy { Files.isSymbolicLink(it.toPath()) } // Get non-symbolic paths first
+ .flatMap { root -> root.walk().filter { it.isFile && it.extension == "java" }.toList() }
+ .sortedBy { Files.isSymbolicLink(it.toPath()) } // This time is for .java files
+ .distinctBy { it.canonicalPath }
+ .mapNotNull { localFileSystem.findFileByPath(it.path)?.let { psiManager.findFile(it) } as? PsiJavaFile }
+
+ val anyChangesWildcard = AnyChanges(options.projectBaseDir)
+ val commonSources: Set<String?> = options.commonSources.map { it.canonicalPath }.toSet()
+ val ksFiles = files.filterNot { it.virtualFile.canonicalPath in commonSources }
+ .map { KSFileImpl.getCached(it) } + javaFiles.map { KSFileJavaImpl.getCached(it) }
+ lateinit var newFiles: List<KSFile>
+
+ handleException(module, project) {
+ val fileClassProcessor = FilesByFacadeFqNameIndexer(bindingTrace)
+ if (!initialized) {
+ incrementalContext = IncrementalContext(
+ options, componentProvider,
+ File(anyChangesWildcard.filePath).relativeTo(options.projectBaseDir)
+ )
+ dirtyFiles = incrementalContext.calcDirtyFiles(ksFiles).toSet()
+ cleanFilenames = ksFiles.filterNot { it in dirtyFiles }.map { it.filePath }.toSet()
+ newFiles = dirtyFiles.toList()
+ // DO NOT filter out common sources.
+ files.forEach { fileClassProcessor.preprocessFile(it) }
+ } else {
+ newFiles = ksFiles.filter {
+ when (it) {
+ is KSFileImpl -> it.file
+ is KSFileJavaImpl -> it.psi
+ else -> null
+ }?.virtualFile?.let { virtualFile ->
+ if (System.getProperty("os.name").startsWith("windows", ignoreCase = true)) {
+ virtualFile.canonicalPath ?: virtualFile.path
+ } else {
+ File(virtualFile.path).canonicalPath
+ }
+ } in newFileNames
+ }
+ incrementalContext.registerGeneratedFiles(newFiles)
+ newFiles.filterIsInstance<KSFileImpl>().forEach { fileClassProcessor.preprocessFile(it.file) }
+ }
+ }?.let { return@doAnalysis it }
+
+ // dirtyFiles cannot be reused because they are created in the old container.
+ val resolver = ResolverImpl(
+ module,
+ ksFiles.filterNot {
+ it.filePath in cleanFilenames
+ },
+ newFiles, deferredSymbols, bindingTrace, project, componentProvider, incrementalContext, options
+ )
+
+ if (!initialized) {
+ // Visit constants so that JavaPsiFacade knows them.
+ // The annotation visitor in ResolverImpl covered newFiles already.
+ // Skip private and local members, which are not visible to Java files.
+ ksFiles.filterIsInstance<KSFileImpl>().filter { it !in dirtyFiles }.forEach {
+ try {
+ it.accept(
+ object : KSVisitorVoid() {
+ private fun visitDeclarationContainer(container: KSDeclarationContainer) {
+ container.declarations.filterNot {
+ it.getVisibility() == Visibility.PRIVATE
+ }.forEach {
+ it.accept(this, Unit)
+ }
+ }
+
+ override fun visitFile(file: KSFile, data: Unit) =
+ visitDeclarationContainer(file)
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) =
+ visitDeclarationContainer(classDeclaration)
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ if (property.modifiers.contains(Modifier.CONST)) {
+ property.getter // force resolution
+ }
+ }
+ },
+ Unit
+ )
+ } catch (_: Exception) {
+ // Do nothing.
+ }
+ }
+ }
+
+ val providers = loadProviders()
+ if (!initialized) {
+ codeGenerator = CodeGeneratorImpl(
+ options.classOutputDir,
+ options.javaOutputDir,
+ options.kotlinOutputDir,
+ options.resourceOutputDir,
+ options.projectBaseDir,
+ anyChangesWildcard,
+ ksFiles,
+ options.incremental
+ )
+ processors = providers.mapNotNull { provider ->
+ var processor: SymbolProcessor? = null
+ handleException(module, project) {
+ processor = provider.create(
+ SymbolProcessorEnvironment(
+ options.processingOptions,
+ options.languageVersion,
+ codeGenerator,
+ logger,
+ options.apiVersion,
+ options.compilerVersion,
+ findTargetInfos(module)
+ )
+ )
+ }?.let { analysisResult ->
+ resolver.tearDown()
+ return@doAnalysis analysisResult
+ }
+ if (logger.hasError()) {
+ return@mapNotNull null
+ }
+ processor?.also { deferredSymbols[it] = mutableListOf() }
+ }
+ /* Kotlin compiler expects a source dir to exist, but processors might not generate Kotlin source.
+ Create it during initialization just in case. */
+ options.kotlinOutputDir.mkdirs()
+ initialized = true
+ }
+ if (!logger.hasError()) {
+ processors.forEach processing@{ processor ->
+ handleException(module, project) {
+ deferredSymbols[processor] =
+ processor.process(resolver).filter { it.origin == Origin.KOTLIN || it.origin == Origin.JAVA }
+ }?.let {
+ resolver.tearDown()
+ return it
+ }
+ if (logger.hasError()) {
+ return@processing
+ }
+ if (!deferredSymbols.containsKey(processor) || deferredSymbols[processor]!!.isEmpty()) {
+ deferredSymbols.remove(processor)
+ }
+ }
+ }
+ // Post processing.
+ newFileNames = codeGenerator.generatedFile.filter { it.extension == "kt" || it.extension == "java" }
+ .map { it.canonicalPath.replace(File.separatorChar, '/') }.toSet()
+ if (codeGenerator.generatedFile.isEmpty()) {
+ finished = true
+ }
+ KSObjectCacheManager.clear()
+ codeGenerator.closeFiles()
+ if (logger.hasError()) {
+ finished = true
+ processors.forEach { processor ->
+ handleException(module, project) {
+ processor.onError()
+ }?.let {
+ resolver.tearDown()
+ return it
+ }
+ }
+ } else {
+ if (finished) {
+ processors.forEach { processor ->
+ handleException(module, project) {
+ processor.finish()
+ }?.let {
+ resolver.tearDown()
+ return it
+ }
+ }
+ if (deferredSymbols.isNotEmpty()) {
+ deferredSymbols.map { entry ->
+ logger.warn(
+ "Unable to process:${entry.key::class.qualifiedName}: ${
+ entry.value.map { it.toString() }.joinToString(";")
+ }"
+ )
+ }
+ }
+ if (!logger.hasError()) {
+ incrementalContext.updateCachesAndOutputs(
+ dirtyFiles,
+ codeGenerator.outputs,
+ codeGenerator.sourceToOutputs
+ )
+ }
+ }
+ }
+ if (finished) {
+ logger.reportAll()
+ }
+ resolver.tearDown()
+ return if (finished && !options.withCompilation) {
+ if (!options.returnOkOnError && logger.hasError()) {
+ AnalysisResult.compilationError(BindingContext.EMPTY)
+ } else {
+ AnalysisResult.success(BindingContext.EMPTY, module, shouldGenerateCode = false)
+ }
+ } else {
+ AnalysisResult.RetryWithAdditionalRoots(
+ BindingContext.EMPTY,
+ module,
+ listOf(options.javaOutputDir),
+ listOf(options.kotlinOutputDir),
+ listOf(options.classOutputDir)
+ )
+ }
+ }
+
+ abstract fun loadProviders(): List<SymbolProcessorProvider>
+
+ private var annotationProcessingComplete = false
+
+ private fun setAnnotationProcessingComplete(): Boolean {
+ if (annotationProcessingComplete) return true
+
+ annotationProcessingComplete = true
+ return false
+ }
+
+ private fun KSPLogger.reportAll() {
+ (this as MessageCollectorBasedKSPLogger).reportAll()
+ }
+
+ private fun KSPLogger.hasError(): Boolean {
+ return (this as MessageCollectorBasedKSPLogger).recordedEvents.any {
+ it.severity == CompilerMessageSeverity.ERROR || it.severity == CompilerMessageSeverity.EXCEPTION
+ }
+ }
+
+ private fun handleException(module: ModuleDescriptor, project: Project, call: () -> Unit): AnalysisResult? {
+ try {
+ call()
+ } catch (e: Exception) {
+ fun Exception.logToError() {
+ val sw = StringWriter()
+ printStackTrace(PrintWriter(sw))
+ logger.error(sw.toString())
+ }
+
+ fun Exception.isNotRecoverable(): Boolean =
+ stackTrace.first().className.let {
+ // TODO: convert non-critical exceptions thrown by KSP to recoverable errors.
+ it.startsWith(KSP_PACKAGE_NAME) || it.startsWith(KOTLIN_PACKAGE_NAME)
+ }
+
+ // Returning non-null here allows
+ // 1. subsequent processing of other processors in current round.
+ // 2. processor.onError() be called.
+ //
+ // In other words, returning non-null let current round finish.
+ when {
+ e is KSPCompilationError -> {
+ logger.error("${project.findLocationString(e.file, e.offset)}: ${e.message}")
+ logger.reportAll()
+ return if (options.returnOkOnError) {
+ AnalysisResult.success(BindingContext.EMPTY, module, shouldGenerateCode = false)
+ } else {
+ AnalysisResult.compilationError(BindingContext.EMPTY)
+ }
+ }
+
+ e.isNotRecoverable() -> {
+ e.logToError()
+ logger.reportAll()
+ return if (options.returnOkOnError) {
+ AnalysisResult.success(BindingContext.EMPTY, module, shouldGenerateCode = false)
+ } else {
+ AnalysisResult.internalError(BindingContext.EMPTY, e)
+ }
+ }
+
+ // Let this round finish.
+ else -> {
+ e.logToError()
+ }
+ }
+ }
+ return null
+ }
+}
+
+fun findTargetInfos(module: ModuleDescriptor): List<PlatformInfo> =
+ module.platform?.componentPlatforms?.map { platform ->
+ when (platform) {
+ is JdkPlatform -> JvmPlatformInfoImpl(platform.platformName, platform.targetVersion.toString())
+ is JsPlatform -> JsPlatformInfoImpl(platform.platformName)
+ is NativePlatform -> NativePlatformInfoImpl(platform.platformName, platform.targetName)
+ // Unknown platform; toString() may be more informative than platformName
+ else -> UnknownPlatformInfoImpl(platform.toString())
+ }
+ } ?: emptyList()
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingPlugin.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingPlugin.kt
new file mode 100644
index 00000000..9d2c400b
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingPlugin.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.
+ */
+
+package com.google.devtools.ksp
+
+import com.google.devtools.ksp.processing.impl.MessageCollectorBasedKSPLogger
+import com.intellij.core.CoreApplicationEnvironment
+import com.intellij.mock.MockProject
+import com.intellij.psi.PsiTreeChangeAdapter
+import com.intellij.psi.PsiTreeChangeListener
+import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
+import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
+import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption
+import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException
+import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
+import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
+import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi
+import org.jetbrains.kotlin.config.CommonConfigurationKeys
+import org.jetbrains.kotlin.config.CompilerConfiguration
+import org.jetbrains.kotlin.config.CompilerConfigurationKey
+import org.jetbrains.kotlin.config.KotlinCompilerVersion
+import org.jetbrains.kotlin.config.languageVersionSettings
+import org.jetbrains.kotlin.config.toKotlinVersion
+import org.jetbrains.kotlin.resolve.extensions.AnalysisHandlerExtension
+
+private val KSP_OPTIONS = CompilerConfigurationKey.create<KspOptions.Builder>("Ksp options")
+
+@ExperimentalCompilerApi
+class KotlinSymbolProcessingCommandLineProcessor : CommandLineProcessor {
+ override val pluginId = "com.google.devtools.ksp.symbol-processing"
+
+ override val pluginOptions: Collection<AbstractCliOption> = KspCliOption.values().asList()
+
+ override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) {
+ if (option !is KspCliOption) {
+ throw CliOptionProcessingException("Unknown option: ${option.optionName}")
+ }
+
+ val kspOptions = configuration[KSP_OPTIONS]
+ ?: KspOptions.Builder().also { configuration.put(KSP_OPTIONS, it) }
+ kspOptions.processOption(option, value)
+ }
+}
+
+// Changes here may break some third party libraries like Kotlin Compile Testing, where the compiler is invoked in
+// another way. Do our best to notify them when changing this.
+//
+// Third party libraries:
+// https://github.com/tschuchortdev/kotlin-compile-testing
+@Suppress("DEPRECATION")
+@ExperimentalCompilerApi
+class KotlinSymbolProcessingComponentRegistrar : ComponentRegistrar {
+ override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
+ val contentRoots = configuration[CLIConfigurationKeys.CONTENT_ROOTS] ?: emptyList()
+ val options = configuration[KSP_OPTIONS]?.apply {
+ javaSourceRoots.addAll(contentRoots.filterIsInstance<JavaSourceRoot>().map { it.file })
+ languageVersion = configuration.languageVersionSettings.languageVersion.toKotlinVersion()
+ apiVersion = configuration.languageVersionSettings.apiVersion.toKotlinVersion()
+ compilerVersion = KotlinCompilerVersion.getVersion().toKotlinVersion()
+ }?.build() ?: return
+ val messageCollector = configuration.get(CLIConfigurationKeys.ORIGINAL_MESSAGE_COLLECTOR_KEY)
+ ?: throw IllegalStateException("ksp: message collector not found!")
+ val wrappedMessageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
+ ?: throw IllegalStateException("ksp: message collector not found!")
+ val logger = MessageCollectorBasedKSPLogger(
+ messageCollector, wrappedMessageCollector, options.allWarningsAsErrors
+ )
+ if (options.processingClasspath.isNotEmpty()) {
+ if (options.withCompilation && options.incremental) {
+ throw IllegalStateException("ksp: `incremental` is incompatible with `withCompilation`.")
+ }
+ val kotlinSymbolProcessingHandlerExtension = KotlinSymbolProcessingExtension(options, logger)
+ AnalysisHandlerExtension.registerExtension(project, kotlinSymbolProcessingHandlerExtension)
+ configuration.put(CommonConfigurationKeys.LOOKUP_TRACKER, DualLookupTracker())
+
+ // Dummy extension point; Required by dropPsiCaches().
+ CoreApplicationEnvironment.registerExtensionPoint(
+ project.extensionArea, PsiTreeChangeListener.EP.name, PsiTreeChangeAdapter::class.java
+ )
+ }
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/JvmUtils.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/JvmUtils.kt
new file mode 100644
index 00000000..88b4c256
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/JvmUtils.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processing.impl
+
+internal val JVM_STATIC_ANNOTATION_FQN = "kotlin.jvm.JvmStatic"
+internal val JVM_DEFAULT_ANNOTATION_FQN = "kotlin.jvm.JvmDefault"
+internal val JVM_DEFAULT_WITHOUT_COMPATIBILITY_ANNOTATION_FQN = "kotlin.jvm.JvmDefaultWithoutCompatibility"
+internal val JVM_STRICTFP_ANNOTATION_FQN = "kotlin.jvm.Strictfp"
+internal val JVM_SYNCHRONIZED_ANNOTATION_FQN = "kotlin.jvm.Synchronized"
+internal val JVM_TRANSIENT_ANNOTATION_FQN = "kotlin.jvm.Transient"
+internal val JVM_VOLATILE_ANNOTATION_FQN = "kotlin.jvm.Volatile"
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/KSPCompilationError.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/KSPCompilationError.kt
new file mode 100644
index 00000000..a21edfd5
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/KSPCompilationError.kt
@@ -0,0 +1,6 @@
+package com.google.devtools.ksp.processing.impl
+
+import com.intellij.psi.PsiFile
+
+// PsiElement.toLocation() isn't available before ResolveImpl is initialized.
+class KSPCompilationError(val file: PsiFile, val offset: Int, override val message: String) : Exception()
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/MessageCollectorBasedKSPLogger.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/MessageCollectorBasedKSPLogger.kt
new file mode 100644
index 00000000..67c99dba
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/MessageCollectorBasedKSPLogger.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processing.impl
+
+import com.google.devtools.ksp.processing.KSPLogger
+import com.google.devtools.ksp.symbol.FileLocation
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.NonExistLocation
+import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
+import org.jetbrains.kotlin.cli.common.messages.MessageCollector
+import java.io.PrintWriter
+import java.io.StringWriter
+
+class MessageCollectorBasedKSPLogger(
+ private val messageCollector: MessageCollector,
+ private val wrappedMessageCollector: MessageCollector,
+ private val allWarningsAsErrors: Boolean
+) : KSPLogger {
+
+ companion object {
+ const val PREFIX = "[ksp] "
+ }
+
+ data class Event(val severity: CompilerMessageSeverity, val message: String)
+
+ val recordedEvents = mutableListOf<Event>()
+
+ private val reportToCompilerSeverity = setOf(CompilerMessageSeverity.ERROR, CompilerMessageSeverity.EXCEPTION)
+
+ private var reportedToCompiler = false
+
+ private fun convertMessage(message: String, symbol: KSNode?): String =
+ when (val location = symbol?.location) {
+ is FileLocation -> "$PREFIX${location.filePath}:${location.lineNumber}: $message"
+ is NonExistLocation, null -> "$PREFIX$message"
+ }
+
+ override fun logging(message: String, symbol: KSNode?) {
+ recordedEvents.add(Event(CompilerMessageSeverity.LOGGING, convertMessage(message, symbol)))
+ }
+
+ override fun info(message: String, symbol: KSNode?) {
+ recordedEvents.add(Event(CompilerMessageSeverity.INFO, convertMessage(message, symbol)))
+ }
+
+ override fun warn(message: String, symbol: KSNode?) {
+ val severity = if (allWarningsAsErrors) CompilerMessageSeverity.ERROR else CompilerMessageSeverity.WARNING
+ recordedEvents.add(Event(severity, convertMessage(message, symbol)))
+ }
+
+ override fun error(message: String, symbol: KSNode?) {
+ recordedEvents.add(Event(CompilerMessageSeverity.ERROR, convertMessage(message, symbol)))
+ }
+
+ override fun exception(e: Throwable) {
+ val writer = StringWriter()
+ e.printStackTrace(PrintWriter(writer))
+ recordedEvents.add(Event(CompilerMessageSeverity.EXCEPTION, writer.toString()))
+ }
+
+ fun reportAll() {
+ for (event in recordedEvents) {
+ if (!reportedToCompiler && event.severity in reportToCompilerSeverity) {
+ reportedToCompiler = true
+ wrappedMessageCollector.report(event.severity, "Error occurred in KSP, check log for detail")
+ }
+ messageCollector.report(event.severity, event.message)
+ }
+ }
+}
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
new file mode 100644
index 00000000..7c1fade2
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processing/impl/ResolverImpl.kt
@@ -0,0 +1,1613 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processing.impl
+
+import com.google.devtools.ksp.*
+import com.google.devtools.ksp.processing.KSBuiltIns
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.ClassKind
+import com.google.devtools.ksp.symbol.Variance
+import com.google.devtools.ksp.symbol.impl.binary.*
+import com.google.devtools.ksp.symbol.impl.declarationsInSourceOrder
+import com.google.devtools.ksp.symbol.impl.findParentAnnotated
+import com.google.devtools.ksp.symbol.impl.findPsi
+import com.google.devtools.ksp.symbol.impl.getInstanceForCurrentRound
+import com.google.devtools.ksp.symbol.impl.java.*
+import com.google.devtools.ksp.symbol.impl.jvmAccessFlag
+import com.google.devtools.ksp.symbol.impl.kotlin.*
+import com.google.devtools.ksp.symbol.impl.resolveContainingClass
+import com.google.devtools.ksp.symbol.impl.synthetic.*
+import com.google.devtools.ksp.visitor.CollectAnnotatedSymbolsVisitor
+import com.intellij.openapi.project.Project
+import com.intellij.psi.*
+import com.intellij.psi.impl.source.PsiClassReferenceType
+import org.jetbrains.kotlin.builtins.KotlinBuiltIns
+import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
+import org.jetbrains.kotlin.codegen.ClassBuilderMode
+import org.jetbrains.kotlin.codegen.OwnerKind
+import org.jetbrains.kotlin.codegen.state.JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME
+import org.jetbrains.kotlin.codegen.state.JVM_WILDCARD_ANNOTATION_FQ_NAME
+import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
+import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
+import org.jetbrains.kotlin.container.ComponentProvider
+import org.jetbrains.kotlin.container.get
+import org.jetbrains.kotlin.container.tryGetService
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
+import org.jetbrains.kotlin.descriptors.annotations.Annotations
+import org.jetbrains.kotlin.incremental.components.NoLookupLocation
+import org.jetbrains.kotlin.load.java.components.TypeUsage
+import org.jetbrains.kotlin.load.java.descriptors.JavaForKotlinOverridePropertyDescriptor
+import org.jetbrains.kotlin.load.java.lazy.JavaResolverComponents
+import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
+import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
+import org.jetbrains.kotlin.load.java.lazy.TypeParameterResolver
+import org.jetbrains.kotlin.load.java.lazy.childForClassOrPackage
+import org.jetbrains.kotlin.load.java.lazy.childForMethod
+import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaTypeParameterDescriptor
+import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeResolver
+import org.jetbrains.kotlin.load.java.lazy.types.toAttributes
+import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
+import org.jetbrains.kotlin.load.java.structure.JavaClass
+import org.jetbrains.kotlin.load.java.structure.classId
+import org.jetbrains.kotlin.load.java.structure.impl.JavaArrayTypeImpl
+import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
+import org.jetbrains.kotlin.load.java.structure.impl.JavaConstructorImpl
+import org.jetbrains.kotlin.load.java.structure.impl.JavaFieldImpl
+import org.jetbrains.kotlin.load.java.structure.impl.JavaMethodImpl
+import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeImpl
+import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeParameterImpl
+import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
+import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaMethod
+import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaMethodBase
+import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
+import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass
+import org.jetbrains.kotlin.load.kotlin.getContainingKotlinJvmBinaryClass
+import org.jetbrains.kotlin.load.kotlin.getOptimalModeForReturnType
+import org.jetbrains.kotlin.load.kotlin.getOptimalModeForValueParameter
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.FqNameUnsafe
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.resolve.*
+import org.jetbrains.kotlin.resolve.annotations.argumentValue
+import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
+import org.jetbrains.kotlin.resolve.calls.inference.components.composeWith
+import org.jetbrains.kotlin.resolve.calls.inference.substitute
+import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
+import org.jetbrains.kotlin.resolve.constants.*
+import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
+import org.jetbrains.kotlin.resolve.descriptorUtil.classId
+import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
+import org.jetbrains.kotlin.resolve.descriptorUtil.module
+import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor
+import org.jetbrains.kotlin.resolve.lazy.DeclarationScopeProvider
+import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
+import org.jetbrains.kotlin.resolve.lazy.ResolveSession
+import org.jetbrains.kotlin.resolve.multiplatform.findActuals
+import org.jetbrains.kotlin.resolve.multiplatform.findExpects
+import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
+import org.jetbrains.kotlin.resolve.scopes.LexicalScope
+import org.jetbrains.kotlin.resolve.scopes.MemberScope
+import org.jetbrains.kotlin.types.*
+import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext
+import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
+import org.jetbrains.kotlin.types.typeUtil.substitute
+import org.jetbrains.kotlin.types.typeUtil.supertypes
+import org.jetbrains.kotlin.util.containingNonLocalDeclaration
+import org.jetbrains.org.objectweb.asm.ClassReader
+import org.jetbrains.org.objectweb.asm.ClassVisitor
+import org.jetbrains.org.objectweb.asm.MethodVisitor
+import org.jetbrains.org.objectweb.asm.Opcodes
+import org.jetbrains.org.objectweb.asm.Opcodes.API_VERSION
+import java.io.File
+import java.util.Stack
+
+class ResolverImpl(
+ val module: ModuleDescriptor,
+ val allKSFiles: Collection<KSFile>,
+ val newKSFiles: Collection<KSFile>,
+ private val deferredSymbols: Map<SymbolProcessor, List<KSAnnotated>>,
+ val bindingTrace: BindingTrace,
+ val project: Project,
+ componentProvider: ComponentProvider,
+ val incrementalContext: IncrementalContext,
+ val options: KspOptions,
+) : Resolver {
+ val psiDocumentManager = PsiDocumentManager.getInstance(project)
+ private val nameToKSMap: MutableMap<KSName, KSClassDeclaration>
+ private val javaTypeParameterMap: MutableMap<LazyJavaTypeParameterDescriptor, PsiTypeParameter> = mutableMapOf()
+
+ /**
+ * Checking as member of is an expensive operation, hence we cache result values in this map.
+ */
+ private val functionAsMemberOfCache: MutableMap<Pair<KSFunctionDeclaration, KSType>, KSFunction>
+ private val propertyAsMemberOfCache: MutableMap<Pair<KSPropertyDeclaration, KSType>, KSType>
+
+ private val typeMapper = KotlinTypeMapper(
+ BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES,
+ module.name.getNonSpecialIdentifier(),
+ KotlinTypeMapper.LANGUAGE_VERSION_SETTINGS_DEFAULT, // TODO use proper LanguageVersionSettings
+ true
+ )
+ private val qualifiedExpressionResolver = QualifiedExpressionResolver(LanguageVersionSettingsImpl.DEFAULT)
+
+ private val aliasingFqNs: MutableMap<String, KSTypeAlias> = mutableMapOf()
+ private val aliasingNames: MutableSet<String> = mutableSetOf()
+ private val topDownAnalysisContext by lazy {
+ TopDownAnalysisContext(TopDownAnalysisMode.TopLevelDeclarations, DataFlowInfo.EMPTY, declarationScopeProvider)
+ }
+
+ companion object {
+ var instance: ResolverImpl? = null
+ }
+
+ var resolveSession: ResolveSession
+ var bodyResolver: BodyResolver
+ var constantExpressionEvaluator: ConstantExpressionEvaluator
+ var declarationScopeProvider: DeclarationScopeProvider
+
+ lateinit var moduleClassResolver: ModuleClassResolver
+ lateinit var javaTypeResolver: JavaTypeResolver
+ lateinit var lazyJavaResolverContext: LazyJavaResolverContext
+
+ init {
+ resolveSession = componentProvider.get()
+ bodyResolver = componentProvider.get()
+ declarationScopeProvider = componentProvider.get()
+ constantExpressionEvaluator = componentProvider.get()
+
+ componentProvider.tryGetService(JavaResolverComponents::class.java)?.let {
+ lazyJavaResolverContext = LazyJavaResolverContext(it, TypeParameterResolver.EMPTY) { null }
+ javaTypeResolver = lazyJavaResolverContext.typeResolver
+ moduleClassResolver = lazyJavaResolverContext.components.moduleClassResolver
+ }
+ instance = this
+
+ nameToKSMap = mutableMapOf()
+ functionAsMemberOfCache = mutableMapOf()
+ propertyAsMemberOfCache = mutableMapOf()
+
+ val visitor = object : KSVisitorVoid() {
+ override fun visitFile(file: KSFile, data: Unit) {
+ file.declarations.forEach { it.accept(this, data) }
+
+ // TODO: evaluate with benchmarks: cost of getContainingFile v.s. name collision
+ // Import aliases are file-scoped. `aliasingNamesByFile` could be faster
+ (file as? KSFileImpl)?.file?.importDirectives?.forEach {
+ it.aliasName?.let { aliasingNames.add(it) }
+ }
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ val qualifiedName = classDeclaration.qualifiedName
+ if (qualifiedName != null) {
+ nameToKSMap[qualifiedName] = classDeclaration
+ }
+ classDeclaration.declarations.forEach { it.accept(this, data) }
+ }
+
+ override fun visitTypeAlias(typeAlias: KSTypeAlias, data: Unit) {
+ typeAlias.qualifiedName?.asString()?.let { fqn ->
+ aliasingFqNs[fqn] = typeAlias
+ aliasingNames.add(fqn.substringAfterLast('.'))
+ }
+ }
+ }
+
+ // FIXME: reuse results from previous rounds and only loop through newKSFiles.
+ allKSFiles.forEach { it.accept(visitor, Unit) }
+ }
+
+ // Mitigation for processors with memory leaks
+ // https://github.com/google/ksp/issues/1063
+ fun tearDown() {
+ instance = null
+ }
+
+ override fun getNewFiles(): Sequence<KSFile> {
+ return newKSFiles.asSequence()
+ }
+
+ override fun getAllFiles(): Sequence<KSFile> {
+ return allKSFiles.asSequence()
+ }
+
+ override fun getClassDeclarationByName(name: KSName): KSClassDeclaration? {
+ nameToKSMap[name]?.let { return it }
+
+ return module.resolveClassByFqName(FqName(name.asString()), NoLookupLocation.WHEN_FIND_BY_FQNAME)
+ ?.let {
+ val psi = it.findPsi()
+ if (psi != null) {
+ when (psi) {
+ is KtClassOrObject -> KSClassDeclarationImpl.getCached(psi)
+ is PsiClass -> KSClassDeclarationJavaImpl.getCached(psi)
+ else -> throw IllegalStateException("unexpected psi: ${psi.javaClass}")
+ }
+ } else {
+ KSClassDeclarationDescriptorImpl.getCached(it)
+ }
+ }
+ }
+
+ override fun getFunctionDeclarationsByName(
+ name: KSName,
+ includeTopLevel: Boolean,
+ ): Sequence<KSFunctionDeclaration> {
+ val qualifier = name.getQualifier()
+ val functionName = name.getShortName()
+ val nonTopLevelResult = this.getClassDeclarationByName(qualifier)?.getDeclaredFunctions()
+ ?.filter { it.simpleName.asString() == functionName }?.asSequence() ?: emptySequence()
+ return if (!includeTopLevel) nonTopLevelResult else {
+ nonTopLevelResult.plus(
+ module.getPackage(FqName(qualifier))
+ .memberScope.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS) {
+ it.asString() == functionName
+ }
+ .filterIsInstance<MemberDescriptor>().mapNotNull { it.toKSDeclaration() as? KSFunctionDeclaration }
+ )
+ }
+ }
+
+ override fun getPropertyDeclarationByName(name: KSName, includeTopLevel: Boolean): KSPropertyDeclaration? {
+ val qualifier = name.getQualifier()
+ val propertyName = name.getShortName()
+ val nonTopLevelResult = this.getClassDeclarationByName(qualifier)?.getDeclaredProperties()
+ ?.singleOrNull { it.simpleName.asString() == propertyName }
+ return if (!includeTopLevel) nonTopLevelResult else {
+ val topLevelResult = (
+ module.getPackage(FqName(qualifier))
+ .memberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES) {
+ it.asString() == propertyName
+ }
+ .also {
+ if (it.size > 1) {
+ throw IllegalStateException("Found multiple properties with same qualified name")
+ }
+ }
+ .singleOrNull() as? MemberDescriptor
+ )?.toKSDeclaration() as? KSPropertyDeclaration
+ if (topLevelResult != null && nonTopLevelResult != null) {
+ throw IllegalStateException("Found multiple properties with same qualified name")
+ }
+ nonTopLevelResult ?: topLevelResult
+ }
+ }
+
+ internal fun checkAnnotation(annotation: KSAnnotation, ksName: KSName, shortName: String): Boolean {
+ val annotationType = annotation.annotationType
+ val referencedName = (annotationType.element as? KSClassifierReference)?.referencedName()
+ val simpleName = referencedName?.substringAfterLast('.')
+ return (simpleName == shortName || simpleName in aliasingNames) &&
+ annotationType.resolveToUnderlying().declaration.qualifiedName == ksName
+ }
+
+ override fun getSymbolsWithAnnotation(annotationName: String, inDepth: Boolean): Sequence<KSAnnotated> {
+ // If annotationName is a typealias, resolve to underlying type.
+ val realAnnotationName =
+ aliasingFqNs[annotationName]?.type?.resolveToUnderlying()?.declaration?.qualifiedName?.asString()
+ ?: annotationName
+
+ val ksName = KSNameImpl.getCached(realAnnotationName)
+ val shortName = ksName.getShortName()
+
+ fun checkAnnotated(annotated: KSAnnotated): Boolean {
+ return annotated.annotations.any {
+ checkAnnotation(it, ksName, shortName)
+ }
+ }
+
+ val allAnnotated = if (inDepth) newAnnotatedSymbolsWithLocals else newAnnotatedSymbols
+ return allAnnotated.asSequence().filter(::checkAnnotated)
+ }
+
+ private fun collectAnnotatedSymbols(inDepth: Boolean): Collection<KSAnnotated> {
+ val visitor = CollectAnnotatedSymbolsVisitor(inDepth)
+
+ for (file in newKSFiles) {
+ file.accept(visitor, Unit)
+ }
+
+ return visitor.symbols
+ }
+
+ private val deferredSymbolsUpdated: Collection<KSAnnotated> by lazy {
+ deferredSymbols.values.flatten().mapNotNull { it.getInstanceForCurrentRound() }
+ }
+
+ private val newAnnotatedSymbols: Collection<KSAnnotated> by lazy {
+ collectAnnotatedSymbols(false) + deferredSymbolsUpdated
+ }
+
+ private val newAnnotatedSymbolsWithLocals: Collection<KSAnnotated> by lazy {
+ collectAnnotatedSymbols(true) + deferredSymbolsUpdated
+ }
+
+ override fun getKSNameFromString(name: String): KSName {
+ return KSNameImpl.getCached(name)
+ }
+
+ override fun createKSTypeReferenceFromKSType(type: KSType): KSTypeReference {
+ return KSTypeReferenceSyntheticImpl.getCached(type, null)
+ }
+
+ @KspExperimental
+ override fun mapToJvmSignature(declaration: KSDeclaration): String? = mapToJvmSignatureInternal(declaration)
+
+ internal fun mapToJvmSignatureInternal(declaration: KSDeclaration): String? = when (declaration) {
+ is KSClassDeclaration -> resolveClassDeclaration(declaration)?.let { typeMapper.mapType(it).descriptor }
+ is KSFunctionDeclaration -> resolveFunctionDeclaration(declaration)?.let {
+ when (it) {
+ is FunctionDescriptor -> typeMapper.mapAsmMethod(it).descriptor
+ is PropertyDescriptor -> typeMapper.mapFieldSignature(it.type, it) ?: typeMapper.mapType(it).descriptor
+ else -> throw IllegalStateException("Unexpected descriptor type for declaration: $declaration")
+ }
+ }
+ is KSPropertyDeclaration -> resolvePropertyDeclaration(declaration)?.let {
+ typeMapper.mapFieldSignature(it.type, it) ?: typeMapper.mapType(it).descriptor
+ }
+ else -> null
+ }
+
+ override fun overrides(overrider: KSDeclaration, overridee: KSDeclaration): Boolean {
+ fun resolveForOverride(declaration: KSDeclaration): DeclarationDescriptor? {
+ return when (declaration) {
+ is KSPropertyDeclaration -> resolvePropertyDeclaration(declaration)
+ is KSFunctionDeclarationJavaImpl -> resolveJavaDeclaration(declaration.psi)
+ is KSFunctionDeclaration -> resolveFunctionDeclaration(declaration)
+ else -> null
+ }
+ }
+
+ if (!overridee.isOpen())
+ return false
+ if (!overridee.isVisibleFrom(overrider))
+ return false
+ if (!(
+ overridee is KSFunctionDeclaration || overrider is KSFunctionDeclaration ||
+ (overridee is KSPropertyDeclaration && overrider is KSPropertyDeclaration)
+ )
+ )
+ return false
+
+ if (overrider is KSPropertyDeclarationJavaImpl)
+ return false
+
+ val superDescriptor = resolveForOverride(overridee) as? CallableMemberDescriptor ?: return false
+ val subDescriptor = resolveForOverride(overrider) as? CallableMemberDescriptor ?: return false
+ val subClassDescriptor = overrider.closestClassDeclaration()?.let {
+ resolveClassDeclaration(it)
+ } ?: return false
+ val superClassDescriptor = overridee.closestClassDeclaration()?.let {
+ resolveClassDeclaration(it)
+ } ?: return false
+
+ incrementalContext.recordLookupWithSupertypes(subClassDescriptor.defaultType)
+
+ val typeOverride = subClassDescriptor.getAllSuperClassifiers()
+ .filter { it != subClassDescriptor } // exclude subclass itself as it cannot override its own methods
+ .any {
+ it == superClassDescriptor
+ }
+ if (!typeOverride) return false
+
+ incrementalContext.recordLookupForDeclaration(overrider)
+ incrementalContext.recordLookupForDeclaration(overridee)
+
+ return OverridingUtil.overrides(subDescriptor, superDescriptor, true, true)
+ }
+
+ // check if the candidate is overridden from the original declaration.
+ private fun isOriginal(original: KSDeclaration, candidate: KSDeclaration): Boolean {
+ incrementalContext.recordLookupForDeclaration(original)
+ incrementalContext.recordLookupForDeclaration(candidate)
+ val originalDescriptor = when (original) {
+ is KSPropertyDeclaration -> resolvePropertyDeclaration(original)
+ is KSFunctionDeclaration ->
+ (resolveFunctionDeclaration(original) as? FunctionDescriptor)?.propertyIfAccessor
+ else -> return false
+ }
+
+ val candidateDescriptors = when (candidate) {
+ is KSPropertyDeclaration -> resolvePropertyDeclaration(candidate)?.overriddenDescriptors
+ is KSFunctionDeclaration -> resolveFunctionDeclaration(candidate)?.overriddenDescriptors
+ else -> return false
+ }
+ return candidateDescriptors?.any { it == originalDescriptor } ?: false
+ }
+
+ override fun overrides(
+ overrider: KSDeclaration,
+ overridee: KSDeclaration,
+ containingClass: KSClassDeclaration
+ ): Boolean {
+ incrementalContext.recordLookupForDeclaration(containingClass)
+ return when (overrider) {
+ is KSPropertyDeclaration -> containingClass.getAllProperties().singleOrNull {
+ it.simpleName.asString() == overrider.simpleName.asString() && isOriginal(overrider, it)
+ }?.let { overrides(it, overridee) } ?: false
+ is KSFunctionDeclaration -> {
+ val candidates = containingClass.getAllFunctions().filter {
+ it.simpleName.asString() == overridee.simpleName.asString()
+ }
+ if (overrider.simpleName.asString().startsWith("get") ||
+ overrider.simpleName.asString().startsWith("set")
+ ) {
+ candidates.plus(
+ containingClass.getAllProperties().filter {
+ val overriderName = overrider.simpleName.asString().substring(3)
+ .replaceFirstChar { it.lowercase() }
+ it.simpleName.asString() == overriderName ||
+ it.simpleName.asString().replaceFirstChar { it.lowercase() } == overriderName
+ }
+ // TODO: It is currently not possible to do the overridden descriptor optimization for java overrides.
+ ).any { overrides(it, overridee) }
+ } else {
+ candidates.singleOrNull { isOriginal(overrider, it) }?.let { overrides(it, overridee) } ?: false
+ }
+ }
+ else -> false
+ }
+ }
+
+ fun evaluateConstant(expression: KtExpression?, expectedType: KotlinType): ConstantValue<*>? {
+ return expression?.let {
+ if (it is KtClassLiteralExpression && it.receiverExpression != null) {
+ val parent = KtStubbedPsiUtil.getPsiOrStubParent(it, KtPrimaryConstructor::class.java, false)
+ val scope = resolveSession.declarationScopeProvider.getResolutionScopeForDeclaration(parent!!)
+ val result = qualifiedExpressionResolver
+ .resolveDescriptorForDoubleColonLHS(it.receiverExpression!!, scope, bindingTrace, false)
+ val classifier = result.classifierDescriptor ?: return null
+ val typeResolutionContext = TypeResolutionContext(scope, bindingTrace, true, true, false)
+ val possiblyBareType = resolveSession.typeResolver
+ .resolveTypeForClassifier(typeResolutionContext, classifier, result, it, Annotations.EMPTY)
+ var actualType = if (possiblyBareType.isBare)
+ possiblyBareType.bareTypeConstructor.declarationDescriptor!!.defaultType
+ else possiblyBareType.actualType
+ var arrayDimension = 0
+ while (KotlinBuiltIns.isArray(actualType)) {
+ actualType = actualType.arguments.single().type
+ arrayDimension += 1
+ }
+ KClassValue(actualType.constructor.declarationDescriptor.classId!!, arrayDimension)
+ } else {
+ constantExpressionEvaluator.evaluateExpression(it, bindingTrace)?.toConstantValue(expectedType) ?: run {
+ val parent = KtStubbedPsiUtil
+ .getPsiOrStubParent(expression, KtPrimaryConstructor::class.java, false)
+ val scope = resolveSession.declarationScopeProvider.getResolutionScopeForDeclaration(parent!!)
+ qualifiedExpressionResolver
+ .resolvePackageHeader(expression.containingKtFile.packageDirective!!, module, bindingTrace)
+ bodyResolver.resolveConstructorParameterDefaultValues(
+ topDownAnalysisContext.outerDataFlowInfo, bindingTrace,
+ parent, (scope.ownerDescriptor as ClassDescriptor).constructors.first(), scope,
+ resolveSession.inferenceSession
+ )
+ constantExpressionEvaluator.evaluateExpression(it, bindingTrace)?.toConstantValue(expectedType)
+ }
+ }
+ }
+ }
+
+ fun resolveDeclaration(declaration: KtDeclaration): DeclarationDescriptor? {
+ return if (KtPsiUtil.isLocal(declaration)) {
+ resolveDeclarationForLocal(declaration)
+ bindingTrace.bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration)
+ } else {
+ resolveSession.resolveToDescriptor(declaration)
+ }
+ }
+
+ // TODO: Resolve Java variables is not supported by this function. Not needed currently.
+ fun resolveJavaDeclaration(psi: PsiElement): DeclarationDescriptor? {
+ return when (psi) {
+ is PsiClass -> moduleClassResolver.resolveClass(
+ JavaClassImpl(psi).apply { workaroundForNested(lazyJavaResolverContext) }
+ )
+ is PsiMethod -> {
+ // TODO: get rid of hardcoded check if possible.
+ val property = if (psi.name.startsWith("set") || psi.name.startsWith("get")) {
+ moduleClassResolver
+ .resolveContainingClass(psi)
+ ?.findEnclosedDescriptor(
+ kindFilter = DescriptorKindFilter.CALLABLES
+ ) {
+ (it as? PropertyDescriptor)?.getter?.findPsi() == psi ||
+ (it as? PropertyDescriptor)?.setter?.findPsi() == psi
+ }
+ } else null
+ property ?: moduleClassResolver
+ .resolveContainingClass(psi)?.let { containingClass ->
+ val filter = if (psi is SyntheticElement) {
+ { declaration: DeclarationDescriptor -> declaration.name.asString() == psi.name }
+ } else {
+ { declaration: DeclarationDescriptor -> declaration.findPsi() == psi }
+ }
+ containingClass.findEnclosedDescriptor(
+ kindFilter = DescriptorKindFilter.FUNCTIONS,
+ filter = filter
+ )
+ }
+ }
+ is PsiField -> {
+ moduleClassResolver
+ .resolveClass(
+ JavaFieldImpl(psi).containingClass.apply { workaroundForNested(lazyJavaResolverContext) }
+ )
+ ?.findEnclosedDescriptor(
+ kindFilter = DescriptorKindFilter.VARIABLES,
+ filter = { it.findPsi() == psi }
+ )
+ }
+ else -> throw IllegalStateException("unhandled psi element kind: ${psi.javaClass}")
+ }
+ }
+
+ fun resolveClassDeclaration(classDeclaration: KSClassDeclaration): ClassDescriptor? {
+ return when (classDeclaration) {
+ is KSClassDeclarationImpl -> resolveDeclaration(classDeclaration.ktClassOrObject)
+ is KSClassDeclarationDescriptorImpl -> classDeclaration.descriptor
+ is KSClassDeclarationJavaImpl -> resolveJavaDeclaration(classDeclaration.psi)
+ else -> throw IllegalStateException("unexpected class: ${classDeclaration.javaClass}")
+ } as ClassDescriptor?
+ }
+
+ fun resolveFunctionDeclaration(function: KSFunctionDeclaration): CallableDescriptor? {
+ return when (function) {
+ is KSFunctionDeclarationImpl -> resolveDeclaration(function.ktFunction)
+ is KSFunctionDeclarationDescriptorImpl -> function.descriptor
+ is KSFunctionDeclarationJavaImpl -> {
+ val descriptor = resolveJavaDeclaration(function.psi)
+ if (descriptor is JavaForKotlinOverridePropertyDescriptor) {
+ if (function.simpleName.asString().startsWith("set")) {
+ descriptor.setter
+ } else {
+ descriptor.getter
+ }
+ } else {
+ descriptor
+ }
+ }
+ is KSConstructorSyntheticImpl -> {
+ // we might create synthetic constructor when it is not declared in code
+ // it is either for kotlin, where we can use primary constructor, or for java
+ // where we can use the only available constructor
+ val resolved = resolveClassDeclaration(function.ksClassDeclaration)
+ resolved?.unsubstitutedPrimaryConstructor ?: resolved?.constructors?.singleOrNull()
+ }
+ else -> throw IllegalStateException("unexpected class: ${function.javaClass}")
+ } as? CallableDescriptor
+ }
+
+ fun resolvePropertyDeclaration(property: KSPropertyDeclaration): PropertyDescriptor? {
+ return when (property) {
+ is KSPropertyDeclarationImpl -> resolveDeclaration(property.ktProperty)
+ is KSPropertyDeclarationParameterImpl -> resolveDeclaration(property.ktParameter)
+ is KSPropertyDeclarationDescriptorImpl -> property.descriptor
+ is KSPropertyDeclarationJavaImpl -> resolveJavaDeclaration(property.psi)
+ else -> throw IllegalStateException("unexpected class: ${property.javaClass}")
+ } as PropertyDescriptor?
+ }
+
+ fun resolvePropertyAccessorDeclaration(accessor: KSPropertyAccessor): PropertyAccessorDescriptor? {
+ return when (accessor) {
+ is KSPropertyAccessorDescriptorImpl -> accessor.descriptor
+ is KSPropertyAccessorImpl -> resolveDeclaration(accessor.ktPropertyAccessor)
+ is KSPropertySetterSyntheticImpl -> resolvePropertyDeclaration(accessor.receiver)?.setter
+ is KSPropertyGetterSyntheticImpl -> resolvePropertyDeclaration(accessor.receiver)?.getter
+ else -> throw IllegalStateException("unexpected class: ${accessor.javaClass}")
+ } as PropertyAccessorDescriptor?
+ }
+
+ fun resolveJavaType(psi: PsiType, parentTypeReference: KSTypeReference? = null): KotlinType {
+ incrementalContext.recordLookup(psi)
+ val javaType = JavaTypeImpl.create(psi)
+
+ var parent: KSNode? = parentTypeReference
+
+ val stack = Stack<KSNode>()
+ while (parent != null) {
+ if (parent is KSFunctionDeclarationJavaImpl || parent is KSClassDeclarationJavaImpl) {
+ stack.push(parent)
+ }
+ parent = parent.parent
+ }
+ // Construct resolver context for the PsiType
+ var resolverContext = lazyJavaResolverContext
+
+ for (e in stack) {
+ when (e) {
+ is KSFunctionDeclarationJavaImpl -> {
+ // Non-physical methods have no interesting scope and may have no containing class
+ if (!e.psi.isPhysical || e.psi.containingClass == null)
+ continue
+ resolverContext = resolverContext
+ .childForMethod(
+ resolveJavaDeclaration(e.psi)!!,
+ if (e.psi.isConstructor) JavaConstructorImpl(e.psi) else JavaMethodImpl(e.psi)
+ )
+ }
+ is KSClassDeclarationJavaImpl -> {
+ resolverContext = resolverContext
+ .childForClassOrPackage(resolveJavaDeclaration(e.psi) as ClassDescriptor, JavaClassImpl(e.psi))
+ }
+ }
+ }
+ return if (javaType is JavaArrayTypeImpl)
+ resolverContext
+ .typeResolver.transformArrayType(javaType, TypeUsage.COMMON.toAttributes(), psi is PsiEllipsisType)
+ else
+ resolverContext.typeResolver.transformJavaType(javaType, TypeUsage.COMMON.toAttributes())
+ }
+
+ /*
+ * Don't map Java types in annotation parameters
+ *
+ * Users may specify Java types explicitly by instances of `Class<T>`.
+ * The situation is similar to `getClassDeclarationByName` where we have
+ * decided to keep those Java types not mapped.
+ *
+ * It would be troublesome if users try to use reflection on types that
+ * were mapped to Kotlin builtins, becuase some of those builtins don't
+ * even exist in classpath.
+ *
+ * Therefore, ResolverImpl.resolveJavaType cannot be used.
+ */
+ fun resolveJavaTypeInAnnotations(psiType: PsiType): KSType = if (options.mapAnnotationArgumentsInJava) {
+ getKSTypeCached(resolveJavaType(psiType))
+ } else {
+ when (psiType) {
+ is PsiPrimitiveType -> {
+ getClassDeclarationByName(psiType.boxedTypeName!!)!!.asStarProjectedType()
+ }
+ is PsiArrayType -> {
+ val componentType = resolveJavaTypeInAnnotations(psiType.componentType)
+ val componentTypeRef = createKSTypeReferenceFromKSType(componentType)
+ val typeArgs = listOf(getTypeArgument(componentTypeRef, Variance.INVARIANT))
+ builtIns.arrayType.replace(typeArgs)
+ }
+ else -> {
+ getClassDeclarationByName(psiType.canonicalText)?.asStarProjectedType() ?: KSErrorType
+ }
+ }
+ }
+
+ fun KotlinType.expandNonRecursively(): KotlinType =
+ (constructor.declarationDescriptor as? TypeAliasDescriptor)?.expandedType?.withAbbreviation(this as SimpleType)
+ ?: this
+
+ fun TypeProjection.expand(): TypeProjection {
+ val expandedType = type.expand()
+ return if (expandedType == type) this else substitute { expandedType }
+ }
+
+ // TODO: Is this the most efficient way?
+ fun KotlinType.expand(): KotlinType =
+ replace(arguments.map { it.expand() }).expandNonRecursively()
+
+ fun KtTypeReference.lookup(): KotlinType? =
+ bindingTrace.get(BindingContext.ABBREVIATED_TYPE, this)?.expand() ?: bindingTrace.get(BindingContext.TYPE, this)
+
+ fun resolveUserType(type: KSTypeReference): KSType {
+ when (type) {
+ is KSTypeReferenceImpl -> {
+ val typeReference = type.ktTypeReference
+ typeReference.lookup()?.let {
+ return getKSTypeCached(it, type.element.typeArguments, type.annotations)
+ }
+ KtStubbedPsiUtil.getContainingDeclaration(typeReference)?.let { containingDeclaration ->
+ resolveDeclaration(containingDeclaration)?.let {
+ // TODO: only resolve relevant branch.
+ ForceResolveUtil.forceResolveAllContents(it)
+ }
+ // TODO: Fix resolution look up to avoid fallback to file scope.
+ typeReference.lookup()?.let {
+ return getKSTypeCached(it, type.element.typeArguments, type.annotations)
+ }
+ }
+ val scope = resolveSession.fileScopeProvider.getFileResolutionScope(typeReference.containingKtFile)
+ return resolveSession.typeResolver.resolveType(scope, typeReference, bindingTrace, false).let {
+ getKSTypeCached(it, type.element.typeArguments, type.annotations)
+ }
+ }
+ is KSTypeReferenceDescriptorImpl -> {
+ return getKSTypeCached(type.kotlinType)
+ }
+ is KSTypeReferenceJavaImpl -> {
+ val psi = (type.psi as? PsiClassReferenceType)?.resolve()
+ if (psi is PsiTypeParameter) {
+ (type.psi as PsiClassReferenceType).typeArguments().forEach {
+ if (it is PsiType) {
+ incrementalContext.recordLookup(it)
+ }
+ }
+ val containingDeclaration = if (psi.owner is PsiClass) {
+ moduleClassResolver.resolveClass(
+ JavaClassImpl(psi.owner as PsiClass).apply { workaroundForNested(lazyJavaResolverContext) }
+ )
+ } else {
+ val owner = psi.owner
+ check(owner is PsiMethod) {
+ "unexpected owner type: $owner / ${owner?.javaClass}"
+ }
+ moduleClassResolver.resolveContainingClass(owner)
+ ?.findEnclosedDescriptor(
+ kindFilter = DescriptorKindFilter.FUNCTIONS,
+ filter = { it.findPsi() == owner }
+ ) as FunctionDescriptor
+ } as DeclarationDescriptor
+ val typeParameterDescriptor = LazyJavaTypeParameterDescriptor(
+ lazyJavaResolverContext,
+ JavaTypeParameterImpl(psi),
+ psi.index,
+ containingDeclaration
+ )
+ javaTypeParameterMap[typeParameterDescriptor] = psi
+ }
+ return getKSTypeCached(resolveJavaType(type.psi, type), type.element.typeArguments, type.annotations)
+ }
+ else -> throw IllegalStateException("Unable to resolve type for $type, $ExceptionMessage")
+ }
+ }
+
+ fun findDeclaration(kotlinType: KotlinType): KSDeclaration {
+ val descriptor = kotlinType.constructor.declarationDescriptor
+ val psi = descriptor?.findPsi()
+ return if (psi != null) {
+ when (psi) {
+ is KtClassOrObject -> KSClassDeclarationImpl.getCached(psi)
+ is PsiClass -> KSClassDeclarationJavaImpl.getCached(psi)
+ is KtTypeAlias -> KSTypeAliasImpl.getCached(psi)
+ is KtTypeParameter -> KSTypeParameterImpl.getCached(psi)
+ is PsiEnumConstant -> KSClassDeclarationJavaEnumEntryImpl.getCached(psi)
+ else -> throw IllegalStateException("Unexpected psi type: ${psi.javaClass}, $ExceptionMessage")
+ }
+ } else {
+ when (descriptor) {
+ is ClassDescriptor -> KSClassDeclarationDescriptorImpl.getCached(descriptor)
+ // LazyJavaTypeParameterDescriptor has `source` overridden to `NO_SOURCE`, therefore
+ // need to look up psi within KSP.
+ is TypeParameterDescriptor -> if (descriptor in javaTypeParameterMap) {
+ KSTypeParameterJavaImpl.getCached(javaTypeParameterMap[descriptor]!!)
+ } else {
+ KSTypeParameterDescriptorImpl.getCached(descriptor)
+ }
+ is TypeAliasDescriptor -> KSTypeAliasDescriptorImpl.getCached(descriptor)
+ null -> throw IllegalStateException("Failed to resolve descriptor for $kotlinType")
+ else -> throw IllegalStateException(
+ "Unexpected descriptor type: ${descriptor.javaClass}, $ExceptionMessage"
+ )
+ }
+ }
+ }
+
+ // Finds closest non-local scope.
+ fun KtElement.findLexicalScope(): LexicalScope {
+ return containingNonLocalDeclaration()?.let {
+ resolveSession.declarationScopeProvider.getResolutionScopeForDeclaration(it)
+ } ?: resolveSession.fileScopeProvider.getFileResolutionScope(this.containingKtFile)
+ }
+
+ fun resolveAnnotationEntry(ktAnnotationEntry: KtAnnotationEntry): AnnotationDescriptor? {
+ bindingTrace.get(BindingContext.ANNOTATION, ktAnnotationEntry)?.let { return it }
+ KtStubbedPsiUtil.getContainingDeclaration(ktAnnotationEntry)?.let { containingDeclaration ->
+ if (KtPsiUtil.isLocal(containingDeclaration)) {
+ resolveDeclarationForLocal(containingDeclaration)
+ } else {
+ resolveSession.resolveToDescriptor(containingDeclaration).annotations.forEach {}
+ }
+ } ?: ktAnnotationEntry.containingKtFile.let {
+ resolveSession.getFileAnnotations(it).forEach {}
+ }
+ return bindingTrace.get(BindingContext.ANNOTATION, ktAnnotationEntry)
+ }
+
+ fun resolveDeclarationForLocal(localDeclaration: KtDeclaration) {
+ var declaration = KtStubbedPsiUtil.getContainingDeclaration(localDeclaration) ?: return
+ while (KtPsiUtil.isLocal(declaration))
+ declaration = KtStubbedPsiUtil.getContainingDeclaration(declaration)!!
+
+ val containingFD = resolveSession.resolveToDescriptor(declaration).also {
+ ForceResolveUtil.forceResolveAllContents(it)
+ }
+
+ if (declaration is KtNamedFunction) {
+ val dataFlowInfo = DataFlowInfo.EMPTY
+ val scope = resolveSession.declarationScopeProvider.getResolutionScopeForDeclaration(declaration)
+ bodyResolver.resolveFunctionBody(
+ dataFlowInfo,
+ bindingTrace,
+ declaration,
+ containingFD as FunctionDescriptor,
+ scope,
+ null
+ )
+ }
+ }
+
+ @KspExperimental
+ override fun getJvmName(accessor: KSPropertyAccessor): String? {
+ val descriptor = resolvePropertyAccessorDeclaration(accessor)
+
+ return descriptor?.let {
+ // KotlinTypeMapper.mapSignature always uses OwnerKind.IMPLEMENTATION
+ typeMapper.mapFunctionName(descriptor, OwnerKind.IMPLEMENTATION)
+ }
+ }
+
+ @KspExperimental
+ override fun getJvmName(declaration: KSFunctionDeclaration): String? {
+ // function names might be mangled if they receive inline class parameters or they are internal
+ val descriptor = resolveFunctionDeclaration(declaration)
+ return (descriptor as? FunctionDescriptor)?.let {
+ // KotlinTypeMapper.mapSignature always uses OwnerKind.IMPLEMENTATION
+ typeMapper.mapFunctionName(it, OwnerKind.IMPLEMENTATION)
+ }
+ }
+
+ @KspExperimental
+ override fun getOwnerJvmClassName(declaration: KSPropertyDeclaration): String? {
+ val descriptor = resolvePropertyDeclaration(declaration) ?: return null
+ return getJvmOwnerQualifiedName(descriptor)
+ }
+
+ @KspExperimental
+ override fun getOwnerJvmClassName(declaration: KSFunctionDeclaration): String? {
+ val descriptor = resolveFunctionDeclaration(declaration) ?: return null
+ return getJvmOwnerQualifiedName(descriptor)
+ }
+
+ private fun getJvmOwnerQualifiedName(descriptor: DeclarationDescriptor): String? {
+ return try {
+ typeMapper.mapImplementationOwner(descriptor).className
+ } catch (unsupported: UnsupportedOperationException) {
+ null
+ }
+ }
+
+ private fun extractThrowsFromClassFile(
+ virtualFileContent: ByteArray,
+ jvmDesc: String?,
+ simpleName: String?
+ ): Sequence<KSType> {
+ val exceptionNames = mutableListOf<String>()
+ ClassReader(virtualFileContent).accept(
+ object : ClassVisitor(API_VERSION) {
+ override fun visitMethod(
+ access: Int,
+ name: String?,
+ descriptor: String?,
+ signature: String?,
+ exceptions: Array<out String>?,
+ ): MethodVisitor {
+ if (name == simpleName && jvmDesc == descriptor) {
+ exceptions?.toList()?.let { exceptionNames.addAll(it) }
+ }
+ return object : MethodVisitor(API_VERSION) {
+ }
+ }
+ },
+ ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES
+ )
+ return exceptionNames.mapNotNull {
+ this@ResolverImpl.getClassDeclarationByName(it.replace("/", "."))?.asStarProjectedType()
+ }.asSequence()
+ }
+
+ @SuppressWarnings("UNCHECKED_CAST")
+ private fun extractThrowsAnnotation(annotated: KSAnnotated): Sequence<KSType> {
+ return annotated.annotations
+ .singleOrNull {
+ it.shortName.asString() == "Throws" &&
+ it.annotationType.resolve().declaration.qualifiedName?.asString() == "kotlin.Throws"
+ }?.arguments
+ ?.singleOrNull()
+ ?.let { it.value as? ArrayList<KSType> }
+ ?.asSequence() ?: emptySequence()
+ }
+
+ // TODO: refactor and reuse BinaryClassInfoCache
+ @KspExperimental
+ override fun getJvmCheckedException(function: KSFunctionDeclaration): Sequence<KSType> {
+ return when (function.origin) {
+ Origin.JAVA -> {
+ val psi = (function as KSFunctionDeclarationJavaImpl).psi
+ psi.throwsList.referencedTypes.asSequence().map { getKSTypeCached(resolveJavaType(it)) }
+ }
+ Origin.KOTLIN -> {
+ extractThrowsAnnotation(function)
+ }
+ Origin.KOTLIN_LIB, Origin.JAVA_LIB -> {
+ val descriptor = (function as KSFunctionDeclarationDescriptorImpl).descriptor
+ val jvmDesc = this.mapToJvmSignature(function)
+ val virtualFileContent = if (function.origin == Origin.KOTLIN_LIB) {
+ (descriptor.getContainingKotlinJvmBinaryClass() as? VirtualFileKotlinClass)?.file
+ ?.contentsToByteArray()
+ } else {
+ (
+ ((descriptor.source as? JavaSourceElement)?.javaElement as? BinaryJavaMethodBase)
+ ?.containingClass as? BinaryJavaClass
+ )?.virtualFile?.contentsToByteArray()
+ }
+ if (virtualFileContent == null) {
+ return emptySequence()
+ }
+ extractThrowsFromClassFile(virtualFileContent, jvmDesc, function.simpleName.asString())
+ }
+ else -> emptySequence()
+ }
+ }
+
+ @KspExperimental
+ override fun getJvmCheckedException(accessor: KSPropertyAccessor): Sequence<KSType> {
+ return when (accessor.origin) {
+ Origin.KOTLIN, Origin.SYNTHETIC -> {
+ extractThrowsAnnotation(accessor)
+ }
+ Origin.KOTLIN_LIB -> {
+ val descriptor = (accessor as KSPropertyAccessorDescriptorImpl).descriptor
+ val jvmDesc = typeMapper.mapAsmMethod(descriptor).descriptor
+ val virtualFileContent = if (accessor.origin == Origin.KOTLIN_LIB) {
+ (descriptor.correspondingProperty.getContainingKotlinJvmBinaryClass() as? VirtualFileKotlinClass)
+ ?.file?.contentsToByteArray()
+ } else {
+ (
+ ((descriptor.source as? JavaSourceElement)?.javaElement as? BinaryJavaMethod)?.containingClass
+ as? BinaryJavaClass
+ )?.virtualFile?.contentsToByteArray()
+ }
+ if (virtualFileContent == null) {
+ return emptySequence()
+ }
+ extractThrowsFromClassFile(virtualFileContent, jvmDesc, getJvmName(accessor))
+ }
+ else -> emptySequence()
+ }
+ }
+
+ private val javaPackageToClassMap: Map<String, List<KSDeclaration>> by lazy {
+ val packageToClassMapping = mutableMapOf<String, List<KSDeclaration>>()
+ allKSFiles
+ .filter { file ->
+ file.origin == Origin.JAVA &&
+ options.javaSourceRoots.any { root ->
+ file.filePath.startsWith(root.absolutePath) &&
+ file.filePath.substringAfter(root.absolutePath)
+ .dropLastWhile { c -> c != File.separatorChar }.dropLast(1).drop(1)
+ .replace(File.separatorChar, '.') == file.packageName.asString()
+ }
+ }
+ .forEach {
+ packageToClassMapping.put(
+ it.packageName.asString(),
+ packageToClassMapping.getOrDefault(it.packageName.asString(), emptyList())
+ .plus(
+ it.declarations.filterNot {
+ it.containingFile?.fileName?.split(".")?.first() == it.simpleName.asString()
+ }
+ )
+ )
+ }
+ packageToClassMapping
+ }
+
+ @KspExperimental
+ override fun getDeclarationsFromPackage(packageName: String): Sequence<KSDeclaration> {
+ val noPackageFilter = DescriptorKindFilter.ALL.withoutKinds(DescriptorKindFilter.PACKAGES_MASK)
+ return module.getPackage(FqName(packageName))
+ .memberScope.getContributedDescriptors(noPackageFilter)
+ .asSequence()
+ .mapNotNull { (it as? MemberDescriptor)?.toKSDeclaration() }
+ .plus(javaPackageToClassMap.getOrDefault(packageName, emptyList()).asSequence())
+ }
+
+ override fun getTypeArgument(typeRef: KSTypeReference, variance: Variance): KSTypeArgument {
+ return KSTypeArgumentLiteImpl.getCached(typeRef, variance)
+ }
+
+ internal fun asMemberOf(
+ property: KSPropertyDeclaration,
+ containing: KSType,
+ ): KSType {
+ val key = property to containing
+ return propertyAsMemberOfCache.getOrPut(key) {
+ computeAsMemberOf(property, containing)
+ }
+ }
+
+ private fun computeAsMemberOf(
+ property: KSPropertyDeclaration,
+ containing: KSType,
+ ): KSType {
+ val propertyDeclaredIn = property.closestClassDeclaration()
+ ?: throw IllegalArgumentException(
+ "Cannot call asMemberOf with a property that is " +
+ "not declared in a class or an interface"
+ )
+ val declaration = resolvePropertyDeclaration(property)
+ if (declaration != null && containing is KSTypeImpl && !containing.isError) {
+ incrementalContext.recordLookupWithSupertypes(containing.kotlinType)
+ incrementalContext.recordLookupForDeclaration(property)
+ if (!containing.kotlinType.isSubtypeOf(propertyDeclaredIn)) {
+ throw IllegalArgumentException(
+ "$containing is not a sub type of the class/interface that contains `$property` " +
+ "($propertyDeclaredIn)"
+ )
+ }
+ val typeSubstitutor = containing.kotlinType.createTypeSubstitutor()
+ val substituted = declaration.substitute(typeSubstitutor) as? ValueDescriptor
+ substituted?.let {
+ return getKSTypeCached(substituted.type)
+ }
+ }
+ // if substitution fails, fallback to the type from the property
+ return KSErrorType
+ }
+
+ internal fun asMemberOf(
+ function: KSFunctionDeclaration,
+ containing: KSType,
+ ): KSFunction {
+ val key = function to containing
+ return functionAsMemberOfCache.getOrPut(key) {
+ computeAsMemberOf(function, containing)
+ }
+ }
+
+ private fun computeAsMemberOf(
+ function: KSFunctionDeclaration,
+ containing: KSType,
+ ): KSFunction {
+ val functionDeclaredIn = function.closestClassDeclaration()
+ ?: throw IllegalArgumentException(
+ "Cannot call asMemberOf with a function that is " +
+ "not declared in a class or an interface"
+ )
+ val declaration = resolveFunctionDeclaration(function)
+ if (declaration != null && containing is KSTypeImpl && !containing.isError) {
+ incrementalContext.recordLookupWithSupertypes(containing.kotlinType)
+ incrementalContext.recordLookupForDeclaration(function)
+ if (!containing.kotlinType.isSubtypeOf(functionDeclaredIn)) {
+ throw IllegalArgumentException(
+ "$containing is not a sub type of the class/interface that contains " +
+ "`$function` ($functionDeclaredIn)"
+ )
+ }
+ val typeSubstitutor = containing.kotlinType.createTypeSubstitutor()
+ if (declaration is PropertyAccessorDescriptor) {
+ val substitutedProperty = (declaration.correspondingProperty).substitute(typeSubstitutor)
+ // TODO: Fix in upstream for property accessors: https://github.com/JetBrains/kotlin/blob/master/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/PropertyAccessorDescriptorImpl.java#L122
+ return KSFunctionImpl(
+ (substitutedProperty as PropertyDescriptor).accessors.single {
+ it.name == declaration.name
+ }
+ )
+ }
+ val substituted = declaration.substitute(typeSubstitutor)
+ return KSFunctionImpl(substituted)
+ }
+ // if substitution fails, return an error function that resembles the original declaration
+ return KSFunctionErrorImpl(function)
+ }
+
+ private fun KotlinType.isSubtypeOf(declaration: KSClassDeclaration): Boolean {
+ val classDeclaration = resolveClassDeclaration(declaration)
+ if (classDeclaration == null) {
+ throw IllegalArgumentException(
+ "Cannot find the declaration for class $classDeclaration"
+ )
+ }
+ return constructor
+ .declarationDescriptor
+ ?.getAllSuperClassifiers()
+ ?.any { it == classDeclaration } == true
+ }
+
+ override val builtIns: KSBuiltIns by lazy {
+ val builtIns = module.builtIns
+ object : KSBuiltIns {
+ override val anyType: KSType by lazy { getKSTypeCached(builtIns.anyType) }
+ override val nothingType by lazy { getKSTypeCached(builtIns.nothingType) }
+ override val unitType: KSType by lazy { getKSTypeCached(builtIns.unitType) }
+ override val numberType: KSType by lazy { getKSTypeCached(builtIns.numberType) }
+ override val byteType: KSType by lazy { getKSTypeCached(builtIns.byteType) }
+ override val shortType: KSType by lazy { getKSTypeCached(builtIns.shortType) }
+ override val intType: KSType by lazy { getKSTypeCached(builtIns.intType) }
+ override val longType: KSType by lazy { getKSTypeCached(builtIns.longType) }
+ override val floatType: KSType by lazy { getKSTypeCached(builtIns.floatType) }
+ override val doubleType: KSType by lazy { getKSTypeCached(builtIns.doubleType) }
+ override val charType: KSType by lazy { getKSTypeCached(builtIns.charType) }
+ override val booleanType: KSType by lazy { getKSTypeCached(builtIns.booleanType) }
+ override val stringType: KSType by lazy { getKSTypeCached(builtIns.stringType) }
+ override val iterableType: KSType by lazy {
+ getKSTypeCached(builtIns.iterableType.replaceArgumentsWithStarProjections())
+ }
+ override val annotationType: KSType by lazy { getKSTypeCached(builtIns.annotationType) }
+ override val arrayType: KSType by lazy {
+ getKSTypeCached(builtIns.array.defaultType.replaceArgumentsWithStarProjections())
+ }
+ }
+ }
+
+ internal val mockSerializableType = module.builtIns.numberType.supertypes().singleOrNull {
+ it.constructor.declarationDescriptor?.name?.asString() == "Serializable"
+ }
+
+ internal val javaSerializableType = module.resolveClassByFqName(
+ FqName("java.io.Serializable"), NoLookupLocation.WHEN_FIND_BY_FQNAME
+ )?.defaultType
+
+ @KspExperimental
+ override fun mapJavaNameToKotlin(javaName: KSName): KSName? =
+ JavaToKotlinClassMap.mapJavaToKotlin(FqName(javaName.asString()))?.toKSName()
+
+ @KspExperimental
+ override fun mapKotlinNameToJava(kotlinName: KSName): KSName? =
+ JavaToKotlinClassMap.mapKotlinToJava(FqNameUnsafe(kotlinName.asString()))?.toKSName()
+
+ @KspExperimental
+ internal fun mapToJvmSignature(accessor: KSPropertyAccessor): String {
+ return resolvePropertyAccessorDeclaration(accessor)?.let {
+ typeMapper.mapAsmMethod(it).descriptor
+ } ?: ""
+ }
+
+ @KspExperimental
+ override fun getDeclarationsInSourceOrder(container: KSDeclarationContainer): Sequence<KSDeclaration> {
+ return container.declarationsInSourceOrder
+ }
+
+ @KspExperimental
+ override fun effectiveJavaModifiers(declaration: KSDeclaration): Set<Modifier> {
+ val modifiers = HashSet<Modifier>(declaration.modifiers.filter { it in javaModifiers })
+
+ // This is only needed by sources.
+ // PUBLIC, PRIVATE, PROTECTED are already handled in descriptor based impls.
+ fun addVisibilityModifiers() {
+ when {
+ declaration.isPublic() -> modifiers.add(Modifier.PUBLIC)
+ declaration.isPrivate() -> modifiers.add(Modifier.PRIVATE)
+ declaration.isProtected() -> modifiers.add(Modifier.PROTECTED)
+ }
+ }
+
+ when (declaration.origin) {
+ Origin.JAVA -> {
+ addVisibilityModifiers()
+ if (declaration is KSClassDeclaration && declaration.classKind == ClassKind.INTERFACE)
+ modifiers.add(Modifier.ABSTRACT)
+ }
+ Origin.KOTLIN -> {
+ addVisibilityModifiers()
+ if (!declaration.isOpen())
+ modifiers.add(Modifier.FINAL)
+ if (declaration.hasAnnotation(JVM_STATIC_ANNOTATION_FQN))
+ modifiers.add(Modifier.JAVA_STATIC)
+ if (declaration.hasAnnotation(JVM_DEFAULT_ANNOTATION_FQN))
+ modifiers.add(Modifier.JAVA_DEFAULT)
+ if (declaration.hasAnnotation(JVM_DEFAULT_WITHOUT_COMPATIBILITY_ANNOTATION_FQN))
+ modifiers.add(Modifier.JAVA_DEFAULT)
+ if (declaration.hasAnnotation(JVM_STRICTFP_ANNOTATION_FQN))
+ modifiers.add(Modifier.JAVA_STRICT)
+ if (declaration.hasAnnotation(JVM_SYNCHRONIZED_ANNOTATION_FQN))
+ modifiers.add(Modifier.JAVA_SYNCHRONIZED)
+ if (declaration.hasAnnotation(JVM_TRANSIENT_ANNOTATION_FQN))
+ modifiers.add(Modifier.JAVA_TRANSIENT)
+ if (declaration.hasAnnotation(JVM_VOLATILE_ANNOTATION_FQN))
+ modifiers.add(Modifier.JAVA_VOLATILE)
+ when (declaration) {
+ is KSClassDeclaration -> {
+ if (declaration.isCompanionObject)
+ modifiers.add(Modifier.JAVA_STATIC)
+ if (declaration.classKind == ClassKind.INTERFACE)
+ modifiers.add(Modifier.ABSTRACT)
+ }
+ is KSPropertyDeclaration -> {
+ if (declaration.isAbstract())
+ modifiers.add(Modifier.ABSTRACT)
+ }
+ is KSFunctionDeclaration -> {
+ if (declaration.isAbstract)
+ modifiers.add(Modifier.ABSTRACT)
+ }
+ }
+ }
+ Origin.KOTLIN_LIB, Origin.JAVA_LIB -> {
+ when (declaration) {
+ is KSPropertyDeclaration -> {
+ if (declaration.jvmAccessFlag and Opcodes.ACC_TRANSIENT != 0)
+ modifiers.add(Modifier.JAVA_TRANSIENT)
+ if (declaration.jvmAccessFlag and Opcodes.ACC_VOLATILE != 0)
+ modifiers.add(Modifier.JAVA_VOLATILE)
+ }
+ is KSFunctionDeclaration -> {
+ if (declaration.jvmAccessFlag and Opcodes.ACC_STRICT != 0)
+ modifiers.add(Modifier.JAVA_STRICT)
+ if (declaration.jvmAccessFlag and Opcodes.ACC_SYNCHRONIZED != 0)
+ modifiers.add(Modifier.JAVA_SYNCHRONIZED)
+ }
+ }
+ }
+ else -> Unit
+ }
+ return modifiers
+ }
+
+ private enum class RefPosition {
+ PARAMETER_TYPE,
+ RETURN_TYPE,
+ SUPER_TYPE
+ }
+
+ // Search in self and parents for the first type reference that is not part of a type argument.
+ private fun KSTypeReference.findOuterMostRef(): Pair<KSTypeReference, List<Int>> {
+ fun KSNode.findParentRef(): KSTypeReference? {
+ var parent = parent
+ while (parent != null && parent !is KSTypeReference)
+ parent = parent.parent
+ return parent as? KSTypeReference
+ }
+
+ val fallback = Pair<KSTypeReference, List<Int>>(this, emptyList())
+ val indexes = mutableListOf<Int>()
+ var candidate: KSTypeReference = this
+ // KSTypeArgument's parent can be either KSReferenceElement or KSType.
+ while (candidate.parent is KSTypeArgument) {
+ // If the parent is a KSType, it's a synthetic reference.
+ // Do nothing and reply on the fallback behavior.
+ val referenceElement = (candidate.parent!!.parent as? KSReferenceElement) ?: return fallback
+ indexes.add(referenceElement.typeArguments.indexOf(candidate.parent))
+ // In case the program isn't properly structured, fallback.
+ candidate = referenceElement.findParentRef() ?: return fallback
+ }
+ return Pair(candidate, indexes)
+ }
+
+ // TODO: Strict mode for catching unhandled cases.
+ private fun findRefPosition(ref: KSTypeReference): RefPosition = when (val parent = ref.parent) {
+ is KSCallableReference -> when (ref) {
+ parent.returnType -> RefPosition.RETURN_TYPE
+ else -> RefPosition.PARAMETER_TYPE
+ }
+ is KSFunctionDeclaration -> when (ref) {
+ parent.returnType -> RefPosition.RETURN_TYPE
+ else -> RefPosition.PARAMETER_TYPE
+ }
+ is KSPropertyGetter -> RefPosition.RETURN_TYPE
+ is KSPropertyDeclaration -> when (ref) {
+ parent.type -> RefPosition.RETURN_TYPE
+ else -> RefPosition.PARAMETER_TYPE
+ }
+ is KSClassDeclaration -> RefPosition.SUPER_TYPE
+ // is KSTypeArgument -> RefPosition.PARAMETER_TYPE
+ // is KSAnnotation -> RefPosition.PARAMETER_TYPE
+ // is KSTypeAlias -> RefPosition.PARAMETER_TYPE
+ // is KSValueParameter -> RefPosition.PARAMETER_TYPE
+ // is KSTypeParameter -> RefPosition.PARAMETER_TYPE
+ else -> RefPosition.PARAMETER_TYPE
+ }
+
+ private fun KSTypeReference.isReturnTypeOfAnnotationMethod(): Boolean {
+ var candidate = this.parent
+ while (candidate !is KSClassDeclaration && candidate != null)
+ candidate = candidate.parent
+ return (candidate as? KSClassDeclaration)?.classKind == ClassKind.ANNOTATION_CLASS
+ }
+
+ // Convert type arguments for Java wildcard, recursively.
+ private fun KotlinType.toWildcard(mode: TypeMappingMode): KotlinType? {
+ val parameters = constructor.parameters
+ val arguments = arguments
+
+ val wildcardArguments = parameters.zip(arguments).map { (parameter, argument) ->
+ if (!argument.isStarProjection &&
+ parameter.variance != argument.projectionKind &&
+ parameter.variance != org.jetbrains.kotlin.types.Variance.INVARIANT &&
+ argument.projectionKind != org.jetbrains.kotlin.types.Variance.INVARIANT
+ ) {
+ // conflicting variances
+ // TODO: error message
+ return null
+ }
+
+ val argMode = mode.updateFromAnnotations(argument.type)
+ val variance = KotlinTypeMapper.getVarianceForWildcard(parameter, argument, argMode)
+ val genericMode = argMode.toGenericArgumentMode(
+ getEffectiveVariance(parameter.variance, argument.projectionKind)
+ )
+ TypeProjectionImpl(variance, argument.type.toWildcard(genericMode) ?: return null)
+ }
+
+ return replace(wildcardArguments)
+ }
+
+ private val JVM_SUPPRESS_WILDCARDS_NAME = KSNameImpl.getCached("kotlin.jvm.JvmSuppressWildcards")
+ private val JVM_SUPPRESS_WILDCARDS_SHORT = "JvmSuppressWildcards"
+ private fun KSTypeReference.findJvmSuppressWildcards(): Boolean? {
+ var candidate: KSNode? = this
+
+ while (candidate != null) {
+ if ((candidate is KSTypeReference || candidate is KSDeclaration)) {
+ (
+ (candidate as KSAnnotated).annotations.firstOrNull {
+ checkAnnotation(it, JVM_SUPPRESS_WILDCARDS_NAME, JVM_SUPPRESS_WILDCARDS_SHORT)
+ }?.arguments?.firstOrNull()?.value as? Boolean
+ )?.let {
+ // KSAnnotated.getAnnotationsByType is handy but it uses reflection.
+ return it
+ }
+ }
+ candidate = candidate.parent
+ }
+
+ return null
+ }
+
+ private fun TypeMappingMode.updateFromAnnotations(
+ type: KotlinType
+ ): TypeMappingMode {
+ (
+ type.annotations.findAnnotation(JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME)
+ ?.argumentValue("suppress")?.value as? Boolean
+ )?.let {
+ return this.suppressJvmWildcards(it)
+ }
+
+ if (type.annotations.hasAnnotation(JVM_WILDCARD_ANNOTATION_FQ_NAME)) {
+ return TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode(
+ skipDeclarationSiteWildcards = false,
+ isForAnnotationParameter = isForAnnotationParameter,
+ fallbackMode = this,
+ needInlineClassWrapping = needInlineClassWrapping,
+ mapTypeAliases = mapTypeAliases
+ )
+ }
+
+ return this
+ }
+
+ private fun TypeMappingMode.suppressJvmWildcards(
+ suppress: Boolean
+ ): TypeMappingMode {
+ return TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode(
+ skipDeclarationSiteWildcards = suppress,
+ isForAnnotationParameter = isForAnnotationParameter,
+ needInlineClassWrapping = needInlineClassWrapping,
+ mapTypeAliases = mapTypeAliases
+ )
+ }
+
+ private fun TypeMappingMode.updateFromParents(
+ ref: KSTypeReference
+ ): TypeMappingMode {
+ ref.findJvmSuppressWildcards()?.let {
+ return this.suppressJvmWildcards(it)
+ }
+
+ return this
+ }
+
+ // Type arguments need to be resolved recursively in a top-down manner. So we find and resolve the outer most
+ // reference that contains this argument. Then locate and return the argument.
+ @KspExperimental
+ override fun getJavaWildcard(reference: KSTypeReference): KSTypeReference {
+ // If the outer-most reference cannot be found, e.g., when this reference is nested in KSType.arguments,
+ // fallback to PARAMETER_TYPE effectively.
+ val (ref, indexes) = reference.findOuterMostRef()
+
+ val type = ref.resolve()
+ if (type.isError)
+ return reference
+
+ val position = findRefPosition(ref)
+ val kotlinType = (type as KSTypeImpl).kotlinType
+
+ val typeSystem = SimpleClassicTypeSystemContext
+ val typeMappingMode = when (position) {
+ RefPosition.PARAMETER_TYPE -> typeSystem.getOptimalModeForValueParameter(kotlinType)
+ RefPosition.RETURN_TYPE ->
+ typeSystem.getOptimalModeForReturnType(kotlinType, ref.isReturnTypeOfAnnotationMethod())
+ RefPosition.SUPER_TYPE -> TypeMappingMode.SUPER_TYPE
+ }.updateFromParents(ref)
+
+ val parameters = kotlinType.constructor.parameters
+ val arguments = kotlinType.arguments
+
+ parameters.zip(arguments).forEach { (parameter, argument) ->
+ 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)
+ }
+ }
+
+ 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)
+ }
+
+ @KspExperimental
+ override fun isJavaRawType(type: KSType): Boolean {
+ return type is KSTypeImpl && type.kotlinType.unwrap() is RawType
+ }
+
+ private val psiJavaFiles = allKSFiles.filterIsInstance<KSFileJavaImpl>().map {
+ Pair(it.psi.virtualFile.path, it.psi)
+ }.toMap()
+
+ internal fun findPsiJavaFile(path: String): PsiFile? = psiJavaFiles.get(path)
+}
+
+// TODO: cross module resolution
+fun DeclarationDescriptor.findExpectsInKSDeclaration(): Sequence<KSDeclaration> =
+ findExpects().asSequence().map {
+ it.toKSDeclaration()
+ }
+
+// TODO: cross module resolution
+fun DeclarationDescriptor.findActualsInKSDeclaration(): Sequence<KSDeclaration> =
+ findActuals(this.module).asSequence().map {
+ it.toKSDeclaration()
+ }
+
+fun MemberDescriptor.toKSDeclaration(): KSDeclaration =
+ when (val psi = findPsi()) {
+ is KtClassOrObject -> KSClassDeclarationImpl.getCached(psi)
+ is KtFunction -> KSFunctionDeclarationImpl.getCached(psi)
+ is KtProperty -> KSPropertyDeclarationImpl.getCached((psi))
+ is KtTypeAlias -> KSTypeAliasImpl.getCached(psi)
+ is PsiClass -> KSClassDeclarationJavaImpl.getCached(psi)
+ is PsiMethod -> KSFunctionDeclarationJavaImpl.getCached(psi)
+ is PsiField -> KSPropertyDeclarationJavaImpl.getCached(psi)
+ else -> when (this) {
+ is ClassDescriptor -> KSClassDeclarationDescriptorImpl.getCached(this)
+ is FunctionDescriptor -> KSFunctionDeclarationDescriptorImpl.getCached(this)
+ is PropertyDescriptor -> KSPropertyDeclarationDescriptorImpl.getCached(this)
+ else -> throw IllegalStateException("Unknown expect/actual implementation")
+ }
+ }
+
+/**
+ * [NewTypeSubstitutor] handles variance better than [TypeSubstitutor] so we use it when subtituting
+ * types in [ResolverImpl.asMemberOf] implementations.
+ */
+private fun TypeSubstitutor.toNewSubstitutor() = composeWith(
+ org.jetbrains.kotlin.resolve.calls.inference.components.EmptySubstitutor
+)
+
+private fun KotlinType.createTypeSubstitutor(): NewTypeSubstitutor {
+ return SubstitutionUtils.buildDeepSubstitutor(this).toNewSubstitutor()
+}
+
+/**
+ * Extracts the identifier from a module Name.
+ *
+ * One caveat here is that kotlin passes a special name into the plugin which cannot be used as an identifier.
+ * On the other hand, to construct the correct TypeMapper, we need a non-special name.
+ * This function extracts the non-special name from a given name if it is special.
+ *
+ * @see: https://github.com/JetBrains/kotlin/blob/master/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt#L305
+ */
+private fun Name.getNonSpecialIdentifier(): String {
+ // the analyzer might pass down a special name which will break type mapper name computations.
+ // If it is a special name, we turn it back to an id
+ if (!isSpecial || asString().isBlank()) {
+ return asString()
+ }
+ // special names starts with a `<` and usually end with `>`
+ return if (asString().last() == '>') {
+ asString().substring(1, asString().length - 1)
+ } else {
+ asString().substring(1)
+ }
+}
+
+private inline fun MemberScope.findEnclosedDescriptor(
+ kindFilter: DescriptorKindFilter,
+ crossinline filter: (DeclarationDescriptor) -> Boolean,
+): DeclarationDescriptor? {
+ return getContributedDescriptors(
+ kindFilter = kindFilter
+ ).firstOrNull(filter)
+}
+
+private inline fun ClassDescriptor.findEnclosedDescriptor(
+ kindFilter: DescriptorKindFilter,
+ crossinline filter: (DeclarationDescriptor) -> Boolean,
+): DeclarationDescriptor? {
+ return this.unsubstitutedMemberScope.findEnclosedDescriptor(
+ kindFilter = kindFilter,
+ filter = filter
+ ) ?: this.staticScope.findEnclosedDescriptor(
+ kindFilter = kindFilter,
+ filter = filter
+ ) ?: constructors.firstOrNull {
+ kindFilter.accepts(it) && filter(it)
+ }
+}
+
+internal fun KSAnnotated.findAnnotationFromUseSiteTarget(): Sequence<KSAnnotation> {
+ return when (this) {
+ is KSPropertyGetter -> (this.receiver as? KSDeclarationImpl)?.let {
+ it.originalAnnotations.asSequence().filter { it.useSiteTarget == AnnotationUseSiteTarget.GET }
+ }
+ is KSPropertySetter -> (this.receiver as? KSDeclarationImpl)?.let {
+ it.originalAnnotations.asSequence().filter { it.useSiteTarget == AnnotationUseSiteTarget.SET }
+ }
+ is KSValueParameter -> {
+ var parent = when (this) {
+ is KSValueParameterSyntheticImpl -> this.owner
+ is KSValueParameterImpl -> this.ktParameter.findParentAnnotated()
+ else -> null
+ }
+ // TODO: eliminate annotationsFromParents to make this fully sequence.
+ val annotationsFromParents = mutableListOf<KSAnnotation>()
+ (parent as? KSPropertyAccessorImpl)?.let {
+ annotationsFromParents.addAll(
+ it.originalAnnotations.asSequence()
+ .filter { it.useSiteTarget == AnnotationUseSiteTarget.SETPARAM }
+ )
+ parent = (parent as KSPropertyAccessorImpl).receiver
+ }
+ (parent as? KSPropertyDeclarationImpl)?.let {
+ annotationsFromParents.addAll(
+ it.originalAnnotations.asSequence()
+ .filter { it.useSiteTarget == AnnotationUseSiteTarget.SETPARAM }
+ )
+ }
+ annotationsFromParents.asSequence()
+ }
+ else -> emptySequence()
+ } ?: emptySequence()
+}
+
+// Resolve to underlying type.
+// Only slightly slower than resolving a plain type, because everything is resolved and cached in the first resolve().
+// FIXME: add a resolution mode in resolveUserType() to resolve to underlying type directly.
+internal fun KSTypeReference.resolveToUnderlying(): KSType {
+ var candidate = resolve()
+ var declaration = candidate.declaration
+ while (declaration is KSTypeAlias) {
+ candidate = declaration.type.resolve()
+ declaration = candidate.declaration
+ }
+ return candidate
+}
+
+// TODO: Remove this after upgrading to Kotlin 1.8.20.
+// Temporary work around for https://github.com/google/ksp/issues/1034
+// Force resolve outer most class for Java nested classes.
+internal fun JavaClass.workaroundForNested(
+ lazyJavaResolverContext: LazyJavaResolverContext = ResolverImpl.instance!!.lazyJavaResolverContext
+) {
+ var outerMost = outerClass
+ while (outerMost?.outerClass != null) {
+ outerMost = outerMost.outerClass
+ }
+ outerMost?.classId?.let { lazyJavaResolverContext.components.finder.findClass(it) }
+}
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
new file mode 100644
index 00000000..e52920c7
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSAnnotationDescriptorImpl.kt
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.ExceptionMessage
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.findPsi
+import com.google.devtools.ksp.symbol.impl.java.KSAnnotationJavaImpl
+import com.google.devtools.ksp.symbol.impl.kotlin.KSErrorType
+import com.google.devtools.ksp.symbol.impl.kotlin.KSValueArgumentLiteImpl
+import com.google.devtools.ksp.symbol.impl.kotlin.getKSTypeCached
+import com.google.devtools.ksp.symbol.impl.synthetic.KSTypeReferenceSyntheticImpl
+import com.intellij.psi.JavaPsiFacade
+import com.intellij.psi.PsiAnnotation
+import com.intellij.psi.PsiAnnotationMethod
+import org.jetbrains.kotlin.builtins.StandardNames
+import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
+import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.NotFoundClasses
+import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
+import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
+import org.jetbrains.kotlin.load.java.components.JavaAnnotationDescriptor
+import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaAnnotationDescriptor
+import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
+import org.jetbrains.kotlin.load.java.structure.*
+import org.jetbrains.kotlin.load.java.structure.impl.VirtualFileBoundJavaClass
+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.BinaryJavaMethod
+import org.jetbrains.kotlin.load.java.structure.impl.classFiles.ClassifierResolutionContext
+import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass
+import org.jetbrains.kotlin.load.kotlin.getContainingKotlinJvmBinaryClass
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
+import org.jetbrains.kotlin.resolve.constants.*
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.TypeConstructor
+import org.jetbrains.kotlin.types.isError
+import org.jetbrains.kotlin.types.typeUtil.builtIns
+import org.jetbrains.org.objectweb.asm.AnnotationVisitor
+import org.jetbrains.org.objectweb.asm.ClassReader
+import org.jetbrains.org.objectweb.asm.ClassVisitor
+import org.jetbrains.org.objectweb.asm.MethodVisitor
+import org.jetbrains.org.objectweb.asm.Opcodes.API_VERSION
+
+class KSAnnotationDescriptorImpl private constructor(
+ val descriptor: AnnotationDescriptor,
+ override val parent: KSNode?
+) : KSAnnotation {
+ companion object : KSObjectCache<Pair<AnnotationDescriptor, KSNode?>, KSAnnotationDescriptorImpl>() {
+ fun getCached(descriptor: AnnotationDescriptor, parent: KSNode?) = cache.getOrPut(Pair(descriptor, parent)) {
+ KSAnnotationDescriptorImpl(descriptor, parent)
+ }
+ }
+
+ override val origin =
+ when (descriptor) {
+ is JavaAnnotationDescriptor, is LazyJavaAnnotationDescriptor -> Origin.JAVA_LIB
+ else -> Origin.KOTLIN_LIB
+ }
+
+ override val location: Location = NonExistLocation
+
+ override val annotationType: KSTypeReference by lazy {
+ KSTypeReferenceDescriptorImpl.getCached(descriptor.type, origin, this)
+ }
+
+ override val arguments: List<KSValueArgument> by lazy {
+ descriptor.createKSValueArguments(this)
+ }
+
+ override val defaultArguments: List<KSValueArgument> by lazy {
+ descriptor.getDefaultArguments(this)
+ }
+
+ override val shortName: KSName by lazy {
+ KSNameImpl.getCached(descriptor.fqName!!.shortName().asString())
+ }
+
+ override val useSiteTarget: AnnotationUseSiteTarget? = null
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitAnnotation(this, data)
+ }
+
+ override fun toString(): String {
+ return "@${shortName.asString()}"
+ }
+}
+
+private fun ClassId.findKSClassDeclaration(): KSClassDeclaration? {
+ val ksName = KSNameImpl.getCached(this.asSingleFqName().asString().replace("$", "."))
+ return ResolverImpl.instance!!.getClassDeclarationByName(ksName)
+}
+
+private fun ClassId.findKSType(): KSType? = findKSClassDeclaration()?.asStarProjectedType()
+
+private fun <T> ConstantValue<T>.toValue(parent: KSNode): Any? = when (this) {
+ is AnnotationValue -> KSAnnotationDescriptorImpl.getCached(value, parent)
+ is ArrayValue -> value.map { it.toValue(parent) }
+ is EnumValue -> value.first.findKSClassDeclaration()?.declarations?.find {
+ it is KSClassDeclaration && it.classKind == ClassKind.ENUM_ENTRY &&
+ it.simpleName.asString() == value.second.asString()
+ }?.let { (it as KSClassDeclaration).asStarProjectedType() }
+ is KClassValue -> when (val classValue = value) {
+ is KClassValue.Value.NormalClass -> if (classValue.arrayDimensions > 0) {
+ classValue.value.classId.findKSType()?.let { componentType ->
+ var resultingType = componentType
+ for (i in 1..classValue.arrayDimensions) {
+ resultingType = ResolverImpl.instance!!.builtIns.arrayType.replace(
+ listOf(
+ ResolverImpl.instance!!.getTypeArgument(
+ KSTypeReferenceSyntheticImpl.getCached(resultingType, null), Variance.INVARIANT
+ )
+ )
+ )
+ }
+ resultingType
+ }
+ } else classValue.classId.findKSType()
+ is KClassValue.Value.LocalClass -> getKSTypeCached(classValue.type)
+ }
+ is ErrorValue, is NullValue -> null
+ else -> value
+}
+
+fun AnnotationDescriptor.createKSValueArguments(ownerAnnotation: KSAnnotation): List<KSValueArgument> {
+ val presentValueArguments = allValueArguments.map { (name, constantValue) ->
+ KSValueArgumentLiteImpl.getCached(
+ KSNameImpl.getCached(name.asString()),
+ constantValue.toValue(ownerAnnotation),
+ ownerAnnotation
+ )
+ }
+ val presentValueArgumentNames = presentValueArguments.map { it.name.asString() }
+ val argumentsFromDefault = this.type.getDefaultConstructorArguments(presentValueArgumentNames, ownerAnnotation)
+ return presentValueArguments.plus(argumentsFromDefault)
+}
+
+internal fun AnnotationDescriptor.getDefaultArguments(ownerAnnotation: KSAnnotation): List<KSValueArgument> {
+ return this.type.getDefaultConstructorArguments(emptyList(), ownerAnnotation)
+}
+
+internal fun TypeConstructor.toDeclarationDescriptor(): ClassDescriptor? {
+ if (this.declarationDescriptor !is NotFoundClasses.MockClassDescriptor) {
+ return this.declarationDescriptor as? ClassDescriptor
+ }
+ val fqName = (this.declarationDescriptor as? ClassDescriptor)?.fqNameSafe ?: return null
+ val shortNames = fqName.shortName().asString().split("$")
+ var parent = ResolverImpl.instance!!
+ .getClassDeclarationByName("${fqName.parent().asString()}.${shortNames.first()}")
+ for (i in 1 until shortNames.size) {
+ if (parent == null) {
+ return null
+ }
+ parent = parent.declarations
+ .filterIsInstance<KSClassDeclaration>()
+ .singleOrNull { it.simpleName.asString() == shortNames[i] }
+ }
+ return parent?.let { ResolverImpl.instance!!.resolveClassDeclaration(it) }
+}
+
+internal fun KotlinType.getDefaultConstructorArguments(
+ excludeNames: List<String>,
+ ownerAnnotation: KSAnnotation
+): List<KSValueArgument> {
+ return this.constructor.toDeclarationDescriptor()?.constructors?.single()
+ ?.getAbsentDefaultArguments(excludeNames, ownerAnnotation) ?: emptyList()
+}
+
+fun ClassConstructorDescriptor.getAbsentDefaultArguments(
+ excludeNames: List<String>,
+ ownerAnnotation: KSAnnotation
+): List<KSValueArgument> {
+ return this.valueParameters
+ .filterNot { param -> excludeNames.contains(param.name.asString()) || !param.hasDefaultValue() }
+ .map { param ->
+ KSValueArgumentLiteImpl.getCached(
+ KSNameImpl.getCached(param.name.asString()),
+ param.getDefaultValue(ownerAnnotation),
+ ownerAnnotation,
+ Origin.SYNTHETIC
+ )
+ }
+}
+
+fun ValueParameterDescriptor.getDefaultValue(ownerAnnotation: KSAnnotation): Any? {
+
+ // Copied from kotlin compiler
+ // TODO: expose in upstream
+ fun convertTypeToKClassValue(javaType: JavaType): KClassValue? {
+ var type = javaType
+ var arrayDimensions = 0
+ while (type is JavaArrayType) {
+ type = type.componentType
+ arrayDimensions++
+ }
+ return when (type) {
+ is JavaPrimitiveType -> {
+ val primitiveType = type.type
+ // void.class is not representable in Kotlin, we approximate it by Unit::class
+ ?: return KClassValue(ClassId.topLevel(StandardNames.FqNames.unit.toSafe()), 0)
+ if (arrayDimensions > 0) {
+ KClassValue(ClassId.topLevel(primitiveType.arrayTypeFqName), arrayDimensions - 1)
+ } else {
+ KClassValue(ClassId.topLevel(primitiveType.typeFqName), arrayDimensions)
+ }
+ }
+ is JavaClassifierType -> {
+ val fqName = FqName(type.classifierQualifiedName)
+ // TODO: support nested classes somehow
+ val classId = JavaToKotlinClassMap.mapJavaToKotlin(fqName) ?: ClassId.topLevel(fqName)
+ KClassValue(classId, arrayDimensions)
+ }
+ else -> null
+ }
+ }
+
+ // Copied from kotlin compiler
+ // TODO: expose in upstream
+ fun JavaAnnotationArgument.convert(expectedType: KotlinType): ConstantValue<*>? {
+ return when (this) {
+ is JavaLiteralAnnotationArgument -> value?.let {
+ when (value) {
+ // Note: `value` expression may be of class that does not match field type in some cases
+ // tested for Int, left other checks just in case
+ is Byte, is Short, is Int, is Long -> {
+ ConstantValueFactory.createIntegerConstantValue((value as Number).toLong(), expectedType, false)
+ }
+ else -> {
+ ConstantValueFactory.createConstantValue(value)
+ }
+ }
+ }
+ is JavaEnumValueAnnotationArgument -> {
+ enumClassId?.let { enumClassId ->
+ entryName?.let { entryName ->
+ EnumValue(enumClassId, entryName)
+ }
+ }
+ }
+ is JavaArrayAnnotationArgument -> {
+ val elementType = expectedType.builtIns.getArrayElementType(expectedType)
+ ConstantValueFactory.createArrayValue(
+ getElements().mapNotNull { it.convert(elementType) },
+ expectedType
+ )
+ }
+ is JavaAnnotationAsAnnotationArgument -> {
+ AnnotationValue(
+ LazyJavaAnnotationDescriptor(ResolverImpl.instance!!.lazyJavaResolverContext, this.getAnnotation())
+ )
+ }
+ is JavaClassObjectAnnotationArgument -> {
+ convertTypeToKClassValue(getReferencedType())
+ }
+ else -> null
+ }
+ }
+
+ val psi = this.findPsi()
+ return when (psi) {
+ null -> {
+ val file = if (this.source is JavaSourceElement) {
+ (
+ ((this.source as JavaSourceElement).javaElement as? BinaryJavaMethod)
+ ?.containingClass as? VirtualFileBoundJavaClass
+ )?.virtualFile?.contentsToByteArray()
+ } else {
+ (this.containingDeclaration.getContainingKotlinJvmBinaryClass() as? VirtualFileKotlinClass)
+ ?.file?.contentsToByteArray()
+ }
+ if (file == null) {
+ null
+ } else {
+ var defaultValue: JavaAnnotationArgument? = null
+ ClassReader(file).accept(
+ object : ClassVisitor(API_VERSION) {
+ override fun visitMethod(
+ access: Int,
+ name: String?,
+ desc: String?,
+ signature: String?,
+ exceptions: Array<out String>?
+ ): MethodVisitor {
+ return if (name == this@getDefaultValue.name.asString()) {
+ object : MethodVisitor(API_VERSION) {
+ override fun visitAnnotationDefault(): AnnotationVisitor =
+ BinaryJavaAnnotationVisitor(
+ ClassifierResolutionContext { null },
+ BinaryClassSignatureParser()
+ ) {
+ defaultValue = it
+ }
+ }
+ } else {
+ object : MethodVisitor(API_VERSION) {}
+ }
+ }
+ },
+ ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES
+ )
+ if (!this.type.isError) {
+ defaultValue?.convert(this.type)?.toValue(ownerAnnotation)
+ } else {
+ KSErrorType
+ }
+ }
+ }
+ is KtParameter -> if (!this.type.isError) {
+ ResolverImpl.instance!!.evaluateConstant(psi.defaultValue, this.type)?.toValue(ownerAnnotation)
+ } else {
+ KSErrorType
+ }
+ is PsiAnnotationMethod -> {
+ when (psi.defaultValue) {
+ is PsiAnnotation -> KSAnnotationJavaImpl.getCached(psi.defaultValue as PsiAnnotation)
+ else -> JavaPsiFacade.getInstance(psi.project).constantEvaluationHelper
+ .computeConstantExpression((psi).defaultValue)
+ }
+ }
+ else -> throw IllegalStateException("Unexpected psi ${psi.javaClass}, $ExceptionMessage")
+ }
+}
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
new file mode 100644
index 00000000..94f788fb
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassDeclarationDescriptorImpl.kt
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.*
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.*
+import com.google.devtools.ksp.symbol.impl.java.KSFunctionDeclarationJavaImpl
+import com.google.devtools.ksp.symbol.impl.java.KSPropertyDeclarationJavaImpl
+import com.google.devtools.ksp.symbol.impl.kotlin.*
+import com.google.devtools.ksp.symbol.impl.replaceTypeArguments
+import com.intellij.psi.PsiField
+import com.intellij.psi.PsiMethod
+import org.jetbrains.kotlin.builtins.StandardNames
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.psi.KtClassOrObject
+import org.jetbrains.kotlin.psi.KtFunction
+import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.kotlin.psi.KtProperty
+import org.jetbrains.kotlin.resolve.calls.tower.isSynthesized
+import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
+import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
+import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
+import org.jetbrains.kotlin.descriptors.ClassKind as KtClassKind
+
+class KSClassDeclarationDescriptorImpl private constructor(val descriptor: ClassDescriptor) :
+ KSClassDeclaration,
+ KSDeclarationDescriptorImpl(descriptor),
+ KSExpectActual by KSExpectActualDescriptorImpl(descriptor) {
+ companion object : KSObjectCache<ClassDescriptor, KSClassDeclarationDescriptorImpl>() {
+ fun getCached(descriptor: ClassDescriptor) = cache.getOrPut(descriptor) {
+ KSClassDeclarationDescriptorImpl(descriptor)
+ }
+ }
+
+ override val classKind: ClassKind by lazy {
+ when (descriptor.kind) {
+ KtClassKind.INTERFACE -> ClassKind.INTERFACE
+ KtClassKind.CLASS -> ClassKind.CLASS
+ KtClassKind.OBJECT -> ClassKind.OBJECT
+ KtClassKind.ENUM_CLASS -> ClassKind.ENUM_CLASS
+ KtClassKind.ENUM_ENTRY -> ClassKind.ENUM_ENTRY
+ KtClassKind.ANNOTATION_CLASS -> ClassKind.ANNOTATION_CLASS
+ }
+ }
+
+ override val isCompanionObject by lazy {
+ descriptor.isCompanionObject
+ }
+
+ override fun getSealedSubclasses(): Sequence<KSClassDeclaration> {
+ return descriptor.sealedSubclassesSequence()
+ }
+
+ override fun getAllFunctions(): Sequence<KSFunctionDeclaration> = descriptor.getAllFunctions()
+
+ override fun getAllProperties(): Sequence<KSPropertyDeclaration> = descriptor.getAllProperties()
+
+ override val primaryConstructor: KSFunctionDeclaration? by lazy {
+ descriptor.unsubstitutedPrimaryConstructor?.let { KSFunctionDeclarationDescriptorImpl.getCached(it) }
+ }
+
+ // Workaround for https://github.com/google/ksp/issues/195
+ private val mockSerializableType = ResolverImpl.instance!!.mockSerializableType
+ private val javaSerializableType = ResolverImpl.instance!!.javaSerializableType
+
+ override val superTypes: Sequence<KSTypeReference> by lazy {
+
+ descriptor.defaultType.constructor.supertypes.asSequence().map { kotlinType ->
+ KSTypeReferenceDescriptorImpl.getCached(
+ javaSerializableType?.let { if (kotlinType === mockSerializableType) it else kotlinType }
+ ?: kotlinType,
+ origin,
+ this
+ )
+ }.memoized()
+ }
+
+ override val typeParameters: List<KSTypeParameter> by lazy {
+ descriptor.declaredTypeParameters.map { KSTypeParameterDescriptorImpl.getCached(it) }
+ }
+
+ override val declarations: Sequence<KSDeclaration> by lazy {
+ sequenceOf(
+ descriptor.unsubstitutedMemberScope.getDescriptorsFiltered(),
+ // FIXME: Support static, synthetic `entries` for enums when the language feature is enabled.
+ descriptor.staticScope.getDescriptorsFiltered().filterNot {
+ descriptor.kind == KtClassKind.ENUM_CLASS &&
+ it is CallableDescriptor &&
+ it.isSynthesized &&
+ it.name == StandardNames.ENUM_ENTRIES
+ },
+ descriptor.constructors
+ ).flatten()
+ .filter {
+ it is MemberDescriptor &&
+ it.visibility != DescriptorVisibilities.INHERITED &&
+ it.visibility != DescriptorVisibilities.INVISIBLE_FAKE &&
+ (it !is CallableMemberDescriptor || it.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE)
+ }
+ .map {
+ when (it) {
+ is PropertyDescriptor -> KSPropertyDeclarationDescriptorImpl.getCached(it)
+ is FunctionDescriptor -> KSFunctionDeclarationDescriptorImpl.getCached(it)
+ is ClassDescriptor -> getCached(it)
+ else -> throw IllegalStateException("Unexpected descriptor type ${it.javaClass}, $ExceptionMessage")
+ }
+ }.memoized()
+ }
+
+ override val modifiers: Set<Modifier> by lazy {
+ val modifiers = mutableSetOf<Modifier>()
+ modifiers.addAll(descriptor.toKSModifiers())
+ if (descriptor.isData) {
+ modifiers.add(Modifier.DATA)
+ }
+ if (descriptor.isInline) {
+ modifiers.add(Modifier.INLINE)
+ }
+ if (descriptor.kind == KtClassKind.ANNOTATION_CLASS) {
+ modifiers.add(Modifier.ANNOTATION)
+ }
+ if (descriptor.isInner) {
+ modifiers.add(Modifier.INNER)
+ }
+ if (descriptor.isFun) {
+ modifiers.add(Modifier.FUN)
+ }
+ if (descriptor.isValue) {
+ modifiers.add(Modifier.VALUE)
+ }
+ modifiers
+ }
+
+ override fun asType(typeArguments: List<KSTypeArgument>): KSType =
+ descriptor.defaultType.replaceTypeArguments(typeArguments)?.let {
+ getKSTypeCached(it, typeArguments)
+ } ?: KSErrorType
+
+ override fun asStarProjectedType(): KSType {
+ return getKSTypeCached(descriptor.defaultType.replaceArgumentsWithStarProjections())
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitClassDeclaration(this, data)
+ }
+}
+
+internal fun ClassDescriptor.getAllFunctions(): Sequence<KSFunctionDeclaration> {
+ ResolverImpl.instance!!.incrementalContext.recordLookupForGetAllFunctions(this)
+ val functionDescriptors = unsubstitutedMemberScope.getDescriptorsFiltered(DescriptorKindFilter.FUNCTIONS)
+ .asSequence()
+ .filter { (it as FunctionDescriptor).visibility != DescriptorVisibilities.INVISIBLE_FAKE }
+ return functionDescriptors.plus(constructors).map {
+ when (val psi = it.findPsi()) {
+ is KtFunction -> KSFunctionDeclarationImpl.getCached(psi)
+ is PsiMethod -> KSFunctionDeclarationJavaImpl.getCached(psi)
+ else -> KSFunctionDeclarationDescriptorImpl.getCached(it as FunctionDescriptor)
+ }
+ }
+}
+
+internal fun ClassDescriptor.getAllProperties(): Sequence<KSPropertyDeclaration> {
+ ResolverImpl.instance!!.incrementalContext.recordLookupForGetAllProperties(this)
+ return unsubstitutedMemberScope.getDescriptorsFiltered(DescriptorKindFilter.VARIABLES).asSequence()
+ .filter { (it as PropertyDescriptor).visibility != DescriptorVisibilities.INVISIBLE_FAKE }
+ .map {
+ when (val psi = it.findPsi()) {
+ is KtParameter -> KSPropertyDeclarationParameterImpl.getCached(psi)
+ is KtProperty -> KSPropertyDeclarationImpl.getCached(psi)
+ is PsiField -> KSPropertyDeclarationJavaImpl.getCached(psi)
+ else -> KSPropertyDeclarationDescriptorImpl.getCached(it as PropertyDescriptor)
+ }
+ }
+}
+
+internal fun ClassDescriptor.sealedSubclassesSequence(): Sequence<KSClassDeclaration> {
+ // TODO record incremental subclass lookups in Kotlin 1.5.x?
+ return sealedSubclasses
+ .asSequence()
+ .map { sealedSubClass ->
+ when (val psi = sealedSubClass.findPsi()) {
+ is KtClassOrObject -> KSClassDeclarationImpl.getCached(psi)
+ else -> KSClassDeclarationDescriptorImpl.getCached(sealedSubClass)
+ }
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassifierReferenceDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassifierReferenceDescriptorImpl.kt
new file mode 100644
index 00000000..96e086ee
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSClassifierReferenceDescriptorImpl.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.*
+import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
+import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.TypeProjection
+
+class KSClassifierReferenceDescriptorImpl private constructor(
+ val descriptor: ClassifierDescriptor,
+ val arguments: List<TypeProjection>,
+ override val origin: Origin,
+ override val parent: KSNode?
+) :
+ KSClassifierReference {
+ companion object : KSObjectCache<Triple<ClassifierDescriptor, List<TypeProjection>, Pair<KSNode?, Origin>>,
+ KSClassifierReferenceDescriptorImpl>() {
+ fun getCached(kotlinType: KotlinType, origin: Origin, parent: KSNode?) = cache.getOrPut(
+ Triple(
+ kotlinType.constructor.declarationDescriptor!!,
+ kotlinType.arguments,
+ Pair(parent, origin)
+ )
+ ) {
+ KSClassifierReferenceDescriptorImpl(
+ kotlinType.constructor.declarationDescriptor!!, kotlinType.arguments, origin, parent
+ )
+ }
+
+ fun getCached(
+ descriptor: ClassifierDescriptor,
+ arguments: List<TypeProjection>,
+ origin: Origin,
+ parent: KSNode?
+ ) = cache.getOrPut(
+ Triple(descriptor, arguments, Pair(parent, origin))
+ ) { KSClassifierReferenceDescriptorImpl(descriptor, arguments, origin, parent) }
+ }
+
+ private val nDeclaredArgs by lazy {
+ (descriptor as? ClassifierDescriptorWithTypeParameters)?.declaredTypeParameters?.size ?: 0
+ }
+
+ override val location: Location = NonExistLocation
+
+ override val qualifier: KSClassifierReference? by lazy {
+ val outerDescriptor = descriptor.containingDeclaration as? ClassifierDescriptor ?: return@lazy null
+ val outerArguments = arguments.drop(nDeclaredArgs)
+ getCached(outerDescriptor, outerArguments, origin, parent)
+ }
+
+ override val typeArguments: List<KSTypeArgument> by lazy {
+ arguments.map { KSTypeArgumentDescriptorImpl.getCached(it, origin, this.parent) }
+ }
+
+ override fun referencedName(): String {
+ val declaredArgs = if (arguments.isEmpty() || nDeclaredArgs == 0)
+ emptyList()
+ else
+ arguments.subList(0, nDeclaredArgs)
+ return descriptor.name.asString() + if (declaredArgs.isNotEmpty()) "<${
+ declaredArgs.map { it.toString() }
+ .joinToString(", ")
+ }>" else ""
+ }
+
+ override fun toString() = referencedName()
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSDeclarationDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSDeclarationDescriptorImpl.kt
new file mode 100644
index 00000000..db041b26
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSDeclarationDescriptorImpl.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import org.jetbrains.kotlin.backend.common.serialization.findPackage
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
+import org.jetbrains.kotlin.resolve.descriptorUtil.parents
+import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
+import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
+
+abstract class KSDeclarationDescriptorImpl(private val descriptor: DeclarationDescriptor) : KSDeclaration {
+
+ override val origin by lazy {
+ descriptor.origin
+ }
+
+ override val containingFile: KSFile? = null
+
+ override val location: Location = NonExistLocation
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ descriptor.annotations.asSequence().map { KSAnnotationDescriptorImpl.getCached(it, this) }.memoized()
+ }
+
+ override val parentDeclaration: KSDeclaration? by lazy {
+ val containingDescriptor = descriptor.parents.first()
+ when (containingDescriptor) {
+ is ClassDescriptor -> KSClassDeclarationDescriptorImpl.getCached(containingDescriptor)
+ is FunctionDescriptor -> KSFunctionDeclarationDescriptorImpl.getCached(containingDescriptor)
+ else -> null
+ } as KSDeclaration?
+ }
+
+ override val parent: KSNode? by lazy {
+ parentDeclaration
+ }
+
+ override val packageName: KSName by lazy {
+ KSNameImpl.getCached(descriptor.findPackage().fqName.asString())
+ }
+
+ override val qualifiedName: KSName by lazy {
+ KSNameImpl.getCached(descriptor.fqNameSafe.asString())
+ }
+
+ override val simpleName: KSName by lazy {
+ KSNameImpl.getCached(descriptor.name.asString())
+ }
+
+ override fun toString(): String {
+ return this.simpleName.asString()
+ }
+
+ override val docString = null
+}
+
+val DeclarationDescriptor.origin: Origin
+ get() = if (parentsWithSelf.firstIsInstanceOrNull<JavaClassDescriptor>() != null) {
+ Origin.JAVA_LIB
+ } else {
+ Origin.KOTLIN_LIB
+ }
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSExpectActualDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSExpectActualDescriptorImpl.kt
new file mode 100644
index 00000000..7e527d77
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSExpectActualDescriptorImpl.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.processing.impl.findActualsInKSDeclaration
+import com.google.devtools.ksp.processing.impl.findExpectsInKSDeclaration
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSExpectActual
+import org.jetbrains.kotlin.descriptors.MemberDescriptor
+
+class KSExpectActualDescriptorImpl(val descriptor: MemberDescriptor) : KSExpectActual {
+ override val isExpect: Boolean = descriptor.isExpect
+
+ override val isActual: Boolean = descriptor.isActual
+
+ private val expects: Sequence<KSDeclaration> by lazy {
+ descriptor.findExpectsInKSDeclaration()
+ }
+
+ override fun findExpects(): Sequence<KSDeclaration> {
+ if (!isActual)
+ return emptySequence()
+ return expects
+ }
+
+ private val actuals: Sequence<KSDeclaration> by lazy {
+ descriptor.findActualsInKSDeclaration()
+ }
+
+ override fun findActuals(): Sequence<KSDeclaration> {
+ if (!isExpect)
+ return emptySequence()
+ return actuals
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSFunctionDeclarationDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSFunctionDeclarationDescriptorImpl.kt
new file mode 100644
index 00000000..0749a095
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSFunctionDeclarationDescriptorImpl.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.ExceptionMessage
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.*
+import com.google.devtools.ksp.toFunctionKSModifiers
+import com.google.devtools.ksp.toKSModifiers
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
+import org.jetbrains.kotlin.load.java.isFromJava
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
+import org.jetbrains.org.objectweb.asm.Opcodes
+
+class KSFunctionDeclarationDescriptorImpl private constructor(val descriptor: FunctionDescriptor) :
+ KSFunctionDeclaration,
+ KSDeclarationDescriptorImpl(descriptor),
+ KSExpectActual by KSExpectActualDescriptorImpl(descriptor) {
+ companion object : KSObjectCache<FunctionDescriptor, KSFunctionDeclarationDescriptorImpl>() {
+ fun getCached(descriptor: FunctionDescriptor) =
+ cache.getOrPut(descriptor) { KSFunctionDeclarationDescriptorImpl(descriptor) }
+ }
+
+ override fun findOverridee(): KSDeclaration? {
+ return descriptor?.findClosestOverridee()?.toKSDeclaration()
+ }
+
+ override val typeParameters: List<KSTypeParameter> by lazy {
+ descriptor.typeParameters.map { KSTypeParameterDescriptorImpl.getCached(it) }
+ }
+
+ override val declarations: Sequence<KSDeclaration> = emptySequence()
+
+ override val extensionReceiver: KSTypeReference? by lazy {
+ val extensionReceiver = descriptor.extensionReceiverParameter?.type
+ if (extensionReceiver != null) {
+ KSTypeReferenceDescriptorImpl.getCached(extensionReceiver, origin, this)
+ } else {
+ null
+ }
+ }
+
+ override val functionKind: FunctionKind by lazy {
+
+ when {
+ descriptor.dispatchReceiverParameter == null -> when {
+ descriptor.isFromJava -> FunctionKind.STATIC
+ else -> FunctionKind.TOP_LEVEL
+ }
+ !descriptor.name.isSpecial && !descriptor.name.asString().isEmpty() -> FunctionKind.MEMBER
+ descriptor is AnonymousFunctionDescriptor -> FunctionKind.ANONYMOUS
+ else -> throw IllegalStateException(
+ "Unable to resolve FunctionKind for ${descriptor.fqNameSafe}, $ExceptionMessage"
+ )
+ }
+ }
+
+ override val isAbstract: Boolean by lazy {
+ this.modifiers.contains(Modifier.ABSTRACT)
+ }
+
+ override val modifiers: Set<Modifier> by lazy {
+ val modifiers = mutableSetOf<Modifier>()
+ modifiers.addAll(descriptor.toKSModifiers())
+ modifiers.addAll(descriptor.toFunctionKSModifiers())
+
+ if (this.origin == Origin.JAVA_LIB) {
+ if (this.jvmAccessFlag and Opcodes.ACC_STRICT != 0)
+ modifiers.add(Modifier.JAVA_STRICT)
+ if (this.jvmAccessFlag and Opcodes.ACC_SYNCHRONIZED != 0)
+ modifiers.add(Modifier.JAVA_SYNCHRONIZED)
+ }
+
+ modifiers
+ }
+
+ override val parameters: List<KSValueParameter> by lazy {
+ descriptor.valueParameters.map { KSValueParameterDescriptorImpl.getCached(it, this) }
+ }
+
+ override val returnType: KSTypeReference? by lazy {
+ val returnType = descriptor.returnType
+ if (returnType == null) {
+ null
+ } else {
+ KSTypeReferenceDescriptorImpl.getCached(returnType, origin, this)
+ }
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitFunctionDeclaration(this, data)
+ }
+
+ override fun asMemberOf(containing: KSType): KSFunction =
+ ResolverImpl.instance!!.asMemberOf(this, containing)
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSNodeDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSNodeDescriptorImpl.kt
new file mode 100644
index 00000000..0c82f750
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSNodeDescriptorImpl.kt
@@ -0,0 +1,9 @@
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.NonExistLocation
+
+abstract class KSNodeDescriptorImpl(override val parent: KSNode?) : KSNode {
+ override val location: Location = NonExistLocation
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertyAccessorDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertyAccessorDescriptorImpl.kt
new file mode 100644
index 00000000..505bb569
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertyAccessorDescriptorImpl.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.toKSPropertyDeclaration
+import com.google.devtools.ksp.toFunctionKSModifiers
+import com.google.devtools.ksp.toKSModifiers
+import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
+
+abstract class KSPropertyAccessorDescriptorImpl(val descriptor: PropertyAccessorDescriptor) : KSPropertyAccessor {
+ override val origin: Origin by lazy {
+ when (receiver.origin) {
+ // if receiver is kotlin source, that means we are a synthetic where developer
+ // didn't declare an explicit accessor so we used the descriptor instead
+ Origin.KOTLIN -> Origin.SYNTHETIC
+ else -> descriptor.origin
+ }
+ }
+
+ override val receiver: KSPropertyDeclaration by lazy {
+ descriptor.correspondingProperty.toKSPropertyDeclaration()
+ }
+
+ override val parent: KSNode? by lazy {
+ receiver
+ }
+
+ override val location: Location
+ get() {
+ // if receiver is kotlin source, that means `this` is synthetic hence we want the property's location
+ // Otherwise, receiver is also from a .class file where the location will be NoLocation
+ return receiver.location
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ descriptor.annotations.asSequence().map { KSAnnotationDescriptorImpl.getCached(it, this) }.memoized()
+ }
+
+ override val modifiers: Set<Modifier> by lazy {
+ val modifiers = mutableSetOf<Modifier>()
+ modifiers.addAll(descriptor.toKSModifiers())
+ modifiers.addAll(descriptor.toFunctionKSModifiers())
+ modifiers
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertyDeclarationDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertyDeclarationDescriptorImpl.kt
new file mode 100644
index 00000000..ad9e52f3
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertyDeclarationDescriptorImpl.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.hasBackingFieldWithBinaryClassSupport
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.*
+import com.google.devtools.ksp.toKSModifiers
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.org.objectweb.asm.Opcodes
+
+class KSPropertyDeclarationDescriptorImpl private constructor(val descriptor: PropertyDescriptor) :
+ KSPropertyDeclaration,
+ KSDeclarationDescriptorImpl(descriptor),
+ KSExpectActual by KSExpectActualDescriptorImpl(descriptor) {
+ companion object : KSObjectCache<PropertyDescriptor, KSPropertyDeclarationDescriptorImpl>() {
+ fun getCached(descriptor: PropertyDescriptor) = cache.getOrPut(descriptor) {
+ KSPropertyDeclarationDescriptorImpl(descriptor)
+ }
+ }
+
+ override val extensionReceiver: KSTypeReference? by lazy {
+ if (descriptor.extensionReceiverParameter != null) {
+ KSTypeReferenceDescriptorImpl.getCached(descriptor.extensionReceiverParameter!!.type, origin, this)
+ } else {
+ null
+ }
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ // annotations on backing field will not visible in the property declaration so we query it directly to load
+ // its annotations as well.
+ val backingFieldAnnotations = descriptor.backingField?.annotations?.map {
+ KSAnnotationDescriptorImpl.getCached(it, this)
+ }.orEmpty()
+ (super.annotations + backingFieldAnnotations).memoized()
+ }
+
+ override val isMutable: Boolean by lazy {
+ descriptor.isVar
+ }
+
+ override val modifiers: Set<Modifier> by lazy {
+ val modifiers = mutableSetOf<Modifier>()
+ modifiers.addAll(descriptor.toKSModifiers())
+ if (descriptor.isConst) {
+ modifiers.add(Modifier.CONST)
+ }
+ if (descriptor.isLateInit) {
+ modifiers.add(Modifier.LATEINIT)
+ }
+
+ if (this.origin == Origin.JAVA_LIB) {
+ if (this.jvmAccessFlag and Opcodes.ACC_TRANSIENT != 0)
+ modifiers.add(Modifier.JAVA_TRANSIENT)
+ if (this.jvmAccessFlag and Opcodes.ACC_VOLATILE != 0)
+ modifiers.add(Modifier.JAVA_VOLATILE)
+ }
+
+ modifiers
+ }
+
+ override val setter: KSPropertySetter? by lazy {
+ if (descriptor.setter != null) {
+ KSPropertySetterDescriptorImpl.getCached(descriptor.setter as PropertySetterDescriptor)
+ } else {
+ null
+ }
+ }
+
+ override val getter: KSPropertyGetter? by lazy {
+ if (descriptor.getter != null) {
+ KSPropertyGetterDescriptorImpl.getCached(descriptor.getter as PropertyGetterDescriptor)
+ } else {
+ null
+ }
+ }
+
+ override val typeParameters: List<KSTypeParameter> by lazy {
+ descriptor.typeParameters.map { KSTypeParameterDescriptorImpl.getCached(it) }
+ }
+
+ override val type: KSTypeReference by lazy {
+ KSTypeReferenceDescriptorImpl.getCached(descriptor.type, origin, this)
+ }
+
+ override val hasBackingField: Boolean by lazy {
+ descriptor.hasBackingFieldWithBinaryClassSupport()
+ }
+
+ override fun findOverridee(): KSPropertyDeclaration? {
+ val propertyDescriptor = ResolverImpl.instance!!.resolvePropertyDeclaration(this)
+ return propertyDescriptor?.findClosestOverridee()?.toKSPropertyDeclaration()
+ }
+
+ override fun isDelegated(): Boolean {
+ return (descriptor as? PropertyDescriptor)?.delegateField != null
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertyDeclaration(this, data)
+ }
+
+ override fun asMemberOf(containing: KSType): KSType =
+ ResolverImpl.instance!!.asMemberOf(this, containing)
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertyGetterDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertyGetterDescriptorImpl.kt
new file mode 100644
index 00000000..a0951aad
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertyGetterDescriptorImpl.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.*
+import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor
+
+class KSPropertyGetterDescriptorImpl private constructor(descriptor: PropertyGetterDescriptor) :
+ KSPropertyAccessorDescriptorImpl(descriptor), KSPropertyGetter {
+ companion object : KSObjectCache<PropertyGetterDescriptor, KSPropertyGetterDescriptorImpl>() {
+ fun getCached(descriptor: PropertyGetterDescriptor) = cache.getOrPut(descriptor) {
+ KSPropertyGetterDescriptorImpl(descriptor)
+ }
+ }
+
+ override val returnType: KSTypeReference? by lazy {
+ if (descriptor.returnType != null) {
+ KSTypeReferenceDescriptorImpl.getCached(descriptor.returnType!!, origin, this)
+ } else {
+ null
+ }
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertyGetter(this, data)
+ }
+
+ override fun toString(): String {
+ return "$receiver.getter()"
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertySetterDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertySetterDescriptorImpl.kt
new file mode 100644
index 00000000..834089b0
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSPropertySetterDescriptorImpl.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.*
+import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor
+
+class KSPropertySetterDescriptorImpl private constructor(descriptor: PropertySetterDescriptor) :
+ KSPropertyAccessorDescriptorImpl(descriptor), KSPropertySetter {
+ companion object : KSObjectCache<PropertySetterDescriptor, KSPropertySetterDescriptorImpl>() {
+ fun getCached(descriptor: PropertySetterDescriptor) = cache.getOrPut(descriptor) {
+ KSPropertySetterDescriptorImpl(descriptor)
+ }
+ }
+
+ override val parameter: KSValueParameter by lazy {
+ descriptor.valueParameters.singleOrNull()?.let { KSValueParameterDescriptorImpl.getCached(it, this) }
+ ?: throw IllegalStateException("Failed to resolve property type")
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertySetter(this, data)
+ }
+
+ override fun toString(): String {
+ return "$receiver.setter()"
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeAliasDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeAliasDescriptorImpl.kt
new file mode 100644
index 00000000..29dc0613
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeAliasDescriptorImpl.kt
@@ -0,0 +1,38 @@
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.toKSModifiers
+import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
+
+class KSTypeAliasDescriptorImpl(descriptor: TypeAliasDescriptor) :
+ KSTypeAlias,
+ KSDeclarationDescriptorImpl(descriptor),
+ KSExpectActual by KSExpectActualDescriptorImpl(descriptor) {
+ companion object : KSObjectCache<TypeAliasDescriptor, KSTypeAliasDescriptorImpl>() {
+ fun getCached(descriptor: TypeAliasDescriptor) = KSTypeAliasDescriptorImpl.cache.getOrPut(descriptor) {
+ KSTypeAliasDescriptorImpl(descriptor)
+ }
+ }
+
+ override val name: KSName by lazy {
+ KSNameImpl.getCached(descriptor.name.asString())
+ }
+
+ override val modifiers: Set<Modifier> by lazy {
+ descriptor.toKSModifiers()
+ }
+
+ override val typeParameters: List<KSTypeParameter> by lazy {
+ descriptor.declaredTypeParameters.map { KSTypeParameterDescriptorImpl.getCached(it) }
+ }
+
+ override val type: KSTypeReference by lazy {
+ KSTypeReferenceDescriptorImpl.getCached(descriptor.underlyingType, origin, this)
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeAlias(this, data)
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeArgumentDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeArgumentDescriptorImpl.kt
new file mode 100644
index 00000000..5b76e27a
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeArgumentDescriptorImpl.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.IdKeyTriple
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.NonExistLocation
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.Variance
+import com.google.devtools.ksp.symbol.impl.kotlin.KSTypeArgumentImpl
+import org.jetbrains.kotlin.types.TypeProjection
+
+class KSTypeArgumentDescriptorImpl private constructor(
+ val descriptor: TypeProjection,
+ override val origin: Origin,
+ override val parent: KSNode?
+) : KSTypeArgumentImpl() {
+ companion object : KSObjectCache<IdKeyTriple<TypeProjection, Origin, KSNode?>, KSTypeArgumentDescriptorImpl>() {
+ fun getCached(descriptor: TypeProjection, origin: Origin, parent: KSNode?) = cache
+ .getOrPut(IdKeyTriple(descriptor, origin, parent)) {
+ KSTypeArgumentDescriptorImpl(descriptor, origin, parent)
+ }
+ }
+
+ override val location: Location = NonExistLocation
+
+ override val type: KSTypeReference by lazy {
+ KSTypeReferenceDescriptorImpl.getCached(descriptor.type, origin, if (parent != null) this else null)
+ }
+
+ override val variance: Variance by lazy {
+ if (descriptor.isStarProjection)
+ Variance.STAR
+ else {
+ when (descriptor.projectionKind) {
+ org.jetbrains.kotlin.types.Variance.IN_VARIANCE -> Variance.CONTRAVARIANT
+ org.jetbrains.kotlin.types.Variance.OUT_VARIANCE -> Variance.COVARIANT
+ else -> Variance.INVARIANT
+ }
+ }
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ descriptor.type.annotations.asSequence().map { KSAnnotationDescriptorImpl.getCached(it, this) }
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeParameterDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeParameterDescriptorImpl.kt
new file mode 100644
index 00000000..98de3b98
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeParameterDescriptorImpl.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.ExceptionMessage
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.kotlin.KSExpectActualNoImpl
+import com.google.devtools.ksp.toKSVariance
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.descriptors.PropertyDescriptor
+import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
+
+class KSTypeParameterDescriptorImpl private constructor(val descriptor: TypeParameterDescriptor) :
+ KSTypeParameter,
+ KSDeclarationDescriptorImpl(descriptor),
+ KSExpectActual by KSExpectActualNoImpl() {
+ companion object : KSObjectCache<TypeParameterDescriptor, KSTypeParameterDescriptorImpl>() {
+ fun getCached(descriptor: TypeParameterDescriptor) = cache.getOrPut(descriptor) {
+ KSTypeParameterDescriptorImpl(descriptor)
+ }
+ }
+
+ override val bounds: Sequence<KSTypeReference> by lazy {
+ descriptor.upperBounds.asSequence().map { KSTypeReferenceDescriptorImpl.getCached(it, origin, this) }
+ }
+
+ override val typeParameters: List<KSTypeParameter> = emptyList()
+
+ override val parentDeclaration: KSDeclaration? by lazy {
+ when (val parent = descriptor.containingDeclaration) {
+ is ClassDescriptor -> KSClassDeclarationDescriptorImpl.getCached(parent)
+ is FunctionDescriptor -> KSFunctionDeclarationDescriptorImpl.getCached(parent)
+ is PropertyDescriptor -> KSPropertyDeclarationDescriptorImpl.getCached(parent)
+ else -> throw IllegalStateException(
+ "Unexpected containing declaration for ${descriptor.fqNameSafe}, $ExceptionMessage"
+ )
+ }
+ }
+
+ override val modifiers: Set<Modifier> = emptySet()
+
+ override val isReified: Boolean by lazy {
+ descriptor.isReified
+ }
+
+ override val name: KSName by lazy {
+ KSNameImpl.getCached(descriptor.name.asString())
+ }
+
+ override val variance: Variance = descriptor.variance.toKSVariance()
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeParameter(this, data)
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeReferenceDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeReferenceDescriptorImpl.kt
new file mode 100644
index 00000000..91f68fa4
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSTypeReferenceDescriptorImpl.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.IdKeyTriple
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSReferenceElement
+import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.symbol.NonExistLocation
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.impl.kotlin.getKSTypeCached
+import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype
+import org.jetbrains.kotlin.types.AbbreviatedType
+import org.jetbrains.kotlin.types.KotlinType
+
+class KSTypeReferenceDescriptorImpl private constructor(
+ val kotlinType: KotlinType,
+ override val origin: Origin,
+ override val parent: KSNode?
+) : KSTypeReference {
+ companion object : KSObjectCache<IdKeyTriple<KotlinType, Origin, KSNode?>, KSTypeReferenceDescriptorImpl>() {
+ fun getCached(kotlinType: KotlinType, origin: Origin, parent: KSNode?) = cache
+ .getOrPut(IdKeyTriple(kotlinType, origin, parent)) {
+ KSTypeReferenceDescriptorImpl(kotlinType, origin, parent)
+ }
+ }
+
+ private fun KotlinType.findAlias(): KotlinType =
+ (kotlinType as? AbbreviatedType)?.abbreviation ?: this
+
+ override val location: Location = NonExistLocation
+
+ override val element: KSReferenceElement by lazy {
+ KSClassifierReferenceDescriptorImpl.getCached(kotlinType.findAlias(), origin, this)
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ kotlinType.annotations.asSequence().map { KSAnnotationDescriptorImpl.getCached(it, this) }.memoized()
+ }
+
+ override val modifiers: Set<Modifier> by lazy {
+ if (kotlinType.isSuspendFunctionTypeOrSubtype) {
+ setOf(Modifier.SUSPEND)
+ } else {
+ emptySet<Modifier>()
+ }
+ }
+
+ override fun resolve(): KSType {
+ return getKSTypeCached(kotlinType)
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeReference(this, data)
+ }
+
+ override fun toString(): String {
+ return element.toString()
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSValueParameterDescriptorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSValueParameterDescriptorImpl.kt
new file mode 100644
index 00000000..29f53a45
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/binary/KSValueParameterDescriptorImpl.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.binary
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
+import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
+import org.jetbrains.kotlin.resolve.calls.components.isVararg
+
+class KSValueParameterDescriptorImpl private constructor(
+ val descriptor: ValueParameterDescriptor,
+ override val parent: KSNode?
+) : KSValueParameter {
+ companion object : KSObjectCache<Pair<ValueParameterDescriptor, KSNode?>, KSValueParameterDescriptorImpl>() {
+ fun getCached(descriptor: ValueParameterDescriptor, parent: KSNode?) = cache
+ .getOrPut(Pair(descriptor, parent)) { KSValueParameterDescriptorImpl(descriptor, parent) }
+ }
+
+ override val origin by lazy {
+ descriptor.origin
+ }
+
+ override val location: Location = NonExistLocation
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ descriptor.annotations.asSequence().map { KSAnnotationDescriptorImpl.getCached(it, this) }
+ }
+
+ override val isCrossInline: Boolean = descriptor.isCrossinline
+
+ override val isNoInline: Boolean = descriptor.isNoinline
+
+ override val isVararg: Boolean = descriptor.isVararg
+
+ override val isVal: Boolean = !descriptor.isVar
+
+ override val isVar: Boolean = descriptor.isVar
+
+ override val name: KSName? by lazy {
+ KSNameImpl.getCached(descriptor.name.asString())
+ }
+
+ override val type: KSTypeReference by lazy {
+ // Descriptor wraps vararg with Array<>, to align with the actual behavior in source.
+ if (isVararg) {
+ KSTypeReferenceDescriptorImpl.getCached(descriptor.varargElementType!!, origin, this)
+ } else {
+ KSTypeReferenceDescriptorImpl.getCached(descriptor.type, origin, this)
+ }
+ }
+
+ override val hasDefault: Boolean = descriptor.hasDefaultValue()
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitValueParameter(this, data)
+ }
+
+ override fun toString(): String {
+ return name?.asString() ?: "_"
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSAnnotationJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSAnnotationJavaImpl.kt
new file mode 100644
index 00000000..f6ae397b
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSAnnotationJavaImpl.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.binary.getAbsentDefaultArguments
+import com.google.devtools.ksp.symbol.impl.binary.getDefaultConstructorArguments
+import com.google.devtools.ksp.symbol.impl.kotlin.KSTypeImpl
+import com.google.devtools.ksp.symbol.impl.toLocation
+import com.intellij.lang.jvm.JvmClassKind
+import com.intellij.psi.*
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+
+class KSAnnotationJavaImpl private constructor(val psi: PsiAnnotation) : KSAnnotation {
+ companion object : KSObjectCache<PsiAnnotation, KSAnnotationJavaImpl>() {
+ fun getCached(psi: PsiAnnotation) = cache.getOrPut(psi) { KSAnnotationJavaImpl(psi) }
+ }
+
+ override val origin = Origin.JAVA
+
+ override val location: Location by lazy {
+ psi.toLocation()
+ }
+
+ override val parent: KSNode? by lazy {
+ var parentPsi = psi.parent
+ while (true) {
+ when (parentPsi) {
+ null, is PsiJavaFile, is PsiClass, is PsiMethod, is PsiParameter, is PsiTypeParameter, is PsiType ->
+ break
+ else -> parentPsi = parentPsi.parent
+ }
+ }
+ when (parentPsi) {
+ is PsiJavaFile -> KSFileJavaImpl.getCached(parentPsi)
+ is PsiClass -> KSClassDeclarationJavaImpl.getCached(parentPsi)
+ is PsiMethod -> KSFunctionDeclarationJavaImpl.getCached(parentPsi)
+ is PsiParameter -> KSValueParameterJavaImpl.getCached(parentPsi)
+ is PsiTypeParameter -> KSTypeParameterJavaImpl.getCached(parentPsi)
+ is PsiType ->
+ if (parentPsi.parent is PsiClassType) KSTypeArgumentJavaImpl.getCached(parentPsi, this)
+ else KSTypeReferenceJavaImpl.getCached(parentPsi, this)
+ else -> null
+ }
+ }
+
+ override val annotationType: KSTypeReference by lazy {
+ KSTypeReferenceLiteJavaImpl.getCached(psi, this)
+ }
+
+ override val arguments: List<KSValueArgument> by lazy {
+ val annotationConstructor = (
+ (annotationType.resolve() as? KSTypeImpl)?.kotlinType?.constructor
+ ?.declarationDescriptor as? ClassDescriptor
+ )?.constructors?.single()
+ val presentValueArguments = psi.parameterList.attributes
+ .mapIndexed { index, it ->
+ // use the name in the attribute if it is explicitly specified, otherwise, fall back to index.
+ val name = it.name ?: annotationConstructor?.valueParameters?.getOrNull(index)?.name?.asString()
+ val value = it.value
+ val calculatedValue: Any? = if (value is PsiArrayInitializerMemberValue) {
+ value.initializers.map {
+ calcValue(it)
+ }
+ } else {
+ calcValue(it.value)
+ }
+ KSValueArgumentJavaImpl.getCached(
+ name = name?.let(KSNameImpl::getCached),
+ value = calculatedValue,
+ this
+ )
+ }
+ val presentValueArgumentNames = presentValueArguments.map { it.name?.asString() ?: "" }
+ val argumentsFromDefault = annotationConstructor?.let {
+ it.getAbsentDefaultArguments(presentValueArgumentNames, this)
+ } ?: emptyList()
+ presentValueArguments.plus(argumentsFromDefault)
+ }
+
+ override val defaultArguments: List<KSValueArgument> by lazy {
+ val kotlinType = (annotationType.resolve() as? KSTypeImpl)?.kotlinType
+ kotlinType?.getDefaultConstructorArguments(emptyList(), this) ?: emptyList()
+ }
+
+ private fun calcValue(value: PsiAnnotationMemberValue?): Any? {
+ if (value is PsiAnnotation) {
+ return getCached(value)
+ }
+ val result = when (value) {
+ is PsiReference -> value.resolve()?.let { resolved ->
+ JavaPsiFacade.getInstance(value.project).constantEvaluationHelper.computeConstantExpression(value)
+ ?: resolved
+ }
+ else -> value?.let {
+ JavaPsiFacade.getInstance(value.project).constantEvaluationHelper.computeConstantExpression(value)
+ }
+ }
+ return when (result) {
+ is PsiType -> {
+ ResolverImpl.instance!!.resolveJavaTypeInAnnotations(result)
+ }
+ is PsiLiteralValue -> {
+ result.value
+ }
+ is PsiField -> {
+ // manually handle enums as constant expression evaluator does not seem to be resolving them.
+ val containingClass = result.containingClass
+ if (containingClass?.classKind == JvmClassKind.ENUM) {
+ // this is an enum entry
+ containingClass.qualifiedName?.let {
+ ResolverImpl.instance!!.getClassDeclarationByName(it)
+ }?.declarations?.find {
+ it is KSClassDeclaration && it.classKind == ClassKind.ENUM_ENTRY &&
+ it.simpleName.asString() == result.name
+ }?.let { (it as KSClassDeclaration).asStarProjectedType() }
+ ?.let {
+ return it
+ }
+ } else {
+ null
+ }
+ }
+ else -> result
+ }
+ }
+
+ override val shortName: KSName by lazy {
+ KSNameImpl.getCached(psi.qualifiedName!!.split(".").last())
+ }
+
+ override val useSiteTarget: AnnotationUseSiteTarget? = null
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitAnnotation(this, data)
+ }
+
+ override fun toString(): String {
+ return "@${shortName.asString()}"
+ }
+}
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
new file mode 100644
index 00000000..05f017be
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaEnumEntryImpl.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.*
+import com.google.devtools.ksp.symbol.impl.binary.getAllFunctions
+import com.google.devtools.ksp.symbol.impl.binary.getAllProperties
+import com.google.devtools.ksp.symbol.impl.kotlin.KSErrorType
+import com.google.devtools.ksp.symbol.impl.kotlin.KSExpectActualNoImpl
+import com.google.devtools.ksp.symbol.impl.kotlin.getKSTypeCached
+import com.google.devtools.ksp.toKSModifiers
+import com.intellij.psi.PsiEnumConstant
+import com.intellij.psi.PsiJavaFile
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+
+class KSClassDeclarationJavaEnumEntryImpl private constructor(val psi: PsiEnumConstant) :
+ KSClassDeclaration,
+ KSDeclarationJavaImpl(psi),
+ KSExpectActual by KSExpectActualNoImpl() {
+ companion object : KSObjectCache<PsiEnumConstant, KSClassDeclarationJavaEnumEntryImpl>() {
+ fun getCached(psi: PsiEnumConstant) = cache.getOrPut(psi) { KSClassDeclarationJavaEnumEntryImpl(psi) }
+ }
+
+ override val origin = Origin.JAVA
+
+ override val location: Location by lazy {
+ psi.toLocation()
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ psi.annotations.asSequence().map { KSAnnotationJavaImpl.getCached(it) }
+ }
+
+ override val classKind: ClassKind = ClassKind.ENUM_ENTRY
+
+ override val containingFile: KSFile? by lazy {
+ KSFileJavaImpl.getCached(psi.containingFile as PsiJavaFile)
+ }
+
+ override val isCompanionObject = false
+
+ override fun getSealedSubclasses(): Sequence<KSClassDeclaration> = emptySequence()
+
+ private val descriptor: ClassDescriptor? by lazy {
+ ResolverImpl.instance!!.resolveJavaDeclaration(psi) as ClassDescriptor
+ }
+
+ override fun getAllFunctions(): Sequence<KSFunctionDeclaration> =
+ descriptor?.getAllFunctions() ?: emptySequence()
+
+ override fun getAllProperties(): Sequence<KSPropertyDeclaration> =
+ descriptor?.getAllProperties() ?: emptySequence()
+
+ override val declarations: Sequence<KSDeclaration> = emptySequence()
+
+ override val modifiers: Set<Modifier> by lazy {
+ psi.toKSModifiers()
+ }
+
+ override val parentDeclaration: KSDeclaration? by lazy {
+ psi.findParentDeclaration()
+ }
+
+ override val primaryConstructor: KSFunctionDeclaration? = null
+
+ override val qualifiedName: KSName by lazy {
+ KSNameImpl.getCached("${parentDeclaration!!.qualifiedName!!.asString()}.${psi.name}")
+ }
+
+ override val simpleName: KSName by lazy {
+ KSNameImpl.getCached(psi.name)
+ }
+
+ override val superTypes: Sequence<KSTypeReference> = emptySequence()
+
+ override val typeParameters: List<KSTypeParameter> = emptyList()
+
+ // Enum can't have type parameters.
+ override fun asType(typeArguments: List<KSTypeArgument>): KSType {
+ if (typeArguments.isNotEmpty())
+ return KSErrorType
+ return asStarProjectedType()
+ }
+
+ override fun asStarProjectedType(): KSType {
+ return getKSTypeCached(descriptor!!.defaultType)
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitClassDeclaration(this, data)
+ }
+}
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
new file mode 100644
index 00000000..f12933f8
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassDeclarationJavaImpl.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.isConstructor
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.processing.impl.workaroundForNested
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.*
+import com.google.devtools.ksp.symbol.impl.binary.getAllFunctions
+import com.google.devtools.ksp.symbol.impl.binary.getAllProperties
+import com.google.devtools.ksp.symbol.impl.kotlin.KSErrorType
+import com.google.devtools.ksp.symbol.impl.kotlin.KSExpectActualNoImpl
+import com.google.devtools.ksp.symbol.impl.kotlin.getKSTypeCached
+import com.google.devtools.ksp.symbol.impl.replaceTypeArguments
+import com.google.devtools.ksp.symbol.impl.synthetic.KSConstructorSyntheticImpl
+import com.google.devtools.ksp.toKSModifiers
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiEnumConstant
+import com.intellij.psi.PsiJavaFile
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
+import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
+
+class KSClassDeclarationJavaImpl private constructor(val psi: PsiClass) :
+ KSClassDeclaration,
+ KSDeclarationJavaImpl(psi),
+ KSExpectActual by KSExpectActualNoImpl() {
+ companion object : KSObjectCache<PsiClass, KSClassDeclarationJavaImpl>() {
+ fun getCached(psi: PsiClass) = cache.getOrPut(psi) { KSClassDeclarationJavaImpl(psi) }
+ }
+
+ override val origin = Origin.JAVA
+
+ override val location: Location by lazy {
+ psi.toLocation()
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ psi.annotations.asSequence().map { KSAnnotationJavaImpl.getCached(it) }.memoized()
+ }
+
+ override val classKind: ClassKind by lazy {
+ when {
+ psi.isAnnotationType -> ClassKind.ANNOTATION_CLASS
+ psi.isInterface -> ClassKind.INTERFACE
+ psi.isEnum -> ClassKind.ENUM_CLASS
+ else -> ClassKind.CLASS
+ }
+ }
+
+ override val containingFile: KSFile? by lazy {
+ KSFileJavaImpl.getCached(psi.containingFile as PsiJavaFile)
+ }
+
+ override val isCompanionObject = false
+
+ // Could the resolution ever fail?
+ private val descriptor: ClassDescriptor? by lazy {
+ ResolverImpl.instance!!.moduleClassResolver.resolveClass(JavaClassImpl(psi).apply { workaroundForNested() })
+ }
+
+ // TODO in 1.5 + jvmTarget 15, will we return Java permitted types?
+ override fun getSealedSubclasses(): Sequence<KSClassDeclaration> = emptySequence()
+
+ override fun getAllFunctions(): Sequence<KSFunctionDeclaration> =
+ descriptor?.getAllFunctions() ?: emptySequence()
+
+ override fun getAllProperties(): Sequence<KSPropertyDeclaration> =
+ descriptor?.getAllProperties() ?: emptySequence()
+
+ override val declarations: Sequence<KSDeclaration> by lazy {
+ val allDeclarations = (
+ psi.fields.asSequence().map {
+ when (it) {
+ is PsiEnumConstant -> KSClassDeclarationJavaEnumEntryImpl.getCached(it)
+ else -> KSPropertyDeclarationJavaImpl.getCached(it)
+ }
+ } +
+ psi.innerClasses.map { KSClassDeclarationJavaImpl.getCached(it) } +
+ psi.constructors.map { KSFunctionDeclarationJavaImpl.getCached(it) } +
+ psi.methods.map { KSFunctionDeclarationJavaImpl.getCached(it) }
+ )
+ .distinct()
+ // java annotation classes are interface. they get a constructor in .class
+ // hence they should get one here.
+ if (classKind == ClassKind.ANNOTATION_CLASS || !psi.isInterface) {
+ val hasConstructor = allDeclarations.any {
+ it is KSFunctionDeclaration && it.isConstructor()
+ }
+ if (hasConstructor) {
+ allDeclarations.memoized()
+ } else {
+ (allDeclarations + KSConstructorSyntheticImpl.getCached(this)).memoized()
+ }
+ } else {
+ allDeclarations.memoized()
+ }
+ }
+
+ override val modifiers: Set<Modifier> by lazy {
+ val modifiers = mutableSetOf<Modifier>()
+ modifiers.addAll(psi.toKSModifiers())
+ if (psi.isAnnotationType) {
+ modifiers.add(Modifier.ANNOTATION)
+ }
+ if (psi.isEnum) {
+ modifiers.add(Modifier.ENUM)
+ }
+ modifiers
+ }
+
+ override val primaryConstructor: KSFunctionDeclaration? = null
+
+ override val qualifiedName: KSName by lazy {
+ KSNameImpl.getCached(psi.qualifiedName!!)
+ }
+
+ override val simpleName: KSName by lazy {
+ KSNameImpl.getCached(psi.name!!)
+ }
+
+ override val superTypes: Sequence<KSTypeReference> by lazy {
+ val adjusted = if (!psi.isInterface && psi.superTypes.size > 1) {
+ psi.superTypes.filterNot {
+ it.className == "Object" && it.canonicalText == "java.lang.Object"
+ }
+ } else {
+ psi.superTypes.toList()
+ }
+ adjusted.asSequence().map { KSTypeReferenceJavaImpl.getCached(it, this) }.memoized()
+ }
+
+ override val typeParameters: List<KSTypeParameter> by lazy {
+ psi.typeParameters.map { KSTypeParameterJavaImpl.getCached(it) }
+ }
+
+ override fun asType(typeArguments: List<KSTypeArgument>): KSType {
+ return descriptor?.let {
+ it.defaultType.replaceTypeArguments(typeArguments)?.let {
+ getKSTypeCached(it, typeArguments)
+ }
+ } ?: KSErrorType
+ }
+
+ override fun asStarProjectedType(): KSType {
+ return descriptor?.let {
+ getKSTypeCached(it.defaultType.replaceArgumentsWithStarProjections())
+ } ?: KSErrorType
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitClassDeclaration(this, data)
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassifierReferenceJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassifierReferenceJavaImpl.kt
new file mode 100644
index 00000000..748a0b93
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassifierReferenceJavaImpl.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.getInstanceForCurrentRound
+import com.google.devtools.ksp.symbol.impl.toLocation
+import com.intellij.psi.PsiClassType
+import com.intellij.psi.PsiJavaCodeReferenceElement
+import com.intellij.psi.impl.source.PsiClassReferenceType
+
+class KSClassifierReferenceJavaImpl private constructor(
+ val psi: PsiClassType,
+ override val parent: KSNode
+) : KSClassifierReference {
+ companion object : KSObjectCache<Pair<PsiClassType, KSNode>, KSClassifierReferenceJavaImpl>() {
+ fun getCached(psi: PsiClassType, parent: KSNode): KSClassifierReferenceJavaImpl {
+ val curParent = getInstanceForCurrentRound(parent) as KSTypeReference
+ return cache.getOrPut(Pair(psi, curParent)) { KSClassifierReferenceJavaImpl(psi, curParent) }
+ }
+ }
+
+ override val origin = Origin.JAVA
+
+ override val location: Location by lazy {
+ (psi as? PsiJavaCodeReferenceElement)?.toLocation() ?: NonExistLocation
+ }
+
+ override val qualifier: KSClassifierReference? by lazy {
+ val qualifierReference = (psi as? PsiClassReferenceType)?.reference?.qualifier as? PsiJavaCodeReferenceElement
+ ?: return@lazy null
+ val qualifierType = PsiClassReferenceType(qualifierReference, psi.languageLevel)
+ getCached(qualifierType, parent)
+ }
+
+ // PsiClassType.parameters is semantically argument
+ override val typeArguments: List<KSTypeArgument> by lazy {
+ psi.parameters.map { KSTypeArgumentJavaImpl.getCached(it, this) }
+ }
+
+ override fun referencedName(): String {
+ return psi.className + if (psi.parameterCount > 0) "<${
+ psi.parameters.joinToString(", ") {
+ it.presentableText
+ }
+ }>" else ""
+ }
+
+ override fun toString() = referencedName()
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassifierReferenceLiteImplForJava.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassifierReferenceLiteImplForJava.kt
new file mode 100644
index 00000000..3d2a0624
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSClassifierReferenceLiteImplForJava.kt
@@ -0,0 +1,50 @@
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.ExceptionMessage
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.KSClassifierReference
+import com.google.devtools.ksp.symbol.KSTypeArgument
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.NonExistLocation
+import com.google.devtools.ksp.symbol.Origin
+import com.intellij.psi.PsiAnnotation
+import com.intellij.psi.PsiMethod
+
+class KSClassifierReferenceLiteImplForJava(
+ override val parent: KSTypeReferenceLiteJavaImpl,
+ private val name: String?
+) : KSClassifierReference {
+ companion object : KSObjectCache<Pair<KSTypeReferenceLiteJavaImpl, String?>, KSClassifierReference>() {
+ fun getCached(parent: KSTypeReferenceLiteJavaImpl, name: String? = null) =
+ KSClassifierReferenceLiteImplForJava.cache
+ .getOrPut(Pair(parent, name)) { KSClassifierReferenceLiteImplForJava(parent, name) }
+ }
+ override val qualifier: KSClassifierReference? by lazy {
+ val referencedName = referencedName()
+ if (referencedName.lastIndexOf('.') == -1) {
+ null
+ } else {
+ getCached(parent, referencedName.substringBeforeLast('.'))
+ }
+ }
+
+ override fun referencedName(): String {
+ return name ?: when (parent.psiElement) {
+ is PsiAnnotation -> parent.psiElement.nameReferenceElement?.text ?: "<ERROR>"
+ is PsiMethod -> parent.psiElement.name
+ else -> throw IllegalStateException(
+ "Unexpected psi type in KSTypeReferenceLiteJavaImpl: ${parent.psiElement.javaClass}, $ExceptionMessage"
+ )
+ }
+ }
+
+ override val typeArguments: List<KSTypeArgument> = emptyList()
+
+ override val origin: Origin = Origin.JAVA
+
+ override val location: Location = NonExistLocation
+
+ override fun toString(): String {
+ return referencedName()
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSDeclarationJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSDeclarationJavaImpl.kt
new file mode 100644
index 00000000..3609a5a3
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSDeclarationJavaImpl.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.getDocString
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSName
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.impl.findParentAnnotated
+import com.google.devtools.ksp.symbol.impl.findParentDeclaration
+import com.intellij.psi.PsiElement
+
+abstract class KSDeclarationJavaImpl(private val psi: PsiElement) : KSDeclaration {
+ override val packageName: KSName by lazy {
+ this.containingFile!!.packageName
+ }
+
+ override fun toString(): String {
+ return this.simpleName.asString()
+ }
+
+ override val docString by lazy {
+ psi.getDocString()
+ }
+
+ override val parentDeclaration: KSDeclaration? by lazy {
+ psi.findParentDeclaration()
+ }
+
+ override val parent: KSNode? by lazy {
+ psi.findParentAnnotated()
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSFileJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSFileJavaImpl.kt
new file mode 100644
index 00000000..e49eea06
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSFileJavaImpl.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.toLocation
+import com.intellij.psi.PsiJavaFile
+
+class KSFileJavaImpl private constructor(val psi: PsiJavaFile) : KSFile {
+ companion object : KSObjectCache<PsiJavaFile, KSFileJavaImpl>() {
+ fun getCached(psi: PsiJavaFile) = cache.getOrPut(psi) { KSFileJavaImpl(psi) }
+ }
+
+ override val origin = Origin.JAVA
+
+ override val location: Location by lazy {
+ psi.toLocation()
+ }
+ override val parent: KSNode? = null
+
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override val declarations: Sequence<KSDeclaration> by lazy {
+ psi.classes.asSequence().map { KSClassDeclarationJavaImpl.getCached(it) }.memoized()
+ }
+
+ override val fileName: String by lazy {
+ psi.name
+ }
+
+ override val filePath: String by lazy {
+ psi.virtualFile.path
+ }
+
+ override val packageName: KSName = KSNameImpl.getCached(psi.packageName)
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitFile(this, data)
+ }
+
+ override fun toString(): String {
+ return "File: ${this.fileName}"
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSFunctionDeclarationJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSFunctionDeclarationJavaImpl.kt
new file mode 100644
index 00000000..1513fffc
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSFunctionDeclarationJavaImpl.kt
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.*
+import com.google.devtools.ksp.symbol.impl.kotlin.KSExpectActualNoImpl
+import com.google.devtools.ksp.toKSModifiers
+import com.intellij.lang.jvm.JvmModifier
+import com.intellij.psi.PsiJavaFile
+import com.intellij.psi.PsiMethod
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+
+class KSFunctionDeclarationJavaImpl private constructor(val psi: PsiMethod) :
+ KSFunctionDeclaration,
+ KSDeclarationJavaImpl(psi),
+ KSExpectActual by KSExpectActualNoImpl() {
+ companion object : KSObjectCache<PsiMethod, KSFunctionDeclarationJavaImpl>() {
+ fun getCached(psi: PsiMethod) = cache.getOrPut(psi) { KSFunctionDeclarationJavaImpl(psi) }
+ }
+
+ override val origin = Origin.JAVA
+
+ override val location: Location by lazy {
+ psi.toLocation()
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ psi.annotations.asSequence().map { KSAnnotationJavaImpl.getCached(it) }.memoized()
+ }
+
+ override val containingFile: KSFile? by lazy {
+ KSFileJavaImpl.getCached(psi.containingFile as PsiJavaFile)
+ }
+
+ override fun findOverridee(): KSDeclaration? {
+ val descriptor = ResolverImpl.instance!!.resolveFunctionDeclaration(this)
+ return (descriptor as? FunctionDescriptor)?.findClosestOverridee()?.toKSDeclaration()
+ }
+
+ override val declarations: Sequence<KSDeclaration> = emptySequence()
+
+ override val extensionReceiver: KSTypeReference? = null
+
+ override val functionKind: FunctionKind = when {
+ psi.hasModifier(JvmModifier.STATIC) -> FunctionKind.STATIC
+ else -> FunctionKind.MEMBER
+ }
+
+ override val isAbstract: Boolean by lazy {
+ this.modifiers.contains(Modifier.ABSTRACT) ||
+ (
+ (this.parentDeclaration as? KSClassDeclaration)?.classKind == ClassKind.INTERFACE &&
+ !this.modifiers.contains(Modifier.JAVA_DEFAULT) && functionKind != FunctionKind.STATIC
+ )
+ }
+
+ override val modifiers: Set<Modifier> by lazy {
+ psi.toKSModifiers()
+ }
+
+ override val parameters: List<KSValueParameter> by lazy {
+ psi.parameterList.parameters.map { KSValueParameterJavaImpl.getCached(it) }
+ }
+
+ override val parentDeclaration: KSDeclaration? by lazy {
+ psi.findParentDeclaration()
+ }
+
+ override val qualifiedName: KSName by lazy {
+ KSNameImpl.getCached("${parentDeclaration?.qualifiedName?.asString()}.${this.simpleName.asString()}")
+ }
+
+ override val returnType: KSTypeReference? by lazy {
+ when {
+ psi.returnType != null -> {
+ KSTypeReferenceJavaImpl.getCached(psi.returnType!!, this)
+ }
+ psi.isConstructor -> {
+ KSTypeReferenceLiteJavaImpl.getCached(psi, this)
+ }
+ else -> {
+ null
+ }
+ }
+ }
+
+ override val simpleName: KSName by lazy {
+ if (psi.isConstructor) {
+ KSNameImpl.getCached("<init>")
+ } else {
+ KSNameImpl.getCached(psi.name)
+ }
+ }
+
+ override val typeParameters: List<KSTypeParameter> by lazy {
+ psi.typeParameters.map { KSTypeParameterJavaImpl.getCached(it) }
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitFunctionDeclaration(this, data)
+ }
+
+ override fun asMemberOf(containing: KSType): KSFunction =
+ ResolverImpl.instance!!.asMemberOf(this, containing)
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSNodeJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSNodeJavaImpl.kt
new file mode 100644
index 00000000..860fb5fa
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSNodeJavaImpl.kt
@@ -0,0 +1,12 @@
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.impl.toLocation
+import com.intellij.psi.PsiElement
+
+abstract class KSNodeJavaImpl(private val psi: PsiElement, override val parent: KSNode?) : KSNode {
+ override val location: Location by lazy {
+ psi.toLocation()
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSPropertyDeclarationJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSPropertyDeclarationJavaImpl.kt
new file mode 100644
index 00000000..57ff5941
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSPropertyDeclarationJavaImpl.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.*
+import com.google.devtools.ksp.symbol.impl.kotlin.KSExpectActualNoImpl
+import com.google.devtools.ksp.toKSModifiers
+import com.intellij.psi.PsiField
+import com.intellij.psi.PsiJavaFile
+
+class KSPropertyDeclarationJavaImpl private constructor(val psi: PsiField) :
+ KSPropertyDeclaration,
+ KSDeclarationJavaImpl(psi),
+ KSExpectActual by KSExpectActualNoImpl() {
+ companion object : KSObjectCache<PsiField, KSPropertyDeclarationJavaImpl>() {
+ fun getCached(psi: PsiField) = cache.getOrPut(psi) { KSPropertyDeclarationJavaImpl(psi) }
+ }
+
+ override val origin = Origin.JAVA
+
+ override val location: Location by lazy {
+ psi.toLocation()
+ }
+
+ override val isMutable: Boolean
+ get() = !modifiers.contains(Modifier.FINAL)
+
+ override val hasBackingField: Boolean
+ get() = true
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ psi.annotations.asSequence().map { KSAnnotationJavaImpl.getCached(it) }.memoized()
+ }
+
+ override val containingFile: KSFile? by lazy {
+ KSFileJavaImpl.getCached(psi.containingFile as PsiJavaFile)
+ }
+
+ override val extensionReceiver: KSTypeReference? = null
+
+ override val getter: KSPropertyGetter? = null
+
+ override val setter: KSPropertySetter? = null
+
+ override val modifiers: Set<Modifier> by lazy {
+ psi.toKSModifiers()
+ }
+
+ override val parentDeclaration: KSDeclaration? by lazy {
+ psi.findParentDeclaration()
+ }
+
+ override val qualifiedName: KSName by lazy {
+ KSNameImpl.getCached("${parentDeclaration?.qualifiedName?.asString()}.${this.simpleName.asString()}")
+ }
+
+ override val simpleName: KSName by lazy {
+ KSNameImpl.getCached(psi.name)
+ }
+
+ override val typeParameters: List<KSTypeParameter> = emptyList()
+
+ override val type: KSTypeReference by lazy {
+ KSTypeReferenceJavaImpl.getCached(psi.type, this)
+ }
+
+ override fun findOverridee(): KSPropertyDeclaration? {
+ return null
+ }
+
+ override fun isDelegated(): Boolean {
+ return false
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertyDeclaration(this, data)
+ }
+
+ override fun asMemberOf(containing: KSType): KSType =
+ ResolverImpl.instance!!.asMemberOf(this, containing)
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeArgumentJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeArgumentJavaImpl.kt
new file mode 100644
index 00000000..211cf4c8
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeArgumentJavaImpl.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.kotlin.KSTypeArgumentImpl
+import com.google.devtools.ksp.symbol.impl.toLocation
+import com.intellij.psi.PsiType
+import com.intellij.psi.PsiWildcardType
+import com.intellij.psi.impl.source.PsiClassReferenceType
+
+class KSTypeArgumentJavaImpl private constructor(
+ val psi: PsiType,
+ override val parent: KSNode?
+) : KSTypeArgumentImpl() {
+ companion object : KSObjectCache<PsiType, KSTypeArgumentJavaImpl>() {
+ fun getCached(psi: PsiType, parent: KSNode?) = cache.getOrPut(psi) { KSTypeArgumentJavaImpl(psi, parent) }
+ }
+
+ override val origin = Origin.JAVA
+
+ override val location: Location by lazy {
+ (psi as? PsiClassReferenceType)?.reference?.toLocation() ?: NonExistLocation
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ psi.annotations.asSequence().map { KSAnnotationJavaImpl.getCached(it) }.memoized()
+ }
+
+ // Could be unbounded, need to model unbdouned type argument.
+ override val type: KSTypeReference? by lazy {
+ KSTypeReferenceJavaImpl.getCached(psi, this)
+ }
+
+ override val variance: Variance by lazy {
+ if (psi is PsiWildcardType) {
+ when {
+ psi.isExtends -> Variance.COVARIANT
+ psi.isSuper -> Variance.CONTRAVARIANT
+ psi.bound == null -> Variance.STAR
+ else -> Variance.INVARIANT
+ }
+ } else {
+ Variance.INVARIANT
+ }
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeParameterJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeParameterJavaImpl.kt
new file mode 100644
index 00000000..e3c41286
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeParameterJavaImpl.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.findParentDeclaration
+import com.google.devtools.ksp.symbol.impl.kotlin.KSExpectActualNoImpl
+import com.google.devtools.ksp.symbol.impl.toLocation
+import com.intellij.psi.PsiJavaFile
+import com.intellij.psi.PsiTypeParameter
+
+class KSTypeParameterJavaImpl private constructor(val psi: PsiTypeParameter) :
+ KSTypeParameter,
+ KSDeclarationJavaImpl(psi),
+ KSExpectActual by KSExpectActualNoImpl() {
+ companion object : KSObjectCache<PsiTypeParameter, KSTypeParameterJavaImpl>() {
+ fun getCached(psi: PsiTypeParameter) = cache.getOrPut(psi) { KSTypeParameterJavaImpl(psi) }
+ }
+
+ override val origin = Origin.JAVA
+
+ override val location: Location by lazy {
+ psi.toLocation()
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ psi.annotations.asSequence().map { KSAnnotationJavaImpl.getCached(it) }.memoized()
+ }
+
+ override val bounds: Sequence<KSTypeReference> by lazy {
+ psi.extendsListTypes.asSequence().map { KSTypeReferenceJavaImpl.getCached(it, this) }.memoized()
+ }
+ override val simpleName: KSName by lazy {
+ KSNameImpl.getCached(psi.name ?: "_")
+ }
+
+ override val qualifiedName: KSName? by lazy {
+ KSNameImpl.getCached(parentDeclaration?.qualifiedName?.asString() ?: "" + "." + simpleName.asString())
+ }
+
+ override val typeParameters: List<KSTypeParameter> = emptyList()
+
+ override val parentDeclaration: KSDeclaration? by lazy {
+ psi.findParentDeclaration()
+ }
+
+ override val containingFile: KSFile? by lazy {
+ KSFileJavaImpl.getCached(psi.containingFile as PsiJavaFile)
+ }
+
+ override val modifiers: Set<Modifier> = emptySet()
+
+ override val isReified: Boolean = false
+
+ override val name: KSName by lazy {
+ KSNameImpl.getCached(psi.name!!)
+ }
+
+ override val variance: Variance = Variance.INVARIANT
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeParameter(this, data)
+ }
+}
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
new file mode 100644
index 00000000..6b035244
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeReferenceJavaImpl.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.ExceptionMessage
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSReferenceElement
+import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.symbol.NonExistLocation
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.impl.binary.KSClassDeclarationDescriptorImpl
+import com.google.devtools.ksp.symbol.impl.binary.KSClassifierReferenceDescriptorImpl
+import com.google.devtools.ksp.symbol.impl.kotlin.KSErrorType
+import com.google.devtools.ksp.symbol.impl.kotlin.KSTypeImpl
+import com.google.devtools.ksp.symbol.impl.toLocation
+import com.intellij.psi.PsiArrayType
+import com.intellij.psi.PsiClassType
+import com.intellij.psi.PsiPrimitiveType
+import com.intellij.psi.PsiType
+import com.intellij.psi.PsiWildcardType
+import com.intellij.psi.impl.source.PsiClassReferenceType
+import org.jetbrains.kotlin.descriptors.NotFoundClasses
+import org.jetbrains.kotlin.load.java.NOT_NULL_ANNOTATIONS
+import org.jetbrains.kotlin.load.java.NULLABLE_ANNOTATIONS
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.Variance
+import org.jetbrains.kotlin.types.typeUtil.makeNullable
+
+class KSTypeReferenceJavaImpl private constructor(val psi: PsiType, override val parent: KSNode?) : KSTypeReference {
+ companion object : KSObjectCache<Pair<PsiType, KSNode?>, KSTypeReferenceJavaImpl>() {
+ fun getCached(psi: PsiType, parent: KSNode?) = cache
+ .getOrPut(Pair(psi, parent)) { KSTypeReferenceJavaImpl(psi, parent) }
+ }
+
+ override val origin = Origin.JAVA
+
+ override val location: Location by lazy {
+ (psi as? PsiClassReferenceType)?.reference?.toLocation() ?: NonExistLocation
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ psi.annotations.asSequence().map { KSAnnotationJavaImpl.getCached(it) }.memoized()
+ }
+
+ override val modifiers: Set<Modifier> = emptySet()
+
+ override val element: KSReferenceElement by lazy {
+ fun PsiPrimitiveType.toKotlinType(): KotlinType {
+ return when (this.name) {
+ "int" -> ResolverImpl.instance!!.module.builtIns.intType
+ "short" -> ResolverImpl.instance!!.module.builtIns.shortType
+ "byte" -> ResolverImpl.instance!!.module.builtIns.byteType
+ "long" -> ResolverImpl.instance!!.module.builtIns.longType
+ "float" -> ResolverImpl.instance!!.module.builtIns.floatType
+ "double" -> ResolverImpl.instance!!.module.builtIns.doubleType
+ "char" -> ResolverImpl.instance!!.module.builtIns.charType
+ "boolean" -> ResolverImpl.instance!!.module.builtIns.booleanType
+ "void" -> ResolverImpl.instance!!.module.builtIns.unitType
+ else -> throw IllegalStateException("Unexpected primitive type ${this.name}, $ExceptionMessage")
+ }
+ }
+
+ val type = if (psi is PsiWildcardType) {
+ psi.bound
+ } else {
+ psi
+ }
+ when (type) {
+ is PsiClassType -> KSClassifierReferenceJavaImpl.getCached(type, this)
+ is PsiWildcardType -> KSClassifierReferenceJavaImpl.getCached(type.extendsBound as PsiClassType, this)
+ is PsiPrimitiveType -> KSClassifierReferenceDescriptorImpl.getCached(type.toKotlinType(), origin, this)
+ is PsiArrayType -> {
+ val componentType = ResolverImpl.instance!!.resolveJavaType(type.componentType, this)
+ if (type.componentType !is PsiPrimitiveType) {
+ KSClassifierReferenceDescriptorImpl.getCached(
+ ResolverImpl.instance!!.module.builtIns.getArrayType(Variance.INVARIANT, componentType),
+ origin,
+ this
+ )
+ } else {
+ KSClassifierReferenceDescriptorImpl.getCached(
+ ResolverImpl.instance!!.module.builtIns
+ .getPrimitiveArrayKotlinTypeByPrimitiveKotlinType(componentType)!!,
+ origin, this
+ )
+ }
+ }
+ null ->
+ KSClassifierReferenceDescriptorImpl.getCached(
+ (ResolverImpl.instance!!.builtIns.anyType as KSTypeImpl).kotlinType.makeNullable(), origin, this
+ )
+ else -> throw IllegalStateException("Unexpected psi type for ${type.javaClass}, $ExceptionMessage")
+ }
+ }
+
+ override fun resolve(): KSType {
+ val resolvedType = ResolverImpl.instance!!.resolveUserType(this)
+ val relatedAnnotations = (annotations + ((parent as? KSAnnotated)?.annotations ?: emptySequence()))
+ .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 hasNotNull = relatedAnnotations.any { it in NOT_NULL_ANNOTATIONS }
+ val hasNullable = relatedAnnotations.any { it in NULLABLE_ANNOTATIONS }
+ return if (hasNullable && !hasNotNull) {
+ resolved.makeNullable()
+ } else if (!hasNullable && hasNotNull) {
+ resolved.makeNotNullable()
+ } else resolved
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeReference(this, data)
+ }
+
+ override fun toString(): String {
+ return element.toString()
+ }
+}
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
new file mode 100644
index 00000000..601c8bee
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSTypeReferenceLiteJavaImpl.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.ExceptionMessage
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSReferenceElement
+import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.symbol.NonExistLocation
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.impl.kotlin.KSErrorType
+import com.intellij.psi.PsiAnnotation
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiJavaFile
+import com.intellij.psi.PsiMethod
+
+class KSTypeReferenceLiteJavaImpl private constructor(val psiElement: PsiElement, override val parent: KSNode) :
+ KSTypeReference {
+ companion object : KSObjectCache<KSNode, KSTypeReferenceLiteJavaImpl>() {
+ fun getCached(psiElement: PsiElement, parent: KSNode) = cache
+ .getOrPut(parent) { KSTypeReferenceLiteJavaImpl(psiElement, parent) }
+ }
+
+ val type: KSType by lazy {
+ when (psiElement) {
+ is PsiAnnotation -> {
+ val psiClass = psiElement.nameReferenceElement!!.resolve() as? PsiClass
+ psiClass?.let {
+ (psiElement.containingFile as? PsiJavaFile)?.let {
+ ResolverImpl.instance!!.incrementalContext.recordLookup(it, psiClass.qualifiedName!!)
+ }
+ KSClassDeclarationJavaImpl.getCached(psiClass).asStarProjectedType()
+ } ?: KSErrorType
+ }
+ is PsiMethod -> {
+ KSClassDeclarationJavaImpl.getCached(psiElement.containingClass!!).asStarProjectedType()
+ }
+ else -> throw IllegalStateException(
+ "Unexpected psi type in KSTypeReferenceLiteJavaImpl: ${psiElement.javaClass}, $ExceptionMessage"
+ )
+ }
+ }
+
+ override val origin = Origin.JAVA
+
+ override val location: Location = NonExistLocation
+
+ override val element: KSReferenceElement by lazy {
+ KSClassifierReferenceLiteImplForJava.getCached(this)
+ }
+
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override val modifiers: Set<Modifier> = emptySet()
+
+ override fun resolve(): KSType {
+ return type
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeReference(this, data)
+ }
+
+ override fun toString(): String {
+ return type.toString()
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSValueArgumentJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSValueArgumentJavaImpl.kt
new file mode 100644
index 00000000..1424b9e4
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSValueArgumentJavaImpl.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSName
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.NonExistLocation
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.impl.kotlin.KSValueArgumentImpl
+
+class KSValueArgumentJavaImpl private constructor(
+ override val name: KSName?,
+ override val value: Any?,
+ override val parent: KSNode?
+) : KSValueArgumentImpl() {
+ companion object : KSObjectCache<Triple<KSName?, Any?, KSNode?>, KSValueArgumentJavaImpl>() {
+ fun getCached(name: KSName?, value: Any?, parent: KSNode?) =
+ cache.getOrPut(Triple(name, value, parent)) { KSValueArgumentJavaImpl(name, value, parent) }
+ }
+
+ override val origin = Origin.JAVA
+
+ override val location: Location = NonExistLocation
+
+ override val isSpread: Boolean = false
+
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override fun toString(): String {
+ return "${name?.asString() ?: ""}:$value"
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSValueParameterJavaImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSValueParameterJavaImpl.kt
new file mode 100644
index 00000000..086b670a
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/java/KSValueParameterJavaImpl.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.java
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.toLocation
+import com.intellij.psi.PsiAnnotation
+import com.intellij.psi.PsiMethod
+import com.intellij.psi.PsiParameter
+
+class KSValueParameterJavaImpl private constructor(val psi: PsiParameter) : KSValueParameter {
+ companion object : KSObjectCache<PsiParameter, KSValueParameterJavaImpl>() {
+ fun getCached(psi: PsiParameter) = cache.getOrPut(psi) { KSValueParameterJavaImpl(psi) }
+ }
+
+ override val origin = Origin.JAVA
+
+ override val location: Location by lazy {
+ psi.toLocation()
+ }
+ override val parent: KSNode? by lazy {
+ var parentPsi = psi.parent
+ while (true) {
+ when (parentPsi) {
+ null, is PsiMethod, is PsiAnnotation -> break
+ else -> parentPsi = parentPsi.parent
+ }
+ }
+ when (parentPsi) {
+ is PsiMethod -> KSFunctionDeclarationJavaImpl.getCached(parentPsi)
+ is PsiAnnotation -> KSAnnotationJavaImpl.getCached(parentPsi)
+ else -> null
+ }
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ psi.annotations.asSequence().map { KSAnnotationJavaImpl.getCached(it) }
+ }
+
+ override val isCrossInline: Boolean = false
+
+ override val isNoInline: Boolean = false
+
+ override val isVararg: Boolean = psi.isVarArgs
+
+ override val isVal: Boolean = false
+
+ override val isVar: Boolean = false
+
+ override val name: KSName? by lazy {
+ if (psi.name != null) {
+ KSNameImpl.getCached(psi.name!!)
+ } else {
+ null
+ }
+ }
+
+ override val type: KSTypeReference by lazy {
+ KSTypeReferenceJavaImpl.getCached(psi.type, this)
+ }
+
+ override val hasDefault: Boolean = false
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitValueParameter(this, data)
+ }
+
+ override fun toString(): String {
+ return name?.asString() ?: "_"
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSAnnotationImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSAnnotationImpl.kt
new file mode 100644
index 00000000..19bde157
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSAnnotationImpl.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.binary.createKSValueArguments
+import com.google.devtools.ksp.symbol.impl.binary.getDefaultArguments
+import com.google.devtools.ksp.symbol.impl.toLocation
+import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
+import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*
+import org.jetbrains.kotlin.psi.KtAnnotationEntry
+import org.jetbrains.kotlin.psi.KtClassOrObject
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.psi.KtFunction
+import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.kotlin.psi.KtProperty
+import org.jetbrains.kotlin.psi.KtPropertyAccessor
+import org.jetbrains.kotlin.psi.KtTypeAlias
+import org.jetbrains.kotlin.psi.KtTypeParameter
+import org.jetbrains.kotlin.psi.KtTypeProjection
+import org.jetbrains.kotlin.psi.KtTypeReference
+
+class KSAnnotationImpl private constructor(val ktAnnotationEntry: KtAnnotationEntry) : KSAnnotation {
+ companion object : KSObjectCache<KtAnnotationEntry, KSAnnotationImpl>() {
+ fun getCached(ktAnnotationEntry: KtAnnotationEntry) = cache.getOrPut(ktAnnotationEntry) {
+ KSAnnotationImpl(ktAnnotationEntry)
+ }
+ }
+
+ override val origin = Origin.KOTLIN
+
+ override val parent: KSNode? by lazy {
+ var parentPsi = ktAnnotationEntry.parent
+ while (true) {
+ when (parentPsi) {
+ null, is KtFile, is KtClassOrObject, is KtFunction, is KtParameter, is KtTypeParameter,
+ is KtTypeAlias, is KtProperty, is KtPropertyAccessor, is KtTypeProjection, is KtTypeReference -> break
+ else -> parentPsi = parentPsi.parent
+ }
+ }
+ when (parentPsi) {
+ is KtFile -> KSFileImpl.getCached(parentPsi)
+ is KtClassOrObject -> KSClassDeclarationImpl.getCached(parentPsi)
+ is KtFunction -> KSFunctionDeclarationImpl.getCached(parentPsi)
+ is KtParameter -> KSValueParameterImpl.getCached(parentPsi)
+ is KtTypeParameter -> KSTypeParameterImpl.getCached(parentPsi)
+ is KtTypeAlias -> KSTypeAliasImpl.getCached(parentPsi)
+ is KtProperty -> KSPropertyDeclarationImpl.getCached(parentPsi)
+ is KtPropertyAccessor -> KSPropertyAccessorImpl.getCached(parentPsi)
+ is KtTypeProjection -> KSTypeArgumentKtImpl.getCached(parentPsi)
+ is KtTypeReference -> KSTypeReferenceImpl.getCached(parentPsi)
+ else -> null
+ }
+ }
+
+ override val location: Location by lazy {
+ ktAnnotationEntry.toLocation()
+ }
+
+ override val annotationType: KSTypeReference by lazy {
+ KSTypeReferenceImpl.getCached(ktAnnotationEntry.typeReference!!)
+ }
+
+ override val arguments: List<KSValueArgument> by lazy {
+ resolved?.createKSValueArguments(this) ?: emptyList()
+ }
+
+ override val defaultArguments: List<KSValueArgument> by lazy {
+ resolved?.getDefaultArguments(this) ?: emptyList()
+ }
+
+ override val shortName: KSName by lazy {
+ KSNameImpl.getCached(ktAnnotationEntry.shortName!!.asString())
+ }
+
+ override val useSiteTarget: AnnotationUseSiteTarget? by lazy {
+ when (ktAnnotationEntry.useSiteTarget?.getAnnotationUseSiteTarget()) {
+ null -> null
+ FILE -> AnnotationUseSiteTarget.FILE
+ PROPERTY -> AnnotationUseSiteTarget.PROPERTY
+ FIELD -> AnnotationUseSiteTarget.FIELD
+ PROPERTY_GETTER -> AnnotationUseSiteTarget.GET
+ PROPERTY_SETTER -> AnnotationUseSiteTarget.SET
+ RECEIVER -> AnnotationUseSiteTarget.RECEIVER
+ CONSTRUCTOR_PARAMETER -> AnnotationUseSiteTarget.PARAM
+ SETTER_PARAMETER -> AnnotationUseSiteTarget.SETPARAM
+ PROPERTY_DELEGATE_FIELD -> AnnotationUseSiteTarget.DELEGATE
+ }
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitAnnotation(this, data)
+ }
+
+ private val resolved: AnnotationDescriptor? by lazy {
+ ResolverImpl.instance!!.resolveAnnotationEntry(ktAnnotationEntry)
+ }
+
+ override fun toString(): String {
+ return "@${shortName.asString()}"
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSCallableReferenceImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSCallableReferenceImpl.kt
new file mode 100644
index 00000000..c71f37d4
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSCallableReferenceImpl.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.findParentOfType
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.toLocation
+import org.jetbrains.kotlin.psi.KtFunctionType
+import org.jetbrains.kotlin.psi.KtTypeReference
+
+class KSCallableReferenceImpl private constructor(val ktFunctionType: KtFunctionType) : KSCallableReference {
+ companion object : KSObjectCache<KtFunctionType, KSCallableReferenceImpl>() {
+ fun getCached(ktFunctionType: KtFunctionType) = cache.getOrPut(ktFunctionType) {
+ KSCallableReferenceImpl(ktFunctionType)
+ }
+ }
+
+ override val origin = Origin.KOTLIN
+
+ override val location: Location by lazy {
+ ktFunctionType.toLocation()
+ }
+
+ override val parent: KSNode? by lazy {
+ ktFunctionType.findParentOfType<KtTypeReference>()?.let { KSTypeReferenceImpl.getCached(it) }
+ }
+
+ override val typeArguments: List<KSTypeArgument> by lazy {
+ ktFunctionType.typeArgumentsAsTypes.map { KSTypeArgumentLiteImpl.getCached(it) }
+ }
+
+ override val functionParameters: List<KSValueParameter> by lazy {
+ ktFunctionType.parameters.map { KSValueParameterImpl.getCached(it) }
+ }
+
+ override val receiverType: KSTypeReference? by lazy {
+ if (ktFunctionType.receiver != null) {
+ KSTypeReferenceImpl.getCached(ktFunctionType.receiverTypeReference!!)
+ } else {
+ null
+ }
+ }
+
+ override val returnType: KSTypeReference by lazy {
+ KSTypeReferenceImpl.getCached(ktFunctionType.returnTypeReference!!)
+ }
+
+ override fun toString(): String {
+ return "${receiverType?.let { "$it." } ?: ""}(${functionParameters
+ .joinToString(", ") { it.type.toString() }}) -> $returnType"
+ }
+}
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
new file mode 100644
index 00000000..89bb2b4f
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassDeclarationImpl.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.getClassType
+import com.google.devtools.ksp.isConstructor
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.*
+import com.google.devtools.ksp.symbol.impl.binary.getAllFunctions
+import com.google.devtools.ksp.symbol.impl.binary.getAllProperties
+import com.google.devtools.ksp.symbol.impl.binary.sealedSubclassesSequence
+import com.google.devtools.ksp.symbol.impl.synthetic.KSConstructorSyntheticImpl
+import com.google.devtools.ksp.symbol.impl.synthetic.KSTypeReferenceSyntheticImpl
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.psi.KtClassOrObject
+import org.jetbrains.kotlin.psi.KtObjectDeclaration
+import org.jetbrains.kotlin.psi.KtSecondaryConstructor
+import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
+
+class KSClassDeclarationImpl private constructor(val ktClassOrObject: KtClassOrObject) :
+ KSClassDeclaration,
+ KSDeclarationImpl(ktClassOrObject),
+ KSExpectActual by KSExpectActualImpl(ktClassOrObject) {
+ companion object : KSObjectCache<KtClassOrObject, KSClassDeclarationImpl>() {
+ fun getCached(ktClassOrObject: KtClassOrObject) =
+ cache.getOrPut(ktClassOrObject) { KSClassDeclarationImpl(ktClassOrObject) }
+ }
+
+ override val classKind: ClassKind by lazy {
+ ktClassOrObject.getClassType()
+ }
+
+ override val isCompanionObject by lazy {
+ (ktClassOrObject is KtObjectDeclaration) && (ktClassOrObject.isCompanion())
+ }
+
+ override fun getSealedSubclasses(): Sequence<KSClassDeclaration> {
+ return if (Modifier.SEALED in modifiers) {
+ ResolverImpl.instance!!.incrementalContext.recordGetSealedSubclasses(this)
+ descriptor.sealedSubclassesSequence()
+ } else {
+ emptySequence()
+ }
+ }
+
+ override fun getAllFunctions(): Sequence<KSFunctionDeclaration> = descriptor.getAllFunctions()
+
+ override fun getAllProperties(): Sequence<KSPropertyDeclaration> = descriptor.getAllProperties()
+
+ override val declarations: Sequence<KSDeclaration> by lazy {
+ val propertiesFromConstructor = primaryConstructor?.parameters
+ ?.asSequence()
+ ?.filter { it.isVar || it.isVal }
+ ?.map { KSPropertyDeclarationParameterImpl.getCached((it as KSValueParameterImpl).ktParameter) }
+ ?: emptySequence()
+ var result = propertiesFromConstructor.plus(ktClassOrObject.declarations.asSequence().getKSDeclarations())
+ primaryConstructor?.let { primaryConstructor: KSFunctionDeclaration ->
+ // if primary constructor is from source, it won't show up in declarations
+ // hence add it as well.
+ if (primaryConstructor.origin == Origin.KOTLIN) {
+ result = sequenceOf(primaryConstructor).plus(result)
+ }
+ }
+ if (classKind != ClassKind.INTERFACE) {
+ // check if we need to add a synthetic constructor
+ val hasConstructor = result.any {
+ it is KSFunctionDeclaration && it.isConstructor()
+ }
+ if (hasConstructor) {
+ result.memoized()
+ } else {
+ (result + KSConstructorSyntheticImpl.getCached(this)).memoized()
+ }
+ } else {
+ result.memoized()
+ }
+ }
+
+ override val primaryConstructor: KSFunctionDeclaration? by lazy {
+ ktClassOrObject.primaryConstructor?.let { KSFunctionDeclarationImpl.getCached(it) }
+ ?: if ((classKind == ClassKind.CLASS || classKind == ClassKind.ENUM_CLASS) &&
+ ktClassOrObject.declarations.none { it is KtSecondaryConstructor }
+ )
+ KSConstructorSyntheticImpl.getCached(this) else null
+ }
+
+ override val superTypes: Sequence<KSTypeReference> by lazy {
+ val resolver = ResolverImpl.instance!!
+ ktClassOrObject.superTypeListEntries
+ .asSequence()
+ .map { KSTypeReferenceImpl.getCached(it.typeReference!!) }
+ .ifEmpty {
+ sequenceOf(
+ KSTypeReferenceSyntheticImpl.getCached(
+ resolver.builtIns.anyType,
+ this
+ )
+ )
+ }
+ .memoized()
+ }
+
+ private val descriptor: ClassDescriptor by lazy {
+ (ResolverImpl.instance!!.resolveDeclaration(ktClassOrObject) as ClassDescriptor)
+ }
+
+ override fun asType(typeArguments: List<KSTypeArgument>): KSType {
+ return descriptor.defaultType.replaceTypeArguments(typeArguments)?.let {
+ getKSTypeCached(it, typeArguments)
+ } ?: KSErrorType
+ }
+
+ override fun asStarProjectedType(): KSType {
+ return getKSTypeCached(descriptor.defaultType.replaceArgumentsWithStarProjections())
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitClassDeclaration(this, data)
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassifierReferenceImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassifierReferenceImpl.kt
new file mode 100644
index 00000000..575c15d5
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSClassifierReferenceImpl.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.findParentOfType
+import com.google.devtools.ksp.symbol.KSClassifierReference
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSTypeArgument
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.impl.toLocation
+import org.jetbrains.kotlin.psi.*
+
+class KSClassifierReferenceImpl private constructor(val ktUserType: KtUserType) : KSClassifierReference {
+ companion object : KSObjectCache<KtUserType, KSClassifierReferenceImpl>() {
+ fun getCached(ktUserType: KtUserType) = cache.getOrPut(ktUserType) { KSClassifierReferenceImpl(ktUserType) }
+ }
+
+ override val origin = Origin.KOTLIN
+
+ override val location: Location by lazy {
+ ktUserType.toLocation()
+ }
+
+ override val parent: KSNode? by lazy {
+ ktUserType.findParentOfType<KtTypeReference>()?.let { KSTypeReferenceImpl.getCached(it) }
+ }
+
+ override val typeArguments: List<KSTypeArgument> by lazy {
+ ktUserType.typeArguments.map { KSTypeArgumentKtImpl.getCached(it) }
+ }
+
+ override fun referencedName(): String {
+ return ktUserType.referencedName ?: ""
+ }
+
+ override val qualifier: KSClassifierReference? by lazy {
+ if (ktUserType.qualifier == null) {
+ null
+ } else {
+ KSClassifierReferenceImpl.getCached(ktUserType.qualifier!!)
+ }
+ }
+
+ override fun toString() = referencedName()
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSDeclarationImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSDeclarationImpl.kt
new file mode 100644
index 00000000..3e596664
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSDeclarationImpl.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.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.getDocString
+import com.google.devtools.ksp.isConstructor
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.findParentAnnotated
+import com.google.devtools.ksp.symbol.impl.findParentDeclaration
+import com.google.devtools.ksp.symbol.impl.toLocation
+import com.google.devtools.ksp.toKSModifiers
+import org.jetbrains.kotlin.psi.*
+
+abstract class KSDeclarationImpl(val ktDeclaration: KtDeclaration) : KSDeclaration {
+ override val origin: Origin = Origin.KOTLIN
+
+ override val location: Location by lazy {
+ ktDeclaration.toLocation()
+ }
+
+ override val simpleName: KSName by lazy {
+ KSNameImpl.getCached(ktDeclaration.name!!)
+ }
+
+ override val qualifiedName: KSName? by lazy {
+ (ktDeclaration as? KtNamedDeclaration)?.fqName?.let { KSNameImpl.getCached(it.asString()) }
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ ktDeclaration.annotationEntries.asSequence().map { KSAnnotationImpl.getCached(it) }.memoized()
+ }
+
+ override val modifiers: Set<Modifier> by lazy {
+ // we do not check for JVM_STATIC here intentionally as it actually means static in parent class,
+ // not in this class.
+ // see: https://github.com/google/ksp/issues/378
+ if (this is KSFunctionDeclaration && this.isConstructor() &&
+ (this.parentDeclaration as? KSClassDeclaration)?.classKind == ClassKind.ENUM_CLASS
+ ) {
+ setOf(Modifier.FINAL, Modifier.PRIVATE)
+ } else {
+ ktDeclaration.toKSModifiers()
+ }
+ }
+
+ override val containingFile: KSFile? by lazy {
+ KSFileImpl.getCached(ktDeclaration.containingKtFile)
+ }
+
+ override val packageName: KSName by lazy {
+ this.containingFile!!.packageName
+ }
+
+ override val typeParameters: List<KSTypeParameter> by lazy {
+ (ktDeclaration as? KtTypeParameterListOwner)?.let {
+ it.typeParameters.map { KSTypeParameterImpl.getCached(it) }
+ } ?: emptyList()
+ }
+
+ override val parentDeclaration: KSDeclaration? by lazy {
+ ktDeclaration.findParentDeclaration()
+ }
+
+ override val parent: KSNode? by lazy {
+ ktDeclaration.findParentAnnotated()
+ }
+
+ override fun toString(): String {
+ return this.simpleName.asString()
+ }
+
+ internal val originalAnnotations: List<KSAnnotation> by lazy {
+ ktDeclaration.annotationEntries.map { KSAnnotationImpl.getCached(it) }
+ }
+
+ override val docString by lazy {
+ ktDeclaration.getDocString()
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSDefNonNullReferenceImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSDefNonNullReferenceImpl.kt
new file mode 100644
index 00000000..37d07c92
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSDefNonNullReferenceImpl.kt
@@ -0,0 +1,41 @@
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.findParentOfType
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.toLocation
+import org.jetbrains.kotlin.psi.KtIntersectionType
+import org.jetbrains.kotlin.psi.KtTypeReference
+import org.jetbrains.kotlin.psi.KtUserType
+
+class KSDefNonNullReferenceImpl private constructor(val ktIntersectionType: KtIntersectionType) :
+ KSDefNonNullReference {
+ companion object : KSObjectCache<KtIntersectionType, KSDefNonNullReferenceImpl>() {
+ fun getCached(ktIntersectionType: KtIntersectionType) = KSDefNonNullReferenceImpl
+ .cache.getOrPut(ktIntersectionType) { KSDefNonNullReferenceImpl(ktIntersectionType) }
+ }
+
+ override val enclosedType: KSClassifierReference by lazy {
+ val lhs = ktIntersectionType.getLeftTypeRef()?.typeElement
+ if (lhs is KtUserType) {
+ KSClassifierReferenceImpl.getCached(lhs)
+ } else {
+ throw IllegalStateException("LHS operand of definitely non null type should be a user type")
+ }
+ }
+
+ override val typeArguments: List<KSTypeArgument>
+ get() = emptyList()
+
+ override val origin: Origin
+ get() = Origin.KOTLIN
+
+ override val location: Location
+ get() = ktIntersectionType.toLocation()
+
+ override val parent: KSNode? by lazy {
+ ktIntersectionType.findParentOfType<KtTypeReference>()?.let { KSTypeReferenceImpl.getCached(it) }
+ }
+
+ override fun toString() = "${enclosedType.referencedName()} & Any"
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSDynamicReferenceImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSDynamicReferenceImpl.kt
new file mode 100644
index 00000000..27579fce
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSDynamicReferenceImpl.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.*
+
+class KSDynamicReferenceImpl private constructor(override val parent: KSNode?) : KSDynamicReference {
+ companion object : KSObjectCache<KSTypeReference, KSDynamicReferenceImpl>() {
+ fun getCached(parent: KSTypeReference) = cache.getOrPut(parent) { KSDynamicReferenceImpl(parent) }
+ }
+
+ override val origin = Origin.KOTLIN
+
+ override val location: Location by lazy {
+ NonExistLocation
+ }
+
+ override val typeArguments: List<KSTypeArgument> = emptyList()
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitDynamicReference(this, data)
+ }
+
+ override fun toString(): String {
+ return "<dynamic type>"
+ }
+}
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
new file mode 100644
index 00000000..8cf66385
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSErrorType.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.synthetic.KSErrorTypeClassDeclaration
+
+object KSErrorType : KSType {
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override val arguments: List<KSTypeArgument> = emptyList()
+
+ override val declaration: KSDeclaration = KSErrorTypeClassDeclaration
+
+ override val isError: Boolean = true
+
+ override val nullability: Nullability = Nullability.NULLABLE
+
+ override fun isAssignableFrom(that: KSType): Boolean {
+ return false
+ }
+
+ override fun isCovarianceFlexible(): Boolean {
+ return false
+ }
+
+ override fun isMutabilityFlexible(): Boolean {
+ return false
+ }
+
+ override fun makeNotNullable(): KSType {
+ return this
+ }
+
+ override fun makeNullable(): KSType {
+ return this
+ }
+
+ override val isMarkedNullable: Boolean = false
+
+ override fun replace(arguments: List<KSTypeArgument>): KSType {
+ return this
+ }
+
+ override fun starProjection(): KSType {
+ return this
+ }
+
+ override fun toString(): String {
+ return "<ERROR TYPE>"
+ }
+
+ override val isFunctionType: Boolean = false
+
+ override val isSuspendFunctionType: Boolean = false
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSExpectActualImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSExpectActualImpl.kt
new file mode 100644
index 00000000..18c3f9c5
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSExpectActualImpl.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.processing.impl.findActualsInKSDeclaration
+import com.google.devtools.ksp.processing.impl.findExpectsInKSDeclaration
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSExpectActual
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
+import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
+import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
+
+class KSExpectActualImpl(val declaration: KtDeclaration) : KSExpectActual {
+ /**
+ * "All actual declarations that match any part of an expected declaration need to be marked as actual."
+ */
+ override val isActual: Boolean = declaration.hasActualModifier()
+
+ private fun KtDeclaration.isExpect(): Boolean = hasExpectModifier() || containingClassOrObject?.isExpect() == true
+
+ override val isExpect: Boolean = declaration.isExpect()
+
+ private val expects: Sequence<KSDeclaration> by lazy {
+ descriptor?.findExpectsInKSDeclaration() ?: emptySequence()
+ }
+
+ override fun findExpects(): Sequence<KSDeclaration> {
+ if (!isActual)
+ return emptySequence()
+ return expects
+ }
+
+ private val actuals: Sequence<KSDeclaration> by lazy {
+ descriptor?.findActualsInKSDeclaration() ?: emptySequence()
+ }
+
+ override fun findActuals(): Sequence<KSDeclaration> {
+ if (!isExpect)
+ return emptySequence()
+ return actuals
+ }
+
+ private val descriptor: DeclarationDescriptor? by lazy {
+ ResolverImpl.instance!!.resolveDeclaration(declaration)
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSExpectActualNoImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSExpectActualNoImpl.kt
new file mode 100644
index 00000000..c06cd2ca
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSExpectActualNoImpl.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSExpectActual
+
+class KSExpectActualNoImpl : KSExpectActual {
+ override val isActual: Boolean = false
+
+ override val isExpect: Boolean = false
+
+ override fun findActuals(): Sequence<KSDeclaration> = emptySequence()
+
+ override fun findExpects(): Sequence<KSDeclaration> = emptySequence()
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFileImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFileImpl.kt
new file mode 100644
index 00000000..3e333a2e
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFileImpl.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.getKSDeclarations
+import com.google.devtools.ksp.symbol.impl.toLocation
+import org.jetbrains.kotlin.psi.KtFile
+
+class KSFileImpl private constructor(val file: KtFile) : KSFile {
+ companion object : KSObjectCache<KtFile, KSFileImpl>() {
+ fun getCached(file: KtFile) = cache.getOrPut(file) { KSFileImpl(file) }
+ }
+
+ override val origin = Origin.KOTLIN
+
+ override val location: Location by lazy {
+ file.toLocation()
+ }
+
+ override val parent: KSNode? = null
+
+ override val packageName: KSName by lazy {
+ KSNameImpl.getCached(file.packageFqName.asString())
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ file.annotationEntries.asSequence().map { KSAnnotationImpl.getCached(it) }.memoized()
+ }
+
+ override val declarations: Sequence<KSDeclaration> by lazy {
+ file.declarations.asSequence().getKSDeclarations().memoized()
+ }
+
+ override val fileName: String by lazy {
+ file.name
+ }
+
+ override val filePath: String by lazy {
+ file.virtualFilePath
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitFile(this, data)
+ }
+
+ override fun toString(): String {
+ return "File: ${this.fileName}"
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionDeclarationImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionDeclarationImpl.kt
new file mode 100644
index 00000000..75017fbb
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionDeclarationImpl.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.ExceptionMessage
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.processing.impl.KSPCompilationError
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.*
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtConstructor
+import org.jetbrains.kotlin.psi.KtFunction
+import org.jetbrains.kotlin.psi.KtFunctionLiteral
+import org.jetbrains.kotlin.psi.KtNamedFunction
+import org.jetbrains.kotlin.psi.psiUtil.startOffset
+import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing
+
+class KSFunctionDeclarationImpl private constructor(val ktFunction: KtFunction) :
+ KSFunctionDeclaration,
+ KSDeclarationImpl(ktFunction),
+ KSExpectActual by KSExpectActualImpl(ktFunction) {
+ companion object : KSObjectCache<KtFunction, KSFunctionDeclarationImpl>() {
+ fun getCached(ktFunction: KtFunction) = cache.getOrPut(ktFunction) { KSFunctionDeclarationImpl(ktFunction) }
+ }
+
+ override fun findOverridee(): KSDeclaration? {
+ val descriptor = ResolverImpl.instance!!.resolveFunctionDeclaration(this)
+ return (descriptor as? FunctionDescriptor)?.findClosestOverridee()?.toKSDeclaration()
+ }
+
+ override val simpleName: KSName by lazy {
+ if (ktFunction is KtConstructor<*>) {
+ KSNameImpl.getCached("<init>")
+ } else {
+ if (ktFunction.name == null) {
+ throw KSPCompilationError(
+ ktFunction.containingFile,
+ ktFunction.startOffset,
+ "Function declaration must have a name"
+ )
+ }
+ KSNameImpl.getCached(ktFunction.name!!)
+ }
+ }
+
+ override val declarations: Sequence<KSDeclaration> by lazy {
+ if (!ktFunction.hasBlockBody()) {
+ emptySequence()
+ } else {
+ ktFunction.bodyBlockExpression?.statements?.asSequence()?.getKSDeclarations()?.memoized() ?: emptySequence()
+ }
+ }
+
+ override val extensionReceiver: KSTypeReference? by lazy {
+ if (ktFunction.receiverTypeReference != null) {
+ KSTypeReferenceImpl.getCached(ktFunction.receiverTypeReference!!)
+ } else {
+ null
+ }
+ }
+
+ override val functionKind: FunctionKind by lazy {
+ if (parentDeclaration == null) {
+ FunctionKind.TOP_LEVEL
+ } else {
+ when (ktFunction) {
+ is KtNamedFunction, is KtConstructor<*> -> FunctionKind.MEMBER
+ is KtFunctionLiteral -> if (ktFunction.node.findChildByType(KtTokens.FUN_KEYWORD) != null)
+ FunctionKind.ANONYMOUS else FunctionKind.LAMBDA
+ else -> throw IllegalStateException("Unexpected psi type ${ktFunction.javaClass}, $ExceptionMessage")
+ }
+ }
+ }
+
+ override val isAbstract: Boolean by lazy {
+ this.modifiers.contains(Modifier.ABSTRACT) ||
+ (
+ (this.parentDeclaration as? KSClassDeclaration)?.classKind == ClassKind.INTERFACE &&
+ !this.ktFunction.hasBody()
+ )
+ }
+
+ override val parameters: List<KSValueParameter> by lazy {
+ ktFunction.valueParameters.map { KSValueParameterImpl.getCached(it) }
+ }
+
+ override val returnType: KSTypeReference by lazy {
+ if (ktFunction.typeReference != null) {
+ KSTypeReferenceImpl.getCached(ktFunction.typeReference!!)
+ } else {
+ KSTypeReferenceDeferredImpl.getCached(this) {
+ val desc = ResolverImpl.instance!!.resolveDeclaration(ktFunction) as FunctionDescriptor
+ getKSTypeCached(desc.returnTypeOrNothing)
+ }
+ }
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitFunctionDeclaration(this, data)
+ }
+
+ override fun asMemberOf(containing: KSType): KSFunction =
+ ResolverImpl.instance!!.asMemberOf(this, containing)
+}
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
new file mode 100644
index 00000000..5100e367
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionErrorImpl.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.symbol.KSFunction
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSTypeParameter
+
+/**
+ * Used when `ResolverImpl.asMemberOf` is called with an error type or function declaration cannot be found.
+ */
+class KSFunctionErrorImpl(
+ private val declaration: KSFunctionDeclaration
+) : KSFunction {
+ override val isError: Boolean = true
+
+ override val returnType: KSType = KSErrorType
+
+ override val parameterTypes: List<KSType?>
+ get() = declaration.parameters.map {
+ KSErrorType
+ }
+ override val typeParameters: List<KSTypeParameter>
+ get() = emptyList()
+
+ override val extensionReceiverType: KSType?
+ get() = declaration.extensionReceiver?.let {
+ KSErrorType
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as KSFunctionErrorImpl
+
+ if (declaration != other.declaration) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ return declaration.hashCode()
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionImpl.kt
new file mode 100644
index 00000000..55eebfbf
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSFunctionImpl.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.symbol.KSFunction
+import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSTypeParameter
+import com.google.devtools.ksp.symbol.impl.binary.KSTypeParameterDescriptorImpl
+import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import java.util.Objects
+
+class KSFunctionImpl(val descriptor: CallableDescriptor) : KSFunction {
+
+ override val isError: Boolean = false
+
+ private val cachedHashCode by lazy(LazyThreadSafetyMode.PUBLICATION) {
+ Objects.hash(
+ returnType ?: 0,
+ parameterTypes,
+ typeParameters,
+ extensionReceiverType ?: 0
+ )
+ }
+
+ override val returnType by lazy(LazyThreadSafetyMode.PUBLICATION) {
+ descriptor.returnType?.let(::getKSTypeCached)
+ }
+ override val parameterTypes: List<KSType> by lazy(LazyThreadSafetyMode.PUBLICATION) {
+ descriptor.valueParameters.map {
+ getKSTypeCached(it.type)
+ }
+ }
+ override val typeParameters: List<KSTypeParameter> by lazy(LazyThreadSafetyMode.PUBLICATION) {
+ descriptor.typeParameters.map {
+ KSTypeParameterDescriptorImpl.getCached(it)
+ }
+ }
+
+ override val extensionReceiverType: KSType? by lazy(LazyThreadSafetyMode.PUBLICATION) {
+ descriptor.extensionReceiverParameter?.type?.let(::getKSTypeCached)
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as KSFunctionImpl
+
+ if (returnType != other.returnType) return false
+ if (parameterTypes != other.parameterTypes) return false
+ if (typeParameters != other.typeParameters) return false
+ if (extensionReceiverType != other.extensionReceiverType) return false
+
+ return true
+ }
+
+ override fun hashCode() = cachedHashCode
+
+ override fun toString(): String {
+ return "KSFunctionImpl(descriptor=$descriptor)"
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSNodeKtImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSNodeKtImpl.kt
new file mode 100644
index 00000000..8c44b145
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSNodeKtImpl.kt
@@ -0,0 +1,12 @@
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.impl.toLocation
+import org.jetbrains.kotlin.psi.KtElement
+
+abstract class KSNodeKtImpl(private val element: KtElement) : KSNode {
+ override val location: Location by lazy {
+ element.toLocation()
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyAccessorImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyAccessorImpl.kt
new file mode 100644
index 00000000..d7559bf7
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyAccessorImpl.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.processing.impl.findAnnotationFromUseSiteTarget
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.toLocation
+import com.google.devtools.ksp.toKSModifiers
+import org.jetbrains.kotlin.psi.KtProperty
+import org.jetbrains.kotlin.psi.KtPropertyAccessor
+
+abstract class KSPropertyAccessorImpl(val ktPropertyAccessor: KtPropertyAccessor) : KSPropertyAccessor {
+ companion object {
+ fun getCached(ktPropertyAccessor: KtPropertyAccessor): KSPropertyAccessor {
+ return if (ktPropertyAccessor.isGetter) {
+ KSPropertyGetterImpl.getCached(ktPropertyAccessor)
+ } else {
+ KSPropertySetterImpl.getCached(ktPropertyAccessor)
+ }
+ }
+ }
+ override val receiver: KSPropertyDeclaration by lazy {
+ KSPropertyDeclarationImpl.getCached(ktPropertyAccessor.property as KtProperty)
+ }
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ ktPropertyAccessor.filterUseSiteTargetAnnotations().map { KSAnnotationImpl.getCached(it) }
+ .plus(this.findAnnotationFromUseSiteTarget())
+ }
+
+ override val parent: KSNode? by lazy {
+ receiver
+ }
+
+ override val location: Location by lazy {
+ ktPropertyAccessor.toLocation()
+ }
+
+ override val modifiers: Set<Modifier> by lazy {
+ ktPropertyAccessor.toKSModifiers()
+ }
+
+ override val origin: Origin = Origin.KOTLIN
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertyAccessor(this, data)
+ }
+
+ internal val originalAnnotations: List<KSAnnotation> by lazy {
+ ktPropertyAccessor.annotationEntries.map { KSAnnotationImpl.getCached(it) }
+ }
+}
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
new file mode 100644
index 00000000..312b73d1
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationImpl.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.*
+import com.google.devtools.ksp.symbol.impl.binary.KSPropertyGetterDescriptorImpl
+import com.google.devtools.ksp.symbol.impl.binary.KSPropertySetterDescriptorImpl
+import org.jetbrains.kotlin.descriptors.PropertyDescriptor
+import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
+import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtAnnotated
+import org.jetbrains.kotlin.psi.KtAnnotationEntry
+import org.jetbrains.kotlin.psi.KtProperty
+import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
+import org.jetbrains.kotlin.resolve.BindingContext
+
+class KSPropertyDeclarationImpl private constructor(val ktProperty: KtProperty) :
+ KSPropertyDeclaration,
+ KSDeclarationImpl(ktProperty),
+ KSExpectActual by KSExpectActualImpl(ktProperty) {
+ companion object : KSObjectCache<KtProperty, KSPropertyDeclarationImpl>() {
+ fun getCached(ktProperty: KtProperty) = cache.getOrPut(ktProperty) { KSPropertyDeclarationImpl(ktProperty) }
+ }
+
+ private val propertyDescriptor by lazy {
+ ResolverImpl.instance!!.resolveDeclaration(ktProperty) as? PropertyDescriptor
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ ktProperty.filterUseSiteTargetAnnotations().map { KSAnnotationImpl.getCached(it) }
+ }
+
+ override val extensionReceiver: KSTypeReference? by lazy {
+ if (ktProperty.isExtensionDeclaration()) {
+ KSTypeReferenceImpl.getCached(ktProperty.receiverTypeReference!!)
+ } else {
+ null
+ }
+ }
+
+ override val isMutable: Boolean by lazy {
+ ktProperty.isVar
+ }
+
+ override val hasBackingField: Boolean by lazy {
+ // taken from: https://github.com/JetBrains/kotlin/blob/master/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt#L104
+ when {
+ ktProperty.initializer != null -> true
+ ktProperty.hasModifier(KtTokens.LATEINIT_KEYWORD) -> true
+ else -> {
+ val context = ResolverImpl.instance!!.bindingTrace.bindingContext
+ val descriptor = ResolverImpl.instance!!.resolveDeclaration(ktProperty)
+ descriptor is PropertyDescriptor && context[BindingContext.BACKING_FIELD_REQUIRED, descriptor] == true
+ }
+ }
+ }
+
+ override val getter: KSPropertyGetter? by lazy {
+ ktProperty.getter?.let {
+ KSPropertyGetterImpl.getCached(it)
+ } ?: propertyDescriptor?.getter?.let {
+ KSPropertyGetterDescriptorImpl.getCached(it)
+ }
+ }
+
+ override val setter: KSPropertySetter? by lazy {
+ ktProperty.setter?.let {
+ KSPropertySetterImpl.getCached(it)
+ } ?: propertyDescriptor?.setter?.let {
+ KSPropertySetterDescriptorImpl.getCached(it)
+ }
+ }
+
+ override val type: KSTypeReference by lazy {
+ if (ktProperty.typeReference != null) {
+ KSTypeReferenceImpl.getCached(ktProperty.typeReference!!)
+ } else {
+ KSTypeReferenceDeferredImpl.getCached(this) {
+ val desc = propertyDescriptor as? VariableDescriptorWithAccessors
+ if (desc == null) {
+ KSErrorType
+ } else {
+ getKSTypeCached(desc.type)
+ }
+ }
+ }
+ }
+
+ override fun isDelegated(): Boolean = ktProperty.hasDelegate()
+
+ override fun findOverridee(): KSPropertyDeclaration? {
+ return propertyDescriptor?.findClosestOverridee()?.toKSPropertyDeclaration()
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertyDeclaration(this, data)
+ }
+
+ override fun asMemberOf(containing: KSType): KSType =
+ ResolverImpl.instance!!.asMemberOf(this, containing)
+}
+
+internal fun KtAnnotated.filterUseSiteTargetAnnotations(): Sequence<KtAnnotationEntry> {
+ return this.annotationEntries.asSequence().filter { property ->
+ property.useSiteTarget?.getAnnotationUseSiteTarget()?.let {
+ it != AnnotationUseSiteTarget.PROPERTY_GETTER && it != AnnotationUseSiteTarget.PROPERTY_SETTER &&
+ it != AnnotationUseSiteTarget.SETTER_PARAMETER && it != AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER
+ } ?: true
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationParameterImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationParameterImpl.kt
new file mode 100644
index 00000000..1e69d243
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyDeclarationParameterImpl.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.isPrivate
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.*
+import com.google.devtools.ksp.symbol.impl.synthetic.KSPropertyGetterSyntheticImpl
+import com.google.devtools.ksp.symbol.impl.synthetic.KSPropertySetterSyntheticImpl
+import org.jetbrains.kotlin.psi.KtParameter
+
+class KSPropertyDeclarationParameterImpl private constructor(val ktParameter: KtParameter) :
+ KSPropertyDeclaration,
+ KSDeclarationImpl(ktParameter),
+ KSExpectActual by KSExpectActualImpl(ktParameter) {
+ companion object : KSObjectCache<KtParameter, KSPropertyDeclarationParameterImpl>() {
+ fun getCached(ktParameter: KtParameter) = cache.getOrPut(ktParameter) {
+ KSPropertyDeclarationParameterImpl(ktParameter)
+ }
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ ktParameter.filterUseSiteTargetAnnotations().map { KSAnnotationImpl.getCached(it) }
+ .filterNot { valueParameterAnnotation ->
+ valueParameterAnnotation.useSiteTarget == AnnotationUseSiteTarget.PARAM ||
+ (
+ valueParameterAnnotation.annotationType.resolve()
+ .declaration.annotations.any { metaAnnotation ->
+ metaAnnotation.annotationType.resolve().declaration.qualifiedName
+ ?.asString() == "kotlin.annotation.Target" &&
+ (metaAnnotation.arguments.singleOrNull()?.value as? ArrayList<*>)?.any {
+ (it as? KSType)?.declaration?.qualifiedName
+ ?.asString() == "kotlin.annotation.AnnotationTarget.VALUE_PARAMETER"
+ } ?: false
+ } && valueParameterAnnotation.useSiteTarget == null
+ )
+ }
+ }
+
+ override val parentDeclaration: KSDeclaration? by lazy {
+ ktParameter.findParentDeclaration()!!.parentDeclaration
+ }
+
+ override val hasBackingField: Boolean
+ get() = true
+
+ override val extensionReceiver: KSTypeReference? = null
+
+ override val isMutable: Boolean by lazy {
+ ktParameter.isMutable
+ }
+
+ override val getter: KSPropertyGetter? by lazy {
+ if (this.isPrivate()) {
+ null
+ } else {
+ KSPropertyGetterSyntheticImpl.getCached(this)
+ }
+ }
+
+ override val setter: KSPropertySetter? by lazy {
+ if (ktParameter.isMutable && !this.isPrivate()) {
+ KSPropertySetterSyntheticImpl.getCached(this)
+ } else {
+ null
+ }
+ }
+
+ override val type: KSTypeReference by lazy {
+ if (ktParameter.typeReference != null) {
+ KSTypeReferenceImpl.getCached(ktParameter.typeReference!!)
+ } else {
+ throw IllegalStateException("properties in parameter must have explicit type")
+ }
+ }
+
+ override fun isDelegated(): Boolean = false
+
+ override fun findOverridee(): KSPropertyDeclaration? {
+ return ResolverImpl.instance!!.resolvePropertyDeclaration(this)?.original
+ ?.findClosestOverridee()?.toKSPropertyDeclaration()
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertyDeclaration(this, data)
+ }
+
+ override fun asMemberOf(containing: KSType): KSType =
+ ResolverImpl.instance!!.asMemberOf(this, containing)
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyGetterImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyGetterImpl.kt
new file mode 100644
index 00000000..bf328c29
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertyGetterImpl.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.binary.KSTypeReferenceDescriptorImpl
+import org.jetbrains.kotlin.descriptors.PropertyDescriptor
+import org.jetbrains.kotlin.psi.KtPropertyAccessor
+
+class KSPropertyGetterImpl private constructor(ktPropertyGetter: KtPropertyAccessor) :
+ KSPropertyAccessorImpl(ktPropertyGetter),
+ KSPropertyGetter {
+ companion object : KSObjectCache<KtPropertyAccessor, KSPropertyGetterImpl>() {
+ fun getCached(ktPropertyGetter: KtPropertyAccessor) = cache.getOrPut(ktPropertyGetter) {
+ KSPropertyGetterImpl(ktPropertyGetter)
+ }
+ }
+
+ override val returnType: KSTypeReference? by lazy {
+ val property = ktPropertyGetter.property
+ if (property.typeReference != null) {
+ KSTypeReferenceImpl.getCached(property.typeReference!!)
+ } else {
+ val desc = ResolverImpl.instance!!.resolveDeclaration(property) as PropertyDescriptor
+ KSTypeReferenceDescriptorImpl.getCached(desc.returnType!!, origin, this)
+ }
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertyGetter(this, data)
+ }
+
+ override fun toString(): String {
+ return "$receiver.getter()"
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertySetterImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertySetterImpl.kt
new file mode 100644
index 00000000..177567b0
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSPropertySetterImpl.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.impl.synthetic.KSValueParameterSyntheticImpl
+import org.jetbrains.kotlin.psi.KtPropertyAccessor
+
+class KSPropertySetterImpl private constructor(ktPropertySetter: KtPropertyAccessor) :
+ KSPropertyAccessorImpl(ktPropertySetter),
+ KSPropertySetter {
+ companion object : KSObjectCache<KtPropertyAccessor, KSPropertySetterImpl>() {
+ fun getCached(ktPropertySetter: KtPropertyAccessor) = cache.getOrPut(ktPropertySetter) {
+ KSPropertySetterImpl(ktPropertySetter)
+ }
+ }
+
+ override val parameter: KSValueParameter by lazy {
+ ktPropertySetter.parameterList?.parameters?.singleOrNull()?.let { KSValueParameterImpl.getCached(it) }
+ ?: KSValueParameterSyntheticImpl.getCached(this) {
+ ResolverImpl.instance!!.resolvePropertyAccessorDeclaration(this)
+ ?.valueParameters?.singleOrNull()
+ }
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertySetter(this, data)
+ }
+
+ override fun toString(): String {
+ return "$receiver.setter()"
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeAliasImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeAliasImpl.kt
new file mode 100644
index 00000000..7ccbcec6
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeAliasImpl.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import org.jetbrains.kotlin.psi.*
+
+class KSTypeAliasImpl private constructor(val ktTypeAlias: KtTypeAlias) :
+ KSTypeAlias,
+ KSDeclarationImpl(ktTypeAlias),
+ KSExpectActual by KSExpectActualImpl(ktTypeAlias) {
+ companion object : KSObjectCache<KtTypeAlias, KSTypeAliasImpl>() {
+ fun getCached(ktTypeAlias: KtTypeAlias) = cache.getOrPut(ktTypeAlias) { KSTypeAliasImpl(ktTypeAlias) }
+ }
+
+ override val name: KSName by lazy {
+ KSNameImpl.getCached(ktTypeAlias.name!!)
+ }
+
+ override val type: KSTypeReference by lazy {
+ KSTypeReferenceImpl.getCached(ktTypeAlias.getTypeReference()!!)
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeAlias(this, data)
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeArgumentImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeArgumentImpl.kt
new file mode 100644
index 00000000..d3cb3975
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeArgumentImpl.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.findParentOfType
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSTypeArgument
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.Variance
+import com.google.devtools.ksp.symbol.impl.toLocation
+import org.jetbrains.kotlin.psi.KtProjectionKind
+import org.jetbrains.kotlin.psi.KtTypeProjection
+import org.jetbrains.kotlin.psi.KtUserType
+
+abstract class KSTypeArgumentImpl : KSTypeArgument {
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeArgument(this, data)
+ }
+
+ override fun toString(): String {
+ return "$variance $type"
+ }
+}
+
+class KSTypeArgumentKtImpl private constructor(val ktTypeArgument: KtTypeProjection) : KSTypeArgumentImpl() {
+ companion object : KSObjectCache<KtTypeProjection, KSTypeArgumentKtImpl>() {
+ fun getCached(ktTypeArgument: KtTypeProjection) = cache.getOrPut(ktTypeArgument) {
+ KSTypeArgumentKtImpl(ktTypeArgument)
+ }
+ }
+
+ override val origin = Origin.KOTLIN
+
+ override val location: Location by lazy {
+ ktTypeArgument.toLocation()
+ }
+
+ override val parent: KSNode? by lazy {
+ ktTypeArgument.findParentOfType<KtUserType>()?.let { KSClassifierReferenceImpl.getCached(it) }
+ }
+
+ override val variance: Variance by lazy {
+ when (ktTypeArgument.projectionKind) {
+ KtProjectionKind.STAR -> Variance.STAR
+ KtProjectionKind.IN -> Variance.CONTRAVARIANT
+ KtProjectionKind.NONE -> Variance.INVARIANT
+ KtProjectionKind.OUT -> Variance.COVARIANT
+ }
+ }
+
+ override val type: KSTypeReference? by lazy {
+ if (ktTypeArgument.typeReference != null) {
+ KSTypeReferenceImpl.getCached(ktTypeArgument.typeReference!!)
+ } else {
+ null
+ }
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ ktTypeArgument.annotationEntries.asSequence().map { KSAnnotationImpl.getCached(it) }.memoized()
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeArgumentLiteImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeArgumentLiteImpl.kt
new file mode 100644
index 00000000..d080fd87
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeArgumentLiteImpl.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.findParentOfType
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.NonExistLocation
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.Variance
+import org.jetbrains.kotlin.psi.KtFunctionType
+import org.jetbrains.kotlin.psi.KtTypeReference
+
+class KSTypeArgumentLiteImpl private constructor(override val type: KSTypeReference, override val variance: Variance) :
+ KSTypeArgumentImpl() {
+ companion object : KSObjectCache<Pair<KSTypeReference, Variance>, KSTypeArgumentLiteImpl>() {
+ fun getCached(type: KSTypeReference, variance: Variance) = cache.getOrPut(Pair(type, variance)) {
+ KSTypeArgumentLiteImpl(type, variance)
+ }
+
+ fun getCached(type: KtTypeReference) = cache.getOrPut(
+ Pair(KSTypeReferenceImpl.getCached(type), Variance.INVARIANT)
+ ) {
+ KSTypeArgumentLiteImpl(KSTypeReferenceImpl.getCached(type), Variance.INVARIANT)
+ }
+ }
+
+ override val origin = Origin.KOTLIN
+
+ override val location: Location = NonExistLocation
+
+ override val parent: KSNode? by lazy {
+ (type as? KSTypeReferenceImpl)?.ktTypeReference
+ ?.findParentOfType<KtFunctionType>()?.let { KSCallableReferenceImpl.getCached(it) }
+ }
+
+ override val annotations: Sequence<KSAnnotation> = type.annotations
+}
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
new file mode 100644
index 00000000..9e8929a8
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeImpl.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.IdKey
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+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.Origin
+import com.google.devtools.ksp.symbol.impl.binary.KSAnnotationDescriptorImpl
+import com.google.devtools.ksp.symbol.impl.binary.KSTypeArgumentDescriptorImpl
+import com.google.devtools.ksp.symbol.impl.convertKotlinType
+import com.google.devtools.ksp.symbol.impl.replaceTypeArguments
+import org.jetbrains.kotlin.builtins.isFunctionType
+import org.jetbrains.kotlin.builtins.isKFunctionType
+import org.jetbrains.kotlin.builtins.isKSuspendFunctionType
+import org.jetbrains.kotlin.builtins.isSuspendFunctionType
+import org.jetbrains.kotlin.descriptors.NotFoundClasses
+import org.jetbrains.kotlin.descriptors.SourceElement
+import org.jetbrains.kotlin.types.*
+import org.jetbrains.kotlin.types.typeUtil.TypeNullability
+import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
+import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
+import org.jetbrains.kotlin.types.typeUtil.makeNullable
+import org.jetbrains.kotlin.types.typeUtil.nullability
+import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
+
+class KSTypeImpl private constructor(
+ val kotlinType: KotlinType,
+ private val ksTypeArguments: List<KSTypeArgument>? = null,
+ override val annotations: Sequence<KSAnnotation> = sequenceOf()
+) : KSType {
+ companion object : KSObjectCache<IdKey<KotlinType>, KSTypeImpl>() {
+ fun getCached(
+ kotlinType: KotlinType,
+ ksTypeArguments: List<KSTypeArgument>? = null,
+ annotations: Sequence<KSAnnotation> = sequenceOf()
+ ): KSTypeImpl {
+ return cache.getOrPut(IdKey(kotlinType)) { KSTypeImpl(kotlinType, ksTypeArguments, annotations) }
+ }
+ }
+
+ override val declaration: KSDeclaration by lazy {
+ ResolverImpl.instance!!.findDeclaration(kotlinType.getAbbreviation() ?: kotlinType)
+ }
+
+ override val nullability: Nullability by lazy {
+ when (kotlinType.nullability()) {
+ TypeNullability.NULLABLE -> Nullability.NULLABLE
+ TypeNullability.NOT_NULL -> Nullability.NOT_NULL
+ TypeNullability.FLEXIBLE -> Nullability.PLATFORM
+ }
+ }
+
+ // TODO: fix calls to getKSTypeCached and use ksTypeArguments when available.
+ override val arguments: List<KSTypeArgument> by lazy {
+ (kotlinType.getAbbreviation() ?: kotlinType).arguments.map {
+ KSTypeArgumentDescriptorImpl.getCached(it, Origin.SYNTHETIC, null)
+ }
+ }
+
+ override fun isAssignableFrom(that: KSType): Boolean {
+ val subType = (that as? KSTypeImpl)?.kotlinType?.convertKotlinType() ?: return false
+ ResolverImpl.instance!!.incrementalContext.recordLookupWithSupertypes(subType)
+ val thisType = (this as? KSTypeImpl)?.kotlinType?.convertKotlinType() ?: return false
+ return subType.isSubtypeOf(thisType)
+ }
+
+ // TODO: find a better way to reuse the logic in [DescriptorRendererImpl.renderFlexibleType].
+ override fun isMutabilityFlexible(): Boolean {
+ return kotlinType.toString().startsWith("(Mutable)")
+ }
+
+ // TODO: find a better way to reuse the logic in [DescriptorRendererImpl.renderFlexibleType].
+ override fun isCovarianceFlexible(): Boolean {
+ return kotlinType.toString().startsWith("Array<(out) ")
+ }
+
+ override fun replace(arguments: List<KSTypeArgument>): KSType {
+ return kotlinType.replaceTypeArguments(arguments)?.let {
+ getKSTypeCached(it, arguments)
+ } ?: KSErrorType
+ }
+
+ override fun starProjection(): KSType {
+ return getKSTypeCached(kotlinType.replaceArgumentsWithStarProjections())
+ }
+
+ private val meNullable: KSType by lazy { getKSTypeCached(kotlinType.makeNullable()) }
+ override fun makeNullable(): KSType = meNullable
+
+ private val meNotNullable: KSType by lazy { getKSTypeCached(kotlinType.makeNotNullable()) }
+ override fun makeNotNullable(): KSType = meNotNullable
+
+ override val isMarkedNullable: Boolean = kotlinType.isMarkedNullable
+
+ override val isError: Boolean = false
+
+ override fun equals(other: Any?): Boolean {
+ if (other !is KSTypeImpl)
+ return false
+ return kotlinType.equals(other.kotlinType)
+ }
+
+ override fun hashCode(): Int = kotlinType.hashCode()
+
+ override fun toString(): String = (kotlinType.getAbbreviation() ?: kotlinType).toString()
+
+ override val isFunctionType: Boolean
+ get() = kotlinType.isFunctionType || kotlinType.isKFunctionType
+
+ override val isSuspendFunctionType: Boolean
+ get() = kotlinType.isSuspendFunctionType || kotlinType.isKSuspendFunctionType
+}
+
+fun getKSTypeCached(
+ kotlinType: KotlinType,
+ ksTypeArguments: List<KSTypeArgument>? = null,
+ annotations: Sequence<KSAnnotation> = sequenceOf()
+): KSType {
+ return if (kotlinType.isError ||
+ kotlinType.constructor.declarationDescriptor is NotFoundClasses.MockClassDescriptor
+ ) {
+ KSErrorType
+ } else {
+ KSTypeImpl.getCached(
+ kotlinType,
+ ksTypeArguments,
+ annotations + kotlinType.annotations
+ .filter { it.source == SourceElement.NO_SOURCE }
+ .map { KSAnnotationDescriptorImpl.getCached(it, null) }
+ .asSequence()
+ )
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeParameterImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeParameterImpl.kt
new file mode 100644
index 00000000..340833a4
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeParameterImpl.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.KSExpectActual
+import com.google.devtools.ksp.symbol.KSName
+import com.google.devtools.ksp.symbol.KSTypeParameter
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Variance
+import com.google.devtools.ksp.symbol.impl.synthetic.KSTypeReferenceSyntheticImpl
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtTypeParameter
+import org.jetbrains.kotlin.psi.KtTypeParameterListOwner
+
+class KSTypeParameterImpl private constructor(val ktTypeParameter: KtTypeParameter) :
+ KSTypeParameter,
+ KSDeclarationImpl(ktTypeParameter),
+ KSExpectActual by KSExpectActualNoImpl() {
+ companion object : KSObjectCache<KtTypeParameter, KSTypeParameterImpl>() {
+ fun getCached(ktTypeParameter: KtTypeParameter) =
+ cache.getOrPut(ktTypeParameter) { KSTypeParameterImpl(ktTypeParameter) }
+ }
+
+ override val name: KSName by lazy {
+ KSNameImpl.getCached(ktTypeParameter.name!!)
+ }
+
+ override val isReified: Boolean by lazy {
+ ktTypeParameter.modifierList?.hasModifier(KtTokens.REIFIED_KEYWORD) ?: false
+ }
+
+ override val variance: Variance by lazy {
+ when {
+ ktTypeParameter.modifierList == null -> Variance.INVARIANT
+ ktTypeParameter.modifierList!!.hasModifier(KtTokens.OUT_KEYWORD) -> Variance.COVARIANT
+ ktTypeParameter.modifierList!!.hasModifier(KtTokens.IN_KEYWORD) -> Variance.CONTRAVARIANT
+ else -> Variance.INVARIANT
+ }
+ }
+
+ private val owner: KtTypeParameterListOwner by lazy {
+ (parentDeclaration as KSDeclarationImpl).ktDeclaration as KtTypeParameterListOwner
+ }
+
+ override val bounds: Sequence<KSTypeReference> by lazy {
+ val list = sequenceOf(ktTypeParameter.extendsBound)
+ list.plus(
+ owner.typeConstraints
+ .filter {
+ it.subjectTypeParameterName!!.getReferencedName() == ktTypeParameter.nameAsSafeName.asString()
+ }
+ .map { it.boundTypeReference }
+ ).filterNotNull().map { KSTypeReferenceImpl.getCached(it) }.ifEmpty {
+ sequenceOf(
+ KSTypeReferenceSyntheticImpl.getCached(ResolverImpl.instance!!.builtIns.anyType.makeNullable(), this)
+ )
+ }.memoized()
+ }
+
+ override val qualifiedName: KSName? by lazy {
+ KSNameImpl.getCached("${this.parentDeclaration!!.qualifiedName!!.asString()}.${simpleName.asString()}")
+ }
+
+ override val simpleName: KSName by lazy {
+ KSNameImpl.getCached(ktTypeParameter.name ?: "_")
+ }
+
+ override val typeParameters: List<KSTypeParameter> = emptyList()
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeParameter(this, data)
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeReferenceDeferredImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeReferenceDeferredImpl.kt
new file mode 100644
index 00000000..16a74374
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeReferenceDeferredImpl.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSReferenceElement
+import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.symbol.NonExistLocation
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.impl.getInstanceForCurrentRound
+
+class KSTypeReferenceDeferredImpl private constructor(
+ private val resolver: () -> KSType,
+ override val parent: KSNode?
+) : KSTypeReference {
+ companion object : KSObjectCache<KSDeclaration, KSTypeReferenceDeferredImpl>() {
+ fun getCached(parent: KSDeclaration, resolver: () -> KSType): KSTypeReferenceDeferredImpl {
+ val currentParent = parent.getInstanceForCurrentRound() as KSDeclaration
+ return cache
+ .getOrPut(currentParent) { KSTypeReferenceDeferredImpl(resolver, currentParent) }
+ }
+ }
+
+ override val origin = Origin.KOTLIN
+
+ override val location: Location = NonExistLocation
+
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override val element: KSReferenceElement? = null
+
+ override val modifiers: Set<Modifier> = emptySet()
+
+ private val resolved: KSType by lazy {
+ resolver()
+ }
+
+ override fun resolve(): KSType = resolved
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeReference(this, data)
+ }
+
+ override fun toString(): String {
+ return resolved.toString()
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeReferenceImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeReferenceImpl.kt
new file mode 100644
index 00000000..9f751700
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSTypeReferenceImpl.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.ExceptionMessage
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSReferenceElement
+import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.impl.toLocation
+import com.google.devtools.ksp.toKSModifiers
+import org.jetbrains.kotlin.psi.*
+
+class KSTypeReferenceImpl private constructor(val ktTypeReference: KtTypeReference) : KSTypeReference {
+ companion object : KSObjectCache<KtTypeReference, KSTypeReferenceImpl>() {
+ fun getCached(ktTypeReference: KtTypeReference) = cache.getOrPut(ktTypeReference) {
+ KSTypeReferenceImpl(ktTypeReference)
+ }
+ }
+
+ override val origin = Origin.KOTLIN
+
+ override val location: Location by lazy {
+ ktTypeReference.toLocation()
+ }
+ override val parent: KSNode? by lazy {
+ var parentPsi = ktTypeReference.parent
+ while (
+ parentPsi != null && parentPsi !is KtAnnotationEntry && parentPsi !is KtFunctionType &&
+ parentPsi !is KtClassOrObject && parentPsi !is KtFunction && parentPsi !is KtUserType &&
+ parentPsi !is KtProperty && parentPsi !is KtTypeAlias && parentPsi !is KtTypeProjection &&
+ parentPsi !is KtTypeParameter && parentPsi !is KtParameter
+ ) {
+ parentPsi = parentPsi.parent
+ }
+ when (parentPsi) {
+ is KtAnnotationEntry -> KSAnnotationImpl.getCached(parentPsi)
+ is KtFunctionType -> KSCallableReferenceImpl.getCached(parentPsi)
+ is KtClassOrObject -> KSClassDeclarationImpl.getCached(parentPsi)
+ is KtFunction -> KSFunctionDeclarationImpl.getCached(parentPsi)
+ is KtUserType -> KSClassifierReferenceImpl.getCached(parentPsi)
+ is KtProperty -> KSPropertyDeclarationImpl.getCached(parentPsi)
+ is KtTypeAlias -> KSTypeAliasImpl.getCached(parentPsi)
+ is KtTypeProjection -> KSTypeArgumentKtImpl.getCached(parentPsi)
+ is KtTypeParameter -> KSTypeParameterImpl.getCached(parentPsi)
+ is KtParameter -> KSValueParameterImpl.getCached(parentPsi)
+ else -> null
+ }
+ }
+
+ // Parenthesized type in grammar seems to be implemented as KtNullableType.
+ private fun visitNullableType(visit: (KtNullableType) -> Unit) {
+ var typeElement = ktTypeReference.typeElement
+ while (typeElement is KtNullableType) {
+ visit(typeElement)
+ typeElement = typeElement.innerType
+ }
+ }
+
+ // Annotations and modifiers are only allowed in one of the parenthesized type.
+ // https://github.com/JetBrains/kotlin/blob/50e12239ef8141a45c4dca2bf0544be6191ecfb6/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java#L608
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ fun List<KtAnnotationEntry>.toKSAnnotations(): Sequence<KSAnnotation> =
+ asSequence().map {
+ KSAnnotationImpl.getCached(it)
+ }
+
+ val innerAnnotations = mutableListOf<Sequence<KSAnnotation>>()
+ visitNullableType {
+ innerAnnotations.add(it.annotationEntries.toKSAnnotations())
+ }
+
+ (ktTypeReference.annotationEntries.toKSAnnotations() + innerAnnotations.asSequence().flatten()).memoized()
+ }
+
+ override val modifiers: Set<Modifier> by lazy {
+ val innerModifiers = mutableSetOf<Modifier>()
+ visitNullableType {
+ innerModifiers.addAll(it.modifierList.toKSModifiers())
+ }
+ ktTypeReference.toKSModifiers() + innerModifiers
+ }
+
+ override val element: KSReferenceElement by lazy {
+ var typeElement = ktTypeReference.typeElement
+ while (typeElement is KtNullableType)
+ typeElement = typeElement.innerType
+ when (typeElement) {
+ is KtFunctionType -> KSCallableReferenceImpl.getCached(typeElement)
+ is KtUserType -> KSClassifierReferenceImpl.getCached(typeElement)
+ is KtDynamicType -> KSDynamicReferenceImpl.getCached(this)
+ is KtIntersectionType -> KSDefNonNullReferenceImpl.getCached(typeElement)
+ else -> throw IllegalStateException("Unexpected type element ${typeElement?.javaClass}, $ExceptionMessage")
+ }
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeReference(this, data)
+ }
+
+ override fun resolve(): KSType = ResolverImpl.instance!!.resolveUserType(this)
+
+ override fun toString(): String {
+ return element.toString()
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueArgumentImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueArgumentImpl.kt
new file mode 100644
index 00000000..aac1f416
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueArgumentImpl.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSName
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSValueArgument
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.NonExistLocation
+import com.google.devtools.ksp.symbol.Origin
+
+class KSValueArgumentLiteImpl private constructor(
+ override val name: KSName,
+ override val value: Any?,
+ override val parent: KSNode?,
+ override val origin: Origin
+) : KSValueArgumentImpl() {
+ companion object : KSObjectCache<Triple<KSName, Any?, KSNode>, KSValueArgumentLiteImpl>() {
+
+ fun getCached(name: KSName, value: Any?, parent: KSNode, origin: Origin = Origin.KOTLIN) = cache
+ .getOrPut(Triple(name, value, parent)) {
+ KSValueArgumentLiteImpl(name, value, parent, origin)
+ }
+ }
+
+ override val location: Location = NonExistLocation
+
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override val isSpread: Boolean = false
+}
+
+abstract class KSValueArgumentImpl : KSValueArgument {
+ override fun hashCode(): Int {
+ return name.hashCode() * 31 + value.hashCode()
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (other !is KSValueArgument)
+ return false
+
+ return other.name == this.name && other.value == this.value
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitValueArgument(this, data)
+ }
+
+ override fun toString(): String {
+ return "${name?.asString() ?: ""}:$value"
+ }
+}
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
new file mode 100644
index 00000000..162d77fa
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/kotlin/KSValueParameterImpl.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.processing.impl.findAnnotationFromUseSiteTarget
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSName
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSValueParameter
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.impl.synthetic.KSTypeReferenceSyntheticImpl
+import com.google.devtools.ksp.symbol.impl.toLocation
+import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
+import org.jetbrains.kotlin.lexer.KtTokens.CROSSINLINE_KEYWORD
+import org.jetbrains.kotlin.lexer.KtTokens.NOINLINE_KEYWORD
+import org.jetbrains.kotlin.psi.KtAnnotationEntry
+import org.jetbrains.kotlin.psi.KtFunction
+import org.jetbrains.kotlin.psi.KtFunctionType
+import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.kotlin.psi.KtProperty
+import org.jetbrains.kotlin.psi.KtPropertyAccessor
+
+class KSValueParameterImpl private constructor(val ktParameter: KtParameter) : KSValueParameter {
+ companion object : KSObjectCache<KtParameter, KSValueParameterImpl>() {
+ fun getCached(ktParameter: KtParameter) = cache.getOrPut(ktParameter) { KSValueParameterImpl(ktParameter) }
+ }
+
+ override val origin = Origin.KOTLIN
+
+ override val location: Location by lazy {
+ ktParameter.toLocation()
+ }
+
+ override val parent: KSNode? by lazy {
+ var parentPsi = ktParameter.parent
+ while (
+ parentPsi != null && parentPsi !is KtAnnotationEntry && parentPsi !is KtFunctionType &&
+ parentPsi !is KtFunction && parentPsi !is KtPropertyAccessor
+ ) {
+ parentPsi = parentPsi.parent
+ }
+ when (parentPsi) {
+ is KtAnnotationEntry -> KSAnnotationImpl.getCached(parentPsi)
+ is KtFunctionType -> KSCallableReferenceImpl.getCached(parentPsi)
+ is KtFunction -> KSFunctionDeclarationImpl.getCached(parentPsi)
+ is KtPropertyAccessor -> if (parentPsi.isSetter) KSPropertySetterImpl.getCached(parentPsi) else null
+ else -> null
+ }
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ ktParameter.annotationEntries.asSequence().filter { annotation ->
+ annotation.useSiteTarget?.getAnnotationUseSiteTarget()?.let {
+ it != AnnotationUseSiteTarget.PROPERTY_GETTER &&
+ it != AnnotationUseSiteTarget.PROPERTY_SETTER &&
+ it != AnnotationUseSiteTarget.SETTER_PARAMETER &&
+ it != AnnotationUseSiteTarget.FIELD
+ } ?: true
+ }.map { KSAnnotationImpl.getCached(it) }.filterNot { valueParameterAnnotation ->
+ valueParameterAnnotation.annotationType.resolve().declaration.annotations.any { metaAnnotation ->
+ metaAnnotation.annotationType.resolve().declaration.qualifiedName
+ ?.asString() == "kotlin.annotation.Target" &&
+ (metaAnnotation.arguments.singleOrNull()?.value as? ArrayList<*>)?.none {
+ (it as? KSType)?.declaration?.qualifiedName
+ ?.asString() == "kotlin.annotation.AnnotationTarget.VALUE_PARAMETER"
+ } ?: false
+ }
+ }
+ .plus(this.findAnnotationFromUseSiteTarget()).memoized()
+ }
+
+ override val isCrossInline: Boolean = ktParameter.hasModifier(CROSSINLINE_KEYWORD)
+
+ override val isNoInline: Boolean = ktParameter.hasModifier(NOINLINE_KEYWORD)
+
+ override val isVararg: Boolean = ktParameter.isVarArg
+
+ override val isVal = ktParameter.hasValOrVar() && !ktParameter.isMutable
+
+ override val isVar = ktParameter.hasValOrVar() && ktParameter.isMutable
+
+ override val name: KSName? by lazy {
+ if (ktParameter.name == null) {
+ null
+ } else {
+ KSNameImpl.getCached(ktParameter.name!!)
+ }
+ }
+
+ override val type: KSTypeReference by lazy {
+ ktParameter.typeReference?.let { KSTypeReferenceImpl.getCached(it) }
+ ?: findPropertyForAccessor()?.type ?: KSTypeReferenceSyntheticImpl.getCached(KSErrorType, this)
+ }
+
+ override val hasDefault: Boolean = ktParameter.hasDefaultValue()
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitValueParameter(this, data)
+ }
+
+ override fun toString(): String {
+ return name?.asString() ?: "_"
+ }
+
+ private fun findPropertyForAccessor(): KSPropertyDeclaration? {
+ return (ktParameter.parent?.parent?.parent as? KtProperty)?.let { KSPropertyDeclarationImpl.getCached(it) }
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSConstructorSyntheticImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSConstructorSyntheticImpl.kt
new file mode 100644
index 00000000..19108d99
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSConstructorSyntheticImpl.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.synthetic
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.isPublic
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+
+class KSConstructorSyntheticImpl private constructor(val ksClassDeclaration: KSClassDeclaration) :
+ KSFunctionDeclaration,
+ KSDeclaration
+ by ksClassDeclaration {
+ companion object : KSObjectCache<KSClassDeclaration, KSConstructorSyntheticImpl>() {
+ fun getCached(ksClassDeclaration: KSClassDeclaration) =
+ KSConstructorSyntheticImpl.cache.getOrPut(ksClassDeclaration) {
+ KSConstructorSyntheticImpl(ksClassDeclaration)
+ }
+ }
+
+ override val isAbstract: Boolean = false
+
+ override val extensionReceiver: KSTypeReference? = null
+
+ override val parameters: List<KSValueParameter> = emptyList()
+
+ override val functionKind: FunctionKind = FunctionKind.MEMBER
+
+ override val qualifiedName: KSName? by lazy {
+ KSNameImpl.getCached(ksClassDeclaration.qualifiedName?.asString()?.plus(".<init>") ?: "")
+ }
+
+ override val simpleName: KSName by lazy {
+ KSNameImpl.getCached("<init>")
+ }
+
+ override val typeParameters: List<KSTypeParameter> = emptyList()
+
+ override val containingFile: KSFile? by lazy {
+ ksClassDeclaration.containingFile
+ }
+
+ override val parentDeclaration: KSDeclaration? by lazy {
+ ksClassDeclaration
+ }
+
+ override val parent: KSNode? by lazy {
+ parentDeclaration
+ }
+
+ override val returnType: KSTypeReference by lazy {
+ KSTypeReferenceSyntheticImpl(
+ ksClassDeclaration.asStarProjectedType(), this
+ )
+ }
+
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override val isActual: Boolean = false
+
+ override val isExpect: Boolean = false
+
+ override val declarations: Sequence<KSDeclaration> = emptySequence()
+
+ override val location: Location by lazy {
+ ksClassDeclaration.location
+ }
+
+ override val modifiers: Set<Modifier> by lazy {
+ if (ksClassDeclaration.classKind == ClassKind.ENUM_CLASS) {
+ return@lazy setOf(Modifier.FINAL, Modifier.PRIVATE)
+ }
+ // add public if parent class is public
+ if (ksClassDeclaration.isPublic()) {
+ setOf(Modifier.FINAL, Modifier.PUBLIC)
+ } else {
+ setOf(Modifier.FINAL)
+ }
+ }
+
+ override val origin: Origin = Origin.SYNTHETIC
+
+ override fun findOverridee(): KSFunctionDeclaration? = null
+
+ override fun findActuals(): Sequence<KSDeclaration> {
+ return emptySequence()
+ }
+
+ override fun findExpects(): Sequence<KSDeclaration> {
+ return emptySequence()
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitFunctionDeclaration(this, data)
+ }
+
+ override fun toString(): String {
+ return "synthetic constructor for ${this.parentDeclaration}"
+ }
+
+ override fun asMemberOf(containing: KSType): KSFunction =
+ ResolverImpl.instance!!.asMemberOf(this, containing)
+}
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
new file mode 100644
index 00000000..2a71233b
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSErrorTypeClassDeclaration.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.
+ */
+
+package com.google.devtools.ksp.symbol.impl.synthetic
+
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+
+object KSErrorTypeClassDeclaration : KSClassDeclaration {
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override val classKind: ClassKind = ClassKind.CLASS
+
+ override val containingFile: KSFile? = null
+
+ override val declarations: Sequence<KSDeclaration> = emptySequence()
+
+ override val isActual: Boolean = false
+
+ override val isExpect: Boolean = false
+
+ override val isCompanionObject: Boolean = false
+
+ override val location: Location = NonExistLocation
+
+ override val parent: KSNode? = null
+
+ override val modifiers: Set<Modifier> = emptySet()
+
+ override val origin: Origin = Origin.SYNTHETIC
+
+ override val packageName: KSName = KSNameImpl.getCached("")
+
+ override val parentDeclaration: KSDeclaration? = null
+
+ override val primaryConstructor: KSFunctionDeclaration? = null
+
+ override val qualifiedName: KSName? = null
+
+ override val simpleName: KSName = KSNameImpl.getCached("<Error>")
+
+ override val superTypes: Sequence<KSTypeReference> = emptySequence()
+
+ override val typeParameters: List<KSTypeParameter> = emptyList()
+
+ override fun getSealedSubclasses(): Sequence<KSClassDeclaration> = emptySequence()
+
+ override fun asStarProjectedType(): KSType {
+ return ResolverImpl.instance!!.builtIns.nothingType
+ }
+
+ override fun asType(typeArguments: List<KSTypeArgument>): KSType {
+ return ResolverImpl.instance!!.builtIns.nothingType
+ }
+
+ override fun findActuals(): Sequence<KSDeclaration> {
+ return emptySequence()
+ }
+
+ override fun findExpects(): Sequence<KSDeclaration> {
+ return emptySequence()
+ }
+
+ override fun getAllFunctions(): Sequence<KSFunctionDeclaration> {
+ return emptySequence()
+ }
+
+ override fun getAllProperties(): Sequence<KSPropertyDeclaration> {
+ return emptySequence()
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitClassDeclaration(this, data)
+ }
+
+ override fun toString(): String {
+ return "Error type synthetic declaration"
+ }
+
+ override val docString = null
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSPropertyAccessorSyntheticImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSPropertyAccessorSyntheticImpl.kt
new file mode 100644
index 00000000..f6f0ad9f
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSPropertyAccessorSyntheticImpl.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.synthetic
+
+import com.google.devtools.ksp.processing.impl.findAnnotationFromUseSiteTarget
+import com.google.devtools.ksp.symbol.*
+
+abstract class KSPropertyAccessorSyntheticImpl(ksPropertyDeclaration: KSPropertyDeclaration) : KSPropertyAccessor {
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ this.findAnnotationFromUseSiteTarget()
+ }
+
+ override val location: Location by lazy {
+ ksPropertyDeclaration.location
+ }
+
+ override val modifiers: Set<Modifier> = emptySet()
+
+ override val origin: Origin = Origin.SYNTHETIC
+
+ override val receiver: KSPropertyDeclaration = ksPropertyDeclaration
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertyAccessor(this, data)
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSPropertyGetterSyntheticImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSPropertyGetterSyntheticImpl.kt
new file mode 100644
index 00000000..70455bb3
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSPropertyGetterSyntheticImpl.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.synthetic
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSPropertyGetter
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.impl.binary.KSTypeReferenceDescriptorImpl
+import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
+
+class KSPropertyGetterSyntheticImpl(val ksPropertyDeclaration: KSPropertyDeclaration) :
+ KSPropertyAccessorSyntheticImpl(ksPropertyDeclaration), KSPropertyGetter {
+ companion object : KSObjectCache<KSPropertyDeclaration, KSPropertyGetterSyntheticImpl>() {
+ fun getCached(ksPropertyDeclaration: KSPropertyDeclaration) =
+ KSPropertyGetterSyntheticImpl.cache.getOrPut(ksPropertyDeclaration) {
+ KSPropertyGetterSyntheticImpl(ksPropertyDeclaration)
+ }
+ }
+
+ private val descriptor: PropertyAccessorDescriptor by lazy {
+ ResolverImpl.instance!!.resolvePropertyDeclaration(ksPropertyDeclaration)!!.getter!!
+ }
+
+ override val returnType: KSTypeReference? by lazy {
+ if (descriptor.returnType != null) {
+ KSTypeReferenceDescriptorImpl.getCached(descriptor.returnType!!, origin, this)
+ } else {
+ null
+ }
+ }
+ override val parent: KSNode? = ksPropertyDeclaration
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertyGetter(this, data)
+ }
+
+ override fun toString(): String {
+ return "$receiver.getter()"
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSPropertySetterSyntheticImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSPropertySetterSyntheticImpl.kt
new file mode 100644
index 00000000..c8120e55
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSPropertySetterSyntheticImpl.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.symbol.impl.synthetic
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSPropertySetter
+import com.google.devtools.ksp.symbol.KSValueParameter
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.impl.binary.KSValueParameterDescriptorImpl
+import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
+
+class KSPropertySetterSyntheticImpl(val ksPropertyDeclaration: KSPropertyDeclaration) :
+ KSPropertyAccessorSyntheticImpl(ksPropertyDeclaration), KSPropertySetter {
+ companion object : KSObjectCache<KSPropertyDeclaration, KSPropertySetterSyntheticImpl>() {
+ fun getCached(ksPropertyDeclaration: KSPropertyDeclaration) =
+ KSPropertySetterSyntheticImpl.cache.getOrPut(ksPropertyDeclaration) {
+ KSPropertySetterSyntheticImpl(ksPropertyDeclaration)
+ }
+ }
+
+ private val descriptor: PropertyAccessorDescriptor by lazy {
+ ResolverImpl.instance!!.resolvePropertyDeclaration(ksPropertyDeclaration)!!.setter!!
+ }
+
+ override val parameter: KSValueParameter by lazy {
+ descriptor.valueParameters.singleOrNull()?.let { KSValueParameterDescriptorImpl.getCached(it, this) }
+ ?: throw IllegalStateException("Failed to resolve property type")
+ }
+
+ override val parent: KSNode? = ksPropertyDeclaration
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertySetter(this, data)
+ }
+
+ override fun toString(): String {
+ return "$receiver.getter()"
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSTypeReferenceSyntheticImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSTypeReferenceSyntheticImpl.kt
new file mode 100644
index 00000000..aa2631e4
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSTypeReferenceSyntheticImpl.kt
@@ -0,0 +1,43 @@
+package com.google.devtools.ksp.symbol.impl.synthetic
+
+import com.google.devtools.ksp.IdKey
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSReferenceElement
+import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.symbol.NonExistLocation
+import com.google.devtools.ksp.symbol.Origin
+
+class KSTypeReferenceSyntheticImpl(val ksType: KSType, override val parent: KSNode?) : KSTypeReference {
+ companion object : KSObjectCache<Pair<IdKey<KSType>, KSNode?>, KSTypeReferenceSyntheticImpl>() {
+ fun getCached(ksType: KSType, parent: KSNode?) = KSTypeReferenceSyntheticImpl.cache
+ .getOrPut(Pair(IdKey(ksType), parent)) { KSTypeReferenceSyntheticImpl(ksType, parent) }
+ }
+
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override val element: KSReferenceElement? = null
+
+ override val location: Location = NonExistLocation
+
+ override val modifiers: Set<Modifier> = emptySet()
+
+ override val origin: Origin = Origin.SYNTHETIC
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeReference(this, data)
+ }
+
+ override fun resolve(): KSType {
+ return ksType
+ }
+
+ override fun toString(): String {
+ return ksType.toString()
+ }
+}
diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSValueParameterSyntheticImpl.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSValueParameterSyntheticImpl.kt
new file mode 100644
index 00000000..6e5692b2
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/synthetic/KSValueParameterSyntheticImpl.kt
@@ -0,0 +1,76 @@
+package com.google.devtools.ksp.symbol.impl.synthetic
+
+import com.google.devtools.ksp.ExceptionMessage
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.processing.impl.findAnnotationFromUseSiteTarget
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSName
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSValueParameter
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.NonExistLocation
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.impl.binary.KSAnnotationDescriptorImpl
+import com.google.devtools.ksp.symbol.impl.binary.KSTypeReferenceDescriptorImpl
+import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
+import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
+import org.jetbrains.kotlin.resolve.calls.components.isVararg
+
+class KSValueParameterSyntheticImpl(val owner: KSAnnotated?, resolve: () -> ValueParameterDescriptor?) :
+ KSValueParameter {
+
+ companion object :
+ KSObjectCache<Pair<KSAnnotated?, () -> ValueParameterDescriptor?>, KSValueParameterSyntheticImpl>() {
+ fun getCached(owner: KSAnnotated? = null, resolve: () -> ValueParameterDescriptor?) =
+ KSValueParameterSyntheticImpl.cache.getOrPut(Pair(owner, resolve)) {
+ KSValueParameterSyntheticImpl(owner, resolve)
+ }
+ }
+
+ private val descriptor by lazy {
+ resolve() ?: throw IllegalStateException("Failed to resolve for synthetic value parameter, $ExceptionMessage")
+ }
+
+ override val name: KSName? by lazy {
+ KSNameImpl.getCached(descriptor.name.asString())
+ }
+
+ override val type: KSTypeReference by lazy {
+ KSTypeReferenceDescriptorImpl.getCached(descriptor.type, origin, this)
+ }
+
+ override val isVararg: Boolean = descriptor.isVararg
+
+ override val isNoInline: Boolean = descriptor.isNoinline
+
+ override val isCrossInline: Boolean = descriptor.isCrossinline
+
+ override val isVal: Boolean = !descriptor.isVar
+
+ override val isVar: Boolean = descriptor.isVar
+
+ override val hasDefault: Boolean = descriptor.hasDefaultValue()
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ descriptor.annotations.asSequence()
+ .map { KSAnnotationDescriptorImpl.getCached(it, this) }.plus(this.findAnnotationFromUseSiteTarget())
+ }
+
+ override val origin: Origin = Origin.SYNTHETIC
+
+ override val location: Location = NonExistLocation
+
+ override val parent: KSNode? = owner
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitValueParameter(this, data)
+ }
+
+ override fun toString(): String {
+ return name?.asString() ?: "_"
+ }
+}
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
new file mode 100644
index 00000000..4e19baf1
--- /dev/null
+++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/utils.kt
@@ -0,0 +1,559 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.symbol.impl
+
+import com.google.devtools.ksp.BinaryClassInfoCache
+import com.google.devtools.ksp.ExceptionMessage
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.processing.impl.workaroundForNested
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.Variance
+import com.google.devtools.ksp.symbol.impl.binary.KSClassDeclarationDescriptorImpl
+import com.google.devtools.ksp.symbol.impl.binary.KSDeclarationDescriptorImpl
+import com.google.devtools.ksp.symbol.impl.binary.KSFunctionDeclarationDescriptorImpl
+import com.google.devtools.ksp.symbol.impl.binary.KSPropertyDeclarationDescriptorImpl
+import com.google.devtools.ksp.symbol.impl.binary.KSTypeArgumentDescriptorImpl
+import com.google.devtools.ksp.symbol.impl.java.*
+import com.google.devtools.ksp.symbol.impl.kotlin.*
+import com.google.devtools.ksp.symbol.impl.synthetic.KSPropertyGetterSyntheticImpl
+import com.google.devtools.ksp.symbol.impl.synthetic.KSPropertySetterSyntheticImpl
+import com.google.devtools.ksp.symbol.impl.synthetic.KSValueParameterSyntheticImpl
+import com.intellij.psi.*
+import com.intellij.psi.impl.light.LightMethod
+import com.intellij.psi.impl.source.PsiClassImpl
+import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMapper
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.load.java.descriptors.JavaClassConstructorDescriptor
+import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
+import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
+import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
+import org.jetbrains.kotlin.load.java.structure.impl.JavaConstructorImpl
+import org.jetbrains.kotlin.load.java.structure.impl.JavaMethodImpl
+import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaField
+import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaMethodBase
+import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
+import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
+import org.jetbrains.kotlin.load.kotlin.getContainingKotlinJvmBinaryClass
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
+import org.jetbrains.kotlin.resolve.descriptorUtil.getOwnerForEffectiveDispatchReceiverParameter
+import org.jetbrains.kotlin.resolve.source.getPsi
+import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
+import org.jetbrains.kotlin.types.*
+import java.util.*
+import kotlin.Comparator
+import kotlin.collections.ArrayDeque
+
+fun PsiElement.findParentAnnotated(): KSAnnotated? {
+ var parent = when (this) {
+ // Unfortunately, LightMethod doesn't implement parent.
+ is LightMethod -> this.containingClass
+ else -> this.parent
+ }
+
+ while (parent != null && parent !is KtDeclaration && parent !is KtFile && parent !is PsiClass &&
+ parent !is PsiMethod && parent !is PsiJavaFile && parent !is KtTypeAlias
+ ) {
+ parent = parent.parent
+ }
+
+ return when (parent) {
+ is KtClassOrObject -> KSClassDeclarationImpl.getCached(parent)
+ is KtFile -> KSFileImpl.getCached(parent)
+ is KtFunction -> KSFunctionDeclarationImpl.getCached(parent)
+ is PsiClass -> KSClassDeclarationJavaImpl.getCached(parent)
+ is PsiJavaFile -> KSFileJavaImpl.getCached(parent)
+ is PsiMethod -> KSFunctionDeclarationJavaImpl.getCached(parent)
+ is KtProperty -> KSPropertyDeclarationImpl.getCached(parent)
+ is KtPropertyAccessor -> if (parent.isGetter) {
+ KSPropertyGetterImpl.getCached(parent)
+ } else {
+ KSPropertySetterImpl.getCached(parent)
+ }
+ is KtTypeAlias -> KSTypeAliasImpl.getCached(parent)
+ else -> null
+ }
+}
+
+fun PsiElement.findParentDeclaration(): KSDeclaration? {
+ return this.findParentAnnotated() as? KSDeclaration
+}
+
+fun PsiElement.toLocation(): Location {
+ val file = this.containingFile
+ val document = ResolverImpl.instance!!.psiDocumentManager.getDocument(file) ?: return NonExistLocation
+ return FileLocation(file.virtualFile.path, document.getLineNumber(this.textOffset) + 1)
+}
+
+// TODO: handle local functions/classes correctly
+fun Sequence<KtElement>.getKSDeclarations(): Sequence<KSDeclaration> =
+ this.mapNotNull {
+ when (it) {
+ is KtFunction -> KSFunctionDeclarationImpl.getCached(it)
+ is KtProperty -> KSPropertyDeclarationImpl.getCached(it)
+ is KtClassOrObject -> KSClassDeclarationImpl.getCached(it)
+ is KtTypeAlias -> KSTypeAliasImpl.getCached(it)
+ else -> null
+ }
+ }
+
+fun List<PsiElement>.getKSJavaDeclarations() =
+ this.mapNotNull {
+ when (it) {
+ is PsiClass -> KSClassDeclarationJavaImpl.getCached(it)
+ is PsiMethod -> KSFunctionDeclarationJavaImpl.getCached(it)
+ is PsiField -> KSPropertyDeclarationJavaImpl.getCached(it)
+ else -> null
+ }
+ }
+
+fun org.jetbrains.kotlin.types.Variance.toKSVariance(): Variance {
+ return when (this) {
+ org.jetbrains.kotlin.types.Variance.IN_VARIANCE -> Variance.CONTRAVARIANT
+ org.jetbrains.kotlin.types.Variance.OUT_VARIANCE -> Variance.COVARIANT
+ org.jetbrains.kotlin.types.Variance.INVARIANT -> Variance.INVARIANT
+ else -> throw IllegalStateException("Unexpected variance value $this, $ExceptionMessage")
+ }
+}
+
+private fun KSTypeReference.toKotlinType() = (resolve() as? KSTypeImpl)?.kotlinType
+
+// returns null if error
+internal fun KotlinType.replaceTypeArguments(newArguments: List<KSTypeArgument>): KotlinType? {
+ if (newArguments.isNotEmpty() && this.arguments.size != newArguments.size)
+ return null
+ return replace(
+ newArguments.mapIndexed { index, ksTypeArgument ->
+ val variance = when (ksTypeArgument.variance) {
+ Variance.INVARIANT -> org.jetbrains.kotlin.types.Variance.INVARIANT
+ Variance.COVARIANT -> org.jetbrains.kotlin.types.Variance.OUT_VARIANCE
+ Variance.CONTRAVARIANT -> org.jetbrains.kotlin.types.Variance.IN_VARIANCE
+ Variance.STAR -> return@mapIndexed StarProjectionImpl(constructor.parameters[index])
+ }
+
+ val type = when (ksTypeArgument) {
+ is KSTypeArgumentKtImpl, is KSTypeArgumentJavaImpl, is KSTypeArgumentLiteImpl -> ksTypeArgument.type!!
+ is KSTypeArgumentDescriptorImpl -> return@mapIndexed ksTypeArgument.descriptor
+ else -> throw IllegalStateException(
+ "Unexpected psi for type argument: ${ksTypeArgument.javaClass}, $ExceptionMessage"
+ )
+ }.toKotlinType() ?: return null
+
+ TypeProjectionImpl(variance, type)
+ }
+ )
+}
+
+internal fun FunctionDescriptor.toKSDeclaration(): KSDeclaration {
+ if (this.kind != CallableMemberDescriptor.Kind.DECLARATION)
+ return KSFunctionDeclarationDescriptorImpl.getCached(this)
+ val psi = this.findPsi() ?: return KSFunctionDeclarationDescriptorImpl.getCached(this)
+ // Java default constructor has a kind DECLARATION of while still being synthetic.
+ if (psi is PsiClassImpl && this is JavaClassConstructorDescriptor) {
+ return KSFunctionDeclarationDescriptorImpl.getCached(this)
+ }
+ return when (psi) {
+ is KtFunction -> KSFunctionDeclarationImpl.getCached(psi)
+ is PsiMethod -> KSFunctionDeclarationJavaImpl.getCached(psi)
+ is KtProperty -> KSPropertyDeclarationImpl.getCached(psi)
+ else -> throw IllegalStateException("unexpected psi: ${psi.javaClass}")
+ }
+}
+
+internal fun PropertyDescriptor.toKSPropertyDeclaration(): KSPropertyDeclaration {
+ if (this.kind != CallableMemberDescriptor.Kind.DECLARATION)
+ return KSPropertyDeclarationDescriptorImpl.getCached(this)
+ val psi = this.findPsi() ?: return KSPropertyDeclarationDescriptorImpl.getCached(this)
+ return when (psi) {
+ is KtProperty -> KSPropertyDeclarationImpl.getCached(psi)
+ is KtParameter -> KSPropertyDeclarationParameterImpl.getCached(psi)
+ is PsiField -> KSPropertyDeclarationJavaImpl.getCached(psi)
+ is PsiMethod -> {
+ // happens when a java class implements a kotlin interface that declares properties.
+ KSPropertyDeclarationDescriptorImpl.getCached(this)
+ }
+ else -> throw IllegalStateException("unexpected psi: ${psi.javaClass}")
+ }
+}
+
+/**
+ * @see KSFunctionDeclaration.findOverridee / [KSPropertyDeclaration.findOverridee] for docs.
+ */
+internal inline fun <reified T : CallableMemberDescriptor> T.findClosestOverridee(): T? {
+ // When there is an intermediate class between the overridden and our function, we might receive
+ // a FAKE_OVERRIDE function which is not desired as we are trying to find the actual
+ // declared method.
+
+ // we also want to return the closes function declaration. That is either the closest
+ // class / interface method OR in case of equal distance (e.g. diamon dinheritance), pick the
+ // one declared first in the code.
+
+ (getOwnerForEffectiveDispatchReceiverParameter() as? ClassDescriptor)?.defaultType?.let {
+ ResolverImpl.instance!!.incrementalContext.recordLookupWithSupertypes(it)
+ }
+
+ val queue = ArrayDeque<T>()
+ queue.add(this)
+
+ while (queue.isNotEmpty()) {
+ val current = queue.removeFirst()
+ ResolverImpl.instance!!.incrementalContext.recordLookupForCallableMemberDescriptor(current.original)
+ val overriddenDescriptors: Collection<T> = current.original.overriddenDescriptors.filterIsInstance<T>()
+ overriddenDescriptors.firstOrNull {
+ it.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE
+ }?.let {
+ ResolverImpl.instance!!.incrementalContext.recordLookupForCallableMemberDescriptor(it.original)
+ return it.original as T?
+ }
+ // if all methods are fake, add them to the queue
+ queue.addAll(overriddenDescriptors)
+ }
+ return null
+}
+
+internal fun ModuleClassResolver.resolveContainingClass(psiMethod: PsiMethod): ClassDescriptor? {
+ return if (psiMethod.isConstructor) {
+ resolveClass(JavaConstructorImpl(psiMethod).containingClass.apply { workaroundForNested() })
+ } else {
+ resolveClass(JavaMethodImpl(psiMethod).containingClass.apply { workaroundForNested() })
+ }
+}
+
+internal fun getInstanceForCurrentRound(node: KSNode): KSNode? {
+ return when (node.origin) {
+ Origin.KOTLIN_LIB, Origin.JAVA_LIB -> null
+ else -> when (node) {
+ is KSClassDeclarationImpl -> KSClassDeclarationImpl.getCached(node.ktClassOrObject)
+ is KSFileImpl -> KSFileImpl.getCached(node.file)
+ is KSFunctionDeclarationImpl -> KSFunctionDeclarationImpl.getCached(node.ktFunction)
+ is KSPropertyDeclarationImpl -> KSPropertyDeclarationImpl.getCached(node.ktProperty)
+ is KSPropertyGetterImpl -> KSPropertyGetterImpl.getCached(node.ktPropertyAccessor)
+ is KSPropertySetterImpl -> KSPropertySetterImpl.getCached(node.ktPropertyAccessor)
+ is KSTypeAliasImpl -> KSTypeAliasImpl.getCached(node.ktTypeAlias)
+ is KSTypeArgumentLiteImpl -> KSTypeArgumentLiteImpl.getCached(node.type, node.variance)
+ is KSTypeArgumentKtImpl -> KSTypeArgumentKtImpl.getCached(node.ktTypeArgument)
+ is KSTypeParameterImpl -> KSTypeParameterImpl.getCached(node.ktTypeParameter)
+ is KSTypeReferenceImpl -> KSTypeReferenceImpl.getCached(node.ktTypeReference)
+ is KSValueParameterImpl -> KSValueParameterImpl.getCached(node.ktParameter)
+ is KSClassDeclarationJavaEnumEntryImpl -> KSClassDeclarationJavaEnumEntryImpl.getCached(node.psi)
+ is KSClassDeclarationJavaImpl -> KSClassDeclarationJavaImpl.getCached(node.psi)
+ is KSFileJavaImpl -> KSFileJavaImpl.getCached(node.psi)
+ is KSFunctionDeclarationJavaImpl -> KSFunctionDeclarationJavaImpl.getCached(node.psi)
+ is KSPropertyDeclarationJavaImpl -> KSPropertyDeclarationJavaImpl.getCached(node.psi)
+ is KSTypeArgumentJavaImpl -> KSTypeArgumentJavaImpl.getCached(node.psi, node.parent)
+ is KSTypeParameterJavaImpl -> KSTypeParameterJavaImpl.getCached(node.psi)
+ is KSTypeReferenceJavaImpl ->
+ KSTypeReferenceJavaImpl.getCached(node.psi, (node.parent as? KSAnnotated)?.getInstanceForCurrentRound())
+ is KSValueParameterJavaImpl -> KSValueParameterJavaImpl.getCached(node.psi)
+ is KSPropertyGetterSyntheticImpl -> KSPropertyGetterSyntheticImpl.getCached(node.ksPropertyDeclaration)
+ is KSPropertySetterSyntheticImpl -> KSPropertySetterSyntheticImpl.getCached(node.ksPropertyDeclaration)
+ is KSValueParameterSyntheticImpl ->
+ KSPropertySetterImpl.getCached(node.owner as KtPropertyAccessor).parameter
+ is KSAnnotationJavaImpl -> KSAnnotationJavaImpl.getCached(node.psi)
+ is KSAnnotationImpl -> KSAnnotationImpl.getCached(node.ktAnnotationEntry)
+ is KSClassifierReferenceJavaImpl -> KSClassifierReferenceJavaImpl.getCached(node.psi, node.parent)
+ is KSValueArgumentJavaImpl ->
+ KSValueArgumentJavaImpl.getCached(node.name, node.value, getInstanceForCurrentRound(node.parent!!))
+ else -> null
+ }
+ }
+}
+
+internal fun KSAnnotated.getInstanceForCurrentRound(): KSAnnotated? = getInstanceForCurrentRound(this) as? KSAnnotated
+
+/**
+ * Helper class to read the order of fields/methods in a .class file compiled from Kotlin.
+ *
+ * When a compiled Kotlin class is read from descriptors, the order of fields / methods do not match
+ * the order in the original source file (or the .class file).
+ * This helper class reads the order from the binary class (using the visitor API) and allows
+ * [KSClassDeclarationDescriptorImpl] to sort its declarations based on the .class file.
+ *
+ * Note that the ordering is relevant only for fields and methods. For any other declaration, the
+ * order that was returned from the descriptor API is kept.
+ *
+ * see: https://github.com/google/ksp/issues/250
+ */
+@KspExperimental
+internal class DeclarationOrdering(
+ binaryClass: KotlinJvmBinaryClass
+) : KotlinJvmBinaryClass.MemberVisitor {
+ // Map of fieldName -> Order
+ private val fieldOrdering = mutableMapOf<String, Int>()
+ // Map of method name to (jvm desc -> Order) map
+ // multiple methods might have the same name, hence we need to use signature matching for
+ // methods. That being said, we only do it when we find multiple methods with the same name
+ // otherwise, there is no reason to compute the jvm signature.
+ private val methodOrdering = mutableMapOf<String, MutableMap<String, Int>>()
+ // This map is built while we are sorting to ensure for the same declaration, we return the same
+ // order, in case it is not found in fields / methods.
+ private val declOrdering = IdentityHashMap<KSDeclaration, Int>()
+ // Helper class to generate ids that can be used for comparison.
+ private val orderProvider = OrderProvider()
+
+ init {
+ binaryClass.visitMembers(this, null)
+ orderProvider.seal()
+ }
+
+ val comparator = Comparator<KSDeclarationDescriptorImpl> { first, second ->
+ getOrder(first).compareTo(getOrder(second))
+ }
+
+ private fun getOrder(decl: KSDeclarationDescriptorImpl): Int {
+ return declOrdering.getOrPut(decl) {
+ when (decl) {
+ is KSPropertyDeclarationDescriptorImpl -> {
+ fieldOrdering[decl.simpleName.asString()]?.let {
+ return@getOrPut it
+ }
+ // might be a property without backing field. Use method ordering instead
+ decl.getter?.let { getter ->
+ return@getOrPut findMethodOrder(
+ ResolverImpl.instance!!.getJvmName(getter).toString()
+ ) {
+ ResolverImpl.instance!!.mapToJvmSignature(getter)
+ }
+ }
+ decl.setter?.let { setter ->
+ return@getOrPut findMethodOrder(
+ ResolverImpl.instance!!.getJvmName(setter).toString()
+ ) {
+ ResolverImpl.instance!!.mapToJvmSignature(setter)
+ }
+ }
+ orderProvider.next(decl)
+ }
+ is KSFunctionDeclarationDescriptorImpl -> {
+ findMethodOrder(
+ ResolverImpl.instance!!.getJvmName(decl).toString()
+ ) {
+ ResolverImpl.instance!!.mapToJvmSignature(decl).toString()
+ }
+ }
+ else -> orderProvider.nextIgnoreSealed()
+ }
+ }
+ }
+
+ private inline fun findMethodOrder(
+ jvmName: String,
+ crossinline getJvmDesc: () -> String
+ ): Int {
+ val methods = methodOrdering[jvmName]
+ // if there is 1 method w/ that name, just return.
+ // otherwise, we need signature matching
+ return when {
+ methods == null -> {
+ orderProvider.next(jvmName)
+ }
+ methods.size == 1 -> {
+ // only 1 method with this name, return it, no reason to resolve jvm
+ // signature
+ methods.values.first()
+ }
+ else -> {
+ // need to match using the jvm signature
+ val jvmDescriptor = getJvmDesc()
+ methods.getOrPut(jvmDescriptor) {
+ orderProvider.next(jvmName)
+ }
+ }
+ }
+ }
+
+ override fun visitField(
+ name: Name,
+ desc: String,
+ initializer: Any?
+ ): KotlinJvmBinaryClass.AnnotationVisitor? {
+ fieldOrdering.getOrPut(name.asString()) {
+ orderProvider.next(name)
+ }
+ return null
+ }
+
+ override fun visitMethod(
+ name: Name,
+ desc: String
+ ): KotlinJvmBinaryClass.MethodAnnotationVisitor? {
+ methodOrdering.getOrPut(name.asString()) {
+ mutableMapOf()
+ }.put(desc, orderProvider.next(name))
+ return null
+ }
+
+ /**
+ * Helper class to generate order values for items.
+ * Each time we see a new declaration, we give it an increasing order.
+ *
+ * This provider can also run in STRICT MODE to ensure that if we don't find an expected value
+ * during sorting, we can crash instead of picking the next ID. For now, it is only used for
+ * testing.
+ */
+ private class OrderProvider {
+ private var nextId = 0
+ private var sealed = false
+
+ /**
+ * Seals the provider, preventing it from generating new IDs if [STRICT_MODE] is enabled.
+ */
+ fun seal() {
+ sealed = true
+ }
+
+ /**
+ * Returns the next available order value.
+ *
+ * @param ref Used for logging if the data is sealed and we shouldn't provide a new order.
+ */
+ fun next(ref: Any): Int {
+ check(!sealed || !STRICT_MODE) {
+ "couldn't find item $ref"
+ }
+ return nextId ++
+ }
+
+ /**
+ * Returns the next ID without checking whether the model is sealed or not. This is useful
+ * for declarations where we don't care about the order (e.g. inner class declarations).
+ */
+ fun nextIgnoreSealed(): Int {
+ return nextId ++
+ }
+ }
+ companion object {
+ /**
+ * Used in tests to prevent fallback behavior of creating a new ID when we cannot find the
+ * order.
+ */
+ var STRICT_MODE = false
+ }
+}
+
+/**
+ * Same as KSDeclarationContainer.declarations, but sorted by declaration order in the source.
+ *
+ * Note that this is SLOW. AVOID IF POSSIBLE.
+ */
+@KspExperimental
+internal val KSDeclarationContainer.declarationsInSourceOrder: Sequence<KSDeclaration>
+ get() {
+ // Only Kotlin libs can be out of order.
+ if (this !is KSClassDeclarationDescriptorImpl || origin != Origin.KOTLIN_LIB)
+ return declarations
+
+ val declarationOrdering = (
+ (descriptor as? DeserializedClassDescriptor)?.source as? KotlinJvmBinarySourceElement
+ )?.binaryClass?.let {
+ DeclarationOrdering(it)
+ } ?: return declarations
+
+ return (declarations as? Sequence<KSDeclarationDescriptorImpl>)?.sortedWith(declarationOrdering.comparator)
+ ?: declarations
+ }
+
+internal val KSPropertyDeclaration.jvmAccessFlag: Int
+ get() = when (origin) {
+ Origin.KOTLIN_LIB -> {
+ val descriptor = (this as KSPropertyDeclarationDescriptorImpl).descriptor
+ val kotlinBinaryJavaClass = descriptor.getContainingKotlinJvmBinaryClass()
+ // 0 if no backing field
+ kotlinBinaryJavaClass?.let {
+ BinaryClassInfoCache.getCached(it).fieldAccFlags.get(this.simpleName.asString()) ?: 0
+ } ?: 0
+ }
+ Origin.JAVA_LIB -> {
+ val descriptor = (this as KSPropertyDeclarationDescriptorImpl).descriptor
+ ((descriptor.source as? JavaSourceElement)?.javaElement as? BinaryJavaField)?.access ?: 0
+ }
+ else -> throw IllegalStateException("this function expects only KOTLIN_LIB or JAVA_LIB")
+ }
+
+internal val KSFunctionDeclaration.jvmAccessFlag: Int
+ get() = when (origin) {
+ Origin.KOTLIN_LIB -> {
+ val jvmDesc = ResolverImpl.instance!!.mapToJvmSignatureInternal(this)
+ val descriptor = (this as KSFunctionDeclarationDescriptorImpl).descriptor
+ // Companion.<init> doesn't have containing KotlinJvmBinaryClass.
+ val kotlinBinaryJavaClass = descriptor.getContainingKotlinJvmBinaryClass()
+ kotlinBinaryJavaClass?.let {
+ BinaryClassInfoCache.getCached(it).methodAccFlags.get(this.simpleName.asString() + jvmDesc) ?: 0
+ } ?: 0
+ }
+ Origin.JAVA_LIB -> {
+ val descriptor = (this as KSFunctionDeclarationDescriptorImpl).descriptor
+ // Some functions, like `equals` in builtin types, doesn't have source.
+ ((descriptor.source as? JavaSourceElement)?.javaElement as? BinaryJavaMethodBase)?.access ?: 0
+ }
+ else -> throw IllegalStateException("this function expects only KOTLIN_LIB or JAVA_LIB")
+ }
+
+// Compiler subtype checking does not convert Java types to Kotlin types, while getting super types
+// from a java type does the conversion, therefore resulting in subtype checking for Java types to fail.
+// Check if candidate super type is a Java type, convert to Kotlin type for subtype checking.
+// Also, if the type is a generic deserialized type, that actually represents a function type,
+// a conversion is also required to yield a type with a correctly recognised descriptor.
+internal fun KotlinType.convertKotlinType(): KotlinType {
+ val declarationDescriptor = this.constructor.declarationDescriptor
+ val base = if (declarationDescriptor?.shouldMapToKotlinForAssignabilityCheck() == true) {
+ JavaToKotlinClassMapper
+ .mapJavaToKotlin(declarationDescriptor.fqNameSafe, ResolverImpl.instance!!.module.builtIns)
+ ?.defaultType
+ ?.replace(this.arguments)
+ ?: this
+ } else this
+ val newarguments =
+ base.arguments.map { if (it !is StarProjectionImpl) it.replaceType(it.type.convertKotlinType()) else it }
+ val upperBound = if (base.unwrap() is FlexibleType) {
+ (base.unwrap() as FlexibleType).upperBound.arguments
+ .map { if (it !is StarProjectionImpl) it.replaceType(it.type.convertKotlinType()) else it }
+ } else newarguments
+ return base.replace(
+ newarguments,
+ annotations,
+ upperBound
+ )
+}
+
+private fun ClassifierDescriptor.shouldMapToKotlinForAssignabilityCheck(): Boolean {
+ return when (this) {
+ is JavaClassDescriptor -> true // All java types need to be mapped to kotlin
+ is DeserializedDescriptor -> {
+ // If this is a generic deserialized type descriptor, which actually is a kotlin function type.
+ // This may be the case if the client explicitly mapped a kotlin function type to the JVM one.
+ // Such types need to be remapped to be represented by a correct function class descriptor.
+ fqNameSafe.parent().asString() == "kotlin.jvm.functions"
+ }
+ else -> false
+ }
+}
+
+fun DeclarationDescriptor.findPsi(): PsiElement? {
+ // For synthetic members.
+ if ((this is CallableMemberDescriptor) && this.kind != CallableMemberDescriptor.Kind.DECLARATION) return null
+ val psi = (this as? DeclarationDescriptorWithSource)?.source?.getPsi() ?: return null
+ if (psi is KtElement) return psi
+
+ // Find Java PSIs loaded by KSP
+ val containingFile = ResolverImpl.instance!!.findPsiJavaFile(psi.containingFile.virtualFile.path) ?: return null
+ val leaf = containingFile.findElementAt(psi.textOffset) ?: return null
+ return leaf.parentsWithSelf.firstOrNull { psi.manager.areElementsEquivalent(it, psi) }
+}
diff --git a/compiler-plugin/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor b/compiler-plugin/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
new file mode 100644
index 00000000..d854d7f4
--- /dev/null
+++ b/compiler-plugin/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
@@ -0,0 +1 @@
+com.google.devtools.ksp.KotlinSymbolProcessingCommandLineProcessor \ No newline at end of file
diff --git a/compiler-plugin/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar b/compiler-plugin/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
new file mode 100644
index 00000000..f78c55bd
--- /dev/null
+++ b/compiler-plugin/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
@@ -0,0 +1 @@
+com.google.devtools.ksp.KotlinSymbolProcessingComponentRegistrar \ No newline at end of file
diff --git a/compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/AbstractKSPCompilerPluginTest.kt b/compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/AbstractKSPCompilerPluginTest.kt
new file mode 100644
index 00000000..d57acae2
--- /dev/null
+++ b/compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/AbstractKSPCompilerPluginTest.kt
@@ -0,0 +1,77 @@
+package com.google.devtools.ksp.test
+
+import com.google.devtools.ksp.DualLookupTracker
+import com.google.devtools.ksp.KotlinSymbolProcessingExtension
+import com.google.devtools.ksp.KspOptions
+import com.google.devtools.ksp.processing.impl.MessageCollectorBasedKSPLogger
+import com.google.devtools.ksp.processor.AbstractTestProcessor
+import com.google.devtools.ksp.testutils.AbstractKSPTest
+import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
+import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
+import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
+import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
+import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoot
+import org.jetbrains.kotlin.codegen.GenerationUtils
+import org.jetbrains.kotlin.config.CommonConfigurationKeys
+import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
+import org.jetbrains.kotlin.test.model.FrontendKinds
+import org.jetbrains.kotlin.test.model.TestModule
+import org.jetbrains.kotlin.test.services.TestServices
+import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
+import org.jetbrains.kotlin.test.services.javaFiles
+import java.io.File
+
+abstract class AbstractKSPCompilerPluginTest : AbstractKSPTest(FrontendKinds.ClassicFrontend) {
+ override fun runTest(
+ testServices: TestServices,
+ mainModule: TestModule,
+ libModules: List<TestModule>,
+ testProcessor: AbstractTestProcessor,
+ ): List<String> {
+ val compilerConfiguration = testServices.compilerConfigurationProvider.getCompilerConfiguration(mainModule)
+ compilerConfiguration.put(CommonConfigurationKeys.MODULE_NAME, mainModule.name)
+ compilerConfiguration.put(CommonConfigurationKeys.LOOKUP_TRACKER, DualLookupTracker())
+ if (!mainModule.javaFiles.isEmpty()) {
+ mainModule.writeJavaFiles()
+ compilerConfiguration.addJavaSourceRoot(mainModule.javaDir)
+ }
+
+ // TODO: other platforms
+ val kotlinCoreEnvironment = KotlinCoreEnvironment.createForTests(
+ disposable,
+ compilerConfiguration,
+ EnvironmentConfigFiles.JVM_CONFIG_FILES
+ )
+
+ val ktFiles = mainModule.loadKtFiles(kotlinCoreEnvironment.project)
+
+ val logger = MessageCollectorBasedKSPLogger(
+ PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false),
+ PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false),
+ false
+ )
+
+ val testRoot = mainModule.testRoot
+ val analysisExtension =
+ KotlinSymbolProcessingExtension(
+ KspOptions.Builder().apply {
+ if (!mainModule.javaFiles.isEmpty()) {
+ javaSourceRoots.add(mainModule.javaDir)
+ }
+ classOutputDir = File(testRoot, "kspTest/classes/main")
+ javaOutputDir = File(testRoot, "kspTest/src/main/java")
+ kotlinOutputDir = File(testRoot, "kspTest/src/main/kotlin")
+ resourceOutputDir = File(testRoot, "kspTest/src/main/resources")
+ projectBaseDir = testRoot
+ cachesDir = File(testRoot, "kspTest/kspCaches")
+ kspOutputDir = File(testRoot, "kspTest")
+ }.build(),
+ logger, testProcessor
+ )
+ AnalysisHandlerExtension.registerExtension(kotlinCoreEnvironment.project, analysisExtension)
+
+ GenerationUtils.compileFilesTo(ktFiles, kotlinCoreEnvironment, mainModule.outDir)
+
+ return testProcessor.toResult()
+ }
+}
diff --git a/compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/KSPCompilerPluginTest.kt b/compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/KSPCompilerPluginTest.kt
new file mode 100644
index 00000000..e970b5d7
--- /dev/null
+++ b/compiler-plugin/src/test/kotlin/com/google/devtools/ksp/test/KSPCompilerPluginTest.kt
@@ -0,0 +1,545 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.test
+
+import org.jetbrains.kotlin.test.TestMetadata
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.condition.DisabledOnOs
+import org.junit.jupiter.api.condition.OS
+import org.junit.jupiter.api.parallel.Execution
+import org.junit.jupiter.api.parallel.ExecutionMode
+
+@Execution(ExecutionMode.SAME_THREAD)
+class KSPCompilerPluginTest : AbstractKSPCompilerPluginTest() {
+ @TestMetadata("annotatedUtil.kt")
+ @Test
+ fun testAnnotatedUtil() {
+ runTest("../test-utils/testData/api/annotatedUtil.kt")
+ }
+
+ @TestMetadata("javaAnnotatedUtil.kt")
+ @Test
+ fun testJavaAnnotatedUtil() {
+ runTest("../test-utils/testData/api/javaAnnotatedUtil.kt")
+ }
+
+ @TestMetadata("abstractFunctions.kt")
+ @Test
+ fun testAbstractFunctions() {
+ runTest("../test-utils/testData/api/abstractFunctions.kt")
+ }
+
+ @TestMetadata("allFunctions_java_inherits_kt.kt")
+ @Test
+ fun testAllFunctions_java_inherits_kt() {
+ runTest("../test-utils/testData/api/allFunctions_java_inherits_kt.kt")
+ }
+
+ @TestMetadata("allFunctions_kotlin.kt")
+ @Test
+ fun testAllFunctions_kotlin() {
+ runTest("../test-utils/testData/api/allFunctions_java_inherits_kt.kt")
+ }
+
+ @TestMetadata("allFunctions_kt_inherits_java.kt")
+ @Test
+ fun testAllFunctions_kt_inherits_java() {
+ runTest("../test-utils/testData/api/allFunctions_kt_inherits_java.kt")
+ }
+
+ @TestMetadata("annotationInDependencies.kt")
+ @Test
+ fun testAnnotationsInDependencies() {
+ runTest("../test-utils/testData/api/annotationInDependencies.kt")
+ }
+
+ @TestMetadata("annotationOnConstructorParameter.kt")
+ @Test
+ fun testAnnotationOnConstructorParameter() {
+ runTest("../test-utils/testData/api/annotationOnConstructorParameter.kt")
+ }
+
+ @TestMetadata("annotationWithArbitraryClassValue.kt")
+ @Test
+ fun testAnnotationWithArbitraryClassValue() {
+ runTest("../test-utils/testData/api/annotationWithArbitraryClassValue.kt")
+ }
+
+ @TestMetadata("annotationValue_java.kt")
+ @Test
+ fun testAnnotationValue_java() {
+ runTest("../test-utils/testData/api/annotationValue_java.kt")
+ }
+
+ @TestMetadata("annotationValue_kt.kt")
+ @Test
+ fun testAnnotationValue_kt() {
+ runTest("../test-utils/testData/api/annotationValue_kt.kt")
+ }
+
+ @TestMetadata("annotationWithArrayValue.kt")
+ @Test
+ fun testAnnotationWithArrayValue() {
+ runTest("../test-utils/testData/api/annotationWithArrayValue.kt")
+ }
+
+ @TestMetadata("annotationWithDefault.kt")
+ @Test
+ fun testAnnotationWithDefault() {
+ runTest("../test-utils/testData/api/annotationWithDefault.kt")
+ }
+
+ @TestMetadata("annotationWithDefaultValues.kt")
+ @Test
+ fun testAnnotationWithDefaultValues() {
+ runTest("../test-utils/testData/api/annotationWithDefaultValues.kt")
+ }
+
+ @TestMetadata("annotationWithJavaTypeValue.kt")
+ @Test
+ fun testAnnotationWithJavaTypeValue() {
+ runTest("../test-utils/testData/api/annotationWithJavaTypeValue.kt")
+ }
+
+ @TestMetadata("asMemberOf.kt")
+ @Test
+ fun testAsMemberOf() {
+ runTest("../test-utils/testData/api/asMemberOf.kt")
+ }
+
+ @TestMetadata("backingFields.kt")
+ @Test
+ fun testBackingFields() {
+ runTest("../test-utils/testData/api/backingFields.kt")
+ }
+
+ @TestMetadata("builtInTypes.kt")
+ @Test
+ fun testBuiltInTypes() {
+ runTest("../test-utils/testData/api/builtInTypes.kt")
+ }
+
+ @TestMetadata("checkOverride.kt")
+ @Test
+ fun testCheckOverride() {
+ runTest("../test-utils/testData/api/checkOverride.kt")
+ }
+
+ @TestMetadata("classKinds.kt")
+ @Test
+ fun testClassKinds() {
+ runTest("../test-utils/testData/api/classKinds.kt")
+ }
+
+ @TestMetadata("companion.kt")
+ @Test
+ fun testCompanion() {
+ runTest("../test-utils/testData/api/companion.kt")
+ }
+
+ @TestMetadata("constProperties.kt")
+ @Test
+ fun testConstProperties() {
+ runTest("../test-utils/testData/api/constProperties.kt")
+ }
+
+ @TestMetadata("constructorDeclarations.kt")
+ @Test
+ fun testConstructorDeclarations() {
+ runTest("../test-utils/testData/api/constructorDeclarations.kt")
+ }
+
+ @TestMetadata("crossModuleTypeAlias.kt")
+ @Test
+ fun testCrossModuleTypeAlias() {
+ runTest("../test-utils/testData/api/crossModuleTypeAlias.kt")
+ }
+
+ @TestMetadata("declarationInconsistency.kt")
+ @Test
+ fun testDeclarationInconsistency() {
+ runTest("../test-utils/testData/api/declarationInconsistency.kt")
+ }
+
+ @TestMetadata("declarationPackageName.kt")
+ @Test
+ fun testDeclarationPackageName() {
+ runTest("../test-utils/testData/api/declarationPackageName.kt")
+ }
+
+ @TestMetadata("declarationOrder.kt")
+ @Test
+ fun testDeclarationOrder() {
+ runTest("../test-utils/testData/api/declarationOrder.kt")
+ }
+
+ @TestMetadata("declarationUtil.kt")
+ @Test
+ fun testDeclarationUtil() {
+ runTest("../test-utils/testData/api/declarationUtil.kt")
+ }
+
+ @TestMetadata("declared.kt")
+ @Test
+ fun testDeclared() {
+ runTest("../test-utils/testData/api/declared.kt")
+ }
+
+ @TestMetadata("docString.kt")
+ @Test
+ fun testDocString() {
+ runTest("../test-utils/testData/api/docString.kt")
+ }
+
+ @TestMetadata("equivalentJavaWildcards.kt")
+ @Test
+ fun testEquivalentJavaWildcards() {
+ runTest("../test-utils/testData/api/equivalentJavaWildcards.kt")
+ }
+
+ @TestMetadata("errorTypes.kt")
+ @Test
+ fun testErrorTypes() {
+ runTest("../test-utils/testData/api/errorTypes.kt")
+ }
+
+ @TestMetadata("functionTypeAlias.kt")
+ @Test
+ fun testFunctionTypeAlias() {
+ runTest("../test-utils/testData/api/functionTypeAlias.kt")
+ }
+
+ @TestMetadata("functionTypeAnnotation.kt")
+ @Test
+ fun testFunctionTypeAnnotation() {
+ runTest("../test-utils/testData/api/functionTypeAnnotation.kt")
+ }
+
+ @TestMetadata("functionTypes.kt")
+ @Test
+ fun testFunctionTypes() {
+ runTest("../test-utils/testData/api/functionTypes.kt")
+ }
+
+ @TestMetadata("getAnnotationByTypeWithInnerDefault.kt")
+ @Test
+ fun testGetAnnotationByTypeWithInnerDefault() {
+ runTest("../test-utils/testData/api/getAnnotationByTypeWithInnerDefault.kt")
+ }
+
+ @DisabledOnOs(OS.WINDOWS)
+ @TestMetadata("getPackage.kt")
+ @Test
+ fun testGetPackage() {
+ runTest("../test-utils/testData/api/getPackage.kt")
+ }
+
+ @TestMetadata("getByName.kt")
+ @Test
+ fun testGetByName() {
+ runTest("../test-utils/testData/api/getByName.kt")
+ }
+
+ @TestMetadata("getSymbolsFromAnnotation.kt")
+ @Test
+ fun testGetSymbolsFromAnnotation() {
+ runTest("../test-utils/testData/api/getSymbolsFromAnnotation.kt")
+ }
+
+ @TestMetadata("hello.kt")
+ @Test
+ fun testHello() {
+ runTest("../test-utils/testData/api/hello.kt")
+ }
+
+ @TestMetadata("implicitElements.kt")
+ @Test
+ fun testImplicitElements() {
+ runTest("../test-utils/testData/api/implicitElements.kt")
+ }
+
+ @TestMetadata("implicitPropertyAccessors.kt")
+ @Test
+ fun testImplicitPropertyAccessors() {
+ runTest("../test-utils/testData/api/implicitPropertyAccessors.kt")
+ }
+
+ @TestMetadata("inheritedTypeAlias.kt")
+ @Test
+ fun testInheritedTypeAlias() {
+ runTest("../test-utils/testData/api/inheritedTypeAlias.kt")
+ }
+
+ @TestMetadata("innerTypes.kt")
+ @Test
+ fun testInnerTypes() {
+ runTest("../test-utils/testData/api/innerTypes.kt")
+ }
+
+ @TestMetadata("interfaceWithDefault.kt")
+ @Test
+ fun testInterfaceWithDefault() {
+ runTest("../test-utils/testData/api/interfaceWithDefault.kt")
+ }
+
+ @TestMetadata("javaModifiers.kt")
+ @Test
+ fun testJavaModifiers() {
+ runTest("../test-utils/testData/api/javaModifiers.kt")
+ }
+
+ @TestMetadata("javaNonNullTypes.kt")
+ @Test
+ fun testJavaNonNullTypes() {
+ runTest("../test-utils/testData/api/javaNonNullTypes.kt")
+ }
+
+ @TestMetadata("javaSubtype.kt")
+ @Test
+ fun testJavaSubtype() {
+ runTest("../test-utils/testData/api/javaSubtype.kt")
+ }
+
+ @TestMetadata("javaToKotlinMapper.kt")
+ @Test
+ fun testJavaToKotlinMapper() {
+ runTest("../test-utils/testData/api/javaToKotlinMapper.kt")
+ }
+
+ @TestMetadata("javaTypes.kt")
+ @Test
+ fun testJavaTypes() {
+ runTest("../test-utils/testData/api/javaTypes.kt")
+ }
+
+ @TestMetadata("javaTypes2.kt")
+ @Test
+ fun testJavaTypes2() {
+ runTest("../test-utils/testData/api/javaTypes2.kt")
+ }
+
+ @TestMetadata("javaWildcards2.kt")
+ @Test
+ fun testJavaWildcards2() {
+ runTest("../test-utils/testData/api/javaWildcards2.kt")
+ }
+
+ @TestMetadata("lateinitProperties.kt")
+ @Test
+ fun testLateinitProperties() {
+ runTest("../test-utils/testData/api/lateinitProperties.kt")
+ }
+
+ @TestMetadata("libOrigins.kt")
+ @Test
+ fun testLibOrigins() {
+ runTest("../test-utils/testData/api/libOrigins.kt")
+ }
+
+ @TestMetadata("makeNullable.kt")
+ @Test
+ fun testMakeNullable() {
+ runTest("../test-utils/testData/api/makeNullable.kt")
+ }
+
+ @TestMetadata("mangledNames.kt")
+ @Test
+ fun testMangledNames() {
+ runTest("../test-utils/testData/api/mangledNames.kt")
+ }
+
+ @TestMetadata("multipleModules.kt")
+ @Test
+ fun testMultipleModules() {
+ runTest("../test-utils/testData/api/multipleModules.kt")
+ }
+
+ @TestMetadata("nestedClassType.kt")
+ @Test
+ fun testNestedClassType() {
+ runTest("../test-utils/testData/api/nestedClassType.kt")
+ }
+
+ @TestMetadata("nullableTypes.kt")
+ @Test
+ fun testNullableTypes() {
+ runTest("../test-utils/testData/api/nullableTypes.kt")
+ }
+
+ @TestMetadata("overridee.kt")
+ @Test
+ fun testOverridee() {
+ runTest("../test-utils/testData/api/overridee.kt")
+ }
+
+ @TestMetadata("parameterTypes.kt")
+ @Test
+ fun testParameterTypes() {
+ runTest("../test-utils/testData/api/parameterTypes.kt")
+ }
+
+ @TestMetadata("parent.kt")
+ @Test
+ fun testParent() {
+ runTest("../test-utils/testData/api/parent.kt")
+ }
+
+ @TestMetadata("platformDeclaration.kt")
+ @Test
+ fun testPlatformDeclaration() {
+ runTest("../test-utils/testData/api/platformDeclaration.kt")
+ }
+
+ @TestMetadata("rawTypes.kt")
+ @Test
+ fun testRawTypes() {
+ runTest("../test-utils/testData/api/rawTypes.kt")
+ }
+
+ @DisabledOnOs(OS.WINDOWS)
+ @TestMetadata("recordJavaAnnotationTypes.kt")
+ @Test
+ fun testRecordJavaAnnotationTypes() {
+ runTest("../test-utils/testData/api/recordJavaAnnotationTypes.kt")
+ }
+
+ @DisabledOnOs(OS.WINDOWS)
+ @TestMetadata("recordJavaAsMemberOf.kt")
+ @Test
+ fun testRecordJavaAsMemberOf() {
+ runTest("../test-utils/testData/api/recordJavaAsMemberOf.kt")
+ }
+
+ @DisabledOnOs(OS.WINDOWS)
+ @TestMetadata("recordJavaGetAllMembers.kt")
+ @Test
+ fun testRecordJavaGetAllMembers() {
+ runTest("../test-utils/testData/api/recordJavaGetAllMembers.kt")
+ }
+
+ @DisabledOnOs(OS.WINDOWS)
+ @TestMetadata("recordJavaOverrides.kt")
+ @Test
+ fun testRecordJavaOverrides() {
+ runTest("../test-utils/testData/api/recordJavaOverrides.kt")
+ }
+
+ @DisabledOnOs(OS.WINDOWS)
+ @TestMetadata("recordJavaSupertypes.kt")
+ @Test
+ fun testRecordJavaSupertypes() {
+ runTest("../test-utils/testData/api/recordJavaSupertypes.kt")
+ }
+
+ @TestMetadata("referenceElement.kt")
+ @Test
+ fun testReferenceElement() {
+ runTest("../test-utils/testData/api/referenceElement.kt")
+ }
+
+ @TestMetadata("replaceWithErrorTypeArgs.kt")
+ @Test
+ fun testReplaceWithErrorTypeArgs() {
+ runTest("../test-utils/testData/api/replaceWithErrorTypeArgs.kt")
+ }
+
+ @TestMetadata("resolveJavaType.kt")
+ @Test
+ fun testResolveJavaType() {
+ runTest("../test-utils/testData/api/resolveJavaType.kt")
+ }
+
+ @DisabledOnOs(OS.WINDOWS)
+ @TestMetadata("sealedClass.kt")
+ @Test
+ fun testSealedClass() {
+ runTest("../test-utils/testData/api/sealedClass.kt")
+ }
+
+ @TestMetadata("signatureMapper.kt")
+ @Test
+ fun testSignatureMapper() {
+ runTest("../test-utils/testData/api/signatureMapper.kt")
+ }
+
+ @TestMetadata("superTypes.kt")
+ @Test
+ fun testSuperTypes() {
+ runTest("../test-utils/testData/api/superTypes.kt")
+ }
+
+ @TestMetadata("throwList.kt")
+ @Test
+ fun testThrowList() {
+ runTest("../test-utils/testData/api/throwList.kt")
+ }
+
+ @TestMetadata("topLevelMembers.kt")
+ @Test
+ fun testTopLevelMembers() {
+ runTest("../test-utils/testData/api/topLevelMembers.kt")
+ }
+
+ @TestMetadata("typeAlias.kt")
+ @Test
+ fun testTypeAlias() {
+ runTest("../test-utils/testData/api/typeAlias.kt")
+ }
+
+ @TestMetadata("typeAliasComparison.kt")
+ @Test
+ fun testTypeAliasComparison() {
+ runTest("../test-utils/testData/api/typeAliasComparison.kt")
+ }
+
+ @TestMetadata("typeComposure.kt")
+ @Test
+ fun testTypeComposure() {
+ runTest("../test-utils/testData/api/typeComposure.kt")
+ }
+
+ @TestMetadata("typeParameterEquals.kt")
+ @Test
+ fun testTypeParameterEquals() {
+ runTest("../test-utils/testData/api/typeParameterEquals.kt")
+ }
+
+ @TestMetadata("typeParameterReference.kt")
+ @Test
+ fun testTypeParameterReference() {
+ runTest("../test-utils/testData/api/typeParameterReference.kt")
+ }
+
+ @TestMetadata("varianceTypeCheck.kt")
+ @Test
+ fun testVarianceTypeCheck() {
+ runTest("../test-utils/testData/api/varianceTypeCheck.kt")
+ }
+
+ @TestMetadata("validateTypes.kt")
+ @Test
+ fun testValidateTypes() {
+ runTest("../test-utils/testData/api/validateTypes.kt")
+ }
+
+ @TestMetadata("visibilities.kt")
+ @Test
+ fun testVisibilities() {
+ runTest("../test-utils/testData/api/visibilities.kt")
+ }
+}
diff --git a/examples/multiplatform/.gitignore b/examples/multiplatform/.gitignore
new file mode 100644
index 00000000..22554236
--- /dev/null
+++ b/examples/multiplatform/.gitignore
@@ -0,0 +1,5 @@
+.gradle/
+.idea/
+build/
+**/build/
+
diff --git a/examples/multiplatform/build.gradle.kts b/examples/multiplatform/build.gradle.kts
new file mode 100644
index 00000000..e8535316
--- /dev/null
+++ b/examples/multiplatform/build.gradle.kts
@@ -0,0 +1,14 @@
+plugins {
+ kotlin("multiplatform") apply false
+}
+
+subprojects {
+ repositories {
+ mavenCentral()
+ }
+
+ tasks.withType<JavaCompile>().configureEach {
+ sourceCompatibility = JavaVersion.VERSION_1_8.toString()
+ targetCompatibility = JavaVersion.VERSION_1_8.toString()
+ }
+}
diff --git a/examples/multiplatform/gradle.properties b/examples/multiplatform/gradle.properties
new file mode 100644
index 00000000..a332ce2f
--- /dev/null
+++ b/examples/multiplatform/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx2048M
+kotlinVersion=1.7.22
+kspVersion=1.7.22-1.0.8
diff --git a/examples/multiplatform/gradle/wrapper/gradle-wrapper.jar b/examples/multiplatform/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..58499e4f
--- /dev/null
+++ b/examples/multiplatform/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/examples/multiplatform/gradle/wrapper/gradle-wrapper.properties b/examples/multiplatform/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..36ea3d13
--- /dev/null
+++ b/examples/multiplatform/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/examples/multiplatform/gradlew b/examples/multiplatform/gradlew
new file mode 100755
index 00000000..9d9cdba7
--- /dev/null
+++ b/examples/multiplatform/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS --illegal-access=permit $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/examples/multiplatform/gradlew.bat b/examples/multiplatform/gradlew.bat
new file mode 100644
index 00000000..e95643d6
--- /dev/null
+++ b/examples/multiplatform/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/examples/multiplatform/settings.gradle.kts b/examples/multiplatform/settings.gradle.kts
new file mode 100644
index 00000000..c9b97367
--- /dev/null
+++ b/examples/multiplatform/settings.gradle.kts
@@ -0,0 +1,17 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion apply false
+ kotlin("multiplatform") version kotlinVersion apply false
+ }
+ repositories {
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+rootProject.name = "multiplatform"
+
+include(":workload")
+include(":test-processor")
diff --git a/examples/multiplatform/test-processor/build.gradle.kts b/examples/multiplatform/test-processor/build.gradle.kts
new file mode 100644
index 00000000..842898f6
--- /dev/null
+++ b/examples/multiplatform/test-processor/build.gradle.kts
@@ -0,0 +1,22 @@
+val kspVersion: String by project
+
+plugins {
+ kotlin("multiplatform")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+kotlin {
+ jvm()
+ sourceSets {
+ val jvmMain by getting {
+ dependencies {
+ implementation("com.squareup:javapoet:1.12.1")
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+ }
+ kotlin.srcDir("src/main/kotlin")
+ resources.srcDir("src/main/resources")
+ }
+ }
+}
diff --git a/examples/multiplatform/test-processor/src/main/kotlin/TestProcessor.kt b/examples/multiplatform/test-processor/src/main/kotlin/TestProcessor.kt
new file mode 100644
index 00000000..0a06826d
--- /dev/null
+++ b/examples/multiplatform/test-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,52 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+import java.io.OutputStreamWriter
+
+class TestProcessor(val codeGenerator: CodeGenerator, val logger: KSPLogger) : SymbolProcessor {
+ var invoked = false
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val allFiles = resolver.getAllFiles().map { it.fileName }
+ logger.warn(allFiles.toList().toString())
+ if (invoked) {
+ return emptyList()
+ }
+ invoked = true
+
+ codeGenerator.createNewFile(Dependencies(false), "", "Foo", "kt").use { output ->
+ OutputStreamWriter(output).use { writer ->
+ writer.write("package com.example\n\n")
+ writer.write("class Foo {\n")
+
+ val visitor = ClassVisitor()
+ resolver.getAllFiles().forEach {
+ it.accept(visitor, writer)
+ }
+
+ writer.write("}\n")
+ }
+ }
+ return emptyList()
+ }
+}
+
+class ClassVisitor : KSTopDownVisitor<OutputStreamWriter, Unit>() {
+ override fun defaultHandler(node: KSNode, data: OutputStreamWriter) {
+ }
+
+ override fun visitClassDeclaration(
+ classDeclaration: KSClassDeclaration,
+ data: OutputStreamWriter
+ ) {
+ super.visitClassDeclaration(classDeclaration, data)
+ val symbolName = classDeclaration.simpleName.asString().lowercase()
+ data.write(" val $symbolName = true\n")
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
+ return TestProcessor(environment.codeGenerator, environment.logger)
+ }
+}
diff --git a/examples/multiplatform/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/examples/multiplatform/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..c91e3e9e
--- /dev/null
+++ b/examples/multiplatform/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+TestProcessorProvider
diff --git a/examples/multiplatform/workload/build.gradle.kts b/examples/multiplatform/workload/build.gradle.kts
new file mode 100644
index 00000000..62a61680
--- /dev/null
+++ b/examples/multiplatform/workload/build.gradle.kts
@@ -0,0 +1,60 @@
+plugins {
+ kotlin("multiplatform")
+ id("com.google.devtools.ksp")
+}
+
+version = "1.0-SNAPSHOT"
+
+kotlin {
+ jvm {
+ withJava()
+ }
+ js(IR) {
+ browser()
+ nodejs()
+ }
+ linuxX64() {
+ binaries {
+ executable()
+ }
+ }
+ // requires Android SDK
+ androidNativeX64() {
+ binaries {
+ executable()
+ }
+ }
+ // requires Android SDK
+ androidNativeArm64() {
+ binaries {
+ executable()
+ }
+ }
+ mingwX64()
+ sourceSets {
+ val commonMain by getting
+ val linuxX64Main by getting
+ val linuxX64Test by getting
+ val androidNativeX64Main by getting
+ val androidNativeArm64Main by getting
+ }
+}
+
+dependencies {
+ add("kspCommonMainMetadata", project(":test-processor"))
+ add("kspJvm", project(":test-processor"))
+ add("kspJvmTest", project(":test-processor"))
+ add("kspJs", project(":test-processor"))
+ add("kspJsTest", project(":test-processor"))
+ add("kspAndroidNativeX64", project(":test-processor"))
+ add("kspAndroidNativeX64Test", project(":test-processor"))
+ add("kspAndroidNativeArm64", project(":test-processor"))
+ add("kspAndroidNativeArm64Test", project(":test-processor"))
+ add("kspLinuxX64", project(":test-processor"))
+ add("kspLinuxX64Test", project(":test-processor"))
+ add("kspMingwX64", project(":test-processor"))
+ add("kspMingwX64Test", project(":test-processor"))
+
+ // The universal "ksp" configuration has performance issue and is deprecated on multiplatform since 1.0.1
+ // ksp(project(":test-processor"))
+}
diff --git a/examples/multiplatform/workload/src/androidNativeArm64Main/kotlin/Main.kt b/examples/multiplatform/workload/src/androidNativeArm64Main/kotlin/Main.kt
new file mode 100644
index 00000000..bf7bfe3e
--- /dev/null
+++ b/examples/multiplatform/workload/src/androidNativeArm64Main/kotlin/Main.kt
@@ -0,0 +1,7 @@
+import com.example.Bar
+import com.example.Foo
+
+fun main() {
+ println(Bar().toString())
+ println(Foo().toString())
+}
diff --git a/examples/multiplatform/workload/src/androidNativeX64Main/kotlin/Main.kt b/examples/multiplatform/workload/src/androidNativeX64Main/kotlin/Main.kt
new file mode 100644
index 00000000..bf7bfe3e
--- /dev/null
+++ b/examples/multiplatform/workload/src/androidNativeX64Main/kotlin/Main.kt
@@ -0,0 +1,7 @@
+import com.example.Bar
+import com.example.Foo
+
+fun main() {
+ println(Bar().toString())
+ println(Foo().toString())
+}
diff --git a/examples/multiplatform/workload/src/commonMain/kotlin/com/example/Bar.kt b/examples/multiplatform/workload/src/commonMain/kotlin/com/example/Bar.kt
new file mode 100644
index 00000000..480d3cb2
--- /dev/null
+++ b/examples/multiplatform/workload/src/commonMain/kotlin/com/example/Bar.kt
@@ -0,0 +1,5 @@
+package com.example
+
+class Bar {
+ val baz = Foo().baz
+}
diff --git a/examples/multiplatform/workload/src/commonMain/kotlin/com/example/Baz.kt b/examples/multiplatform/workload/src/commonMain/kotlin/com/example/Baz.kt
new file mode 100644
index 00000000..83015598
--- /dev/null
+++ b/examples/multiplatform/workload/src/commonMain/kotlin/com/example/Baz.kt
@@ -0,0 +1,5 @@
+package com.example
+
+class Baz {
+ val bar = Foo().bar
+}
diff --git a/examples/multiplatform/workload/src/linuxX64Main/kotlin/Main.kt b/examples/multiplatform/workload/src/linuxX64Main/kotlin/Main.kt
new file mode 100644
index 00000000..bf7bfe3e
--- /dev/null
+++ b/examples/multiplatform/workload/src/linuxX64Main/kotlin/Main.kt
@@ -0,0 +1,7 @@
+import com.example.Bar
+import com.example.Foo
+
+fun main() {
+ println(Bar().toString())
+ println(Foo().toString())
+}
diff --git a/examples/multiplatform/workload/src/linuxX64Test/kotlin/MyTest.kt b/examples/multiplatform/workload/src/linuxX64Test/kotlin/MyTest.kt
new file mode 100644
index 00000000..436503de
--- /dev/null
+++ b/examples/multiplatform/workload/src/linuxX64Test/kotlin/MyTest.kt
@@ -0,0 +1 @@
+class MyTest
diff --git a/examples/playground/.gitignore b/examples/playground/.gitignore
new file mode 100644
index 00000000..75b55abc
--- /dev/null
+++ b/examples/playground/.gitignore
@@ -0,0 +1,5 @@
+.gradle/
+.idea/
+build/
+*/build/
+
diff --git a/examples/playground/build.gradle.kts b/examples/playground/build.gradle.kts
new file mode 100644
index 00000000..19af4449
--- /dev/null
+++ b/examples/playground/build.gradle.kts
@@ -0,0 +1,14 @@
+plugins {
+ kotlin("jvm")
+}
+
+subprojects {
+ repositories {
+ mavenCentral()
+ }
+
+ tasks.withType<JavaCompile>().configureEach {
+ sourceCompatibility = JavaVersion.VERSION_1_8.toString()
+ targetCompatibility = JavaVersion.VERSION_1_8.toString()
+ }
+}
diff --git a/examples/playground/gradle.properties b/examples/playground/gradle.properties
new file mode 100644
index 00000000..aaec2022
--- /dev/null
+++ b/examples/playground/gradle.properties
@@ -0,0 +1,3 @@
+kotlin.code.style=official
+kotlinVersion=1.7.22
+kspVersion=1.7.22-1.0.8 \ No newline at end of file
diff --git a/examples/playground/gradle/wrapper/gradle-wrapper.jar b/examples/playground/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..62d4c053
--- /dev/null
+++ b/examples/playground/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/examples/playground/gradle/wrapper/gradle-wrapper.properties b/examples/playground/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..69a97150
--- /dev/null
+++ b/examples/playground/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/examples/playground/gradlew b/examples/playground/gradlew
new file mode 100755
index 00000000..fbd7c515
--- /dev/null
+++ b/examples/playground/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://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.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/examples/playground/gradlew.bat b/examples/playground/gradlew.bat
new file mode 100644
index 00000000..a9f778a7
--- /dev/null
+++ b/examples/playground/gradlew.bat
@@ -0,0 +1,104 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/examples/playground/settings.gradle.kts b/examples/playground/settings.gradle.kts
new file mode 100644
index 00000000..1fecf40a
--- /dev/null
+++ b/examples/playground/settings.gradle.kts
@@ -0,0 +1,17 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ gradlePluginPortal()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "playground"
+
+include(":workload")
+include(":test-processor")
diff --git a/examples/playground/test-processor/build.gradle.kts b/examples/playground/test-processor/build.gradle.kts
new file mode 100644
index 00000000..009ce54c
--- /dev/null
+++ b/examples/playground/test-processor/build.gradle.kts
@@ -0,0 +1,19 @@
+val kspVersion: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.squareup:javapoet:1.12.1")
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
+
diff --git a/examples/playground/test-processor/src/main/kotlin/Builder.kt b/examples/playground/test-processor/src/main/kotlin/Builder.kt
new file mode 100644
index 00000000..b7e0697f
--- /dev/null
+++ b/examples/playground/test-processor/src/main/kotlin/Builder.kt
@@ -0,0 +1,4 @@
+package com.example.annotation
+
+annotation class Builder {
+} \ No newline at end of file
diff --git a/examples/playground/test-processor/src/main/kotlin/BuilderProcessor.kt b/examples/playground/test-processor/src/main/kotlin/BuilderProcessor.kt
new file mode 100644
index 00000000..061c3291
--- /dev/null
+++ b/examples/playground/test-processor/src/main/kotlin/BuilderProcessor.kt
@@ -0,0 +1,79 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.validate
+import java.io.File
+import java.io.OutputStream
+
+fun OutputStream.appendText(str: String) {
+ this.write(str.toByteArray())
+}
+class BuilderProcessor(
+ val codeGenerator: CodeGenerator,
+ val logger: KSPLogger
+) : SymbolProcessor {
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val symbols = resolver.getSymbolsWithAnnotation("com.example.annotation.Builder")
+ val ret = symbols.filter { !it.validate() }.toList()
+ symbols
+ .filter { it is KSClassDeclaration && it.validate() }
+ .forEach { it.accept(BuilderVisitor(), Unit) }
+ return ret
+ }
+
+ inner class BuilderVisitor : KSVisitorVoid() {
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ classDeclaration.primaryConstructor!!.accept(this, data)
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ val parent = function.parentDeclaration as KSClassDeclaration
+ val packageName = parent.containingFile!!.packageName.asString()
+ val className = "${parent.simpleName.asString()}Builder"
+ val file = codeGenerator.createNewFile(Dependencies(true, function.containingFile!!), packageName , className)
+ file.appendText("package $packageName\n\n")
+ file.appendText("import HELLO\n\n")
+ file.appendText("class $className{\n")
+ function.parameters.forEach {
+ val name = it.name!!.asString()
+ val typeName = StringBuilder(it.type.resolve().declaration.qualifiedName?.asString() ?: "<ERROR>")
+ val typeArgs = it.type.element!!.typeArguments
+ if (it.type.element!!.typeArguments.isNotEmpty()) {
+ typeName.append("<")
+ typeName.append(
+ typeArgs.map {
+ val type = it.type?.resolve()
+ "${it.variance.label} ${type?.declaration?.qualifiedName?.asString() ?: "ERROR"}" +
+ if (type?.nullability == Nullability.NULLABLE) "?" else ""
+ }.joinToString(", ")
+ )
+ typeName.append(">")
+ }
+ file.appendText(" private var $name: $typeName? = null\n")
+ file.appendText(" internal fun with${name.replaceFirstChar { it.uppercase() } }($name: $typeName): $className {\n")
+ file.appendText(" this.$name = $name\n")
+ file.appendText(" return this\n")
+ file.appendText(" }\n\n")
+ }
+ file.appendText(" internal fun build(): ${parent.qualifiedName!!.asString()} {\n")
+ file.appendText(" return ${parent.qualifiedName!!.asString()}(")
+ file.appendText(
+ function.parameters.map {
+ "${it.name!!.asString()}!!"
+ }.joinToString(", ")
+ )
+ file.appendText(")\n")
+ file.appendText(" }\n")
+ file.appendText("}\n")
+ file.close()
+ }
+ }
+
+}
+
+class BuilderProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ environment: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return BuilderProcessor(environment.codeGenerator, environment.logger)
+ }
+} \ No newline at end of file
diff --git a/examples/playground/test-processor/src/main/kotlin/JavaBuilderProcessor.kt b/examples/playground/test-processor/src/main/kotlin/JavaBuilderProcessor.kt
new file mode 100644
index 00000000..a3eb1f15
--- /dev/null
+++ b/examples/playground/test-processor/src/main/kotlin/JavaBuilderProcessor.kt
@@ -0,0 +1,58 @@
+import com.example.annotation.Builder
+import com.squareup.javapoet.*
+import javax.annotation.processing.AbstractProcessor
+import javax.annotation.processing.RoundEnvironment
+import javax.lang.model.SourceVersion
+import javax.lang.model.element.ExecutableElement
+import javax.lang.model.element.Modifier
+import javax.lang.model.element.PackageElement
+import javax.lang.model.element.TypeElement
+
+class JavaBuilderProcessor : AbstractProcessor() {
+
+ override fun getSupportedSourceVersion(): SourceVersion {
+ return SourceVersion.latestSupported()
+ }
+ override fun getSupportedAnnotationTypes(): MutableSet<String> {
+ return mutableSetOf("com.example.annotation.Builder")
+ }
+
+ private fun processType(typeElement: TypeElement) {
+ val typeSpecBuilder = TypeSpec.classBuilder("${typeElement.simpleName}Builder")
+ val constructor = typeElement.enclosedElements.filterIsInstance<ExecutableElement>()
+ .filter { it.simpleName.toString() == "<init>" }
+ .first()
+
+ constructor.parameters.forEach {
+ typeSpecBuilder.addField(ClassName.get(it.asType()), it.simpleName.toString(), Modifier.PRIVATE)
+ val parameterSpec = ParameterSpec.builder(ClassName.get(it.asType()), it.simpleName.toString()).build()
+ typeSpecBuilder.addMethod(
+ MethodSpec.methodBuilder("with${it.simpleName.toString().replaceFirstChar { it.uppercase() } }")
+ .addParameter(parameterSpec)
+ .addModifiers(Modifier.PUBLIC)
+ .addStatement("this.\$N = \$N", it.simpleName, it.simpleName)
+ .addStatement("return this")
+ .returns(ClassName.bestGuess("${typeElement.qualifiedName}Builder"))
+ .build()
+ )
+ }
+ val statements = constructor.parameters.map { it.simpleName.toString() }.joinToString(", ")
+ typeSpecBuilder.addMethod(
+ MethodSpec.methodBuilder("build")
+ .addModifiers(Modifier.PUBLIC)
+ .returns(ClassName.get(typeElement.asType()))
+ .addStatement("return new ${typeElement.simpleName}($statements)")
+ .build()
+ )
+ val javaFileBuilder = JavaFile.builder((typeElement.enclosingElement as PackageElement).qualifiedName.toString(), typeSpecBuilder.build())
+ javaFileBuilder.skipJavaLangImports(true).build().writeTo(processingEnv.filer)
+ }
+
+ override fun process(annotations: MutableSet<out TypeElement>?, roundEnv: RoundEnvironment?): Boolean {
+ val elements = roundEnv!!.getElementsAnnotatedWith(Builder::class.java)
+ elements.filterIsInstance<TypeElement>()
+ .map { processType(it) }
+ return true
+ }
+
+} \ No newline at end of file
diff --git a/examples/playground/test-processor/src/main/kotlin/TestProcessor.kt b/examples/playground/test-processor/src/main/kotlin/TestProcessor.kt
new file mode 100644
index 00000000..d7858703
--- /dev/null
+++ b/examples/playground/test-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,259 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.validate
+import java.io.File
+import java.io.OutputStream
+
+
+class TestProcessor(
+ val codeGenerator: CodeGenerator,
+ val options: Map<String, String>
+) : SymbolProcessor {
+ lateinit var file: OutputStream
+ var invoked = false
+
+ fun emit(s: String, indent: String) {
+ file.appendText("$indent$s\n")
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ if (invoked) {
+ return emptyList()
+ }
+ file = codeGenerator.createNewFile(Dependencies(false), "", "TestProcessor", "log")
+ emit("TestProcessor: init($options)", "")
+
+ val javaFile = codeGenerator.createNewFile(Dependencies(false), "", "Generated", "java")
+ javaFile.appendText("class Generated {}")
+
+ val fileKt = codeGenerator.createNewFile(Dependencies(false), "", "HELLO", "java")
+ fileKt.appendText("public class HELLO{\n")
+ fileKt.appendText("public int foo() { return 1234; }\n")
+ fileKt.appendText("}")
+
+ val files = resolver.getAllFiles()
+ emit("TestProcessor: process()", "")
+ val visitor = TestVisitor()
+ for (file in files) {
+ emit("TestProcessor: processing ${file.fileName}", "")
+ file.accept(visitor, "")
+ }
+ invoked = true
+ return emptyList()
+ }
+
+ inner class TestVisitor : KSVisitor<String, Unit> {
+
+ override fun visitReferenceElement(element: KSReferenceElement, data: String) {
+ }
+
+ override fun visitModifierListOwner(modifierListOwner: KSModifierListOwner, data: String) {
+ TODO("Not yet implemented")
+ }
+
+ override fun visitNode(node: KSNode, data: String) {
+ TODO("Not yet implemented")
+ }
+
+ override fun visitPropertyAccessor(accessor: KSPropertyAccessor, data: String) {
+ TODO("Not yet implemented")
+ }
+
+ override fun visitDynamicReference(reference: KSDynamicReference, data: String) {
+ TODO("Not yet implemented")
+ }
+ val visited = HashSet<Any>()
+
+ private fun checkVisited(symbol: Any): Boolean {
+ return if (visited.contains(symbol)) {
+ true
+ } else {
+ visited.add(symbol)
+ false
+ }
+ }
+
+ private fun invokeCommonDeclarationApis(declaration: KSDeclaration, indent: String) {
+ emit(
+ "${declaration.modifiers.joinToString(" ")} ${declaration.simpleName.asString()}", indent
+ )
+ declaration.annotations.forEach{ it.accept(this, "$indent ") }
+ if (declaration.parentDeclaration != null)
+ emit(" enclosing: ${declaration.parentDeclaration!!.qualifiedName?.asString()}", indent)
+ declaration.containingFile?.let { emit("${it.packageName.asString()}.${it.fileName}", indent) }
+ declaration.typeParameters.forEach { it.accept(this, "$indent ") }
+ }
+
+ override fun visitFile(file: KSFile, data: String) {
+ if (checkVisited(file)) return
+ file.annotations.forEach{ it.accept(this, "$data ") }
+ emit(file.packageName.asString(), data)
+ for (declaration in file.declarations) {
+ declaration.accept(this, data)
+ }
+ }
+
+ override fun visitAnnotation(annotation: KSAnnotation, data: String) {
+ if (checkVisited(annotation)) return
+ emit("annotation", data)
+ annotation.annotationType.accept(this, "$data ")
+ annotation.arguments.forEach { it.accept(this, "$data ") }
+ }
+
+ override fun visitCallableReference(reference: KSCallableReference, data: String) {
+ if (checkVisited(reference)) return
+ emit("element: ", data)
+ reference.functionParameters.forEach { it.accept(this, "$data ") }
+ reference.receiverType?.accept(this, "$data receiver")
+ reference.returnType.accept(this, "$data ")
+ }
+
+ override fun visitPropertyGetter(getter: KSPropertyGetter, data: String) {
+ if (checkVisited(getter)) return
+ emit("propertyGetter: ", data)
+ getter.annotations.forEach { it.accept(this, "$data ") }
+ emit(getter.modifiers.joinToString(" "), data)
+ getter.returnType?.accept(this, "$data ")
+ }
+
+ override fun visitPropertySetter(setter: KSPropertySetter, data: String) {
+ if (checkVisited(setter)) return
+ emit("propertySetter: ", data)
+ setter.annotations.forEach { it.accept(this, "$data ") }
+ emit(setter.modifiers.joinToString(" "), data)
+ }
+
+ override fun visitTypeArgument(typeArgument: KSTypeArgument, data: String) {
+ if (checkVisited(typeArgument)) return
+ typeArgument.annotations.forEach{ it.accept(this, "$data ") }
+ emit(
+ when (typeArgument.variance) {
+ Variance.STAR -> "*"
+ Variance.COVARIANT -> "out"
+ Variance.CONTRAVARIANT -> "in"
+ else -> ""
+ }, data
+ )
+ typeArgument.type?.accept(this, "$data ")
+ }
+
+ override fun visitTypeParameter(typeParameter: KSTypeParameter, data: String) {
+ if (checkVisited(typeParameter)) return
+ typeParameter.annotations.forEach{ it.accept(this, "$data ") }
+ if (typeParameter.isReified) {
+ emit("reified ", data)
+ }
+ emit(
+ when (typeParameter.variance) {
+ Variance.COVARIANT -> "out "
+ Variance.CONTRAVARIANT -> "in "
+ else -> ""
+ } + typeParameter.name.asString(), data
+ )
+ if (typeParameter.bounds.toList().isNotEmpty()) {
+ typeParameter.bounds.forEach { it.accept(this, "$data ") }
+ }
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: String) {
+ if (checkVisited(valueParameter)) return
+ valueParameter.annotations.forEach { it.accept(this, "$data ") }
+ if (valueParameter.isVararg) {
+ emit("vararg", "$data ")
+ }
+ if (valueParameter.isNoInline) {
+ emit("noinline", "$data ")
+ }
+ if (valueParameter.isCrossInline) {
+ emit("crossinline ", "$data ")
+ }
+ emit(valueParameter.name?.asString() ?: "_", "$data ")
+ valueParameter.type.accept(this, "$data ")
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: String) {
+ if (checkVisited(function)) return
+ invokeCommonDeclarationApis(function, data)
+ for (declaration in function.declarations) {
+ declaration.accept(this, "$data ")
+ }
+ function.parameters.forEach { it.accept(this, "$data ") }
+ function.typeParameters.forEach { it.accept(this, "$data ") }
+ function.extensionReceiver?.accept(this, "$data extension:")
+ emit("returnType:", data)
+ function.returnType?.accept(this, "$data ")
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: String) {
+ if (checkVisited(classDeclaration)) return
+ invokeCommonDeclarationApis(classDeclaration, data)
+ emit(classDeclaration.classKind.type, data)
+ for (declaration in classDeclaration.declarations) {
+ declaration.accept(this, "$data ")
+ }
+ classDeclaration.superTypes.forEach { it.accept(this, "$data ") }
+ classDeclaration.primaryConstructor?.accept(this, "$data ")
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: String) {
+ if (checkVisited(property)) return
+ invokeCommonDeclarationApis(property, data)
+ property.type.accept(this, "$data ")
+ property.extensionReceiver?.accept(this, "$data extension:")
+ property.setter?.accept(this, "$data ")
+ property.getter?.accept(this, "$data ")
+ }
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: String) {
+ if (checkVisited(typeReference)) return
+ typeReference.annotations.forEach{ it.accept(this, "$data ") }
+ val type = typeReference.resolve()
+ type.let {
+ emit("resolved to: ${it.declaration.qualifiedName?.asString()}", data)
+ }
+ try {
+ typeReference.element?.accept(this, "$data ")
+ } catch (e: IllegalStateException) {
+ emit("TestProcessor: exception: $e", data)
+ }
+ }
+
+ override fun visitAnnotated(annotated: KSAnnotated, data: String) {
+ }
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: String) {
+ }
+
+ override fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: String) {
+ }
+
+ override fun visitParenthesizedReference(reference: KSParenthesizedReference, data: String) {
+ }
+
+ override fun visitClassifierReference(reference: KSClassifierReference, data: String) {
+ if (checkVisited(reference)) return
+ if (reference.typeArguments.isNotEmpty()) {
+ reference.typeArguments.forEach { it.accept(this, "$data ") }
+ }
+ }
+
+ override fun visitTypeAlias(typeAlias: KSTypeAlias, data: String) {
+ }
+
+ override fun visitValueArgument(valueArgument: KSValueArgument, data: String) {
+ if (checkVisited(valueArgument)) return
+ val name = valueArgument.name?.asString() ?: "<no name>"
+ emit("$name: ${valueArgument.value}", data)
+ valueArgument.annotations.forEach { it.accept(this, "$data ") }
+ }
+ }
+
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ environment: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return TestProcessor(environment.codeGenerator, environment.options)
+ }
+}
diff --git a/examples/playground/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/examples/playground/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..d9f9ecdb
--- /dev/null
+++ b/examples/playground/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1,2 @@
+TestProcessorProvider
+BuilderProcessorProvider
diff --git a/examples/playground/test-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/examples/playground/test-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor
new file mode 100644
index 00000000..3722677b
--- /dev/null
+++ b/examples/playground/test-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor
@@ -0,0 +1 @@
+JavaBuilderProcessor \ No newline at end of file
diff --git a/examples/playground/workload/build.gradle.kts b/examples/playground/workload/build.gradle.kts
new file mode 100644
index 00000000..1a2bb8f5
--- /dev/null
+++ b/examples/playground/workload/build.gradle.kts
@@ -0,0 +1,17 @@
+plugins {
+ id("com.google.devtools.ksp")
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation(project(":test-processor"))
+ ksp(project(":test-processor"))
+}
+
+ksp {
+ arg("option1", "value1")
+ arg("option2", "value2")
+}
diff --git a/examples/playground/workload/src/main/java/com/example/A.kt b/examples/playground/workload/src/main/java/com/example/A.kt
new file mode 100644
index 00000000..dd00ee25
--- /dev/null
+++ b/examples/playground/workload/src/main/java/com/example/A.kt
@@ -0,0 +1,19 @@
+package com.example
+
+import HELLO
+
+fun main() {
+ val hello = HELLO()
+ println(hello.foo())
+
+ val builder = AClassBuilder()
+ builder
+ .withA(1)
+ .withB("foo")
+ .withC(2.3)
+ .withD(hello)
+ val aClass : AClass = builder.build()
+ println(aClass.foo())
+}
+
+
diff --git a/examples/playground/workload/src/main/java/com/example/AClass.kt b/examples/playground/workload/src/main/java/com/example/AClass.kt
new file mode 100644
index 00000000..984b5433
--- /dev/null
+++ b/examples/playground/workload/src/main/java/com/example/AClass.kt
@@ -0,0 +1,10 @@
+package com.example
+
+import com.example.annotation.Builder
+import HELLO
+
+@Builder
+class AClass(private val a: Int, val b: String, val c: Double, val d: HELLO) {
+ val p = "$a, $b, $c, ${d.foo()}"
+ fun foo() = p
+} \ No newline at end of file
diff --git a/gradle-plugin/build.gradle.kts b/gradle-plugin/build.gradle.kts
new file mode 100644
index 00000000..81132dbc
--- /dev/null
+++ b/gradle-plugin/build.gradle.kts
@@ -0,0 +1,160 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+description = "Kotlin Symbol Processor"
+
+val kotlinBaseVersion: String by project
+val junitVersion: String by project
+val googleTruthVersion: String by project
+val agpBaseVersion: String by project
+val signingKey: String? by project
+val signingPassword: String? by project
+
+tasks.withType<KotlinCompile> {
+ compilerOptions.freeCompilerArgs.add("-Xjvm-default=all-compatibility")
+}
+
+plugins {
+ kotlin("jvm")
+ id("java-gradle-plugin")
+ `maven-publish`
+ signing
+ id("org.jetbrains.dokka") version ("1.7.20")
+}
+
+dependencies {
+ implementation("org.jetbrains.kotlin:kotlin-gradle-plugin-api:$kotlinBaseVersion")
+ implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinBaseVersion")
+ compileOnly("org.jetbrains.kotlin:kotlin-compiler-embeddable:$kotlinBaseVersion")
+ // replace AGP dependency w/ gradle-api when we have source registering API available.
+ compileOnly("com.android.tools.build:gradle:$agpBaseVersion")
+ compileOnly(gradleApi())
+ testImplementation(gradleApi())
+ testImplementation(project(":api"))
+ testImplementation("junit:junit:$junitVersion")
+ testImplementation("com.google.truth:truth:$googleTruthVersion")
+ testImplementation(gradleTestKit())
+}
+
+tasks.named("validatePlugins").configure {
+ onlyIf {
+ // while traversing classpath, this hits a class not found issue.
+ // Disabled until gradle kotlin version and our kotlin version matches
+ // java.lang.ClassNotFoundException: org/jetbrains/kotlin/compilerRunner/KotlinLogger
+ false
+ }
+}
+
+gradlePlugin {
+ plugins {
+ create("symbol-processing-gradle-plugin") {
+ id = "com.google.devtools.ksp"
+ displayName = "com.google.devtools.ksp.gradle.plugin"
+ implementationClass = "com.google.devtools.ksp.gradle.KspGradleSubplugin"
+ description = "Kotlin symbol processing integration for Gradle"
+ }
+ }
+}
+
+tasks {
+ val sourcesJar by creating(Jar::class) {
+ archiveClassifier.set("sources")
+ from(project.sourceSets.main.get().allSource)
+ }
+}
+
+val dokkaJavadocJar by tasks.register<Jar>("dokkaJavadocJar") {
+ dependsOn(tasks.dokkaJavadoc)
+ from(tasks.dokkaJavadoc.flatMap { it.outputDirectory })
+ archiveClassifier.set("javadoc")
+}
+
+publishing {
+ publications {
+ // the name of this publication should match the name java-gradle-plugin looks up
+ // https://github.com/gradle/gradle/blob/master/subprojects/plugin-development/src/main/java/org/gradle/plugin/devel/plugins/MavenPluginPublishPlugin.java#L73
+ this.create<MavenPublication>("pluginMaven") {
+ artifactId = "symbol-processing-gradle-plugin"
+ artifact(tasks["sourcesJar"])
+ artifact(tasks["dokkaJavadocJar"])
+ pom {
+ name.set("symbol-processing-gradle-plugin")
+ description.set("Kotlin symbol processing integration for Gradle")
+ }
+ }
+ }
+}
+
+signing {
+ isRequired = hasProperty("signingKey")
+ useInMemoryPgpKeys(signingKey, signingPassword)
+ sign(extensions.getByType<PublishingExtension>().publications)
+}
+
+/**
+ * Create a properties file with that can be read from the gradle-plugin tests to setup test
+ * projects.
+ */
+val testPropsOutDir = project.layout.buildDirectory.dir("test-config")
+val writeTestPropsTask = tasks.register<WriteProperties>("prepareTestConfiguration") {
+ description = "Generates a properties file with the current environment for gradle integration tests"
+ this.setOutputFile(
+ testPropsOutDir.map {
+ it.file("testprops.properties")
+ }
+ )
+ property("kspVersion", version)
+ property("mavenRepoDir", File(rootProject.buildDir, "repos/test").absolutePath)
+ property("kspProjectRootDir", rootProject.projectDir.absolutePath)
+ property("processorClasspath", project.tasks["compileTestKotlin"].outputs.files.asPath)
+}
+
+java {
+ sourceSets {
+ test {
+ resources.srcDir(testPropsOutDir)
+ }
+ }
+}
+
+tasks.named("compileTestKotlin").configure {
+ dependsOn(writeTestPropsTask)
+}
+
+tasks.named<Test>("test").configure {
+ dependsOn(":api:publishAllPublicationsToTestRepository")
+ dependsOn(":gradle-plugin:publishAllPublicationsToTestRepository")
+ dependsOn(":symbol-processing:publishAllPublicationsToTestRepository")
+}
+
+abstract class WriteVersionSrcTask @Inject constructor(
+ @get:Input val kspVersion: String,
+ @get:Input val kotlinVersion: String,
+ @get:org.gradle.api.tasks.OutputDirectory val outputSrcDir: File
+) : DefaultTask() {
+ @TaskAction
+ fun generate() {
+ File(outputSrcDir, "KSPVersions.kt").writeText(
+ """
+ package com.google.devtools.ksp.gradle
+ val KSP_KOTLIN_BASE_VERSION = "$kotlinVersion"
+ val KSP_VERSION = "$kspVersion"
+ """.trimIndent()
+ )
+ }
+}
+
+val kspVersionDir = File(project.buildDir, "generated/ksp-versions")
+val writeVersionSrcTask = tasks.register<WriteVersionSrcTask>(
+ "generateKSPVersions",
+ version.toString(),
+ kotlinBaseVersion,
+ kspVersionDir
+)
+
+kotlin {
+ sourceSets {
+ main {
+ kotlin.srcDir(writeVersionSrcTask.map { it.outputSrcDir })
+ }
+ }
+}
diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/AndroidPluginIntegration.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/AndroidPluginIntegration.kt
new file mode 100644
index 00000000..c98c9274
--- /dev/null
+++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/AndroidPluginIntegration.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.gradle
+
+import com.android.build.api.dsl.CommonExtension
+import com.android.build.gradle.BaseExtension
+import org.gradle.api.Project
+import org.gradle.api.file.FileCollection
+import org.gradle.api.tasks.TaskProvider
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
+import java.io.File
+
+/**
+ * This helper class handles communication with the android plugin.
+ * It is isolated in a separate class to avoid adding dependency on the android plugin.
+ * Instead, we add a compileOnly dependency to the Android Plugin, which means we can still function
+ * without the Android plugin. The downside is that we need to ensure never to access Android
+ * plugin APIs directly without checking its existence (we have tests covering that case).
+ */
+@Suppress("UnstableApiUsage") // some android APIs are unsable.
+object AndroidPluginIntegration {
+
+ private val agpPluginIds = listOf("com.android.application", "com.android.library", "com.android.dynamic-feature")
+
+ fun forEachAndroidSourceSet(project: Project, onSourceSet: (String) -> Unit) {
+ agpPluginIds.forEach { agpPluginId ->
+ project.pluginManager.withPlugin(agpPluginId) {
+ // for android apps, we need a configuration per source set
+ decorateAndroidExtension(project, onSourceSet)
+ }
+ }
+ }
+
+ private fun decorateAndroidExtension(project: Project, onSourceSet: (String) -> Unit) {
+ val sourceSets = when (val androidExt = project.extensions.getByName("android")) {
+ is BaseExtension -> androidExt.sourceSets
+ is CommonExtension<*, *, *, *> -> androidExt.sourceSets
+ else -> throw RuntimeException("Unsupported Android Gradle plugin version.")
+ }
+ sourceSets.all {
+ onSourceSet(it.name)
+ }
+ }
+
+ fun getCompilationSourceSets(kotlinCompilation: KotlinJvmAndroidCompilation): List<String> {
+ return kotlinCompilation.androidVariant
+ .sourceSets
+ .map { it.name }
+ }
+
+ fun registerGeneratedSources(
+ project: Project,
+ kotlinCompilation: KotlinJvmAndroidCompilation,
+ kspTaskProvider: TaskProvider<KspTaskJvm>,
+ javaOutputDir: File,
+ kotlinOutputDir: File,
+ classOutputDir: File,
+ resourcesOutputDir: FileCollection,
+ ) {
+ val kspJavaOutput = project.fileTree(javaOutputDir).builtBy(kspTaskProvider)
+ val kspKotlinOutput = project.fileTree(kotlinOutputDir).builtBy(kspTaskProvider)
+ val kspClassOutput = project.fileTree(classOutputDir).builtBy(kspTaskProvider)
+ kspJavaOutput.include("**/*.java")
+ kspKotlinOutput.include("**/*.kt")
+ kspClassOutput.include("**/*.class")
+ kotlinCompilation.androidVariant.registerExternalAptJavaOutput(kspJavaOutput)
+ kotlinCompilation.androidVariant.addJavaSourceFoldersToModel(kspKotlinOutput.dir)
+ kotlinCompilation.androidVariant.registerPreJavacGeneratedBytecode(kspClassOutput)
+ kotlinCompilation.androidVariant.registerPostJavacGeneratedBytecode(resourcesOutputDir)
+ }
+}
diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KotlinFactories.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KotlinFactories.kt
new file mode 100644
index 00000000..73b5d8e1
--- /dev/null
+++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KotlinFactories.kt
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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.
+ */
+
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+
+package com.google.devtools.ksp.gradle
+
+import org.gradle.api.Project
+import org.gradle.api.Task
+import org.gradle.api.file.FileCollection
+import org.gradle.api.model.ObjectFactory
+import org.gradle.api.provider.ListProperty
+import org.gradle.api.provider.Property
+import org.gradle.api.provider.ProviderFactory
+import org.gradle.api.tasks.CacheableTask
+import org.gradle.api.tasks.IgnoreEmptyDirectories
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.Internal
+import org.gradle.api.tasks.Nested
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.PathSensitive
+import org.gradle.api.tasks.PathSensitivity
+import org.gradle.api.tasks.SkipWhenEmpty
+import org.gradle.api.tasks.TaskProvider
+import org.gradle.process.CommandLineArgumentProvider
+import org.gradle.process.ExecOperations
+import org.gradle.work.InputChanges
+import org.gradle.workers.WorkerExecutor
+import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
+import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
+import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
+import org.jetbrains.kotlin.cli.common.arguments.K2MetadataCompilerArguments
+import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions
+import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompilerOptionsDefault
+import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptionsDefault
+import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonCompilerOptionsDefault
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
+import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
+import org.jetbrains.kotlin.gradle.plugin.mpp.enabledOnCurrentHost
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeCompilationData
+import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon
+import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
+import org.jetbrains.kotlin.gradle.tasks.TaskOutputsBackup
+import org.jetbrains.kotlin.gradle.tasks.configuration.BaseKotlin2JsCompileConfig
+import org.jetbrains.kotlin.gradle.tasks.configuration.KotlinCompileCommonConfig
+import org.jetbrains.kotlin.gradle.tasks.configuration.KotlinCompileConfig
+import org.jetbrains.kotlin.incremental.ChangedFiles
+import java.io.File
+import java.nio.file.Paths
+import javax.inject.Inject
+
+/**
+ * TODO: Replace with KGP's Kotlin*Factory after:
+ * https://youtrack.jetbrains.com/issue/KT-54986/KGP-API-to-toggle-incremental-compilation
+ * https://youtrack.jetbrains.com/issue/KT-55031/KGP-API-to-create-compilation-tasks-of-JS-Metadata-and-Native
+ */
+class KotlinFactories {
+ companion object {
+ fun registerKotlinJvmCompileTask(
+ project: Project,
+ taskName: String,
+ kotlinCompilation: KotlinCompilationData<*>,
+ ): TaskProvider<out KspTaskJvm> {
+ return project.tasks.register(taskName, KspTaskJvm::class.java).also { kspTaskProvider ->
+ KotlinCompileConfig(kotlinCompilation)
+ .execute(kspTaskProvider as TaskProvider<KotlinCompile>)
+
+ // useClasspathSnapshot isn't configurable per task.
+ // Workaround: enable the other path and ignore irrelevant changes
+ // See [KotlinCompileConfig] in for details.
+ // FIXME: make it configurable in upstream or support useClasspathSnapshot == true, if possible.
+ kspTaskProvider.configure {
+ if (it.classpathSnapshotProperties.useClasspathSnapshot.get()) {
+ it.classpathSnapshotProperties.classpath.from(project.provider { it.libraries })
+ }
+ }
+ }
+ }
+
+ fun registerKotlinJSCompileTask(
+ project: Project,
+ taskName: String,
+ kotlinCompilation: KotlinCompilationData<*>,
+ ): TaskProvider<out KspTaskJS> {
+ return project.tasks.register(taskName, KspTaskJS::class.java).also { kspTaskProvider ->
+ BaseKotlin2JsCompileConfig<Kotlin2JsCompile>(kotlinCompilation)
+ .execute(kspTaskProvider as TaskProvider<Kotlin2JsCompile>)
+ kspTaskProvider.configure {
+ it.incrementalJsKlib = false
+ }
+ }
+ }
+
+ fun registerKotlinMetadataCompileTask(
+ project: Project,
+ taskName: String,
+ kotlinCompilation: KotlinCompilationData<*>,
+ ): TaskProvider<out KspTaskMetadata> {
+ return project.tasks.register(taskName, KspTaskMetadata::class.java).also { kspTaskProvider ->
+ KotlinCompileCommonConfig(kotlinCompilation)
+ .execute(kspTaskProvider as TaskProvider<KotlinCompileCommon>)
+ }
+ }
+
+ fun registerKotlinNativeCompileTask(
+ project: Project,
+ taskName: String,
+ kotlinCompilation: KotlinCompilation<*>
+ ): TaskProvider<out KspTaskNative> {
+ return project.tasks.register(
+ taskName,
+ KspTaskNative::class.java,
+ kotlinCompilation as KotlinNativeCompilationData<*>
+ ).apply {
+ configure { kspTask ->
+ kspTask.onlyIf {
+ kspTask.konanTarget.enabledOnCurrentHost
+ }
+ }
+ }
+ }
+ }
+}
+
+interface KspTask : Task {
+ @get:Internal
+ val options: ListProperty<SubpluginOption>
+
+ @get:Nested
+ val commandLineArgumentProviders: ListProperty<CommandLineArgumentProvider>
+
+ @get:Internal
+ val incrementalChangesTransformers: ListProperty<(ChangedFiles) -> List<SubpluginOption>>
+}
+
+@CacheableTask
+abstract class KspTaskJvm @Inject constructor(
+ workerExecutor: WorkerExecutor,
+ objectFactory: ObjectFactory
+) : KotlinCompile(
+ objectFactory.newInstance(KotlinJvmCompilerOptionsDefault::class.java),
+ workerExecutor,
+ objectFactory
+ ),
+ KspTask {
+ @get:OutputDirectory
+ abstract val destination: Property<File>
+
+ // Override incrementalProps to exclude irrelevant changes
+ override val incrementalProps: List<FileCollection>
+ get() = listOf(
+ sources,
+ javaSources,
+ commonSourceSet,
+ classpathSnapshotProperties.classpath,
+ )
+
+ // Overrding an internal function is hacky.
+ // TODO: Ask upstream to open it.
+ @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "EXPOSED_PARAMETER_TYPE")
+ fun `callCompilerAsync$kotlin_gradle_plugin_common`(
+ args: K2JVMCompilerArguments,
+ kotlinSources: Set<File>,
+ inputChanges: InputChanges,
+ taskOutputsBackup: TaskOutputsBackup?
+ ) {
+ val changedFiles = getChangedFiles(inputChanges, incrementalProps)
+ val extraOptions = incrementalChangesTransformers.get().flatMap {
+ it(changedFiles)
+ }
+ args.addPluginOptions(extraOptions)
+ super.callCompilerAsync(args, kotlinSources, inputChanges, taskOutputsBackup)
+ }
+
+ override fun skipCondition(): Boolean = sources.isEmpty && javaSources.isEmpty
+
+ @get:InputFiles
+ @get:SkipWhenEmpty
+ @get:IgnoreEmptyDirectories
+ @get:PathSensitive(PathSensitivity.RELATIVE)
+ override val javaSources: FileCollection = super.javaSources.filter {
+ !destination.get().isParentOf(it)
+ }
+}
+
+@CacheableTask
+abstract class KspTaskJS @Inject constructor(
+ objectFactory: ObjectFactory,
+ workerExecutor: WorkerExecutor
+) : Kotlin2JsCompile(
+ objectFactory.newInstance(KotlinJsCompilerOptionsDefault::class.java),
+ objectFactory,
+ workerExecutor
+ ),
+ KspTask {
+
+ // Overrding an internal function is hacky.
+ // TODO: Ask upstream to open it.
+ @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "EXPOSED_PARAMETER_TYPE")
+ fun `callCompilerAsync$kotlin_gradle_plugin_common`(
+ args: K2JSCompilerArguments,
+ kotlinSources: Set<File>,
+ inputChanges: InputChanges,
+ taskOutputsBackup: TaskOutputsBackup?
+ ) {
+ val changedFiles = getChangedFiles(inputChanges, incrementalProps)
+ val extraOptions = incrementalChangesTransformers.get().flatMap {
+ it(changedFiles)
+ }
+ args.addPluginOptions(extraOptions)
+ super.callCompilerAsync(args, kotlinSources, inputChanges, taskOutputsBackup)
+ }
+}
+
+@CacheableTask
+abstract class KspTaskMetadata @Inject constructor(
+ workerExecutor: WorkerExecutor,
+ objectFactory: ObjectFactory
+) : KotlinCompileCommon(
+ objectFactory.newInstance(KotlinMultiplatformCommonCompilerOptionsDefault::class.java),
+ workerExecutor,
+ objectFactory
+ ),
+ KspTask {
+
+ // Overrding an internal function is hacky.
+ // TODO: Ask upstream to open it.
+ @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "EXPOSED_PARAMETER_TYPE")
+ fun `callCompilerAsync$kotlin_gradle_plugin_common`(
+ args: K2MetadataCompilerArguments,
+ kotlinSources: Set<File>,
+ inputChanges: InputChanges,
+ taskOutputsBackup: TaskOutputsBackup?
+ ) {
+ val changedFiles = getChangedFiles(inputChanges, incrementalProps)
+ val extraOptions = incrementalChangesTransformers.get().flatMap {
+ it(changedFiles)
+ }
+ args.addPluginOptions(extraOptions)
+ super.callCompilerAsync(args, kotlinSources, inputChanges, taskOutputsBackup)
+ }
+}
+
+@CacheableTask
+abstract class KspTaskNative @Inject internal constructor(
+ compilation: KotlinNativeCompilationData<*>,
+ objectFactory: ObjectFactory,
+ providerFactory: ProviderFactory,
+ execOperations: ExecOperations
+) : KotlinNativeCompile(compilation, objectFactory, providerFactory, execOperations), KspTask {
+
+ override val compilerOptions: KotlinCommonCompilerOptions =
+ objectFactory.newInstance(KotlinMultiplatformCommonCompilerOptionsDefault::class.java)
+}
+
+internal fun SubpluginOption.toArg() = "plugin:${KspGradleSubplugin.KSP_PLUGIN_ID}:$key=$value"
+
+internal fun CommonCompilerArguments.addPluginOptions(options: List<SubpluginOption>) {
+ pluginOptions = (options.map { it.toArg() } + pluginOptions!!).toTypedArray()
+}
+
+internal fun File.isParentOf(childCandidate: File): Boolean {
+ val parentPath = Paths.get(this.absolutePath).normalize()
+ val childCandidatePath = Paths.get(childCandidate.absolutePath).normalize()
+
+ return childCandidatePath.startsWith(parentPath)
+}
diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspConfigurations.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspConfigurations.kt
new file mode 100644
index 00000000..bf16812d
--- /dev/null
+++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspConfigurations.kt
@@ -0,0 +1,176 @@
+package com.google.devtools.ksp.gradle
+
+import org.gradle.api.InvalidUserCodeException
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.jetbrains.kotlin.gradle.dsl.*
+import org.jetbrains.kotlin.gradle.plugin.*
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
+
+/**
+ * Creates and retrieves ksp-related configurations.
+ */
+class KspConfigurations(private val project: Project) {
+ companion object {
+ private const val PREFIX = "ksp"
+ }
+
+ private val allowAllTargetConfiguration =
+ project.findProperty("ksp.allow.all.target.configuration")?.let {
+ it.toString().toBoolean()
+ } ?: true
+
+ // The "ksp" configuration, applied to every compilations.
+ private val configurationForAll = project.configurations.create(PREFIX)
+
+ private fun configurationNameOf(vararg parts: String): String {
+ return parts.joinToString("") {
+ it.replaceFirstChar { it.uppercase() }
+ }.replaceFirstChar { it.lowercase() }
+ }
+
+ @OptIn(ExperimentalStdlibApi::class)
+ private fun createConfiguration(
+ name: String,
+ readableSetName: String,
+ ): Configuration {
+ // maybeCreate to be future-proof, but we should never have a duplicate with current logic
+ return project.configurations.maybeCreate(name).apply {
+ description = "KSP dependencies for the '$readableSetName' source set."
+ isCanBeResolved = false // we'll resolve the processor classpath config
+ isCanBeConsumed = false
+ isVisible = false
+ }
+ }
+
+ private fun getAndroidConfigurationName(target: KotlinTarget, sourceSet: String): String {
+ val isMain = sourceSet.endsWith("main", ignoreCase = true)
+ val nameWithoutMain = when {
+ isMain -> sourceSet.substring(0, sourceSet.length - 4)
+ else -> sourceSet
+ }
+ // Note: on single-platform, target name is conveniently set to "".
+ return configurationNameOf(PREFIX, target.name, nameWithoutMain)
+ }
+
+ private fun getKotlinConfigurationName(compilation: KotlinCompilation<*>, sourceSet: KotlinSourceSet): String {
+ val isMain = compilation.name == KotlinCompilation.MAIN_COMPILATION_NAME
+ val isDefault = sourceSet.name == compilation.defaultSourceSetName && compilation !is KotlinCommonCompilation
+ // Note: on single-platform, target name is conveniently set to "".
+ val name = if (isMain && isDefault) {
+ // For js(IR), js(LEGACY), the target "js" is created.
+ //
+ // When js(BOTH) is used, target "jsLegacy" and "jsIr" are created.
+ // Both targets share the same source set. Therefore configurations other than main compilation
+ // are shared. E.g., "kspJsTest".
+ // For simplicity and consistency, let's not distinguish them.
+ when (val targetName = compilation.target.name) {
+ "jsLegacy", "jsIr" -> "js"
+ else -> targetName
+ }
+ } else if (compilation is KotlinCommonCompilation) {
+ sourceSet.name + compilation.target.name.capitalize()
+ } else {
+ sourceSet.name
+ }
+ return configurationNameOf(PREFIX, name)
+ }
+
+ init {
+ project.plugins.withType(KotlinBasePluginWrapper::class.java).configureEach {
+ // 1.6.0: decorateKotlinProject(project.kotlinExtension)?
+ decorateKotlinProject(project.extensions.getByName("kotlin") as KotlinProjectExtension, project)
+ }
+ }
+
+ private fun decorateKotlinProject(kotlin: KotlinProjectExtension, project: Project) {
+ when (kotlin) {
+ is KotlinSingleTargetExtension<*> -> decorateKotlinTarget(kotlin.target)
+ is KotlinMultiplatformExtension -> {
+ kotlin.targets.configureEach(::decorateKotlinTarget)
+
+ var reported = false
+ configurationForAll.dependencies.whenObjectAdded {
+ if (!reported) {
+ reported = true
+ val msg = "The 'ksp' configuration is deprecated in Kotlin Multiplatform projects. " +
+ "Please use target-specific configurations like 'kspJvm' instead."
+
+ if (allowAllTargetConfiguration) {
+ project.logger.warn(msg)
+ } else {
+ throw InvalidUserCodeException(msg)
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Decorate the [KotlinSourceSet]s belonging to [target] to create one KSP configuration per source set,
+ * named ksp<SourceSet>. The only exception is the main source set, for which we avoid using the
+ * "main" suffix (so what would be "kspJvmMain" becomes "kspJvm").
+ *
+ * For Android, we prefer to use AndroidSourceSets from AGP rather than [KotlinSourceSet]s.
+ * Even though the Kotlin Plugin does create [KotlinSourceSet]s out of AndroidSourceSets
+ * ( https://kotlinlang.org/docs/mpp-configure-compilations.html#compilation-of-the-source-set-hierarchy ),
+ * there are slight differences between the two - Kotlin creates some extra sets with unexpected word ordering,
+ * and things get worse when you add product flavors. So, we use AGP sets as the source of truth.
+ */
+ private fun decorateKotlinTarget(target: KotlinTarget) {
+ if (target.platformType == KotlinPlatformType.androidJvm) {
+ AndroidPluginIntegration.forEachAndroidSourceSet(target.project) { sourceSet ->
+ createConfiguration(
+ name = getAndroidConfigurationName(target, sourceSet),
+ readableSetName = "$sourceSet (Android)"
+ )
+ }
+ } else {
+ target.compilations.configureEach { compilation ->
+ compilation.kotlinSourceSets.forEach { sourceSet ->
+ createConfiguration(
+ name = getKotlinConfigurationName(compilation, sourceSet),
+ readableSetName = sourceSet.name
+ )
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the user-facing configurations involved in the given compilation.
+ * We use [KotlinCompilation.kotlinSourceSets], not [KotlinCompilation.allKotlinSourceSets] for a few reasons:
+ * 1) consistency with how we created the configurations. For example, all* can return user-defined sets
+ * that don't belong to any compilation, like user-defined intermediate source sets (e.g. iosMain).
+ * These do not currently have their own ksp configuration.
+ * 2) all* can return sets belonging to other [KotlinCompilation]s
+ *
+ * See test: SourceSetConfigurationsTest.configurationsForMultiplatformApp_doesNotCrossCompilationBoundaries
+ */
+ fun find(compilation: KotlinCompilation<*>): Set<Configuration> {
+ val results = mutableListOf<String>()
+ if (compilation is KotlinCommonCompilation) {
+ results.add(getKotlinConfigurationName(compilation, compilation.defaultSourceSet))
+ }
+ compilation.kotlinSourceSets.mapTo(results) {
+ getKotlinConfigurationName(compilation, it)
+ }
+ if (compilation.platformType == KotlinPlatformType.androidJvm) {
+ compilation as KotlinJvmAndroidCompilation
+ AndroidPluginIntegration.getCompilationSourceSets(compilation).mapTo(results) {
+ getAndroidConfigurationName(compilation.target, it)
+ }
+ }
+
+ // Include the `ksp` configuration, if it exists, for all compilations.
+ if (allowAllTargetConfiguration) {
+ results.add(configurationForAll.name)
+ }
+
+ return results.mapNotNull {
+ compilation.target.project.configurations.findByName(it)
+ }.toSet()
+ }
+}
diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspExtension.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspExtension.kt
new file mode 100644
index 00000000..9beac05d
--- /dev/null
+++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspExtension.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.gradle
+
+import org.gradle.api.GradleException
+import org.gradle.process.CommandLineArgumentProvider
+
+open class KspExtension {
+ internal val apOptions = mutableMapOf<String, String>()
+ internal val commandLineArgumentProviders = mutableListOf<CommandLineArgumentProvider>()
+ internal val excludedProcessors = mutableSetOf<String>()
+
+ open val arguments: Map<String, String> get() = apOptions.toMap()
+
+ open fun arg(k: String, v: String) {
+ if ('=' in k) {
+ throw GradleException("'=' is not allowed in custom option's name.")
+ }
+ apOptions.put(k, v)
+ }
+
+ open fun arg(arg: CommandLineArgumentProvider) {
+ commandLineArgumentProviders.add(arg)
+ }
+
+ @Deprecated("KSP will stop supporting other compiler plugins in KSP's Gradle tasks after 1.0.8.")
+ open var blockOtherCompilerPlugins: Boolean = true
+
+ // Instruct KSP to pickup sources from compile tasks, instead of source sets.
+ // Note that it depends on behaviors of other Gradle plugins, that may bring surprises and can be hard to debug.
+ // Use your discretion.
+ open var allowSourcesFromOtherPlugins: Boolean = false
+
+ // Treat all warning as errors.
+ open var allWarningsAsErrors: Boolean = false
+
+ // Keep processor providers from being called. Providers will still be loaded if they're in classpath.
+ open fun excludeProcessor(fullyQualifiedName: String) {
+ excludedProcessors.add(fullyQualifiedName)
+ }
+}
diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspSubplugin.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspSubplugin.kt
new file mode 100644
index 00000000..97d6d479
--- /dev/null
+++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspSubplugin.kt
@@ -0,0 +1,762 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.gradle
+
+import com.google.devtools.ksp.gradle.model.builder.KspModelBuilder
+import org.gradle.api.Action
+import org.gradle.api.Project
+import org.gradle.api.Task
+import org.gradle.api.UnknownTaskException
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.attributes.Attribute
+import org.gradle.api.file.ConfigurableFileCollection
+import org.gradle.api.file.FileCollection
+import org.gradle.api.provider.ListProperty
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.TaskProvider
+import org.gradle.api.tasks.compile.JavaCompile
+import org.gradle.language.jvm.tasks.ProcessResources
+import org.gradle.process.CommandLineArgumentProvider
+import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
+import org.gradle.util.GradleVersion
+import org.jetbrains.kotlin.config.ApiVersion
+import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
+import org.jetbrains.kotlin.gradle.internal.kapt.incremental.CLASS_STRUCTURE_ARTIFACT_TYPE
+import org.jetbrains.kotlin.gradle.internal.kapt.incremental.ClasspathSnapshot
+import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptClasspathChanges
+import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformAction
+import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformLegacyAction
+import org.jetbrains.kotlin.gradle.plugin.CompilerPluginConfig
+import org.jetbrains.kotlin.gradle.plugin.FilesSubpluginOption
+import org.jetbrains.kotlin.gradle.plugin.InternalSubpluginOption
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationWithResources
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerPluginSupportPlugin
+import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
+import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
+import org.jetbrains.kotlin.gradle.plugin.SubpluginArtifact
+import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
+import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaCompilation
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
+import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
+import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool
+import org.jetbrains.kotlin.gradle.tasks.BaseKotlinCompile
+import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon
+import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
+import org.jetbrains.kotlin.incremental.ChangedFiles
+import org.jetbrains.kotlin.incremental.isJavaFile
+import org.jetbrains.kotlin.incremental.isKotlinFile
+import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
+import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
+import java.io.File
+import java.util.concurrent.Callable
+import javax.inject.Inject
+
+class KspGradleSubplugin @Inject internal constructor(private val registry: ToolingModelBuilderRegistry) :
+ KotlinCompilerPluginSupportPlugin {
+ companion object {
+ const val KSP_PLUGIN_ID = "com.google.devtools.ksp.symbol-processing"
+ const val KSP_API_ID = "symbol-processing-api"
+ const val KSP_COMPILER_PLUGIN_ID = "symbol-processing"
+ const val KSP_COMPILER_PLUGIN_ID_NON_EMBEDDABLE = "symbol-processing-cmdline"
+ const val KSP_GROUP_ID = "com.google.devtools.ksp"
+ const val KSP_PLUGIN_CLASSPATH_CONFIGURATION_NAME = "kspPluginClasspath"
+ const val KSP_PLUGIN_CLASSPATH_CONFIGURATION_NAME_NON_EMBEDDABLE = "kspPluginClasspathNonEmbeddable"
+
+ @JvmStatic
+ fun getKspOutputDir(project: Project, sourceSetName: String, target: String) =
+ File(project.project.buildDir, "generated/ksp/$target/$sourceSetName")
+
+ @JvmStatic
+ fun getKspClassOutputDir(project: Project, sourceSetName: String, target: String) =
+ File(getKspOutputDir(project, sourceSetName, target), "classes")
+
+ @JvmStatic
+ fun getKspJavaOutputDir(project: Project, sourceSetName: String, target: String) =
+ File(getKspOutputDir(project, sourceSetName, target), "java")
+
+ @JvmStatic
+ fun getKspKotlinOutputDir(project: Project, sourceSetName: String, target: String) =
+ File(getKspOutputDir(project, sourceSetName, target), "kotlin")
+
+ @JvmStatic
+ fun getKspResourceOutputDir(project: Project, sourceSetName: String, target: String) =
+ File(getKspOutputDir(project, sourceSetName, target), "resources")
+
+ @JvmStatic
+ fun getKspCachesDir(project: Project, sourceSetName: String, target: String) =
+ File(project.project.buildDir, "kspCaches/$target/$sourceSetName")
+
+ @JvmStatic
+ private fun getSubpluginOptions(
+ project: Project,
+ kspExtension: KspExtension,
+ classpath: Configuration,
+ sourceSetName: String,
+ target: String,
+ isIncremental: Boolean,
+ allWarningsAsErrors: Boolean,
+ commandLineArgumentProviders: ListProperty<CommandLineArgumentProvider>,
+ commonSources: List<File>,
+ ): List<SubpluginOption> {
+ val options = mutableListOf<SubpluginOption>()
+ options +=
+ InternalSubpluginOption("classOutputDir", getKspClassOutputDir(project, sourceSetName, target).path)
+ options +=
+ InternalSubpluginOption("javaOutputDir", getKspJavaOutputDir(project, sourceSetName, target).path)
+ options +=
+ InternalSubpluginOption("kotlinOutputDir", getKspKotlinOutputDir(project, sourceSetName, target).path)
+ options += InternalSubpluginOption(
+ "resourceOutputDir",
+ getKspResourceOutputDir(project, sourceSetName, target).path
+ )
+ options += InternalSubpluginOption("cachesDir", getKspCachesDir(project, sourceSetName, target).path)
+ options += InternalSubpluginOption("kspOutputDir", getKspOutputDir(project, sourceSetName, target).path)
+ options += SubpluginOption("incremental", isIncremental.toString())
+ options += SubpluginOption(
+ "incrementalLog",
+ project.findProperty("ksp.incremental.log")?.toString() ?: "false"
+ )
+ options += InternalSubpluginOption("projectBaseDir", project.project.projectDir.canonicalPath)
+ options += SubpluginOption("allWarningsAsErrors", allWarningsAsErrors.toString())
+ options += FilesSubpluginOption("apclasspath", classpath.toList())
+ // Turn this on by default to work KT-30172 around. It is off by default in the compiler plugin.
+ options += SubpluginOption(
+ "returnOkOnError",
+ project.findProperty("ksp.return.ok.on.error")?.toString() ?: "true"
+ )
+ commonSources.ifNotEmpty {
+ options += FilesSubpluginOption("commonSources", this)
+ }
+
+ kspExtension.apOptions.forEach {
+ options += SubpluginOption("apoption", "${it.key}=${it.value}")
+ }
+ options += SubpluginOption(
+ "excludedProcessors",
+ kspExtension.excludedProcessors.joinToString(":")
+ )
+ options += SubpluginOption(
+ "mapAnnotationArgumentsInJava",
+ project.findProperty("ksp.map.annotation.arguments.in.java")?.toString() ?: "false"
+ )
+ commandLineArgumentProviders.get().forEach {
+ it.asArguments().forEach { argument ->
+ if (!argument.matches(Regex("\\S+=\\S+"))) {
+ throw IllegalArgumentException("KSP apoption does not match \\S+=\\S+: $argument")
+ }
+ options += SubpluginOption("apoption", argument)
+ }
+ }
+ return options
+ }
+ }
+
+ private lateinit var kspConfigurations: KspConfigurations
+
+ override fun apply(target: Project) {
+ target.extensions.create("ksp", KspExtension::class.java)
+ kspConfigurations = KspConfigurations(target)
+ registry.register(KspModelBuilder())
+ }
+
+ override fun isApplicable(kotlinCompilation: KotlinCompilation<*>): Boolean {
+ val project = kotlinCompilation.target.project
+ val kspVersion = ApiVersion.parse(KSP_KOTLIN_BASE_VERSION)!!
+ val kotlinVersion = ApiVersion.parse(project.getKotlinPluginVersion())!!
+
+ // Check version and show warning by default.
+ val noVersionCheck = project.findProperty("ksp.version.check")?.toString()?.toBoolean() == false
+ if (!noVersionCheck) {
+ if (kspVersion < kotlinVersion) {
+ project.logger.warn(
+ "ksp-$KSP_VERSION is too old for kotlin-$kotlinVersion. " +
+ "Please upgrade ksp or downgrade kotlin-gradle-plugin to $KSP_KOTLIN_BASE_VERSION."
+ )
+ }
+ if (kspVersion > kotlinVersion) {
+ project.logger.warn(
+ "ksp-$KSP_VERSION is too new for kotlin-$kotlinVersion. " +
+ "Please upgrade kotlin-gradle-plugin to $KSP_KOTLIN_BASE_VERSION."
+ )
+ }
+ }
+
+ return true
+ }
+
+ // TODO: to be future proof, protect with `synchronized`
+ // Map from default input source set to output source set
+ private val sourceSetMap: MutableMap<KotlinSourceSet, KotlinSourceSet> = mutableMapOf()
+
+ override fun applyToCompilation(kotlinCompilation: KotlinCompilation<*>): Provider<List<SubpluginOption>> {
+ val project = kotlinCompilation.target.project
+ val kotlinCompileProvider: TaskProvider<AbstractKotlinCompileTool<*>> =
+ project.locateTask(kotlinCompilation.compileKotlinTaskName) ?: return project.provider { emptyList() }
+ val kspExtension = project.extensions.getByType(KspExtension::class.java)
+ val kspConfigurations = kspConfigurations.find(kotlinCompilation)
+ val nonEmptyKspConfigurations = kspConfigurations.filter { it.allDependencies.isNotEmpty() }
+ if (nonEmptyKspConfigurations.isEmpty()) {
+ return project.provider { emptyList() }
+ }
+ if (kotlinCompileProvider.name == "compileKotlinMetadata") {
+ return project.provider { emptyList() }
+ }
+
+ val target = kotlinCompilation.target.name
+ val sourceSetName = kotlinCompilation.defaultSourceSet.name
+ val classOutputDir = getKspClassOutputDir(project, sourceSetName, target)
+ val javaOutputDir = getKspJavaOutputDir(project, sourceSetName, target)
+ val kotlinOutputDir = getKspKotlinOutputDir(project, sourceSetName, target)
+ val resourceOutputDir = getKspResourceOutputDir(project, sourceSetName, target)
+ val kspOutputDir = getKspOutputDir(project, sourceSetName, target)
+
+ val kspClasspathCfg = project.configurations.maybeCreate(KSP_PLUGIN_CLASSPATH_CONFIGURATION_NAME)
+ project.dependencies.add(
+ KSP_PLUGIN_CLASSPATH_CONFIGURATION_NAME,
+ "$KSP_GROUP_ID:$KSP_API_ID:$KSP_VERSION"
+ )
+ project.dependencies.add(
+ KSP_PLUGIN_CLASSPATH_CONFIGURATION_NAME,
+ "$KSP_GROUP_ID:$KSP_COMPILER_PLUGIN_ID:$KSP_VERSION"
+ )
+
+ val kspClasspathCfgNonEmbeddable = project.configurations.maybeCreate(
+ KSP_PLUGIN_CLASSPATH_CONFIGURATION_NAME_NON_EMBEDDABLE
+ )
+ project.dependencies.add(
+ KSP_PLUGIN_CLASSPATH_CONFIGURATION_NAME_NON_EMBEDDABLE,
+ "$KSP_GROUP_ID:$KSP_API_ID:$KSP_VERSION"
+ )
+ project.dependencies.add(
+ KSP_PLUGIN_CLASSPATH_CONFIGURATION_NAME_NON_EMBEDDABLE,
+ "$KSP_GROUP_ID:$KSP_COMPILER_PLUGIN_ID_NON_EMBEDDABLE:$KSP_VERSION"
+ )
+
+ findJavaTaskForKotlinCompilation(kotlinCompilation)?.configure { javaCompile ->
+ val generatedJavaSources = javaCompile.project.fileTree(javaOutputDir)
+ generatedJavaSources.include("**/*.java")
+ javaCompile.source(generatedJavaSources)
+ javaCompile.classpath += project.files(classOutputDir)
+ }
+
+ val processingModel = project.findProperty("ksp.experimental.processing.model")?.toString() ?: "traditional"
+
+ assert(kotlinCompileProvider.name.startsWith("compile"))
+ val kspTaskName = kotlinCompileProvider.name.replaceFirst("compile", "ksp")
+
+ val kspGeneratedSourceSet =
+ project.kotlinExtension.sourceSets.create("generatedBy" + kspTaskName.capitalizeAsciiOnly())
+ sourceSetMap.put(kotlinCompilation.defaultSourceSet, kspGeneratedSourceSet)
+
+ val processorClasspath = project.configurations.maybeCreate("${kspTaskName}ProcessorClasspath")
+ .extendsFrom(*nonEmptyKspConfigurations.toTypedArray())
+ fun configureAsKspTask(kspTask: KspTask, isIncremental: Boolean) {
+ // depends on the processor; if the processor changes, it needs to be reprocessed.
+ kspTask.dependsOn(processorClasspath.buildDependencies)
+ kspTask.commandLineArgumentProviders.addAll(kspExtension.commandLineArgumentProviders)
+
+ val commonSources: List<File> = when (processingModel) {
+ "hierarchical" -> {
+ fun unclaimedDeps(roots: Set<KotlinSourceSet>): Set<KotlinSourceSet> {
+ val unclaimedParents =
+ roots.flatMap { it.dependsOn }.filterNot { it in sourceSetMap }.toSet()
+ return if (unclaimedParents.isEmpty()) {
+ unclaimedParents
+ } else {
+ unclaimedParents + unclaimedDeps(unclaimedParents)
+ }
+ }
+ // Source sets that are not claimed by other compilations.
+ // I.e., those that should be processed by this compilation.
+ val unclaimed =
+ kotlinCompilation.kotlinSourceSets + unclaimedDeps(kotlinCompilation.kotlinSourceSets)
+ val commonSourceSets = kotlinCompilation.allKotlinSourceSets - unclaimed
+ commonSourceSets.flatMap { it.kotlin.files }
+ }
+ else -> emptyList()
+ }
+
+ kspTask.options.addAll(
+ kspTask.project.provider {
+ getSubpluginOptions(
+ project,
+ kspExtension,
+ processorClasspath,
+ sourceSetName,
+ target,
+ isIncremental,
+ kspExtension.allWarningsAsErrors,
+ kspTask.commandLineArgumentProviders,
+ commonSources,
+ )
+ }
+ )
+ kspTask.inputs.property("apOptions", kspExtension.arguments)
+ }
+
+ fun configureAsAbstractKotlinCompileTool(kspTask: AbstractKotlinCompileTool<*>) {
+ when (kspTask) {
+ is Kotlin2JsCompile -> {
+ kspTask.outputFileProperty.value(
+ File(kspOutputDir, "dummyOutput.js")
+ )
+ }
+ else -> kspTask.destinationDirectory.set(kspOutputDir)
+ }
+ kspTask.outputs.dirs(
+ kotlinOutputDir,
+ javaOutputDir,
+ classOutputDir,
+ resourceOutputDir
+ )
+
+ val kotlinCompileTask = kotlinCompileProvider.get()
+ if (kspExtension.allowSourcesFromOtherPlugins) {
+ fun FileCollection.nonSelfDeps(): List<Task> =
+ buildDependencies.getDependencies(null).filterNot {
+ it.name == kspTaskName
+ }
+
+ fun setSource(source: FileCollection) {
+ // kspTask.setSource(source) would create circular dependency.
+ // Therefore we need to manually extract input deps, filter them, and tell kspTask.
+ kspTask.setSource(project.provider { source.files })
+ kspTask.dependsOn(project.provider { source.nonSelfDeps() })
+ }
+
+ setSource(kotlinCompileTask.sources - kspGeneratedSourceSet.kotlin)
+ if (kotlinCompileTask is KotlinCompile) {
+ setSource(kotlinCompileTask.javaSources - kspGeneratedSourceSet.kotlin)
+ }
+ } else {
+ kotlinCompilation.allKotlinSourceSets.filterNot { it == kspGeneratedSourceSet }.forEach { sourceSet ->
+ kspTask.setSource(sourceSet.kotlin)
+ }
+ if (kotlinCompilation is KotlinCommonCompilation) {
+ kspTask.setSource(kotlinCompilation.defaultSourceSet.kotlin)
+ }
+ val generated = when (processingModel) {
+ "hierarchical" -> {
+ // boundary parent source sets that are going to be compiled by other compilations
+ fun claimedParents(root: KotlinSourceSet): Set<KotlinSourceSet> {
+ val (claimed, unclaimed) = root.dependsOn.partition { it in sourceSetMap }
+ return claimed.toSet() + unclaimed.flatMap { claimedParents(it) }
+ }
+ kotlinCompilation.kotlinSourceSets.flatMap { claimedParents(it) }.map { sourceSetMap[it]!! }
+ }
+ else -> emptyList()
+ }
+ generated.forEach {
+ kspTask.setSource(it.kotlin)
+ }
+ }
+ kspTask.exclude { kspOutputDir.isParentOf(it.file) }
+
+ kspTask.libraries.setFrom(
+ kotlinCompileTask.project.files(
+ Callable {
+ kotlinCompileTask.libraries.filter {
+ !kspOutputDir.isParentOf(it)
+ }
+ }
+ )
+ )
+ // kotlinc's incremental compilation isn't compatible with symbol processing in a few ways:
+ // * It doesn't consider private / internal changes when computing dirty sets.
+ // * It compiles iteratively; Sources can be compiled in different rounds.
+ (kspTask as? AbstractKotlinCompile<*>)?.incremental = false
+ }
+
+ fun maybeBlockOtherPlugins(kspTask: BaseKotlinCompile) {
+ if (kspExtension.blockOtherCompilerPlugins) {
+ kspTask.pluginClasspath.setFrom(kspClasspathCfg)
+ kspTask.pluginOptions.set(emptyList())
+ }
+ }
+
+ fun configurePluginOptions(kspTask: BaseKotlinCompile) {
+ kspTask.pluginOptions.add(
+ project.provider {
+ CompilerPluginConfig().apply {
+ (kspTask as KspTask).options.get().forEach {
+ addPluginArgument(KSP_PLUGIN_ID, it)
+ }
+ }
+ }
+ )
+ }
+
+ val isIncremental = project.findProperty("ksp.incremental")?.toString()?.toBoolean() ?: true
+
+ // Create and configure KSP tasks.
+ val kspTaskProvider = when (kotlinCompilation.platformType) {
+ KotlinPlatformType.jvm, KotlinPlatformType.androidJvm -> {
+ kotlinCompilation as KotlinCompilationData<*>
+ KotlinFactories.registerKotlinJvmCompileTask(project, kspTaskName, kotlinCompilation).also {
+ it.configure { kspTask ->
+ val kotlinCompileTask = kotlinCompileProvider.get() as KotlinCompile
+ maybeBlockOtherPlugins(kspTask as BaseKotlinCompile)
+ configureAsKspTask(kspTask, isIncremental)
+ configureAsAbstractKotlinCompileTool(kspTask as AbstractKotlinCompileTool<*>)
+ configurePluginOptions(kspTask)
+ kspTask.compilerOptions.noJdk.value(kotlinCompileTask.compilerOptions.noJdk)
+ kspTask.compilerOptions.useK2.value(false)
+ kspTask.ownModuleName.value(kotlinCompileTask.ownModuleName.map { "$it-ksp" })
+ kspTask.moduleName.value(kotlinCompileTask.moduleName.get())
+ kspTask.destination.value(kspOutputDir)
+
+ val isIntermoduleIncremental =
+ (project.findProperty("ksp.incremental.intermodule")?.toString()?.toBoolean() ?: true) &&
+ isIncremental
+ val classStructureFiles = getClassStructureFiles(project, kspTask.libraries)
+ kspTask.incrementalChangesTransformers.add(
+ createIncrementalChangesTransformer(
+ isIncremental,
+ isIntermoduleIncremental,
+ getKspCachesDir(project, sourceSetName, target),
+ project.provider { classStructureFiles },
+ project.provider { kspTask.libraries },
+ project.provider { processorClasspath }
+ )
+ )
+ }
+ // Don't support binary generation for non-JVM platforms yet.
+ // FIXME: figure out how to add user generated libraries.
+ kotlinCompilation.output.classesDirs.from(classOutputDir)
+ }
+ }
+ KotlinPlatformType.js, KotlinPlatformType.wasm -> {
+ kotlinCompilation as KotlinCompilationData<*>
+ KotlinFactories.registerKotlinJSCompileTask(project, kspTaskName, kotlinCompilation).also {
+ it.configure { kspTask ->
+ val kotlinCompileTask = kotlinCompileProvider.get() as Kotlin2JsCompile
+ maybeBlockOtherPlugins(kspTask as BaseKotlinCompile)
+ configureAsKspTask(kspTask, isIncremental)
+ configureAsAbstractKotlinCompileTool(kspTask as AbstractKotlinCompileTool<*>)
+ configurePluginOptions(kspTask)
+ kspTask.compilerOptions.freeCompilerArgs
+ .value(kotlinCompileTask.compilerOptions.freeCompilerArgs)
+ kspTask.compilerOptions.useK2.value(false)
+ kspTask.moduleName.value(kotlinCompileTask.moduleName.map { "$it-ksp" })
+
+ kspTask.incrementalChangesTransformers.add(
+ createIncrementalChangesTransformer(
+ isIncremental,
+ false,
+ getKspCachesDir(project, sourceSetName, target),
+ project.provider { project.files() },
+ project.provider { project.files() },
+ project.provider { project.files() },
+ )
+ )
+ }
+ }
+ }
+ KotlinPlatformType.common -> {
+ kotlinCompilation as KotlinCompilationData<*>
+ KotlinFactories.registerKotlinMetadataCompileTask(project, kspTaskName, kotlinCompilation).also {
+ it.configure { kspTask ->
+ val kotlinCompileTask = kotlinCompileProvider.get() as KotlinCompileCommon
+ maybeBlockOtherPlugins(kspTask as BaseKotlinCompile)
+ configureAsKspTask(kspTask, isIncremental)
+ configureAsAbstractKotlinCompileTool(kspTask as AbstractKotlinCompileTool<*>)
+ configurePluginOptions(kspTask)
+ kspTask.compilerOptions.useK2.value(false)
+
+ kspTask.incrementalChangesTransformers.add(
+ createIncrementalChangesTransformer(
+ isIncremental,
+ false,
+ getKspCachesDir(project, sourceSetName, target),
+ project.provider { project.files() },
+ project.provider { project.files() },
+ project.provider { project.files() },
+ )
+ )
+ }
+ }
+ }
+ KotlinPlatformType.native -> {
+ KotlinFactories.registerKotlinNativeCompileTask(project, kspTaskName, kotlinCompilation).also {
+ it.configure { kspTask ->
+ val kotlinCompileTask = kotlinCompileProvider.get() as KotlinNativeCompile
+ configureAsKspTask(kspTask, false)
+ configureAsAbstractKotlinCompileTool(kspTask)
+
+ val useEmbeddable = project.findProperty("kotlin.native.useEmbeddableCompilerJar")
+ ?.toString()?.toBoolean() ?: true
+ val classpathCfg = if (useEmbeddable) {
+ kspClasspathCfg
+ } else {
+ kspClasspathCfgNonEmbeddable
+ }
+ // KotlinNativeCompile computes -Xplugin=... from compilerPluginClasspath.
+ if (kspExtension.blockOtherCompilerPlugins) {
+ kspTask.compilerPluginClasspath = classpathCfg
+ } else {
+ kspTask.compilerPluginClasspath =
+ classpathCfg + kotlinCompileTask.compilerPluginClasspath!!
+ kspTask.compilerPluginOptions.addPluginArgument(kotlinCompileTask.compilerPluginOptions)
+ }
+ kspTask.commonSources.from(kotlinCompileTask.commonSources)
+ val kspOptions = kspTask.options.get().flatMap { listOf("-P", it.toArg()) }
+ kspTask.compilerOptions.freeCompilerArgs.value(
+ kspOptions + kotlinCompileTask.compilerOptions.freeCompilerArgs.get()
+ )
+ kspTask.compilerOptions.useK2.value(false)
+ // Cannot use lambda; See below for details.
+ // https://docs.gradle.org/7.2/userguide/validation_problems.html#implementation_unknown
+ kspTask.doFirst(object : Action<Task> {
+ override fun execute(t: Task) {
+ kspOutputDir.deleteRecursively()
+ }
+ })
+ }
+ }
+ }
+ // No else; The cases should be exhaustive
+ }
+ kspGeneratedSourceSet.kotlin.srcDir(project.files(kotlinOutputDir, javaOutputDir).builtBy(kspTaskProvider))
+ kotlinCompilation.source(kspGeneratedSourceSet)
+ kotlinCompileProvider.configure { kotlinCompile ->
+ when (kotlinCompile) {
+ is AbstractKotlinCompile<*> -> kotlinCompile.libraries.from(project.files(classOutputDir))
+ // is KotlinNativeCompile -> TODO: support binary generation?
+ }
+ }
+
+ val processResourcesTaskName =
+ (kotlinCompilation as? KotlinCompilationWithResources)?.processResourcesTaskName ?: "processResources"
+ project.locateTask<ProcessResources>(processResourcesTaskName)?.let { provider ->
+ provider.configure { resourcesTask ->
+ resourcesTask.from(project.files(resourceOutputDir).builtBy(kspTaskProvider))
+ }
+ }
+ if (kotlinCompilation is KotlinJvmAndroidCompilation) {
+ AndroidPluginIntegration.registerGeneratedSources(
+ project = project,
+ kotlinCompilation = kotlinCompilation,
+ kspTaskProvider = kspTaskProvider as TaskProvider<KspTaskJvm>,
+ javaOutputDir = javaOutputDir,
+ kotlinOutputDir = kotlinOutputDir,
+ classOutputDir = classOutputDir,
+ resourcesOutputDir = project.files(resourceOutputDir)
+ )
+ }
+
+ return project.provider { emptyList() }
+ }
+
+ override fun getCompilerPluginId() = KSP_PLUGIN_ID
+ override fun getPluginArtifact(): SubpluginArtifact =
+ SubpluginArtifact(
+ groupId = "com.google.devtools.ksp",
+ artifactId = KSP_COMPILER_PLUGIN_ID,
+ version = KSP_VERSION
+ )
+
+ override fun getPluginArtifactForNative(): SubpluginArtifact? =
+ SubpluginArtifact(
+ groupId = "com.google.devtools.ksp",
+ artifactId = KSP_COMPILER_PLUGIN_ID_NON_EMBEDDABLE,
+ version = KSP_VERSION
+ )
+}
+
+// Copied from kotlin-gradle-plugin, because they are internal.
+internal inline fun <reified T : Task> Project.locateTask(name: String): TaskProvider<T>? =
+ try {
+ tasks.withType(T::class.java).named(name)
+ } catch (e: UnknownTaskException) {
+ null
+ }
+
+// Copied from kotlin-gradle-plugin, because they are internal.
+internal fun findJavaTaskForKotlinCompilation(compilation: KotlinCompilation<*>): TaskProvider<out JavaCompile>? =
+ when (compilation) {
+ is KotlinJvmAndroidCompilation -> compilation.compileJavaTaskProvider
+ is KotlinWithJavaCompilation<*, *> -> compilation.compileJavaTaskProvider
+ is KotlinJvmCompilation -> compilation.compileJavaTaskProvider // may be null for Kotlin-only JVM target in MPP
+ else -> null
+ }
+
+internal val artifactType = Attribute.of("artifactType", String::class.java)
+
+internal fun maybeRegisterTransform(project: Project) {
+ // Use the same flag with KAPT, so as to share the same transformation in case KAPT and KSP are both enabled.
+ if (!project.extensions.extraProperties.has("KaptStructureTransformAdded")) {
+ val transformActionClass =
+ if (GradleVersion.current() >= GradleVersion.version("5.4"))
+ StructureTransformAction::class.java
+ else
+
+ StructureTransformLegacyAction::class.java
+ project.dependencies.registerTransform(transformActionClass) { transformSpec ->
+ transformSpec.from.attribute(artifactType, "jar")
+ transformSpec.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
+ }
+
+ project.dependencies.registerTransform(transformActionClass) { transformSpec ->
+ transformSpec.from.attribute(artifactType, "directory")
+ transformSpec.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
+ }
+
+ project.extensions.extraProperties["KaptStructureTransformAdded"] = true
+ }
+}
+
+internal fun getClassStructureFiles(
+ project: Project,
+ libraries: ConfigurableFileCollection,
+): FileCollection {
+ maybeRegisterTransform(project)
+
+ val classStructureIfIncremental = project.configurations.detachedConfiguration(
+ project.dependencies.create(project.files(project.provider { libraries }))
+ )
+
+ return classStructureIfIncremental.incoming.artifactView { viewConfig ->
+ viewConfig.attributes.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
+ }.files
+}
+
+// Reuse Kapt's infrastructure to compute affected names in classpath.
+// This is adapted from KaptTask.findClasspathChanges.
+internal fun findClasspathChanges(
+ changes: ChangedFiles,
+ cacheDir: File,
+ allDataFiles: Set<File>,
+ libs: List<File>,
+ processorCP: List<File>,
+): KaptClasspathChanges {
+ cacheDir.mkdirs()
+
+ val changedFiles = (changes as? ChangedFiles.Known)?.let { it.modified + it.removed }?.toSet() ?: allDataFiles
+
+ val loadedPrevious = ClasspathSnapshot.ClasspathSnapshotFactory.loadFrom(cacheDir)
+ val previousAndCurrentDataFiles = lazy { loadedPrevious.getAllDataFiles() + allDataFiles }
+ val allChangesRecognized = changedFiles.all {
+ val extension = it.extension
+ if (extension.isEmpty() || extension == "kt" || extension == "java" || extension == "jar" ||
+ extension == "class"
+ ) {
+ return@all true
+ }
+ // if not a directory, Java source file, jar, or class, it has to be a structure file, in order to understand changes
+ it in previousAndCurrentDataFiles.value
+ }
+ val previousSnapshot = if (allChangesRecognized) {
+ loadedPrevious
+ } else {
+ ClasspathSnapshot.ClasspathSnapshotFactory.getEmptySnapshot()
+ }
+
+ val currentSnapshot =
+ ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(
+ cacheDir,
+ libs,
+ processorCP,
+ allDataFiles
+ )
+
+ val classpathChanges = currentSnapshot.diff(previousSnapshot, changedFiles)
+ if (classpathChanges is KaptClasspathChanges.Unknown || changes is ChangedFiles.Unknown) {
+ cacheDir.deleteRecursively()
+ cacheDir.mkdirs()
+ }
+ currentSnapshot.writeToCache()
+
+ return classpathChanges
+}
+
+internal fun ChangedFiles.hasNonSourceChange(): Boolean {
+ if (this !is ChangedFiles.Known)
+ return true
+
+ return !(this.modified + this.removed).all {
+ it.isKotlinFile(listOf("kt")) || it.isJavaFile()
+ }
+}
+
+fun KaptClasspathChanges.toSubpluginOptions(): List<SubpluginOption> {
+ return if (this is KaptClasspathChanges.Known) {
+ this.names.map { it.replace('/', '.').replace('$', '.') }.ifNotEmpty {
+ listOf(SubpluginOption("changedClasses", joinToString(":")))
+ } ?: emptyList()
+ } else {
+ emptyList()
+ }
+}
+
+fun ChangedFiles.toSubpluginOptions(): List<SubpluginOption> {
+ return if (this is ChangedFiles.Known) {
+ val options = mutableListOf<SubpluginOption>()
+ this.modified.filter { it.isKotlinFile(listOf("kt")) || it.isJavaFile() }.ifNotEmpty {
+ options += SubpluginOption("knownModified", map { it.path }.joinToString(File.pathSeparator))
+ }
+ this.removed.filter { it.isKotlinFile(listOf("kt")) || it.isJavaFile() }.ifNotEmpty {
+ options += SubpluginOption("knownRemoved", map { it.path }.joinToString(File.pathSeparator))
+ }
+ options
+ } else {
+ emptyList()
+ }
+}
+
+// Return a closure that captures required arguments only.
+internal fun createIncrementalChangesTransformer(
+ isKspIncremental: Boolean,
+ isIntermoduleIncremental: Boolean,
+ cacheDir: File,
+ classpathStructure: Provider<FileCollection>,
+ libraries: Provider<FileCollection>,
+ processorCP: Provider<FileCollection>,
+): (ChangedFiles) -> List<SubpluginOption> = { changedFiles ->
+ val options = mutableListOf<SubpluginOption>()
+ if (isKspIncremental) {
+ if (isIntermoduleIncremental) {
+ // findClasspathChanges may clear caches, if there are
+ // 1. unknown changes, or
+ // 2. changes in annotation processors.
+ val classpathChanges = findClasspathChanges(
+ changedFiles,
+ cacheDir,
+ classpathStructure.get().files,
+ libraries.get().files.toList(),
+ processorCP.get().files.toList()
+ )
+ options += classpathChanges.toSubpluginOptions()
+ } else {
+ if (changedFiles.hasNonSourceChange()) {
+ cacheDir.deleteRecursively()
+ }
+ }
+ } else {
+ cacheDir.deleteRecursively()
+ }
+ options += changedFiles.toSubpluginOptions()
+
+ options
+}
diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/model/Ksp.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/model/Ksp.kt
new file mode 100644
index 00000000..22077a0c
--- /dev/null
+++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/model/Ksp.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.gradle.model
+
+/**
+ * Entry point for Kotlin Ksp models.
+ * Represents the description of annotations interpreted by 'kotlin-ksp-gradle' plugin.
+ */
+interface Ksp {
+
+ /**
+ * Return a number representing the version of this API.
+ * Always increasing if changed.
+ *
+ * @return the version of this model.
+ */
+ val modelVersion: Long
+
+ /**
+ * Returns the module (Gradle project) name.
+ *
+ * @return the module name.
+ */
+ val name: String
+}
diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/model/builder/KspModelBuilder.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/model/builder/KspModelBuilder.kt
new file mode 100644
index 00000000..760d83bc
--- /dev/null
+++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/model/builder/KspModelBuilder.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.gradle.model.builder
+
+import com.google.devtools.ksp.gradle.KspExtension
+import com.google.devtools.ksp.gradle.model.Ksp
+import com.google.devtools.ksp.gradle.model.impl.KspImpl
+import org.gradle.api.Project
+import org.gradle.tooling.provider.model.ToolingModelBuilder
+
+/**
+ * [ToolingModelBuilder] for [Ksp] models.
+ * This model builder is registered for Kotlin All Open sub-plugin.
+ */
+class KspModelBuilder : ToolingModelBuilder {
+
+ override fun canBuild(modelName: String): Boolean {
+ return modelName == Ksp::class.java.name
+ }
+
+ override fun buildAll(modelName: String, project: Project): Any? {
+ if (modelName == Ksp::class.java.name) {
+ val extension = project.extensions.getByType(KspExtension::class.java)
+ return KspImpl(project.name)
+ }
+ return null
+ }
+}
diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/model/impl/KspImpl.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/model/impl/KspImpl.kt
new file mode 100644
index 00000000..a6ca2699
--- /dev/null
+++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/model/impl/KspImpl.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.gradle.model.impl
+
+import com.google.devtools.ksp.gradle.model.Ksp
+import java.io.Serializable
+
+/**
+ * Implementation of the [Ksp] interface.
+ */
+data class KspImpl(
+ override val name: String
+) : Ksp, Serializable {
+
+ override val modelVersion = serialVersionUID
+
+ companion object {
+ private const val serialVersionUID = 1L
+ }
+}
diff --git a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/GradleCompilationTest.kt b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/GradleCompilationTest.kt
new file mode 100644
index 00000000..3f5b0320
--- /dev/null
+++ b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/GradleCompilationTest.kt
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.gradle
+
+import com.google.common.truth.Truth.assertThat
+import com.google.devtools.ksp.gradle.processor.TestSymbolProcessorProvider
+import com.google.devtools.ksp.gradle.testing.DependencyDeclaration.Companion.artifact
+import com.google.devtools.ksp.gradle.testing.DependencyDeclaration.Companion.module
+import com.google.devtools.ksp.gradle.testing.KspIntegrationTestRule
+import com.google.devtools.ksp.processing.CodeGenerator
+import com.google.devtools.ksp.processing.Dependencies
+import com.google.devtools.ksp.processing.KSPLogger
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.symbol.KSAnnotated
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assume
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+
+class GradleCompilationTest {
+ @Rule
+ @JvmField
+ val tmpDir = TemporaryFolder()
+
+ @Rule
+ @JvmField
+ val testRule = KspIntegrationTestRule(tmpDir)
+
+ @Test
+ fun errorMessageFailsCompilation() {
+ testRule.setupAppAsJvmApp()
+ testRule.appModule.dependencies.add(
+ module(configuration = "ksp", testRule.processorModule)
+ )
+ testRule.appModule.addSource(
+ "Foo.kt",
+ """
+ class Foo {
+ }
+ """.trimIndent()
+ )
+ class ErrorReporting(private val logger: KSPLogger) : SymbolProcessor {
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ logger.error("my processor failure")
+ return emptyList()
+ }
+ }
+
+ class Provider : TestSymbolProcessorProvider({ env -> ErrorReporting(env.logger) })
+
+ testRule.addProvider(Provider::class)
+ val failure = testRule.runner()
+ .withArguments("app:assemble")
+ .buildAndFail()
+ assertThat(failure.output).contains("my processor failure")
+ }
+
+ @Test
+ fun applicationCanAccessGeneratedCode() {
+ testRule.setupAppAsJvmApp()
+ testRule.appModule.dependencies.add(
+ module(configuration = "ksp", testRule.processorModule)
+ )
+ testRule.appModule.addSource(
+ "Foo.kt",
+ """
+ class Foo {
+ val x = ToBeGenerated()
+ }
+ """.trimIndent()
+ )
+ testRule.appModule.addSource(
+ "JavaSrc.java",
+ """
+ class JavaSrc {
+ ToBeGenerated x;
+ }
+ """.trimIndent()
+ )
+ class MyProcessor(private val codeGenerator: CodeGenerator) : SymbolProcessor {
+ var count = 0
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ if (count == 0) {
+ codeGenerator.createNewFile(Dependencies.ALL_FILES, "", "Generated").use {
+ it.writer(Charsets.UTF_8).use {
+ it.write("class ToBeGenerated")
+ }
+ }
+ count += 1
+ }
+ return emptyList()
+ }
+ }
+
+ class Provider : TestSymbolProcessorProvider({ env -> MyProcessor(env.codeGenerator) })
+
+ testRule.addProvider(Provider::class)
+
+ testRule.runner()
+ .withDebug(true)
+ .withArguments("app:assemble")
+ .forwardOutput()
+ .build()
+ }
+
+ @Test
+ fun testCommandLineArgumentProvider() {
+ // FIXME
+ Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true))
+ testRule.setupAppAsAndroidApp()
+ testRule.appModule.addSource("Foo.kt", "class Foo")
+ testRule.appModule.addSource(
+ "Entity.kt",
+ """
+ import androidx.room.Entity
+ import androidx.room.PrimaryKey
+ import androidx.room.ColumnInfo
+
+ @Entity
+ data class User(
+ @PrimaryKey val uid: Int,
+ @ColumnInfo(name = "first_name") val firstName: String?,
+ @ColumnInfo(name = "last_name") val lastName: String?
+ )
+ """.trimIndent()
+ )
+ testRule.appModule.addSource(
+ "UserDao.kt",
+ """
+ import androidx.room.Dao
+ import androidx.room.Query
+
+ @Dao
+ interface UserDao {
+ @Query("SELECT * FROM User")
+ fun getAll(): List<User>
+ }
+ """.trimIndent()
+ )
+ testRule.appModule.addSource(
+ "Database.kt",
+ """
+ import androidx.room.Database
+ import androidx.room.RoomDatabase
+
+ @Database(entities = [User::class], version = 1)
+ abstract class Database : RoomDatabase() {
+ abstract fun userDao(): UserDao
+ }
+ """.trimIndent()
+ )
+ testRule.appModule.dependencies.addAll(
+ listOf(
+ artifact(configuration = "ksp", "androidx.room:room-compiler:2.4.2"),
+ artifact(configuration = "implementation", "androidx.room:room-runtime:2.4.2")
+ )
+ )
+ testRule.appModule.buildFileAdditions.add(
+ """
+ ksp {
+ arg(Provider(project.layout.projectDirectory.dir("schemas").asFile))
+ }
+ class Provider(roomOutputDir: File) : CommandLineArgumentProvider {
+
+ @OutputDirectory
+ val outputDir = roomOutputDir
+
+ override fun asArguments(): Iterable<String> {
+ return listOf(
+ "room.schemaLocation=${'$'}{outputDir.path}",
+ "room.generateKotlin=true"
+ )
+ }
+ }
+ tasks.withType<com.google.devtools.ksp.gradle.KspTask>().configureEach {
+ doFirst {
+ options.get().forEach { option ->
+ println("${'$'}{option.key}=${'$'}{option.value}")
+ }
+ }
+ }
+
+ """.trimIndent()
+ )
+ val result = testRule.runner().withArguments(":app:assembleDebug").build()
+ val pattern1 = Regex.escape("apoption=room.schemaLocation=")
+ val pattern2 = Regex.escape("${testRule.appModule.moduleRoot}/schemas")
+ assertThat(result.output).containsMatch("$pattern1\\S*$pattern2")
+ assertThat(result.output).contains("apoption=room.generateKotlin=true")
+ val schemasFolder = testRule.appModule.moduleRoot.resolve("schemas")
+ assertThat(result.task(":app:kspDebugKotlin")!!.outcome).isEquivalentAccordingToCompareTo(TaskOutcome.SUCCESS)
+ assertThat(schemasFolder.exists()).isTrue()
+ assertThat(schemasFolder.resolve("Database/1.json").exists()).isTrue()
+ }
+
+ @Test
+ fun invalidArguments() {
+ testRule.setupAppAsJvmApp()
+ testRule.appModule.addSource("Foo.kt", "class Foo")
+ testRule.appModule.buildFileAdditions.add(
+ """
+ ksp {
+ arg(Provider())
+ }
+ class Provider() : CommandLineArgumentProvider {
+ override fun asArguments(): Iterable<String> {
+ return listOf(
+ "invalid"
+ )
+ }
+ }
+ """.trimIndent()
+ )
+ testRule.appModule.dependencies.addAll(
+ listOf(
+ artifact(configuration = "ksp", "androidx.room:room-compiler:2.4.2")
+ )
+ )
+
+ val result = testRule.runner().withArguments(":app:assemble").buildAndFail()
+ assertThat(result.output).contains("KSP apoption does not match \\S+=\\S+: invalid")
+ }
+
+ @Test
+ fun commandLineArgumentIsIncludedInApoptionsWhenAddedInKspTask() {
+ testRule.setupAppAsAndroidApp()
+ testRule.appModule.dependencies.addAll(
+ listOf(
+ artifact(configuration = "ksp", "androidx.room:room-compiler:2.4.2")
+ )
+ )
+ testRule.appModule.buildFileAdditions.add(
+ """
+ class Provider(roomOutputDir: File) : CommandLineArgumentProvider {
+
+ @OutputDirectory
+ val outputDir = roomOutputDir
+
+ override fun asArguments(): Iterable<String> {
+ return listOf(
+ "room.schemaLocation=${'$'}{outputDir.path}"
+ )
+ }
+ }
+ afterEvaluate {
+ tasks.withType<com.google.devtools.ksp.gradle.KspTask>().configureEach {
+ val destination = project.layout.projectDirectory.dir("schemas-${'$'}{this.name}")
+ commandLineArgumentProviders.add(Provider(destination.asFile))
+
+ options.get().forEach { option ->
+ println("${'$'}{option.key}=${'$'}{option.value}")
+ }
+ commandLineArgumentProviders.get().forEach { commandLine ->
+ println("commandLine=${'$'}{commandLine.asArguments()}")
+ }
+ }
+ }
+ """.trimIndent()
+ )
+ val result = testRule.runner().withDebug(true).withArguments(":app:assembleDebug").build()
+ val pattern1 = Regex.escape("apoption=room.schemaLocation=")
+ val pattern2 = Regex.escape("${testRule.appModule.moduleRoot}/schemas-kspDebugKotlin")
+ val pattern3 = Regex.escape("commandLine=[")
+ assertThat(result.output).containsMatch("$pattern1\\S*$pattern2")
+ assertThat(result.output).containsMatch("$pattern3\\S*$pattern2")
+ }
+
+ @Test
+ fun kspLibrariesHaveNoGenerated() {
+ testRule.setupAppAsJvmApp()
+ testRule.appModule.addSource("Foo.kt", "class Foo")
+ testRule.appModule.buildFileAdditions.add(
+ """
+ afterEvaluate {
+ tasks.withType<com.google.devtools.ksp.gradle.KspTaskJvm>().configureEach {
+ libraries.files.forEach {
+ println("HAS LIBRARY: ${'$'}{it.path}")
+ }
+ }
+ }
+ """.trimIndent()
+ )
+
+ testRule.appModule.dependencies.add(
+ module(configuration = "ksp", testRule.processorModule)
+ )
+
+ class DummyProcessor : SymbolProcessor {
+ override fun process(resolver: Resolver): List<KSAnnotated> = emptyList()
+ }
+
+ class Provider : TestSymbolProcessorProvider({ env -> DummyProcessor() })
+
+ testRule.addProvider(Provider::class)
+
+ val result = testRule.runner().withArguments(":app:assemble").build()
+ assertThat(result.output).contains("HAS LIBRARY: ")
+ assertThat(result.output).doesNotContain("app/build/generated/ksp/main/classes")
+ }
+}
diff --git a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/ProcessorClasspathConfigurationsTest.kt b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/ProcessorClasspathConfigurationsTest.kt
new file mode 100644
index 00000000..37fb64de
--- /dev/null
+++ b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/ProcessorClasspathConfigurationsTest.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.gradle
+
+import com.google.devtools.ksp.gradle.testing.KspIntegrationTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+
+class ProcessorClasspathConfigurationsTest {
+ @Rule
+ @JvmField
+ val tmpDir = TemporaryFolder()
+
+ @Rule
+ @JvmField
+ val testRule = KspIntegrationTestRule(tmpDir)
+
+ private val kspConfigs by lazy {
+ """configurations.matching { it.name.startsWith("ksp") && !it.name.endsWith("ProcessorClasspath") }"""
+ }
+
+ // config name is <KotlinCompileTaskName>.replace("compile", "ksp") + "ProcessorClasspath"
+ // they should extend all non-empty ksp configurations
+ @Test
+ fun testConfigurationsForSinglePlatformApp() {
+ testRule.setupAppAsJvmApp()
+ testRule.appModule.addSource("Foo.kt", "class Foo")
+ testRule.appModule.buildFileAdditions.add(
+ """
+ $kspConfigs.all {
+ // Make sure ksp configs are not empty.
+ project.dependencies.add(name, "androidx.room:room-compiler:2.4.2")
+ }
+ tasks.register("testConfigurations") {
+ // Resolve all tasks to trigger classpath config creation
+ dependsOn(tasks["tasks"])
+ doLast {
+ val main = configurations["kspKotlinProcessorClasspath"]
+ val test = configurations["kspTestKotlinProcessorClasspath"]
+ require(main.extendsFrom.map { it.name } == listOf("ksp"))
+ require(test.extendsFrom.map { it.name } == listOf("kspTest", "ksp"))
+ }
+ }
+ """.trimIndent()
+ )
+ testRule.runner()
+ .withArguments(":app:testConfigurations", "--info")
+ .build()
+ }
+
+ @Test
+ fun testConfigurationsForSinglePlatformAppDisallowAll() {
+ testRule.setupAppAsJvmApp()
+ testRule.appModule.addSource("Foo.kt", "class Foo")
+ testRule.appModule.buildFileAdditions.add(
+ """
+ $kspConfigs.all {
+ // Make sure ksp configs are not empty.
+ project.dependencies.add(name, "androidx.room:room-compiler:2.4.2")
+ }
+ tasks.register("testConfigurations") {
+ // Resolve all tasks to trigger classpath config creation
+ dependsOn(tasks["tasks"])
+ doLast {
+ val main = configurations["kspKotlinProcessorClasspath"]
+ val test = configurations["kspTestKotlinProcessorClasspath"]
+ require(main.extendsFrom.map { it.name } == listOf("ksp"))
+ require(test.extendsFrom.map { it.name } == listOf("kspTest"))
+ }
+ }
+ """.trimIndent()
+ )
+ testRule.runner()
+ .withArguments(":app:testConfigurations", "-Pksp.allow.all.target.configuration=false")
+ .build()
+ }
+
+ @Test
+ fun testConfigurationsForMultiPlatformApp() {
+ testRule.setupAppAsMultiplatformApp(
+ """
+ kotlin {
+ jvm { }
+ js(IR) { browser() }
+ }
+ """.trimIndent()
+ )
+ testRule.appModule.addMultiplatformSource("commonMain", "Foo.kt", "class Foo")
+ testRule.appModule.buildFileAdditions.add(
+ """
+ $kspConfigs.matching { it.name != "ksp" }.all {
+ // Make sure ksp configs are not empty.
+ project.dependencies.add(name, "androidx.room:room-compiler:2.4.2")
+ }
+ tasks.register("testConfigurations") {
+ // Resolve all tasks to trigger classpath config creation
+ dependsOn(tasks["tasks"])
+ doLast {
+ val jvmMain = configurations["kspKotlinJvmProcessorClasspath"]
+ val jvmTest = configurations["kspTestKotlinJvmProcessorClasspath"]
+ val jsMain = configurations["kspKotlinJsProcessorClasspath"]
+ val jsTest = configurations["kspTestKotlinJsProcessorClasspath"]
+ require(jvmMain.extendsFrom.map { it.name } == listOf("kspJvm"))
+ require(jvmTest.extendsFrom.map { it.name } == listOf("kspJvmTest"))
+ require(jsMain.extendsFrom.map { it.name } == listOf("kspJs"))
+ require(jsTest.extendsFrom.map { it.name } == listOf("kspJsTest"))
+ }
+ }
+ """.trimIndent()
+ )
+ testRule.runner()
+ .withArguments(":app:testConfigurations")
+ .build()
+ }
+}
diff --git a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/SourceSetConfigurationsTest.kt b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/SourceSetConfigurationsTest.kt
new file mode 100644
index 00000000..2230c4b0
--- /dev/null
+++ b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/SourceSetConfigurationsTest.kt
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.gradle
+
+import com.google.common.truth.Truth.assertThat
+import com.google.devtools.ksp.gradle.processor.TestSymbolProcessorProvider
+import com.google.devtools.ksp.gradle.testing.DependencyDeclaration.Companion.module
+import com.google.devtools.ksp.gradle.testing.KspIntegrationTestRule
+import com.google.devtools.ksp.gradle.testing.PluginDeclaration
+import com.google.devtools.ksp.processing.CodeGenerator
+import com.google.devtools.ksp.processing.Dependencies
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import java.io.File
+
+class SourceSetConfigurationsTest {
+ @Rule
+ @JvmField
+ val tmpDir = TemporaryFolder()
+
+ @Rule
+ @JvmField
+ val testRule = KspIntegrationTestRule(tmpDir)
+
+ @Test
+ fun configurationsForJvmApp() {
+ testRule.setupAppAsJvmApp()
+ testRule.appModule.addSource("Foo.kt", "class Foo")
+ val result = testRule.runner()
+ .withArguments(":app:dependencies")
+ .build()
+ val configurations = result.output.lines().map { it.split(' ').first() }
+
+ assertThat(configurations).containsAtLeast("ksp", "kspTest")
+ }
+
+ @Test
+ fun configurationsForAndroidApp() {
+ testRule.setupAppAsAndroidApp()
+ testRule.appModule.addSource("Foo.kt", "class Foo")
+ val result = testRule.runner()
+ .withArguments(":app:dependencies")
+ .build()
+ val configurations = result.output.lines().map { it.split(' ').first() }
+
+ assertThat(configurations).containsAtLeast(
+ "ksp",
+ "kspAndroidTest",
+ "kspAndroidTestDebug",
+ "kspAndroidTestRelease",
+ "kspDebug",
+ "kspRelease",
+ "kspTest",
+ "kspTestDebug",
+ "kspTestRelease"
+ )
+ }
+
+ @Test
+ fun configurationsForMultiplatformApp() {
+ testRule.setupAppAsMultiplatformApp(
+ """
+ kotlin {
+ jvm { }
+ android(name = "foo") { }
+ js(BOTH) { browser() }
+ androidNativeX86 { }
+ androidNativeX64(name = "bar") { }
+ }
+
+ tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
+ kotlinOptions.freeCompilerArgs += "-Xuse-deprecated-legacy-compiler"
+ }
+ """.trimIndent()
+ )
+ testRule.appModule.addMultiplatformSource("commonMain", "Foo.kt", "class Foo")
+ val result = testRule.runner()
+ .withArguments(":app:dependencies")
+ .build()
+ val configurations = result.output.lines().map { it.split(' ').first() }
+
+ assertThat(configurations).containsAtLeast(
+ // jvm target:
+ "kspJvm",
+ "kspJvmTest",
+ // android target, named foo:
+ "kspFoo",
+ "kspFooAndroidTest",
+ "kspFooAndroidTestDebug",
+ "kspFooAndroidTestRelease",
+ "kspFooDebug",
+ "kspFooRelease",
+ "kspFooTest",
+ "kspFooTestDebug",
+ "kspFooTestRelease",
+ // js target:
+ "kspJs",
+ "kspJsTest",
+ // androidNativeX86 target:
+ "kspAndroidNativeX86",
+ "kspAndroidNativeX86Test",
+ // androidNative64 target, named bar:
+ "kspBar",
+ "kspBarTest"
+ )
+ }
+
+ @Test
+ fun configurationsForMultiplatformApp_doesNotCrossCompilationBoundaries() {
+ // Adding a ksp dependency on jvmParent should not leak into jvmChild compilation,
+ // even if the source sets depend on each other. This works because we use
+ // KotlinCompilation.kotlinSourceSets instead of KotlinCompilation.allKotlinSourceSets
+ testRule.setupAppAsMultiplatformApp(
+ """
+ kotlin {
+ jvm("jvmParent") { }
+ jvm("jvmChild") { }
+ }
+ """.trimIndent()
+ )
+ testRule.appModule.addMultiplatformSource("commonMain", "Foo.kt", "class Foo")
+ testRule.appModule.buildFileAdditions.add(
+ """
+ kotlin {
+ sourceSets {
+ this["jvmChildMain"].dependsOn(this["jvmParentMain"])
+ }
+ }
+ dependencies {
+ add("kspJvmParent", "androidx.room:room-compiler:2.4.2")
+ }
+ tasks.register("checkConfigurations") {
+ doLast {
+ // child has no dependencies, so task is not created.
+ val parent = tasks.findByName("kspKotlinJvmParent")
+ val child = tasks.findByName("kspKotlinJvmChild")
+ require(parent != null)
+ require(child == null)
+ }
+ }
+ """.trimIndent()
+ )
+ testRule.runner()
+ .withArguments(":app:checkConfigurations")
+ .build()
+ }
+
+ @Test
+ fun registerGeneratedSourcesToAndroid() {
+ testRule.setupAppAsAndroidApp()
+ testRule.appModule.dependencies.addAll(
+ listOf(
+ module("ksp", testRule.processorModule),
+ module("kspTest", testRule.processorModule),
+ module("kspAndroidTest", testRule.processorModule)
+ )
+ )
+ testRule.appModule.buildFileAdditions.add(
+ """
+ tasks.register("printSources") {
+ fun logVariantSources(variants: DomainObjectSet<out com.android.build.gradle.api.BaseVariant>) {
+ variants.all {
+ println("VARIANT:" + this.name)
+ val baseVariant = (this as com.android.build.gradle.internal.api.BaseVariantImpl)
+ val variantData = baseVariant::class.java.getMethod("getVariantData").invoke(baseVariant)
+ as com.android.build.gradle.internal.variant.BaseVariantData
+ variantData.extraGeneratedSourceFolders.forEach {
+ println("SRC:" + it.relativeTo(buildDir).path)
+ }
+ variantData.allPreJavacGeneratedBytecode.forEach {
+ println("BYTE:" + it.relativeTo(buildDir).path)
+ }
+ }
+ }
+ doLast {
+ logVariantSources(android.applicationVariants)
+ logVariantSources(android.testVariants)
+ logVariantSources(android.unitTestVariants)
+ }
+ }
+ """.trimIndent()
+ )
+ val result = testRule.runner().withDebug(true).withArguments(":app:printSources").build()
+
+ data class SourceFolder(
+ val variantName: String,
+ val path: String
+ )
+
+ fun String.normalizePath() = replace(File.separatorChar, '/')
+ // parse output to get variant names and sources
+ // variant name -> list of sources
+ val variantSources = mutableListOf<SourceFolder>()
+ lateinit var currentVariantName: String
+ result.output.lines().forEach { line ->
+ when {
+ line.startsWith("VARIANT:") -> {
+ currentVariantName = line.substring("VARIANT:".length)
+ }
+ line.startsWith("SRC:") -> {
+ variantSources.add(
+ SourceFolder(
+ variantName = currentVariantName,
+ path = line.normalizePath()
+ )
+ )
+ }
+
+ line.startsWith("BYTE:") -> {
+ variantSources.add(
+ SourceFolder(
+ variantName = currentVariantName,
+ path = line.normalizePath()
+ )
+ )
+ }
+ }
+ }
+ assertThat(
+ variantSources.filter {
+ // there might be more, we are only interested in ksp
+ it.path.contains("ksp")
+ }
+ ).containsExactly(
+ SourceFolder(
+ "debug", "SRC:generated/ksp/debug/java"
+ ),
+ SourceFolder(
+ "release", "SRC:generated/ksp/release/java"
+ ),
+ SourceFolder(
+ "debugAndroidTest", "SRC:generated/ksp/debugAndroidTest/java"
+ ),
+ SourceFolder(
+ "debugUnitTest", "SRC:generated/ksp/debugUnitTest/java"
+ ),
+ SourceFolder(
+ "releaseUnitTest", "SRC:generated/ksp/releaseUnitTest/java"
+ ),
+ SourceFolder(
+ "debug", "SRC:generated/ksp/debug/kotlin"
+ ),
+ SourceFolder(
+ "release", "SRC:generated/ksp/release/kotlin"
+ ),
+ SourceFolder(
+ "debugAndroidTest", "SRC:generated/ksp/debugAndroidTest/kotlin"
+ ),
+ SourceFolder(
+ "debugUnitTest", "SRC:generated/ksp/debugUnitTest/kotlin"
+ ),
+ SourceFolder(
+ "releaseUnitTest", "SRC:generated/ksp/releaseUnitTest/kotlin"
+ ),
+ // TODO byte sources seems to be overridden by tmp/kotlin-classes/debug
+ // assert them as well once fixed
+ )
+ }
+
+ @Test
+ fun configurationsForAndroidApp_withBuildFlavorsMatchesKapt() {
+ testRule.setupAppAsAndroidApp()
+ testRule.appModule.buildFileAdditions.add(
+ """
+ android {
+ flavorDimensions("version")
+ productFlavors {
+ create("free") {
+ dimension = "version"
+ applicationId = "foo.bar"
+ }
+ create("paid") {
+ dimension = "version"
+ applicationId = "foo.baz"
+ }
+ }
+ }
+ """.trimIndent()
+ )
+ testRule.appModule.plugins.add(PluginDeclaration.kotlin("kapt", testRule.testConfig.kotlinBaseVersion))
+ testRule.appModule.addSource("Foo.kt", "class Foo")
+ val result = testRule.runner()
+ .withArguments(":app:dependencies")
+ .build()
+
+ // kaptClasspath_* seem to be intermediate configurations that never run.
+ val configurations = result.output.lines().map { it.split(' ').first() }
+ val kaptConfigurations = configurations.filter {
+ it.startsWith("kapt") && !it.startsWith("kaptClasspath_")
+ }
+ val kspConfigurations = configurations.filter {
+ it.startsWith("ksp")
+ }
+ assertThat(kspConfigurations).containsExactlyElementsIn(
+ kaptConfigurations.map {
+ it.replace("kapt", "ksp")
+ }
+ )
+ assertThat(kspConfigurations).isNotEmpty()
+ }
+
+ @Test
+ fun kspForTests_jvm() {
+ kspForTests(androidApp = false, useAndroidTest = false)
+ }
+
+ @Test
+ fun kspForTests_android_androidTest() {
+ kspForTests(androidApp = true, useAndroidTest = true)
+ }
+
+ @Test
+ fun kspForTests_android_junit() {
+ kspForTests(androidApp = true, useAndroidTest = false)
+ }
+
+ private fun kspForTests(androidApp: Boolean, useAndroidTest: Boolean) {
+ if (androidApp) {
+ testRule.setupAppAsAndroidApp()
+ } else {
+ testRule.setupAppAsJvmApp()
+ }
+ if (useAndroidTest) {
+ check(androidApp) {
+ "cannot set use android test w/o android app"
+ }
+ }
+
+ testRule.appModule.addSource(
+ "App.kt",
+ """
+ @Suppress("app")
+ class InApp {
+ }
+ """.trimIndent()
+ )
+ val testSource = """
+ @Suppress("test")
+ class InTest {
+ val impl = InTest_Impl()
+ }
+ """.trimIndent()
+ if (useAndroidTest) {
+ testRule.appModule.addAndroidTestSource("InTest.kt", testSource)
+ } else {
+ testRule.appModule.addTestSource("InTest.kt", testSource)
+ }
+
+ class Processor(val codeGenerator: CodeGenerator) : SymbolProcessor {
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getSymbolsWithAnnotation(Suppress::class.qualifiedName!!)
+ .filterIsInstance<KSClassDeclaration>()
+ .forEach {
+ if (it.simpleName.asString() == "InApp") {
+ error("should not run on the app sources")
+ }
+ val genClassName = "${it.simpleName.asString()}_Impl"
+ codeGenerator.createNewFile(Dependencies.ALL_FILES, "", genClassName).use {
+ it.writer().use {
+ it.write("class $genClassName")
+ }
+ }
+ }
+ return emptyList()
+ }
+ }
+
+ class Provider : TestSymbolProcessorProvider({ env -> Processor(env.codeGenerator) })
+
+ testRule.addProvider(Provider::class)
+ if (useAndroidTest) {
+ testRule.appModule.dependencies.add(
+ module("kspAndroidTest", testRule.processorModule)
+ )
+ testRule.runner().withArguments(":processor:assemble", ":app:assembleAndroidTest", "--stacktrace").build()
+ } else {
+ testRule.appModule.dependencies.add(
+ module("kspTest", testRule.processorModule)
+ )
+ testRule.runner().withArguments(":app:test", "--stacktrace").build()
+ }
+ }
+}
diff --git a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/model/builder/KspModelBuilderTest.kt b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/model/builder/KspModelBuilderTest.kt
new file mode 100644
index 00000000..e2dd3d9a
--- /dev/null
+++ b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/model/builder/KspModelBuilderTest.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.gradle.model.builder
+
+import com.google.devtools.ksp.gradle.model.Ksp
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class KspModelBuilderTest {
+ @Test
+ fun testCanBuild() {
+ val modelBuilder = KspModelBuilder()
+ assertTrue(modelBuilder.canBuild(Ksp::class.java.name))
+ assertFalse(modelBuilder.canBuild("wrongModel"))
+ }
+}
diff --git a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/processor/TestSymbolProcessorProvider.kt b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/processor/TestSymbolProcessorProvider.kt
new file mode 100644
index 00000000..5746f987
--- /dev/null
+++ b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/processor/TestSymbolProcessorProvider.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.gradle.processor
+
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
+import com.google.devtools.ksp.processing.SymbolProcessorProvider
+
+abstract class TestSymbolProcessorProvider(
+ private val builder: (
+ environment: SymbolProcessorEnvironment
+ ) -> SymbolProcessor
+) : SymbolProcessorProvider {
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = builder(environment)
+}
diff --git a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/DependencyDeclaration.kt b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/DependencyDeclaration.kt
new file mode 100644
index 00000000..02ffae27
--- /dev/null
+++ b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/DependencyDeclaration.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2021 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.
+ */
+@file:Suppress("DataClassPrivateConstructor")
+
+package com.google.devtools.ksp.gradle.testing
+
+/**
+ * Value class to declare dependencies between test projects.
+ * See builder methods in the companion to create an instance of this.
+ */
+data class DependencyDeclaration private constructor(
+ val configuration: String,
+ val dependency: String
+) {
+ fun toCode() = "$configuration($dependency)"
+
+ companion object {
+ /**
+ * Creates a module dependency for the given configuration.
+ */
+ fun module(configuration: String, module: TestModule) =
+ DependencyDeclaration(configuration, "project(\":${module.name}\")")
+
+ /**
+ * Create an artifact dependency for the given configuration.
+ */
+ fun artifact(configuration: String, coordinates: String) =
+ DependencyDeclaration(configuration, "\"$coordinates\"")
+
+ /**
+ * Creates a files dependency for the given configuration.
+ */
+ fun files(configuration: String, path: String) =
+ DependencyDeclaration(configuration, "files(\"$path\")")
+ }
+}
diff --git a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/KspIntegrationTestRule.kt b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/KspIntegrationTestRule.kt
new file mode 100644
index 00000000..088fa89b
--- /dev/null
+++ b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/KspIntegrationTestRule.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.gradle.testing
+
+import com.google.devtools.ksp.processing.SymbolProcessorProvider
+import org.gradle.testkit.runner.GradleRunner
+import org.junit.rules.TemporaryFolder
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
+import kotlin.reflect.KClass
+
+/**
+ * JUnit test rule to setup a [TestProject] which contains a KSP processor module and an
+ * application. The application can either be an android app or jvm app.
+ * Test must call [setupAppAsAndroidApp] or [setupAppAsJvmApp] before using the [runner].
+ */
+class KspIntegrationTestRule(
+ private val tmpFolder: TemporaryFolder
+) : TestWatcher() {
+ /**
+ * Initialized when the test starts.
+ */
+ private lateinit var testProject: TestProject
+
+ /**
+ * The application module in the test project
+ */
+ val appModule
+ get() = testProject.appModule
+
+ /**
+ * The processor module in the test project
+ */
+ val processorModule
+ get() = testProject.processorModule
+
+ /**
+ * The configuration passed from the KSP's main build which includes important setup information
+ * like KSP version, local maven repo etc.
+ */
+ val testConfig = TestConfig.read()
+
+ /**
+ * Returns a gradle runner that is ready to run tasks on the test project.
+ */
+ fun runner(): GradleRunner {
+ testProject.writeFiles()
+ return GradleRunner.create()
+ .withProjectDir(testProject.rootDir)
+ }
+
+ /**
+ * Adds the given [SymbolProcessorProvider] to the list of providers in the processor module.
+ * The processors built with these providers will run on the test application.
+ *
+ * The passed argument must be a class with a name (e.g. not inline) as it will be added to
+ * the classpath of the processor and will be re-loaded when the test runs. For this reason,
+ * these classes cannot access to the rest of the test instance.
+ */
+ fun addProvider(provider: KClass<out SymbolProcessorProvider>) {
+ val qName = checkNotNull(provider.java.name) {
+ "Must provide a class that can be loaded by qualified name"
+ }
+ testProject.processorModule.kspServicesFile.appendText("$qName\n")
+ }
+
+ /**
+ * Sets up the app module as a jvm app, adding necessary plugin dependencies.
+ */
+ fun setupAppAsJvmApp() {
+ testProject.appModule.plugins.addAll(
+ listOf(
+ PluginDeclaration.kotlin("jvm", testConfig.kotlinBaseVersion),
+ PluginDeclaration.id("com.google.devtools.ksp", testConfig.kspVersion)
+ )
+ )
+ }
+
+ /**
+ * Sets up the app module as an android app, adding necessary plugin dependencies, a manifest
+ * file and necessary gradle configuration.
+ */
+ fun setupAppAsAndroidApp() {
+ testProject.appModule.plugins.addAll(
+ listOf(
+ PluginDeclaration.id("com.android.application", testConfig.androidBaseVersion),
+ PluginDeclaration.kotlin("android", testConfig.kotlinBaseVersion),
+ PluginDeclaration.id("com.google.devtools.ksp", testConfig.kspVersion)
+ )
+ )
+ addAndroidBoilerplate()
+ }
+
+ /**
+ * Sets up the app module as a multiplatform app with the specified [targets], wrapped in a kotlin { } block.
+ */
+ fun setupAppAsMultiplatformApp(targets: String) {
+ testProject.appModule.plugins.addAll(
+ listOf(
+ PluginDeclaration.id("com.android.application", testConfig.androidBaseVersion),
+ PluginDeclaration.kotlin("multiplatform", testConfig.kotlinBaseVersion),
+ PluginDeclaration.id("com.google.devtools.ksp", testConfig.kspVersion)
+ )
+ )
+ testProject.appModule.buildFileAdditions.add(targets)
+ addAndroidBoilerplate()
+ }
+
+ private fun addAndroidBoilerplate() {
+ testProject.writeAndroidGradlePropertiesFile()
+ testProject.appModule.buildFileAdditions.add(
+ """
+ android {
+ compileSdkVersion(31)
+ defaultConfig {
+ minSdkVersion(24)
+ }
+ }
+ """.trimIndent()
+ )
+ testProject.appModule.moduleRoot.resolve("src/main/AndroidManifest.xml")
+ .also {
+ it.parentFile.mkdirs()
+ }.writeText(
+ """
+ <?xml version="1.0" encoding="utf-8"?>
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.kspandroidtestapp">
+ </manifest>
+ """.trimIndent()
+ )
+ }
+
+ override fun starting(description: Description) {
+ super.starting(description)
+ testProject = TestProject(tmpFolder.newFolder(), testConfig)
+ }
+}
diff --git a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/PluginDeclaration.kt b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/PluginDeclaration.kt
new file mode 100644
index 00000000..721f2d8f
--- /dev/null
+++ b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/PluginDeclaration.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021 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.
+ */
+@file:Suppress("DataClassPrivateConstructor")
+
+package com.google.devtools.ksp.gradle.testing
+
+/**
+ * Value class to hold a plugin declaration information.
+ *
+ * When the project runner is created, [KspIntegrationTestRule] makes necessary updates on the
+ * gradle files to add the plugin.
+ *
+ * To create an instance, use the helper methods in the companion.
+ */
+data class PluginDeclaration private constructor(
+ val text: String,
+ val version: String
+) {
+ fun toCode() = text
+
+ companion object {
+ /**
+ * Creates a plugin declaration with the given id and version.
+ */
+ fun id(id: String, version: String) = PluginDeclaration("id(\"$id\")", version)
+
+ /**
+ * Creates a kotlin plugin declaration with the given id and version.
+ */
+ fun kotlin(id: String, version: String) = PluginDeclaration("kotlin(\"$id\")", version)
+ }
+}
diff --git a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/TestConfig.kt b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/TestConfig.kt
new file mode 100644
index 00000000..1c048da6
--- /dev/null
+++ b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/TestConfig.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.gradle.testing
+
+import java.io.File
+import java.util.*
+
+/**
+ * Test configuration passed down from the main KSP build.
+ * See the `prepareTestConfiguration` task in the build.gradle.kts file in the `gradle-plugin`.
+ */
+data class TestConfig(
+ /**
+ * The root directory of the main KSP project
+ */
+ val kspProjectDir: File,
+ /**
+ * The classpath that can be used to load processors.
+ * The testing infra allows loading processors from the test classpath of the gradle-plugin.
+ * This classpath is the output of the test compilation in the main KSP project.
+ */
+ val processorClasspath: String,
+ /**
+ * The local maven repository that can be used while running tests
+ */
+ val mavenRepoDir: File,
+ /**
+ * The version of KSP.
+ */
+ val kspVersion: String
+) {
+ private val kspProjectProperties by lazy {
+ Properties().also { props ->
+ kspProjectDir.resolve("gradle.properties").inputStream().use {
+ props.load(it)
+ }
+ }
+ }
+ val kotlinBaseVersion by lazy {
+ kspProjectProperties["kotlinBaseVersion"] as String
+ }
+
+ val androidBaseVersion by lazy {
+ kspProjectProperties["agpBaseVersion"] as String
+ }
+
+ val mavenRepoPath = mavenRepoDir.path.replace(File.separatorChar, '/')
+
+ companion object {
+ /**
+ * Loads the test configuration from resources.
+ */
+ fun read(): TestConfig {
+ val props = Properties()
+ TestConfig::class.java.classLoader.getResourceAsStream("testprops.properties").use {
+ props.load(it)
+ }
+ return TestConfig(
+ kspProjectDir = File(props.get("kspProjectRootDir") as String),
+ processorClasspath = props.get("processorClasspath") as String,
+ mavenRepoDir = File(props.get("mavenRepoDir") as String),
+ kspVersion = props.get("kspVersion") as String
+ )
+ }
+ }
+}
diff --git a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/TestModule.kt b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/TestModule.kt
new file mode 100644
index 00000000..293d1485
--- /dev/null
+++ b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/TestModule.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.gradle.testing
+
+import java.io.File
+
+/**
+ * Simpler wrapper that represents a module in a test project.
+ *
+ * It has helper methods to add plugins, dependencies or sources to the project.
+ *
+ * It is loosely structured, which means it won't check its integrity. (e.g. you can add android
+ * sources w/o adding android plugin). It is meant to serve as a convenient way to configure
+ * modules.
+ */
+class TestModule(
+ val moduleRoot: File,
+ plugins: List<PluginDeclaration> = emptyList(),
+ dependencies: List<DependencyDeclaration> = emptyList()
+) {
+ val plugins = LinkedHashSet(plugins)
+ val dependencies = LinkedHashSet(dependencies)
+ val buildFileAdditions = LinkedHashSet<String>()
+ val name = moduleRoot.name
+
+ init {
+ moduleRoot.mkdirs()
+ }
+
+ /**
+ * Adds the given source file to the main source set.
+ */
+ fun addSource(name: String, contents: String) {
+ val srcDir = when {
+ name.endsWith(".kt") -> kotlinSourceDir
+ name.endsWith(".java") -> javaSourceDir
+ else -> error("must provide java or kotlin file")
+ }
+ srcDir.resolve(name).writeText(contents)
+ }
+
+ /**
+ * Adds the given source file to the test source set.
+ */
+ fun addTestSource(name: String, contents: String) {
+ val srcDir = when {
+ name.endsWith(".kt") -> kotlinTestSourceDir
+ name.endsWith(".java") -> javaTestSourceDir
+ else -> error("must provide java or kotlin file")
+ }
+ srcDir.resolve(name).writeText(contents)
+ }
+
+ /**
+ * Adds the given source file to the AndroidTest source set.
+ */
+ fun addAndroidTestSource(name: String, contents: String) {
+ val srcDir = when {
+ name.endsWith(".kt") -> kotlinAndroidTestSourceDir
+ name.endsWith(".java") -> javaAndroidTestSourceDir
+ else -> error("must provide java or kotlin file")
+ }
+ srcDir.resolve(name).writeText(contents)
+ }
+
+ /**
+ * Adds the given source file to the given KotlinSourceSet in a multiplatform project.
+ */
+ fun addMultiplatformSource(sourceSet: String, name: String, contents: String) {
+ require(name.endsWith(".kt")) { "multiplatform source extension needs to be *.kt." }
+ val srcDir = multiplatformKotlinSourceDir(sourceSet)
+ srcDir.resolve(name).writeText(contents)
+ }
+
+ private fun multiplatformKotlinSourceDir(sourceSet: String) = moduleRoot.resolve("src/$sourceSet/kotlin").also {
+ it.mkdirs()
+ }
+
+ private val kotlinSourceDir
+ get() = moduleRoot.resolve("src/main/kotlin").also {
+ it.mkdirs()
+ }
+
+ private val javaSourceDir
+ get() = moduleRoot.resolve("src/main/java").also {
+ it.mkdirs()
+ }
+
+ private val kotlinTestSourceDir
+ get() = moduleRoot.resolve("src/test/kotlin").also {
+ it.mkdirs()
+ }
+
+ private val javaTestSourceDir
+ get() = moduleRoot.resolve("src/test/java").also {
+ it.mkdirs()
+ }
+
+ private val kotlinAndroidTestSourceDir
+ get() = moduleRoot.resolve("src/androidTest/kotlin").also {
+ it.mkdirs()
+ }
+
+ private val javaAndroidTestSourceDir
+ get() = moduleRoot.resolve("src/androidTest/java").also {
+ it.mkdirs()
+ }
+
+ private val servicesDir
+ get() = moduleRoot.resolve("src/main/resources/META-INF/services/").also {
+ it.mkdirs()
+ }
+
+ val kspServicesFile
+ get() = servicesDir.resolve("com.google.devtools.ksp.processing.SymbolProcessorProvider")
+
+ private val buildFile
+ get() = moduleRoot.resolve("build.gradle.kts")
+
+ /**
+ * Writes the build file.
+ */
+ fun writeBuildFile() {
+ val contents = buildString {
+ appendln("plugins {")
+ plugins.forEach { plugin ->
+ appendln(plugin.toCode().prependIndent(" "))
+ }
+ appendln("}")
+ appendln("dependencies {")
+ dependencies.forEach { dependency ->
+ appendln(dependency.toCode().prependIndent(" "))
+ }
+ appendln("}")
+ buildFileAdditions.forEach {
+ appendln(it)
+ }
+ }
+ buildFile.writeText(contents)
+ }
+}
diff --git a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/TestProject.kt b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/TestProject.kt
new file mode 100644
index 00000000..7d21ad18
--- /dev/null
+++ b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/TestProject.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.gradle.testing
+
+import java.io.File
+
+/**
+ * Simple wrapper that represents a test project.
+ */
+class TestProject(
+ val rootDir: File,
+ val testConfig: TestConfig
+) {
+ val processorModule = TestModule(
+ rootDir.resolve("processor")
+ ).also {
+ it.plugins.add(PluginDeclaration.kotlin("jvm", testConfig.kotlinBaseVersion))
+ it.dependencies.add(
+ DependencyDeclaration.artifact(
+ "implementation",
+ "com.google.devtools.ksp:symbol-processing-api:${testConfig.kspVersion}"
+ )
+ )
+ // add gradle-plugin test classpath as a dependency to be able to load processors.
+ testConfig.processorClasspath.split(File.pathSeparatorChar).forEach { path ->
+ it.dependencies.add(
+ DependencyDeclaration.files("implementation", path.replace(File.separatorChar, '/'))
+ )
+ }
+ }
+
+ val appModule = TestModule(
+ rootDir.resolve("app")
+ )
+
+ fun writeFiles() {
+ writeBuildFile()
+ writeSettingsFile()
+ writeRootProperties()
+ appModule.writeBuildFile()
+ processorModule.writeBuildFile()
+ }
+
+ private fun writeRootProperties() {
+ val contents = """
+
+ kotlin.jvm.target.validation.mode=warning
+ """.trimIndent()
+ rootDir.resolve("gradle.properties").appendText(contents)
+ }
+
+ private fun writeSettingsFile() {
+ val contents = """
+ include("processor")
+ include("app")
+ pluginManagement {
+ repositories {
+ maven("${testConfig.mavenRepoPath}")
+ gradlePluginPortal()
+ google()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+ }
+ """.trimIndent()
+ rootDir.resolve("settings.gradle.kts").writeText(contents)
+ }
+
+ fun writeAndroidGradlePropertiesFile() {
+ val contents = """
+ android.useAndroidX=true
+ org.gradle.jvmargs=-Xmx2048M -XX:MaxMetaspaceSize=512m
+ """.trimIndent()
+ rootDir.resolve("gradle.properties").writeText(contents)
+ }
+
+ private fun writeBuildFile() {
+ val rootBuildFile = buildString {
+ appendln("plugins {")
+ val allPlugins = (processorModule.plugins + appModule.plugins).distinct()
+ allPlugins.forEach {
+ appendln(""" ${it.text} version "${it.version}" apply false """)
+ }
+ appendln("}")
+ appendln(
+ """
+ repositories {
+ maven("${testConfig.mavenRepoPath}")
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ google()
+ }
+ configurations.all {
+ resolutionStrategy.eachDependency {
+ if (requested.group == "org.jetbrains.kotlin") {
+ useVersion("${testConfig.kotlinBaseVersion}")
+ }
+ }
+ }
+ subprojects {
+ repositories {
+ maven("${testConfig.mavenRepoPath}")
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ google()
+ }
+ configurations.all {
+ resolutionStrategy.eachDependency {
+ if (requested.group == "org.jetbrains.kotlin") {
+ useVersion("${testConfig.kotlinBaseVersion}")
+ }
+ }
+ }
+ }
+ """.trimIndent()
+ )
+ }
+ rootDir.resolve("build.gradle.kts").writeText(rootBuildFile)
+ }
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 00000000..c4881fba
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,11 @@
+# Copied from kotlinc
+org.gradle.jvmargs=-Duser.country=US -Dkotlin.daemon.jvm.options=-Xmx2200m -Dfile.encoding=UTF-8
+
+kotlinBaseVersion=1.8.10
+agpBaseVersion=7.0.0
+intellijVersion=203.8084.24
+junitVersion=4.12
+googleTruthVersion=1.1
+compilerTestEnabled=false
+
+kotlin.jvm.target.validation.mode=warning
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..7454180f
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..ffed3a25
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 00000000..744e882e
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://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.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MSYS* | MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 00000000..ac1b06f9
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/integration-tests/build.gradle.kts b/integration-tests/build.gradle.kts
new file mode 100644
index 00000000..305592c4
--- /dev/null
+++ b/integration-tests/build.gradle.kts
@@ -0,0 +1,24 @@
+val junitVersion: String by project
+val kotlinBaseVersion: String by project
+val agpBaseVersion: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+dependencies {
+ testImplementation("junit:junit:$junitVersion")
+ testImplementation(gradleTestKit())
+ testImplementation("org.jetbrains.kotlin:kotlin-compiler:$kotlinBaseVersion")
+}
+
+tasks.named<Test>("test") {
+ systemProperty("kotlinVersion", kotlinBaseVersion)
+ systemProperty("kspVersion", version)
+ systemProperty("agpVersion", agpBaseVersion)
+ systemProperty("testRepo", File(rootProject.buildDir, "repos/test").absolutePath)
+ dependsOn(":api:publishAllPublicationsToTestRepository")
+ dependsOn(":gradle-plugin:publishAllPublicationsToTestRepository")
+ dependsOn(":symbol-processing:publishAllPublicationsToTestRepository")
+ dependsOn(":symbol-processing-cmdline:publishAllPublicationsToTestRepository")
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIT.kt
new file mode 100644
index 00000000..7c485212
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIT.kt
@@ -0,0 +1,84 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class AndroidIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("playground-android", "playground")
+
+ @Test
+ fun testPlaygroundAndroid() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ // Disabling configuration cache. See https://github.com/google/ksp/issues/299 for details
+ gradleRunner.withArguments(
+ "clean", "build", "minifyReleaseWithR8", "--configuration-cache-problems=warn", "--info", "--stacktrace"
+ ).build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:build")?.outcome)
+ val mergedConfiguration = File(project.root, "workload/build/outputs/mapping/release/configuration.txt")
+ assert(mergedConfiguration.exists()) {
+ "Merged configuration file not found!\n${printDirectoryTree(project.root)}"
+ }
+ val configurationText = mergedConfiguration.readText()
+ assert("-keep class com.example.AClassBuilder { *; }" in configurationText) {
+ "Merged configuration did not contain generated proguard rules!\n$configurationText"
+ }
+ }
+ }
+}
+
+/**
+ * Pretty print the directory tree and its file names.
+ *
+ * @param folder
+ * must be a folder.
+ * @return
+ */
+fun printDirectoryTree(folder: File): String? {
+ require(folder.isDirectory) { "folder is not a Directory" }
+ val indent = 0
+ val sb = StringBuilder()
+ printDirectoryTree(folder, indent, sb)
+ return sb.toString()
+}
+
+private fun printDirectoryTree(
+ folder: File,
+ indent: Int,
+ sb: StringBuilder
+) {
+ require(folder.isDirectory) { "folder is not a Directory" }
+ sb.append(getIndentString(indent))
+ sb.append("+--")
+ sb.append(folder.name)
+ sb.append("/")
+ sb.append("\n")
+ for (file in folder.listFiles()) {
+ if (file.isDirectory) {
+ printDirectoryTree(file, indent + 1, sb)
+ } else {
+ printFile(file, indent + 1, sb)
+ }
+ }
+}
+
+private fun printFile(file: File, indent: Int, sb: StringBuilder) {
+ sb.append(getIndentString(indent))
+ sb.append("+--")
+ sb.append(file.name)
+ sb.append("\n")
+}
+
+private fun getIndentString(indent: Int): String? {
+ val sb = StringBuilder()
+ for (i in 0 until indent) {
+ sb.append("| ")
+ }
+ return sb.toString()
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIncrementalIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIncrementalIT.kt
new file mode 100644
index 00000000..3cd01c14
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIncrementalIT.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.test
+
+import com.google.devtools.ksp.test.fixtures.BuildResultFixture
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class AndroidIncrementalIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("playground-android-multi", "playground")
+
+ @Test
+ fun testPlaygroundAndroid() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments(
+ "clean", ":application:compileDebugKotlin", "--configuration-cache-problems=warn", "--debug", "--stacktrace"
+ ).build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:compileDebugKotlin")?.outcome)
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":application:compileDebugKotlin")?.outcome)
+ }
+
+ project.root.resolve("workload/src/main/java/com/example/A.kt").also {
+ it.appendText(
+ """
+
+ class Unused
+ """.trimIndent()
+ )
+ }
+
+ gradleRunner.withArguments(
+ ":application:compileDebugKotlin", "--configuration-cache-problems=warn", "--debug", "--stacktrace"
+ ).build().let { result ->
+ Assert.assertEquals(
+ setOf("workload/src/main/java/com/example/A.kt".replace('/', File.separatorChar)),
+ BuildResultFixture(result).compiledKotlinSources,
+ )
+ }
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/Artifact.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/Artifact.kt
new file mode 100644
index 00000000..0b09a07a
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/Artifact.kt
@@ -0,0 +1,24 @@
+import org.junit.*
+import java.io.File
+import java.util.zip.ZipFile
+
+// A snapshot of the digest of output jar.
+class Artifact(file: File) {
+ private fun getCRCs(file: File): Map<String, Long> {
+ Assert.assertTrue(file.exists())
+ return ZipFile(file).use {
+ it.entries().asSequence().map {
+ it.name to it.crc
+ }.toMap()
+ }
+ }
+
+ val crcs: Map<String, Long> = getCRCs(file)
+
+ override fun equals(other: Any?): Boolean {
+ if (other !is Artifact)
+ return false
+
+ return crcs == other.crcs
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/BuildCacheIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/BuildCacheIT.kt
new file mode 100644
index 00000000..c1c0c498
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/BuildCacheIT.kt
@@ -0,0 +1,41 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class BuildCacheIT {
+ @Rule
+ @JvmField
+ val project1: TemporaryTestProject = TemporaryTestProject("buildcache", "playground")
+
+ @Rule
+ @JvmField
+ val project2: TemporaryTestProject = TemporaryTestProject("buildcache", "playground")
+
+ @Test
+ fun testBuildCache() {
+ val buildCacheDir = File(project1.root, "build-cache").absolutePath.replace(File.separatorChar, '/')
+ File(project1.root, "gradle.properties").appendText("\nbuildCacheDir=$buildCacheDir")
+ File(project2.root, "gradle.properties").appendText("\nbuildCacheDir=$buildCacheDir")
+
+ GradleRunner.create().withProjectDir(project1.root).withArguments(
+ "--build-cache",
+ ":workload:clean",
+ "build"
+ ).build().let {
+ Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload:kspKotlin")?.outcome)
+ }
+
+ GradleRunner.create().withProjectDir(project2.root).withArguments(
+ "--build-cache",
+ ":workload:clean",
+ "build"
+ ).build().let {
+ Assert.assertEquals(TaskOutcome.FROM_CACHE, it.task(":workload:kspKotlin")?.outcome)
+ }
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/GeneratedRefsIncIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/GeneratedRefsIncIT.kt
new file mode 100644
index 00000000..30a8f01c
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/GeneratedRefsIncIT.kt
@@ -0,0 +1,69 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class GeneratedRefsIncIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("refs-gen", "test-processor")
+
+ @Test
+ fun testGeneratedRefsInc() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ val expected = listOf(
+ "w: [ksp] 1: [File: Bar.kt, File: Baz.kt]",
+ "w: [ksp] 2: [File: Foo.kt]",
+ "w: [ksp] 3: [File: Goo.kt]"
+ )
+
+ val expectedBar = listOf(
+ "w: [ksp] 1: [File: Bar.kt]",
+ "w: [ksp] 2: [File: Foo.kt]",
+ "w: [ksp] 3: [File: Goo.kt]"
+ )
+
+ gradleRunner.withArguments("assemble").build().let { result ->
+ val outputs = result.output.lines().filter { it.startsWith("w: [ksp]") }
+ Assert.assertEquals(expected, outputs)
+ }
+
+ File(project.root, "workload/src/main/kotlin/com/example/Baz.kt").appendText("\n\n")
+ gradleRunner.withArguments("assemble").build().let { result ->
+ val outputs = result.output.lines().filter { it.startsWith("w: [ksp]") }
+ Assert.assertEquals(expected, outputs)
+ }
+
+ // Baz doesn't depend on Bar, so touching Bar won't invalidate Baz.
+ File(project.root, "workload/src/main/kotlin/com/example/Bar.kt").appendText("\n\n")
+ gradleRunner.withArguments("assemble").build().let { result ->
+ val outputs = result.output.lines().filter { it.startsWith("w: [ksp]") }
+ Assert.assertEquals(expectedBar, outputs)
+ }
+
+ // Make Baz depends on Bar; Bar will be invalidated.
+ File(project.root, "workload/src/main/kotlin/com/example/Bar.kt").appendText("\nclass List<T>\n")
+ gradleRunner.withArguments("assemble").build().let { result ->
+ val outputs = result.output.lines().filter { it.startsWith("w: [ksp]") }
+ Assert.assertEquals(expected, outputs)
+ }
+
+ // Baz depended on Bar, so Baz should be invalidated.
+ project.restore("workload/src/main/kotlin/com/example/Bar.kt")
+ gradleRunner.withArguments("assemble").build().let { result ->
+ val outputs = result.output.lines().filter { it.startsWith("w: [ksp]") }
+ Assert.assertEquals(expected, outputs)
+ }
+
+ // Baz doesn't depend on Bar, so touching Bar won't invalidate Baz.
+ File(project.root, "workload/src/main/kotlin/com/example/Bar.kt").appendText("\n\n")
+ gradleRunner.withArguments("assemble").build().let { result ->
+ val outputs = result.output.lines().filter { it.startsWith("w: [ksp]") }
+ Assert.assertEquals(expectedBar, outputs)
+ }
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/GeneratedSrcsIncIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/GeneratedSrcsIncIT.kt
new file mode 100644
index 00000000..df9fc89f
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/GeneratedSrcsIncIT.kt
@@ -0,0 +1,34 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class GeneratedSrcsIncIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("srcs-gen", "test-processor")
+
+ @Test
+ fun testGeneratedSrcsInc() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ val expected = listOf(
+ "w: [ksp] 1: [File: Bar.kt, File: Baz.kt]",
+ "w: [ksp] 2: [File: Foo.kt]",
+ "w: [ksp] 3: [File: FooBar.kt, File: FooBaz.kt]"
+ )
+
+ gradleRunner.withArguments("assemble").build().let { result ->
+ val outputs = result.output.lines().filter { it.startsWith("w: [ksp]") }
+ Assert.assertEquals(expected, outputs)
+ }
+ File(project.root, "workload/src/main/kotlin/com/example/Baz.kt").appendText(System.lineSeparator())
+ gradleRunner.withArguments("assemble").build().let { result ->
+ val outputs = result.output.lines().filter { it.startsWith("w: [ksp]") }
+ Assert.assertEquals(expected, outputs)
+ }
+ }
+}
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
new file mode 100644
index 00000000..29f56108
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/GetSealedSubclassesIncIT.kt
@@ -0,0 +1,56 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class GetSealedSubclassesIncIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("sealed-subclasses", "test-processor")
+
+ @Test
+ fun testGetSealedSubclassesInc() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ val expected2 = listOf(
+ "w: [ksp] Processing Impl1.kt",
+ "w: [ksp] Impl1 : []",
+ "w: [ksp] Processing Impl2.kt",
+ "w: [ksp] Impl2 : []",
+ "w: [ksp] Processing Sealed.kt",
+ "w: [ksp] Sealed : [Impl1, Impl2]",
+ )
+
+ val expected3 = listOf(
+ "w: [ksp] Processing Impl1.kt",
+ "w: [ksp] Impl1 : []",
+ "w: [ksp] Processing Impl2.kt",
+ "w: [ksp] Impl2 : []",
+ "w: [ksp] Processing Impl3.kt",
+ "w: [ksp] Impl3 : []",
+ "w: [ksp] Processing Sealed.kt",
+ "w: [ksp] Sealed : [Impl1, Impl2, Impl3]",
+ )
+
+ gradleRunner.withArguments("assemble").build().let { result ->
+ val outputs = result.output.lines().filter { it.startsWith("w: [ksp]") }
+ Assert.assertEquals(expected2, outputs)
+ }
+
+ File(project.root, "workload/src/main/kotlin/com/example/Impl3.kt").appendText("package com.example\n\n")
+ File(project.root, "workload/src/main/kotlin/com/example/Impl3.kt").appendText("class Impl3 : Sealed()\n")
+ gradleRunner.withArguments("assemble").build().let { result ->
+ val outputs = result.output.lines().filter { it.startsWith("w: [ksp]") }
+ Assert.assertEquals(expected3, outputs)
+ }
+
+ File(project.root, "workload/src/main/kotlin/com/example/Impl3.kt").delete()
+ gradleRunner.withArguments("assemble").build().let { result ->
+ val outputs = result.output.lines().filter { it.startsWith("w: [ksp]") }
+ Assert.assertEquals(expected2, outputs)
+ }
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/HmppIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/HmppIT.kt
new file mode 100644
index 00000000..9da354ed
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/HmppIT.kt
@@ -0,0 +1,83 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+
+class HmppIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("hmpp")
+
+ val taskToFilesTraditional = mapOf(
+ ":workload:kspCommonMainKotlinMetadata" to "w: [ksp] EchoProcessor: CommonMain",
+ ":workload:kspJvmJsKotlinMetadata" to "w: [ksp] EchoProcessor: CommonMain_JvmJs",
+ ":workload:kspJvmLinuxX64KotlinMetadata" to "w: [ksp] EchoProcessor: CommonMain_JvmLinuxX64",
+ ":workload:kspKotlinJvm" to "w: [ksp] EchoProcessor: CommonMain_JvmJs_JvmLinuxX64_JvmMain_JvmOnly",
+ ":workload:kspKotlinJs" to "w: [ksp] EchoProcessor: CommonMain_JsMain_JvmJs",
+ ":workload:kspKotlinLinuxX64" to "w: [ksp] EchoProcessor: CommonMain_JvmLinuxX64_LinuxX64Main",
+ )
+
+ @Test
+ fun testTraditional() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ taskToFilesTraditional.forEach { (task, expected) ->
+ gradleRunner.withArguments(
+ "--configuration-cache-problems=warn",
+ task,
+ ).build().let { result ->
+ val logs = result.output.lines().filter { it.startsWith("w: [ksp] EchoProcessor: ") }.toSet()
+ Assert.assertTrue(expected in logs)
+ }
+ }
+ }
+
+ val taskToFilesHmpp = mapOf(
+ ":workload:kspCommonMainKotlinMetadata" to setOf(
+ "w: [ksp] EchoProcessor: CommonMain",
+ ),
+ ":workload:kspJvmJsKotlinMetadata" to setOf(
+ "w: [ksp] EchoProcessor: CommonMain",
+ "w: [ksp] EchoProcessor: (CommonMain)_JvmJs",
+ ),
+ ":workload:kspJvmLinuxX64KotlinMetadata" to setOf(
+ "w: [ksp] EchoProcessor: CommonMain",
+ "w: [ksp] EchoProcessor: (CommonMain)_JvmLinuxX64",
+ ),
+ ":workload:kspKotlinJvm" to setOf(
+ "w: [ksp] EchoProcessor: CommonMain",
+ "w: [ksp] EchoProcessor: (CommonMain)_JvmJs",
+ "w: [ksp] EchoProcessor: (CommonMain)_JvmLinuxX64",
+ "w: [ksp] EchoProcessor: ((CommonMain)_JvmJs)_((CommonMain)_JvmLinuxX64)_(CommonMain)_JvmMain_JvmOnly",
+ ),
+ ":workload:kspKotlinJs" to setOf(
+ "w: [ksp] EchoProcessor: CommonMain",
+ "w: [ksp] EchoProcessor: (CommonMain)_JvmJs",
+ "w: [ksp] EchoProcessor: ((CommonMain)_JvmJs)_(CommonMain)_JsMain",
+ ),
+ ":workload:kspKotlinLinuxX64" to setOf(
+ "w: [ksp] EchoProcessor: CommonMain",
+ "w: [ksp] EchoProcessor: (CommonMain)_JvmLinuxX64",
+ "w: [ksp] EchoProcessor: ((CommonMain)_JvmLinuxX64)_(CommonMain)_LinuxX64Main",
+ ),
+ )
+
+ @Test
+ fun testHmpp() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ taskToFilesHmpp.forEach { (task, expected) ->
+ gradleRunner.withArguments(
+ "--configuration-cache-problems=warn",
+ "--rerun-tasks",
+ "-Pksp.experimental.processing.model=hierarchical",
+ task,
+ ).build().let { result ->
+ val logs = result.output.lines().filter { it.startsWith("w: [ksp] EchoProcessor: ") }.toSet()
+ Assert.assertTrue(logs == expected)
+ }
+ }
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalCPIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalCPIT.kt
new file mode 100644
index 00000000..cf07dd66
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalCPIT.kt
@@ -0,0 +1,130 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class IncrementalCPIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("incremental-classpath")
+
+ val src2Dirty = listOf(
+ "l1/src/main/kotlin/p1/L1.kt" to setOf(
+ "w: [ksp] p1/K1.kt",
+ "w: [ksp] processing done",
+ ),
+ "l2/src/main/kotlin/p1/L2.kt" to setOf(
+ "w: [ksp] p1/K1.kt",
+ "w: [ksp] p1/K2.kt",
+ "w: [ksp] processing done",
+ ),
+ "l3/src/main/kotlin/p1/L3.kt" to setOf(
+ "w: [ksp] p1/K3.kt",
+ "w: [ksp] processing done",
+ ),
+ "l4/src/main/kotlin/p1/L4.kt" to setOf(
+ "w: [ksp] p1/K3.kt",
+ "w: [ksp] processing done",
+ ),
+ "l5/src/main/kotlin/p1/L5.kt" to setOf(
+ "w: [ksp] processing done",
+ ),
+ )
+
+ val emptyMessage = setOf("w: [ksp] processing done")
+
+ @Test
+ fun testCPChanges() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("clean", "assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:assemble")?.outcome)
+ }
+
+ src2Dirty.forEach { (src, expectedDirties) ->
+ File(project.root, src).appendText("\n\n")
+ gradleRunner.withArguments("assemble").build().let { result ->
+ // Trivial changes should not result in re-processing.
+ Assert.assertEquals(TaskOutcome.UP_TO_DATE, result.task(":workload:kspKotlin")?.outcome)
+ }
+ }
+
+ var i = 100
+ src2Dirty.forEach { (src, expectedDirties) ->
+ File(project.root, src).appendText("\n{ val v$i = ${i++} }\n")
+ gradleRunner.withArguments("assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ val dirties = result.output.lines().filter { it.startsWith("w: [ksp]") }.toSet()
+ Assert.assertEquals(expectedDirties, dirties)
+ }
+ }
+
+ src2Dirty.forEach { (src, expectedDirties) ->
+ File(project.root, src).appendText("\n\nclass C${i++}\n")
+ gradleRunner.withArguments("assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ val dirties = result.output.lines().filter { it.startsWith("w: [ksp]") }.toSet()
+ // Non-signature changes should not affect anything.
+ Assert.assertEquals(emptyMessage, dirties)
+ }
+ }
+ }
+
+ private fun toggleFlags(vararg extras: String) {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root).withDebug(true)
+
+ gradleRunner.withArguments(
+ *extras,
+ "--rerun-tasks",
+ "-Pksp.incremental=true",
+ "-Pksp.incremental.intermodule=true",
+ "assemble"
+ ).build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ }
+
+ gradleRunner.withArguments(
+ *extras,
+ "--rerun-tasks",
+ "-Pksp.incremental=false",
+ "-Pksp.incremental.intermodule=true",
+ "assemble"
+ ).build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ }
+
+ gradleRunner.withArguments(
+ *extras,
+ "--rerun-tasks",
+ "-Pksp.incremental=true",
+ "-Pksp.incremental.intermodule=false",
+ "assemble"
+ ).build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ }
+
+ gradleRunner.withArguments(
+ *extras,
+ "--rerun-tasks",
+ "-Pksp.incremental=false",
+ "-Pksp.incremental.intermodule=false",
+ "assemble"
+ ).build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ }
+ }
+
+ @Test
+ fun toggleIncrementalFlagsWithoutConfigurationCache() {
+ toggleFlags("--no-configuration-cache")
+ }
+
+ @Test
+ fun toggleIncrementalFlagsWithConfigurationCache() {
+ toggleFlags("--configuration-cache")
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalIT.kt
new file mode 100644
index 00000000..880598bf
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalIT.kt
@@ -0,0 +1,262 @@
+package com.google.devtools.ksp.test
+
+import Artifact
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class IncrementalIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("incremental")
+
+ val src2Dirty = listOf(
+ "workload/src/main/java/p1/J1.java" to setOf(
+ "w: [ksp] p1/TestK2J.kt",
+ "w: [ksp] p1/TestJ2J.java",
+ "w: [ksp] p1/J1.java",
+ ),
+ "workload/src/main/java/p1/J2.java" to setOf(
+ "w: [ksp] p1/J2.java",
+ ),
+ "workload/src/main/java/p1/TestJ2J.java" to setOf(
+ "w: [ksp] p1/TestJ2J.java",
+ ),
+ "workload/src/main/java/p1/TestJ2K.java" to setOf(
+ "w: [ksp] p1/TestJ2K.java",
+ ),
+ "workload/src/main/java/p2/J2.java" to setOf(
+ "w: [ksp] p1/TestK2J.kt",
+ "w: [ksp] p2/J2.java",
+ "w: [ksp] p1/TestJ2J.java",
+ ),
+ "workload/src/main/java/p3/J1.java" to setOf(
+ "w: [ksp] p3/J1.java",
+ ),
+ "workload/src/main/java/p3/J2.java" to setOf(
+ "w: [ksp] p3/J2.java",
+ ),
+ "workload/src/main/java/p3/J3.java" to setOf(
+ "w: [ksp] p1/TestK2J.kt",
+ "w: [ksp] p1/TestJ2J.java",
+ "w: [ksp] p3/J3.java",
+ ),
+ "workload/src/main/kotlin/p1/K1.kt" to setOf(
+ "w: [ksp] p1/TestK2K.kt",
+ "w: [ksp] p1/K1.kt",
+ "w: [ksp] p1/TestJ2K.java",
+ ),
+ "workload/src/main/kotlin/p1/K2.kt" to setOf(
+ "w: [ksp] p1/K2.kt",
+ ),
+ "workload/src/main/kotlin/p1/TestK2J.kt" to setOf(
+ "w: [ksp] p1/TestK2J.kt",
+ ),
+ "workload/src/main/kotlin/p1/TestK2K.kt" to setOf(
+ "w: [ksp] p1/TestK2K.kt",
+ ),
+ "workload/src/main/kotlin/p2/K2.kt" to setOf(
+ "w: [ksp] p1/TestK2K.kt",
+ "w: [ksp] p2/K2.kt",
+ "w: [ksp] p1/TestJ2K.java",
+ ),
+ "workload/src/main/kotlin/p3/K1.kt" to setOf(
+ "w: [ksp] p3/K1.kt",
+ ),
+ "workload/src/main/kotlin/p3/K2.kt" to setOf(
+ "w: [ksp] p3/K2.kt",
+ ),
+ "workload/src/main/kotlin/p3/K3.kt" to setOf(
+ "w: [ksp] p1/TestK2K.kt",
+ "w: [ksp] p3/K3.kt",
+ "w: [ksp] p1/TestJ2K.java",
+ )
+ )
+
+ @Test
+ fun testUpToDate() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("clean", "assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:assemble")?.outcome)
+ }
+
+ gradleRunner.withArguments("assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.UP_TO_DATE, result.task(":workload:kspKotlin")?.outcome)
+ }
+ }
+
+ @Test
+ fun testIsolating() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("clean", "assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:assemble")?.outcome)
+ }
+ val cleanArtifact = Artifact(File(project.root, "workload/build/libs/workload-1.0-SNAPSHOT.jar"))
+
+ src2Dirty.forEach { (src, expectedDirties) ->
+ File(project.root, src).appendText("\n\n")
+ gradleRunner.withArguments("assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ val dirties = result.output.lines().filter { it.startsWith("w: [ksp]") }.toSet()
+ Assert.assertEquals(expectedDirties, dirties)
+ }
+ }
+ val incrementalArtifact = Artifact(File(project.root, "workload/build/libs/workload-1.0-SNAPSHOT.jar"))
+ Assert.assertEquals(cleanArtifact, incrementalArtifact)
+ }
+
+ val changeSets = listOf(
+ listOf(7, 5),
+ listOf(0, 12),
+ listOf(13, 14),
+ listOf(8, 10),
+ listOf(11, 4),
+ listOf(3, 15),
+ listOf(6, 9),
+ listOf(2, 1),
+ listOf(3, 1, 12),
+ listOf(13, 0, 11),
+ listOf(6, 8, 4),
+ listOf(10, 9, 15),
+ listOf(2, 14, 5, 7),
+ listOf(5, 0, 13, 15),
+ listOf(3, 2, 6, 7),
+ listOf(4, 14, 10, 1),
+ listOf(12, 9, 8, 11),
+ listOf(12, 13, 5, 14, 7),
+ listOf(11, 2, 8, 8, 9),
+ listOf(11, 2, 8, 8, 9),
+ listOf(4, 0, 15, 1, 10),
+ )
+
+ @Test
+ fun testMultipleChanges() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("clean", "assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:assemble")?.outcome)
+ }
+
+ changeSets.forEach { changeSet ->
+ changeSet.forEach {
+ File(project.root, src2Dirty[it].first).appendText("\n\n")
+ }
+ val expectedDirties = changeSet.flatMapTo(mutableSetOf()) {
+ src2Dirty[it].second
+ }
+ gradleRunner.withArguments("assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ val dirties = result.output.lines().filter { it.startsWith("w: [ksp]") }.toSet()
+ Assert.assertEquals(expectedDirties, dirties)
+ }
+ }
+ }
+
+ @Test
+ fun testMultipleDeletes() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("clean", "assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:assemble")?.outcome)
+ }
+
+ val srcs = src2Dirty.map { it.first }
+
+ changeSets.forEach { changeSet ->
+ val notChanged = IntRange(0, srcs.size - 1).filter { it !in changeSet }
+
+ // Touch a file so that Gradle won't UP_TO_DATE for us.
+ notChanged.first().let {
+ File(project.root, srcs[it]).appendText("\n\n")
+ }
+
+ // Delete files
+ changeSet.forEach {
+ File(project.root, srcs[it]).delete()
+ }
+
+ // in: "workload/src/main/kotlin/p1/K2.kt"
+ // out: "p1/K2.kt"
+ val expectedOutputs = notChanged.map() {
+ srcs[it].split("/").subList(4, 6).joinToString(File.separator) + ".log"
+ }.sorted()
+
+ gradleRunner.withArguments(":workload:kspKotlin").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ val outputRoot = File(project.root, "workload/build/generated/ksp/main/resources")
+ val outputs = outputRoot.walk().filter { it.isFile() }.map {
+ it.toRelativeString(outputRoot)
+ }.sorted().toList()
+
+ Assert.assertEquals(expectedOutputs, outputs)
+ }
+
+ changeSet.forEach {
+ project.restore(srcs[it])
+ }
+ }
+ }
+
+ @Test
+ fun testArgChange() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ gradleRunner.withArguments("assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:assemble")?.outcome)
+ }
+ val cleanArtifact = Artifact(File(project.root, "workload/build/libs/workload-1.0-SNAPSHOT.jar"))
+
+ val expectedDirties = src2Dirty.map { it.second }.flatten().toSet()
+ fun buildAndCheck() {
+ gradleRunner.withArguments("assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ val dirties = result.output.lines().filter { it.startsWith("w: [ksp]") }.toSet()
+ Assert.assertEquals(dirties, expectedDirties)
+ }
+ val incrementalArtifact = Artifact(File(project.root, "workload/build/libs/workload-1.0-SNAPSHOT.jar"))
+ Assert.assertEquals(cleanArtifact, incrementalArtifact)
+ }
+
+ File(project.root, "workload/build.gradle.kts").appendText("\nksp { arg(\"option1\", \"value1\") }\n")
+ buildAndCheck()
+
+ project.restore("workload/build.gradle.kts")
+ File(project.root, "workload/build.gradle.kts").appendText("\nksp { arg(\"option1\", \"value2\") }\n")
+ buildAndCheck()
+
+ File(project.root, "workload/build.gradle.kts").appendText("\nksp { arg(\"option2\", \"value2\") }\n")
+ buildAndCheck()
+
+ project.restore("workload/build.gradle.kts")
+ buildAndCheck()
+ }
+
+ @Test
+ fun testProcessorChange() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ gradleRunner.withArguments("build").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ Assert.assertEquals(TaskOutcome.NO_SOURCE, result.task(":workload:kspTestKotlin")?.outcome)
+ }
+ val cleanArtifact = Artifact(File(project.root, "workload/build/libs/workload-1.0-SNAPSHOT.jar"))
+
+ val expectedDirties = src2Dirty.map { it.second }.flatten().toSet()
+ fun buildAndCheck() {
+ gradleRunner.withArguments("build").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ Assert.assertEquals(TaskOutcome.NO_SOURCE, result.task(":workload:kspTestKotlin")?.outcome)
+ val dirties = result.output.lines().filter { it.startsWith("w: [ksp]") }.toSet()
+ Assert.assertEquals(dirties, expectedDirties)
+ }
+ val incrementalArtifact = Artifact(File(project.root, "workload/build/libs/workload-1.0-SNAPSHOT.jar"))
+ Assert.assertEquals(cleanArtifact, incrementalArtifact)
+ }
+
+ File(project.root, "validator/src/main/kotlin/Validator.kt").appendText("\n")
+ buildAndCheck()
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalMultiChainIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalMultiChainIT.kt
new file mode 100644
index 00000000..33680be3
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalMultiChainIT.kt
@@ -0,0 +1,49 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class IncrementalMultiChainIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("incremental-multi-chain")
+
+ @Test
+ fun testMultiChain() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ val k2 = File(project.root, "workload/src/main/kotlin/K2.kt")
+
+ gradleRunner.withArguments("run").build().let { result ->
+ Assert.assertTrue(result.output.contains("validating K1.kt"))
+ Assert.assertTrue(result.output.contains("validating Main.kt"))
+ Assert.assertTrue(result.output.contains("validating K1Impl.kt"))
+ Assert.assertTrue(result.output.contains("validating AllImpls.kt"))
+ Assert.assertTrue(result.output.contains("[K1Impl]"))
+ }
+
+ k2.writeText(
+ "@NeedsImpl\ninterface K2\n"
+ )
+ gradleRunner.withArguments("run").build().let { result ->
+ Assert.assertTrue(result.output.contains("validating K1.kt"))
+ Assert.assertTrue(result.output.contains("validating K2.kt"))
+ Assert.assertTrue(result.output.contains("validating Main.kt"))
+ Assert.assertTrue(result.output.contains("validating K1Impl.kt"))
+ Assert.assertTrue(result.output.contains("validating K2Impl.kt"))
+ Assert.assertTrue(result.output.contains("validating AllImpls.kt"))
+ Assert.assertTrue(result.output.contains("[K1Impl, K2Impl]"))
+ }
+
+ k2.delete()
+ gradleRunner.withArguments("run").build().let { result ->
+ Assert.assertTrue(result.output.contains("validating K1.kt"))
+ Assert.assertTrue(result.output.contains("validating Main.kt"))
+ Assert.assertTrue(result.output.contains("validating K1Impl.kt"))
+ Assert.assertTrue(result.output.contains("validating AllImpls.kt"))
+ Assert.assertTrue(result.output.contains("[K1Impl]"))
+ }
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalRemovalIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalRemovalIT.kt
new file mode 100644
index 00000000..78de3c04
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalRemovalIT.kt
@@ -0,0 +1,35 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class IncrementalRemovalIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("incremental-removal")
+
+ @Test
+ fun testRemoveOutputs() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ val k1 = "workload/src/main/kotlin/p1/K1.kt"
+
+ gradleRunner.withArguments("run").build().let { result ->
+ Assert.assertTrue(result.output.contains("result: generated"))
+ }
+
+ File(project.root, k1).writeText(
+ "package p1\n\nclass K1\n\nclass Foo : Bar { override fun s() = \"crafted\" }\n"
+ )
+ gradleRunner.withArguments("run").build().let { result ->
+ Assert.assertTrue(result.output.contains("result: crafted"))
+ }
+
+ project.restore(k1)
+ gradleRunner.withArguments("run").build().let { result ->
+ Assert.assertTrue(result.output.contains("result: generated"))
+ }
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/InitPlusProviderIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/InitPlusProviderIT.kt
new file mode 100644
index 00000000..31b7cb58
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/InitPlusProviderIT.kt
@@ -0,0 +1,33 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+import java.util.jar.JarFile
+
+class InitPlusProviderIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("init-plus-provider")
+
+ @Test
+ fun testInitPlusProvider() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ val resultCleanBuild = gradleRunner.withArguments("clean", "build").build()
+
+ Assert.assertEquals(TaskOutcome.SUCCESS, resultCleanBuild.task(":workload:build")?.outcome)
+
+ val artifact = File(project.root, "workload/build/libs/workload-1.0-SNAPSHOT.jar")
+ Assert.assertTrue(artifact.exists())
+
+ JarFile(artifact).use { jarFile ->
+ Assert.assertTrue(jarFile.getEntry("TestProcessor.log").size > 0)
+ Assert.assertTrue(jarFile.getEntry("HelloFromProvider.class").size > 0)
+ Assert.assertTrue(jarFile.getEntry("GeneratedFromProvider.class").size > 0)
+ }
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/JavaNestedClassIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/JavaNestedClassIT.kt
new file mode 100644
index 00000000..14cd0903
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/JavaNestedClassIT.kt
@@ -0,0 +1,22 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+
+class JavaNestedClassIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("javaNestedClass")
+
+ @Test
+ fun testJavaNestedClass() {
+
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ val resultCleanBuild = gradleRunner.withArguments("clean", "build").build()
+ Assert.assertEquals(TaskOutcome.SUCCESS, resultCleanBuild.task(":workload:build")?.outcome)
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/JavaOnlyIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/JavaOnlyIT.kt
new file mode 100644
index 00000000..bf94e522
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/JavaOnlyIT.kt
@@ -0,0 +1,34 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Assume
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class JavaOnlyIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("java-only", "test-processor")
+
+ @Test
+ fun testJavaOnly() {
+ // FIXME: `clean` fails to delete files on windows.
+ Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true))
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:assemble")?.outcome)
+ }
+
+ File(project.root, "workload/src/main/java/com/example/Foo.java").delete()
+
+ gradleRunner.withArguments("clean", "assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.NO_SOURCE, result.task(":workload:kspKotlin")?.outcome)
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:assemble")?.outcome)
+ }
+ }
+}
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
new file mode 100644
index 00000000..7c9c2dcd
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt
@@ -0,0 +1,369 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.BuildResult
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Assume
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+import java.util.jar.*
+
+class KMPImplementedIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("kmp")
+
+ private fun verify(jarName: String, contents: List<String>) {
+ val artifact = File(project.root, jarName)
+ Assert.assertTrue(artifact.exists())
+
+ JarFile(artifact).use { jarFile ->
+ contents.forEach {
+ Assert.assertTrue(jarFile.getEntry(it).size > 0)
+ }
+ }
+ }
+
+ private fun verifyKexe(path: String) {
+ val artifact = File(project.root, path)
+ Assert.assertTrue(artifact.exists())
+ Assert.assertTrue(artifact.readBytes().size > 0)
+ }
+
+ private fun checkExecutionOptimizations(log: String) {
+ Assert.assertFalse(
+ "Execution optimizations have been disabled",
+ log.contains("Execution optimizations have been disabled")
+ )
+ }
+
+ @Test
+ fun testJvm() {
+ 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-jvm:build"
+ ).build().let {
+ Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-jvm:build")?.outcome)
+ verify(
+ "workload-jvm/build/libs/workload-jvm-jvm-1.0-SNAPSHOT.jar",
+ listOf(
+ "com/example/Foo.class"
+ )
+ )
+ Assert.assertFalse(it.output.contains("kotlin scripting plugin:"))
+ Assert.assertTrue(it.output.contains("w: [ksp] platforms: [JVM"))
+ Assert.assertTrue(it.output.contains("w: [ksp] List has superTypes: true"))
+ checkExecutionOptimizations(it.output)
+ }
+ }
+
+ @Test
+ fun testJvmErrorLog() {
+ Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true))
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ File(project.root, "workload-jvm/build.gradle.kts").appendText("\nksp { arg(\"exception\", \"process\") }\n")
+ gradleRunner.withArguments(
+ "--configuration-cache-problems=warn",
+ "clean",
+ ":workload-jvm:build"
+ ).buildAndFail().let {
+ val errors = it.output.lines().filter { it.startsWith("e: [ksp]") }
+ Assert.assertEquals("e: [ksp] java.lang.Exception: Test Exception in process", errors.first())
+ }
+ project.restore("workload-jvm/build.gradle.kts")
+ }
+
+ @Test
+ fun testJs() {
+ 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-js:build"
+ ).build().let {
+ Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-js:build")?.outcome)
+ verify(
+ "workload-js/build/libs/workload-js-jslegacy-1.0-SNAPSHOT.jar",
+ listOf(
+ "playground-workload-js-js-legacy.js"
+ )
+ )
+ verify(
+ "workload-js/build/libs/workload-js-jsir-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: [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))
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ File(project.root, "workload-js/build.gradle.kts").appendText("\nksp { arg(\"exception\", \"process\") }\n")
+ gradleRunner.withArguments(
+ "--configuration-cache-problems=warn",
+ "clean",
+ ":workload-js:build"
+ ).buildAndFail().let {
+ val errors = it.output.lines().filter { it.startsWith("e: [ksp]") }
+ Assert.assertEquals("e: [ksp] java.lang.Exception: Test Exception in process", errors.first())
+ }
+ project.restore("workload-js/build.gradle.kts")
+ }
+
+ @Test
+ fun testJsFailWarning() {
+ File(project.root, "workload-js/build.gradle.kts")
+ .appendText("\nksp {\n allWarningsAsErrors = true\n}\n")
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments(
+ "--configuration-cache-problems=warn",
+ "clean",
+ ":workload-js:build"
+ ).buildAndFail()
+ }
+
+ @Test
+ fun testAndroidNative() {
+ 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-androidNative:build"
+ ).build().let {
+ Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-androidNative:build")?.outcome)
+ verifyKexe(
+ "workload-androidNative/build/bin/androidNativeX64/debugExecutable/workload-androidNative.kexe"
+ )
+ verifyKexe(
+ "workload-androidNative/build/bin/androidNativeX64/releaseExecutable/workload-androidNative.kexe"
+ )
+ verifyKexe(
+ "workload-androidNative/build/bin/androidNativeArm64/debugExecutable/workload-androidNative.kexe"
+ )
+ verifyKexe(
+ "workload-androidNative/build/bin/androidNativeArm64/releaseExecutable/workload-androidNative.kexe"
+ )
+ Assert.assertFalse(it.output.contains("kotlin scripting plugin:"))
+ Assert.assertTrue(it.output.contains("w: [ksp] platforms: [Native"))
+ checkExecutionOptimizations(it.output)
+ }
+ }
+
+ @Test
+ fun testLinuxX64() {
+ Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true))
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ val genDir = File(project.root, "workload-linuxX64/build/generated/ksp/linuxX64/linuxX64Main/kotlin")
+
+ gradleRunner.withArguments(
+ "--configuration-cache-problems=warn",
+ "clean",
+ ":workload-linuxX64:build"
+ ).build().let {
+ Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-linuxX64:build")?.outcome)
+ Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-linuxX64:kspTestKotlinLinuxX64")?.outcome)
+ verifyKexe("workload-linuxX64/build/bin/linuxX64/debugExecutable/workload-linuxX64.kexe")
+ verifyKexe("workload-linuxX64/build/bin/linuxX64/releaseExecutable/workload-linuxX64.kexe")
+
+ // TODO: Enable after CI's Xcode version catches up.
+ // Assert.assertTrue(
+ // result.task(":workload-linuxX64:kspKotlinIosArm64")?.outcome == TaskOutcome.SUCCESS ||
+ // result.task(":workload-linuxX64:kspKotlinIosArm64")?.outcome == TaskOutcome.SKIPPED
+ // )
+ // Assert.assertTrue(
+ // result.task(":workload-linuxX64:kspKotlinMacosX64")?.outcome == TaskOutcome.SUCCESS ||
+ // result.task(":workload-linuxX64:kspKotlinMacosX64")?.outcome == TaskOutcome.SKIPPED
+ // )
+ Assert.assertTrue(
+ it.task(":workload-linuxX64:kspKotlinMingwX64")?.outcome == TaskOutcome.SUCCESS ||
+ it.task(":workload-linuxX64:kspKotlinMingwX64")?.outcome == TaskOutcome.SKIPPED
+ )
+ Assert.assertFalse(it.output.contains("kotlin scripting plugin:"))
+ Assert.assertTrue(it.output.contains("w: [ksp] platforms: [Native"))
+ Assert.assertTrue(it.output.contains("w: [ksp] List has superTypes: true"))
+ Assert.assertTrue(File(genDir, "Main_dot_kt.kt").exists())
+ Assert.assertTrue(File(genDir, "ToBeRemoved_dot_kt.kt").exists())
+ checkExecutionOptimizations(it.output)
+ }
+
+ File(project.root, "workload-linuxX64/src/linuxX64Main/kotlin/ToBeRemoved.kt").delete()
+ gradleRunner.withArguments(
+ "--configuration-cache-problems=warn",
+ ":workload-linuxX64:build"
+ ).build().let {
+ Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-linuxX64:build")?.outcome)
+ Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-linuxX64:kspTestKotlinLinuxX64")?.outcome)
+ verifyKexe("workload-linuxX64/build/bin/linuxX64/debugExecutable/workload-linuxX64.kexe")
+ verifyKexe("workload-linuxX64/build/bin/linuxX64/releaseExecutable/workload-linuxX64.kexe")
+ Assert.assertTrue(File(genDir, "Main_dot_kt.kt").exists())
+ Assert.assertFalse(File(genDir, "ToBeRemoved_dot_kt.kt").exists())
+ checkExecutionOptimizations(it.output)
+ }
+ }
+
+ @Test
+ fun testNonEmbeddableArtifact() {
+ Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true))
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments(
+ "--configuration-cache-problems=warn",
+ "-Pkotlin.native.useEmbeddableCompilerJar=false",
+ ":workload-linuxX64:kspTestKotlinLinuxX64"
+ ).build()
+
+ gradleRunner.withArguments(
+ "--configuration-cache-problems=warn",
+ "-Pkotlin.native.useEmbeddableCompilerJar=true",
+ ":workload-linuxX64:kspTestKotlinLinuxX64"
+ ).build()
+
+ gradleRunner.withArguments(
+ "--configuration-cache-problems=warn",
+ ":workload-linuxX64:kspTestKotlinLinuxX64"
+ ).build()
+ }
+
+ @Test
+ fun testLinuxX64ErrorLog() {
+ Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true))
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ File(project.root, "workload-linuxX64/build.gradle.kts")
+ .appendText("\nksp { arg(\"exception\", \"process\") }\n")
+ gradleRunner.withArguments(
+ "--configuration-cache-problems=warn",
+ "clean",
+ ":workload-linuxX64:build"
+ ).buildAndFail().let {
+ val errors = it.output.lines().filter { it.startsWith("e: [ksp]") }
+ Assert.assertEquals("e: [ksp] java.lang.Exception: Test Exception in process", errors.first())
+ }
+ project.restore("workload-js/build.gradle.kts")
+ }
+
+ private fun verifyAll(result: BuildResult) {
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:build")?.outcome)
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspTestKotlinLinuxX64")?.outcome)
+
+ verify(
+ "workload/build/libs/workload-jvm-1.0-SNAPSHOT.jar",
+ listOf(
+ "com/example/Foo.class"
+ )
+ )
+
+ verify(
+ "workload/build/libs/workload-jslegacy-1.0-SNAPSHOT.jar",
+ listOf(
+ "playground-workload-js-legacy.js"
+ )
+ )
+
+ verify(
+ "workload/build/libs/workload-jsir-1.0-SNAPSHOT.klib",
+ listOf(
+ "default/ir/types.knt"
+ )
+ )
+
+ verifyKexe("workload/build/bin/linuxX64/debugExecutable/workload.kexe")
+ verifyKexe("workload/build/bin/linuxX64/releaseExecutable/workload.kexe")
+ verifyKexe("workload/build/bin/androidNativeX64/debugExecutable/workload.kexe")
+ verifyKexe("workload/build/bin/androidNativeX64/releaseExecutable/workload.kexe")
+ verifyKexe("workload/build/bin/androidNativeArm64/debugExecutable/workload.kexe")
+ verifyKexe("workload/build/bin/androidNativeArm64/releaseExecutable/workload.kexe")
+
+ // TODO: Enable after CI's Xcode version catches up.
+ // Assert.assertTrue(
+ // result.task(":workload:kspKotlinIosArm64")?.outcome == TaskOutcome.SUCCESS ||
+ // result.task(":workload:kspKotlinIosArm64")?.outcome == TaskOutcome.SKIPPED
+ // )
+ // Assert.assertTrue(
+ // result.task(":workload:kspKotlinMacosX64")?.outcome == TaskOutcome.SUCCESS ||
+ // result.task(":workload:kspKotlinMacosX64")?.outcome == TaskOutcome.SKIPPED
+ // )
+ Assert.assertTrue(
+ result.task(":workload:kspKotlinMingwX64")?.outcome == TaskOutcome.SUCCESS ||
+ result.task(":workload:kspKotlinMingwX64")?.outcome == TaskOutcome.SKIPPED
+ )
+
+ Assert.assertFalse(result.output.contains("kotlin scripting plugin:"))
+ Assert.assertTrue(result.output.contains("w: [ksp] platforms: [JVM"))
+ Assert.assertTrue(result.output.contains("w: [ksp] platforms: [JS"))
+ Assert.assertTrue(result.output.contains("w: [ksp] platforms: [Native"))
+ }
+
+ @Test
+ fun testMainConfiguration() {
+ Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true))
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ val buildScript = File(project.root, "workload/build.gradle.kts")
+ val lines = buildScript.readLines().takeWhile {
+ it.trimEnd() != "dependencies {"
+ }
+ buildScript.writeText(lines.joinToString(System.lineSeparator()))
+ buildScript.appendText(System.lineSeparator())
+ buildScript.appendText("dependencies {")
+ buildScript.appendText(System.lineSeparator())
+ buildScript.appendText(" add(\"ksp\", project(\":test-processor\"))")
+ buildScript.appendText(System.lineSeparator())
+ buildScript.appendText("}")
+
+ val messages = listOf(
+ "The 'ksp' configuration is deprecated in Kotlin Multiplatform projects. ",
+ "Please use target-specific configurations like 'kspJvm' instead."
+ )
+
+ // KotlinNative doesn't support configuration cache yet.
+ gradleRunner.withArguments(
+ "--configuration-cache-problems=warn",
+ "clean",
+ "build",
+ "-Pksp.allow.all.target.configuration=false"
+ ).buildAndFail().apply {
+ Assert.assertTrue(
+ messages.all {
+ output.contains(it)
+ }
+ )
+ checkExecutionOptimizations(output)
+ }
+
+ // KotlinNative doesn't support configuration cache yet.
+ gradleRunner.withArguments(
+ "--configuration-cache-problems=warn",
+ "clean",
+ "build"
+ ).build().apply {
+ Assert.assertTrue(
+ messages.all {
+ output.contains(it)
+ }
+ )
+ verifyAll(this)
+ checkExecutionOptimizations(output)
+ }
+ }
+}
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
new file mode 100644
index 00000000..80f8cce6
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KSPCmdLineOptionsIT.kt
@@ -0,0 +1,85 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.jetbrains.kotlin.cli.common.ExitCode
+import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.ByteArrayOutputStream
+import java.io.File
+import java.io.PrintStream
+import java.net.URLClassLoader
+
+data class CompileResult(val exitCode: ExitCode, val output: String)
+
+class KSPCmdLineOptionsIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("cmd-options")
+
+ private fun runCmdCompiler(pluginOptions: List<String>): CompileResult {
+ 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")
+ val classLoader = URLClassLoader(arrayOf(processorJar.toURI().toURL()), javaClass.classLoader)
+ val compiler = classLoader.loadClass(K2JVMCompiler::class.java.name).newInstance() as K2JVMCompiler
+ val repoPath = "../build/repos/test/com/google/devtools/ksp/"
+ val kspPluginId = "com.google.devtools.ksp.symbol-processing"
+ val kspPluginJar = File("$repoPath/symbol-processing-cmdline/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 compilerArgs = mutableListOf(
+ "-no-stdlib",
+ "-Xplugin=${kspPluginJar.absolutePath}",
+ "-Xplugin=${kspApiJar.absolutePath}",
+ "-P", "plugin:$kspPluginId:apclasspath=${processorJar.absolutePath}",
+ "-P", "plugin:$kspPluginId:projectBaseDir=${project.root}/build",
+ "-P", "plugin:$kspPluginId:classOutputDir=${project.root}/build",
+ "-P", "plugin:$kspPluginId:javaOutputDir=${project.root}/build/out",
+ "-P", "plugin:$kspPluginId:kotlinOutputDir=${project.root}/build/out",
+ "-P", "plugin:$kspPluginId:resourceOutputDir=${project.root}/build/out",
+ "-P", "plugin:$kspPluginId:kspOutputDir=${project.root}/build/out",
+ "-P", "plugin:$kspPluginId:cachesDir=${project.root}/build/out",
+ "-P", "plugin:$kspPluginId:incremental=false",
+ "-d", "${project.root}/build/out"
+ )
+ pluginOptions.forEach {
+ compilerArgs.add("-P")
+ compilerArgs.add("plugin:$kspPluginId:$it")
+ }
+ compilerArgs.add(File(project.root, "workload/src/main/kotlin/com/example/A.kt").absolutePath)
+ val outStream = ByteArrayOutputStream()
+ val exitCode = compiler.exec(PrintStream(outStream), *compilerArgs.toTypedArray())
+ return CompileResult(exitCode, outStream.toString())
+ }
+
+ @Test
+ fun testWithCompilationOnError() {
+ val result = runCmdCompiler(listOf("apoption=error=true", "withCompilation=true"))
+ val errors = result.output.lines().filter { it.startsWith("error: [ksp]") }
+ val exitCode = result.exitCode
+ Assert.assertTrue(exitCode == ExitCode.COMPILATION_ERROR)
+ Assert.assertTrue(
+ errors.any {
+ it.startsWith("error: [ksp] java.lang.IllegalStateException: Error on request")
+ }
+ )
+ }
+
+ @Test
+ fun testWithCompilationOnErrorOk() {
+ val result = runCmdCompiler(listOf("apoption=error=true", "returnOkOnError=true", "withCompilation=true"))
+ val errors = result.output.lines().filter { it.startsWith("error: [ksp]") }
+ val exitCode = result.exitCode
+ Assert.assertTrue(exitCode == ExitCode.OK)
+ Assert.assertTrue(
+ errors.any {
+ it.startsWith("error: [ksp] java.lang.IllegalStateException: Error on request")
+ }
+ )
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KotlinConstsInJavaIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KotlinConstsInJavaIT.kt
new file mode 100644
index 00000000..d8714bf7
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KotlinConstsInJavaIT.kt
@@ -0,0 +1,42 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.BuildResult
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Assume
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class KotlinConstsInJavaIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("kotlin-consts-in-java")
+
+ private fun GradleRunner.buildAndCheck(vararg args: String, extraCheck: (BuildResult) -> Unit = {}) =
+ buildAndCheckOutcome(*args, outcome = TaskOutcome.SUCCESS, extraCheck = extraCheck)
+
+ private fun GradleRunner.buildAndCheckOutcome(
+ vararg args: String,
+ outcome: TaskOutcome,
+ extraCheck: (BuildResult) -> Unit = {}
+ ) {
+ val result = this.withArguments(*args).build()
+
+ Assert.assertEquals(outcome, result.task(":workload:kspKotlin")?.outcome)
+
+ extraCheck(result)
+ }
+
+ @Test
+ fun testKotlinConstsInJava() {
+ // FIXME: `clean` fails to delete files on windows.
+ Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true))
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root).withDebug(true)
+ gradleRunner.buildAndCheck(":workload:kspKotlin")
+
+ File(project.root, "workload/src/main/java/com/example/JavaClass.java").appendText("\n")
+ gradleRunner.buildAndCheck(":workload:kspKotlin")
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/MapAnnotationArgumentsIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/MapAnnotationArgumentsIT.kt
new file mode 100644
index 00000000..870b4e60
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/MapAnnotationArgumentsIT.kt
@@ -0,0 +1,40 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+
+class MapAnnotationArgumentsIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("map-annotation-arguments", "test-processor")
+
+ val expectedErrors = listOf(
+ "e: [ksp] unboxedChar: Char != Character\n",
+ "e: [ksp] boxedChar: (Char..Char?) != Character\n",
+ "e: Error occurred in KSP, check log for detail\n",
+ )
+
+ @Test
+ fun testMapAnnotationArguments() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("assemble", "-Pksp.map.annotation.arguments.in.java=true").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:assemble")?.outcome)
+ }
+
+ gradleRunner.withArguments("clean", "assemble", "--rerun-tasks").buildAndFail().let { result ->
+ Assert.assertEquals(TaskOutcome.FAILED, result.task(":workload:kspKotlin")?.outcome)
+ Assert.assertTrue(expectedErrors.all { it in result.output })
+ }
+
+ gradleRunner.withArguments("clean", "assemble", "-Pksp.map.annotation.arguments.in.java=false", "--rerun-tasks")
+ .buildAndFail().let { result ->
+ Assert.assertEquals(TaskOutcome.FAILED, result.task(":workload:kspKotlin")?.outcome)
+ Assert.assertTrue(expectedErrors.all { it in result.output })
+ }
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/MultiplatformIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/MultiplatformIT.kt
new file mode 100644
index 00000000..9d7cb56e
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/MultiplatformIT.kt
@@ -0,0 +1,34 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+import java.util.jar.*
+
+class MultiplatformIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("playground-mpp", "playground")
+
+ @Test
+ fun testJVM() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ val resultCleanBuild =
+ gradleRunner.withArguments("--configuration-cache-problems=warn", "clean", "build").build()
+
+ Assert.assertEquals(TaskOutcome.SUCCESS, resultCleanBuild.task(":workload:build")?.outcome)
+
+ val artifact = File(project.root, "workload/build/libs/workload-jvm-1.0-SNAPSHOT.jar")
+ Assert.assertTrue(artifact.exists())
+
+ JarFile(artifact).use { jarFile ->
+ Assert.assertTrue(jarFile.getEntry("TestProcessor.log").size > 0)
+ Assert.assertTrue(jarFile.getEntry("hello/HELLO.class").size > 0)
+ Assert.assertTrue(jarFile.getEntry("com/example/AClassBuilder.class").size > 0)
+ }
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OnErrorIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OnErrorIT.kt
new file mode 100644
index 00000000..d44740af
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OnErrorIT.kt
@@ -0,0 +1,111 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class OnErrorIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("on-error")
+
+ @Test
+ fun testOnError() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("clean", "assemble").buildAndFail().let { result ->
+ val errors = result.output.lines().filter { it.startsWith("e: [ksp]") }
+ Assert.assertEquals("e: [ksp] Error processor: errored at 2", errors.first())
+ Assert.assertEquals("e: [ksp] NormalProcessor called error on 2", errors.last())
+ }
+ }
+
+ @Test
+ fun testOnExceptionInInit() {
+ File(project.root, "workload/build.gradle.kts").appendText("\nksp { arg(\"exception\", \"init\") }\n")
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("clean", "assemble").buildAndFail().let { result ->
+ val errors = result.output.lines().filter { it.startsWith("e: [ksp]") }
+ Assert.assertEquals("e: [ksp] java.lang.Exception: Test Exception in init", errors.first())
+ }
+ project.restore("workload/build.gradle.kts")
+ }
+
+ @Test
+ fun testOnExceptionInProcess() {
+ File(project.root, "workload/build.gradle.kts").appendText("\nksp { arg(\"exception\", \"process\") }\n")
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("clean", "assemble").buildAndFail().let { result ->
+ val errors = result.output.lines().filter { it.startsWith("e: [ksp]") }
+ Assert.assertEquals("e: [ksp] java.lang.Exception: Test Exception in process", errors.first())
+ }
+ project.restore("workload/build.gradle.kts")
+ }
+
+ @Test
+ fun testOnExceptionInFinish() {
+ File(project.root, "workload/build.gradle.kts").appendText("\nksp { arg(\"exception\", \"finish\") }\n")
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("clean", "assemble").buildAndFail().let { result ->
+ val errors = result.output.lines().filter { it.startsWith("e: [ksp]") }
+ Assert.assertEquals("e: [ksp] java.lang.Exception: Test Exception in finish", errors.first())
+ }
+ project.restore("workload/build.gradle.kts")
+ }
+
+ @Test
+ fun testOnExceptionInOnError() {
+ File(project.root, "workload/build.gradle.kts").appendText("\nksp { arg(\"exception\", \"error\") }\n")
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("clean", "assemble").buildAndFail().let { result ->
+ val errors = result.output.lines().filter { it.startsWith("e: [ksp]") }
+
+ Assert.assertEquals("e: [ksp] Error processor: errored at 2", errors.first())
+ Assert.assertEquals("e: [ksp] java.lang.Exception: Test Exception in error", errors[1])
+ }
+ project.restore("workload/build.gradle.kts")
+ }
+
+ @Test
+ fun testCreateTwice() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root).withDebug(true)
+
+ File(project.root, "workload/build.gradle.kts").appendText("\nksp { arg(\"exception\", \"createTwice\") }\n")
+ gradleRunner.withArguments("clean", "assemble").buildAndFail().let { result ->
+ val errors = result.output.lines().filter { it.startsWith("e: [ksp]") }
+
+ Assert.assertTrue(
+ errors.any {
+ it.startsWith("e: [ksp] kotlin.io.FileAlreadyExistsException:")
+ }
+ )
+
+ Assert.assertFalse(result.output.contains("e: java.lang.IllegalStateException: Should not be called!"))
+ }
+ project.restore("workload/build.gradle.kts")
+ }
+
+ @Test
+ fun testCreateTwiceNotOkOnError() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root).withDebug(true)
+
+ File(project.root, "workload/build.gradle.kts").appendText("\nksp { arg(\"exception\", \"createTwice\") }\n")
+ File(project.root, "gradle.properties").appendText("\nksp.return.ok.on.error=false")
+ gradleRunner.withArguments("clean", "assemble").buildAndFail().let { result ->
+ val errors = result.output.lines().filter { it.startsWith("e: [ksp]") }
+
+ Assert.assertTrue(
+ errors.any {
+ it.startsWith("e: [ksp] kotlin.io.FileAlreadyExistsException:")
+ }
+ )
+ }
+ project.restore("workload/build.gradle.kts")
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OnlyResourcesFileIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OnlyResourcesFileIT.kt
new file mode 100644
index 00000000..21b182a5
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OnlyResourcesFileIT.kt
@@ -0,0 +1,21 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.junit.Rule
+import org.junit.Test
+
+class OnlyResourcesFileIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("only-resources-file")
+
+ @Test
+ fun test() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments(
+ "--configuration-cache-problems=warn",
+ "jvmJar",
+ ).build()
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OutputDepsIt.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OutputDepsIt.kt
new file mode 100644
index 00000000..9c39e743
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OutputDepsIt.kt
@@ -0,0 +1,157 @@
+package com.google.devtools.ksp.test
+
+import Artifact
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Assume
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class OutputDepsIt {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("output-deps")
+
+ val src2Dirty = listOf(
+ "workload/src/main/java/p1/J1.java" to setOf(
+ "w: [ksp] p1/J1.java",
+ "w: [ksp] p1/K1.kt",
+ "w: [ksp] p1/K2.kt",
+ ),
+ "workload/src/main/java/p1/J2.java" to setOf(
+ "w: [ksp] p1/J2.java",
+ ),
+ "workload/src/main/kotlin/p1/K1.kt" to setOf(
+ "w: [ksp] p1/J1.java",
+ "w: [ksp] p1/K1.kt",
+ "w: [ksp] p1/K2.kt",
+ ),
+ "workload/src/main/kotlin/p1/K2.kt" to setOf(
+ "w: [ksp] p1/J1.java",
+ "w: [ksp] p1/K1.kt",
+ "w: [ksp] p1/K2.kt",
+ ),
+ )
+
+ val src2Output = mapOf(
+ "workload/src/main/java/p1/J1.java" to setOf(
+ "kotlin/p1/J1Generated.kt",
+ "kotlin/p1/K1Generated.kt",
+ "kotlin/p1/K2Generated.kt",
+ "resources/p1.Anno1.log",
+ "resources/p1.Anno2.log",
+ ),
+ "workload/src/main/java/p1/J2.java" to setOf(
+ "kotlin/p1/J2Generated.kt",
+ "resources/p1.Anno1.log",
+ "resources/p1.Anno2.log",
+ ),
+ "workload/src/main/kotlin/p1/K1.kt" to setOf(
+ "kotlin/p1/J1Generated.kt",
+ "kotlin/p1/K1Generated.kt",
+ "kotlin/p1/K2Generated.kt",
+ "resources/p1.Anno1.log",
+ "resources/p1.Anno2.log",
+ ),
+ "workload/src/main/kotlin/p1/K2.kt" to setOf(
+ "kotlin/p1/J1Generated.kt",
+ "kotlin/p1/K1Generated.kt",
+ "kotlin/p1/K2Generated.kt",
+ "resources/p1.Anno1.log",
+ "resources/p1.Anno2.log",
+ ),
+ )
+
+ val deletedSrc2Output = listOf(
+ "workload/src/main/java/p1/J1.java" to listOf(
+ "kotlin/p1/Anno1Generated.kt",
+ "kotlin/p1/Anno2Generated.kt",
+ "kotlin/p1/J2Generated.kt",
+ "kotlin/p1/K1Generated.kt",
+ "kotlin/p1/K2Generated.kt",
+ "resources/p1.Anno1.log",
+ "resources/p1.Anno2.log",
+ ),
+ "workload/src/main/java/p1/J2.java" to listOf(
+ "kotlin/p1/Anno1Generated.kt",
+ "kotlin/p1/Anno2Generated.kt",
+ "kotlin/p1/K1Generated.kt",
+ "kotlin/p1/K2Generated.kt",
+ "resources/p1.Anno1.log",
+ "resources/p1.Anno2.log",
+ ),
+ "workload/src/main/kotlin/p1/K1.kt" to listOf(
+ "kotlin/p1/Anno1Generated.kt",
+ "kotlin/p1/Anno2Generated.kt",
+ "kotlin/p1/K2Generated.kt",
+ "resources/p1.Anno1.log",
+ "resources/p1.Anno2.log",
+ ),
+ "workload/src/main/kotlin/p1/K2.kt" to listOf(
+ "kotlin/p1/Anno1Generated.kt",
+ "kotlin/p1/Anno2Generated.kt",
+ "resources/p1.Anno1.log",
+ "resources/p1.Anno2.log",
+ ),
+ )
+
+ @Test
+ fun testOutputDeps() {
+ // FIXME
+ Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true))
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:assemble")?.outcome)
+ }
+ val cleanArtifact = Artifact(File(project.root, "workload/build/libs/workload-1.0-SNAPSHOT.jar"))
+
+ src2Dirty.forEach { (src, expectedDirties) ->
+ val srcFile = File(project.root, src)
+ // In case that the test goes faster than the precision of timestamps.
+ // It's 1s on Github's CI.
+ Thread.sleep(1000)
+ srcFile.appendText("\n\n")
+ Thread.sleep(1000)
+ gradleRunner.withArguments("assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ val dirties = result.output.lines().filter { it.startsWith("w: [ksp]") }.toSet()
+ Assert.assertEquals(expectedDirties, dirties)
+
+ val outputRoot = File(project.root, "workload/build/generated/ksp/main/")
+ outputRoot.walk().filter { it.isFile() }.forEach {
+ if (it.toRelativeString(outputRoot) in src2Output[src]!!) {
+ Assert.assertTrue(it.lastModified() > srcFile.lastModified())
+ } else {
+ Assert.assertTrue(it.lastModified() < srcFile.lastModified())
+ }
+ }
+ }
+ }
+ val incrementalArtifact = Artifact(File(project.root, "workload/build/libs/workload-1.0-SNAPSHOT.jar"))
+ Assert.assertEquals(cleanArtifact, incrementalArtifact)
+ }
+
+ @Test
+ fun testDeletion() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:assemble")?.outcome)
+ }
+
+ deletedSrc2Output.forEach { (src, expectedDirties) ->
+ File(project.root, src).delete()
+ gradleRunner.withArguments("assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ val outputRoot = File(project.root, "workload/build/generated/ksp/main/")
+ val outputs = outputRoot.walk().filter { it.isFile() }.map {
+ it.toRelativeString(outputRoot).replace(File.separatorChar, '/')
+ }.toList().sorted()
+ Assert.assertEquals(expectedDirties, outputs)
+ }
+ }
+ }
+}
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
new file mode 100644
index 00000000..eeaaf502
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/PlaygroundIT.kt
@@ -0,0 +1,210 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.BuildResult
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Assume
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+import java.util.jar.*
+
+class PlaygroundIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("playground")
+
+ private fun GradleRunner.buildAndCheck(vararg args: String, extraCheck: (BuildResult) -> Unit = {}) =
+ buildAndCheckOutcome(*args, outcome = TaskOutcome.SUCCESS, extraCheck = extraCheck)
+
+ private fun GradleRunner.buildAndCheckOutcome(
+ vararg args: String,
+ outcome: TaskOutcome,
+ extraCheck: (BuildResult) -> Unit = {}
+ ) {
+ val result = this.withArguments(*args).build()
+
+ Assert.assertEquals(outcome, result.task(":workload:build")?.outcome)
+
+ val artifact = File(project.root, "workload/build/libs/workload-1.0-SNAPSHOT.jar")
+ Assert.assertTrue(artifact.exists())
+
+ JarFile(artifact).use { jarFile ->
+ Assert.assertTrue(jarFile.getEntry("TestProcessor.log").size > 0)
+ Assert.assertTrue(jarFile.getEntry("hello/HELLO.class").size > 0)
+ Assert.assertTrue(jarFile.getEntry("g/G.class").size > 0)
+ Assert.assertTrue(jarFile.getEntry("com/example/AClassBuilder.class").size > 0)
+ }
+
+ extraCheck(result)
+ }
+
+ @Test
+ fun testPlayground() {
+ // FIXME: `clean` fails to delete files on windows.
+ Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true))
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ gradleRunner.buildAndCheck("clean", "build")
+ gradleRunner.buildAndCheck("clean", "build")
+ }
+
+ // TODO: add another plugin and see if it is blocked.
+ // Or use a project that depends on a builtin plugin like all-open and see if the build fails
+ @Test
+ fun testBlockOtherCompilerPlugins() {
+ // FIXME: `clean` fails to delete files on windows.
+ Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true))
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ File(project.root, "workload/build.gradle.kts")
+ .appendText("\nksp {\n blockOtherCompilerPlugins = false\n}\n")
+ gradleRunner.buildAndCheck("clean", "build")
+ gradleRunner.buildAndCheck("clean", "build")
+ project.restore("workload/build.gradle.kts")
+ }
+
+ @Test
+ fun testAllowSourcesFromOtherPlugins() {
+ fun checkGBuilder() {
+ val artifact = File(project.root, "workload/build/libs/workload-1.0-SNAPSHOT.jar")
+
+ JarFile(artifact).use { jarFile ->
+ Assert.assertTrue(jarFile.getEntry("g/GBuilder.class").size > 0)
+ }
+ }
+
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ File(project.root, "workload/build.gradle.kts")
+ .appendText("\nksp {\n allowSourcesFromOtherPlugins = true\n}\n")
+ gradleRunner.buildAndCheck("clean", "build") { checkGBuilder() }
+ gradleRunner.buildAndCheckOutcome("build", "--info", outcome = TaskOutcome.UP_TO_DATE) {
+ Assert.assertEquals(TaskOutcome.UP_TO_DATE, it.task(":workload:kspKotlin")?.outcome)
+ checkGBuilder()
+ }
+ project.restore("workload/build.gradle.kts")
+ }
+
+ /** Regression test for https://github.com/google/ksp/issues/518. */
+ @Test
+ fun testBuildWithConfigureOnDemand() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ gradleRunner.buildAndCheck("--configure-on-demand", ":workload:build")
+ }
+
+ @Test
+ fun testBuildCache() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ // The first build can be FROM_CACHE or SUCCESS, and we only care about the second build.
+ gradleRunner.buildAndCheck("--build-cache", ":workload:clean", "build")
+ gradleRunner.buildAndCheck("--build-cache", ":workload:clean", "build") {
+ Assert.assertEquals(TaskOutcome.FROM_CACHE, it.task(":workload:kspKotlin")?.outcome)
+ }
+ }
+
+ @Test
+ fun testAllWarningsAsErrors() {
+ File(project.root, "workload/build.gradle.kts")
+ .appendText("\nksp {\n allWarningsAsErrors = true\n}\n")
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ gradleRunner.withArguments("build").buildAndFail().let { result ->
+ Assert.assertTrue(result.output.contains("This is a harmless warning."))
+ }
+ }
+
+ // Compiler's test infra report this kind of error before KSP, so it is not testable there.
+ @Test
+ fun testNoFunctionName() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ fun buildAndFileAndCheck() {
+ gradleRunner.withArguments("build").buildAndFail().let { result ->
+ Assert.assertTrue(result.output.contains("Function declaration must have a name"))
+ }
+ }
+
+ File(project.root, "workload/src/main/java/com/example/A.kt").appendText("\n{}\n")
+ buildAndFileAndCheck()
+ project.restore("workload/src/main/java/com/example/A.kt")
+
+ File(project.root, "workload/src/main/java/com/example/A.kt").appendText("\nfun() = {0}\n")
+ buildAndFileAndCheck()
+ project.restore("workload/src/main/java/com/example/A.kt")
+ }
+
+ @Test
+ fun testRewriteFile() {
+ File(
+ project.root,
+ "test-processor/src/main/resources/META-INF/services/" +
+ "com.google.devtools.ksp.processing.SymbolProcessorProvider"
+ ).writeText("RewriteProcessorProvider")
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ gradleRunner.withArguments("build").buildAndFail().let { result ->
+ Assert.assertTrue(result.output.contains("kotlin.io.FileAlreadyExistsException"))
+ }
+ }
+
+ // Disabled for now: ERROR: K2 does not support plugins yet, so please remove -Xuse-k2 flag
+ // Test -Xuse-fir for compilation; KSP still uses FE1.0
+ @Ignore
+ @Test
+ fun testFirPreview() {
+ val gradleProperties = File(project.root, "gradle.properties")
+ gradleProperties.appendText("\nkotlin.useK2=true")
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ gradleRunner.buildAndCheck("clean", "build") { result ->
+ Assert.assertTrue(result.output.contains("This build uses experimental K2 compiler"))
+ Assert.assertTrue(result.output.contains("-Xuse-k2"))
+ }
+ project.restore(gradleProperties.path)
+ }
+
+ @Test
+ fun testVersions() {
+ val kotlinCompile = "org.jetbrains.kotlin.gradle.tasks.KotlinCompile"
+ val buildFile = File(project.root, "workload/build.gradle.kts")
+ buildFile.appendText("\ntasks.withType<$kotlinCompile> {")
+ buildFile.appendText("\n kotlinOptions.apiVersion = \"1.5\"")
+ buildFile.appendText("\n kotlinOptions.languageVersion = \"1.5\"")
+ buildFile.appendText("\n}")
+
+ val kotlinVersion = System.getProperty("kotlinVersion").split('-').first()
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ gradleRunner.buildAndCheck("clean", "build") { result ->
+ Assert.assertTrue(result.output.contains("language version: 1.5"))
+ Assert.assertTrue(result.output.contains("api version: 1.5"))
+ Assert.assertTrue(result.output.contains("compiler version: $kotlinVersion"))
+ }
+ project.restore(buildFile.path)
+ }
+
+ @Test
+ fun testExcludeProcessor() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ File(project.root, "workload/build.gradle.kts")
+ .appendText("\nksp {\n excludeProcessor(\"TestProcessorProvider\")\n")
+ File(project.root, "workload/build.gradle.kts")
+ .appendText("\n excludeProcessor(\"NotMatchingAnything\")\n}\n")
+ gradleRunner.withArguments("build").buildAndFail().let {
+ Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload:kspKotlin")?.outcome)
+ Assert.assertEquals(TaskOutcome.FAILED, it.task(":workload:compileKotlin")?.outcome)
+ Assert.assertTrue("Unresolved reference: AClassBuilder" in it.output)
+ }
+ gradleRunner.withArguments("build").buildAndFail().let {
+ Assert.assertEquals(TaskOutcome.UP_TO_DATE, it.task(":workload:kspKotlin")?.outcome)
+ Assert.assertEquals(TaskOutcome.FAILED, it.task(":workload:compileKotlin")?.outcome)
+ Assert.assertTrue("Unresolved reference: AClassBuilder" in it.output)
+ }
+
+ project.restore("workload/build.gradle.kts")
+ File(project.root, "workload/build.gradle.kts")
+ .appendText("\nksp {\n excludeProcessor(\"DoNotMatch\")\n}\n")
+ gradleRunner.buildAndCheck("build")
+
+ project.restore("workload/build.gradle.kts")
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/PsiCacheIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/PsiCacheIT.kt
new file mode 100644
index 00000000..9f3a46dd
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/PsiCacheIT.kt
@@ -0,0 +1,18 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.junit.Rule
+import org.junit.Test
+
+class PsiCacheIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("psi-cache", "test-processor")
+
+ @Test
+ fun testPsiCache() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("assemble").build()
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/TemporaryTestProject.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/TemporaryTestProject.kt
new file mode 100644
index 00000000..fea748f0
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/TemporaryTestProject.kt
@@ -0,0 +1,41 @@
+package com.google.devtools.ksp.test
+
+import org.junit.rules.TemporaryFolder
+import java.io.File
+
+class TemporaryTestProject(projectName: String, baseProject: String? = null) : TemporaryFolder() {
+ private val testProjectSrc = File("src/test/resources", projectName)
+ private val baseProjectSrc = baseProject?.let { File("src/test/resources", baseProject) }
+
+ override fun before() {
+ super.before()
+
+ baseProjectSrc?.copyRecursively(root)
+ testProjectSrc.copyRecursively(root, true)
+
+ val kotlinVersion = System.getProperty("kotlinVersion")
+ val kspVersion = System.getProperty("kspVersion")
+ val agpVersion = System.getProperty("agpVersion")
+ val testRepo = System.getProperty("testRepo").replace(File.separator, "/")
+ val gradleProperties = File(root, "gradle.properties")
+ gradleProperties.appendText("\nkotlinVersion=$kotlinVersion")
+ gradleProperties.appendText("\nkspVersion=$kspVersion")
+ gradleProperties.appendText("\nagpVersion=$agpVersion")
+ gradleProperties.appendText("\ntestRepo=$testRepo")
+ gradleProperties.appendText("\norg.gradle.unsafe.configuration-cache=true")
+ gradleProperties.appendText("\nkotlin.jvm.target.validation.mode=warning")
+ // Uncomment this to debug compiler and compiler plugin.
+ // gradleProperties.appendText("\nsystemProp.kotlin.compiler.execution.strategy=in-process")
+ }
+
+ fun restore(file: String) {
+ fun copySafe(src: File, dst: File) {
+ if (src.exists())
+ src.copyTo(dst, true)
+ }
+ baseProjectSrc?.let {
+ copySafe(File(baseProjectSrc, file), File(root, file))
+ }
+ copySafe(File(testProjectSrc, file), File(root, file))
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/VerboseIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/VerboseIT.kt
new file mode 100644
index 00000000..935cd39b
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/VerboseIT.kt
@@ -0,0 +1,67 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.BuildResult
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+import java.util.jar.JarFile
+
+class VerboseIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("playground")
+
+ private fun GradleRunner.buildAndCheck(vararg args: String, extraCheck: (BuildResult) -> Unit = {}) =
+ buildAndCheckOutcome(*args, outcome = TaskOutcome.SUCCESS, extraCheck = extraCheck)
+
+ private fun GradleRunner.buildAndCheckOutcome(
+ vararg args: String,
+ outcome: TaskOutcome,
+ extraCheck: (BuildResult) -> Unit = {}
+ ) {
+ val result = this.withArguments(*args).build()
+
+ Assert.assertEquals(outcome, result.task(":workload:build")?.outcome)
+
+ val artifact = File(project.root, "workload/build/libs/workload-1.0-SNAPSHOT.jar")
+ Assert.assertTrue(artifact.exists())
+
+ JarFile(artifact).use { jarFile ->
+ Assert.assertTrue(jarFile.getEntry("TestProcessor.log").size > 0)
+ Assert.assertTrue(jarFile.getEntry("hello/HELLO.class").size > 0)
+ Assert.assertTrue(jarFile.getEntry("g/G.class").size > 0)
+ Assert.assertTrue(jarFile.getEntry("com/example/AClassBuilder.class").size > 0)
+ }
+
+ extraCheck(result)
+ }
+
+ @Test
+ fun testNoProvider() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ File(
+ project.root,
+ "test-processor/src/main/resources/META-INF/services/" +
+ "com.google.devtools.ksp.processing.SymbolProcessorProvider"
+ ).delete()
+ gradleRunner.withArguments("build").buildAndFail().let { result ->
+ Assert.assertTrue(result.output.contains("No providers found in processor classpath."))
+ }
+ }
+
+ @Test
+ fun testProviderAndRoundLogging() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ gradleRunner.buildAndCheck("--debug", "clean", "build") { result ->
+ Assert.assertTrue(
+ result.output.contains(
+ "i: [ksp] loaded provider(s): [TestProcessorProvider, TestProcessorProvider2]"
+ )
+ )
+ Assert.assertTrue(result.output.contains("v: [ksp] round 3 of processing"))
+ }
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/VersionCheckIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/VersionCheckIT.kt
new file mode 100644
index 00000000..52a62a4d
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/VersionCheckIT.kt
@@ -0,0 +1,42 @@
+package com.google.devtools.ksp.test
+
+import org.gradle.testkit.runner.GradleRunner
+import org.junit.Assert
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore
+class VersionCheckIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("playground")
+
+ @Test
+ fun testVersion() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ val result = gradleRunner.withArguments(
+ "-PkotlinVersion=1.4.20", "clean", "build"
+ ).buildAndFail()
+ Assert.assertTrue(result.output.contains("is too new for kotlin"))
+ }
+
+ @Test
+ fun testVersionOK() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ val result = gradleRunner.withArguments(
+ "clean", "build"
+ ).build()
+ Assert.assertFalse(result.output.contains("is too new for kotlin"))
+ Assert.assertFalse(result.output.contains("is too old for kotlin"))
+ }
+
+ @Test
+ fun testMuteVersionCheck() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ val result = gradleRunner.withArguments(
+ "-PkotlinVersion=1.4.20", "-Pksp.version.check=false", "clean", "build"
+ ).buildAndFail()
+ Assert.assertFalse(result.output.contains("is too new for kotlin"))
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/fixtures/BuildResultFixture.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/fixtures/BuildResultFixture.kt
new file mode 100644
index 00000000..cb66ea1b
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/fixtures/BuildResultFixture.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.test.fixtures
+
+import org.gradle.testkit.runner.BuildResult
+
+private val compileKotlinSrcs = Regex("\\[KOTLIN\\] compile iteration: ([^\\r\\n]*)")
+
+class BuildResultFixture(private val result: BuildResult) {
+
+ /** Get all compiled Kotlin sources in the current build. */
+ val compiledKotlinSources by lazy {
+ compileKotlinSrcs.findAll(result.output)
+ .asIterable()
+ .flatMap {
+ it.groups[1]!!.value.split(", ")
+ }.toSet()
+ }
+}
diff --git a/integration-tests/src/test/resources/buildcache/settings.gradle.kts b/integration-tests/src/test/resources/buildcache/settings.gradle.kts
new file mode 100644
index 00000000..24430bc3
--- /dev/null
+++ b/integration-tests/src/test/resources/buildcache/settings.gradle.kts
@@ -0,0 +1,27 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+buildCache {
+ val buildCacheDir: String by settings
+ local {
+ directory = File(buildCacheDir)
+ removeUnusedEntriesAfterDays = 30
+ }
+}
+
+rootProject.name = "playground"
+
+include(":workload")
+include(":test-processor")
diff --git a/integration-tests/src/test/resources/cmd-options/build.gradle.kts b/integration-tests/src/test/resources/cmd-options/build.gradle.kts
new file mode 100644
index 00000000..c5737a2e
--- /dev/null
+++ b/integration-tests/src/test/resources/cmd-options/build.gradle.kts
@@ -0,0 +1,8 @@
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
diff --git a/integration-tests/src/test/resources/cmd-options/gradle.properties b/integration-tests/src/test/resources/cmd-options/gradle.properties
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/integration-tests/src/test/resources/cmd-options/gradle.properties
diff --git a/integration-tests/src/test/resources/cmd-options/processors/build.gradle.kts b/integration-tests/src/test/resources/cmd-options/processors/build.gradle.kts
new file mode 100644
index 00000000..999cb80a
--- /dev/null
+++ b/integration-tests/src/test/resources/cmd-options/processors/build.gradle.kts
@@ -0,0 +1,23 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
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
new file mode 100644
index 00000000..c38d2298
--- /dev/null
+++ b/integration-tests/src/test/resources/cmd-options/processors/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,37 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+
+class TestProcessor : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+ lateinit var logger: KSPLogger
+ lateinit var options: Map<String, String>
+ var rounds = 0
+
+ fun init(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger
+ ) {
+ this.logger = logger
+ this.options = options
+ this.codeGenerator = codeGenerator
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ if (options.containsKey("error")) {
+ throw IllegalStateException("Error on request")
+ }
+ return emptyList()
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return TestProcessor().apply {
+ init(env.options, env.kotlinVersion, env.codeGenerator, env.logger)
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/cmd-options/processors/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/cmd-options/processors/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..e6522f19
--- /dev/null
+++ b/integration-tests/src/test/resources/cmd-options/processors/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+TestProcessorProvider \ No newline at end of file
diff --git a/integration-tests/src/test/resources/cmd-options/settings.gradle.kts b/integration-tests/src/test/resources/cmd-options/settings.gradle.kts
new file mode 100644
index 00000000..79202ef6
--- /dev/null
+++ b/integration-tests/src/test/resources/cmd-options/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ val kspVersion: String by settings
+ val kotlinVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "cmd-options"
+
+include(":workload")
+include(":processors")
diff --git a/integration-tests/src/test/resources/cmd-options/workload/build.gradle.kts b/integration-tests/src/test/resources/cmd-options/workload/build.gradle.kts
new file mode 100644
index 00000000..a79cec86
--- /dev/null
+++ b/integration-tests/src/test/resources/cmd-options/workload/build.gradle.kts
@@ -0,0 +1,19 @@
+val testRepo: String by project
+
+plugins {
+ id("com.google.devtools.ksp")
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ ksp(project(":processors"))
+}
diff --git a/integration-tests/src/test/resources/cmd-options/workload/src/main/kotlin/com/example/A.kt b/integration-tests/src/test/resources/cmd-options/workload/src/main/kotlin/com/example/A.kt
new file mode 100644
index 00000000..ebf0688c
--- /dev/null
+++ b/integration-tests/src/test/resources/cmd-options/workload/src/main/kotlin/com/example/A.kt
@@ -0,0 +1,4 @@
+package com.example
+
+fun main() {
+}
diff --git a/integration-tests/src/test/resources/hmpp/build.gradle.kts b/integration-tests/src/test/resources/hmpp/build.gradle.kts
new file mode 100644
index 00000000..8dd65667
--- /dev/null
+++ b/integration-tests/src/test/resources/hmpp/build.gradle.kts
@@ -0,0 +1,12 @@
+plugins {
+ kotlin("multiplatform") apply false
+}
+
+val testRepo: String by project
+allprojects {
+ repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
diff --git a/integration-tests/src/test/resources/hmpp/gradle.properties b/integration-tests/src/test/resources/hmpp/gradle.properties
new file mode 100644
index 00000000..4a9594ae
--- /dev/null
+++ b/integration-tests/src/test/resources/hmpp/gradle.properties
@@ -0,0 +1 @@
+org.gradle.jvmargs=-Xmx2048M \ No newline at end of file
diff --git a/integration-tests/src/test/resources/hmpp/settings.gradle.kts b/integration-tests/src/test/resources/hmpp/settings.gradle.kts
new file mode 100644
index 00000000..0f0b53a3
--- /dev/null
+++ b/integration-tests/src/test/resources/hmpp/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion apply false
+ kotlin("multiplatform") version kotlinVersion apply false
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "hmpp"
+
+include(":workload")
+include(":test-processor")
diff --git a/integration-tests/src/test/resources/hmpp/test-processor/build.gradle.kts b/integration-tests/src/test/resources/hmpp/test-processor/build.gradle.kts
new file mode 100644
index 00000000..842898f6
--- /dev/null
+++ b/integration-tests/src/test/resources/hmpp/test-processor/build.gradle.kts
@@ -0,0 +1,22 @@
+val kspVersion: String by project
+
+plugins {
+ kotlin("multiplatform")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+kotlin {
+ jvm()
+ sourceSets {
+ val jvmMain by getting {
+ dependencies {
+ implementation("com.squareup:javapoet:1.12.1")
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+ }
+ kotlin.srcDir("src/main/kotlin")
+ resources.srcDir("src/main/resources")
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/hmpp/test-processor/src/main/kotlin/EchoProcessor.kt b/integration-tests/src/test/resources/hmpp/test-processor/src/main/kotlin/EchoProcessor.kt
new file mode 100644
index 00000000..0b1c39a6
--- /dev/null
+++ b/integration-tests/src/test/resources/hmpp/test-processor/src/main/kotlin/EchoProcessor.kt
@@ -0,0 +1,27 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+
+class EchoProcessor(val codeGenerator: CodeGenerator, val logger: KSPLogger) : SymbolProcessor {
+ var invoked = false
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ if (invoked) {
+ return emptyList()
+ }
+ invoked = true
+
+ val allInputs = resolver.getAllFiles().map { it.fileName.split(".").first() }.sorted().joinToString("_")
+
+ logger.warn("EchoProcessor: $allInputs")
+
+ codeGenerator.createNewFile(Dependencies(true), "", "($allInputs)").close()
+
+ return emptyList()
+ }
+}
+
+class EchoProcessorProvider : SymbolProcessorProvider {
+ override fun create(env: SymbolProcessorEnvironment): SymbolProcessor {
+ return EchoProcessor(env.codeGenerator, env.logger)
+ }
+}
diff --git a/integration-tests/src/test/resources/hmpp/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/hmpp/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..c0cdf71a
--- /dev/null
+++ b/integration-tests/src/test/resources/hmpp/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+EchoProcessorProvider
diff --git a/integration-tests/src/test/resources/hmpp/workload/build.gradle.kts b/integration-tests/src/test/resources/hmpp/workload/build.gradle.kts
new file mode 100644
index 00000000..a6574fc3
--- /dev/null
+++ b/integration-tests/src/test/resources/hmpp/workload/build.gradle.kts
@@ -0,0 +1,55 @@
+plugins {
+ kotlin("multiplatform")
+ id("com.google.devtools.ksp")
+}
+
+version = "1.0-SNAPSHOT"
+
+kotlin {
+ jvm {
+ withJava()
+ }
+
+ js(IR) {
+ browser()
+ }
+
+ linuxX64() {
+ binaries {
+ executable()
+ }
+ }
+
+ sourceSets {
+ val commonMain by getting
+
+ val jvmJs by sourceSets.creating {
+ dependsOn(commonMain)
+ }
+
+ val jvmLinuxX64 by sourceSets.creating {
+ dependsOn(commonMain)
+ }
+
+ val jvmOnly by sourceSets.creating {
+ dependsOn(jvmJs)
+ dependsOn(jvmLinuxX64)
+ }
+
+ val linuxX64Main by getting {
+ dependsOn(jvmLinuxX64)
+ }
+
+ val jvmMain by getting {
+ dependsOn(jvmOnly)
+ }
+
+ val jsMain by getting {
+ dependsOn(jvmJs)
+ }
+ }
+}
+
+dependencies {
+ add("ksp", project(":test-processor"))
+}
diff --git a/integration-tests/src/test/resources/hmpp/workload/src/commonMain/kotlin/CommonMain.kt b/integration-tests/src/test/resources/hmpp/workload/src/commonMain/kotlin/CommonMain.kt
new file mode 100644
index 00000000..301f3efb
--- /dev/null
+++ b/integration-tests/src/test/resources/hmpp/workload/src/commonMain/kotlin/CommonMain.kt
@@ -0,0 +1 @@
+class CommonMain
diff --git a/integration-tests/src/test/resources/hmpp/workload/src/jsMain/kotlin/JsMain.kt b/integration-tests/src/test/resources/hmpp/workload/src/jsMain/kotlin/JsMain.kt
new file mode 100644
index 00000000..1192259a
--- /dev/null
+++ b/integration-tests/src/test/resources/hmpp/workload/src/jsMain/kotlin/JsMain.kt
@@ -0,0 +1 @@
+class JsMain
diff --git a/integration-tests/src/test/resources/hmpp/workload/src/jvmJs/kotlin/JvmJs.kt b/integration-tests/src/test/resources/hmpp/workload/src/jvmJs/kotlin/JvmJs.kt
new file mode 100644
index 00000000..b5ad67b7
--- /dev/null
+++ b/integration-tests/src/test/resources/hmpp/workload/src/jvmJs/kotlin/JvmJs.kt
@@ -0,0 +1 @@
+class JvmJs
diff --git a/integration-tests/src/test/resources/hmpp/workload/src/jvmLinuxX64/kotlin/JvmLinuxX64.kt b/integration-tests/src/test/resources/hmpp/workload/src/jvmLinuxX64/kotlin/JvmLinuxX64.kt
new file mode 100644
index 00000000..38ab721d
--- /dev/null
+++ b/integration-tests/src/test/resources/hmpp/workload/src/jvmLinuxX64/kotlin/JvmLinuxX64.kt
@@ -0,0 +1 @@
+class JvmLinuxX64
diff --git a/integration-tests/src/test/resources/hmpp/workload/src/jvmMain/kotlin/JvmMain.kt b/integration-tests/src/test/resources/hmpp/workload/src/jvmMain/kotlin/JvmMain.kt
new file mode 100644
index 00000000..ffae14b7
--- /dev/null
+++ b/integration-tests/src/test/resources/hmpp/workload/src/jvmMain/kotlin/JvmMain.kt
@@ -0,0 +1 @@
+class JvmMain
diff --git a/integration-tests/src/test/resources/hmpp/workload/src/jvmOnly/kotlin/JvmOnly.kt b/integration-tests/src/test/resources/hmpp/workload/src/jvmOnly/kotlin/JvmOnly.kt
new file mode 100644
index 00000000..a373d6e5
--- /dev/null
+++ b/integration-tests/src/test/resources/hmpp/workload/src/jvmOnly/kotlin/JvmOnly.kt
@@ -0,0 +1 @@
+class JvmOnly
diff --git a/integration-tests/src/test/resources/hmpp/workload/src/linuxX64Main/kotlin/LinuxX64Main.kt b/integration-tests/src/test/resources/hmpp/workload/src/linuxX64Main/kotlin/LinuxX64Main.kt
new file mode 100644
index 00000000..3058bc8d
--- /dev/null
+++ b/integration-tests/src/test/resources/hmpp/workload/src/linuxX64Main/kotlin/LinuxX64Main.kt
@@ -0,0 +1,4 @@
+class LinuxX64Main
+
+fun main() {
+}
diff --git a/integration-tests/src/test/resources/incremental-classpath/build.gradle.kts b/integration-tests/src/test/resources/incremental-classpath/build.gradle.kts
new file mode 100644
index 00000000..c5737a2e
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/build.gradle.kts
@@ -0,0 +1,8 @@
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
diff --git a/integration-tests/src/test/resources/incremental-classpath/gradle.properties b/integration-tests/src/test/resources/incremental-classpath/gradle.properties
new file mode 100644
index 00000000..6b0be573
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/gradle.properties
@@ -0,0 +1,3 @@
+ksp.incremental=true
+ksp.incremental.log=true
+ksp.incremental.intermodule=true \ No newline at end of file
diff --git a/integration-tests/src/test/resources/incremental-classpath/l1/build.gradle.kts b/integration-tests/src/test/resources/incremental-classpath/l1/build.gradle.kts
new file mode 100644
index 00000000..b89421bb
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/l1/build.gradle.kts
@@ -0,0 +1,18 @@
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation(project(":l2"))
+}
diff --git a/integration-tests/src/test/resources/incremental-classpath/l1/src/main/kotlin/p1/L1.kt b/integration-tests/src/test/resources/incremental-classpath/l1/src/main/kotlin/p1/L1.kt
new file mode 100644
index 00000000..dfd4184b
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/l1/src/main/kotlin/p1/L1.kt
@@ -0,0 +1,3 @@
+package p1
+
+open class L1 : L2()
diff --git a/integration-tests/src/test/resources/incremental-classpath/l2/build.gradle.kts b/integration-tests/src/test/resources/incremental-classpath/l2/build.gradle.kts
new file mode 100644
index 00000000..d4adefee
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/l2/build.gradle.kts
@@ -0,0 +1,17 @@
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+}
diff --git a/integration-tests/src/test/resources/incremental-classpath/l2/src/main/kotlin/p1/L2.kt b/integration-tests/src/test/resources/incremental-classpath/l2/src/main/kotlin/p1/L2.kt
new file mode 100644
index 00000000..ce4f1ec1
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/l2/src/main/kotlin/p1/L2.kt
@@ -0,0 +1,3 @@
+package p1
+
+open class L2
diff --git a/integration-tests/src/test/resources/incremental-classpath/l3/build.gradle.kts b/integration-tests/src/test/resources/incremental-classpath/l3/build.gradle.kts
new file mode 100644
index 00000000..d4adefee
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/l3/build.gradle.kts
@@ -0,0 +1,17 @@
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+}
diff --git a/integration-tests/src/test/resources/incremental-classpath/l3/src/main/kotlin/p1/L3.kt b/integration-tests/src/test/resources/incremental-classpath/l3/src/main/kotlin/p1/L3.kt
new file mode 100644
index 00000000..1b79ba13
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/l3/src/main/kotlin/p1/L3.kt
@@ -0,0 +1,3 @@
+package p1
+
+open class L3
diff --git a/integration-tests/src/test/resources/incremental-classpath/l4/build.gradle.kts b/integration-tests/src/test/resources/incremental-classpath/l4/build.gradle.kts
new file mode 100644
index 00000000..d4adefee
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/l4/build.gradle.kts
@@ -0,0 +1,17 @@
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+}
diff --git a/integration-tests/src/test/resources/incremental-classpath/l4/src/main/kotlin/p1/L4.kt b/integration-tests/src/test/resources/incremental-classpath/l4/src/main/kotlin/p1/L4.kt
new file mode 100644
index 00000000..a8c6aa17
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/l4/src/main/kotlin/p1/L4.kt
@@ -0,0 +1,3 @@
+package p1
+
+open class L4
diff --git a/integration-tests/src/test/resources/incremental-classpath/l5/build.gradle.kts b/integration-tests/src/test/resources/incremental-classpath/l5/build.gradle.kts
new file mode 100644
index 00000000..d4adefee
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/l5/build.gradle.kts
@@ -0,0 +1,17 @@
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+}
diff --git a/integration-tests/src/test/resources/incremental-classpath/l5/src/main/kotlin/p1/L5.kt b/integration-tests/src/test/resources/incremental-classpath/l5/src/main/kotlin/p1/L5.kt
new file mode 100644
index 00000000..5bfed66b
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/l5/src/main/kotlin/p1/L5.kt
@@ -0,0 +1,3 @@
+package p1
+
+open class L5
diff --git a/integration-tests/src/test/resources/incremental-classpath/settings.gradle.kts b/integration-tests/src/test/resources/incremental-classpath/settings.gradle.kts
new file mode 100644
index 00000000..c4a1f4cd
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/settings.gradle.kts
@@ -0,0 +1,24 @@
+pluginManagement {
+ val kspVersion: String by settings
+ val kotlinVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "incremental-test"
+
+include(":workload")
+include(":validator")
+include(":l1")
+include(":l2")
+include(":l3")
+include(":l4")
+include(":l5")
diff --git a/integration-tests/src/test/resources/incremental-classpath/validator/build.gradle.kts b/integration-tests/src/test/resources/incremental-classpath/validator/build.gradle.kts
new file mode 100644
index 00000000..ab249cf0
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/validator/build.gradle.kts
@@ -0,0 +1,24 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
diff --git a/integration-tests/src/test/resources/incremental-classpath/validator/src/main/kotlin/Validator.kt b/integration-tests/src/test/resources/incremental-classpath/validator/src/main/kotlin/Validator.kt
new file mode 100644
index 00000000..a467ade0
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/validator/src/main/kotlin/Validator.kt
@@ -0,0 +1,79 @@
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.validate
+import com.google.devtools.ksp.visitor.KSDefaultVisitor
+import java.io.OutputStreamWriter
+
+class Validator : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+ lateinit var logger: KSPLogger
+ var processed = false
+
+ fun init(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger,
+ ) {
+ this.codeGenerator = codeGenerator
+ this.logger = logger
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ if (processed) {
+ return emptyList()
+ }
+ val validator = object : KSDefaultVisitor<OutputStreamWriter, Unit>() {
+ override fun defaultHandler(node: KSNode, data: OutputStreamWriter) = Unit
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: OutputStreamWriter) {
+ data.write(declaration.qualifiedName?.asString() ?: declaration.simpleName.asString())
+ declaration.validate()
+ }
+ }
+
+ // for each file, create an output from it and everything reachable from it.
+ val files = resolver.getAllFiles()
+ files.forEach { file ->
+ logger.warn("${file.packageName.asString()}/${file.fileName}")
+ val output = OutputStreamWriter(
+ codeGenerator.createNewFile(
+ Dependencies(false, file),
+ file.packageName.asString(),
+ file.fileName,
+ "log"
+ )
+ )
+ file.declarations.forEach {
+ it.accept(validator, output)
+ }
+ output.close()
+ }
+
+ // create an output from k3 + l4
+ val k3 = resolver.getClassDeclarationByName("p1.K3")!!
+ val l4 = resolver.getClassDeclarationByName("p1.L4")!!
+ codeGenerator.createNewFile(Dependencies(false), "p1", "l4", "log")
+ codeGenerator.associateWithClasses(listOf(k3, l4), "p1", "l4", "log")
+
+ // create an output from l5
+ val l5 = resolver.getClassDeclarationByName("p1.L5")!!
+ codeGenerator.createNewFile(Dependencies(false), "p1", "l5", "log")
+ codeGenerator.associateWithClasses(listOf(l5), "p1", "l5", "log")
+ logger.warn("processing done")
+
+ processed = true
+ return emptyList()
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment,
+ ): SymbolProcessor {
+ return Validator().apply {
+ init(env.options, env.kotlinVersion, env.codeGenerator, env.logger)
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/incremental-classpath/validator/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/incremental-classpath/validator/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..c91e3e9e
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/validator/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+TestProcessorProvider
diff --git a/integration-tests/src/test/resources/incremental-classpath/workload/build.gradle.kts b/integration-tests/src/test/resources/incremental-classpath/workload/build.gradle.kts
new file mode 100644
index 00000000..e8f910b1
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/workload/build.gradle.kts
@@ -0,0 +1,26 @@
+val testRepo: String by project
+
+plugins {
+ id("com.google.devtools.ksp")
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation(project(":validator"))
+ implementation(project(":l1"))
+ implementation(project(":l2"))
+ implementation(project(":l3"))
+ implementation(project(":l4"))
+ implementation(project(":l5"))
+ testImplementation("junit:junit:4.12")
+ ksp(project(":validator"))
+}
diff --git a/integration-tests/src/test/resources/incremental-classpath/workload/src/main/kotlin/p1/K1.kt b/integration-tests/src/test/resources/incremental-classpath/workload/src/main/kotlin/p1/K1.kt
new file mode 100644
index 00000000..69c56673
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/workload/src/main/kotlin/p1/K1.kt
@@ -0,0 +1,5 @@
+package p1
+
+open class K1 {
+ val v = L1()
+}
diff --git a/integration-tests/src/test/resources/incremental-classpath/workload/src/main/kotlin/p1/K2.kt b/integration-tests/src/test/resources/incremental-classpath/workload/src/main/kotlin/p1/K2.kt
new file mode 100644
index 00000000..ea09ec3d
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/workload/src/main/kotlin/p1/K2.kt
@@ -0,0 +1,5 @@
+package p1
+
+open class K2 {
+ val v = L2()
+}
diff --git a/integration-tests/src/test/resources/incremental-classpath/workload/src/main/kotlin/p1/K3.kt b/integration-tests/src/test/resources/incremental-classpath/workload/src/main/kotlin/p1/K3.kt
new file mode 100644
index 00000000..29929705
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-classpath/workload/src/main/kotlin/p1/K3.kt
@@ -0,0 +1,5 @@
+package p1
+
+open class K3 {
+ val v = L3()
+}
diff --git a/integration-tests/src/test/resources/incremental-multi-chain/build.gradle.kts b/integration-tests/src/test/resources/incremental-multi-chain/build.gradle.kts
new file mode 100644
index 00000000..c5737a2e
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-multi-chain/build.gradle.kts
@@ -0,0 +1,8 @@
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
diff --git a/integration-tests/src/test/resources/incremental-multi-chain/gradle.properties b/integration-tests/src/test/resources/incremental-multi-chain/gradle.properties
new file mode 100644
index 00000000..f9325643
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-multi-chain/gradle.properties
@@ -0,0 +1,2 @@
+ksp.incremental=true
+ksp.incremental.log=true \ No newline at end of file
diff --git a/integration-tests/src/test/resources/incremental-multi-chain/processors/build.gradle.kts b/integration-tests/src/test/resources/incremental-multi-chain/processors/build.gradle.kts
new file mode 100644
index 00000000..ab249cf0
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-multi-chain/processors/build.gradle.kts
@@ -0,0 +1,24 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
diff --git a/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/Aggregator.kt b/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/Aggregator.kt
new file mode 100644
index 00000000..d7c25217
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/Aggregator.kt
@@ -0,0 +1,46 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import java.io.OutputStreamWriter
+
+class Aggregator : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+ lateinit var logger: KSPLogger
+
+ fun init(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger,
+ ) {
+ this.codeGenerator = codeGenerator
+ this.logger = logger
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val impls = resolver.getSymbolsWithAnnotation("Impl").map { it as KSDeclaration }.toList()
+ if (impls.isNotEmpty()) {
+ val names = impls.map { it.simpleName.asString() }.sorted()
+ OutputStreamWriter(
+ codeGenerator.createNewFile(
+ Dependencies(true), "", "AllImpls"
+ )
+ ).use {
+ it.write("class AllImpls {\n")
+ it.write(" override fun toString() = \"$names\"\n")
+ it.write("}\n")
+ }
+ codeGenerator.associate(impls.map { it.containingFile!! }.toList(), "", "AllImpls")
+ }
+ return emptyList()
+ }
+}
+
+class AggregatorProvider : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment,
+ ): SymbolProcessor {
+ return Aggregator().apply {
+ init(env.options, env.kotlinVersion, env.codeGenerator, env.logger)
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/ImplGen.kt b/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/ImplGen.kt
new file mode 100644
index 00000000..fec8d2d2
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/ImplGen.kt
@@ -0,0 +1,46 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import java.io.OutputStreamWriter
+
+class ImplGen : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+ lateinit var logger: KSPLogger
+
+ fun init(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger,
+ ) {
+ this.codeGenerator = codeGenerator
+ this.logger = logger
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getSymbolsWithAnnotation("NeedsImpl").forEach { decl ->
+ decl as KSClassDeclaration
+ val file = decl.containingFile!!
+ val baseName = decl.simpleName.asString()
+ val implName = baseName + "Impl"
+ OutputStreamWriter(
+ codeGenerator.createNewFile(
+ Dependencies(false, file),
+ "", implName
+ )
+ ).use {
+ it.write("@Impl class $implName : $baseName\n")
+ }
+ }
+ return emptyList()
+ }
+}
+
+class ImplGenProvider : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment,
+ ): SymbolProcessor {
+ return ImplGen().apply {
+ init(env.options, env.kotlinVersion, env.codeGenerator, env.logger)
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/Validator.kt b/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/Validator.kt
new file mode 100644
index 00000000..5ecf7527
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/Validator.kt
@@ -0,0 +1,36 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.validate
+
+class Validator : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+ lateinit var logger: KSPLogger
+
+ fun init(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger,
+ ) {
+ this.codeGenerator = codeGenerator
+ this.logger = logger
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach {
+ logger.warn("validating ${it.fileName}")
+ it.validate()
+ }
+ return emptyList()
+ }
+}
+
+class ValidatorProvider : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment,
+ ): SymbolProcessor {
+ return Validator().apply {
+ init(env.options, env.kotlinVersion, env.codeGenerator, env.logger)
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..906e3eaf
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1,3 @@
+AggregatorProvider
+ImplGenProvider
+ValidatorProvider
diff --git a/integration-tests/src/test/resources/incremental-multi-chain/settings.gradle.kts b/integration-tests/src/test/resources/incremental-multi-chain/settings.gradle.kts
new file mode 100644
index 00000000..18f47de4
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-multi-chain/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ val kspVersion: String by settings
+ val kotlinVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "incremental-test"
+
+include(":workload")
+include(":processors")
diff --git a/integration-tests/src/test/resources/incremental-multi-chain/workload/build.gradle.kts b/integration-tests/src/test/resources/incremental-multi-chain/workload/build.gradle.kts
new file mode 100644
index 00000000..2f6a0fc5
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-multi-chain/workload/build.gradle.kts
@@ -0,0 +1,24 @@
+val testRepo: String by project
+
+plugins {
+ id("com.google.devtools.ksp")
+ kotlin("jvm")
+ application
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ ksp(project(":processors"))
+}
+
+application {
+ mainClassName = "MainKt"
+}
diff --git a/integration-tests/src/test/resources/incremental-multi-chain/workload/src/main/kotlin/K1.kt b/integration-tests/src/test/resources/incremental-multi-chain/workload/src/main/kotlin/K1.kt
new file mode 100644
index 00000000..ac8854e9
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-multi-chain/workload/src/main/kotlin/K1.kt
@@ -0,0 +1,2 @@
+@NeedsImpl
+interface K1
diff --git a/integration-tests/src/test/resources/incremental-multi-chain/workload/src/main/kotlin/Main.kt b/integration-tests/src/test/resources/incremental-multi-chain/workload/src/main/kotlin/Main.kt
new file mode 100644
index 00000000..cdf05607
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-multi-chain/workload/src/main/kotlin/Main.kt
@@ -0,0 +1,8 @@
+annotation class NeedsImpl
+annotation class Impl
+
+val x: AllImpls = AllImpls()
+
+fun main() {
+ println(x.toString())
+}
diff --git a/integration-tests/src/test/resources/incremental-removal/build.gradle.kts b/integration-tests/src/test/resources/incremental-removal/build.gradle.kts
new file mode 100644
index 00000000..c5737a2e
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-removal/build.gradle.kts
@@ -0,0 +1,8 @@
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
diff --git a/integration-tests/src/test/resources/incremental-removal/gradle.properties b/integration-tests/src/test/resources/incremental-removal/gradle.properties
new file mode 100644
index 00000000..f9325643
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-removal/gradle.properties
@@ -0,0 +1,2 @@
+ksp.incremental=true
+ksp.incremental.log=true \ No newline at end of file
diff --git a/integration-tests/src/test/resources/incremental-removal/settings.gradle.kts b/integration-tests/src/test/resources/incremental-removal/settings.gradle.kts
new file mode 100644
index 00000000..75f651ef
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-removal/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ val kspVersion: String by settings
+ val kotlinVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "incremental-test"
+
+include(":workload")
+include(":validator")
diff --git a/integration-tests/src/test/resources/incremental-removal/validator/build.gradle.kts b/integration-tests/src/test/resources/incremental-removal/validator/build.gradle.kts
new file mode 100644
index 00000000..ab249cf0
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-removal/validator/build.gradle.kts
@@ -0,0 +1,24 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
diff --git a/integration-tests/src/test/resources/incremental-removal/validator/src/main/kotlin/Validator.kt b/integration-tests/src/test/resources/incremental-removal/validator/src/main/kotlin/Validator.kt
new file mode 100644
index 00000000..635c7d7a
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-removal/validator/src/main/kotlin/Validator.kt
@@ -0,0 +1,48 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.validate
+import java.io.OutputStreamWriter
+
+class Validator : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+ lateinit var logger: KSPLogger
+
+ fun init(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger,
+ ) {
+ this.codeGenerator = codeGenerator
+ this.logger = logger
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getSymbolsWithAnnotation("p1.MyAnnotation").singleOrNull()?.let { decl ->
+ decl as KSClassDeclaration
+ val file = decl.containingFile!!
+ OutputStreamWriter(
+ codeGenerator.createNewFile(
+ Dependencies(false, file),
+ "p1", "Foo"
+ )
+ ).use {
+ it.write("package p1\n\nclass Foo : Bar { override fun s() = \"generated\" }\n")
+ }
+ }
+ resolver.getNewFiles().forEach {
+ it.validate()
+ }
+ return emptyList()
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment,
+ ): SymbolProcessor {
+ return Validator().apply {
+ init(env.options, env.kotlinVersion, env.codeGenerator, env.logger)
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/incremental-removal/validator/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/incremental-removal/validator/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..c91e3e9e
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-removal/validator/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+TestProcessorProvider
diff --git a/integration-tests/src/test/resources/incremental-removal/workload/build.gradle.kts b/integration-tests/src/test/resources/incremental-removal/workload/build.gradle.kts
new file mode 100644
index 00000000..caa2c8c2
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-removal/workload/build.gradle.kts
@@ -0,0 +1,27 @@
+val testRepo: String by project
+
+plugins {
+ id("com.google.devtools.ksp")
+ kotlin("jvm")
+ application
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation(project(":validator"))
+ testImplementation("junit:junit:4.12")
+ ksp(project(":validator"))
+ kspTest(project(":validator"))
+}
+
+application {
+ mainClassName = "p1.MainKt"
+}
diff --git a/integration-tests/src/test/resources/incremental-removal/workload/src/main/kotlin/p1/K1.kt b/integration-tests/src/test/resources/incremental-removal/workload/src/main/kotlin/p1/K1.kt
new file mode 100644
index 00000000..5b31cfdb
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-removal/workload/src/main/kotlin/p1/K1.kt
@@ -0,0 +1,4 @@
+package p1
+
+@MyAnnotation
+class K1
diff --git a/integration-tests/src/test/resources/incremental-removal/workload/src/main/kotlin/p1/Main.kt b/integration-tests/src/test/resources/incremental-removal/workload/src/main/kotlin/p1/Main.kt
new file mode 100644
index 00000000..24b10a60
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental-removal/workload/src/main/kotlin/p1/Main.kt
@@ -0,0 +1,12 @@
+package p1
+
+interface Bar {
+ fun s(): String
+}
+val bar: Foo = Foo()
+
+annotation class MyAnnotation
+
+fun main() {
+ println("result: ${bar.s()}")
+}
diff --git a/integration-tests/src/test/resources/incremental/build.gradle.kts b/integration-tests/src/test/resources/incremental/build.gradle.kts
new file mode 100644
index 00000000..c5737a2e
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/build.gradle.kts
@@ -0,0 +1,8 @@
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
diff --git a/integration-tests/src/test/resources/incremental/gradle.properties b/integration-tests/src/test/resources/incremental/gradle.properties
new file mode 100644
index 00000000..f9325643
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/gradle.properties
@@ -0,0 +1,2 @@
+ksp.incremental=true
+ksp.incremental.log=true \ No newline at end of file
diff --git a/integration-tests/src/test/resources/incremental/settings.gradle.kts b/integration-tests/src/test/resources/incremental/settings.gradle.kts
new file mode 100644
index 00000000..75f651ef
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ val kspVersion: String by settings
+ val kotlinVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "incremental-test"
+
+include(":workload")
+include(":validator")
diff --git a/integration-tests/src/test/resources/incremental/validator/build.gradle.kts b/integration-tests/src/test/resources/incremental/validator/build.gradle.kts
new file mode 100644
index 00000000..ab249cf0
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/validator/build.gradle.kts
@@ -0,0 +1,24 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
diff --git a/integration-tests/src/test/resources/incremental/validator/src/main/kotlin/Validator.kt b/integration-tests/src/test/resources/incremental/validator/src/main/kotlin/Validator.kt
new file mode 100644
index 00000000..96952d10
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/validator/src/main/kotlin/Validator.kt
@@ -0,0 +1,62 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.validate
+import com.google.devtools.ksp.visitor.KSDefaultVisitor
+import java.io.OutputStreamWriter
+
+class Validator : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+ lateinit var logger: KSPLogger
+ var processed = false
+
+ fun init(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger,
+ ) {
+ this.codeGenerator = codeGenerator
+ this.logger = logger
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ if (processed) {
+ return emptyList()
+ }
+ val validator = object : KSDefaultVisitor<OutputStreamWriter, Unit>() {
+ override fun defaultHandler(node: KSNode, data: OutputStreamWriter) = Unit
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: OutputStreamWriter) {
+ data.write(declaration.qualifiedName?.asString() ?: declaration.simpleName.asString())
+ declaration.validate()
+ }
+ }
+
+ val files = resolver.getAllFiles()
+ files.forEach { file ->
+ logger.warn("${file.packageName.asString()}/${file.fileName}")
+ val output = OutputStreamWriter(
+ codeGenerator.createNewFile(
+ Dependencies(false, file),
+ file.packageName.asString(), file.fileName, "log"
+ )
+ )
+ file.declarations.forEach {
+ it.accept(validator, output)
+ }
+ output.close()
+ }
+ processed = true
+ return emptyList()
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment,
+ ): SymbolProcessor {
+ return Validator().apply {
+ init(env.options, env.kotlinVersion, env.codeGenerator, env.logger)
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/incremental/validator/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/incremental/validator/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..c91e3e9e
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/validator/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+TestProcessorProvider
diff --git a/integration-tests/src/test/resources/incremental/workload/build.gradle.kts b/integration-tests/src/test/resources/incremental/workload/build.gradle.kts
new file mode 100644
index 00000000..00e18e2a
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/build.gradle.kts
@@ -0,0 +1,22 @@
+val testRepo: String by project
+
+plugins {
+ id("com.google.devtools.ksp")
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation(project(":validator"))
+ testImplementation("junit:junit:4.12")
+ ksp(project(":validator"))
+ kspTest(project(":validator"))
+}
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/java/p1/J1.java b/integration-tests/src/test/resources/incremental/workload/src/main/java/p1/J1.java
new file mode 100644
index 00000000..b2e2e87c
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/java/p1/J1.java
@@ -0,0 +1,3 @@
+package p1;
+
+public class J1 {}
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/java/p1/J2.java b/integration-tests/src/test/resources/incremental/workload/src/main/java/p1/J2.java
new file mode 100644
index 00000000..7de0687e
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/java/p1/J2.java
@@ -0,0 +1,4 @@
+package p1;
+
+public class J2 {
+}
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/java/p1/TestJ2J.java b/integration-tests/src/test/resources/incremental/workload/src/main/java/p1/TestJ2J.java
new file mode 100644
index 00000000..9866bfee
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/java/p1/TestJ2J.java
@@ -0,0 +1,11 @@
+package p1;
+
+import p2.J2;
+import p3.*;
+
+public class TestJ2J {
+ J1 j1 = null;
+ J2 j2 = null;
+ J3 j3 = null;
+}
+
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/java/p1/TestJ2K.java b/integration-tests/src/test/resources/incremental/workload/src/main/java/p1/TestJ2K.java
new file mode 100644
index 00000000..b5d055bb
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/java/p1/TestJ2K.java
@@ -0,0 +1,10 @@
+package p1;
+
+import p2.K2;
+import p3.*;
+
+public class TestJ2K {
+ K1 k1 = null;
+ K2 k2 = null;
+ K3 k3 = null;
+}
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/java/p2/J2.java b/integration-tests/src/test/resources/incremental/workload/src/main/java/p2/J2.java
new file mode 100644
index 00000000..1e10b7c4
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/java/p2/J2.java
@@ -0,0 +1,4 @@
+package p2;
+
+public class J2 {
+}
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/java/p3/J1.java b/integration-tests/src/test/resources/incremental/workload/src/main/java/p3/J1.java
new file mode 100644
index 00000000..2e5ed679
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/java/p3/J1.java
@@ -0,0 +1,4 @@
+package p3;
+
+public class J1 {
+}
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/java/p3/J2.java b/integration-tests/src/test/resources/incremental/workload/src/main/java/p3/J2.java
new file mode 100644
index 00000000..fc7d454e
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/java/p3/J2.java
@@ -0,0 +1,4 @@
+package p3;
+
+public class J2 {
+}
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/java/p3/J3.java b/integration-tests/src/test/resources/incremental/workload/src/main/java/p3/J3.java
new file mode 100644
index 00000000..08cfb5ec
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/java/p3/J3.java
@@ -0,0 +1,4 @@
+package p3;
+
+public class J3 {
+}
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/K1.kt b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/K1.kt
new file mode 100644
index 00000000..eb739a3d
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/K1.kt
@@ -0,0 +1,3 @@
+package p1
+
+open class K1
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/K2.kt b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/K2.kt
new file mode 100644
index 00000000..e5134f49
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/K2.kt
@@ -0,0 +1,3 @@
+package p1
+
+open class K2
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/TestK2J.kt b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/TestK2J.kt
new file mode 100644
index 00000000..81cb4d47
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/TestK2J.kt
@@ -0,0 +1,10 @@
+package p1
+
+import p2.J2
+import p3.*
+
+open class TestK2J() {
+ val v1: J1 = TODO()
+ val v2: J2 = TODO()
+ val v3: J3 = TODO()
+}
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/TestK2K.kt b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/TestK2K.kt
new file mode 100644
index 00000000..401e340f
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p1/TestK2K.kt
@@ -0,0 +1,10 @@
+package p1
+
+import p2.K2
+import p3.*
+
+open class TestK2K() {
+ val v1: K1 = TODO()
+ val v2: K2 = TODO()
+ val v3: K3 = TODO()
+}
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p2/K2.kt b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p2/K2.kt
new file mode 100644
index 00000000..55ae6f0a
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p2/K2.kt
@@ -0,0 +1,3 @@
+package p2
+
+open class K2
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p3/K1.kt b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p3/K1.kt
new file mode 100644
index 00000000..6f727609
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p3/K1.kt
@@ -0,0 +1,3 @@
+package p3
+
+open class K1
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p3/K2.kt b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p3/K2.kt
new file mode 100644
index 00000000..d3aa0f93
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p3/K2.kt
@@ -0,0 +1,3 @@
+package p3
+
+open class K2
diff --git a/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p3/K3.kt b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p3/K3.kt
new file mode 100644
index 00000000..522ffff4
--- /dev/null
+++ b/integration-tests/src/test/resources/incremental/workload/src/main/kotlin/p3/K3.kt
@@ -0,0 +1,3 @@
+package p3
+
+open class K3
diff --git a/integration-tests/src/test/resources/init-plus-provider/build.gradle.kts b/integration-tests/src/test/resources/init-plus-provider/build.gradle.kts
new file mode 100644
index 00000000..c5737a2e
--- /dev/null
+++ b/integration-tests/src/test/resources/init-plus-provider/build.gradle.kts
@@ -0,0 +1,8 @@
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
diff --git a/integration-tests/src/test/resources/init-plus-provider/provider-processor/build.gradle.kts b/integration-tests/src/test/resources/init-plus-provider/provider-processor/build.gradle.kts
new file mode 100644
index 00000000..ab249cf0
--- /dev/null
+++ b/integration-tests/src/test/resources/init-plus-provider/provider-processor/build.gradle.kts
@@ -0,0 +1,24 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
diff --git a/integration-tests/src/test/resources/init-plus-provider/provider-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/init-plus-provider/provider-processor/src/main/kotlin/TestProcessor.kt
new file mode 100644
index 00000000..7bb6d4d4
--- /dev/null
+++ b/integration-tests/src/test/resources/init-plus-provider/provider-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,41 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import java.io.OutputStream
+
+fun OutputStream.appendText(str: String) {
+ this.write(str.toByteArray())
+}
+
+class TestProcessor(options: Map<String, String>, val codeGenerator: CodeGenerator) : SymbolProcessor {
+ val file: OutputStream = codeGenerator.createNewFile(Dependencies(false), "", "TestProcessor", "log")
+
+ init {
+ file.appendText("TestProcessor: init($options)\n")
+
+ val javaFile = codeGenerator.createNewFile(Dependencies(false), "", "GeneratedFromProvider", "java")
+ javaFile.appendText("class GeneratedFromProvider {}")
+ }
+
+ var invoked = false
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ if (invoked) {
+ return emptyList()
+ }
+
+ val fileKt = codeGenerator.createNewFile(Dependencies(false), "", "HelloFromProvider", "java")
+
+ fileKt.appendText("public class HelloFromProvider{\n")
+ fileKt.appendText(" public int foo() { return 5678; }\n")
+ fileKt.appendText("}")
+
+ invoked = true
+ return emptyList()
+ }
+
+ class Provider : SymbolProcessorProvider {
+ override fun create(
+ environment: SymbolProcessorEnvironment
+ ): SymbolProcessor = TestProcessor(environment.options, environment.codeGenerator)
+ }
+}
diff --git a/integration-tests/src/test/resources/init-plus-provider/provider-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/init-plus-provider/provider-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..5c51c309
--- /dev/null
+++ b/integration-tests/src/test/resources/init-plus-provider/provider-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+TestProcessor$Provider
diff --git a/integration-tests/src/test/resources/init-plus-provider/settings.gradle.kts b/integration-tests/src/test/resources/init-plus-provider/settings.gradle.kts
new file mode 100644
index 00000000..73f2260c
--- /dev/null
+++ b/integration-tests/src/test/resources/init-plus-provider/settings.gradle.kts
@@ -0,0 +1,22 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ val testRepo: String by settings
+
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "init-plus-provider"
+
+include(":workload")
+include(":init-processor")
+include(":provider-processor")
diff --git a/integration-tests/src/test/resources/init-plus-provider/workload/build.gradle.kts b/integration-tests/src/test/resources/init-plus-provider/workload/build.gradle.kts
new file mode 100644
index 00000000..da44c4dd
--- /dev/null
+++ b/integration-tests/src/test/resources/init-plus-provider/workload/build.gradle.kts
@@ -0,0 +1,24 @@
+val testRepo: String by project
+
+plugins {
+ id("com.google.devtools.ksp")
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ ksp(project(":provider-processor"))
+}
+
+ksp {
+ arg("option1", "value1")
+ arg("option2", "value2")
+}
diff --git a/integration-tests/src/test/resources/init-plus-provider/workload/src/main/java/com/example/A.kt b/integration-tests/src/test/resources/init-plus-provider/workload/src/main/java/com/example/A.kt
new file mode 100644
index 00000000..fd782149
--- /dev/null
+++ b/integration-tests/src/test/resources/init-plus-provider/workload/src/main/java/com/example/A.kt
@@ -0,0 +1,7 @@
+package com.example
+
+import HelloFromProvider
+
+fun main() {
+ HelloFromProvider().foo()
+}
diff --git a/integration-tests/src/test/resources/java-only/test-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/java-only/test-processor/src/main/kotlin/TestProcessor.kt
new file mode 100644
index 00000000..fe418e7b
--- /dev/null
+++ b/integration-tests/src/test/resources/java-only/test-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,30 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import java.io.OutputStreamWriter
+
+class TestProcessor(
+ val codeGenerator: CodeGenerator,
+ val logger: KSPLogger
+) : SymbolProcessor {
+ var rounds = 0
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ if (++rounds == 1) {
+ codeGenerator.createNewFile(Dependencies(false), "com.example", "Bar", "kt").use { output ->
+ OutputStreamWriter(output).use { writer ->
+ writer.write("package com.example\n\n")
+ writer.write("interface Bar\n")
+ }
+ }
+ }
+
+ return emptyList()
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ environment: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return TestProcessor(environment.codeGenerator, environment.logger)
+ }
+}
diff --git a/integration-tests/src/test/resources/java-only/workload/src/main/java/com/example/Foo.java b/integration-tests/src/test/resources/java-only/workload/src/main/java/com/example/Foo.java
new file mode 100644
index 00000000..f6a7cf05
--- /dev/null
+++ b/integration-tests/src/test/resources/java-only/workload/src/main/java/com/example/Foo.java
@@ -0,0 +1,4 @@
+package com.example;
+
+class Foo implements Bar {
+}
diff --git a/integration-tests/src/test/resources/javaNestedClass/build.gradle.kts b/integration-tests/src/test/resources/javaNestedClass/build.gradle.kts
new file mode 100644
index 00000000..c5737a2e
--- /dev/null
+++ b/integration-tests/src/test/resources/javaNestedClass/build.gradle.kts
@@ -0,0 +1,8 @@
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
diff --git a/integration-tests/src/test/resources/javaNestedClass/settings.gradle.kts b/integration-tests/src/test/resources/javaNestedClass/settings.gradle.kts
new file mode 100644
index 00000000..5cb08c92
--- /dev/null
+++ b/integration-tests/src/test/resources/javaNestedClass/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "javaNestedClass"
+
+include(":workload")
+include(":test-processor")
diff --git a/integration-tests/src/test/resources/javaNestedClass/test-processor/build.gradle.kts b/integration-tests/src/test/resources/javaNestedClass/test-processor/build.gradle.kts
new file mode 100644
index 00000000..75c6c7c5
--- /dev/null
+++ b/integration-tests/src/test/resources/javaNestedClass/test-processor/build.gradle.kts
@@ -0,0 +1,25 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.squareup:javapoet:1.12.1")
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
diff --git a/integration-tests/src/test/resources/javaNestedClass/test-processor/src/main/kotlin/ValidateProcessor.kt b/integration-tests/src/test/resources/javaNestedClass/test-processor/src/main/kotlin/ValidateProcessor.kt
new file mode 100644
index 00000000..80931541
--- /dev/null
+++ b/integration-tests/src/test/resources/javaNestedClass/test-processor/src/main/kotlin/ValidateProcessor.kt
@@ -0,0 +1,38 @@
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.validate
+
+class ValidateProcessor(env: SymbolProcessorEnvironment) : SymbolProcessor {
+ var logger: KSPLogger = env.logger
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val javaClass = resolver.getClassDeclarationByName("com.example.JavaClass")!!
+ val nestedClass = javaClass.declarations.filterIsInstance<KSClassDeclaration>()
+ .single { it.simpleName.asString() == "NestedClass" }
+ val provideString = nestedClass.declarations.filterIsInstance<KSFunctionDeclaration>()
+ .single { it.simpleName.asString() == "provideString" }
+
+ if (provideString.returnType!!.resolve().isError) {
+ logger.error("provideString.returnType: not ok")
+ }
+ if (nestedClass.asStarProjectedType().isError == true) {
+ logger.error("$javaClass.asStarProjectedType(): not ok")
+ }
+ if (!nestedClass.validate()) {
+ logger.error("Failed to validate $nestedClass")
+ }
+ if (!javaClass.validate()) {
+ logger.error("Failed to validate $javaClass")
+ }
+ return emptyList()
+ }
+}
+
+class ValidateProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return ValidateProcessor(env)
+ }
+}
diff --git a/integration-tests/src/test/resources/javaNestedClass/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/javaNestedClass/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..6af81c2a
--- /dev/null
+++ b/integration-tests/src/test/resources/javaNestedClass/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+ValidateProcessorProvider
diff --git a/integration-tests/src/test/resources/javaNestedClass/workload/build.gradle.kts b/integration-tests/src/test/resources/javaNestedClass/workload/build.gradle.kts
new file mode 100644
index 00000000..f0ea52b0
--- /dev/null
+++ b/integration-tests/src/test/resources/javaNestedClass/workload/build.gradle.kts
@@ -0,0 +1,20 @@
+val testRepo: String by project
+
+plugins {
+ id("com.google.devtools.ksp")
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation(project(":test-processor"))
+ ksp(project(":test-processor"))
+}
diff --git a/integration-tests/src/test/resources/javaNestedClass/workload/src/main/java/com/example/A.kt b/integration-tests/src/test/resources/javaNestedClass/workload/src/main/java/com/example/A.kt
new file mode 100644
index 00000000..ebf0688c
--- /dev/null
+++ b/integration-tests/src/test/resources/javaNestedClass/workload/src/main/java/com/example/A.kt
@@ -0,0 +1,4 @@
+package com.example
+
+fun main() {
+}
diff --git a/integration-tests/src/test/resources/javaNestedClass/workload/src/main/java/com/example/JavaClass.java b/integration-tests/src/test/resources/javaNestedClass/workload/src/main/java/com/example/JavaClass.java
new file mode 100644
index 00000000..2c0b0e32
--- /dev/null
+++ b/integration-tests/src/test/resources/javaNestedClass/workload/src/main/java/com/example/JavaClass.java
@@ -0,0 +1,22 @@
+package com.example;
+
+public class JavaClass {
+
+ public int b2;
+
+ public ENUM e;
+
+ public enum ENUM {
+ R,G,B
+ }
+
+ void inject(InjectionTarget t) {}
+
+ class InjectionTarget {}
+
+ static final class NestedClass {
+ static String provideString() {
+ return "str";
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/kmp/annotations/build.gradle.kts b/integration-tests/src/test/resources/kmp/annotations/build.gradle.kts
new file mode 100644
index 00000000..f02ad073
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/annotations/build.gradle.kts
@@ -0,0 +1,32 @@
+plugins {
+ kotlin("multiplatform")
+ id("com.google.devtools.ksp")
+}
+
+version = "1.0-SNAPSHOT"
+
+kotlin {
+ jvm {
+ }
+ js(BOTH) {
+ browser()
+ nodejs()
+ }
+ linuxX64() {
+ }
+ androidNativeX64() {
+ }
+ androidNativeArm64() {
+ }
+ // TODO: Enable after CI's Xcode version catches up.
+ // iosArm64()
+ // macosX64()
+ mingwX64()
+ sourceSets {
+ val commonMain by getting
+ }
+}
+
+tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
+ kotlinOptions.freeCompilerArgs += "-Xuse-deprecated-legacy-compiler"
+}
diff --git a/integration-tests/src/test/resources/kmp/annotations/src/commonMain/kotlin/com/example/MyAnnotation.kt b/integration-tests/src/test/resources/kmp/annotations/src/commonMain/kotlin/com/example/MyAnnotation.kt
new file mode 100644
index 00000000..b938f1c1
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/annotations/src/commonMain/kotlin/com/example/MyAnnotation.kt
@@ -0,0 +1,3 @@
+package com.example
+
+annotation class MyAnnotation
diff --git a/integration-tests/src/test/resources/kmp/build.gradle.kts b/integration-tests/src/test/resources/kmp/build.gradle.kts
new file mode 100644
index 00000000..8dd65667
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/build.gradle.kts
@@ -0,0 +1,12 @@
+plugins {
+ kotlin("multiplatform") apply false
+}
+
+val testRepo: String by project
+allprojects {
+ repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
diff --git a/integration-tests/src/test/resources/kmp/gradle.properties b/integration-tests/src/test/resources/kmp/gradle.properties
new file mode 100644
index 00000000..4a9594ae
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/gradle.properties
@@ -0,0 +1 @@
+org.gradle.jvmargs=-Xmx2048M \ No newline at end of file
diff --git a/integration-tests/src/test/resources/kmp/settings.gradle.kts b/integration-tests/src/test/resources/kmp/settings.gradle.kts
new file mode 100644
index 00000000..651619e4
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/settings.gradle.kts
@@ -0,0 +1,24 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion apply false
+ kotlin("multiplatform") version kotlinVersion apply false
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "playground"
+
+include(":annotations")
+include(":workload")
+include(":workload-jvm")
+include(":workload-js")
+include(":workload-linuxX64")
+include(":workload-androidNative")
+include(":test-processor")
diff --git a/integration-tests/src/test/resources/kmp/test-processor/build.gradle.kts b/integration-tests/src/test/resources/kmp/test-processor/build.gradle.kts
new file mode 100644
index 00000000..842898f6
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/test-processor/build.gradle.kts
@@ -0,0 +1,22 @@
+val kspVersion: String by project
+
+plugins {
+ kotlin("multiplatform")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+kotlin {
+ jvm()
+ sourceSets {
+ val jvmMain by getting {
+ dependencies {
+ implementation("com.squareup:javapoet:1.12.1")
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+ }
+ kotlin.srcDir("src/main/kotlin")
+ resources.srcDir("src/main/resources")
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/kmp/test-processor/src/main/kotlin/ErrorProcessor.kt b/integration-tests/src/test/resources/kmp/test-processor/src/main/kotlin/ErrorProcessor.kt
new file mode 100644
index 00000000..a702c7bc
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/test-processor/src/main/kotlin/ErrorProcessor.kt
@@ -0,0 +1,61 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import java.io.OutputStream
+
+class ErrorProcessor : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+ lateinit var logger: KSPLogger
+ lateinit var file: OutputStream
+ lateinit var exception: String
+
+ fun init(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger
+ ) {
+ exception = if (options.containsKey("exception")) {
+ options["exception"]!!
+ } else {
+ ""
+ }
+ if (exception == "init") {
+ throw Exception("Test Exception in init")
+ }
+ this.logger = logger
+ this.codeGenerator = codeGenerator
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ if (exception == "createTwice") {
+ codeGenerator.createNewFile(Dependencies.ALL_FILES, "create", "Twice").write("".toByteArray())
+ return emptyList()
+ }
+ if (exception == "process") {
+ throw Exception("Test Exception in process")
+ }
+ return emptyList()
+ }
+
+ override fun finish() {
+ if (exception == "finish") {
+ throw Exception("Test Exception in finish")
+ }
+ }
+
+ override fun onError() {
+ if (exception == "error") {
+ throw Exception("Test Exception in error")
+ }
+ }
+}
+
+class ErrorProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return ErrorProcessor().apply {
+ init(env.options, env.kotlinVersion, env.codeGenerator, env.logger)
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/kmp/test-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/kmp/test-processor/src/main/kotlin/TestProcessor.kt
new file mode 100644
index 00000000..283d50f1
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/test-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,74 @@
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+import java.io.OutputStreamWriter
+
+class TestProcessor(
+ val codeGenerator: CodeGenerator,
+ val logger: KSPLogger,
+ val env: SymbolProcessorEnvironment
+) : SymbolProcessor {
+ var invoked = false
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val allFiles = resolver.getAllFiles().map { it.fileName }
+ logger.warn(allFiles.toList().toString())
+ if (invoked) {
+ return emptyList()
+ }
+ invoked = true
+
+ logger.warn("language version: ${env.kotlinVersion}")
+ logger.warn("api version: ${env.apiVersion}")
+ logger.warn("compiler version: ${env.compilerVersion}")
+ val platforms = env.platforms.map { it.toString() }
+ logger.warn("platforms: $platforms")
+ val list = resolver.getClassDeclarationByName("kotlin.collections.List")
+ logger.warn("List has superTypes: ${list!!.superTypes.count() > 0}")
+
+ codeGenerator.createNewFile(Dependencies(false), "", "Foo", "kt").use { output ->
+ OutputStreamWriter(output).use { writer ->
+ writer.write("package com.example\n\n")
+ writer.write("class Foo {\n")
+
+ val visitor = ClassVisitor()
+ resolver.getAllFiles().forEach {
+ it.accept(visitor, writer)
+ }
+
+ writer.write("}\n")
+ }
+ }
+
+ allFiles.forEach {
+ val fn = it.replace(".", "_dot_")
+ codeGenerator.createNewFile(Dependencies(false), "", fn, "kt").use { output ->
+ OutputStreamWriter(output).use { writer ->
+ writer.write("// empty\n")
+ }
+ }
+ }
+ return emptyList()
+ }
+}
+
+class ClassVisitor : KSTopDownVisitor<OutputStreamWriter, Unit>() {
+ override fun defaultHandler(node: KSNode, data: OutputStreamWriter) {
+ }
+
+ override fun visitClassDeclaration(
+ classDeclaration: KSClassDeclaration,
+ data: OutputStreamWriter
+ ) {
+ super.visitClassDeclaration(classDeclaration, data)
+ val symbolName = classDeclaration.simpleName.asString().toLowerCase()
+ data.write(" val $symbolName = true\n")
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(env: SymbolProcessorEnvironment): SymbolProcessor {
+ return TestProcessor(env.codeGenerator, env.logger, env)
+ }
+}
diff --git a/integration-tests/src/test/resources/kmp/test-processor/src/main/kotlin/ValidateProcessor.kt b/integration-tests/src/test/resources/kmp/test-processor/src/main/kotlin/ValidateProcessor.kt
new file mode 100644
index 00000000..45dbe22b
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/test-processor/src/main/kotlin/ValidateProcessor.kt
@@ -0,0 +1,29 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.validate
+
+class ValidateProcessor(val codeGenerator: CodeGenerator, val logger: KSPLogger) : SymbolProcessor {
+ var invoked = false
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ if (invoked) {
+ return emptyList()
+ }
+ invoked = true
+
+ val toValidate = resolver.getSymbolsWithAnnotation("com.example.MyAnnotation")
+ if (toValidate.firstOrNull() == null || !toValidate.all { it.validate() }) {
+ logger.error("$toValidate.validate(): not ok")
+ }
+ if ((toValidate as? KSClassDeclaration)?.asStarProjectedType()?.isError == true) {
+ logger.error("$toValidate.asStarProjectedType(): not ok")
+ }
+ return emptyList()
+ }
+}
+
+class ValidateProcessorProvider : SymbolProcessorProvider {
+ override fun create(env: SymbolProcessorEnvironment): SymbolProcessor {
+ return ValidateProcessor(env.codeGenerator, env.logger)
+ }
+}
diff --git a/integration-tests/src/test/resources/kmp/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/kmp/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..b688ee02
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1,3 @@
+TestProcessorProvider
+ValidateProcessorProvider
+ErrorProcessorProvider
diff --git a/integration-tests/src/test/resources/kmp/workload-androidNative/build.gradle.kts b/integration-tests/src/test/resources/kmp/workload-androidNative/build.gradle.kts
new file mode 100644
index 00000000..ebf66a8e
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-androidNative/build.gradle.kts
@@ -0,0 +1,41 @@
+plugins {
+ kotlin("multiplatform")
+ id("com.google.devtools.ksp")
+}
+
+version = "1.0-SNAPSHOT"
+
+kotlin {
+ jvm {
+ withJava()
+ }
+ androidNativeX64() {
+ binaries {
+ executable()
+ }
+ }
+ androidNativeArm64() {
+ binaries {
+ executable()
+ }
+ }
+ sourceSets {
+ val commonMain by getting {
+ dependencies {
+ implementation(project(":annotations"))
+ }
+ }
+ val androidNativeX64Main by getting
+ val androidNativeArm64Main by getting
+ }
+}
+
+dependencies {
+ add("kspCommonMainMetadata", project(":test-processor"))
+ add("kspJvm", project(":test-processor"))
+ add("kspJvmTest", project(":test-processor"))
+ add("kspAndroidNativeX64", project(":test-processor"))
+ add("kspAndroidNativeX64Test", project(":test-processor"))
+ add("kspAndroidNativeArm64", project(":test-processor"))
+ add("kspAndroidNativeArm64Test", project(":test-processor"))
+}
diff --git a/integration-tests/src/test/resources/kmp/workload-androidNative/src/androidNativeArm64Main/kotlin/Main.kt b/integration-tests/src/test/resources/kmp/workload-androidNative/src/androidNativeArm64Main/kotlin/Main.kt
new file mode 100644
index 00000000..bf7bfe3e
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-androidNative/src/androidNativeArm64Main/kotlin/Main.kt
@@ -0,0 +1,7 @@
+import com.example.Bar
+import com.example.Foo
+
+fun main() {
+ println(Bar().toString())
+ println(Foo().toString())
+}
diff --git a/integration-tests/src/test/resources/kmp/workload-androidNative/src/androidNativeX64Main/kotlin/Main.kt b/integration-tests/src/test/resources/kmp/workload-androidNative/src/androidNativeX64Main/kotlin/Main.kt
new file mode 100644
index 00000000..bf7bfe3e
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-androidNative/src/androidNativeX64Main/kotlin/Main.kt
@@ -0,0 +1,7 @@
+import com.example.Bar
+import com.example.Foo
+
+fun main() {
+ println(Bar().toString())
+ println(Foo().toString())
+}
diff --git a/integration-tests/src/test/resources/kmp/workload-androidNative/src/commonMain/kotlin/com/example/Bar.kt b/integration-tests/src/test/resources/kmp/workload-androidNative/src/commonMain/kotlin/com/example/Bar.kt
new file mode 100644
index 00000000..480d3cb2
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-androidNative/src/commonMain/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-androidNative/src/commonMain/kotlin/com/example/Baz.kt b/integration-tests/src/test/resources/kmp/workload-androidNative/src/commonMain/kotlin/com/example/Baz.kt
new file mode 100644
index 00000000..83015598
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-androidNative/src/commonMain/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-androidNative/src/commonMain/kotlin/com/example/ToBeValidated.kt b/integration-tests/src/test/resources/kmp/workload-androidNative/src/commonMain/kotlin/com/example/ToBeValidated.kt
new file mode 100644
index 00000000..05497afb
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-androidNative/src/commonMain/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-js/build.gradle.kts b/integration-tests/src/test/resources/kmp/workload-js/build.gradle.kts
new file mode 100644
index 00000000..d94bf9eb
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-js/build.gradle.kts
@@ -0,0 +1,30 @@
+plugins {
+ kotlin("multiplatform")
+ id("com.google.devtools.ksp")
+}
+
+version = "1.0-SNAPSHOT"
+
+kotlin {
+ js(BOTH) {
+ browser()
+ nodejs()
+ }
+ sourceSets {
+ val commonMain by getting {
+ dependencies {
+ implementation(project(":annotations"))
+ }
+ }
+ }
+}
+
+dependencies {
+ add("kspCommonMainMetadata", project(":test-processor"))
+ add("kspJs", project(":test-processor"))
+ add("kspJsTest", project(":test-processor"))
+}
+
+tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
+ kotlinOptions.freeCompilerArgs += "-Xuse-deprecated-legacy-compiler"
+}
diff --git a/integration-tests/src/test/resources/kmp/workload-js/src/commonMain/kotlin/com/example/Bar.kt b/integration-tests/src/test/resources/kmp/workload-js/src/commonMain/kotlin/com/example/Bar.kt
new file mode 100644
index 00000000..480d3cb2
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-js/src/commonMain/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-js/src/commonMain/kotlin/com/example/Baz.kt b/integration-tests/src/test/resources/kmp/workload-js/src/commonMain/kotlin/com/example/Baz.kt
new file mode 100644
index 00000000..83015598
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-js/src/commonMain/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-js/src/commonMain/kotlin/com/example/ToBeValidated.kt b/integration-tests/src/test/resources/kmp/workload-js/src/commonMain/kotlin/com/example/ToBeValidated.kt
new file mode 100644
index 00000000..05497afb
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-js/src/commonMain/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-jvm/build.gradle.kts b/integration-tests/src/test/resources/kmp/workload-jvm/build.gradle.kts
new file mode 100644
index 00000000..f61b2569
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-jvm/build.gradle.kts
@@ -0,0 +1,25 @@
+plugins {
+ kotlin("multiplatform")
+ id("com.google.devtools.ksp")
+}
+
+version = "1.0-SNAPSHOT"
+
+kotlin {
+ jvm {
+ withJava()
+ }
+ sourceSets {
+ val commonMain by getting {
+ dependencies {
+ implementation(project(":annotations"))
+ }
+ }
+ }
+}
+
+dependencies {
+ add("kspCommonMainMetadata", project(":test-processor"))
+ add("kspJvm", project(":test-processor"))
+ add("kspJvmTest", project(":test-processor"))
+}
diff --git a/integration-tests/src/test/resources/kmp/workload-jvm/src/commonMain/kotlin/com/example/Bar.kt b/integration-tests/src/test/resources/kmp/workload-jvm/src/commonMain/kotlin/com/example/Bar.kt
new file mode 100644
index 00000000..480d3cb2
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-jvm/src/commonMain/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-jvm/src/commonMain/kotlin/com/example/Baz.kt b/integration-tests/src/test/resources/kmp/workload-jvm/src/commonMain/kotlin/com/example/Baz.kt
new file mode 100644
index 00000000..83015598
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-jvm/src/commonMain/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-jvm/src/commonMain/kotlin/com/example/ToBeValidated.kt b/integration-tests/src/test/resources/kmp/workload-jvm/src/commonMain/kotlin/com/example/ToBeValidated.kt
new file mode 100644
index 00000000..05497afb
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-jvm/src/commonMain/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-linuxX64/build.gradle.kts b/integration-tests/src/test/resources/kmp/workload-linuxX64/build.gradle.kts
new file mode 100644
index 00000000..c9ff2f5d
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-linuxX64/build.gradle.kts
@@ -0,0 +1,40 @@
+plugins {
+ kotlin("multiplatform")
+ id("com.google.devtools.ksp")
+}
+
+version = "1.0-SNAPSHOT"
+
+kotlin {
+ jvm {
+ withJava()
+ }
+ linuxX64() {
+ binaries {
+ executable()
+ }
+ }
+ // TODO: Enable after CI's Xcode version catches up.
+ // iosArm64()
+ // macosX64()
+ mingwX64()
+ sourceSets {
+ val commonMain by getting {
+ dependencies {
+ implementation(project(":annotations"))
+ }
+ }
+ val linuxX64Main by getting
+ val linuxX64Test by getting
+ }
+}
+
+dependencies {
+ add("kspCommonMainMetadata", project(":test-processor"))
+ add("kspJvm", project(":test-processor"))
+ add("kspJvmTest", project(":test-processor"))
+ add("kspLinuxX64", project(":test-processor"))
+ add("kspLinuxX64Test", project(":test-processor"))
+ add("kspMingwX64", project(":test-processor"))
+ add("kspMingwX64Test", project(":test-processor"))
+}
diff --git a/integration-tests/src/test/resources/kmp/workload-linuxX64/src/commonMain/kotlin/com/example/Bar.kt b/integration-tests/src/test/resources/kmp/workload-linuxX64/src/commonMain/kotlin/com/example/Bar.kt
new file mode 100644
index 00000000..480d3cb2
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-linuxX64/src/commonMain/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-linuxX64/src/commonMain/kotlin/com/example/Baz.kt b/integration-tests/src/test/resources/kmp/workload-linuxX64/src/commonMain/kotlin/com/example/Baz.kt
new file mode 100644
index 00000000..83015598
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-linuxX64/src/commonMain/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-linuxX64/src/commonMain/kotlin/com/example/ToBeValidated.kt b/integration-tests/src/test/resources/kmp/workload-linuxX64/src/commonMain/kotlin/com/example/ToBeValidated.kt
new file mode 100644
index 00000000..05497afb
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-linuxX64/src/commonMain/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-linuxX64/src/linuxX64Main/kotlin/Main.kt b/integration-tests/src/test/resources/kmp/workload-linuxX64/src/linuxX64Main/kotlin/Main.kt
new file mode 100644
index 00000000..bf7bfe3e
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-linuxX64/src/linuxX64Main/kotlin/Main.kt
@@ -0,0 +1,7 @@
+import com.example.Bar
+import com.example.Foo
+
+fun main() {
+ println(Bar().toString())
+ println(Foo().toString())
+}
diff --git a/integration-tests/src/test/resources/kmp/workload-linuxX64/src/linuxX64Main/kotlin/ToBeRemoved.kt b/integration-tests/src/test/resources/kmp/workload-linuxX64/src/linuxX64Main/kotlin/ToBeRemoved.kt
new file mode 100644
index 00000000..56063711
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-linuxX64/src/linuxX64Main/kotlin/ToBeRemoved.kt
@@ -0,0 +1 @@
+class ToBeRemoved
diff --git a/integration-tests/src/test/resources/kmp/workload-linuxX64/src/linuxX64Test/kotlin/MyTest.kt b/integration-tests/src/test/resources/kmp/workload-linuxX64/src/linuxX64Test/kotlin/MyTest.kt
new file mode 100644
index 00000000..836f9f2b
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload-linuxX64/src/linuxX64Test/kotlin/MyTest.kt
@@ -0,0 +1,3 @@
+@com.example.MyAnnotation
+@ExperimentalMultiplatform
+class MyTest
diff --git a/integration-tests/src/test/resources/kmp/workload/build.gradle.kts b/integration-tests/src/test/resources/kmp/workload/build.gradle.kts
new file mode 100644
index 00000000..f0ba36f1
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload/build.gradle.kts
@@ -0,0 +1,66 @@
+plugins {
+ kotlin("multiplatform")
+ id("com.google.devtools.ksp")
+}
+
+version = "1.0-SNAPSHOT"
+
+kotlin {
+ jvm {
+ withJava()
+ }
+ js(BOTH) {
+ browser()
+ nodejs()
+ }
+ linuxX64() {
+ binaries {
+ executable()
+ }
+ }
+ androidNativeX64() {
+ binaries {
+ executable()
+ }
+ }
+ androidNativeArm64() {
+ binaries {
+ executable()
+ }
+ }
+ // TODO: Enable after CI's Xcode version catches up.
+ // iosArm64()
+ // macosX64()
+ mingwX64()
+ sourceSets {
+ val commonMain by getting {
+ dependencies {
+ implementation(project(":annotations"))
+ }
+ }
+ val linuxX64Main by getting
+ val linuxX64Test by getting
+ val androidNativeX64Main by getting
+ val androidNativeArm64Main by getting
+ }
+}
+
+tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
+ kotlinOptions.freeCompilerArgs += "-Xuse-deprecated-legacy-compiler"
+}
+
+dependencies {
+ add("kspCommonMainMetadata", project(":test-processor"))
+ add("kspJvm", project(":test-processor"))
+ add("kspJvmTest", project(":test-processor"))
+ add("kspJs", project(":test-processor"))
+ add("kspJsTest", project(":test-processor"))
+ add("kspAndroidNativeX64", project(":test-processor"))
+ add("kspAndroidNativeX64Test", project(":test-processor"))
+ add("kspAndroidNativeArm64", project(":test-processor"))
+ add("kspAndroidNativeArm64Test", project(":test-processor"))
+ add("kspLinuxX64", project(":test-processor"))
+ add("kspLinuxX64Test", project(":test-processor"))
+ add("kspMingwX64", project(":test-processor"))
+ add("kspMingwX64Test", project(":test-processor"))
+}
diff --git a/integration-tests/src/test/resources/kmp/workload/src/androidNativeArm64Main/kotlin/Main.kt b/integration-tests/src/test/resources/kmp/workload/src/androidNativeArm64Main/kotlin/Main.kt
new file mode 100644
index 00000000..bf7bfe3e
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload/src/androidNativeArm64Main/kotlin/Main.kt
@@ -0,0 +1,7 @@
+import com.example.Bar
+import com.example.Foo
+
+fun main() {
+ println(Bar().toString())
+ println(Foo().toString())
+}
diff --git a/integration-tests/src/test/resources/kmp/workload/src/androidNativeX64Main/kotlin/Main.kt b/integration-tests/src/test/resources/kmp/workload/src/androidNativeX64Main/kotlin/Main.kt
new file mode 100644
index 00000000..bf7bfe3e
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload/src/androidNativeX64Main/kotlin/Main.kt
@@ -0,0 +1,7 @@
+import com.example.Bar
+import com.example.Foo
+
+fun main() {
+ println(Bar().toString())
+ println(Foo().toString())
+}
diff --git a/integration-tests/src/test/resources/kmp/workload/src/commonMain/kotlin/com/example/Bar.kt b/integration-tests/src/test/resources/kmp/workload/src/commonMain/kotlin/com/example/Bar.kt
new file mode 100644
index 00000000..480d3cb2
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload/src/commonMain/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/src/commonMain/kotlin/com/example/Baz.kt b/integration-tests/src/test/resources/kmp/workload/src/commonMain/kotlin/com/example/Baz.kt
new file mode 100644
index 00000000..83015598
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload/src/commonMain/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/src/commonMain/kotlin/com/example/ToBeValidated.kt b/integration-tests/src/test/resources/kmp/workload/src/commonMain/kotlin/com/example/ToBeValidated.kt
new file mode 100644
index 00000000..05497afb
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload/src/commonMain/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/src/linuxX64Main/kotlin/Main.kt b/integration-tests/src/test/resources/kmp/workload/src/linuxX64Main/kotlin/Main.kt
new file mode 100644
index 00000000..bf7bfe3e
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload/src/linuxX64Main/kotlin/Main.kt
@@ -0,0 +1,7 @@
+import com.example.Bar
+import com.example.Foo
+
+fun main() {
+ println(Bar().toString())
+ println(Foo().toString())
+}
diff --git a/integration-tests/src/test/resources/kmp/workload/src/linuxX64Test/kotlin/MyTest.kt b/integration-tests/src/test/resources/kmp/workload/src/linuxX64Test/kotlin/MyTest.kt
new file mode 100644
index 00000000..836f9f2b
--- /dev/null
+++ b/integration-tests/src/test/resources/kmp/workload/src/linuxX64Test/kotlin/MyTest.kt
@@ -0,0 +1,3 @@
+@com.example.MyAnnotation
+@ExperimentalMultiplatform
+class MyTest
diff --git a/integration-tests/src/test/resources/kotlin-consts-in-java/build.gradle.kts b/integration-tests/src/test/resources/kotlin-consts-in-java/build.gradle.kts
new file mode 100644
index 00000000..c5737a2e
--- /dev/null
+++ b/integration-tests/src/test/resources/kotlin-consts-in-java/build.gradle.kts
@@ -0,0 +1,8 @@
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
diff --git a/integration-tests/src/test/resources/kotlin-consts-in-java/settings.gradle.kts b/integration-tests/src/test/resources/kotlin-consts-in-java/settings.gradle.kts
new file mode 100644
index 00000000..9d60cbc7
--- /dev/null
+++ b/integration-tests/src/test/resources/kotlin-consts-in-java/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "playground"
+
+include(":workload")
+include(":test-processor")
diff --git a/integration-tests/src/test/resources/kotlin-consts-in-java/test-processor/build.gradle.kts b/integration-tests/src/test/resources/kotlin-consts-in-java/test-processor/build.gradle.kts
new file mode 100644
index 00000000..ab249cf0
--- /dev/null
+++ b/integration-tests/src/test/resources/kotlin-consts-in-java/test-processor/build.gradle.kts
@@ -0,0 +1,24 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
diff --git a/integration-tests/src/test/resources/kotlin-consts-in-java/test-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/kotlin-consts-in-java/test-processor/src/main/kotlin/TestProcessor.kt
new file mode 100644
index 00000000..7e141927
--- /dev/null
+++ b/integration-tests/src/test/resources/kotlin-consts-in-java/test-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,27 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+
+class TestProcessor(
+ private val codeGenerator: CodeGenerator,
+ private val options: Map<String, String>,
+ private val logger: KSPLogger
+) : SymbolProcessor {
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver
+ .getSymbolsWithAnnotation("com.example.ann.MyAnn")
+ .filterIsInstance<KSFunctionDeclaration>()
+ .forEach { func ->
+ val arg = func.annotations.first().arguments.first().value.toString()
+ if (!arg.startsWith("REPLACE"))
+ throw IllegalStateException(arg)
+ }
+
+ return emptyList()
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor =
+ TestProcessor(environment.codeGenerator, environment.options, environment.logger)
+}
diff --git a/integration-tests/src/test/resources/kotlin-consts-in-java/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/kotlin-consts-in-java/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..c91e3e9e
--- /dev/null
+++ b/integration-tests/src/test/resources/kotlin-consts-in-java/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+TestProcessorProvider
diff --git a/integration-tests/src/test/resources/kotlin-consts-in-java/workload/build.gradle.kts b/integration-tests/src/test/resources/kotlin-consts-in-java/workload/build.gradle.kts
new file mode 100644
index 00000000..f0ea52b0
--- /dev/null
+++ b/integration-tests/src/test/resources/kotlin-consts-in-java/workload/build.gradle.kts
@@ -0,0 +1,20 @@
+val testRepo: String by project
+
+plugins {
+ id("com.google.devtools.ksp")
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation(project(":test-processor"))
+ ksp(project(":test-processor"))
+}
diff --git a/integration-tests/src/test/resources/kotlin-consts-in-java/workload/src/main/java/com/example/JavaClass.java b/integration-tests/src/test/resources/kotlin-consts-in-java/workload/src/main/java/com/example/JavaClass.java
new file mode 100644
index 00000000..a196f754
--- /dev/null
+++ b/integration-tests/src/test/resources/kotlin-consts-in-java/workload/src/main/java/com/example/JavaClass.java
@@ -0,0 +1,9 @@
+package com.example;
+
+import com.example.ann.MyAnn;
+
+public class JavaClass {
+ @MyAnn(KotlinConsts.ACTION)
+ public void f() {
+ }
+}
diff --git a/integration-tests/src/test/resources/kotlin-consts-in-java/workload/src/main/java/com/example/KotlinConsts.kt b/integration-tests/src/test/resources/kotlin-consts-in-java/workload/src/main/java/com/example/KotlinConsts.kt
new file mode 100644
index 00000000..e5231980
--- /dev/null
+++ b/integration-tests/src/test/resources/kotlin-consts-in-java/workload/src/main/java/com/example/KotlinConsts.kt
@@ -0,0 +1,8 @@
+package com.example
+
+class KotlinConsts {
+ companion object {
+ const val ACTION = "REPLACE"
+ const val ACTION2 = "REPLACE"
+ }
+}
diff --git a/integration-tests/src/test/resources/kotlin-consts-in-java/workload/src/main/java/com/example/ann/MyAnn.kt b/integration-tests/src/test/resources/kotlin-consts-in-java/workload/src/main/java/com/example/ann/MyAnn.kt
new file mode 100644
index 00000000..6812ee63
--- /dev/null
+++ b/integration-tests/src/test/resources/kotlin-consts-in-java/workload/src/main/java/com/example/ann/MyAnn.kt
@@ -0,0 +1,3 @@
+package com.example.ann
+
+annotation class MyAnn(val value: String)
diff --git a/integration-tests/src/test/resources/map-annotation-arguments/test-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/map-annotation-arguments/test-processor/src/main/kotlin/TestProcessor.kt
new file mode 100644
index 00000000..7892f012
--- /dev/null
+++ b/integration-tests/src/test/resources/map-annotation-arguments/test-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,36 @@
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+
+class TestProcessor(
+ val codeGenerator: CodeGenerator,
+ val logger: KSPLogger
+) : SymbolProcessor {
+ val expected = mapOf(
+ "unboxedChar" to "Char",
+ "boxedChar" to "(Char..Char?)",
+ )
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val j = resolver.getClassDeclarationByName("com.example.AnnotationTest")!!
+ j.annotations.forEach { annotation ->
+ annotation.arguments.forEach {
+ val key = it.name?.asString()
+ val value = it.value.toString()
+ if (expected[key] != value) {
+ logger.error("$key: ${expected[key]} != $value")
+ }
+ }
+ }
+
+ return emptyList()
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ environment: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return TestProcessor(environment.codeGenerator, environment.logger)
+ }
+}
diff --git a/integration-tests/src/test/resources/map-annotation-arguments/workload/src/main/java/com/example/AnnotationTest.java b/integration-tests/src/test/resources/map-annotation-arguments/workload/src/main/java/com/example/AnnotationTest.java
new file mode 100644
index 00000000..18696806
--- /dev/null
+++ b/integration-tests/src/test/resources/map-annotation-arguments/workload/src/main/java/com/example/AnnotationTest.java
@@ -0,0 +1,8 @@
+package com.example;
+
+@JavaAnnotation(
+ unboxedChar = char.class,
+ boxedChar = Character.class
+)
+public class AnnotationTest {
+}
diff --git a/integration-tests/src/test/resources/map-annotation-arguments/workload/src/main/java/com/example/JavaAnnotation.java b/integration-tests/src/test/resources/map-annotation-arguments/workload/src/main/java/com/example/JavaAnnotation.java
new file mode 100644
index 00000000..c7c8368f
--- /dev/null
+++ b/integration-tests/src/test/resources/map-annotation-arguments/workload/src/main/java/com/example/JavaAnnotation.java
@@ -0,0 +1,6 @@
+package com.example;
+
+public @interface JavaAnnotation {
+ Class unboxedChar();
+ Class boxedChar();
+} \ No newline at end of file
diff --git a/integration-tests/src/test/resources/on-error/build.gradle.kts b/integration-tests/src/test/resources/on-error/build.gradle.kts
new file mode 100644
index 00000000..c5737a2e
--- /dev/null
+++ b/integration-tests/src/test/resources/on-error/build.gradle.kts
@@ -0,0 +1,8 @@
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
diff --git a/integration-tests/src/test/resources/on-error/on-error-processor/build.gradle.kts b/integration-tests/src/test/resources/on-error/on-error-processor/build.gradle.kts
new file mode 100644
index 00000000..999cb80a
--- /dev/null
+++ b/integration-tests/src/test/resources/on-error/on-error-processor/build.gradle.kts
@@ -0,0 +1,23 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
diff --git a/integration-tests/src/test/resources/on-error/on-error-processor/src/main/kotlin/ErrorProcessor.kt b/integration-tests/src/test/resources/on-error/on-error-processor/src/main/kotlin/ErrorProcessor.kt
new file mode 100644
index 00000000..976019bf
--- /dev/null
+++ b/integration-tests/src/test/resources/on-error/on-error-processor/src/main/kotlin/ErrorProcessor.kt
@@ -0,0 +1,70 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import java.io.OutputStream
+
+class ErrorProcessor : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+ lateinit var logger: KSPLogger
+ lateinit var file: OutputStream
+ var rounds = 0
+ lateinit var exception: String
+
+ fun init(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger
+ ) {
+ exception = if (options.containsKey("exception")) {
+ options["exception"]!!
+ } else {
+ ""
+ }
+ if (exception == "init") {
+ throw Exception("Test Exception in init")
+ }
+ this.logger = logger
+ this.codeGenerator = codeGenerator
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ if (exception == "createTwice") {
+ codeGenerator.createNewFile(Dependencies.ALL_FILES, "create", "Twice").write("".toByteArray())
+ return emptyList()
+ }
+ if (exception == "process") {
+ throw Exception("Test Exception in process")
+ }
+ rounds++
+ if (rounds == 2) {
+ if (exception == "" || exception == "error") {
+ logger.error("Error processor: errored at $rounds")
+ }
+ } else {
+ codeGenerator.createNewFile(Dependencies.ALL_FILES, "test", "error", "log")
+ }
+ return emptyList()
+ }
+
+ override fun finish() {
+ if (exception == "finish") {
+ throw Exception("Test Exception in finish")
+ }
+ }
+
+ override fun onError() {
+ if (exception == "error") {
+ throw Exception("Test Exception in error")
+ }
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return ErrorProcessor().apply {
+ init(env.options, env.kotlinVersion, env.codeGenerator, env.logger)
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/on-error/on-error-processor/src/main/kotlin/NormalProcessor.kt b/integration-tests/src/test/resources/on-error/on-error-processor/src/main/kotlin/NormalProcessor.kt
new file mode 100644
index 00000000..c751c582
--- /dev/null
+++ b/integration-tests/src/test/resources/on-error/on-error-processor/src/main/kotlin/NormalProcessor.kt
@@ -0,0 +1,40 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+
+class NormalProcessor : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+ lateinit var logger: KSPLogger
+ var rounds = 0
+
+ override fun onError() {
+ logger.error("NormalProcessor called error on $rounds")
+ }
+
+ fun init(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger
+ ) {
+ this.logger = logger
+ this.codeGenerator = codeGenerator
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ rounds++
+ if (rounds == 1) {
+ codeGenerator.createNewFile(Dependencies.ALL_FILES, "test", "normal", "log")
+ }
+ return emptyList()
+ }
+}
+
+class TestProcessorProvider2 : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return NormalProcessor().apply {
+ init(env.options, env.kotlinVersion, env.codeGenerator, env.logger)
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/on-error/on-error-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/on-error/on-error-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..3a1528c9
--- /dev/null
+++ b/integration-tests/src/test/resources/on-error/on-error-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1,2 @@
+TestProcessorProvider
+TestProcessorProvider2
diff --git a/integration-tests/src/test/resources/on-error/settings.gradle.kts b/integration-tests/src/test/resources/on-error/settings.gradle.kts
new file mode 100644
index 00000000..cff61bf9
--- /dev/null
+++ b/integration-tests/src/test/resources/on-error/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ val kspVersion: String by settings
+ val kotlinVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "on-error"
+
+include(":workload")
+include(":on-error-processor")
diff --git a/integration-tests/src/test/resources/on-error/workload/build.gradle.kts b/integration-tests/src/test/resources/on-error/workload/build.gradle.kts
new file mode 100644
index 00000000..015259a8
--- /dev/null
+++ b/integration-tests/src/test/resources/on-error/workload/build.gradle.kts
@@ -0,0 +1,23 @@
+val testRepo: String by project
+
+plugins {
+ id("com.google.devtools.ksp")
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ ksp(project(":on-error-processor"))
+}
+
+tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
+ kotlinOptions.freeCompilerArgs += "-opt-in=MyOptIn"
+}
diff --git a/integration-tests/src/test/resources/on-error/workload/src/main/kotlin/com/example/A.kt b/integration-tests/src/test/resources/on-error/workload/src/main/kotlin/com/example/A.kt
new file mode 100644
index 00000000..4752447c
--- /dev/null
+++ b/integration-tests/src/test/resources/on-error/workload/src/main/kotlin/com/example/A.kt
@@ -0,0 +1,11 @@
+package com.example
+
+@RequiresOptIn
+@Retention(AnnotationRetention.BINARY)
+@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
+annotation class MyOptIn
+
+@OptIn(MyOptIn::class)
+fun main() {
+ print("hello world")
+}
diff --git a/integration-tests/src/test/resources/only-resources-file/build.gradle.kts b/integration-tests/src/test/resources/only-resources-file/build.gradle.kts
new file mode 100644
index 00000000..7a1ba5b1
--- /dev/null
+++ b/integration-tests/src/test/resources/only-resources-file/build.gradle.kts
@@ -0,0 +1,12 @@
+plugins {
+ kotlin("multiplatform") apply false
+}
+
+val testRepo: String by project
+subprojects {
+ repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
diff --git a/integration-tests/src/test/resources/only-resources-file/settings.gradle.kts b/integration-tests/src/test/resources/only-resources-file/settings.gradle.kts
new file mode 100644
index 00000000..49845b92
--- /dev/null
+++ b/integration-tests/src/test/resources/only-resources-file/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion apply false
+ kotlin("multiplatform") version kotlinVersion apply false
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "playground"
+
+include(":workload")
+include(":test-processor")
diff --git a/integration-tests/src/test/resources/only-resources-file/test-processor/build.gradle.kts b/integration-tests/src/test/resources/only-resources-file/test-processor/build.gradle.kts
new file mode 100644
index 00000000..1d1cb300
--- /dev/null
+++ b/integration-tests/src/test/resources/only-resources-file/test-processor/build.gradle.kts
@@ -0,0 +1,12 @@
+val kspVersion: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+dependencies {
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
diff --git a/integration-tests/src/test/resources/only-resources-file/test-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/only-resources-file/test-processor/src/main/kotlin/TestProcessor.kt
new file mode 100644
index 00000000..6d07416b
--- /dev/null
+++ b/integration-tests/src/test/resources/only-resources-file/test-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,24 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+
+class TestProcessor(val codeGenerator: CodeGenerator) : SymbolProcessor {
+
+ var invoked = false
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ if (invoked) {
+ return emptyList()
+ }
+
+ codeGenerator.createNewFile(Dependencies(false), "", "HelloSwift", "swift")
+
+ invoked = true
+ return emptyList()
+ }
+
+ class Provider : SymbolProcessorProvider {
+ override fun create(
+ environment: SymbolProcessorEnvironment
+ ): SymbolProcessor = TestProcessor(environment.codeGenerator)
+ }
+}
diff --git a/integration-tests/src/test/resources/only-resources-file/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/only-resources-file/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..5c51c309
--- /dev/null
+++ b/integration-tests/src/test/resources/only-resources-file/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+TestProcessor$Provider
diff --git a/integration-tests/src/test/resources/only-resources-file/workload/build.gradle.kts b/integration-tests/src/test/resources/only-resources-file/workload/build.gradle.kts
new file mode 100644
index 00000000..ed0d40c6
--- /dev/null
+++ b/integration-tests/src/test/resources/only-resources-file/workload/build.gradle.kts
@@ -0,0 +1,16 @@
+plugins {
+ kotlin("multiplatform")
+ id("com.google.devtools.ksp")
+}
+
+version = "1.0-SNAPSHOT"
+
+kotlin {
+ jvm {
+ withJava()
+ }
+}
+
+dependencies {
+ add("kspCommonMainMetadata", project(":test-processor"))
+}
diff --git a/integration-tests/src/test/resources/only-resources-file/workload/src/commonMain/kotlin/MyStub.kt b/integration-tests/src/test/resources/only-resources-file/workload/src/commonMain/kotlin/MyStub.kt
new file mode 100644
index 00000000..f0692550
--- /dev/null
+++ b/integration-tests/src/test/resources/only-resources-file/workload/src/commonMain/kotlin/MyStub.kt
@@ -0,0 +1 @@
+class MyStub
diff --git a/integration-tests/src/test/resources/output-deps/build.gradle.kts b/integration-tests/src/test/resources/output-deps/build.gradle.kts
new file mode 100644
index 00000000..c5737a2e
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/build.gradle.kts
@@ -0,0 +1,8 @@
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
diff --git a/integration-tests/src/test/resources/output-deps/gradle.properties b/integration-tests/src/test/resources/output-deps/gradle.properties
new file mode 100644
index 00000000..f9325643
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/gradle.properties
@@ -0,0 +1,2 @@
+ksp.incremental=true
+ksp.incremental.log=true \ No newline at end of file
diff --git a/integration-tests/src/test/resources/output-deps/settings.gradle.kts b/integration-tests/src/test/resources/output-deps/settings.gradle.kts
new file mode 100644
index 00000000..668c5a87
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ val kspVersion: String by settings
+ val kotlinVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "incremental-test"
+
+include(":workload")
+include(":test-processor")
diff --git a/integration-tests/src/test/resources/output-deps/test-processor/build.gradle.kts b/integration-tests/src/test/resources/output-deps/test-processor/build.gradle.kts
new file mode 100644
index 00000000..ab249cf0
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/test-processor/build.gradle.kts
@@ -0,0 +1,24 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
diff --git a/integration-tests/src/test/resources/output-deps/test-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/output-deps/test-processor/src/main/kotlin/TestProcessor.kt
new file mode 100644
index 00000000..9e8436f9
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/test-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,61 @@
+import com.google.devtools.ksp.containingFile
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import java.io.OutputStreamWriter
+
+class TestProcessor : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+ lateinit var logger: KSPLogger
+ var processed = false
+
+ fun init(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger,
+ ) {
+ this.codeGenerator = codeGenerator
+ this.logger = logger
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ if (processed) {
+ return emptyList()
+ }
+ fun outputForAnno(anno: String) {
+ val annoFiles =
+ resolver.getSymbolsWithAnnotation(anno).map { (it as KSDeclaration).containingFile!! }.toList()
+ codeGenerator.createNewFile(Dependencies(false, *annoFiles.toTypedArray()), "", anno, "log").use { output ->
+ OutputStreamWriter(output).use { writer ->
+ writer.write(annoFiles.map { it.fileName }.joinToString(", "))
+ }
+ }
+ }
+
+ outputForAnno("p1.Anno1")
+ outputForAnno("p1.Anno2")
+
+ resolver.getNewFiles().forEach { file ->
+ logger.warn("${file.packageName.asString()}/${file.fileName}")
+ val outputBaseFN = file.fileName.replace(".kt", "Generated").replace(".java", "Generated")
+ codeGenerator.createNewFile(Dependencies(false, file), file.packageName.asString(), outputBaseFN, "kt")
+ .use { output ->
+ OutputStreamWriter(output).use { writer ->
+ writer.write("private val unused = \"unused\"")
+ }
+ }
+ }
+ processed = true
+ return emptyList()
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment,
+ ): SymbolProcessor {
+ return TestProcessor().apply {
+ init(env.options, env.kotlinVersion, env.codeGenerator, env.logger)
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/output-deps/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/output-deps/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..c91e3e9e
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+TestProcessorProvider
diff --git a/integration-tests/src/test/resources/output-deps/workload/build.gradle.kts b/integration-tests/src/test/resources/output-deps/workload/build.gradle.kts
new file mode 100644
index 00000000..f6b92cd5
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/workload/build.gradle.kts
@@ -0,0 +1,19 @@
+val testRepo: String by project
+
+plugins {
+ id("com.google.devtools.ksp")
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ ksp(project(":test-processor"))
+}
diff --git a/integration-tests/src/test/resources/output-deps/workload/src/main/java/p1/J1.java b/integration-tests/src/test/resources/output-deps/workload/src/main/java/p1/J1.java
new file mode 100644
index 00000000..e5e1bc0e
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/workload/src/main/java/p1/J1.java
@@ -0,0 +1,5 @@
+package p1;
+
+@Anno2
+public class J1 {
+}
diff --git a/integration-tests/src/test/resources/output-deps/workload/src/main/java/p1/J2.java b/integration-tests/src/test/resources/output-deps/workload/src/main/java/p1/J2.java
new file mode 100644
index 00000000..7de0687e
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/workload/src/main/java/p1/J2.java
@@ -0,0 +1,4 @@
+package p1;
+
+public class J2 {
+}
diff --git a/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/Anno1.kt b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/Anno1.kt
new file mode 100644
index 00000000..badbcbd8
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/Anno1.kt
@@ -0,0 +1,2 @@
+package p1
+annotation class Anno1
diff --git a/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/Anno2.kt b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/Anno2.kt
new file mode 100644
index 00000000..1c517717
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/Anno2.kt
@@ -0,0 +1,2 @@
+package p1
+annotation class Anno2
diff --git a/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/K1.kt b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/K1.kt
new file mode 100644
index 00000000..43301819
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/K1.kt
@@ -0,0 +1,4 @@
+package p1
+
+@Anno1
+open class K1
diff --git a/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/K2.kt b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/K2.kt
new file mode 100644
index 00000000..506ed473
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/K2.kt
@@ -0,0 +1,5 @@
+package p1
+
+@Anno1
+@Anno2
+open class K2
diff --git a/integration-tests/src/test/resources/playground-android-multi/application/build.gradle.kts b/integration-tests/src/test/resources/playground-android-multi/application/build.gradle.kts
new file mode 100644
index 00000000..4b1192e1
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android-multi/application/build.gradle.kts
@@ -0,0 +1,30 @@
+val testRepo: String by project
+
+plugins {
+ id("com.android.application")
+ kotlin("android")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation(project(":workload"))
+}
+
+android {
+ compileSdkVersion(30)
+ defaultConfig {
+ applicationId = "org.gradle.kotlin.dsl.samples.androidstudio"
+ minSdkVersion(30)
+ targetSdkVersion(30)
+ versionCode = 1
+ versionName = "1.0"
+ }
+}
diff --git a/integration-tests/src/test/resources/playground-android-multi/application/src/main/AndroidManifest.xml b/integration-tests/src/test/resources/playground-android-multi/application/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..81a4ba30
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android-multi/application/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.myapplication">
+</manifest> \ No newline at end of file
diff --git a/integration-tests/src/test/resources/playground-android-multi/application/src/main/java/com/example/application/Foo.kt b/integration-tests/src/test/resources/playground-android-multi/application/src/main/java/com/example/application/Foo.kt
new file mode 100644
index 00000000..4f164e18
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android-multi/application/src/main/java/com/example/application/Foo.kt
@@ -0,0 +1,3 @@
+package com.example.application
+
+class Foo
diff --git a/integration-tests/src/test/resources/playground-android-multi/build.gradle.kts b/integration-tests/src/test/resources/playground-android-multi/build.gradle.kts
new file mode 100644
index 00000000..e1f8d720
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android-multi/build.gradle.kts
@@ -0,0 +1,27 @@
+buildscript {
+ val testRepo: String by project
+
+ repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ google()
+ }
+}
+
+plugins {
+ id("com.android.application") apply false
+ kotlin("android") apply false
+ id("com.google.devtools.ksp") apply false
+ id("com.android.library") apply false
+}
+
+allprojects {
+ val testRepo: String by project
+ repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ google()
+ }
+}
diff --git a/integration-tests/src/test/resources/playground-android-multi/gradle.properties b/integration-tests/src/test/resources/playground-android-multi/gradle.properties
new file mode 100644
index 00000000..b3c7a033
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android-multi/gradle.properties
@@ -0,0 +1 @@
+org.gradle.jvmargs=-Xmx2048M
diff --git a/integration-tests/src/test/resources/playground-android-multi/settings.gradle.kts b/integration-tests/src/test/resources/playground-android-multi/settings.gradle.kts
new file mode 100644
index 00000000..4c6fe413
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android-multi/settings.gradle.kts
@@ -0,0 +1,26 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ val testRepo: String by settings
+ val agpVersion: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion apply false
+ kotlin("jvm") version kotlinVersion apply false
+ kotlin("android") version kotlinVersion apply false
+ id("com.android.application") version agpVersion apply false
+ id("com.android.library") version agpVersion apply false
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ google()
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "playground"
+
+include(":application")
+include(":workload")
+include(":test-processor")
diff --git a/integration-tests/src/test/resources/playground-android-multi/test-processor/build.gradle.kts b/integration-tests/src/test/resources/playground-android-multi/test-processor/build.gradle.kts
new file mode 100644
index 00000000..75c6c7c5
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android-multi/test-processor/build.gradle.kts
@@ -0,0 +1,25 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.squareup:javapoet:1.12.1")
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
diff --git a/integration-tests/src/test/resources/playground-android-multi/workload/build.gradle.kts b/integration-tests/src/test/resources/playground-android-multi/workload/build.gradle.kts
new file mode 100644
index 00000000..3897c89d
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android-multi/workload/build.gradle.kts
@@ -0,0 +1,35 @@
+val testRepo: String by project
+
+plugins {
+ // DO NOT CHANGE THE ORDER.
+ id("com.google.devtools.ksp")
+ id("com.android.library")
+ kotlin("android")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation(project(":test-processor"))
+ ksp(project(":test-processor"))
+}
+
+android {
+ compileSdkVersion(30)
+ defaultConfig {
+ minSdkVersion(30)
+ targetSdkVersion(30)
+ }
+}
+
+ksp {
+ arg("option1", "value1")
+ arg("option2", "value2")
+}
diff --git a/integration-tests/src/test/resources/playground-android-multi/workload/src/main/AndroidManifest.xml b/integration-tests/src/test/resources/playground-android-multi/workload/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..522bce61
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android-multi/workload/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.mylibrary">
+</manifest> \ No newline at end of file
diff --git a/integration-tests/src/test/resources/playground-android/build.gradle.kts b/integration-tests/src/test/resources/playground-android/build.gradle.kts
new file mode 100644
index 00000000..b54fb383
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android/build.gradle.kts
@@ -0,0 +1,20 @@
+buildscript {
+ val testRepo: String by project
+
+ repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ google()
+ }
+}
+
+allprojects {
+ val testRepo: String by project
+ repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ google()
+ }
+}
diff --git a/integration-tests/src/test/resources/playground-android/gradle.properties b/integration-tests/src/test/resources/playground-android/gradle.properties
new file mode 100644
index 00000000..b3c7a033
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android/gradle.properties
@@ -0,0 +1 @@
+org.gradle.jvmargs=-Xmx2048M
diff --git a/integration-tests/src/test/resources/playground-android/settings.gradle.kts b/integration-tests/src/test/resources/playground-android/settings.gradle.kts
new file mode 100644
index 00000000..67a08d91
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android/settings.gradle.kts
@@ -0,0 +1,24 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ val testRepo: String by settings
+ val agpVersion: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion apply false
+ kotlin("jvm") version kotlinVersion apply false
+ kotlin("android") version kotlinVersion apply false
+ id("com.android.application") version agpVersion apply false
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ google()
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "playground"
+
+include(":workload")
+include(":test-processor")
diff --git a/integration-tests/src/test/resources/playground-android/test-processor/build.gradle.kts b/integration-tests/src/test/resources/playground-android/test-processor/build.gradle.kts
new file mode 100644
index 00000000..75c6c7c5
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android/test-processor/build.gradle.kts
@@ -0,0 +1,25 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.squareup:javapoet:1.12.1")
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
diff --git a/integration-tests/src/test/resources/playground-android/workload/build.gradle.kts b/integration-tests/src/test/resources/playground-android/workload/build.gradle.kts
new file mode 100644
index 00000000..b0a0038a
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android/workload/build.gradle.kts
@@ -0,0 +1,45 @@
+val testRepo: String by project
+
+plugins {
+ // DO NOT CHANGE THE ORDER.
+ id("com.google.devtools.ksp")
+ id("com.android.application")
+ kotlin("android")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation(project(":test-processor"))
+ ksp(project(":test-processor"))
+}
+
+android {
+ compileSdkVersion(30)
+ defaultConfig {
+ applicationId = "org.gradle.kotlin.dsl.samples.androidstudio"
+ minSdkVersion(30)
+ targetSdkVersion(30)
+ versionCode = 1
+ versionName = "1.0"
+ }
+ buildTypes {
+ getByName("release") {
+ // For regression testing https://github.com/google/ksp/pull/467
+ proguardFiles.add(file("proguard-rules.pro"))
+ isMinifyEnabled = true
+ }
+ }
+}
+
+ksp {
+ arg("option1", "value1")
+ arg("option2", "value2")
+}
diff --git a/integration-tests/src/test/resources/playground-android/workload/proguard-rules.pro b/integration-tests/src/test/resources/playground-android/workload/proguard-rules.pro
new file mode 100644
index 00000000..a90bbb3f
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android/workload/proguard-rules.pro
@@ -0,0 +1 @@
+-keep class com.example.AClass { *; } \ No newline at end of file
diff --git a/integration-tests/src/test/resources/playground-android/workload/src/main/AndroidManifest.xml b/integration-tests/src/test/resources/playground-android/workload/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..81a4ba30
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-android/workload/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.myapplication">
+</manifest> \ No newline at end of file
diff --git a/integration-tests/src/test/resources/playground-mpp/build.gradle.kts b/integration-tests/src/test/resources/playground-mpp/build.gradle.kts
new file mode 100644
index 00000000..8dd65667
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-mpp/build.gradle.kts
@@ -0,0 +1,12 @@
+plugins {
+ kotlin("multiplatform") apply false
+}
+
+val testRepo: String by project
+allprojects {
+ repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
diff --git a/integration-tests/src/test/resources/playground-mpp/settings.gradle.kts b/integration-tests/src/test/resources/playground-mpp/settings.gradle.kts
new file mode 100644
index 00000000..49845b92
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-mpp/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion apply false
+ kotlin("multiplatform") version kotlinVersion apply false
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "playground"
+
+include(":workload")
+include(":test-processor")
diff --git a/integration-tests/src/test/resources/playground-mpp/test-processor/build.gradle.kts b/integration-tests/src/test/resources/playground-mpp/test-processor/build.gradle.kts
new file mode 100644
index 00000000..842898f6
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-mpp/test-processor/build.gradle.kts
@@ -0,0 +1,22 @@
+val kspVersion: String by project
+
+plugins {
+ kotlin("multiplatform")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+kotlin {
+ jvm()
+ sourceSets {
+ val jvmMain by getting {
+ dependencies {
+ implementation("com.squareup:javapoet:1.12.1")
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+ }
+ kotlin.srcDir("src/main/kotlin")
+ resources.srcDir("src/main/resources")
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/playground-mpp/workload/build.gradle.kts b/integration-tests/src/test/resources/playground-mpp/workload/build.gradle.kts
new file mode 100644
index 00000000..a3179983
--- /dev/null
+++ b/integration-tests/src/test/resources/playground-mpp/workload/build.gradle.kts
@@ -0,0 +1,39 @@
+plugins {
+ kotlin("multiplatform")
+ id("com.google.devtools.ksp")
+}
+
+version = "1.0-SNAPSHOT"
+
+kotlin {
+ jvm {
+ withJava()
+ }
+ linuxX64()
+ mingwX64()
+ macosX64()
+ ios()
+ js(BOTH) {
+ browser()
+ nodejs()
+ }
+ sourceSets {
+ val commonMain by getting
+ val jvmMain by getting {
+ dependencies {
+ implementation(project(":test-processor"))
+ project.dependencies.add("kspJvm", project(":test-processor"))
+ }
+ kotlin.srcDir("src/main/java")
+ }
+ }
+}
+
+tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
+ kotlinOptions.freeCompilerArgs += "-Xuse-deprecated-legacy-compiler"
+}
+
+ksp {
+ arg("option1", "value1")
+ arg("option2", "value2")
+}
diff --git a/integration-tests/src/test/resources/playground/build.gradle.kts b/integration-tests/src/test/resources/playground/build.gradle.kts
new file mode 100644
index 00000000..c5737a2e
--- /dev/null
+++ b/integration-tests/src/test/resources/playground/build.gradle.kts
@@ -0,0 +1,8 @@
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
diff --git a/integration-tests/src/test/resources/playground/settings.gradle.kts b/integration-tests/src/test/resources/playground/settings.gradle.kts
new file mode 100644
index 00000000..9d60cbc7
--- /dev/null
+++ b/integration-tests/src/test/resources/playground/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "playground"
+
+include(":workload")
+include(":test-processor")
diff --git a/integration-tests/src/test/resources/playground/test-processor/build.gradle.kts b/integration-tests/src/test/resources/playground/test-processor/build.gradle.kts
new file mode 100644
index 00000000..75c6c7c5
--- /dev/null
+++ b/integration-tests/src/test/resources/playground/test-processor/build.gradle.kts
@@ -0,0 +1,25 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.squareup:javapoet:1.12.1")
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
diff --git a/integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/Builder.kt b/integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/Builder.kt
new file mode 100644
index 00000000..9434b362
--- /dev/null
+++ b/integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/Builder.kt
@@ -0,0 +1,3 @@
+package com.example.annotation
+
+annotation class Builder
diff --git a/integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/BuilderProcessor.kt b/integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/BuilderProcessor.kt
new file mode 100644
index 00000000..efa5ddcf
--- /dev/null
+++ b/integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/BuilderProcessor.kt
@@ -0,0 +1,104 @@
+import com.google.devtools.ksp.containingFile
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.validate
+import java.io.OutputStream
+
+fun OutputStream.appendText(str: String) {
+ this.write(str.toByteArray())
+}
+
+class BuilderProcessor : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+ lateinit var logger: KSPLogger
+
+ fun init(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger,
+ ) {
+ this.codeGenerator = codeGenerator
+ this.logger = logger
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val symbols = resolver.getSymbolsWithAnnotation("com.example.annotation.Builder")
+ val ret = symbols.filter { !it.validate() }
+ symbols
+ .filter { it is KSClassDeclaration && it.validate() }
+ .forEach { it.accept(BuilderVisitor(), Unit) }
+ return ret.toList()
+ }
+
+ inner class BuilderVisitor : KSVisitorVoid() {
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ classDeclaration.primaryConstructor?.accept(this, data)
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ val parent = function.parentDeclaration as KSClassDeclaration
+ val packageName = parent.containingFile!!.packageName.asString()
+ val className = "${parent.simpleName.asString()}Builder"
+
+ // For regression testing https://github.com/google/ksp/pull/467
+ codeGenerator.createNewFile(
+ Dependencies(true, function.containingFile!!),
+ "",
+ "META-INF/proguard/builder-$className",
+ "pro"
+ ).use { proguardFile ->
+ proguardFile.appendText("-keep class $packageName.$className { *; }")
+ }
+
+ val file = codeGenerator.createNewFile(
+ Dependencies(true, function.containingFile!!), packageName, className
+ )
+ file.appendText("package $packageName\n\n")
+ file.appendText("import hello.HELLO\n\n")
+ file.appendText("class $className{\n")
+ function.parameters.forEach {
+ val name = it.name!!.asString()
+ val typeName = StringBuilder(it.type.resolve().declaration.qualifiedName?.asString() ?: "<ERROR>")
+ val typeArgs = it.type.element!!.typeArguments
+ if (it.type.element!!.typeArguments.toList().isNotEmpty()) {
+ typeName.append("<")
+ typeName.append(
+ typeArgs.map {
+ val type = it.type?.resolve()
+ "${it.variance.label} ${type?.declaration?.qualifiedName?.asString() ?: "ERROR"}" +
+ if (type?.nullability == Nullability.NULLABLE) "?" else ""
+ }.joinToString(", ")
+ )
+ typeName.append(">")
+ }
+ file.appendText(" private var $name: $typeName? = null\n")
+ file.appendText(" internal fun with${name.capitalize()}($name: $typeName): $className {\n")
+ file.appendText(" this.$name = $name\n")
+ file.appendText(" return this\n")
+ file.appendText(" }\n\n")
+ }
+ file.appendText(" internal fun build(): ${parent.qualifiedName!!.asString()} {\n")
+ file.appendText(" return ${parent.qualifiedName!!.asString()}(")
+ file.appendText(
+ function.parameters.map {
+ "${it.name!!.asString()}!!"
+ }.joinToString(", ")
+ )
+ file.appendText(")\n")
+ file.appendText(" }\n")
+ file.appendText("}\n")
+ file.close()
+ }
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment,
+ ): SymbolProcessor {
+ return BuilderProcessor().apply {
+ init(env.options, env.kotlinVersion, env.codeGenerator, env.logger)
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/RewriteProcessor.kt b/integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/RewriteProcessor.kt
new file mode 100644
index 00000000..6c6e2354
--- /dev/null
+++ b/integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/RewriteProcessor.kt
@@ -0,0 +1,30 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+
+class RewriteProcessor : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+
+ fun init(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger
+ ) {
+ this.codeGenerator = codeGenerator
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val fileKt = codeGenerator.createNewFile(Dependencies(false), "hello", "HELLO", "java")
+ return emptyList()
+ }
+}
+
+class RewriteProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return RewriteProcessor().apply {
+ init(env.options, env.kotlinVersion, env.codeGenerator, env.logger)
+ }
+ }
+}
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
new file mode 100644
index 00000000..4b5a3cb5
--- /dev/null
+++ b/integration-tests/src/test/resources/playground/test-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,283 @@
+import com.google.devtools.ksp.containingFile
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import java.io.OutputStream
+
+class TestProcessor : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+ lateinit var file: OutputStream
+ var invoked = false
+
+ fun emit(s: String, indent: String) {
+ file.appendText("$indent$s\n")
+ }
+
+ fun init(
+ options: Map<String, String>,
+ kotlinVersion: KotlinVersion,
+ codeGenerator: CodeGenerator,
+ logger: KSPLogger
+ ) {
+ logger.warn("This is a harmless warning.")
+ this.codeGenerator = codeGenerator
+ file = codeGenerator.createNewFile(Dependencies(false), "", "TestProcessor", "log")
+ emit("TestProcessor: init($options)", "")
+
+ val javaFile = codeGenerator.createNewFile(Dependencies(false), "", "Generated", "java")
+ javaFile.appendText("class Generated {}")
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ if (invoked) {
+ return emptyList()
+ }
+ val fileKt = codeGenerator.createNewFile(Dependencies(false), "hello", "HELLO", "java")
+ fileKt.appendText("package hello;\n")
+ fileKt.appendText("public class HELLO{\n")
+ fileKt.appendText("public int foo() { return 1234; }\n")
+ fileKt.appendText("}")
+
+ val files = resolver.getAllFiles()
+ emit("TestProcessor: process()", "")
+ val visitor = TestVisitor()
+ for (file in files) {
+ emit("TestProcessor: processing ${file.fileName}", "")
+ file.accept(visitor, "")
+ }
+ invoked = true
+ return emptyList()
+ }
+
+ inner class TestVisitor : KSVisitor<String, Unit> {
+
+ override fun visitReferenceElement(element: KSReferenceElement, data: String) {
+ }
+
+ override fun visitModifierListOwner(modifierListOwner: KSModifierListOwner, data: String) {
+ TODO("Not yet implemented")
+ }
+
+ override fun visitNode(node: KSNode, data: String) {
+ TODO("Not yet implemented")
+ }
+
+ override fun visitPropertyAccessor(accessor: KSPropertyAccessor, data: String) {
+ TODO("Not yet implemented")
+ }
+
+ override fun visitDynamicReference(reference: KSDynamicReference, data: String) {
+ TODO("Not yet implemented")
+ }
+
+ override fun visitDefNonNullReference(reference: KSDefNonNullReference, data: String) {
+ TODO("Not yet implemented")
+ }
+
+ val visited = HashSet<Any>()
+
+ private fun checkVisited(symbol: Any): Boolean {
+ return if (visited.contains(symbol)) {
+ true
+ } else {
+ visited.add(symbol)
+ false
+ }
+ }
+
+ private fun invokeCommonDeclarationApis(declaration: KSDeclaration, indent: String) {
+ emit(
+ "${declaration.modifiers.joinToString(" ")} ${declaration.simpleName.asString()}", indent
+ )
+ declaration.annotations.map { it.accept(this, "$indent ") }
+ if (declaration.parentDeclaration != null)
+ emit(" enclosing: ${declaration.parentDeclaration!!.qualifiedName?.asString()}", indent)
+ declaration.containingFile?.let { emit("${it.packageName.asString()}.${it.fileName}", indent) }
+ declaration.typeParameters.map { it.accept(this, "$indent ") }
+ }
+
+ override fun visitFile(file: KSFile, data: String) {
+// if (!file.packageName.asString().startsWith("eu.kanade.tachiyomi.data")) {
+// return
+// }
+ if (checkVisited(file)) return
+ file.annotations.forEach { it.accept(this, "$data ") }
+ emit(file.packageName.asString(), data)
+ for (declaration in file.declarations) {
+ declaration.accept(this, data)
+ }
+ }
+
+ override fun visitAnnotation(annotation: KSAnnotation, data: String) {
+ if (checkVisited(annotation)) return
+ emit("annotation", data)
+ annotation.annotationType.accept(this, "$data ")
+ annotation.arguments.forEach { it.accept(this, "$data ") }
+ }
+
+ override fun visitCallableReference(reference: KSCallableReference, data: String) {
+ if (checkVisited(reference)) return
+ emit("element: ", data)
+ reference.functionParameters.forEach { it.accept(this, "$data ") }
+ reference.receiverType?.accept(this, "$data receiver")
+ reference.returnType.accept(this, "$data ")
+ }
+
+ override fun visitPropertyGetter(getter: KSPropertyGetter, data: String) {
+ if (checkVisited(getter)) return
+ emit("propertyGetter: ", data)
+ getter.annotations.forEach { it.accept(this, "$data ") }
+ emit(getter.modifiers.joinToString(" "), data)
+ getter.returnType?.accept(this, "$data ")
+ }
+
+ override fun visitPropertySetter(setter: KSPropertySetter, data: String) {
+ if (checkVisited(setter)) return
+ emit("propertySetter: ", data)
+ setter.annotations.forEach { it.accept(this, "$data ") }
+ emit(setter.modifiers.joinToString(" "), data)
+// setter.parameter.accept(this, "$data ")
+ }
+
+ override fun visitTypeArgument(typeArgument: KSTypeArgument, data: String) {
+ if (checkVisited(typeArgument)) return
+ typeArgument.annotations.forEach { it.accept(this, "$data ") }
+ emit(
+ when (typeArgument.variance) {
+ Variance.STAR -> "*"
+ Variance.COVARIANT -> "out"
+ Variance.CONTRAVARIANT -> "in"
+ else -> ""
+ },
+ data
+ )
+ typeArgument.type?.accept(this, "$data ")
+ }
+
+ override fun visitTypeParameter(typeParameter: KSTypeParameter, data: String) {
+ if (checkVisited(typeParameter)) return
+ typeParameter.annotations.forEach { it.accept(this, "$data ") }
+ if (typeParameter.isReified) {
+ emit("reified ", data)
+ }
+ emit(
+ when (typeParameter.variance) {
+ Variance.COVARIANT -> "out "
+ Variance.CONTRAVARIANT -> "in "
+ else -> ""
+ } + typeParameter.name.asString(),
+ data
+ )
+ if (typeParameter.bounds.toList().isNotEmpty()) {
+ typeParameter.bounds.forEach { it.accept(this, "$data ") }
+ }
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: String) {
+ if (checkVisited(valueParameter)) return
+ valueParameter.annotations.forEach { it.accept(this, "$data ") }
+ if (valueParameter.isVararg) {
+ emit("vararg", "$data ")
+ }
+ if (valueParameter.isNoInline) {
+ emit("noinline", "$data ")
+ }
+ if (valueParameter.isCrossInline) {
+ emit("crossinline ", "$data ")
+ }
+ emit(valueParameter.name?.asString() ?: "_", "$data ")
+ valueParameter.type.accept(this, "$data ")
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: String) {
+ if (checkVisited(function)) return
+ invokeCommonDeclarationApis(function, data)
+ for (declaration in function.declarations) {
+ declaration.accept(this, "$data ")
+ }
+ function.parameters.forEach { it.accept(this, "$data ") }
+ function.typeParameters.forEach { it.accept(this, "$data ") }
+ function.extensionReceiver?.accept(this, "$data extension:")
+ emit("returnType:", data)
+ function.returnType?.accept(this, "$data ")
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: String) {
+ if (checkVisited(classDeclaration)) return
+ invokeCommonDeclarationApis(classDeclaration, data)
+ emit(classDeclaration.classKind.type, data)
+ for (declaration in classDeclaration.declarations) {
+ declaration.accept(this, "$data ")
+ }
+ classDeclaration.superTypes.forEach { it.accept(this, "$data ") }
+ classDeclaration.primaryConstructor?.accept(this, "$data ")
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: String) {
+ if (checkVisited(property)) return
+ invokeCommonDeclarationApis(property, data)
+ property.type.accept(this, "$data ")
+ property.extensionReceiver?.accept(this, "$data extension:")
+ property.setter?.accept(this, "$data ")
+ property.getter?.accept(this, "$data ")
+ }
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: String) {
+ if (checkVisited(typeReference)) return
+ typeReference.annotations.forEach { it.accept(this, "$data ") }
+ val type = typeReference.resolve()
+ type.let {
+ emit("resolved to: ${it.declaration.qualifiedName?.asString()}", data)
+ }
+ // resolved.accept(this, "$data ")
+ // TODO: KSTypeReferenceJavaImpl hasn't completed yet.
+ try {
+ typeReference.element?.accept(this, "$data ")
+ } catch (e: IllegalStateException) {
+ emit("TestProcessor: exception: $e", data)
+ }
+ }
+
+ override fun visitAnnotated(annotated: KSAnnotated, data: String) {
+ }
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: String) {
+ }
+
+ override fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: String) {
+ }
+
+ override fun visitParenthesizedReference(reference: KSParenthesizedReference, data: String) {
+ }
+
+ override fun visitClassifierReference(reference: KSClassifierReference, data: String) {
+ if (checkVisited(reference)) return
+ if (reference.typeArguments.toList().isNotEmpty()) {
+ reference.typeArguments.forEach { it.accept(this, "$data ") }
+ }
+ }
+
+ override fun visitTypeAlias(typeAlias: KSTypeAlias, data: String) {
+ }
+
+ override fun visitValueArgument(valueArgument: KSValueArgument, data: String) {
+ if (checkVisited(valueArgument)) return
+ val name = valueArgument.name?.asString() ?: "<no name>"
+ emit("$name: ${valueArgument.value}", data)
+ valueArgument.annotations.forEach { it.accept(this, "$data ") }
+ }
+ }
+}
+
+class TestProcessorProvider2 : SymbolProcessorProvider {
+ override fun create(
+ env: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return TestProcessor().apply {
+ init(env.options, env.kotlinVersion, env.codeGenerator, env.logger)
+
+ env.logger.warn("language version: ${env.kotlinVersion}")
+ env.logger.warn("api version: ${env.apiVersion}")
+ env.logger.warn("compiler version: ${env.compilerVersion}")
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/playground/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/playground/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..3a1528c9
--- /dev/null
+++ b/integration-tests/src/test/resources/playground/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1,2 @@
+TestProcessorProvider
+TestProcessorProvider2
diff --git a/integration-tests/src/test/resources/playground/workload/G.kt b/integration-tests/src/test/resources/playground/workload/G.kt
new file mode 100644
index 00000000..f2f80ffe
--- /dev/null
+++ b/integration-tests/src/test/resources/playground/workload/G.kt
@@ -0,0 +1,6 @@
+package g
+
+import com.example.annotation.Builder
+
+@Builder
+class G
diff --git a/integration-tests/src/test/resources/playground/workload/build.gradle.kts b/integration-tests/src/test/resources/playground/workload/build.gradle.kts
new file mode 100644
index 00000000..6cb48fad
--- /dev/null
+++ b/integration-tests/src/test/resources/playground/workload/build.gradle.kts
@@ -0,0 +1,36 @@
+import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool
+
+val testRepo: String by project
+
+plugins {
+ id("com.google.devtools.ksp")
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation(project(":test-processor"))
+ ksp(project(":test-processor"))
+}
+
+ksp {
+ arg("option1", "value1")
+ arg("option2", "value2")
+}
+
+val compileKotlin: AbstractKotlinCompileTool<*> by tasks
+tasks.register<Copy>("copyG") {
+ from("G.kt")
+ into(File(buildDir, "generatedSources").apply { mkdirs() })
+}.let {
+ // Magic. `map` creates a provider to propagate task dependency.
+ compileKotlin.setSource(it.map { it.destinationDir })
+}
diff --git a/integration-tests/src/test/resources/playground/workload/src/main/java/com/example/A.kt b/integration-tests/src/test/resources/playground/workload/src/main/java/com/example/A.kt
new file mode 100644
index 00000000..e5fa7f97
--- /dev/null
+++ b/integration-tests/src/test/resources/playground/workload/src/main/java/com/example/A.kt
@@ -0,0 +1,16 @@
+package com.example
+
+import hello.HELLO
+
+fun main() {
+ val hello = HELLO()
+ println(hello.foo())
+
+ val builder = AClassBuilder()
+ builder
+ .withA(1)
+ .withB("foo")
+ .withC(2.3)
+ val aClass: AClass = builder.build()
+ println(aClass.foo())
+}
diff --git a/integration-tests/src/test/resources/playground/workload/src/main/java/com/example/AClass.kt b/integration-tests/src/test/resources/playground/workload/src/main/java/com/example/AClass.kt
new file mode 100644
index 00000000..180dbe6a
--- /dev/null
+++ b/integration-tests/src/test/resources/playground/workload/src/main/java/com/example/AClass.kt
@@ -0,0 +1,17 @@
+package com.example
+
+import com.example.annotation.Builder
+import hello.HELLO
+
+@Builder
+class AClass(private val a: Int, val b: String, val c: Double, val d: HELLO) {
+ val p = "$a, $b, $c"
+ fun foo() = HELLO()
+ val hello = HELLO()
+ var hello2: HELLO = HELLO()
+ get() { return hello2 }
+ private set
+ class innerClass<T : HELLO>
+
+ val generic = innerClass<HELLO>()
+}
diff --git a/integration-tests/src/test/resources/playground/workload/src/main/java/com/example/BClass.java b/integration-tests/src/test/resources/playground/workload/src/main/java/com/example/BClass.java
new file mode 100644
index 00000000..fcfbcbcf
--- /dev/null
+++ b/integration-tests/src/test/resources/playground/workload/src/main/java/com/example/BClass.java
@@ -0,0 +1,14 @@
+package com.example;
+
+import com.example.annotation.Builder;
+import hello.HELLO;
+import java.util.List;
+
+@Builder
+public class BClass {
+ public HELLO hello;
+ public HELLO helloFun(){
+ return null;
+ }
+ public List<HELLO> list = null;
+} \ No newline at end of file
diff --git a/integration-tests/src/test/resources/psi-cache/test-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/psi-cache/test-processor/src/main/kotlin/TestProcessor.kt
new file mode 100644
index 00000000..ad548224
--- /dev/null
+++ b/integration-tests/src/test/resources/psi-cache/test-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,40 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.validate
+
+class TestProcessor(
+ val codeGenerator: CodeGenerator,
+ val logger: KSPLogger
+) : SymbolProcessor {
+ var rounds = 0
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ rounds++
+
+ val syms = resolver.getSymbolsWithAnnotation("com.example.Anno").toList()
+
+ syms.forEach {
+ val v = it.validate()
+ if (rounds == 2 && v == false) {
+ logger.error("validation failed: $it")
+ }
+ }
+
+ if (rounds == 1) {
+ codeGenerator.createNewFile(Dependencies(true), "com.example", "Foo1").use {
+ it.write("package com.example\n\ninterface Foo1\n".toByteArray())
+ }
+ codeGenerator.createNewFile(Dependencies(true), "com.example", "Foo2", "java").use {
+ it.write("package com.example;\n\npublic interface Foo2{}\n".toByteArray())
+ }
+ return syms.toList()
+ }
+
+ return emptyList()
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
+ return TestProcessor(environment.codeGenerator, environment.logger)
+ }
+}
diff --git a/integration-tests/src/test/resources/psi-cache/workload/src/main/java/com/example/Bar.kt b/integration-tests/src/test/resources/psi-cache/workload/src/main/java/com/example/Bar.kt
new file mode 100644
index 00000000..e6f5a794
--- /dev/null
+++ b/integration-tests/src/test/resources/psi-cache/workload/src/main/java/com/example/Bar.kt
@@ -0,0 +1,6 @@
+package com.example
+
+annotation class Anno
+
+@Anno
+open class Bar : Foo1, Foo2
diff --git a/integration-tests/src/test/resources/psi-cache/workload/src/main/java/com/example/Baz.java b/integration-tests/src/test/resources/psi-cache/workload/src/main/java/com/example/Baz.java
new file mode 100644
index 00000000..4ccfb0db
--- /dev/null
+++ b/integration-tests/src/test/resources/psi-cache/workload/src/main/java/com/example/Baz.java
@@ -0,0 +1,6 @@
+package com.example;
+
+@Anno
+public class Baz implements Foo1, Foo2 {
+
+}
diff --git a/integration-tests/src/test/resources/refs-gen/test-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/refs-gen/test-processor/src/main/kotlin/TestProcessor.kt
new file mode 100644
index 00000000..643deb7c
--- /dev/null
+++ b/integration-tests/src/test/resources/refs-gen/test-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,48 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.validate
+import java.io.OutputStreamWriter
+
+class TestProcessor(
+ val codeGenerator: CodeGenerator,
+ val logger: KSPLogger
+) : SymbolProcessor {
+ // FIXME: use getSymbolsWithAnnotation after it is fixed.
+ var rounds = 0
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ rounds++
+ logger.warn("$rounds: ${resolver.getNewFiles().toList()}")
+
+ if (rounds == 1) {
+ codeGenerator.createNewFile(Dependencies(false), "", "Foo", "kt").use { output ->
+ OutputStreamWriter(output).use { writer ->
+ writer.write("package com.example\n\n")
+ writer.write("open class Foo : Goo()\n")
+ }
+ }
+ }
+
+ if (rounds == 2) {
+ codeGenerator.createNewFile(Dependencies(false), "", "Goo", "kt").use { output ->
+ OutputStreamWriter(output).use { writer ->
+ writer.write("package com.example\n\n")
+ writer.write("open class Goo : Baz()\n")
+ }
+ }
+ }
+
+ resolver.getNewFiles().forEach {
+ it.validate()
+ }
+
+ return emptyList()
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ environment: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return TestProcessor(environment.codeGenerator, environment.logger)
+ }
+}
diff --git a/integration-tests/src/test/resources/refs-gen/workload/src/main/kotlin/com/example/Bar.kt b/integration-tests/src/test/resources/refs-gen/workload/src/main/kotlin/com/example/Bar.kt
new file mode 100644
index 00000000..9f126ff9
--- /dev/null
+++ b/integration-tests/src/test/resources/refs-gen/workload/src/main/kotlin/com/example/Bar.kt
@@ -0,0 +1,3 @@
+package com.example
+
+class Bar : Foo()
diff --git a/integration-tests/src/test/resources/refs-gen/workload/src/main/kotlin/com/example/Baz.kt b/integration-tests/src/test/resources/refs-gen/workload/src/main/kotlin/com/example/Baz.kt
new file mode 100644
index 00000000..58e29ec8
--- /dev/null
+++ b/integration-tests/src/test/resources/refs-gen/workload/src/main/kotlin/com/example/Baz.kt
@@ -0,0 +1,5 @@
+package com.example
+
+open class Baz
+
+val l: List<Int> = TODO()
diff --git a/integration-tests/src/test/resources/sealed-subclasses/test-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/sealed-subclasses/test-processor/src/main/kotlin/TestProcessor.kt
new file mode 100644
index 00000000..934d43df
--- /dev/null
+++ b/integration-tests/src/test/resources/sealed-subclasses/test-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,28 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+
+class TestProcessor(
+ val codeGenerator: CodeGenerator,
+ val logger: KSPLogger
+) : SymbolProcessor {
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach { f ->
+ logger.warn("Processing ${f.fileName}")
+ f.declarations.forEach {
+ if (it is KSClassDeclaration) {
+ val subs = it.getSealedSubclasses().map { it.simpleName.asString() }.toList()
+ logger.warn("${it.simpleName.asString()} : $subs")
+ }
+ }
+ }
+ return emptyList()
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ environment: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return TestProcessor(environment.codeGenerator, environment.logger)
+ }
+}
diff --git a/integration-tests/src/test/resources/sealed-subclasses/workload/src/main/kotlin/com/example/Impl1.kt b/integration-tests/src/test/resources/sealed-subclasses/workload/src/main/kotlin/com/example/Impl1.kt
new file mode 100644
index 00000000..f4cd105e
--- /dev/null
+++ b/integration-tests/src/test/resources/sealed-subclasses/workload/src/main/kotlin/com/example/Impl1.kt
@@ -0,0 +1,3 @@
+package com.example
+
+class Impl1 : Sealed()
diff --git a/integration-tests/src/test/resources/sealed-subclasses/workload/src/main/kotlin/com/example/Impl2.kt b/integration-tests/src/test/resources/sealed-subclasses/workload/src/main/kotlin/com/example/Impl2.kt
new file mode 100644
index 00000000..aa8f5e86
--- /dev/null
+++ b/integration-tests/src/test/resources/sealed-subclasses/workload/src/main/kotlin/com/example/Impl2.kt
@@ -0,0 +1,3 @@
+package com.example
+
+class Impl2 : Sealed()
diff --git a/integration-tests/src/test/resources/sealed-subclasses/workload/src/main/kotlin/com/example/Sealed.kt b/integration-tests/src/test/resources/sealed-subclasses/workload/src/main/kotlin/com/example/Sealed.kt
new file mode 100644
index 00000000..d65d5cc9
--- /dev/null
+++ b/integration-tests/src/test/resources/sealed-subclasses/workload/src/main/kotlin/com/example/Sealed.kt
@@ -0,0 +1,3 @@
+package com.example
+
+sealed class Sealed
diff --git a/integration-tests/src/test/resources/srcs-gen/test-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/srcs-gen/test-processor/src/main/kotlin/TestProcessor.kt
new file mode 100644
index 00000000..f0b0f227
--- /dev/null
+++ b/integration-tests/src/test/resources/srcs-gen/test-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,54 @@
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.*
+import java.io.OutputStreamWriter
+
+class TestProcessor(
+ val codeGenerator: CodeGenerator,
+ val logger: KSPLogger
+) : SymbolProcessor {
+ // FIXME: use getSymbolsWithAnnotation after it is fixed.
+ var rounds = 0
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ rounds++
+ logger.warn("$rounds: ${resolver.getNewFiles().toList().sortedBy { it.fileName }}")
+
+ // Would fail if "Bar.kt" isn't dirty.
+ val barKt = resolver.getAllFiles().single { it.fileName == "Bar.kt" }
+ val bazKt = resolver.getAllFiles().single { it.fileName == "Baz.kt" }
+
+ if (rounds == 1) {
+ codeGenerator.createNewFile(Dependencies(false), "", "Foo", "kt").use { output ->
+ OutputStreamWriter(output).use { writer ->
+ writer.write("package com.example\n\n")
+ writer.write("open class Foo\n")
+ }
+ }
+ }
+
+ if (rounds == 2) {
+ val fooKt = resolver.getAllFiles().single { it.fileName == "Foo.kt" }
+ codeGenerator.createNewFile(Dependencies(false, fooKt, barKt), "", "FooBar", "kt").use { output ->
+ OutputStreamWriter(output).use { writer ->
+ writer.write("package com.example\n\n")
+ writer.write("open class FooBar\n")
+ }
+ }
+ codeGenerator.createNewFile(Dependencies(false, fooKt, bazKt), "", "FooBaz", "kt").use { output ->
+ OutputStreamWriter(output).use { writer ->
+ writer.write("package com.example\n\n")
+ writer.write("open class FooBaz\n")
+ }
+ }
+ }
+
+ return emptyList()
+ }
+}
+
+class TestProcessorProvider : SymbolProcessorProvider {
+ override fun create(
+ environment: SymbolProcessorEnvironment
+ ): SymbolProcessor {
+ return TestProcessor(environment.codeGenerator, environment.logger)
+ }
+}
diff --git a/integration-tests/src/test/resources/srcs-gen/workload/src/main/kotlin/com/example/Bar.kt b/integration-tests/src/test/resources/srcs-gen/workload/src/main/kotlin/com/example/Bar.kt
new file mode 100644
index 00000000..2eb12746
--- /dev/null
+++ b/integration-tests/src/test/resources/srcs-gen/workload/src/main/kotlin/com/example/Bar.kt
@@ -0,0 +1,3 @@
+package com.example
+
+class Bar
diff --git a/integration-tests/src/test/resources/srcs-gen/workload/src/main/kotlin/com/example/Baz.kt b/integration-tests/src/test/resources/srcs-gen/workload/src/main/kotlin/com/example/Baz.kt
new file mode 100644
index 00000000..f7b34a4f
--- /dev/null
+++ b/integration-tests/src/test/resources/srcs-gen/workload/src/main/kotlin/com/example/Baz.kt
@@ -0,0 +1,3 @@
+package com.example
+
+class Baz
diff --git a/integration-tests/src/test/resources/test-processor/build.gradle.kts b/integration-tests/src/test/resources/test-processor/build.gradle.kts
new file mode 100644
index 00000000..c5737a2e
--- /dev/null
+++ b/integration-tests/src/test/resources/test-processor/build.gradle.kts
@@ -0,0 +1,8 @@
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
diff --git a/integration-tests/src/test/resources/test-processor/settings.gradle.kts b/integration-tests/src/test/resources/test-processor/settings.gradle.kts
new file mode 100644
index 00000000..9d60cbc7
--- /dev/null
+++ b/integration-tests/src/test/resources/test-processor/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ }
+}
+
+rootProject.name = "playground"
+
+include(":workload")
+include(":test-processor")
diff --git a/integration-tests/src/test/resources/test-processor/test-processor/build.gradle.kts b/integration-tests/src/test/resources/test-processor/test-processor/build.gradle.kts
new file mode 100644
index 00000000..ab249cf0
--- /dev/null
+++ b/integration-tests/src/test/resources/test-processor/test-processor/build.gradle.kts
@@ -0,0 +1,24 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
diff --git a/integration-tests/src/test/resources/test-processor/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/test-processor/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..c91e3e9e
--- /dev/null
+++ b/integration-tests/src/test/resources/test-processor/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+TestProcessorProvider
diff --git a/integration-tests/src/test/resources/test-processor/workload/build.gradle.kts b/integration-tests/src/test/resources/test-processor/workload/build.gradle.kts
new file mode 100644
index 00000000..f0ea52b0
--- /dev/null
+++ b/integration-tests/src/test/resources/test-processor/workload/build.gradle.kts
@@ -0,0 +1,20 @@
+val testRepo: String by project
+
+plugins {
+ id("com.google.devtools.ksp")
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation(project(":test-processor"))
+ ksp(project(":test-processor"))
+}
diff --git a/kotlin-analysis-api/build.gradle.kts b/kotlin-analysis-api/build.gradle.kts
new file mode 100644
index 00000000..a5bab550
--- /dev/null
+++ b/kotlin-analysis-api/build.gradle.kts
@@ -0,0 +1,121 @@
+description = "Kotlin Symbol Processing implementation using Kotlin Analysis API"
+
+val intellijVersion: String by project
+val junitVersion: String by project
+val kotlinBaseVersion: String by project
+val libsForTesting by configurations.creating
+
+plugins {
+ kotlin("jvm")
+ id("org.jetbrains.intellij") version "0.6.4"
+ id("org.jetbrains.dokka") version ("1.7.20")
+}
+
+intellij {
+ version = intellijVersion
+}
+
+dependencies {
+ implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.3.4")
+ implementation(kotlin("stdlib", kotlinBaseVersion))
+ implementation("org.jetbrains.kotlin:kotlin-compiler:$kotlinBaseVersion")
+
+ implementation("org.jetbrains.kotlin:high-level-api-fir-for-ide:$kotlinBaseVersion") {
+ isTransitive = false
+ }
+ implementation("org.jetbrains.kotlin:high-level-api-for-ide:$kotlinBaseVersion") {
+ isTransitive = false
+ }
+ implementation("org.jetbrains.kotlin:low-level-api-fir-for-ide:$kotlinBaseVersion") {
+ isTransitive = false
+ }
+ implementation("org.jetbrains.kotlin:analysis-api-providers-for-ide:$kotlinBaseVersion") {
+ isTransitive = false
+ }
+ implementation("org.jetbrains.kotlin:analysis-project-structure-for-ide:$kotlinBaseVersion") {
+ isTransitive = false
+ }
+ implementation("org.jetbrains.kotlin:symbol-light-classes-for-ide:$kotlinBaseVersion") {
+ isTransitive = false
+ }
+ implementation("org.jetbrains.kotlin:analysis-api-standalone-for-ide:$kotlinBaseVersion") {
+ isTransitive = false
+ }
+ implementation("org.jetbrains.kotlin:high-level-api-impl-base-for-ide:$kotlinBaseVersion") {
+ isTransitive = false
+ }
+
+ implementation(project(":api"))
+ implementation(project(":common-util"))
+
+ testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-params:5.8.2")
+ testRuntimeOnly("org.junit.platform:junit-platform-suite:1.8.2")
+
+ testImplementation(project(":test-utils"))
+ testImplementation(project(":api"))
+ testImplementation(project(":common-util"))
+
+ testImplementation(kotlin("stdlib", kotlinBaseVersion))
+ testImplementation("org.jetbrains.kotlin:kotlin-compiler:$kotlinBaseVersion")
+ testImplementation("org.jetbrains.kotlin:kotlin-compiler-internal-test-framework:$kotlinBaseVersion")
+ testImplementation("org.jetbrains.kotlin:kotlin-scripting-compiler:$kotlinBaseVersion")
+
+ libsForTesting(kotlin("stdlib", kotlinBaseVersion))
+ libsForTesting(kotlin("test", kotlinBaseVersion))
+ libsForTesting(kotlin("script-runtime", kotlinBaseVersion))
+}
+
+tasks.register<Copy>("CopyLibsForTesting") {
+ from(configurations.get("libsForTesting"))
+ into("dist/kotlinc/lib")
+ val escaped = Regex.escape(kotlinBaseVersion)
+ rename("(.+)-$escaped\\.jar", "$1.jar")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
+
+fun Project.javaPluginConvention(): JavaPluginConvention = the()
+val JavaPluginConvention.testSourceSet: SourceSet
+ get() = sourceSets.getByName("test")
+val Project.testSourceSet: SourceSet
+ get() = javaPluginConvention().testSourceSet
+
+tasks.test {
+ dependsOn("CopyLibsForTesting")
+ maxHeapSize = "2g"
+
+ useJUnitPlatform()
+
+ systemProperty("idea.is.unit.test", "true")
+ systemProperty("idea.home.path", buildDir)
+ systemProperty("java.awt.headless", "true")
+ environment("NO_FS_ROOTS_ACCESS_CHECK", "true")
+ environment("PROJECT_CLASSES_DIRS", testSourceSet.output.classesDirs.asPath)
+ environment("PROJECT_BUILD_DIR", buildDir)
+ testLogging {
+ events("passed", "skipped", "failed")
+ }
+
+ var tempTestDir: File? = null
+ doFirst {
+ tempTestDir = createTempDir()
+ systemProperty("java.io.tmpdir", tempTestDir.toString())
+ }
+
+ doLast {
+ tempTestDir?.let { delete(it) }
+ }
+}
+
+repositories {
+ flatDir {
+ dirs("${project.rootDir}/third_party/prebuilt/repo/")
+ }
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-ide-plugin-dependencies")
+ maven("https://www.jetbrains.com/intellij-repository/releases")
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/CommandLineKSPLogger.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/CommandLineKSPLogger.kt
new file mode 100644
index 00000000..dc046ceb
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/CommandLineKSPLogger.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl
+
+import com.google.devtools.ksp.processing.KSPLogger
+import com.google.devtools.ksp.symbol.KSNode
+
+class CommandLineKSPLogger : KSPLogger {
+ // TODO: support logging level.
+ private val messager = System.err
+ override fun logging(message: String, symbol: KSNode?) {
+ messager.println(message)
+ }
+
+ override fun info(message: String, symbol: KSNode?) {
+ messager.println(message)
+ }
+
+ override fun warn(message: String, symbol: KSNode?) {
+ messager.println(message)
+ }
+
+ override fun error(message: String, symbol: KSNode?) {
+ messager.println(message)
+ }
+
+ override fun exception(e: Throwable) {
+ messager.println(e.message)
+ }
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KSPCommandLineProcessor.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KSPCommandLineProcessor.kt
new file mode 100644
index 00000000..2748fc55
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KSPCommandLineProcessor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl
+
+import com.google.devtools.ksp.KspOptions
+import com.google.devtools.ksp.processing.SymbolProcessorProvider
+import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
+import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots
+import org.jetbrains.kotlin.cli.common.messages.MessageCollector
+import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoots
+import org.jetbrains.kotlin.config.CompilerConfiguration
+import org.jetbrains.kotlin.util.ServiceLoaderLite
+import java.io.File
+import java.net.URLClassLoader
+
+class KSPCommandLineProcessor(val compilerConfiguration: CompilerConfiguration) {
+ private val kspOptionsBuilder = KspOptions.Builder()
+
+ val kspOptions: KspOptions
+ get() = kspOptionsBuilder.build()
+
+ lateinit var providers: List<SymbolProcessorProvider>
+
+ fun processArgs(args: Array<String>) {
+ // TODO: support KSP options
+ val sources = args.toList()
+ compilerConfiguration.addKotlinSourceRoots(sources)
+ compilerConfiguration.addJavaSourceRoots(sources.map { File(it) })
+ compilerConfiguration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
+ val processingClasspath = kspOptionsBuilder.processingClasspath
+ val classLoader = URLClassLoader(
+ processingClasspath.map { it.toURI().toURL() }.toTypedArray(),
+ javaClass.classLoader
+ )
+
+ providers = ServiceLoaderLite.loadImplementations(SymbolProcessorProvider::class.java, classLoader)
+ }
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KSPCoreEnvironment.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KSPCoreEnvironment.kt
new file mode 100644
index 00000000..1a4387de
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KSPCoreEnvironment.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl
+
+import com.intellij.mock.MockProject
+import com.intellij.psi.PsiDocumentManager
+
+class KSPCoreEnvironment(internal val project: MockProject) {
+ companion object {
+ // TODO: get rid of singleton.
+ lateinit var instance: KSPCoreEnvironment
+ }
+ init {
+ instance = this
+ }
+ val psiDocumentManager = PsiDocumentManager.getInstance(project)
+}
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
new file mode 100644
index 00000000..91efb6d9
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KotlinSymbolProcessing.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl
+
+import com.google.devtools.ksp.AnyChanges
+import com.google.devtools.ksp.KspOptions
+import com.google.devtools.ksp.impl.symbol.kotlin.KSFileImpl
+import com.google.devtools.ksp.impl.symbol.kotlin.analyze
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.processing.impl.CodeGeneratorImpl
+import com.google.devtools.ksp.processing.impl.JvmPlatformInfoImpl
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.intellij.mock.MockProject
+import com.intellij.openapi.vfs.StandardFileSystems
+import com.intellij.openapi.vfs.VirtualFileManager
+import com.intellij.psi.PsiJavaFile
+import com.intellij.psi.PsiManager
+import org.jetbrains.kotlin.analysis.api.standalone.StandaloneAnalysisAPISession
+import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession
+import org.jetbrains.kotlin.analysis.project.structure.getKtModule
+import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots
+import org.jetbrains.kotlin.cli.jvm.compiler.createSourceFilesFromSourceRoots
+import org.jetbrains.kotlin.cli.jvm.config.javaSourceRoots
+import org.jetbrains.kotlin.config.CompilerConfiguration
+import java.nio.file.Files
+
+class KotlinSymbolProcessing(
+ val compilerConfiguration: CompilerConfiguration,
+ val options: KspOptions,
+ val logger: KSPLogger,
+ val analysisAPISession: StandaloneAnalysisAPISession,
+ val providers: List<SymbolProcessorProvider>
+) {
+ val project = analysisAPISession.project as MockProject
+ val kspCoreEnvironment = KSPCoreEnvironment(project)
+
+ var finished = false
+ val deferredSymbols = mutableMapOf<SymbolProcessor, List<KSAnnotated>>()
+ val ktFiles = createSourceFilesFromSourceRoots(
+ compilerConfiguration, project, compilerConfiguration.kotlinSourceRoots
+ ).toSet().toList()
+ val javaFiles = compilerConfiguration.javaSourceRoots
+ lateinit var codeGenerator: CodeGeneratorImpl
+ lateinit var processors: List<SymbolProcessor>
+
+ fun prepare() {
+ // TODO: support no Kotlin source mode.
+ ResolverAAImpl.ktModule = ktFiles.first().getKtModule()
+ val ksFiles = ktFiles.map { file ->
+ analyze { KSFileImpl.getCached(file.getFileSymbol()) }
+ }
+ val anyChangesWildcard = AnyChanges(options.projectBaseDir)
+ codeGenerator = CodeGeneratorImpl(
+ options.classOutputDir,
+ options.javaOutputDir,
+ options.kotlinOutputDir,
+ options.resourceOutputDir,
+ options.projectBaseDir,
+ anyChangesWildcard,
+ ksFiles,
+ options.incremental
+ )
+ processors = providers.mapNotNull { provider ->
+ var processor: SymbolProcessor? = null
+ processor = provider.create(
+ SymbolProcessorEnvironment(
+ options.processingOptions,
+ options.languageVersion,
+ codeGenerator,
+ logger,
+ options.apiVersion,
+ options.compilerVersion,
+ // TODO: fix platform info
+ listOf(JvmPlatformInfoImpl("JVM", "1.8"))
+ )
+ )
+ processor.also { deferredSymbols[it] = mutableListOf() }
+ }
+ }
+
+ fun execute() {
+ // TODO: support no kotlin source input.
+ val psiManager = PsiManager.getInstance(project)
+ val localFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
+ val javaSourceRoots = options.javaSourceRoots
+ val javaFiles = javaSourceRoots.sortedBy { Files.isSymbolicLink(it.toPath()) } // Get non-symbolic paths first
+ .flatMap { root -> root.walk().filter { it.isFile && it.extension == "java" }.toList() }
+ .sortedBy { java.nio.file.Files.isSymbolicLink(it.toPath()) } // This time is for .java files
+ .distinctBy { it.canonicalPath }
+ .mapNotNull { localFileSystem.findFileByPath(it.path)?.let { psiManager.findFile(it) } as? PsiJavaFile }
+ val resolver = ResolverAAImpl(
+ ktFiles.map {
+ analyze { it.getFileSymbol() }
+ },
+ javaFiles
+ )
+ ResolverAAImpl.instance = resolver
+ processors.forEach { it.process(resolver) }
+ }
+}
+
+fun main(args: Array<String>) {
+ val compilerConfiguration = CompilerConfiguration()
+ val commandLineProcessor = KSPCommandLineProcessor(compilerConfiguration)
+ val logger = CommandLineKSPLogger()
+
+ val analysisSession = buildStandaloneAnalysisAPISession {
+ buildKtModuleProviderByCompilerConfiguration(compilerConfiguration)
+ }
+
+ val kotlinSymbolProcessing = KotlinSymbolProcessing(
+ commandLineProcessor.compilerConfiguration,
+ commandLineProcessor.kspOptions,
+ logger,
+ analysisSession,
+ commandLineProcessor.providers
+ )
+ kotlinSymbolProcessing.prepare()
+ kotlinSymbolProcessing.execute()
+}
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
new file mode 100644
index 00000000..687b2242
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/ResolverAAImpl.kt
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.impl.symbol.kotlin.KSClassDeclarationEnumEntryImpl
+import com.google.devtools.ksp.impl.symbol.kotlin.KSClassDeclarationImpl
+import com.google.devtools.ksp.impl.symbol.kotlin.KSFileImpl
+import com.google.devtools.ksp.impl.symbol.kotlin.KSFileJavaImpl
+import com.google.devtools.ksp.impl.symbol.kotlin.KSFunctionDeclarationImpl
+import com.google.devtools.ksp.impl.symbol.kotlin.KSPropertyDeclarationImpl
+import com.google.devtools.ksp.impl.symbol.kotlin.KSPropertyDeclarationJavaImpl
+import com.google.devtools.ksp.impl.symbol.kotlin.KSTypeAliasImpl
+import com.google.devtools.ksp.impl.symbol.kotlin.KSTypeArgumentLiteImpl
+import com.google.devtools.ksp.impl.symbol.kotlin.KSTypeImpl
+import com.google.devtools.ksp.impl.symbol.kotlin.analyze
+import com.google.devtools.ksp.impl.symbol.kotlin.toKtClassSymbol
+import com.google.devtools.ksp.processing.KSBuiltIns
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSDeclarationContainer
+import com.google.devtools.ksp.symbol.KSFile
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSName
+import com.google.devtools.ksp.symbol.KSPropertyAccessor
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSTypeArgument
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.symbol.Variance
+import com.google.devtools.ksp.toKSName
+import com.google.devtools.ksp.visitor.CollectAnnotatedSymbolsVisitor
+import com.intellij.psi.PsiJavaFile
+import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtJavaFieldSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtTypeAliasSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
+import org.jetbrains.kotlin.analysis.project.structure.KtModule
+import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.FqNameUnsafe
+import org.jetbrains.kotlin.name.Name
+
+@OptIn(KspExperimental::class)
+class ResolverAAImpl(
+ val ktFiles: List<KtFileSymbol>,
+ val javaFiles: List<PsiJavaFile>
+) : Resolver {
+ companion object {
+ lateinit var instance: ResolverAAImpl
+ lateinit var ktModule: KtModule
+ }
+
+ private val ksFiles by lazy {
+ ktFiles.map { KSFileImpl.getCached(it) } + javaFiles.map { KSFileJavaImpl.getCached(it) }
+ }
+
+ // TODO: fix in upstream for builtin types.
+ override val builtIns: KSBuiltIns by lazy {
+ val builtIns = analyze { analysisSession.builtinTypes }
+ object : KSBuiltIns {
+ override val anyType: KSType by lazy { KSTypeImpl.getCached(builtIns.ANY) }
+ override val nothingType: KSType by lazy { KSTypeImpl.getCached(builtIns.NOTHING) }
+ override val unitType: KSType by lazy { KSTypeImpl.getCached(builtIns.UNIT) }
+ override val numberType: KSType by lazy { TODO() }
+ override val byteType: KSType by lazy { KSTypeImpl.getCached(builtIns.BYTE) }
+ override val shortType: KSType by lazy { KSTypeImpl.getCached(builtIns.SHORT) }
+ override val intType: KSType by lazy { KSTypeImpl.getCached(builtIns.INT) }
+ override val longType: KSType by lazy { KSTypeImpl.getCached(builtIns.LONG) }
+ override val floatType: KSType by lazy { KSTypeImpl.getCached(builtIns.FLOAT) }
+ override val doubleType: KSType by lazy { KSTypeImpl.getCached(builtIns.DOUBLE) }
+ override val charType: KSType by lazy { KSTypeImpl.getCached(builtIns.CHAR) }
+ override val booleanType: KSType by lazy { KSTypeImpl.getCached(builtIns.BOOLEAN) }
+ override val stringType: KSType by lazy { KSTypeImpl.getCached(builtIns.STRING) }
+ override val iterableType: KSType by lazy { TODO() }
+ override val annotationType: KSType by lazy { TODO() }
+ override val arrayType: KSType by lazy { TODO() }
+ }
+ }
+
+ override fun createKSTypeReferenceFromKSType(type: KSType): KSTypeReference {
+ TODO("Not yet implemented")
+ }
+
+ override fun effectiveJavaModifiers(declaration: KSDeclaration): Set<Modifier> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getAllFiles(): Sequence<KSFile> {
+ return ksFiles.asSequence()
+ }
+
+ override fun getClassDeclarationByName(name: KSName): KSClassDeclaration? {
+ fun findClass(name: KSName): KtSymbolWithMembers? {
+ if (name.asString() == "") {
+ return null
+ }
+ val parent = name.getQualifier()
+ val simpleName = name.getShortName()
+ val classId = ClassId(FqName(parent), Name.identifier(simpleName))
+ analyze {
+ classId.toKtClassSymbol()
+ }?.let { return it }
+ return (findClass(KSNameImpl.getCached(name.getQualifier())) as? KtNamedClassOrObjectSymbol)?.let {
+ analyze {
+ (
+ it.getStaticMemberScope().getClassifierSymbols { it.asString() == simpleName }.singleOrNull()
+ ?: it.getMemberScope().getClassifierSymbols { it.asString() == simpleName }.singleOrNull()
+ ) as? KtNamedClassOrObjectSymbol
+ ?: it.getStaticMemberScope().getCallableSymbols { it.asString() == simpleName }.singleOrNull()
+ as? KtEnumEntrySymbol
+ }
+ }
+ }
+ return findClass(name)?.let {
+ when (it) {
+ is KtNamedClassOrObjectSymbol -> KSClassDeclarationImpl.getCached(it)
+ is KtEnumEntrySymbol -> KSClassDeclarationEnumEntryImpl.getCached(it)
+ else -> throw IllegalStateException()
+ }
+ }
+ }
+
+ @KspExperimental
+ override fun getDeclarationsFromPackage(packageName: String): Sequence<KSDeclaration> {
+ return analyze {
+ val packageNames = packageName.split(".")
+ var packages = listOf(analysisSession.ROOT_PACKAGE_SYMBOL)
+ for (curName in packageNames) {
+ packages = packages
+ .flatMap { it.getPackageScope().getPackageSymbols { it.asString() == curName } }
+ .distinct()
+ }
+ packages.flatMap {
+ it.getPackageScope().getAllSymbols().distinct().mapNotNull { symbol ->
+ when (symbol) {
+ is KtNamedClassOrObjectSymbol -> KSClassDeclarationImpl.getCached(symbol)
+ is KtFunctionLikeSymbol -> KSFunctionDeclarationImpl.getCached(symbol)
+ is KtPropertySymbol -> KSPropertyDeclarationImpl.getCached(symbol)
+ is KtTypeAliasSymbol -> KSTypeAliasImpl.getCached(symbol)
+ is KtJavaFieldSymbol -> KSPropertyDeclarationJavaImpl.getCached(symbol)
+ else -> null
+ }
+ }
+ }.asSequence()
+ }
+ }
+
+ override fun getDeclarationsInSourceOrder(container: KSDeclarationContainer): Sequence<KSDeclaration> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getFunctionDeclarationsByName(
+ name: KSName,
+ includeTopLevel: Boolean
+ ): Sequence<KSFunctionDeclaration> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getJavaWildcard(reference: KSTypeReference): KSTypeReference {
+ TODO("Not yet implemented")
+ }
+
+ override fun getJvmCheckedException(accessor: KSPropertyAccessor): Sequence<KSType> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getJvmCheckedException(function: KSFunctionDeclaration): Sequence<KSType> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getJvmName(accessor: KSPropertyAccessor): String? {
+ TODO("Not yet implemented")
+ }
+
+ override fun getJvmName(declaration: KSFunctionDeclaration): String? {
+ TODO("Not yet implemented")
+ }
+
+ override fun getKSNameFromString(name: String): KSName {
+ return KSNameImpl.getCached(name)
+ }
+
+ // FIXME: correct implementation after incremental is ready.
+ override fun getNewFiles(): Sequence<KSFile> {
+ return getAllFiles().asSequence()
+ }
+
+ override fun getOwnerJvmClassName(declaration: KSFunctionDeclaration): String? {
+ TODO("Not yet implemented")
+ }
+
+ override fun getOwnerJvmClassName(declaration: KSPropertyDeclaration): String? {
+ TODO("Not yet implemented")
+ }
+
+ override fun getPropertyDeclarationByName(name: KSName, includeTopLevel: Boolean): KSPropertyDeclaration? {
+ TODO("Not yet implemented")
+ }
+
+ // TODO: optimization and type alias handling.
+ override fun getSymbolsWithAnnotation(annotationName: String, inDepth: Boolean): Sequence<KSAnnotated> {
+ val visitor = CollectAnnotatedSymbolsVisitor(inDepth)
+
+ for (file in getNewFiles()) {
+ file.accept(visitor, Unit)
+ }
+
+ return visitor.symbols.asSequence().filter {
+ it.annotations.any {
+ it.annotationType.resolve().declaration.qualifiedName?.asString() == annotationName
+ }
+ }
+ }
+
+ override fun getTypeArgument(typeRef: KSTypeReference, variance: Variance): KSTypeArgument {
+ return KSTypeArgumentLiteImpl.getCached(typeRef, variance)
+ }
+
+ override fun isJavaRawType(type: KSType): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ @KspExperimental
+ override fun mapJavaNameToKotlin(javaName: KSName): KSName? {
+ return JavaToKotlinClassMap.mapJavaToKotlin(FqName(javaName.asString()))?.toKSName()
+ }
+
+ @KspExperimental
+ override fun mapKotlinNameToJava(kotlinName: KSName): KSName? {
+ return JavaToKotlinClassMap.mapKotlinToJava(FqNameUnsafe(kotlinName.asString()))?.toKSName()
+ }
+
+ override fun mapToJvmSignature(declaration: KSDeclaration): String? {
+ TODO("Not yet implemented")
+ }
+
+ override fun overrides(overrider: KSDeclaration, overridee: KSDeclaration): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ override fun overrides(
+ overrider: KSDeclaration,
+ overridee: KSDeclaration,
+ containingClass: KSClassDeclaration
+ ): Boolean {
+ TODO("Not yet implemented")
+ }
+}
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
new file mode 100644
index 00000000..5cb64b01
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/AbstractKSDeclarationImpl.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSFile
+import com.google.devtools.ksp.symbol.KSName
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSTypeParameter
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.toKSModifiers
+import com.intellij.psi.PsiModifierListOwner
+import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
+import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol
+import org.jetbrains.kotlin.psi.KtModifierListOwner
+
+abstract class AbstractKSDeclarationImpl(val ktDeclarationSymbol: KtDeclarationSymbol) : KSDeclaration {
+ override val origin: Origin by lazy {
+ mapAAOrigin(ktDeclarationSymbol)
+ }
+
+ override val location: Location by lazy {
+ ktDeclarationSymbol.psi.toLocation()
+ }
+
+ override val simpleName: KSName by lazy {
+ KSNameImpl.getCached((ktDeclarationSymbol as? KtNamedSymbol)?.name?.asString() ?: "")
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ originalAnnotations
+ }
+
+ override val modifiers: Set<Modifier> by lazy {
+ when (val psi = ktDeclarationSymbol.psi) {
+ is KtModifierListOwner -> psi.toKSModifiers()
+ is PsiModifierListOwner -> psi.toKSModifiers()
+ null -> when (ktDeclarationSymbol) {
+ is KtPropertySymbol -> ktDeclarationSymbol.toModifiers()
+ is KtClassOrObjectSymbol -> ktDeclarationSymbol.toModifiers()
+ is KtFunctionLikeSymbol -> ktDeclarationSymbol.toModifiers()
+ else -> throw IllegalStateException("Unexpected symbol type ${ktDeclarationSymbol.javaClass}")
+ }
+ else -> emptySet()
+ }
+ }
+
+ override val containingFile: KSFile? by lazy {
+ ktDeclarationSymbol.toContainingFile()
+ }
+
+ override val packageName: KSName by lazy {
+ ((containingFile?.packageName ?: ktDeclarationSymbol.getContainingKSSymbol()?.packageName)?.asString() ?: "")
+ .let { KSNameImpl.getCached(it) }
+ }
+
+ override val typeParameters: List<KSTypeParameter> by lazy {
+ ktDeclarationSymbol.typeParameters.map { KSTypeParameterImpl.getCached(it) }
+ }
+
+ override val parentDeclaration: KSDeclaration? by lazy {
+ parent as? KSDeclaration
+ }
+
+ override val parent: KSNode? by lazy {
+ analyze {
+ ktDeclarationSymbol.getContainingSymbol()?.let {
+ KSClassDeclarationImpl.getCached(it as KtNamedClassOrObjectSymbol)
+ } ?: ktDeclarationSymbol.toContainingFile()
+ }
+ }
+
+ override fun toString(): String {
+ return simpleName.asString()
+ }
+
+ override val docString: String?
+ get() = ktDeclarationSymbol.toDocString()
+
+ internal val originalAnnotations = ktDeclarationSymbol.annotations()
+}
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
new file mode 100644
index 00000000..6681facc
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplication
+import org.jetbrains.kotlin.analysis.api.annotations.KtConstantAnnotationValue
+import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue
+import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
+import org.jetbrains.kotlin.analysis.api.components.KtConstantEvaluationMode
+import org.jetbrains.kotlin.analysis.api.components.buildClassType
+import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
+import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*
+import org.jetbrains.kotlin.psi.KtParameter
+
+class KSAnnotationImpl private constructor(private val annotationApplication: KtAnnotationApplication) : KSAnnotation {
+ companion object : KSObjectCache<KtAnnotationApplication, KSAnnotationImpl>() {
+ fun getCached(annotationApplication: KtAnnotationApplication) =
+ cache.getOrPut(annotationApplication) { KSAnnotationImpl(annotationApplication) }
+ }
+
+ override val annotationType: KSTypeReference by lazy {
+ analyze {
+ KSTypeReferenceImpl.getCached(buildClassType(annotationApplication.classId!!))
+ }
+ }
+
+ override val arguments: List<KSValueArgument> by lazy {
+ val presentArgs = annotationApplication.arguments.map { KSValueArgumentImpl.getCached(it) }
+ val presentNames = presentArgs.mapNotNull { it.name?.asString() }
+ val absentArgs = analyze {
+ annotationApplication.classId?.toKtClassSymbol()?.let { symbol ->
+ symbol.getMemberScope().getConstructors().singleOrNull()?.let {
+ it.valueParameters.filter { valueParameter ->
+ valueParameter.name.asString() !in presentNames
+ }.mapNotNull { valueParameterSymbol ->
+ valueParameterSymbol.getDefaultValue()?.let { constantValue ->
+ KSValueArgumentImpl.getCached(
+ KtNamedAnnotationValue(
+ valueParameterSymbol.name, KtConstantAnnotationValue(constantValue)
+ )
+ )
+ }
+ }
+ }
+ } ?: emptyList<KSValueArgument>()
+ }
+ presentArgs + absentArgs
+ }
+
+ override val defaultArguments: List<KSValueArgument>
+ get() = TODO("Not yet implemented")
+
+ override val shortName: KSName by lazy {
+ KSNameImpl.getCached(annotationApplication.classId!!.shortClassName.asString())
+ }
+
+ override val useSiteTarget: AnnotationUseSiteTarget? by lazy {
+ when (annotationApplication.useSiteTarget) {
+ null -> null
+ FILE -> AnnotationUseSiteTarget.FILE
+ PROPERTY -> AnnotationUseSiteTarget.PROPERTY
+ FIELD -> AnnotationUseSiteTarget.FIELD
+ PROPERTY_GETTER -> AnnotationUseSiteTarget.GET
+ PROPERTY_SETTER -> AnnotationUseSiteTarget.SET
+ RECEIVER -> AnnotationUseSiteTarget.RECEIVER
+ CONSTRUCTOR_PARAMETER -> AnnotationUseSiteTarget.PARAM
+ SETTER_PARAMETER -> AnnotationUseSiteTarget.SETPARAM
+ PROPERTY_DELEGATE_FIELD -> AnnotationUseSiteTarget.DELEGATE
+ }
+ }
+
+ override val origin: Origin = Origin.KOTLIN
+
+ override val location: Location by lazy {
+ annotationApplication.psi?.toLocation() ?: NonExistLocation
+ }
+
+ override val parent: KSNode?
+ get() = TODO("Not yet implemented")
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitAnnotation(this, data)
+ }
+
+ override fun toString(): String {
+ return "@${shortName.asString()}"
+ }
+}
+
+internal fun KtValueParameterSymbol.getDefaultValue(): KtConstantValue? {
+ return this.psi?.let {
+ when (it) {
+ is KtParameter -> analyze {
+ it.defaultValue?.evaluate(KtConstantEvaluationMode.CONSTANT_EXPRESSION_EVALUATION)
+ }
+ else -> throw IllegalStateException("Unhandled default value type ${it.javaClass}")
+ }
+ }
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSCallableReferenceImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSCallableReferenceImpl.kt
new file mode 100644
index 00000000..05e78ddc
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSCallableReferenceImpl.kt
@@ -0,0 +1,36 @@
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.IdKeyPair
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.*
+import org.jetbrains.kotlin.analysis.api.types.KtFunctionalType
+import org.jetbrains.kotlin.analysis.api.types.KtType
+
+class KSCallableReferenceImpl private constructor(
+ private val ktFunctionalType: KtFunctionalType,
+ override val parent: KSNode
+) : KSCallableReference {
+ companion object : KSObjectCache<IdKeyPair<KtType, KSNode>, KSCallableReference>() {
+ fun getCached(ktFunctionalType: KtFunctionalType, parent: KSNode): KSCallableReference =
+ cache.getOrPut(IdKeyPair(ktFunctionalType, parent)) { KSCallableReferenceImpl(ktFunctionalType, parent) }
+ }
+ override val receiverType: KSTypeReference?
+ get() = ktFunctionalType.receiverType?.let { KSTypeReferenceImpl.getCached(it) }
+
+ override val functionParameters: List<KSValueParameter>
+ get() = ktFunctionalType.parameterTypes.map {
+ KSValueParameterLiteImpl.getCached(it, this@KSCallableReferenceImpl)
+ }
+
+ override val returnType: KSTypeReference
+ get() = KSTypeReferenceImpl.getCached(ktFunctionalType.returnType)
+
+ override val typeArguments: List<KSTypeArgument>
+ get() = ktFunctionalType.typeArguments().map { KSTypeArgumentImpl.getCached(it, this) }
+
+ override val origin: Origin
+ get() = parent.origin
+
+ override val location: Location
+ get() = parent.location
+}
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
new file mode 100644
index 00000000..57169f24
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationEnumEntryImpl.kt
@@ -0,0 +1,130 @@
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.ClassKind
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSExpectActual
+import com.google.devtools.ksp.symbol.KSFile
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSName
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSTypeArgument
+import com.google.devtools.ksp.symbol.KSTypeParameter
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.symbol.Origin
+import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
+
+class KSClassDeclarationEnumEntryImpl private constructor(private val ktEnumEntrySymbol: KtEnumEntrySymbol) :
+ KSClassDeclaration,
+ AbstractKSDeclarationImpl(ktEnumEntrySymbol),
+ KSExpectActual by KSExpectActualImpl(ktEnumEntrySymbol) {
+ companion object : KSObjectCache<KtEnumEntrySymbol, KSClassDeclarationEnumEntryImpl>() {
+ fun getCached(ktEnumEntrySymbol: KtEnumEntrySymbol) =
+ cache.getOrPut(ktEnumEntrySymbol) { KSClassDeclarationEnumEntryImpl(ktEnumEntrySymbol) }
+ }
+
+ override val qualifiedName: KSName? by lazy {
+ KSNameImpl.getCached("${this.parentDeclaration!!.qualifiedName!!.asString()}.${simpleName.asString()}")
+ }
+
+ override val classKind: ClassKind = ClassKind.ENUM_ENTRY
+
+ override val primaryConstructor: KSFunctionDeclaration? = null
+
+ override val superTypes: Sequence<KSTypeReference> = emptySequence()
+
+ override val isCompanionObject: Boolean = false
+
+ override fun getSealedSubclasses(): Sequence<KSClassDeclaration> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getAllFunctions(): Sequence<KSFunctionDeclaration> {
+ return ktEnumEntrySymbol.declarations().filterIsInstance<KSFunctionDeclaration>()
+ }
+
+ override fun getAllProperties(): Sequence<KSPropertyDeclaration> {
+ return ktEnumEntrySymbol.declarations().filterIsInstance<KSPropertyDeclaration>()
+ }
+
+ override fun asType(typeArguments: List<KSTypeArgument>): KSType {
+ TODO("Not yet implemented")
+ }
+
+ override fun asStarProjectedType(): KSType {
+ TODO("Not yet implemented")
+ }
+
+ override val typeParameters: List<KSTypeParameter> = emptyList()
+
+ override val packageName: KSName by lazy {
+ ktEnumEntrySymbol.toContainingFile()!!.packageName
+ }
+
+ override val parentDeclaration: KSDeclaration? by lazy {
+ analyze {
+ (
+ ktEnumEntrySymbol.getContainingSymbol()
+ as? KtNamedClassOrObjectSymbol
+ )?.let { KSClassDeclarationImpl.getCached(it) }
+ }
+ }
+
+ override val containingFile: KSFile? by lazy {
+ ktEnumEntrySymbol.toContainingFile()
+ }
+
+ override val docString: String?
+ get() = TODO("Not yet implemented")
+
+ override val modifiers: Set<Modifier>
+ get() = TODO("Not yet implemented")
+
+ override val origin: Origin
+ get() = TODO("Not yet implemented")
+
+ override val location: Location by lazy {
+ ktEnumEntrySymbol.psi.toLocation()
+ }
+
+ override val parent: KSNode? by lazy {
+ analyze {
+ (ktEnumEntrySymbol.getContainingSymbol() as? KtNamedClassOrObjectSymbol)
+ ?.let { KSClassDeclarationImpl.getCached(it) }
+ }
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitClassDeclaration(this, data)
+ }
+
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override val isActual: Boolean
+ get() = TODO("Not yet implemented")
+
+ override val isExpect: Boolean
+ get() = TODO("Not yet implemented")
+
+ override fun findActuals(): Sequence<KSDeclaration> {
+ TODO("Not yet implemented")
+ }
+
+ override fun findExpects(): Sequence<KSDeclaration> {
+ TODO("Not yet implemented")
+ }
+
+ override val declarations: Sequence<KSDeclaration> by lazy {
+ // TODO: fix after .getDeclaredMemberScope() works for enum entry with no initializer.
+ emptySequence()
+ }
+}
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
new file mode 100644
index 00000000..3eb20574
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassDeclarationImpl.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import org.jetbrains.kotlin.analysis.api.KtStarTypeProjection
+import org.jetbrains.kotlin.analysis.api.components.buildClassType
+import org.jetbrains.kotlin.analysis.api.symbols.*
+import org.jetbrains.kotlin.psi.KtObjectDeclaration
+
+class KSClassDeclarationImpl private constructor(internal val ktClassOrObjectSymbol: KtClassOrObjectSymbol) :
+ KSClassDeclaration,
+ AbstractKSDeclarationImpl(ktClassOrObjectSymbol),
+ KSExpectActual by KSExpectActualImpl(ktClassOrObjectSymbol) {
+ companion object : KSObjectCache<KtClassOrObjectSymbol, KSClassDeclarationImpl>() {
+ fun getCached(ktClassOrObjectSymbol: KtClassOrObjectSymbol) =
+ cache.getOrPut(ktClassOrObjectSymbol) { KSClassDeclarationImpl(ktClassOrObjectSymbol) }
+ }
+
+ override val qualifiedName: KSName? by lazy {
+ ktClassOrObjectSymbol.classIdIfNonLocal?.asFqNameString()?.let { KSNameImpl.getCached(it) }
+ }
+
+ override val classKind: ClassKind by lazy {
+ when (ktClassOrObjectSymbol.classKind) {
+ KtClassKind.CLASS -> ClassKind.CLASS
+ KtClassKind.ENUM_CLASS -> ClassKind.ENUM_CLASS
+ KtClassKind.ANNOTATION_CLASS -> ClassKind.ANNOTATION_CLASS
+ KtClassKind.INTERFACE -> ClassKind.INTERFACE
+ KtClassKind.COMPANION_OBJECT, KtClassKind.ANONYMOUS_OBJECT, KtClassKind.OBJECT -> ClassKind.OBJECT
+ }
+ }
+
+ override val primaryConstructor: KSFunctionDeclaration? by lazy {
+ if (ktClassOrObjectSymbol.origin == KtSymbolOrigin.JAVA) {
+ null
+ } else {
+ analyze {
+ ktClassOrObjectSymbol.getMemberScope().getConstructors().singleOrNull { it.isPrimary }?.let {
+ KSFunctionDeclarationImpl.getCached(it)
+ }
+ }
+ }
+ }
+
+ override val superTypes: Sequence<KSTypeReference> by lazy {
+ analyze {
+ val supers = ktClassOrObjectSymbol.superTypes.mapIndexed { index, type ->
+ KSTypeReferenceImpl.getCached(type, this@KSClassDeclarationImpl, index)
+ }
+ // AA is returning additional kotlin.Any for java classes, explicitly extending kotlin.Any will result in
+ // compile error, therefore filtering by name should work.
+ // TODO: reconsider how to model super types for interface.
+ if (supers.size > 1) {
+ supers.filterNot { it.resolve().declaration.qualifiedName?.asString() == "kotlin.Any" }
+ } else {
+ supers
+ }.asSequence()
+ }
+ }
+
+ override val isCompanionObject: Boolean by lazy {
+ (ktClassOrObjectSymbol.psi as? KtObjectDeclaration)?.isCompanion() ?: false
+ }
+
+ override fun getSealedSubclasses(): Sequence<KSClassDeclaration> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getAllFunctions(): Sequence<KSFunctionDeclaration> {
+ return ktClassOrObjectSymbol.getAllFunctions()
+ }
+
+ override fun getAllProperties(): Sequence<KSPropertyDeclaration> {
+ return ktClassOrObjectSymbol.getAllProperties()
+ }
+
+ override fun asType(typeArguments: List<KSTypeArgument>): KSType {
+ return analyze {
+ analysisSession.buildClassType(ktClassOrObjectSymbol) {
+ typeArguments.forEach { argument(it.toKtTypeProjection()) }
+ }.let { KSTypeImpl.getCached(it) }
+ }
+ }
+
+ override fun asStarProjectedType(): KSType {
+ return analyze {
+ KSTypeImpl.getCached(
+ analysisSession.buildClassType(ktClassOrObjectSymbol) {
+ var current: KSNode? = this@KSClassDeclarationImpl
+ while (current is KSClassDeclarationImpl) {
+ current.ktClassOrObjectSymbol.typeParameters.forEach {
+ argument(
+ KtStarTypeProjection(
+ (current as KSClassDeclarationImpl).ktClassOrObjectSymbol.token
+ )
+ )
+ }
+ current = if (Modifier.INNER in current.modifiers) {
+ current.parent
+ } else {
+ null
+ }
+ }
+ }
+ )
+ }
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitClassDeclaration(this, data)
+ }
+
+ override val declarations: Sequence<KSDeclaration> by lazy {
+ ktClassOrObjectSymbol.declarations()
+ }
+}
+
+internal fun KtClassOrObjectSymbol.toModifiers(): Set<Modifier> {
+ val result = mutableSetOf<Modifier>()
+ if (this is KtNamedClassOrObjectSymbol) {
+ result.add(modality.toModifier())
+ result.add(visibility.toModifier())
+ if (isInline) {
+ result.add(Modifier.INLINE)
+ }
+ if (isData) {
+ result.add(Modifier.DATA)
+ }
+ if (isExternal) {
+ result.add(Modifier.EXTERNAL)
+ }
+ }
+ if (classKind == KtClassKind.ENUM_CLASS) {
+ result.add(Modifier.ENUM)
+ }
+ return result
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassifierReferenceImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassifierReferenceImpl.kt
new file mode 100644
index 00000000..9c52b305
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSClassifierReferenceImpl.kt
@@ -0,0 +1,37 @@
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.IdKeyPair
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.*
+import org.jetbrains.kotlin.analysis.api.components.buildClassType
+import org.jetbrains.kotlin.analysis.api.types.KtUsualClassType
+
+class KSClassifierReferenceImpl private constructor(
+ internal val ktType: KtUsualClassType,
+ override val parent: KSTypeReference?
+) : KSClassifierReference {
+ companion object : KSObjectCache<IdKeyPair<KtUsualClassType, KSTypeReference?>, KSClassifierReferenceImpl>() {
+ fun getCached(ktType: KtUsualClassType, parent: KSTypeReference?) =
+ cache.getOrPut(IdKeyPair(ktType, parent)) { KSClassifierReferenceImpl(ktType, parent) }
+ }
+ override val qualifier: KSClassifierReference? by lazy {
+ ktType.classId.outerClassId?.let {
+ analyze {
+ buildClassType(it)
+ }
+ }?.let { getCached(it as KtUsualClassType, parent) }
+ }
+
+ override fun referencedName(): String {
+ return ktType.classId.asFqNameString()
+ }
+
+ override val typeArguments: List<KSTypeArgument> by lazy {
+ ktType.typeArguments().map { KSTypeArgumentImpl.getCached(it, this) }
+ }
+
+ override val origin: Origin = parent?.origin ?: Origin.SYNTHETIC
+
+ override val location: Location
+ get() = parent?.location ?: NonExistLocation
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSDynamicReferenceImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSDynamicReferenceImpl.kt
new file mode 100644
index 00000000..6dd65e60
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSDynamicReferenceImpl.kt
@@ -0,0 +1,26 @@
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.*
+
+class KSDynamicReferenceImpl private constructor(override val parent: KSNode?) : KSDynamicReference {
+ companion object : KSObjectCache<KSTypeReference, KSDynamicReferenceImpl>() {
+ fun getCached(parent: KSTypeReference) = cache.getOrPut(parent) { KSDynamicReferenceImpl(parent) }
+ }
+
+ override val origin = Origin.KOTLIN
+
+ override val location: Location by lazy {
+ NonExistLocation
+ }
+
+ override val typeArguments: List<KSTypeArgument> = emptyList()
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitDynamicReference(this, data)
+ }
+
+ override fun toString(): String {
+ return "<dynamic type>"
+ }
+}
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
new file mode 100644
index 00000000..1fae5450
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorType.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.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
+
+object KSErrorType : KSType {
+ override val declaration: KSDeclaration
+ get() = KSErrorTypeClassDeclaration
+
+ override val nullability: Nullability
+ get() = Nullability.NULLABLE
+
+ override val arguments: List<KSTypeArgument>
+ get() = emptyList()
+
+ override val annotations: Sequence<KSAnnotation>
+ get() = emptySequence()
+
+ override fun isAssignableFrom(that: KSType): Boolean = false
+
+ override fun isMutabilityFlexible(): Boolean = false
+
+ override fun isCovarianceFlexible(): Boolean = false
+
+ override fun replace(arguments: List<KSTypeArgument>): KSType = this
+
+ override fun starProjection(): KSType = this
+
+ override fun makeNullable(): KSType = this
+
+ override fun makeNotNullable(): KSType = this
+
+ override val isMarkedNullable: Boolean = false
+
+ override val isError: Boolean = true
+
+ override val isFunctionType: Boolean = false
+
+ override val isSuspendFunctionType: Boolean = false
+
+ override fun toString(): String {
+ return "<ERROR TYPE>"
+ }
+}
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
new file mode 100644
index 00000000..fe2d9c9f
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSErrorTypeClassDeclaration.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.impl.ResolverAAImpl
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+
+object KSErrorTypeClassDeclaration : KSClassDeclaration {
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override val classKind: ClassKind = ClassKind.CLASS
+
+ override val containingFile: KSFile? = null
+
+ override val declarations: Sequence<KSDeclaration> = emptySequence()
+
+ override val isActual: Boolean = false
+
+ override val isExpect: Boolean = false
+
+ override val isCompanionObject: Boolean = false
+
+ override val location: Location = NonExistLocation
+
+ override val parent: KSNode? = null
+
+ override val modifiers: Set<Modifier> = emptySet()
+
+ override val origin: Origin = Origin.SYNTHETIC
+
+ override val packageName: KSName = KSNameImpl.getCached("")
+
+ override val parentDeclaration: KSDeclaration? = null
+
+ override val primaryConstructor: KSFunctionDeclaration? = null
+
+ override val qualifiedName: KSName? = null
+
+ override val simpleName: KSName = KSNameImpl.getCached("<Error>")
+
+ override val superTypes: Sequence<KSTypeReference> = emptySequence()
+
+ override val typeParameters: List<KSTypeParameter> = emptyList()
+
+ override fun getSealedSubclasses(): Sequence<KSClassDeclaration> = emptySequence()
+
+ override fun asStarProjectedType(): KSType {
+ return ResolverAAImpl.instance.builtIns.nothingType
+ }
+
+ override fun asType(typeArguments: List<KSTypeArgument>): KSType {
+ return ResolverAAImpl.instance.builtIns.nothingType
+ }
+
+ override fun findActuals(): Sequence<KSDeclaration> {
+ return emptySequence()
+ }
+
+ override fun findExpects(): Sequence<KSDeclaration> {
+ return emptySequence()
+ }
+
+ override fun getAllFunctions(): Sequence<KSFunctionDeclaration> {
+ return emptySequence()
+ }
+
+ override fun getAllProperties(): Sequence<KSPropertyDeclaration> {
+ return emptySequence()
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitClassDeclaration(this, data)
+ }
+
+ override fun toString(): String {
+ return "Error type synthetic declaration"
+ }
+
+ override val docString = null
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSExpectActualImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSExpectActualImpl.kt
new file mode 100644
index 00000000..d53a4472
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSExpectActualImpl.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSExpectActual
+import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol
+
+class KSExpectActualImpl(private val declarationSymbol: KtDeclarationSymbol) : KSExpectActual {
+ override val isActual: Boolean
+ get() = TODO("Not yet implemented")
+
+ override val isExpect: Boolean
+ get() = TODO("Not yet implemented")
+
+ override fun findActuals(): Sequence<KSDeclaration> {
+ TODO("Not yet implemented")
+ }
+
+ override fun findExpects(): Sequence<KSDeclaration> {
+ TODO("Not yet implemented")
+ }
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileImpl.kt
new file mode 100644
index 00000000..9146b319
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileImpl.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSFile
+import com.google.devtools.ksp.symbol.KSName
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.Origin
+import com.intellij.psi.PsiFile
+import com.intellij.psi.PsiJavaFile
+import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtTypeAliasSymbol
+import org.jetbrains.kotlin.psi.KtFile
+
+class KSFileImpl private constructor(private val ktFileSymbol: KtFileSymbol) : KSFile {
+ companion object : KSObjectCache<KtFileSymbol, KSFileImpl>() {
+ fun getCached(ktFileSymbol: KtFileSymbol) = cache.getOrPut(ktFileSymbol) { KSFileImpl(ktFileSymbol) }
+ }
+
+ private val psi: PsiFile
+ get() = ktFileSymbol.psi as PsiFile
+
+ override val packageName: KSName by lazy {
+ when (psi) {
+ is KtFile -> KSNameImpl.getCached((psi as KtFile).packageFqName.asString())
+ is PsiJavaFile -> KSNameImpl.getCached((psi as PsiJavaFile).packageName)
+ else -> throw IllegalStateException("Unhandled psi file type ${psi.javaClass}")
+ }
+ }
+
+ override val fileName: String by lazy {
+ psi.name
+ }
+
+ override val filePath: String by lazy {
+ psi.virtualFile.path
+ }
+
+ override val declarations: Sequence<KSDeclaration> by lazy {
+ analyze {
+ ktFileSymbol.getFileScope().getAllSymbols().map {
+ when (it) {
+ is KtNamedClassOrObjectSymbol -> KSClassDeclarationImpl.getCached(it)
+ is KtFunctionSymbol -> KSFunctionDeclarationImpl.getCached(it)
+ is KtPropertySymbol -> KSPropertyDeclarationImpl.getCached(it)
+ is KtTypeAliasSymbol -> KSTypeAliasImpl.getCached(it)
+ else -> throw IllegalStateException("Unhandled ${it.javaClass}")
+ }
+ }
+ }
+ }
+
+ override val origin: Origin = Origin.KOTLIN
+
+ override val location: Location by lazy {
+ ktFileSymbol.psi.toLocation()
+ }
+
+ override val parent: KSNode? = null
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitFile(this, data)
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ ktFileSymbol.annotations()
+ }
+
+ override fun toString(): String {
+ return "File: ${this.fileName}"
+ }
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileJavaImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileJavaImpl.kt
new file mode 100644
index 00000000..29b6fc94
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFileJavaImpl.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSFile
+import com.google.devtools.ksp.symbol.KSName
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.Origin
+import com.intellij.psi.PsiJavaFile
+
+class KSFileJavaImpl private constructor(private val psi: PsiJavaFile) : KSFile {
+ companion object : KSObjectCache<PsiJavaFile, KSFileJavaImpl>() {
+ fun getCached(psi: PsiJavaFile) = cache.getOrPut(psi) { KSFileJavaImpl(psi) }
+ }
+
+ override val packageName: KSName = KSNameImpl.getCached(psi.packageName)
+
+ override val fileName: String = psi.name
+
+ override val filePath: String = psi.virtualFile.path
+
+ override val declarations: Sequence<KSDeclaration> by lazy {
+ psi.classes.asSequence().mapNotNull { psi ->
+ analyze {
+ psi.getNamedClassSymbol()?.let { KSClassDeclarationImpl.getCached(it) }
+ }
+ }
+ }
+
+ override val origin: Origin = Origin.JAVA
+
+ override val location: Location = psi.toLocation()
+
+ override val parent: KSNode? = null
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitFile(this, data)
+ }
+
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override fun toString(): String {
+ return "File: ${this.fileName}"
+ }
+}
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
new file mode 100644
index 00000000..aba47f83
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFunctionDeclarationImpl.kt
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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.
+ */
+
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import com.intellij.psi.PsiClass
+import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirFunctionSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.*
+import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind
+import org.jetbrains.kotlin.descriptors.Modality
+import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
+import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
+import org.jetbrains.kotlin.fir.java.resolveIfJavaType
+import org.jetbrains.kotlin.fir.resolve.getContainingClass
+import org.jetbrains.kotlin.fir.symbols.SymbolInternals
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtFunction
+
+class KSFunctionDeclarationImpl private constructor(internal val ktFunctionSymbol: KtFunctionLikeSymbol) :
+ KSFunctionDeclaration,
+ AbstractKSDeclarationImpl(ktFunctionSymbol),
+ KSExpectActual by KSExpectActualImpl(ktFunctionSymbol) {
+ companion object : KSObjectCache<KtFunctionLikeSymbol, KSFunctionDeclarationImpl>() {
+ fun getCached(ktFunctionSymbol: KtFunctionLikeSymbol) =
+ cache.getOrPut(ktFunctionSymbol) { KSFunctionDeclarationImpl(ktFunctionSymbol) }
+ }
+
+ override val functionKind: FunctionKind by lazy {
+ when (ktFunctionSymbol.symbolKind) {
+ KtSymbolKind.CLASS_MEMBER -> FunctionKind.MEMBER
+ KtSymbolKind.TOP_LEVEL -> FunctionKind.TOP_LEVEL
+ KtSymbolKind.SAM_CONSTRUCTOR -> FunctionKind.LAMBDA
+ else -> throw IllegalStateException("Unexpected symbol kind ${ktFunctionSymbol.symbolKind}")
+ }
+ }
+
+ override val isAbstract: Boolean by lazy {
+ (ktFunctionSymbol as? KtFunctionSymbol)?.modality == Modality.ABSTRACT
+ }
+
+ override val extensionReceiver: KSTypeReference? by lazy {
+ analyze {
+ if (!ktFunctionSymbol.isExtension) {
+ null
+ } else {
+ ktFunctionSymbol.receiverType?.let {
+ KSTypeReferenceImpl.getCached(it, this@KSFunctionDeclarationImpl)
+ }
+ }
+ }
+ }
+
+ @OptIn(SymbolInternals::class)
+ override val returnType: KSTypeReference? by lazy {
+ // FIXME: temporary workaround before upstream fixes java type refs.
+ if (origin == Origin.JAVA) {
+ if (ktFunctionSymbol is KtFirFunctionSymbol) {
+ (ktFunctionSymbol.firSymbol.fir as? FirJavaMethod)?.also {
+ it.returnTypeRef = it.returnTypeRef.resolveIfJavaType(
+ it.moduleData.session,
+ (it.getContainingClass(it.moduleData.session) as FirJavaClass).javaTypeParameterStack
+ )
+ }
+ }
+ }
+ analyze {
+ // Constructors
+ if (ktFunctionSymbol is KtConstructorSymbol) {
+ ((parentDeclaration as KSClassDeclaration).asStarProjectedType() as KSTypeImpl).type
+ } else {
+ ktFunctionSymbol.returnType
+ }.let { KSTypeReferenceImpl.getCached(it, this@KSFunctionDeclarationImpl) }
+ }
+ }
+
+ override val parameters: List<KSValueParameter> by lazy {
+ ktFunctionSymbol.valueParameters.map { KSValueParameterImpl.getCached(it, this) }
+ }
+
+ override fun findOverridee(): KSDeclaration? {
+ TODO("Not yet implemented")
+ }
+
+ override fun asMemberOf(containing: KSType): KSFunction {
+ TODO("Not yet implemented")
+ }
+
+ override val simpleName: KSName by lazy {
+ if (ktFunctionSymbol is KtFunctionSymbol) {
+ KSNameImpl.getCached(ktFunctionSymbol.name.asString())
+ } else {
+ KSNameImpl.getCached("<init>")
+ }
+ }
+
+ override val qualifiedName: KSName? by lazy {
+ KSNameImpl.getCached("${parentDeclaration?.qualifiedName?.asString()}.${this.simpleName.asString()}")
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitFunctionDeclaration(this, data)
+ }
+
+ override val declarations: Sequence<KSDeclaration> by lazy {
+ val psi = ktFunctionSymbol.psi as? KtFunction ?: return@lazy emptySequence()
+ if (!psi.hasBlockBody()) {
+ emptySequence()
+ } else {
+ psi.bodyBlockExpression?.statements?.asSequence()?.filterIsInstance<KtDeclaration>()?.mapNotNull {
+ analyze {
+ it.getSymbol().toKSDeclaration()
+ }
+ } ?: emptySequence()
+ }
+ }
+
+ private fun isSyntheticConstructor(): Boolean {
+ return origin == Origin.SYNTHETIC ||
+ (origin == Origin.JAVA && ktFunctionSymbol.psi == null || ktFunctionSymbol.psi is PsiClass)
+ }
+
+ override fun toString(): String {
+ // TODO: fix origin for implicit Java constructor in AA
+ // TODO: should we change the toString() behavior for synthetic constructors?
+ return if (isSyntheticConstructor()) {
+ "synthetic constructor for ${this.parentDeclaration}"
+ } else {
+ this.simpleName.asString()
+ }
+ }
+
+ override val docString: String? by lazy {
+ if (isSyntheticConstructor()) {
+ parentDeclaration?.docString
+ } else {
+ super.docString
+ }
+ }
+}
+
+internal fun KtFunctionLikeSymbol.toModifiers(): Set<Modifier> {
+ val result = mutableSetOf<Modifier>()
+ if (this is KtFunctionSymbol) {
+ result.add(visibility.toModifier())
+ result.add(modality.toModifier())
+ if (isExternal) {
+ result.add(Modifier.EXTERNAL)
+ }
+ if (isInfix) {
+ result.add(Modifier.INFIX)
+ }
+ if (isInline) {
+ result.add(Modifier.INLINE)
+ }
+ if (isStatic) {
+ result.add(Modifier.JAVA_STATIC)
+ }
+ if (isSuspend) {
+ result.add(Modifier.SUSPEND)
+ }
+ if (isOperator) {
+ result.add(Modifier.OPERATOR)
+ }
+ if (isOperator) {
+ result.add(Modifier.OVERRIDE)
+ }
+ }
+ 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
new file mode 100644
index 00000000..baccc76c
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyAccessorImpl.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.toKSModifiers
+import org.jetbrains.kotlin.analysis.api.annotations.annotations
+import org.jetbrains.kotlin.analysis.api.symbols.KtPropertyAccessorSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtPropertyGetterSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySetterSymbol
+import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
+import org.jetbrains.kotlin.psi.KtModifierListOwner
+
+abstract class KSPropertyAccessorImpl(
+ private val ktPropertyAccessorSymbol: KtPropertyAccessorSymbol,
+ override val receiver: KSPropertyDeclaration
+) : KSPropertyAccessor {
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ ktPropertyAccessorSymbol.annotations.asSequence()
+ .filter { it.useSiteTarget != AnnotationUseSiteTarget.SETTER_PARAMETER }
+ .map { KSAnnotationImpl.getCached(it) }
+ .plus(findAnnotationFromUseSiteTarget())
+ }
+
+ internal val originalAnnotations = ktPropertyAccessorSymbol.annotations()
+
+ override val location: Location by lazy {
+ ktPropertyAccessorSymbol.psi?.toLocation() ?: NonExistLocation
+ }
+
+ override val modifiers: Set<Modifier> by lazy {
+ ((ktPropertyAccessorSymbol.psi as? KtModifierListOwner)?.toKSModifiers() ?: emptySet()).let {
+ if (origin == Origin.SYNTHETIC &&
+ (receiver.parentDeclaration as? KSClassDeclaration)?.classKind == ClassKind.INTERFACE
+ ) {
+ it + Modifier.ABSTRACT
+ } else {
+ it
+ }
+ }
+ }
+
+ override val origin: Origin by lazy {
+ val symbolOrigin = mapAAOrigin(ktPropertyAccessorSymbol)
+ if (symbolOrigin == Origin.KOTLIN && ktPropertyAccessorSymbol.psi == null) {
+ Origin.SYNTHETIC
+ } else {
+ symbolOrigin
+ }
+ }
+
+ override val parent: KSNode?
+ get() = ktPropertyAccessorSymbol.getContainingKSSymbol()
+}
+
+class KSPropertySetterImpl private constructor(
+ owner: KSPropertyDeclaration,
+ setter: KtPropertySetterSymbol
+) : KSPropertyAccessorImpl(setter, owner), KSPropertySetter {
+ companion object : KSObjectCache<Pair<KSPropertyDeclaration, KtPropertySetterSymbol>, KSPropertySetterImpl>() {
+ fun getCached(owner: KSPropertyDeclaration, setter: KtPropertySetterSymbol) =
+ cache.getOrPut(Pair(owner, setter)) { KSPropertySetterImpl(owner, setter) }
+ }
+
+ override val parameter: KSValueParameter by lazy {
+ KSValueParameterImpl.getCached(setter.parameter, this)
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertySetter(this, data)
+ }
+
+ override fun toString(): String {
+ return "$receiver.setter()"
+ }
+}
+
+class KSPropertyGetterImpl private constructor(
+ owner: KSPropertyDeclaration,
+ getter: KtPropertyGetterSymbol
+) : KSPropertyAccessorImpl(getter, owner), KSPropertyGetter {
+ companion object : KSObjectCache<Pair<KSPropertyDeclaration, KtPropertyGetterSymbol>, KSPropertyGetterImpl>() {
+ fun getCached(owner: KSPropertyDeclaration, getter: KtPropertyGetterSymbol) =
+ cache.getOrPut(Pair(owner, getter)) { KSPropertyGetterImpl(owner, getter) }
+ }
+
+ override val returnType: KSTypeReference? by lazy {
+ KSTypeReferenceImpl.getCached(getter.returnType, this@KSPropertyGetterImpl)
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertyGetter(this, data)
+ }
+
+ override fun toString(): String {
+ return "$receiver.getter()"
+ }
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationImpl.kt
new file mode 100644
index 00000000..e1d51e82
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationImpl.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import com.intellij.psi.PsiClass
+import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplication
+import org.jetbrains.kotlin.analysis.api.annotations.annotations
+import org.jetbrains.kotlin.analysis.api.symbols.KtKotlinPropertySymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
+import org.jetbrains.kotlin.analysis.api.symbols.receiverType
+import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
+
+class KSPropertyDeclarationImpl private constructor(internal val ktPropertySymbol: KtPropertySymbol) :
+ KSPropertyDeclaration,
+ AbstractKSDeclarationImpl(ktPropertySymbol),
+ KSExpectActual by KSExpectActualImpl(ktPropertySymbol) {
+ companion object : KSObjectCache<KtPropertySymbol, KSPropertyDeclarationImpl>() {
+ fun getCached(ktPropertySymbol: KtPropertySymbol) =
+ cache.getOrPut(ktPropertySymbol) { KSPropertyDeclarationImpl(ktPropertySymbol) }
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ ktPropertySymbol.annotations.asSequence()
+ .filter { !it.isUseSiteTargetAnnotation() }
+ .map { KSAnnotationImpl.getCached(it) }
+ .filterNot { valueParameterAnnotation ->
+ valueParameterAnnotation.annotationType.resolve().declaration.annotations.any { metaAnnotation ->
+ metaAnnotation.annotationType.resolve().declaration.qualifiedName
+ ?.asString() == "kotlin.annotation.Target" &&
+ (metaAnnotation.arguments.singleOrNull()?.value as? ArrayList<*>)?.any {
+ (it as? KSClassDeclaration)?.qualifiedName
+ ?.asString() == "kotlin.annotation.AnnotationTarget.VALUE_PARAMETER"
+ } ?: false
+ }
+ }
+ }
+
+ override val getter: KSPropertyGetter? by lazy {
+ if (ktPropertySymbol.psi is PsiClass) {
+ null
+ } else {
+ ktPropertySymbol.getter?.let { KSPropertyGetterImpl.getCached(this, it) }
+ }
+ }
+
+ override val setter: KSPropertySetter? by lazy {
+ if (ktPropertySymbol.psi is PsiClass) {
+ null
+ } else {
+ ktPropertySymbol.setter?.let { KSPropertySetterImpl.getCached(this, it) }
+ }
+ }
+
+ override val extensionReceiver: KSTypeReference? by lazy {
+ ktPropertySymbol.receiverType?.let { KSTypeReferenceImpl.getCached(it, this@KSPropertyDeclarationImpl) }
+ }
+
+ override val type: KSTypeReference by lazy {
+ KSTypeReferenceImpl.getCached(ktPropertySymbol.returnType, this@KSPropertyDeclarationImpl)
+ }
+
+ override val isMutable: Boolean by lazy {
+ !ktPropertySymbol.isVal
+ }
+
+ override val hasBackingField: Boolean by lazy {
+ ktPropertySymbol.hasBackingField
+ }
+
+ override fun isDelegated(): Boolean {
+ return ktPropertySymbol.isDelegatedProperty
+ }
+
+ override fun findOverridee(): KSPropertyDeclaration? {
+ TODO("Not yet implemented")
+ }
+
+ override fun asMemberOf(containing: KSType): KSType {
+ TODO("Not yet implemented")
+ }
+
+ override val qualifiedName: KSName? by lazy {
+ KSNameImpl.getCached("${parentDeclaration?.qualifiedName?.asString()}.${this.simpleName.asString()}")
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertyDeclaration(this, data)
+ }
+}
+
+internal fun KtAnnotationApplication.isUseSiteTargetAnnotation(): Boolean {
+ return this.useSiteTarget?.let {
+ it == AnnotationUseSiteTarget.PROPERTY_GETTER ||
+ it == AnnotationUseSiteTarget.PROPERTY_SETTER ||
+ it == AnnotationUseSiteTarget.SETTER_PARAMETER ||
+ it == AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER
+ } ?: false
+}
+
+internal fun KtPropertySymbol.toModifiers(): Set<Modifier> {
+ val result = mutableSetOf<Modifier>()
+ result.add(visibility.toModifier())
+ if (isOverride) {
+ result.add(Modifier.OVERRIDE)
+ }
+ if (isStatic) {
+ Modifier.JAVA_STATIC
+ }
+ result.add(modality.toModifier())
+
+ if (this is KtKotlinPropertySymbol) {
+ if (isLateInit) {
+ result.add(Modifier.LATEINIT)
+ }
+ if (isConst) {
+ result.add(Modifier.CONST)
+ }
+ }
+ return result
+}
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
new file mode 100644
index 00000000..a34abf95
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationJavaImpl.kt
@@ -0,0 +1,78 @@
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirJavaFieldSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtJavaFieldSymbol
+import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
+import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
+import org.jetbrains.kotlin.fir.java.resolveIfJavaType
+import org.jetbrains.kotlin.fir.resolve.getContainingClass
+import org.jetbrains.kotlin.fir.symbols.SymbolInternals
+
+class KSPropertyDeclarationJavaImpl private constructor(private val ktJavaFieldSymbol: KtJavaFieldSymbol) :
+ KSPropertyDeclaration,
+ AbstractKSDeclarationImpl(ktJavaFieldSymbol),
+ KSExpectActual by KSExpectActualImpl(ktJavaFieldSymbol) {
+ companion object : KSObjectCache<KtJavaFieldSymbol, KSPropertyDeclaration>() {
+ fun getCached(ktJavaFieldSymbol: KtJavaFieldSymbol): KSPropertyDeclaration =
+ cache.getOrPut(ktJavaFieldSymbol) { KSPropertyDeclarationJavaImpl(ktJavaFieldSymbol) }
+ }
+ override val getter: KSPropertyGetter?
+ get() = null
+
+ override val setter: KSPropertySetter?
+ get() = null
+
+ override val extensionReceiver: KSTypeReference?
+ get() = null
+
+ @OptIn(SymbolInternals::class)
+ override val type: KSTypeReference by lazy {
+ // FIXME: temporary workaround before upstream fixes java type refs.
+ ((ktJavaFieldSymbol as KtFirJavaFieldSymbol).firSymbol.fir as FirJavaField).also {
+ it.returnTypeRef = it.returnTypeRef.resolveIfJavaType(
+ it.moduleData.session,
+ (it.getContainingClass(it.moduleData.session) as FirJavaClass).javaTypeParameterStack
+ )
+ }
+ KSTypeReferenceImpl.getCached(ktJavaFieldSymbol.returnType, this@KSPropertyDeclarationJavaImpl)
+ }
+
+ override val isMutable: Boolean
+ get() = !modifiers.contains(Modifier.FINAL)
+
+ override val hasBackingField: Boolean
+ get() = true
+
+ override fun isDelegated(): Boolean {
+ return false
+ }
+
+ override fun findOverridee(): KSPropertyDeclaration? {
+ TODO("Not yet implemented")
+ }
+
+ override fun asMemberOf(containing: KSType): KSType {
+ TODO("Not yet implemented")
+ }
+
+ override val typeParameters: List<KSTypeParameter>
+ get() = emptyList()
+
+ override val qualifiedName: KSName? by lazy {
+ KSNameImpl.getCached("${this.parentDeclaration!!.qualifiedName!!.asString()}.${simpleName.asString()}")
+ }
+
+ override val packageName: KSName
+ get() = KSNameImpl.getCached(ktJavaFieldSymbol.callableIdIfNonLocal?.packageName?.asString() ?: "")
+
+ override val origin: Origin
+ get() = Origin.JAVA
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertyDeclaration(this, data)
+ }
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationLocalVariableImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationLocalVariableImpl.kt
new file mode 100644
index 00000000..b6b4c175
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSPropertyDeclarationLocalVariableImpl.kt
@@ -0,0 +1,54 @@
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.KSExpectActual
+import com.google.devtools.ksp.symbol.KSName
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSPropertyGetter
+import com.google.devtools.ksp.symbol.KSPropertySetter
+import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSVisitor
+import org.jetbrains.kotlin.analysis.api.symbols.KtLocalVariableSymbol
+
+class KSPropertyDeclarationLocalVariableImpl private constructor(
+ private val ktLocalVariableSymbol: KtLocalVariableSymbol
+) : KSPropertyDeclaration,
+ AbstractKSDeclarationImpl(ktLocalVariableSymbol),
+ KSExpectActual by KSExpectActualImpl(ktLocalVariableSymbol) {
+ companion object : KSObjectCache<KtLocalVariableSymbol, KSPropertyDeclarationLocalVariableImpl>() {
+ fun getCached(ktLocalVariableSymbol: KtLocalVariableSymbol) =
+ cache.getOrPut(ktLocalVariableSymbol) { KSPropertyDeclarationLocalVariableImpl(ktLocalVariableSymbol) }
+ }
+
+ override val getter: KSPropertyGetter? = null
+
+ override val setter: KSPropertySetter? = null
+
+ override val extensionReceiver: KSTypeReference? = null
+
+ override val type: KSTypeReference by lazy {
+ KSTypeReferenceImpl.getCached(ktLocalVariableSymbol.returnType)
+ }
+
+ override val isMutable: Boolean = !ktLocalVariableSymbol.isVal
+
+ override val hasBackingField: Boolean = false
+
+ override fun isDelegated(): Boolean = false
+
+ override fun findOverridee() = null
+
+ override fun asMemberOf(containing: KSType): KSType {
+ TODO("Not yet implemented")
+ }
+
+ override val qualifiedName: KSName? by lazy {
+ KSNameImpl.getCached("${parentDeclaration?.qualifiedName?.asString()}.${this.simpleName.asString()}")
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitPropertyDeclaration(this, data)
+ }
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeAliasImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeAliasImpl.kt
new file mode 100644
index 00000000..f0b6cc5f
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeAliasImpl.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.KSExpectActual
+import com.google.devtools.ksp.symbol.KSName
+import com.google.devtools.ksp.symbol.KSTypeAlias
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSVisitor
+import org.jetbrains.kotlin.analysis.api.symbols.KtTypeAliasSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.nameOrAnonymous
+
+class KSTypeAliasImpl private constructor(private val ktTypeAliasSymbol: KtTypeAliasSymbol) :
+ KSTypeAlias,
+ AbstractKSDeclarationImpl(ktTypeAliasSymbol),
+ KSExpectActual by KSExpectActualImpl(ktTypeAliasSymbol) {
+ companion object : KSObjectCache<KtTypeAliasSymbol, KSTypeAliasImpl>() {
+ fun getCached(ktTypeAliasSymbol: KtTypeAliasSymbol) =
+ cache.getOrPut(ktTypeAliasSymbol) { KSTypeAliasImpl(ktTypeAliasSymbol) }
+ }
+
+ override val name: KSName by lazy {
+ KSNameImpl.getCached(ktTypeAliasSymbol.nameOrAnonymous.asString())
+ }
+
+ override val type: KSTypeReference by lazy {
+ KSTypeReferenceImpl.getCached(ktTypeAliasSymbol.expandedType, this)
+ }
+
+ override val simpleName: KSName
+ get() = name
+
+ override val qualifiedName: KSName? by lazy {
+ ktTypeAliasSymbol.classIdIfNonLocal?.asFqNameString()?.let { KSNameImpl.getCached(it) }
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeAlias(this, data)
+ }
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeArgumentImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeArgumentImpl.kt
new file mode 100644
index 00000000..ef8aa3eb
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeArgumentImpl.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.IdKeyPair
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSTypeArgument
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.Variance
+import org.jetbrains.kotlin.analysis.api.KtStarTypeProjection
+import org.jetbrains.kotlin.analysis.api.KtTypeArgumentWithVariance
+import org.jetbrains.kotlin.analysis.api.KtTypeProjection
+
+class KSTypeArgumentImpl private constructor(
+ private val ktTypeProjection: KtTypeProjection,
+ override val parent: KSNode?
+) : KSTypeArgument {
+ companion object : KSObjectCache<IdKeyPair<KtTypeProjection, KSNode?>, KSTypeArgumentImpl>() {
+ fun getCached(ktTypeProjection: KtTypeProjection, parent: KSNode? = null) =
+ cache.getOrPut(IdKeyPair(ktTypeProjection, parent)) { KSTypeArgumentImpl(ktTypeProjection, parent) }
+ }
+
+ override val variance: Variance by lazy {
+ when (ktTypeProjection) {
+ is KtStarTypeProjection -> Variance.STAR
+ is KtTypeArgumentWithVariance -> {
+ when (ktTypeProjection.variance) {
+ org.jetbrains.kotlin.types.Variance.INVARIANT -> Variance.INVARIANT
+ org.jetbrains.kotlin.types.Variance.IN_VARIANCE -> Variance.CONTRAVARIANT
+ org.jetbrains.kotlin.types.Variance.OUT_VARIANCE -> Variance.COVARIANT
+ else -> throw IllegalStateException("Unexpected variance")
+ }
+ }
+ }
+ }
+
+ override val type: KSTypeReference? by lazy {
+ ktTypeProjection.type?.let { KSTypeReferenceImpl.getCached(it, this@KSTypeArgumentImpl) }
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ ktTypeProjection.type?.annotations() ?: emptySequence()
+ }
+
+ override val origin: Origin = parent?.origin ?: Origin.SYNTHETIC
+
+ override val location: Location
+ get() = TODO("Not yet implemented")
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeArgument(this, data)
+ }
+
+ override fun toString(): String {
+ return "$variance $type"
+ }
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeArgumentLiteImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeArgumentLiteImpl.kt
new file mode 100644
index 00000000..5eb239e1
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeArgumentLiteImpl.kt
@@ -0,0 +1,33 @@
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSTypeArgument
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSVisitor
+import com.google.devtools.ksp.symbol.Location
+import com.google.devtools.ksp.symbol.NonExistLocation
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.Variance
+
+class KSTypeArgumentLiteImpl private constructor(override val type: KSTypeReference, override val variance: Variance) :
+ KSTypeArgument {
+ companion object : KSObjectCache<Pair<KSTypeReference, Variance>, KSTypeArgument>() {
+ fun getCached(type: KSTypeReference, variance: Variance) = cache.getOrPut(Pair(type, variance)) {
+ KSTypeArgumentLiteImpl(type, variance)
+ }
+ }
+
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override val origin: Origin = Origin.SYNTHETIC
+
+ override val location: Location = NonExistLocation
+
+ override val parent: KSNode? = null
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeArgument(this, data)
+ }
+}
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
new file mode 100644
index 00000000..8ec76268
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeImpl.kt
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.IdKeyPair
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.impl.symbol.kotlin.synthetic.ExtensionFunctionTypeAnnotation
+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 org.jetbrains.kotlin.analysis.api.KtStarTypeProjection
+import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationsList
+import org.jetbrains.kotlin.analysis.api.components.buildClassType
+import org.jetbrains.kotlin.analysis.api.symbols.*
+import org.jetbrains.kotlin.analysis.api.types.*
+
+class KSTypeImpl private constructor(internal val type: KtType) : KSType {
+ companion object : KSObjectCache<IdKeyPair<KtType, KtAnnotationsList>, KSTypeImpl>() {
+ fun getCached(type: KtType): KSTypeImpl = cache.getOrPut(IdKeyPair(type, type.annotationsList)) {
+ KSTypeImpl(type)
+ }
+ }
+
+ private fun KtType.toDeclaration(): KSDeclaration {
+ return analyze {
+ when (this@toDeclaration) {
+ is KtNonErrorClassType -> {
+ when (val symbol = this@toDeclaration.classSymbol) {
+ is KtTypeAliasSymbol -> KSTypeAliasImpl.getCached(symbol)
+ is KtClassOrObjectSymbol -> KSClassDeclarationImpl.getCached(symbol)
+ }
+ }
+ is KtTypeParameterType -> KSTypeParameterImpl.getCached(symbol)
+ is KtClassErrorType -> KSErrorTypeClassDeclaration
+ is KtFlexibleType ->
+ type.lowerBoundIfFlexible().toDeclaration()
+ else -> KSErrorTypeClassDeclaration
+ }
+ }
+ }
+
+ override val declaration: KSDeclaration by lazy {
+ type.toDeclaration()
+ }
+
+ override val nullability: Nullability by lazy {
+ if (type.nullability == KtTypeNullability.NON_NULLABLE) {
+ Nullability.NOT_NULL
+ } else {
+ Nullability.NULLABLE
+ }
+ }
+
+ override val arguments: List<KSTypeArgument> by lazy {
+ (type as? KtNonErrorClassType)?.typeArguments()?.map { KSTypeArgumentImpl.getCached(it) } ?: emptyList()
+ }
+
+ override val annotations: Sequence<KSAnnotation>
+ get() = type.annotations() +
+ if (type is KtFunctionalType && type.receiverType != null) {
+ sequenceOf(KSAnnotationImpl.getCached(ExtensionFunctionTypeAnnotation))
+ } else {
+ emptySequence<KSAnnotation>()
+ }
+
+ override fun isAssignableFrom(that: KSType): Boolean {
+ if (that.isError || this.isError) {
+ return false
+ }
+ return analyze {
+ (that as? KSTypeImpl)?.type?.isSubTypeOf(type) == true
+ }
+ }
+
+ override fun isMutabilityFlexible(): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ override fun isCovarianceFlexible(): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ override fun replace(arguments: List<KSTypeArgument>): KSType {
+ return analyze {
+ analysisSession.buildClassType((type as KtNonErrorClassType).classSymbol) {
+ arguments.forEach { arg -> argument(arg.toKtTypeProjection()) }
+ }.let { getCached(it) }
+ }
+ }
+
+ override fun starProjection(): KSType {
+ return analyze {
+ analysisSession.buildClassType((type as KtNonErrorClassType).classSymbol) {
+ type.typeArguments().forEach {
+ argument(KtStarTypeProjection(type.token))
+ }
+ }.let { getCached(it) }
+ }
+ }
+
+ override fun makeNullable(): KSType {
+ return analyze {
+ getCached(type.withNullability(KtTypeNullability.NULLABLE))
+ }
+ }
+
+ override fun makeNotNullable(): KSType {
+ return analyze {
+ getCached(type.withNullability(KtTypeNullability.NON_NULLABLE))
+ }
+ }
+
+ override val isMarkedNullable: Boolean
+ get() = type.nullability == KtTypeNullability.NULLABLE
+
+ override val isError: Boolean
+ get() = type is KtClassErrorType
+
+ override val isFunctionType: Boolean
+ get() = type is KtFunctionalType && !type.isSuspend
+
+ override val isSuspendFunctionType: Boolean
+ get() = type is KtFunctionalType && type.isSuspend
+
+ override fun hashCode(): Int {
+ return type.toAbbreviatedType().hashCode()
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (other !is KSTypeImpl) {
+ return false
+ }
+ return analyze {
+ type.isEqualTo(other.type)
+ }
+ }
+
+ override fun toString(): String {
+ return type.render()
+ }
+}
+
+internal fun KtType.toAbbreviatedType(): KtType {
+ val symbol = this.classifierSymbol()
+ return when (symbol) {
+ is KtTypeAliasSymbol -> symbol.expandedType.toAbbreviatedType()
+ else -> this
+ }
+}
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
new file mode 100644
index 00000000..8b2672de
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeParameterImpl.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol
+
+class KSTypeParameterImpl private constructor(internal val ktTypeParameterSymbol: KtTypeParameterSymbol) :
+ KSTypeParameter,
+ AbstractKSDeclarationImpl(ktTypeParameterSymbol),
+ KSExpectActual by KSExpectActualImpl(ktTypeParameterSymbol) {
+ companion object : KSObjectCache<KtTypeParameterSymbol, KSTypeParameterImpl>() {
+ fun getCached(ktTypeParameterSymbol: KtTypeParameterSymbol) =
+ cache.getOrPut(ktTypeParameterSymbol) { KSTypeParameterImpl(ktTypeParameterSymbol) }
+ }
+
+ override val name: KSName by lazy {
+ KSNameImpl.getCached(ktTypeParameterSymbol.name.asString())
+ }
+
+ override val variance: Variance by lazy {
+ when (ktTypeParameterSymbol.variance) {
+ org.jetbrains.kotlin.types.Variance.IN_VARIANCE -> Variance.COVARIANT
+ org.jetbrains.kotlin.types.Variance.OUT_VARIANCE -> Variance.CONTRAVARIANT
+ org.jetbrains.kotlin.types.Variance.INVARIANT -> Variance.INVARIANT
+ }
+ }
+
+ override val isReified: Boolean = ktTypeParameterSymbol.isReified
+
+ override val bounds: Sequence<KSTypeReference> by lazy {
+ ktTypeParameterSymbol.upperBounds.asSequence().mapIndexed { index, type ->
+ KSTypeReferenceImpl.getCached(type, this@KSTypeParameterImpl, index)
+ }
+ }
+
+ override val typeParameters: List<KSTypeParameter> = emptyList()
+
+ override val qualifiedName: KSName? by lazy {
+ KSNameImpl.getCached("${this.parentDeclaration!!.qualifiedName!!.asString()}.${simpleName.asString()}")
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeParameter(this, data)
+ }
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeReferenceImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeReferenceImpl.kt
new file mode 100644
index 00000000..b585f20b
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSTypeReferenceImpl.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.ExceptionMessage
+import com.google.devtools.ksp.IdKeyTriple
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.symbol.*
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiTypeParameter
+import com.intellij.psi.impl.source.PsiClassReferenceType
+import org.jetbrains.kotlin.analysis.api.types.*
+import org.jetbrains.kotlin.psi.KtClassOrObject
+import org.jetbrains.kotlin.psi.KtTypeParameter
+
+class KSTypeReferenceImpl private constructor(
+ private val ktType: KtType,
+ override val parent: KSNode?,
+ private val index: Int
+) : KSTypeReference {
+ companion object : KSObjectCache<IdKeyTriple<KtType, KSNode?, Int>, KSTypeReference>() {
+ fun getCached(type: KtType, parent: KSNode? = null, index: Int = -1): KSTypeReference =
+ cache.getOrPut(IdKeyTriple(type, parent, index)) { KSTypeReferenceImpl(type, parent, index) }
+ }
+
+ override val element: KSReferenceElement? by lazy {
+ if (parent == null || parent.origin == Origin.SYNTHETIC) {
+ null
+ } else {
+ when (ktType) {
+ is KtFunctionalType -> KSCallableReferenceImpl.getCached(ktType, this@KSTypeReferenceImpl)
+ is KtDynamicType -> KSDynamicReferenceImpl.getCached(this@KSTypeReferenceImpl)
+ is KtUsualClassType -> KSClassifierReferenceImpl.getCached(ktType, this@KSTypeReferenceImpl)
+ is KtFlexibleType -> KSClassifierReferenceImpl.getCached(
+ ktType.lowerBound as KtUsualClassType,
+ this@KSTypeReferenceImpl
+ )
+ is KtErrorType -> null
+ is KtTypeParameterType -> null
+ else -> throw IllegalStateException("Unexpected type element ${ktType.javaClass}, $ExceptionMessage")
+ }
+ }
+ }
+
+ override fun resolve(): KSType {
+ // TODO: non exist type returns KtNonErrorClassType, check upstream for KtClassErrorType usage.
+ return if (
+ analyze {
+ ktType is KtClassErrorType || (ktType.classifierSymbol() == null)
+ }
+ ) {
+ KSErrorType
+ } else {
+ KSTypeImpl.getCached(ktType)
+ }
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ ktType.annotations()
+ }
+
+ override val origin: Origin = parent?.origin ?: Origin.SYNTHETIC
+
+ override val location: Location by lazy {
+ if (index != -1) {
+ parent?.location ?: NonExistLocation
+ } else {
+ when (parent) {
+ is KSClassDeclarationImpl -> {
+ when (val psi = parent.ktClassOrObjectSymbol.psi) {
+ is KtClassOrObject -> psi.superTypeListEntries.get(index).toLocation()
+ is PsiClass -> (psi as? PsiClassReferenceType)?.reference?.toLocation() ?: NonExistLocation
+ else -> NonExistLocation
+ }
+ }
+ is KSTypeParameterImpl -> {
+ when (val psi = parent.ktTypeParameterSymbol.psi) {
+ is KtTypeParameter -> parent.location
+ is PsiTypeParameter -> (psi.extendsListTypes[index] as? PsiClassReferenceType)
+ ?.reference?.toLocation() ?: NonExistLocation
+ else -> NonExistLocation
+ }
+ }
+ else -> NonExistLocation
+ }
+ }
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitTypeReference(this, data)
+ }
+
+ override val modifiers: Set<Modifier>
+ get() = if (ktType is KtFunctionalType && ktType.isSuspend) {
+ setOf(Modifier.SUSPEND)
+ } else {
+ emptySet()
+ }
+
+ override fun toString(): String {
+ return ktType.render()
+ }
+}
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
new file mode 100644
index 00000000..719e1812
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueArgumentImpl.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.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
+) : KSValueArgument {
+ companion object : KSObjectCache<KtNamedAnnotationValue, KSValueArgumentImpl>() {
+ fun getCached(namedAnnotationValue: KtNamedAnnotationValue) =
+ cache.getOrPut(namedAnnotationValue) { KSValueArgumentImpl(namedAnnotationValue) }
+ }
+
+ override val name: KSName? by lazy {
+ KSNameImpl.getCached(namedAnnotationValue.name.asString())
+ }
+
+ override val isSpread: Boolean = false
+
+ override val value: Any? = namedAnnotationValue.expression.toValue()
+
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override val origin: Origin = Origin.KOTLIN
+
+ override val location: Location by lazy {
+ namedAnnotationValue.expression.sourcePsi?.toLocation() ?: NonExistLocation
+ }
+
+ override val parent: KSNode?
+ get() = TODO("Not yet implemented")
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitValueArgument(this, data)
+ }
+
+ 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<KSClassDeclarationEnumEntryImpl>().singleOrNull {
+ it.simpleName.asString() == this@toValue.callableId?.callableName?.asString()
+ }
+ }
+ }
+ } ?: KSErrorType
+ 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
+ }
+ is KtConstantAnnotationValue -> this.constantValue.value
+ is KtUnsupportedAnnotationValue -> null
+ }
+}
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
new file mode 100644
index 00000000..ac9b20dc
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueParameterImpl.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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.
+ */
+
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirValueParameterSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
+import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
+import org.jetbrains.kotlin.fir.java.declarations.FirJavaValueParameter
+import org.jetbrains.kotlin.fir.java.resolveIfJavaType
+import org.jetbrains.kotlin.fir.symbols.SymbolInternals
+
+class KSValueParameterImpl private constructor(
+ private val ktValueParameterSymbol: KtValueParameterSymbol,
+ override val parent: KSAnnotated
+) : KSValueParameter {
+ companion object : KSObjectCache<KtValueParameterSymbol, KSValueParameterImpl>() {
+ fun getCached(ktValueParameterSymbol: KtValueParameterSymbol, parent: KSAnnotated) =
+ cache.getOrPut(ktValueParameterSymbol) { KSValueParameterImpl(ktValueParameterSymbol, parent) }
+ }
+
+ override val name: KSName? by lazy {
+ if (origin == Origin.SYNTHETIC && parent is KSPropertySetter) {
+ KSNameImpl.getCached("<set-?>")
+ } else {
+ KSNameImpl.getCached(ktValueParameterSymbol.name.asString())
+ }
+ }
+
+ @OptIn(SymbolInternals::class)
+ override val type: KSTypeReference by lazy {
+ // FIXME: temporary workaround before upstream fixes java type refs.
+ if (origin == Origin.JAVA || origin == Origin.JAVA_LIB) {
+ ((ktValueParameterSymbol as KtFirValueParameterSymbol).firSymbol.fir as FirJavaValueParameter).also {
+ // can't get containing class for FirJavaValueParameter, using empty stack for now.
+ it.returnTypeRef =
+ it.returnTypeRef.resolveIfJavaType(it.moduleData.session, JavaTypeParameterStack.EMPTY)
+ }
+ }
+ KSTypeReferenceImpl.getCached(ktValueParameterSymbol.returnType, this@KSValueParameterImpl)
+ }
+
+ override val isVararg: Boolean by lazy {
+ ktValueParameterSymbol.isVararg
+ }
+
+ override val isNoInline: Boolean
+ get() = TODO("Not yet implemented")
+
+ override val isCrossInline: Boolean
+ get() = TODO("Not yet implemented")
+
+ override val isVal: Boolean
+ get() = TODO("Not yet implemented")
+
+ override val isVar: Boolean
+ get() = TODO("Not yet implemented")
+
+ override val hasDefault: Boolean by lazy {
+ ktValueParameterSymbol.hasDefaultValue
+ }
+
+ override val annotations: Sequence<KSAnnotation> by lazy {
+ (
+ ktValueParameterSymbol.generatedPrimaryConstructorProperty?.annotations()
+ ?: ktValueParameterSymbol.annotations()
+ ).plus(findAnnotationFromUseSiteTarget())
+ }
+ override val origin: Origin by lazy {
+ val symbolOrigin = mapAAOrigin(ktValueParameterSymbol)
+ if (symbolOrigin == Origin.KOTLIN && ktValueParameterSymbol.psi == null) {
+ Origin.SYNTHETIC
+ } else {
+ symbolOrigin
+ }
+ }
+
+ override val location: Location by lazy {
+ ktValueParameterSymbol.psi?.toLocation() ?: NonExistLocation
+ }
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitValueParameter(this, data)
+ }
+
+ override fun toString(): String {
+ return name?.asString() ?: "_"
+ }
+}
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueParameterLiteImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueParameterLiteImpl.kt
new file mode 100644
index 00000000..615dc277
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueParameterLiteImpl.kt
@@ -0,0 +1,43 @@
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.IdKeyPair
+import com.google.devtools.ksp.KSObjectCache
+import com.google.devtools.ksp.processing.impl.KSNameImpl
+import com.google.devtools.ksp.symbol.*
+import org.jetbrains.kotlin.analysis.api.types.KtType
+
+class KSValueParameterLiteImpl private constructor(private val ktType: KtType, override val parent: KSNode) :
+ KSValueParameter {
+ companion object : KSObjectCache<IdKeyPair<KtType, KSNode>, KSValueParameter>() {
+ fun getCached(ktType: KtType, parent: KSNode): KSValueParameter = cache.getOrPut(IdKeyPair(ktType, parent)) {
+ KSValueParameterLiteImpl(ktType, parent)
+ }
+ }
+
+ // preferably maybe use empty name to match compiler, but use underscore to match FE1.0 implementation.
+ override val name: KSName = KSNameImpl.getCached("_")
+
+ override val type: KSTypeReference = KSTypeReferenceImpl.getCached(ktType)
+
+ override val isVararg: Boolean = false
+
+ override val isNoInline: Boolean = false
+
+ override val isCrossInline: Boolean = false
+
+ override val isVal: Boolean = false
+
+ override val isVar: Boolean = false
+
+ override val hasDefault: Boolean = false
+
+ override val annotations: Sequence<KSAnnotation> = emptySequence()
+
+ override val origin: Origin = parent.origin
+
+ override val location: Location = parent.location
+
+ override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
+ return visitor.visitValueParameter(this, data)
+ }
+}
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
new file mode 100644
index 00000000..76d0eadd
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/synthetic/KSSyntheticAnnotations.kt
@@ -0,0 +1,11 @@
+package com.google.devtools.ksp.impl.symbol.kotlin.synthetic
+
+import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplication
+import org.jetbrains.kotlin.name.ClassId
+
+val ExtensionFunctionTypeAnnotation = KtAnnotationApplication(
+ ClassId.fromString(ExtensionFunctionType::class.qualifiedName!!),
+ null,
+ null,
+ emptyList()
+)
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
new file mode 100644
index 00000000..f310b197
--- /dev/null
+++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/util.kt
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.symbol.kotlin
+
+import com.google.devtools.ksp.getDocString
+import com.google.devtools.ksp.impl.KSPCoreEnvironment
+import com.google.devtools.ksp.impl.ResolverAAImpl
+import com.google.devtools.ksp.memoized
+import com.google.devtools.ksp.symbol.*
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiJavaFile
+import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
+import org.jetbrains.kotlin.analysis.api.KtStarTypeProjection
+import org.jetbrains.kotlin.analysis.api.KtTypeArgumentWithVariance
+import org.jetbrains.kotlin.analysis.api.KtTypeProjection
+import org.jetbrains.kotlin.analysis.api.analyze
+import org.jetbrains.kotlin.analysis.api.annotations.*
+import org.jetbrains.kotlin.analysis.api.lifetime.KtAlwaysAccessibleLifetimeToken
+import org.jetbrains.kotlin.analysis.api.lifetime.KtAlwaysAccessibleLifetimeTokenFactory
+import org.jetbrains.kotlin.analysis.api.symbols.*
+import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
+import org.jetbrains.kotlin.analysis.api.types.*
+import org.jetbrains.kotlin.descriptors.Modality
+import org.jetbrains.kotlin.descriptors.Visibilities
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.psi.KtElement
+import org.jetbrains.kotlin.types.Variance
+import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
+
+internal val ktSymbolOriginToOrigin = mapOf(
+ KtSymbolOrigin.JAVA to Origin.JAVA,
+ KtSymbolOrigin.SOURCE to Origin.KOTLIN,
+ KtSymbolOrigin.SAM_CONSTRUCTOR to Origin.SYNTHETIC,
+ KtSymbolOrigin.SOURCE_MEMBER_GENERATED to Origin.SYNTHETIC,
+ KtSymbolOrigin.DELEGATED to Origin.SYNTHETIC,
+ KtSymbolOrigin.PROPERTY_BACKING_FIELD to Origin.KOTLIN,
+ KtSymbolOrigin.JAVA_SYNTHETIC_PROPERTY to Origin.SYNTHETIC,
+ KtSymbolOrigin.INTERSECTION_OVERRIDE to Origin.KOTLIN,
+ // TODO: distinguish between kotlin library and java library.
+ KtSymbolOrigin.LIBRARY to Origin.KOTLIN_LIB,
+ KtSymbolOrigin.SUBSTITUTION_OVERRIDE to Origin.JAVA_LIB
+)
+
+internal fun mapAAOrigin(ktSymbol: KtSymbol): Origin {
+ val symbolOrigin = ktSymbolOriginToOrigin[ktSymbol.origin]
+ ?: throw IllegalStateException("unhandled origin ${ktSymbol.origin.name}")
+ return if (symbolOrigin == Origin.JAVA && ktSymbol.psi?.containingFile?.fileType?.isBinary == true) {
+ Origin.JAVA_LIB
+ } else {
+ symbolOrigin
+ }
+}
+
+internal fun KtAnnotationApplication.render(): String {
+ return buildString {
+ append("@")
+ if (this@render.useSiteTarget != null) {
+ append(this@render.useSiteTarget!!.renderName + ":")
+ }
+ append(this@render.classId!!.shortClassName.asString())
+ this@render.arguments.forEach {
+ append(it.expression.render())
+ }
+ }
+}
+
+internal fun KtAnnotationValue.render(): String {
+ return when (this) {
+ is KtAnnotationApplicationValue -> annotationValue.render()
+ is KtArrayAnnotationValue -> values.joinToString(",", "{", "}") { it.render() }
+ is KtConstantAnnotationValue -> constantValue.renderAsKotlinConstant()
+ is KtEnumEntryAnnotationValue -> callableId.toString()
+ is KtKClassAnnotationValue.KtErrorClassAnnotationValue -> "<Error class>"
+ is KtKClassAnnotationValue.KtLocalKClassAnnotationValue -> "$ktClass::class"
+ is KtKClassAnnotationValue.KtNonLocalKClassAnnotationValue -> "$classId::class"
+ is KtUnsupportedAnnotationValue -> throw IllegalStateException("Unsupported annotation value: $this")
+ }
+}
+
+internal fun KtType.render(inFunctionType: Boolean = false): String {
+ return buildString {
+ annotations.forEach {
+ append("[${it.render()}] ")
+ }
+ append(
+ when (this@render) {
+ is KtNonErrorClassType -> buildString {
+ val symbol = this@render.classifierSymbol()
+ if (symbol is KtTypeAliasSymbol) {
+ if (!inFunctionType) {
+ append("[typealias ${symbol.name.asString()}]")
+ } else {
+ append(this@render.toAbbreviatedType().render(inFunctionType))
+ }
+ } else {
+ append(classSymbol.name?.asString())
+ if (typeArguments().isNotEmpty()) {
+ typeArguments().joinToString(separator = ", ", prefix = "<", postfix = ">") {
+ when (it) {
+ is KtStarTypeProjection -> "*"
+ is KtTypeArgumentWithVariance ->
+ "${it.variance}" +
+ (if (it.variance != Variance.INVARIANT) " " else "") +
+ it.type.render(this@render is KtFunctionalType)
+ }
+ }.also { append(it) }
+ }
+ }
+ }
+ is KtClassErrorType, is KtTypeErrorType -> "<ERROR TYPE>"
+ is KtCapturedType -> asStringForDebugging()
+ is KtDefinitelyNotNullType -> original.render(inFunctionType) + " & Any"
+ is KtDynamicType -> "<dynamic type>"
+ is KtFlexibleType -> "(${lowerBound.render(inFunctionType)}..${upperBound.render(inFunctionType)})"
+ is KtIntegerLiteralType -> "ILT: $value"
+ is KtIntersectionType ->
+ this@render.conjuncts
+ .joinToString(separator = " & ", prefix = "(", postfix = ")") { it.render(inFunctionType) }
+ is KtTypeParameterType -> asStringForDebugging()
+ } + if (nullability == KtTypeNullability.NULLABLE) "?" else ""
+ )
+ }
+}
+
+internal fun KSTypeArgument.toKtTypeProjection(): KtTypeProjection {
+ val variance = when (this.variance) {
+ com.google.devtools.ksp.symbol.Variance.INVARIANT -> Variance.INVARIANT
+ com.google.devtools.ksp.symbol.Variance.COVARIANT -> Variance.OUT_VARIANCE
+ com.google.devtools.ksp.symbol.Variance.CONTRAVARIANT -> Variance.IN_VARIANCE
+ else -> null
+ }
+ val argType = (this.type?.resolve() as? KSTypeImpl)?.type
+ // TODO: maybe make a singleton of alwaysAccessibleLifetimeToken?
+ val alwaysAccessibleLifetimeToken = KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project!!)
+ return if (argType == null || variance == null) {
+ KtStarTypeProjection(alwaysAccessibleLifetimeToken)
+ } else {
+ KtTypeArgumentWithVariance(argType, variance, alwaysAccessibleLifetimeToken)
+ }
+}
+
+internal fun PsiElement?.toLocation(): Location {
+ if (this == null) {
+ return NonExistLocation
+ }
+ val file = this.containingFile
+ val document = KSPCoreEnvironment.instance.psiDocumentManager.getDocument(file) ?: return NonExistLocation
+ return FileLocation(file.virtualFile.path, document.getLineNumber(this.textOffset) + 1)
+}
+
+internal fun KtSymbol.toContainingFile(): KSFile? {
+ return when (val psi = this.psi) {
+ is KtElement -> analyze {
+ KSFileImpl.getCached(psi.containingKtFile.getFileSymbol())
+ }
+ is PsiElement -> KSFileJavaImpl.getCached(psi.containingFile as PsiJavaFile)
+ else -> null
+ }
+}
+
+internal fun KtSymbol.toDocString(): String? = this.psi?.getDocString()
+
+internal inline fun <R> analyze(crossinline action: KtAnalysisSession.() -> R): R {
+ return analyze(ResolverAAImpl.ktModule, KtAlwaysAccessibleLifetimeTokenFactory, action)
+}
+
+internal fun KtSymbolWithMembers.declarations(): Sequence<KSDeclaration> {
+ return analyze {
+ this@declarations.let {
+ it.getDeclaredMemberScope().getAllSymbols() + it.getStaticMemberScope().getAllSymbols()
+ }.distinct().map { symbol ->
+ when (symbol) {
+ is KtNamedClassOrObjectSymbol -> KSClassDeclarationImpl.getCached(symbol)
+ is KtFunctionLikeSymbol -> KSFunctionDeclarationImpl.getCached(symbol)
+ is KtPropertySymbol -> KSPropertyDeclarationImpl.getCached(symbol)
+ is KtEnumEntrySymbol -> KSClassDeclarationEnumEntryImpl.getCached(symbol)
+ is KtJavaFieldSymbol -> KSPropertyDeclarationJavaImpl.getCached(symbol)
+ else -> throw IllegalStateException()
+ }
+ }.memoized()
+ }
+}
+
+internal fun KtSymbolWithMembers.getAllProperties(): Sequence<KSPropertyDeclaration> {
+ return analyze {
+ this@getAllProperties.getMemberScope().getCallableSymbols()
+ .filter {
+ it.isVisibleInClass(this@getAllProperties as KtClassOrObjectSymbol) ||
+ it.getContainingSymbol() == this@getAllProperties
+ }
+ .mapNotNull { callableSymbol ->
+ when (callableSymbol) {
+ is KtPropertySymbol -> KSPropertyDeclarationImpl.getCached(callableSymbol)
+ is KtJavaFieldSymbol -> KSPropertyDeclarationJavaImpl.getCached(callableSymbol)
+ else -> null
+ }
+ }
+ }
+}
+
+internal fun KtSymbolWithMembers.getAllFunctions(): Sequence<KSFunctionDeclaration> {
+ return analyze {
+ this@getAllFunctions.getMemberScope().let { it.getCallableSymbols() + it.getConstructors() }
+ .filter {
+ it.isVisibleInClass(this@getAllFunctions as KtClassOrObjectSymbol) ||
+ it.getContainingSymbol() == this@getAllFunctions
+ }
+ .mapNotNull { callableSymbol ->
+ // TODO: replace with single safe cast if no more implementations of KSFunctionDeclaration is added.
+ when (callableSymbol) {
+ is KtFunctionLikeSymbol -> KSFunctionDeclarationImpl.getCached(callableSymbol)
+ else -> null
+ }
+ }
+ }
+}
+
+internal fun KtAnnotated.annotations(): Sequence<KSAnnotation> {
+ return this.annotations.asSequence().map { KSAnnotationImpl.getCached(it) }
+}
+
+internal fun KtSymbol.getContainingKSSymbol(): KSDeclaration? {
+ return analyze {
+ when (val containingSymbol = this@getContainingKSSymbol.getContainingSymbol()) {
+ is KtNamedClassOrObjectSymbol -> KSClassDeclarationImpl.getCached(containingSymbol)
+ is KtFunctionLikeSymbol -> KSFunctionDeclarationImpl.getCached(containingSymbol)
+ is KtPropertySymbol -> KSPropertyDeclarationImpl.getCached(containingSymbol)
+ else -> null
+ }
+ }
+}
+
+internal fun KtSymbol.toKSDeclaration(): KSDeclaration? = this.toKSNode() as? KSDeclaration
+
+internal fun KtSymbol.toKSNode(): KSNode {
+ return when (this) {
+ is KtPropertySymbol -> KSPropertyDeclarationImpl.getCached(this)
+ is KtNamedClassOrObjectSymbol -> KSClassDeclarationImpl.getCached(this)
+ is KtFunctionLikeSymbol -> KSFunctionDeclarationImpl.getCached(this)
+ is KtTypeAliasSymbol -> KSTypeAliasImpl.getCached(this)
+ is KtJavaFieldSymbol -> KSPropertyDeclarationJavaImpl.getCached(this)
+ is KtFileSymbol -> KSFileImpl.getCached(this)
+ is KtEnumEntrySymbol -> KSClassDeclarationEnumEntryImpl.getCached(this)
+ is KtTypeParameterSymbol -> KSTypeParameterImpl.getCached(this)
+ is KtLocalVariableSymbol -> KSPropertyDeclarationLocalVariableImpl.getCached(this)
+ else -> throw IllegalStateException("Unexpected class for KtSymbol: ${this.javaClass}")
+ }
+}
+
+internal fun ClassId.toKtClassSymbol(): KtClassOrObjectSymbol? {
+ return analyze {
+ if (this@toKtClassSymbol.isLocal) {
+ this@toKtClassSymbol.outerClassId?.toKtClassSymbol()?.getDeclaredMemberScope()?.getClassifierSymbols {
+ it.asString() == this@toKtClassSymbol.shortClassName.asString()
+ }?.singleOrNull() as? KtClassOrObjectSymbol
+ } else {
+ getClassOrObjectSymbolByClassId(this@toKtClassSymbol)
+ }
+ }
+}
+
+internal fun KtType.classifierSymbol(): KtClassifierSymbol? {
+ return try {
+ when (this) {
+ is KtTypeParameterType -> this.symbol
+ // TODO: upstream is not exposing enough information for captured types.
+ is KtCapturedType -> TODO("fix in upstream")
+ is KtClassErrorType, is KtTypeErrorType -> null
+ is KtFunctionalType -> classSymbol
+ is KtUsualClassType -> classSymbol
+ is KtDefinitelyNotNullType -> original.classifierSymbol()
+ is KtDynamicType -> null
+ // flexible types have 2 bounds, using lower bound for a safer approximation.
+ // TODO: find a case where lower bound is not appropriate.
+ is KtFlexibleType -> lowerBound.classifierSymbol()
+ is KtIntegerLiteralType -> null
+ // TODO: KSP does not support intersection type.
+ is KtIntersectionType -> null
+ }
+ } catch (e: KotlinExceptionWithAttachments) {
+ // The implementation for getting symbols from a type throws an excpetion
+ // when it can't find the corresponding class symbol fot the given class ID.
+ null
+ }
+}
+
+internal fun KtType.typeArguments(): List<KtTypeProjection> {
+ return (this as? KtNonErrorClassType)?.qualifiers?.reversed()?.flatMap { it.typeArguments } ?: emptyList()
+}
+
+internal fun KSAnnotated.findAnnotationFromUseSiteTarget(): Sequence<KSAnnotation> {
+ return when (this) {
+ is KSPropertyGetter -> (this.receiver as? AbstractKSDeclarationImpl)?.let {
+ it.originalAnnotations.asSequence().filter { it.useSiteTarget == AnnotationUseSiteTarget.GET }
+ }
+ is KSPropertySetter -> (this.receiver as? AbstractKSDeclarationImpl)?.let {
+ it.originalAnnotations.asSequence().filter { it.useSiteTarget == AnnotationUseSiteTarget.SET }
+ }
+ is KSValueParameter -> {
+ var parent = this.parent
+ // TODO: eliminate annotationsFromParents to make this fully sequence.
+ val annotationsFromParents = mutableListOf<KSAnnotation>()
+ (parent as? KSPropertyAccessorImpl)?.let {
+ annotationsFromParents.addAll(
+ it.originalAnnotations.asSequence()
+ .filter { it.useSiteTarget == AnnotationUseSiteTarget.SETPARAM }
+ )
+ parent = (parent as KSPropertyAccessorImpl).receiver
+ }
+ (parent as? KSPropertyDeclarationImpl)?.let {
+ annotationsFromParents.addAll(
+ it.originalAnnotations.asSequence()
+ .filter { it.useSiteTarget == AnnotationUseSiteTarget.SETPARAM }
+ )
+ }
+ annotationsFromParents.asSequence()
+ }
+ else -> emptySequence()
+ } ?: emptySequence()
+}
+
+internal fun org.jetbrains.kotlin.descriptors.Visibility.toModifier(): Modifier {
+ return when (this) {
+ Visibilities.Public -> Modifier.PUBLIC
+ Visibilities.Private -> Modifier.PRIVATE
+ Visibilities.Internal -> Modifier.INTERNAL
+ Visibilities.Protected -> Modifier.PROTECTED
+ else -> Modifier.PUBLIC
+ }
+}
+
+internal fun Modality.toModifier(): Modifier {
+ return when (this) {
+ Modality.FINAL -> Modifier.FINAL
+ Modality.ABSTRACT -> Modifier.ABSTRACT
+ Modality.OPEN -> Modifier.OPEN
+ Modality.SEALED -> Modifier.SEALED
+ }
+}
diff --git a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/impl/test/AbstractKSPAATest.kt b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/impl/test/AbstractKSPAATest.kt
new file mode 100644
index 00000000..39687c83
--- /dev/null
+++ b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/impl/test/AbstractKSPAATest.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.test
+
+import com.google.devtools.ksp.KspOptions
+import com.google.devtools.ksp.impl.CommandLineKSPLogger
+import com.google.devtools.ksp.impl.KotlinSymbolProcessing
+import com.google.devtools.ksp.processor.AbstractTestProcessor
+import com.google.devtools.ksp.testutils.AbstractKSPTest
+import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession
+import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
+import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots
+import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
+import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoot
+import org.jetbrains.kotlin.config.CommonConfigurationKeys
+import org.jetbrains.kotlin.test.compileJavaFiles
+import org.jetbrains.kotlin.test.kotlinPathsForDistDirectoryForTests
+import org.jetbrains.kotlin.test.model.FrontendKinds
+import org.jetbrains.kotlin.test.model.TestModule
+import org.jetbrains.kotlin.test.services.JUnit5Assertions
+import org.jetbrains.kotlin.test.services.TestServices
+import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
+import org.jetbrains.kotlin.test.services.isKtFile
+import org.jetbrains.kotlin.test.services.javaFiles
+import org.jetbrains.kotlin.test.util.KtTestUtil
+import org.jetbrains.kotlin.utils.PathUtil
+import java.io.ByteArrayOutputStream
+import java.io.File
+import java.io.PrintStream
+import java.net.URLClassLoader
+import java.nio.file.Files
+
+abstract class AbstractKSPAATest : AbstractKSPTest(FrontendKinds.FIR) {
+ val TestModule.kotlinSrc
+ get() = File(testRoot, "kotlinSrc")
+
+ fun TestModule.writeKtFiles() {
+ kotlinSrc.mkdirs()
+ files.filter { it.isKtFile }.forEach { file ->
+ File(kotlinSrc, file.relativePath).let {
+ it.parentFile.mkdirs()
+ it.writeText(file.originalContent)
+ }
+ }
+ }
+
+ private fun compileKotlin(dependencies: List<File>, sourcesPath: String, javaSourcePath: String, outDir: File) {
+ val classpath = mutableListOf<String>()
+ classpath.addAll(dependencies.map { it.canonicalPath })
+ if (File(sourcesPath).isDirectory) {
+ classpath += sourcesPath
+ }
+ classpath += PathUtil.kotlinPathsForDistDirectoryForTests.stdlibPath.path
+
+ val args = mutableListOf(
+ sourcesPath,
+ javaSourcePath,
+ "-d", outDir.absolutePath,
+ "-no-stdlib",
+ "-classpath", classpath.joinToString(File.pathSeparator)
+ )
+ runJvmCompiler(args)
+ }
+
+ private fun runJvmCompiler(args: List<String>) {
+ val outStream = ByteArrayOutputStream()
+ val compilerClass = URLClassLoader(arrayOf(), javaClass.classLoader).loadClass(K2JVMCompiler::class.java.name)
+ val compiler = compilerClass.newInstance()
+ val execMethod = compilerClass.getMethod("exec", PrintStream::class.java, Array<String>::class.java)
+ execMethod.invoke(compiler, PrintStream(outStream), args.toTypedArray())
+ }
+
+ override fun compileModule(module: TestModule, testServices: TestServices) {
+ module.writeKtFiles()
+ val javaFiles = module.writeJavaFiles()
+ val dependencies = module.allDependencies.map { outDirForModule(it.moduleName) }
+ compileKotlin(dependencies, module.kotlinSrc.path, module.javaDir.path, module.outDir)
+ val classpath = (dependencies + KtTestUtil.getAnnotationsJar() + module.outDir)
+ .joinToString(File.pathSeparator) { it.absolutePath }
+ val options = listOf(
+ "-classpath", classpath,
+ "-d", module.outDir.path
+ )
+ if (javaFiles.isNotEmpty()) {
+ compileJavaFiles(javaFiles, options, assertions = JUnit5Assertions)
+ }
+ }
+
+ override fun runTest(
+ testServices: TestServices,
+ mainModule: TestModule,
+ libModules: List<TestModule>,
+ testProcessor: AbstractTestProcessor
+ ): List<String> {
+ val compilerConfiguration = testServices.compilerConfigurationProvider.getCompilerConfiguration(mainModule)
+ compilerConfiguration.put(CommonConfigurationKeys.MODULE_NAME, mainModule.name)
+ compilerConfiguration.addKotlinSourceRoot(mainModule.kotlinSrc.absolutePath)
+ mainModule.kotlinSrc.mkdirs()
+ if (!mainModule.javaFiles.isEmpty()) {
+ mainModule.writeJavaFiles()
+ compilerConfiguration.addJavaSourceRoot(mainModule.javaDir)
+ }
+
+ // Some underlying service needs files backed by local fs.
+ // Therefore, this doesn't work:
+ // val ktFiles = mainModule.loadKtFiles(kotlinCoreEnvironment.project)
+ mainModule.writeKtFiles()
+ val kotlinSourceFiles = mainModule.files.filter { it.isKtFile }.map {
+ File(mainModule.kotlinSrc, it.relativePath)
+ }
+ val ktSourceRoots = kotlinSourceFiles
+ .sortedBy { Files.isSymbolicLink(it.toPath()) } // Get non-symbolic paths first
+ .distinctBy { it.canonicalPath }
+ compilerConfiguration.addKotlinSourceRoots(ktSourceRoots.map { it.absolutePath })
+
+ val testRoot = mainModule.testRoot
+
+ val kspOptions = KspOptions.Builder().apply {
+ if (!mainModule.javaFiles.isEmpty()) {
+ javaSourceRoots.add(mainModule.javaDir)
+ }
+ classOutputDir = File(testRoot, "kspTest/classes/main")
+ javaOutputDir = File(testRoot, "kspTest/src/main/java")
+ kotlinOutputDir = File(testRoot, "kspTest/src/main/kotlin")
+ resourceOutputDir = File(testRoot, "kspTest/src/main/resources")
+ projectBaseDir = testRoot
+ cachesDir = File(testRoot, "kspTest/kspCaches")
+ kspOutputDir = File(testRoot, "kspTest")
+ }.build()
+ val analysisSession = buildStandaloneAnalysisAPISession {
+ buildKtModuleProviderByCompilerConfiguration(compilerConfiguration)
+ }
+ val ksp = KotlinSymbolProcessing(
+ compilerConfiguration,
+ kspOptions,
+ CommandLineKSPLogger(),
+ analysisSession,
+ listOf(testProcessor)
+ )
+ ksp.prepare()
+ ksp.execute()
+ return testProcessor.toResult()
+ }
+}
diff --git a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/impl/test/KSPAATest.kt b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/impl/test/KSPAATest.kt
new file mode 100644
index 00000000..98562208
--- /dev/null
+++ b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/impl/test/KSPAATest.kt
@@ -0,0 +1,584 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.impl.test
+
+import org.jetbrains.kotlin.test.TestMetadata
+import org.junit.jupiter.api.Disabled
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.condition.DisabledOnOs
+import org.junit.jupiter.api.condition.OS
+import org.junit.jupiter.api.parallel.Execution
+import org.junit.jupiter.api.parallel.ExecutionMode
+
+@Execution(ExecutionMode.SAME_THREAD)
+@DisabledOnOs(OS.WINDOWS)
+class KSPAATest : AbstractKSPAATest() {
+
+ @Disabled
+ @TestMetadata("annotatedUtil.kt")
+ @Test
+ fun testAnnotatedUtil() {
+ runTest("../test-utils/testData/api/annotatedUtil.kt")
+ }
+
+ @Disabled
+ @TestMetadata("javaAnnotatedUtil.kt")
+ @Test
+ fun testJavaAnnotatedUtil() {
+ runTest("../test-utils/testData/api/javaAnnotatedUtil.kt")
+ }
+
+ @TestMetadata("abstractFunctions.kt")
+ @Test
+ fun testAbstractFunctions() {
+ runTest("../test-utils/testData/api/abstractFunctions.kt")
+ }
+
+ @TestMetadata("allFunctions_java_inherits_kt.kt")
+ @Test
+ fun testAllFunctions_java_inherits_kt() {
+ runTest("../test-utils/testData/api/allFunctions_java_inherits_kt.kt")
+ }
+
+ @TestMetadata("allFunctions_kotlin.kt")
+ @Test
+ fun testAllFunctions_kotlin() {
+ runTest("../test-utils/testData/api/allFunctions_java_inherits_kt.kt")
+ }
+
+ @Disabled
+ @TestMetadata("allFunctions_kt_inherits_java.kt")
+ @Test
+ fun testAllFunctions_kt_inherits_java() {
+ runTest("../test-utils/testData/api/allFunctions_kt_inherits_java.kt")
+ }
+
+ @TestMetadata("annotationInDependencies.kt")
+ @Test
+ fun testAnnotationsInDependencies() {
+ runTest("../test-utils/testData/api/annotationInDependencies.kt")
+ }
+
+ @TestMetadata("annotationOnConstructorParameter.kt")
+ @Test
+ fun testAnnotationOnConstructorParameter() {
+ runTest("../test-utils/testData/api/annotationOnConstructorParameter.kt")
+ }
+
+ @Disabled
+ @TestMetadata("annotationWithArbitraryClassValue.kt")
+ @Test
+ fun testAnnotationWithArbitraryClassValue() {
+ runTest("../test-utils/testData/api/annotationWithArbitraryClassValue.kt")
+ }
+
+ @Disabled
+ @TestMetadata("annotationValue_java.kt")
+ @Test
+ fun testAnnotationValue_java() {
+ runTest("../test-utils/testData/api/annotationValue_java.kt")
+ }
+
+ @TestMetadata("annotationValue_kt.kt")
+ @Test
+ fun testAnnotationValue_kt() {
+ runTest("../test-utils/testData/api/annotationValue_kt.kt")
+ }
+
+ @Disabled
+ @TestMetadata("annotationWithArrayValue.kt")
+ @Test
+ fun testAnnotationWithArrayValue() {
+ runTest("../test-utils/testData/api/annotationWithArrayValue.kt")
+ }
+
+ @Disabled
+ @TestMetadata("annotationWithDefault.kt")
+ @Test
+ fun testAnnotationWithDefault() {
+ runTest("../test-utils/testData/api/annotationWithDefault.kt")
+ }
+
+ @Disabled
+ @TestMetadata("annotationWithDefaultValues.kt")
+ @Test
+ fun testAnnotationWithDefaultValues() {
+ runTest("../test-utils/testData/api/annotationWithDefaultValues.kt")
+ }
+
+ @Disabled
+ @TestMetadata("annotationWithJavaTypeValue.kt")
+ @Test
+ fun testAnnotationWithJavaTypeValue() {
+ runTest("../test-utils/testData/api/annotationWithJavaTypeValue.kt")
+ }
+
+ @Disabled
+ @TestMetadata("asMemberOf.kt")
+ @Test
+ fun testAsMemberOf() {
+ runTest("../test-utils/testData/api/asMemberOf.kt")
+ }
+
+ @Disabled
+ @TestMetadata("backingFields.kt")
+ @Test
+ fun testBackingFields() {
+ runTest("../test-utils/testData/api/backingFields.kt")
+ }
+
+ @Disabled
+ @TestMetadata("builtInTypes.kt")
+ @Test
+ fun testBuiltInTypes() {
+ runTest("../test-utils/testData/api/builtInTypes.kt")
+ }
+
+ @Disabled
+ @TestMetadata("checkOverride.kt")
+ @Test
+ fun testCheckOverride() {
+ runTest("../test-utils/testData/api/checkOverride.kt")
+ }
+
+ @TestMetadata("classKinds.kt")
+ @Test
+ fun testClassKinds() {
+ runTest("../test-utils/testData/api/classKinds.kt")
+ }
+
+ @TestMetadata("companion.kt")
+ @Test
+ fun testCompanion() {
+ runTest("../test-utils/testData/api/companion.kt")
+ }
+
+ @Disabled
+ @TestMetadata("constProperties.kt")
+ @Test
+ fun testConstProperties() {
+ runTest("../test-utils/testData/api/constProperties.kt")
+ }
+
+ @TestMetadata("constructorDeclarations.kt")
+ @Test
+ fun testConstructorDeclarations() {
+ runTest("../test-utils/testData/api/constructorDeclarations.kt")
+ }
+
+ @TestMetadata("crossModuleTypeAlias.kt")
+ @Test
+ fun testCrossModuleTypeAlias() {
+ runTest("../test-utils/testData/api/crossModuleTypeAlias.kt")
+ }
+
+ @TestMetadata("declarationInconsistency.kt")
+ @Test
+ fun testDeclarationInconsistency() {
+ runTest("../test-utils/testData/api/declarationInconsistency.kt")
+ }
+
+ @TestMetadata("declarationPackageName.kt")
+ @Test
+ fun testDeclarationPackageName() {
+ runTest("../test-utils/testData/api/declarationPackageName.kt")
+ }
+
+ @Disabled
+ @TestMetadata("declarationOrder.kt")
+ @Test
+ fun testDeclarationOrder() {
+ runTest("../test-utils/testData/api/declarationOrder.kt")
+ }
+
+ @Disabled
+ @TestMetadata("declarationUtil.kt")
+ @Test
+ fun testDeclarationUtil() {
+ runTest("../test-utils/testData/api/declarationUtil.kt")
+ }
+
+ @TestMetadata("declared.kt")
+ @Test
+ fun testDeclared() {
+ runTest("../test-utils/testData/api/declared.kt")
+ }
+
+ @TestMetadata("docString.kt")
+ @Test
+ fun testDocString() {
+ runTest("../test-utils/testData/api/docString.kt")
+ }
+
+ @Disabled
+ @TestMetadata("equivalentJavaWildcards.kt")
+ @Test
+ fun testEquivalentJavaWildcards() {
+ runTest("../test-utils/testData/api/equivalentJavaWildcards.kt")
+ }
+
+ @TestMetadata("errorTypes.kt")
+ @Test
+ fun testErrorTypes() {
+ runTest("../test-utils/testData/api/errorTypes.kt")
+ }
+
+ @TestMetadata("functionTypeAlias.kt")
+ @Test
+ fun testFunctionTypeAlias() {
+ runTest("../test-utils/testData/api/functionTypeAlias.kt")
+ }
+
+ @TestMetadata("functionTypeAnnotation.kt")
+ @Test
+ fun testFunctionTypeAnnotation() {
+ runTest("../test-utils/testData/api/functionTypeAnnotation.kt")
+ }
+
+ @TestMetadata("functionTypes.kt")
+ @Test
+ fun testFunctionTypes() {
+ runTest("../test-utils/testData/api/functionTypes.kt")
+ }
+
+ @Disabled
+ @TestMetadata("getAnnotationByTypeWithInnerDefault.kt")
+ @Test
+ fun testGetAnnotationByTypeWithInnerDefault() {
+ runTest("../test-utils/testData/api/getAnnotationByTypeWithInnerDefault.kt")
+ }
+
+ @Disabled
+ @TestMetadata("getPackage.kt")
+ @Test
+ fun testGetPackage() {
+ runTest("../test-utils/testData/api/getPackage.kt")
+ }
+
+ @Disabled
+ @TestMetadata("getByName.kt")
+ @Test
+ fun testGetByName() {
+ runTest("../test-utils/testData/api/getByName.kt")
+ }
+
+ @Disabled
+ @TestMetadata("getSymbolsFromAnnotation.kt")
+ @Test
+ fun testGetSymbolsFromAnnotation() {
+ runTest("../test-utils/testData/api/getSymbolsFromAnnotation.kt")
+ }
+
+ @TestMetadata("hello.kt")
+ @Test
+ fun testHello() {
+ runTest("../test-utils/testData/api/hello.kt")
+ }
+
+ @TestMetadata("implicitElements.kt")
+ @Test
+ fun testImplicitElements() {
+ runTest("../test-utils/testData/api/implicitElements.kt")
+ }
+
+ @TestMetadata("implicitPropertyAccessors.kt")
+ @Test
+ fun testImplicitPropertyAccessors() {
+ runTest("../test-utils/testData/api/implicitPropertyAccessors.kt")
+ }
+
+ @Disabled
+ @TestMetadata("inheritedTypeAlias.kt")
+ @Test
+ fun testInheritedTypeAlias() {
+ runTest("../test-utils/testData/api/inheritedTypeAlias.kt")
+ }
+
+ @TestMetadata("innerTypes.kt")
+ @Test
+ fun testInnerTypes() {
+ runTest("testData/innerTypes.kt")
+ }
+
+ @TestMetadata("interfaceWithDefault.kt")
+ @Test
+ fun testInterfaceWithDefault() {
+ runTest("../test-utils/testData/api/interfaceWithDefault.kt")
+ }
+
+ @Disabled
+ @TestMetadata("javaModifiers.kt")
+ @Test
+ fun testJavaModifiers() {
+ runTest("../test-utils/testData/api/javaModifiers.kt")
+ }
+
+ @Disabled
+ @TestMetadata("javaNonNullTypes.kt")
+ @Test
+ fun testJavaNonNullTypes() {
+ runTest("../test-utils/testData/api/javaNonNullTypes.kt")
+ }
+
+ @Disabled
+ @TestMetadata("javaSubtype.kt")
+ @Test
+ fun testJavaSubtype() {
+ runTest("../test-utils/testData/api/javaSubtype.kt")
+ }
+
+ @TestMetadata("javaToKotlinMapper.kt")
+ @Test
+ fun testJavaToKotlinMapper() {
+ runTest("../test-utils/testData/api/javaToKotlinMapper.kt")
+ }
+
+ @TestMetadata("javaTypes.kt")
+ @Test
+ fun testJavaTypes() {
+ runTest("../test-utils/testData/api/javaTypes.kt")
+ }
+
+ @Disabled
+ @TestMetadata("javaTypes2.kt")
+ @Test
+ fun testJavaTypes2() {
+ runTest("../test-utils/testData/api/javaTypes2.kt")
+ }
+
+ @Disabled
+ @TestMetadata("javaWildcards2.kt")
+ @Test
+ fun testJavaWildcards2() {
+ runTest("../test-utils/testData/api/javaWildcards2.kt")
+ }
+
+ @TestMetadata("lateinitProperties.kt")
+ @Test
+ fun testLateinitProperties() {
+ runTest("../test-utils/testData/api/lateinitProperties.kt")
+ }
+
+ @Disabled
+ @TestMetadata("libOrigins.kt")
+ @Test
+ fun testLibOrigins() {
+ runTest("../test-utils/testData/api/libOrigins.kt")
+ }
+
+ @TestMetadata("makeNullable.kt")
+ @Test
+ fun testMakeNullable() {
+ runTest("../test-utils/testData/api/makeNullable.kt")
+ }
+
+ @Disabled
+ @TestMetadata("mangledNames.kt")
+ @Test
+ fun testMangledNames() {
+ runTest("../test-utils/testData/api/mangledNames.kt")
+ }
+
+ @TestMetadata("multipleModules.kt")
+ @Test
+ fun testMultipleModules() {
+ runTest("../test-utils/testData/api/multipleModules.kt")
+ }
+
+ @Disabled
+ @TestMetadata("nestedClassType.kt")
+ @Test
+ fun testNestedClassType() {
+ runTest("../test-utils/testData/api/nestedClassType.kt")
+ }
+
+ @TestMetadata("nullableTypes.kt")
+ @Test
+ fun testNullableTypes() {
+ runTest("../test-utils/testData/api/nullableTypes.kt")
+ }
+
+ @Disabled
+ @TestMetadata("overridee.kt")
+ @Test
+ fun testOverridee() {
+ runTest("../test-utils/testData/api/overridee.kt")
+ }
+
+ @TestMetadata("parameterTypes.kt")
+ @Test
+ fun testParameterTypes() {
+ runTest("../test-utils/testData/api/parameterTypes.kt")
+ }
+
+ @Disabled
+ @TestMetadata("parent.kt")
+ @Test
+ fun testParent() {
+ runTest("../test-utils/testData/api/parent.kt")
+ }
+
+ @Disabled
+ @TestMetadata("platformDeclaration.kt")
+ @Test
+ fun testPlatformDeclaration() {
+ runTest("../test-utils/testData/api/platformDeclaration.kt")
+ }
+
+ @Disabled
+ @TestMetadata("rawTypes.kt")
+ @Test
+ fun testRawTypes() {
+ runTest("../test-utils/testData/api/rawTypes.kt")
+ }
+
+ @Disabled
+ @TestMetadata("recordJavaAnnotationTypes.kt")
+ @Test
+ fun testRecordJavaAnnotationTypes() {
+ runTest("../test-utils/testData/api/recordJavaAnnotationTypes.kt")
+ }
+
+ @Disabled
+ @TestMetadata("recordJavaAsMemberOf.kt")
+ @Test
+ fun testRecordJavaAsMemberOf() {
+ runTest("../test-utils/testData/api/recordJavaAsMemberOf.kt")
+ }
+
+ @Disabled
+ @TestMetadata("recordJavaGetAllMembers.kt")
+ @Test
+ fun testRecordJavaGetAllMembers() {
+ runTest("../test-utils/testData/api/recordJavaGetAllMembers.kt")
+ }
+
+ @Disabled
+ @TestMetadata("recordJavaOverrides.kt")
+ @Test
+ fun testRecordJavaOverrides() {
+ runTest("../test-utils/testData/api/recordJavaOverrides.kt")
+ }
+
+ @Disabled
+ @TestMetadata("recordJavaSupertypes.kt")
+ @Test
+ fun testRecordJavaSupertypes() {
+ runTest("../test-utils/testData/api/recordJavaSupertypes.kt")
+ }
+
+ @Disabled
+ @TestMetadata("referenceElement.kt")
+ @Test
+ fun testReferenceElement() {
+ runTest("../test-utils/testData/api/referenceElement.kt")
+ }
+
+ @Disabled
+ @TestMetadata("replaceWithErrorTypeArgs.kt")
+ @Test
+ fun testReplaceWithErrorTypeArgs() {
+ runTest("../test-utils/testData/api/replaceWithErrorTypeArgs.kt")
+ }
+
+ @Disabled
+ @TestMetadata("resolveJavaType.kt")
+ @Test
+ fun testResolveJavaType() {
+ runTest("../test-utils/testData/api/resolveJavaType.kt")
+ }
+
+ @Disabled
+ @TestMetadata("sealedClass.kt")
+ @Test
+ fun testSealedClass() {
+ runTest("../test-utils/testData/api/sealedClass.kt")
+ }
+
+ @Disabled
+ @TestMetadata("signatureMapper.kt")
+ @Test
+ fun testSignatureMapper() {
+ runTest("../test-utils/testData/api/signatureMapper.kt")
+ }
+
+ @TestMetadata("superTypes.kt")
+ @Test
+ fun testSuperTypes() {
+ runTest("../test-utils/testData/api/superTypes.kt")
+ }
+
+ @Disabled
+ @TestMetadata("throwList.kt")
+ @Test
+ fun testThrowList() {
+ runTest("../test-utils/testData/api/throwList.kt")
+ }
+
+ @Disabled
+ @TestMetadata("topLevelMembers.kt")
+ @Test
+ fun testTopLevelMembers() {
+ runTest("../test-utils/testData/api/topLevelMembers.kt")
+ }
+
+ @TestMetadata("typeAlias.kt")
+ @Test
+ fun testTypeAlias() {
+ runTest("../test-utils/testData/api/typeAlias.kt")
+ }
+
+ @TestMetadata("typeAliasComparison.kt")
+ @Test
+ fun testTypeAliasComparison() {
+ runTest("../test-utils/testData/api/typeAliasComparison.kt")
+ }
+
+ @TestMetadata("typeComposure.kt")
+ @Test
+ fun testTypeComposure() {
+ runTest("../test-utils/testData/api/typeComposure.kt")
+ }
+
+ @Disabled
+ @TestMetadata("typeParameterReference.kt")
+ @Test
+ fun testTypeParameterReference() {
+ runTest("../test-utils/testData/api/typeParameterReference.kt")
+ }
+
+ @Disabled
+ @TestMetadata("varianceTypeCheck.kt")
+ @Test
+ fun testVarianceTypeCheck() {
+ runTest("../test-utils/testData/api/varianceTypeCheck.kt")
+ }
+
+ @TestMetadata("validateTypes.kt")
+ @Test
+ fun testValidateTypes() {
+ runTest("../test-utils/testData/api/validateTypes.kt")
+ }
+
+ @Disabled
+ @TestMetadata("visibilities.kt")
+ @Test
+ fun testVisibilities() {
+ runTest("../test-utils/testData/api/visibilities.kt")
+ }
+}
diff --git a/kotlin-analysis-api/testData/innerTypes.kt b/kotlin-analysis-api/testData/innerTypes.kt
new file mode 100644
index 00000000..1ae5908d
--- /dev/null
+++ b/kotlin-analysis-api/testData/innerTypes.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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: InnerTypeProcessor
+// EXPECTED:
+// C1<*>: [C1<STAR null>]
+// C1<Int>: [C1<INVARIANT Int>]
+// C2<*, *>: [C1.C2<STAR null>, C1<STAR null>]
+// C2<Short, Int>: [C1.C2<INVARIANT Short>, C1<INVARIANT Int>]
+// C3<*, *, *>: [C1.C2.C3<STAR null>, C1.C2<STAR null>, C1<STAR null>]
+// C3<Byte, Short, Int>: [C1.C2.C3<INVARIANT Byte>, C1.C2<INVARIANT Short>, C1<INVARIANT Int>]
+// C4<*>: [C1.C4<STAR null>]
+// C4<Double>: [C1.C4<INVARIANT Double>]
+// C5<*, *>: [C1.C4.C5<STAR null>, C1.C4<STAR null>]
+// C5<Float, Double>: [C1.C4.C5<INVARIANT Float>, C1.C4<INVARIANT Double>]
+// END
+
+@file:Suppress("Byte", "Int", "Short", "Double", "Float", "Suppress", "Any")
+
+class C1<T1> {
+ inner class C2<T2> {
+ inner class C3<T3> {
+
+ }
+ }
+
+ class C4<T4> {
+ inner class C5<T5>
+ }
+}
+
+val c1 = C1<Int>()
+val c2 = c1.C2<Short>()
+val c3 = c2.C3<Byte>()
+val c4 = C1.C4<Double>()
+val c5 = c4.C5<Float>()
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 00000000..68f7e505
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,18 @@
+rootProject.name = "ksp"
+
+pluginManagement {
+ repositories {
+ gradlePluginPortal()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ maven("https://www.jetbrains.com/intellij-repository/snapshots")
+ }
+}
+
+include("api")
+include("gradle-plugin")
+include("common-util")
+include("test-utils")
+include("compiler-plugin")
+include("symbol-processing")
+include("symbol-processing-cmdline")
+include("integration-tests")
diff --git a/symbol-processing-cmdline/build.gradle.kts b/symbol-processing-cmdline/build.gradle.kts
new file mode 100644
index 00000000..dc0738d4
--- /dev/null
+++ b/symbol-processing-cmdline/build.gradle.kts
@@ -0,0 +1,79 @@
+import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
+
+evaluationDependsOn(":common-util")
+evaluationDependsOn(":compiler-plugin")
+
+val kotlinBaseVersion: String by project
+val signingKey: String? by project
+val signingPassword: String? by project
+
+plugins {
+ kotlin("jvm")
+ id("com.github.johnrengelman.shadow") version "6.0.0"
+ `maven-publish`
+ signing
+}
+
+val packedJars by configurations.creating
+
+dependencies {
+ packedJars(project(":compiler-plugin")) { isTransitive = false }
+ packedJars(project(":common-util")) { isTransitive = false }
+}
+
+tasks.withType<ShadowJar>() {
+ archiveClassifier.set("")
+ // ShadowJar picks up the `compile` configuration by default and pulls stdlib in.
+ // Therefore, specifying another configuration instead.
+ configurations = listOf(packedJars)
+}
+
+tasks {
+ publish {
+ dependsOn(shadowJar)
+ dependsOn(project(":compiler-plugin").tasks["dokkaJavadocJar"])
+ dependsOn(project(":compiler-plugin").tasks["sourcesJar"])
+ }
+}
+
+publishing {
+ publications {
+ create<MavenPublication>("shadow") {
+ artifactId = "symbol-processing-cmdline"
+ artifact(tasks["shadowJar"])
+ artifact(project(":compiler-plugin").tasks["dokkaJavadocJar"])
+ artifact(project(":compiler-plugin").tasks["sourcesJar"])
+ pom {
+ name.set("com.google.devtools.ksp:symbol-processing-cmdline")
+ description.set("Symbol processing for K/N and command line")
+ withXml {
+ fun groovy.util.Node.addDependency(
+ groupId: String,
+ artifactId: String,
+ version: String,
+ scope: String = "runtime"
+ ) {
+ appendNode("dependency").apply {
+ appendNode("groupId", groupId)
+ appendNode("artifactId", artifactId)
+ appendNode("version", version)
+ appendNode("scope", scope)
+ }
+ }
+
+ asNode().appendNode("dependencies").apply {
+ addDependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlinBaseVersion)
+ addDependency("org.jetbrains.kotlin", "kotlin-compiler", kotlinBaseVersion)
+ addDependency("com.google.devtools.ksp", "symbol-processing-api", version)
+ }
+ }
+ }
+ }
+ }
+}
+
+signing {
+ isRequired = hasProperty("signingKey")
+ useInMemoryPgpKeys(signingKey, signingPassword)
+ sign(extensions.getByType<PublishingExtension>().publications)
+}
diff --git a/symbol-processing/build.gradle.kts b/symbol-processing/build.gradle.kts
new file mode 100644
index 00000000..572caacf
--- /dev/null
+++ b/symbol-processing/build.gradle.kts
@@ -0,0 +1,83 @@
+import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
+
+evaluationDependsOn(":common-util")
+evaluationDependsOn(":compiler-plugin")
+
+val kotlinBaseVersion: String by project
+val signingKey: String? by project
+val signingPassword: String? by project
+
+plugins {
+ kotlin("jvm")
+ id("com.github.johnrengelman.shadow") version "6.0.0"
+ `maven-publish`
+ signing
+}
+
+val packedJars by configurations.creating
+
+dependencies {
+ packedJars(project(":compiler-plugin")) { isTransitive = false }
+ packedJars(project(":common-util")) { isTransitive = false }
+}
+
+tasks.withType<ShadowJar>() {
+ archiveClassifier.set("")
+ // ShadowJar picks up the `compile` configuration by default and pulls stdlib in.
+ // Therefore, specifying another configuration instead.
+ configurations = listOf(packedJars)
+ relocate("com.intellij", "org.jetbrains.kotlin.com.intellij")
+}
+
+tasks {
+ publish {
+ dependsOn(shadowJar)
+ dependsOn(project(":compiler-plugin").tasks["dokkaJavadocJar"])
+ dependsOn(project(":compiler-plugin").tasks["sourcesJar"])
+ }
+}
+
+publishing {
+ publications {
+ create<MavenPublication>("shadow") {
+ artifactId = "symbol-processing"
+ artifact(project(":compiler-plugin").tasks["dokkaJavadocJar"])
+ artifact(project(":compiler-plugin").tasks["sourcesJar"])
+ artifact(tasks["shadowJar"])
+ pom {
+ name.set("com.google.devtools.ksp:symbol-processing")
+ description.set("Symbol processing for Kotlin")
+ // FIXME: figure out how to make ShadowJar generate dependencies in POM,
+ // or simply depends on kotlin-compiler-embeddable so that relocation
+ // isn't needed, at the price of giving up composite build.
+ withXml {
+ fun groovy.util.Node.addDependency(
+ groupId: String,
+ artifactId: String,
+ version: String,
+ scope: String = "runtime"
+ ) {
+ appendNode("dependency").apply {
+ appendNode("groupId", groupId)
+ appendNode("artifactId", artifactId)
+ appendNode("version", version)
+ appendNode("scope", scope)
+ }
+ }
+
+ asNode().appendNode("dependencies").apply {
+ addDependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlinBaseVersion)
+ addDependency("org.jetbrains.kotlin", "kotlin-compiler-embeddable", kotlinBaseVersion)
+ addDependency("com.google.devtools.ksp", "symbol-processing-api", version)
+ }
+ }
+ }
+ }
+ }
+}
+
+signing {
+ isRequired = hasProperty("signingKey")
+ useInMemoryPgpKeys(signingKey, signingPassword)
+ sign(extensions.getByType<PublishingExtension>().publications)
+}
diff --git a/test-utils/build.gradle.kts b/test-utils/build.gradle.kts
new file mode 100644
index 00000000..ddad28a7
--- /dev/null
+++ b/test-utils/build.gradle.kts
@@ -0,0 +1,34 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+val kotlinBaseVersion: String by project
+val intellijVersion: String by project
+
+tasks.withType<KotlinCompile> {
+ compilerOptions.freeCompilerArgs.add("-Xjvm-default=all-compatibility")
+}
+plugins {
+ kotlin("jvm")
+}
+
+version = "2.0.255-SNAPSHOT"
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+
+ implementation("org.jetbrains.kotlin:kotlin-compiler:$kotlinBaseVersion")
+ implementation("org.jetbrains.kotlin:kotlin-compiler-internal-test-framework:$kotlinBaseVersion")
+
+ implementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
+
+ implementation(project(":api"))
+ implementation(project(":compiler-plugin"))
+}
+
+repositories {
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/")
+ maven("https://www.jetbrains.com/intellij-repository/releases")
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractFunctionsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractFunctionsProcessor.kt
new file mode 100644
index 00000000..2b49854e
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractFunctionsProcessor.kt
@@ -0,0 +1,33 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class AbstractFunctionsProcessor : AbstractTestProcessor() {
+ private val visitor = Visitor()
+
+ override fun toResult(): List<String> {
+ return visitor.abstractFunctionNames.sorted()
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach { it.accept(visitor, Unit) }
+ return emptyList()
+ }
+
+ private class Visitor : KSTopDownVisitor<Unit, Unit>() {
+ val abstractFunctionNames = arrayListOf<String>()
+
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ if (function.isAbstract) {
+ abstractFunctionNames += function.simpleName.asString()
+ }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractTestProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractTestProcessor.kt
new file mode 100644
index 00000000..c6a81876
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractTestProcessor.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
+import com.google.devtools.ksp.processing.SymbolProcessorProvider
+
+abstract class AbstractTestProcessor : SymbolProcessor, SymbolProcessorProvider {
+ abstract fun toResult(): List<String>
+
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = this
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AllFunctionsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AllFunctionsProcessor.kt
new file mode 100644
index 00000000..65c682b2
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AllFunctionsProcessor.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+class AllFunctionsProcessor : AbstractTestProcessor() {
+ val visitor = AllFunctionsVisitor()
+
+ override fun toResult(): List<String> {
+ return visitor.toResult()
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach { it.accept(visitor, Unit) }
+ return emptyList()
+ }
+
+ class AllFunctionsVisitor : KSVisitorVoid() {
+ private val declarationsByClass = mutableMapOf<String, MutableList<String>>()
+ fun toResult(): List<String> {
+ return declarationsByClass.entries
+ .sortedBy {
+ it.key
+ }.flatMap {
+ listOf(it.key) + it.value
+ }
+ }
+ fun KSFunctionDeclaration.toSignature(): String {
+ return this.simpleName.asString() +
+ "(${this.parameters.map {
+ buildString {
+ append(it.type.resolve().declaration.qualifiedName?.asString())
+ if (it.hasDefault) {
+ append("(hasDefault)")
+ }
+ if (it.isVararg) {
+ append(" ...")
+ }
+ }
+ }.joinToString(",")})" +
+ ": ${this.returnType?.resolve()?.declaration?.qualifiedName?.asString() ?: ""}"
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ val declarations = mutableListOf<String>()
+ // first add properties
+ declarations.addAll(
+ classDeclaration.getAllProperties().map {
+ it.toString()
+ }.sorted()
+ )
+ // then add functions
+ declarations.addAll(
+ classDeclaration.getAllFunctions().map {
+ it.toSignature()
+ }.sorted()
+ )
+ declarationsByClass["class: ${classDeclaration.simpleName.asString()}"] = declarations
+ }
+
+ override fun visitFile(file: KSFile, data: Unit) {
+ file.declarations.forEach { it.accept(this, Unit) }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotatedUtilProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotatedUtilProcessor.kt
new file mode 100644
index 00000000..954feb43
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotatedUtilProcessor.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getAnnotationsByType
+import com.google.devtools.ksp.isAnnotationPresent
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+import kotlin.reflect.KClass
+
+class AnnotatedUtilProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ private val annotationKClasses = listOf(
+ ParametersTestAnnotation::class,
+ ParameterArraysTestAnnotation::class,
+ ParametersTestWithNegativeDefaultsAnnotation::class,
+ OuterAnnotation::class
+ )
+ private val visitors = listOf(IsAnnotationPresentVisitor(), GetAnnotationsByTypeVisitor())
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getSymbolsWithAnnotation("com.google.devtools.ksp.processor.Test", true).forEach {
+ results.add("Test: $it")
+ visitors.forEach { visitor -> it.accept(visitor, results) }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ inner class IsAnnotationPresentVisitor : KSTopDownVisitor<MutableCollection<String>, Unit>() {
+ @OptIn(KspExperimental::class)
+ override fun visitAnnotated(annotated: KSAnnotated, data: MutableCollection<String>) {
+ annotationKClasses.forEach { clazz ->
+ if (annotated.isAnnotationPresent(clazz)) {
+ data.add("IsPresent: $clazz")
+ }
+ }
+ }
+
+ override fun defaultHandler(node: KSNode, data: MutableCollection<String>) {
+ }
+ }
+
+ inner class GetAnnotationsByTypeVisitor : KSTopDownVisitor<MutableCollection<String>, Unit>() {
+ @OptIn(KspExperimental::class)
+ override fun visitAnnotated(annotated: KSAnnotated, data: MutableCollection<String>) {
+ annotationKClasses.forEach { clazz ->
+ annotated.getAnnotationsByType(clazz).forEach { data.add("ByType: ${it.asString()}") }
+ }
+ }
+
+ override fun defaultHandler(node: KSNode, data: MutableCollection<String>) {
+ }
+ }
+}
+
+@Suppress("LongParameterList")
+annotation class ParametersTestAnnotation(
+ val booleanValue: Boolean = false,
+ val byteValue: Byte = 2,
+ val shortValue: Short = 3,
+ val charValue: Char = 'b',
+ val doubleValue: Double = 4.0,
+ val floatValue: Float = 5.0f,
+ val intValue: Int = 6,
+ val longValue: Long = 7L,
+ val stringValue: String = "emptystring",
+ val kClassValue: KClass<*> = ParametersTestAnnotation::class,
+ val enumValue: TestEnum = TestEnum.NONE,
+)
+
+fun ParameterArraysTestAnnotation.asString(): String =
+ "ParameterArraysTestAnnotation" +
+ "[booleanArrayValue=${booleanArrayValue.asList()}," +
+ "byteArrayValue=${byteArrayValue.asList()}," +
+ "shortArrayValue=${shortArrayValue.asList()}," +
+ "charArrayValue=${charArrayValue.asList()}," +
+ "doubleArrayValue=${doubleArrayValue.asList()}," +
+ "floatArrayValue=${floatArrayValue.asList()}," +
+ "intArrayValue=${intArrayValue.asList()}," +
+ "longArrayValue=${longArrayValue.asList()}," +
+ "stringArrayValue=${stringArrayValue.asList()}," +
+ "kClassArrayValue=${kClassArrayValue.asList()}," +
+ "enumArrayValue=${enumArrayValue.asList()}]"
+
+@Suppress("LongParameterList")
+annotation class ParameterArraysTestAnnotation(
+ val booleanArrayValue: BooleanArray = booleanArrayOf(),
+ val byteArrayValue: ByteArray = byteArrayOf(),
+ val shortArrayValue: ShortArray = shortArrayOf(),
+ val charArrayValue: CharArray = charArrayOf(),
+ val doubleArrayValue: DoubleArray = doubleArrayOf(),
+ val floatArrayValue: FloatArray = floatArrayOf(),
+ val intArrayValue: IntArray = intArrayOf(),
+ val longArrayValue: LongArray = longArrayOf(),
+ val stringArrayValue: Array<String> = emptyArray(),
+ val kClassArrayValue: Array<KClass<*>> = emptyArray(),
+ val enumArrayValue: Array<TestEnum> = emptyArray(),
+)
+
+annotation class ParametersTestWithNegativeDefaultsAnnotation(
+ val byteValue: Byte = -2,
+ val shortValue: Short = -3,
+ val doubleValue: Double = -4.0,
+ val floatValue: Float = -5.0f,
+ val intValue: Int = -6,
+ val longValue: Long = -7L,
+)
+
+enum class TestEnum {
+ NONE, VALUE1, VALUE2
+}
+
+annotation class Test
+
+annotation class InnerAnnotation(val value: String = "default")
+
+annotation class OuterAnnotation(
+ val innerAnnotation: InnerAnnotation = InnerAnnotation(),
+)
+
+fun Annotation.asString(): String {
+ return when (this) {
+ is ParameterArraysTestAnnotation -> asString()
+ else -> toString()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArbitraryClassValueProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArbitraryClassValueProcessor.kt
new file mode 100644
index 00000000..26bbb2a9
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArbitraryClassValueProcessor.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KSTypeNotPresentException
+import com.google.devtools.ksp.KSTypesNotPresentException
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getAnnotationsByType
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import kotlin.reflect.KClass
+
+@KspExperimental
+class AnnotationArbitraryClassValueProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val symbols = resolver.getSymbolsWithAnnotation(
+ "com.google.devtools.ksp.processor.ClassValueAnnotation"
+ )
+ symbols.flatMap {
+ it.getAnnotationsByType(ClassValueAnnotation::class)
+ }.forEach {
+ logAnnotationValues(it)
+ }
+ return emptyList()
+ }
+
+ private fun logAnnotationValues(classValueAnnotation: ClassValueAnnotation) {
+ try {
+ classValueAnnotation.classValue
+ } catch (e: Exception) {
+ assert(e is KSTypeNotPresentException)
+ e as KSTypeNotPresentException
+ result.add(e.ksType.toString())
+ }
+
+ try {
+ classValueAnnotation.classValues
+ } catch (e: Exception) {
+ assert(e is KSTypesNotPresentException)
+ e as KSTypesNotPresentException
+ result.add(e.ksTypes.joinToString())
+ }
+ }
+}
+
+annotation class ClassValueAnnotation(
+ val classValue: KClass<*>,
+ val classValues: Array<KClass<*>>
+)
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
new file mode 100644
index 00000000..68e263c6
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArgumentProcessor.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSValueArgument
+import com.google.devtools.ksp.symbol.KSVisitorVoid
+
+class AnnotationArgumentProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val visitor = ArgumentVisitor()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getSymbolsWithAnnotation("Bar", true).forEach {
+ it.annotations.forEach { it.arguments.forEach { it.accept(visitor, Unit) } }
+ }
+
+ val C = resolver.getClassDeclarationByName("C")
+ C?.annotations?.first()?.arguments?.forEach { results.add(it.value.toString()) }
+ val ThrowsClass = resolver.getClassDeclarationByName("ThrowsClass")
+ ThrowsClass?.declarations?.filter {
+ it.simpleName.asString() == "throwsException"
+ }?.forEach {
+ it.annotations.single().annotationType.resolve().declaration.let {
+ results.add(it.toString())
+ }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ inner class ArgumentVisitor : KSVisitorVoid() {
+ override fun visitValueArgument(valueArgument: KSValueArgument, data: Unit) {
+ if (valueArgument.value is KSType) {
+ results.add((valueArgument.value as KSType).declaration.toString())
+ } else {
+ results.add(valueArgument.value.toString())
+ }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueProcessor.kt
new file mode 100644
index 00000000..e82a3252
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueProcessor.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+
+class AnnotationArrayValueProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val ktClass = resolver.getClassDeclarationByName("KotlinAnnotated")!!
+ logAnnotations(ktClass)
+ val javaClass = resolver.getClassDeclarationByName("JavaAnnotated")!!
+ logAnnotations(javaClass)
+ return emptyList()
+ }
+
+ private fun logAnnotations(classDeclaration: KSClassDeclaration) {
+ result.add(classDeclaration.qualifiedName!!.asString())
+ classDeclaration.annotations.forEach { annotation ->
+ result.add("${annotation.shortName.asString()} ->")
+ annotation.arguments.forEach {
+ val value = it.value
+ val key = it.name?.asString()
+ if (value is Array<*>) {
+ result.add("$key = [${value.joinToString(", ")}]")
+ } else {
+ result.add("$key = ${it.value}")
+ }
+ }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValueProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValueProcessor.kt
new file mode 100644
index 00000000..bd2c1aae
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValueProcessor.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.isDefault
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+
+class AnnotationDefaultValueProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val ktClass = resolver.getClassDeclarationByName(resolver.getKSNameFromString("A"))!!
+ logAnnotations(ktClass)
+ val javaClass = resolver.getClassDeclarationByName(resolver.getKSNameFromString("JavaAnnotated"))!!
+ logAnnotations(javaClass)
+ return emptyList()
+ }
+
+ private fun logAnnotations(classDeclaration: KSClassDeclaration) {
+ classDeclaration.annotations.forEach { annotation ->
+ result.add(
+ "${annotation.shortName.asString()} -> ${annotation.arguments.map{
+ "${it.name?.asString()}:${it.value}:${it.isDefault()}"
+ }.joinToString(",")}"
+ )
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValuesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValuesProcessor.kt
new file mode 100644
index 00000000..2637cb2f
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValuesProcessor.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+
+class AnnotationDefaultValuesProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val ktClass = resolver.getClassDeclarationByName(resolver.getKSNameFromString("A"))!!
+ logAnnotations(ktClass)
+ val javaClass = resolver.getClassDeclarationByName(resolver.getKSNameFromString("JavaAnnotated"))!!
+ logAnnotations(javaClass)
+ return emptyList()
+ }
+
+ private fun logAnnotations(classDeclaration: KSClassDeclaration) {
+ classDeclaration.annotations.forEach { annotation ->
+ result.add(
+ "${annotation.shortName.asString()} -> ${annotation.defaultArguments.map{
+ "${it.name?.asString()}:${it.value}"
+ }.joinToString(",")}"
+ )
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationJavaTypeValueProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationJavaTypeValueProcessor.kt
new file mode 100644
index 00000000..e59763de
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationJavaTypeValueProcessor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+
+class AnnotationJavaTypeValueProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val javaClass = resolver.getClassDeclarationByName("JavaAnnotated")!!
+ logAnnotations(javaClass)
+ return emptyList()
+ }
+
+ private fun logAnnotations(classDeclaration: KSClassDeclaration) {
+ result.add(classDeclaration.qualifiedName!!.asString())
+ classDeclaration.annotations.forEach { annotation ->
+ result.add("${annotation.shortName.asString()} ->")
+ annotation.arguments.forEach {
+ val value = it.value
+ val key = it.name?.asString()
+ if (value is Array<*>) {
+ result.add("$key = [${value.joinToString(", ")}]")
+ } else {
+ result.add("$key = ${it.value}")
+ }
+ }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationOnConstructorParameterProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationOnConstructorParameterProcessor.kt
new file mode 100644
index 00000000..1b7b0349
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationOnConstructorParameterProcessor.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getDeclaredFunctions
+import com.google.devtools.ksp.getDeclaredProperties
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+class AnnotationOnConstructorParameterProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getAllFiles().first().declarations.single { it.qualifiedName!!.asString() == "Sample" }.let { clz ->
+ clz as KSClassDeclaration
+ val prop1 = clz.getAllProperties().single { it.simpleName.asString() == "fullName" }
+ val prop2 = clz.getDeclaredProperties().single { it.simpleName.asString() == "fullName" }
+ prop1.annotations.forEach { anno ->
+ results.add(anno.shortName.asString())
+ }
+ results.add((prop1 === prop2).toString())
+ val fun1 = clz.getAllFunctions().single { it.simpleName.asString() == "foo" }
+ val fun2 = clz.getDeclaredFunctions().single { it.simpleName.asString() == "foo" }
+ results.add((fun1 === fun2).toString())
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationsInDependenciesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationsInDependenciesProcessor.kt
new file mode 100644
index 00000000..f80b7ef7
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationsInDependenciesProcessor.kt
@@ -0,0 +1,93 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class AnnotationsInDependenciesProcessor : AbstractTestProcessor() {
+ private val results = mutableListOf<String>()
+ override fun toResult() = results
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ // NOTE: There are two cases this test ignores.
+ // a) For property annotations with target, they get added to the property getter/setter whereas it would show
+ // on the property as well if it was in kotlin source. This test expects it in both for kotlin source
+ // whereas it expects it only in the getter/setter for compiled kotlin source
+ // b) When an annotation without a target is used in a constructor (with field), that annotation is not copied
+ // to the backing field for .class files. The assertion line in test ignores it (see the NoTargetAnnotation
+ // output difference for the DataClass)
+ addToResults(resolver, "main.KotlinClass")
+ addToResults(resolver, "lib.KotlinClass")
+ addToResults(resolver, "main.DataClass")
+ addToResults(resolver, "lib.DataClass")
+ return emptyList()
+ }
+
+ private fun addToResults(resolver: Resolver, qName: String) {
+ results.add("$qName ->")
+ val collected = collectAnnotations(resolver, qName)
+ val signatures = collected.flatMap { (annotated, annotations) ->
+ val annotatedSignature = annotated.toSignature()
+ annotations.map {
+ "$annotatedSignature : ${it.toSignature()}"
+ }
+ }.sorted()
+ results.addAll(signatures)
+ }
+
+ private fun collectAnnotations(resolver: Resolver, qName: String): Map<KSAnnotated, List<KSAnnotation>> {
+ val output = mutableMapOf<KSAnnotated, List<KSAnnotation>>()
+ resolver.getClassDeclarationByName(qName)?.accept(
+ AnnotationVisitor(),
+ output
+ )
+ return output
+ }
+
+ private fun KSAnnotated.toSignature(): String {
+ return when (this) {
+ is KSClassDeclaration -> "class " + (qualifiedName ?: simpleName).asString()
+ is KSPropertyDeclaration -> "property ${simpleName.asString()}"
+ is KSFunctionDeclaration -> "function ${simpleName.asString()}"
+ is KSValueParameter -> name?.let {
+ "parameter ${it.asString()}"
+ } ?: "no-name-value-parameter"
+ is KSPropertyGetter -> "getter of ${receiver.toSignature()}"
+ is KSPropertySetter -> "setter of ${receiver.toSignature()}"
+ else -> {
+ error("unexpected annotated")
+ }
+ }
+ }
+
+ private fun KSAnnotation.toSignature(): String {
+ val type = this.annotationType.resolve().declaration.let {
+ (it.qualifiedName ?: it.simpleName).asString()
+ }
+ val args = this.arguments.map {
+ "[${it.name?.asString()} = ${it.value}]"
+ }.joinToString(",")
+ return "$type{$args}"
+ }
+
+ class AnnotationVisitor : KSTopDownVisitor<MutableMap<KSAnnotated, List<KSAnnotation>>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableMap<KSAnnotated, List<KSAnnotation>>) {
+ }
+
+ override fun visitAnnotated(annotated: KSAnnotated, data: MutableMap<KSAnnotated, List<KSAnnotation>>) {
+ val annotations = annotated.annotations.toList()
+ if (annotations.isNotEmpty()) {
+ data[annotated] = annotations
+ }
+ super.visitAnnotated(annotated, data)
+ }
+
+ override fun visitTypeReference(
+ typeReference: KSTypeReference,
+ data: MutableMap<KSAnnotated, List<KSAnnotation>>
+ ) {
+ // don't traverse type references
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AsMemberOfProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AsMemberOfProcessor.kt
new file mode 100644
index 00000000..7c260375
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AsMemberOfProcessor.kt
@@ -0,0 +1,235 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getDeclaredFunctions
+import com.google.devtools.ksp.isConstructor
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+@Suppress("unused") // used by generated tests
+class AsMemberOfProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ // keep a list of all signatures we generate and ensure equals work as expected
+ private val functionsBySignature = mutableMapOf<String, MutableSet<KSFunction>>()
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val base = resolver.getClassDeclarationByName("Base")!!
+ val child1 = resolver.getClassDeclarationByName("Child1")!!
+ addToResults(resolver, base, child1.asStarProjectedType())
+ val child2 = resolver.getClassDeclarationByName("Child2")!!
+ addToResults(resolver, base, child2.asStarProjectedType())
+ val child2WithString = resolver.getDeclaration<KSPropertyDeclaration>("child2WithString")
+ addToResults(resolver, base, child2WithString.type.resolve())
+
+ // check cases where given type is not a subtype
+ val notAChild = resolver.getClassDeclarationByName("NotAChild")!!
+ addToResults(resolver, base, notAChild.asStarProjectedType())
+ val listOfStrings = resolver.getDeclaration<KSPropertyDeclaration>("listOfStrings").type.resolve()
+ val setOfStrings = resolver.getDeclaration<KSPropertyDeclaration>("setOfStrings").type.resolve()
+ val listClass = resolver.getClassDeclarationByName("kotlin.collections.List")!!
+ val setClass = resolver.getClassDeclarationByName("kotlin.collections.Set")!!
+ val listGet = listClass.getAllFunctions().first {
+ it.simpleName.asString() == "get"
+ }
+ results.add("List#get")
+ results.add("listOfStrings: " + resolver.asMemberOfSignature(listGet, listOfStrings))
+ results.add("setOfStrings: " + resolver.asMemberOfSignature(listGet, setOfStrings))
+
+ val setContains = setClass.getAllFunctions().first {
+ it.simpleName.asString() == "contains"
+ }
+ results.add("Set#contains")
+ results.add("listOfStrings: " + resolver.asMemberOfSignature(setContains, listOfStrings))
+ results.add("setOfStrings: " + resolver.asMemberOfSignature(setContains, setOfStrings))
+
+ val javaBase = resolver.getClassDeclarationByName("JavaBase")!!
+ val javaChild1 = resolver.getClassDeclarationByName("JavaChild1")!!
+ addToResults(resolver, javaBase, javaChild1.asStarProjectedType())
+
+ val fileLevelFunction = resolver.getDeclaration<KSFunctionDeclaration>("fileLevelFunction")
+ results.add("fileLevelFunction: " + resolver.asMemberOfSignature(fileLevelFunction, listOfStrings))
+
+ // TODO we should eventually support this, probably as different asReceiverOf kind of API
+ val fileLevelExtensionFunction = resolver.getDeclaration<KSFunctionDeclaration>("fileLevelExtensionFunction")
+ results.add(
+ "fileLevelExtensionFunction: " +
+ resolver.asMemberOfSignature(fileLevelExtensionFunction, listOfStrings)
+ )
+
+ val fileLevelProperty = resolver.getDeclaration<KSPropertyDeclaration>("fileLevelProperty")
+ results.add("fileLevelProperty: " + resolver.asMemberOfSignature(fileLevelProperty, listOfStrings))
+
+ val errorType = resolver.getDeclaration<KSPropertyDeclaration>("errorType").type.resolve()
+ results.add("errorType: " + resolver.asMemberOfSignature(listGet, errorType))
+
+ // make sure values are cached
+ val first = listGet.asMemberOf(listOfStrings)
+ val second = listGet.asMemberOf(listOfStrings)
+ if (first !== second) {
+ results.add("cache error, repeated computation")
+ }
+
+ // validate equals implementation
+ // all functions with the same signature should be equal to each-other unless there is an error / incomplete
+ // type in them
+ val notEqualToItself = functionsBySignature.filter { (_, functions) ->
+ functions.size != 1
+ }.keys
+ results.add("expected comparison failures")
+ results.addAll(notEqualToItself)
+ // make sure we don't have any false positive equals
+ functionsBySignature.forEach { (signature, functions) ->
+ functionsBySignature.forEach { (otherSignature, otherFunctions) ->
+ if (signature != otherSignature && functions.any { otherFunctions.contains(it) }) {
+ results.add("Unexpected equals between $otherSignature and $signature")
+ }
+ }
+ }
+ val javaImpl = resolver.getClassDeclarationByName("JavaImpl")!!
+ val getX = javaImpl.getDeclaredFunctions().first { it.simpleName.asString() == "getX" }
+ val getY = javaImpl.getDeclaredFunctions().first { it.simpleName.asString() == "getY" }
+ val setY = javaImpl.getDeclaredFunctions().first { it.simpleName.asString() == "setY" }
+ results.add(getX.asMemberOf(javaImpl.asStarProjectedType()).toSignature())
+ results.add(getY.asMemberOf(javaImpl.asStarProjectedType()).toSignature())
+ results.add(setY.asMemberOf(javaImpl.asStarProjectedType()).toSignature())
+ return emptyList()
+ }
+
+ private inline fun <reified T : KSDeclaration> Resolver.getDeclaration(name: String): T {
+ return getNewFiles().first {
+ it.fileName == "Input.kt"
+ }.declarations.filterIsInstance<T>().first {
+ it.simpleName.asString() == name
+ }
+ }
+
+ private fun addToResults(resolver: Resolver, baseClass: KSClassDeclaration, child: KSType) {
+ results.add(child.toSignature())
+ val baseProperties = baseClass.getAllProperties()
+ val baseFunction = baseClass.getDeclaredFunctions().filterNot { it.isConstructor() }
+ results.addAll(
+ baseProperties.map { property ->
+ val typeSignature = resolver.asMemberOfSignature(
+ property = property,
+ containing = child
+ )
+ "${property.simpleName.asString()}: $typeSignature"
+ }
+ )
+ results.addAll(
+ baseFunction.map { function ->
+ val functionSignature = resolver.asMemberOfSignature(
+ function = function,
+ containing = child
+ )
+ "${function.simpleName.asString()}: $functionSignature"
+ }
+ )
+ }
+
+ private fun Resolver.asMemberOfSignature(
+ function: KSFunctionDeclaration,
+ containing: KSType
+ ): String {
+ val result = kotlin.runCatching {
+ function.asMemberOf(containing).also {
+ if (it !== function.asMemberOf(containing)) {
+ results.add("cache error, repeated computation")
+ }
+ }
+ }
+ return if (result.isSuccess) {
+ val ksFunction = result.getOrThrow()
+ val signature = ksFunction.toSignature()
+ // record it to validate equality against other signatures
+ functionsBySignature.getOrPut(signature) {
+ mutableSetOf()
+ }.add(ksFunction)
+ signature
+ } else {
+ result.exceptionOrNull()!!.toSignature()
+ }
+ }
+
+ private fun Resolver.asMemberOfSignature(
+ property: KSPropertyDeclaration,
+ containing: KSType
+ ): String {
+ val result = kotlin.runCatching {
+ property.asMemberOf(containing).also {
+ if (it !== property.asMemberOf(containing)) {
+ results.add("cache error, repeated computation")
+ }
+ }
+ }
+ return if (result.isSuccess) {
+ result.getOrThrow().toSignature()
+ } else {
+ result.exceptionOrNull()!!.toSignature()
+ }
+ }
+
+ private fun Throwable.toSignature() = "${this::class.qualifiedName}: $message"
+ private fun KSType.toSignature(): String {
+ val name = this.declaration.qualifiedName?.asString()
+ ?: this.declaration.simpleName.asString()
+ val qName = name + nullability.toSignature()
+ if (arguments.toList().isEmpty()) {
+ return qName
+ }
+ val args = arguments.joinToString(", ") {
+ it.type?.resolve()?.toSignature() ?: "no-type"
+ }
+ return "$qName<$args>"
+ }
+
+ private fun KSTypeParameter.toSignature(): String {
+ val boundsSignature = if (bounds.toList().isEmpty()) {
+ ""
+ } else {
+ bounds.joinToString(
+ separator = ", ",
+ prefix = ": "
+ ) {
+ it.resolve().toSignature()
+ }
+ }
+ val varianceSignature = if (variance.label.isBlank()) {
+ ""
+ } else {
+ "${variance.label} "
+ }
+ val name = this.name.asString()
+ return "$varianceSignature$name$boundsSignature"
+ }
+
+ private fun KSFunction.toSignature(): String {
+ val returnType = this.returnType?.toSignature() ?: "no-return-type"
+ val params = parameterTypes.joinToString(", ") {
+ it?.toSignature() ?: "no-type-param"
+ }
+ val paramTypeArgs = this.typeParameters.joinToString(", ") {
+ it.toSignature()
+ }
+ val paramTypesSignature = if (paramTypeArgs.isBlank()) {
+ ""
+ } else {
+ "<$paramTypeArgs>"
+ }
+ val receiverSignature = if (extensionReceiverType != null) {
+ extensionReceiverType!!.toSignature() + "."
+ } else {
+ ""
+ }
+ return "$receiverSignature$paramTypesSignature($params) -> $returnType"
+ }
+
+ private fun Nullability.toSignature() = when (this) {
+ Nullability.NULLABLE -> "?"
+ Nullability.NOT_NULL -> "!!"
+ Nullability.PLATFORM -> ""
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BackingFieldProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BackingFieldProcessor.kt
new file mode 100644
index 00000000..ed4d8f39
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BackingFieldProcessor.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+@Suppress("unused") // used in tests
+@OptIn(KspExperimental::class)
+open class BackingFieldProcessor : AbstractTestProcessor() {
+ lateinit var results: List<String>
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ results = listOf("lib", "main").flatMap { pkg ->
+ resolver.getDeclarationsFromPackage(pkg)
+ .flatMap { declaration ->
+ val properties = mutableListOf<KSPropertyDeclaration>()
+ declaration.accept(AllMembersVisitor(), properties)
+ properties
+ }.map {
+ "${it.qualifiedName?.asString()}: ${it.hasBackingField}"
+ }.sorted()
+ }
+ return emptyList()
+ }
+
+ private class AllMembersVisitor : KSTopDownVisitor<MutableList<KSPropertyDeclaration>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableList<KSPropertyDeclaration>) {
+ }
+
+ override fun visitPropertyDeclaration(
+ property: KSPropertyDeclaration,
+ data: MutableList<KSPropertyDeclaration>
+ ) {
+ data.add(property)
+ super.visitPropertyDeclaration(property, data)
+ }
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BaseVisitor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BaseVisitor.kt
new file mode 100644
index 00000000..1f7838dd
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BaseVisitor.kt
@@ -0,0 +1,26 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSFile
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSVisitorVoid
+
+open class BaseVisitor : KSVisitorVoid() {
+ override fun visitClassDeclaration(type: KSClassDeclaration, data: Unit) {
+ for (declaration in type.declarations) {
+ declaration.accept(this, Unit)
+ }
+ }
+
+ override fun visitFile(file: KSFile, data: Unit) {
+ for (declaration in file.declarations) {
+ declaration.accept(this, Unit)
+ }
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ for (declaration in function.declarations) {
+ declaration.accept(this, Unit)
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BuiltInTypesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BuiltInTypesProcessor.kt
new file mode 100644
index 00000000..fd5f87a1
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BuiltInTypesProcessor.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+open class BuiltInTypesProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val typeCollector = TypeCollectorNoAccessor()
+ val types = mutableSetOf<KSType>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+ val ignoredNames = mutableSetOf<String>()
+
+ files.forEach {
+ it.accept(typeCollector, types)
+ }
+
+ val builtInTypes = listOf<KSType>(
+ resolver.builtIns.annotationType,
+ resolver.builtIns.anyType,
+ resolver.builtIns.arrayType,
+ resolver.builtIns.booleanType,
+ resolver.builtIns.byteType,
+ resolver.builtIns.charType,
+ resolver.builtIns.doubleType,
+ resolver.builtIns.floatType,
+ resolver.builtIns.intType,
+ resolver.builtIns.iterableType,
+ resolver.builtIns.longType,
+ resolver.builtIns.nothingType,
+ resolver.builtIns.numberType,
+ resolver.builtIns.shortType,
+ resolver.builtIns.stringType,
+ resolver.builtIns.unitType
+ ).sortedBy { it.toString() }
+
+ val collectedTypes = types.sortedBy { it.toString() }
+
+ results.addAll(builtInTypes.zip(collectedTypes).map { (b, c) -> "$b: " + if (b == c) "OK" else "FAIL" })
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CheckOverrideProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CheckOverrideProcessor.kt
new file mode 100644
index 00000000..0eefc142
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CheckOverrideProcessor.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getDeclaredFunctions
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+class CheckOverrideProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ fun checkOverride(overrider: KSDeclaration, overridee: KSDeclaration, containing: KSClassDeclaration? = null) {
+ results.add(
+ "${overrider.qualifiedName?.asString()} overrides ${overridee.qualifiedName?.asString()}: " +
+ "${containing?.let { resolver.overrides(overrider, overridee, containing) }
+ ?: resolver.overrides(overrider, overridee)}"
+ )
+ }
+ val javaList = resolver.getClassDeclarationByName(resolver.getKSNameFromString("JavaList"))
+ as KSClassDeclaration
+ val kotlinList = resolver.getClassDeclarationByName(resolver.getKSNameFromString("KotlinList"))
+ as KSClassDeclaration
+ val getFunKt = resolver.getSymbolsWithAnnotation("GetAnno").single() as KSFunctionDeclaration
+ val getFunJava = javaList.getAllFunctions().single { it.simpleName.asString() == "get" }
+ val fooFunJava = javaList.getDeclaredFunctions().single { it.simpleName.asString() == "foo" }
+ val fooFunKt = resolver.getSymbolsWithAnnotation("FooAnno").single() as KSFunctionDeclaration
+ val foooFunKt = resolver.getSymbolsWithAnnotation("BarAnno").single() as KSFunctionDeclaration
+ val equalFunKt = kotlinList.getDeclaredFunctions().single { it.simpleName.asString() == "equals" }
+ val equalFunJava = javaList.getAllFunctions().single { it.simpleName.asString() == "equals" }
+ val bazPropKt = resolver.getSymbolsWithAnnotation("BazAnno").single() as KSPropertyDeclaration
+ val baz2PropKt = resolver.getSymbolsWithAnnotation("Baz2Anno").single() as KSPropertyDeclaration
+ val bazzPropKt = resolver.getSymbolsWithAnnotation("BazzAnno")
+ .filterIsInstance<KSPropertyDeclaration>().single()
+ val bazz2PropKt = resolver.getSymbolsWithAnnotation("Bazz2Anno").single() as KSPropertyDeclaration
+ checkOverride(getFunKt, getFunJava)
+ checkOverride(fooFunKt, fooFunJava)
+ checkOverride(foooFunKt, fooFunJava)
+ checkOverride(fooFunKt, fooFunKt)
+ checkOverride(equalFunKt, equalFunJava)
+ checkOverride(bazPropKt, baz2PropKt)
+ checkOverride(bazPropKt, bazz2PropKt)
+ checkOverride(bazzPropKt, bazz2PropKt)
+ checkOverride(bazzPropKt, baz2PropKt)
+ checkOverride(bazPropKt, bazPropKt)
+ val JavaImpl = resolver.getClassDeclarationByName("JavaImpl")!!
+ val MyInterface = resolver.getClassDeclarationByName("MyInterface")!!
+ val MyInterface2 = resolver.getClassDeclarationByName("MyInterface2")!!
+ val MyInterface2ImplWithoutType = resolver.getClassDeclarationByName("MyInterface2ImplWithoutType")!!
+ val MyInterface2ImplWithType = resolver.getClassDeclarationByName("MyInterface2ImplWithType")!!
+ val getX = JavaImpl.getDeclaredFunctions().first { it.simpleName.asString() == "getX" }
+ val getY = JavaImpl.getDeclaredFunctions().first { it.simpleName.asString() == "getY" }
+ val setY = JavaImpl.getDeclaredFunctions().first { it.simpleName.asString() == "setY" }
+ val setX = JavaImpl.getDeclaredFunctions().first { it.simpleName.asString() == "setX" }
+ val myInterfaceX = MyInterface.declarations.first { it.simpleName.asString() == "x" }
+ val myInterfaceY = MyInterface.declarations.first { it.simpleName.asString() == "y" }
+ val myInterface2receiveList = MyInterface2.declarations.single()
+ val myInterface2ImplWithoutTypereceiveList = MyInterface2ImplWithoutType.declarations.single()
+ val myInterface2ImplWithTypereceiveList = MyInterface2ImplWithType.declarations.single()
+ checkOverride(getY, getX)
+ checkOverride(getY, myInterfaceX)
+ checkOverride(getX, myInterfaceX)
+ checkOverride(setY, myInterfaceY)
+ checkOverride(setX, myInterfaceX)
+ checkOverride(getY, getY)
+ checkOverride(myInterfaceX, getY)
+ checkOverride(myInterfaceX, getX)
+ checkOverride(myInterfaceY, setY)
+ checkOverride(myInterfaceY, myInterfaceY)
+ checkOverride(myInterface2receiveList, myInterface2ImplWithoutTypereceiveList)
+ checkOverride(myInterface2ImplWithoutTypereceiveList, myInterface2receiveList)
+ checkOverride(myInterface2ImplWithTypereceiveList, myInterface2receiveList)
+ checkOverride(myInterface2ImplWithTypereceiveList, myInterface2ImplWithoutTypereceiveList)
+
+ val JavaDifferentReturnTypes =
+ resolver.getClassDeclarationByName("JavaDifferentReturnType")!!
+ val diffGetX = JavaDifferentReturnTypes.getDeclaredFunctions()
+ .first { it.simpleName.asString() == "foo" }
+ checkOverride(diffGetX, fooFunJava)
+ val base = resolver.getClassDeclarationByName("Base")!!
+ val baseF1 = base.declarations.filter { it.simpleName.asString() == "f1" }.single()
+ val baseProp = base.declarations.filter { it.simpleName.asString() == "prop" }.single()
+ val myInterface3 = resolver.getClassDeclarationByName("MyInterface3")!!
+ val myInterfaceF1 = myInterface3.declarations.filter { it.simpleName.asString() == "f1" }.single()
+ val myInterfaceProp = myInterface3.declarations.filter { it.simpleName.asString() == "prop" }.single()
+ val baseOverride = resolver.getClassDeclarationByName("BaseOverride")!!
+ checkOverride(baseF1, myInterfaceF1, baseOverride)
+ checkOverride(baseProp, myInterfaceProp, baseOverride)
+ val jbase = resolver.getClassDeclarationByName("JBase")!!
+ val jBaseOverride = resolver.getClassDeclarationByName("JBaseOverride")!!
+ val jbaseProp = jbase.declarations.single { it.simpleName.asString() == "getProp" }
+ checkOverride(jbaseProp, myInterfaceProp, jBaseOverride)
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassKindsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassKindsProcessor.kt
new file mode 100644
index 00000000..f2d46467
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassKindsProcessor.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class ClassKindsProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ fun KSClassDeclaration.pretty(): String = "${qualifiedName!!.asString()}: $classKind"
+ val files = resolver.getNewFiles()
+ files.forEach {
+ it.accept(
+ object : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) = Unit
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ results.add(classDeclaration.pretty())
+ super.visitClassDeclaration(classDeclaration, data)
+ }
+ },
+ Unit
+ )
+ }
+
+ results.add(resolver.getClassDeclarationByName("kotlin.Any")!!.pretty())
+ results.add(resolver.getClassDeclarationByName("kotlin.Annotation")!!.pretty())
+ results.add(resolver.getClassDeclarationByName("kotlin.Deprecated")!!.pretty())
+ results.add(resolver.getClassDeclarationByName("kotlin.Double.Companion")!!.pretty())
+ results.add(resolver.getClassDeclarationByName("kotlin.DeprecationLevel")!!.pretty())
+ results.add(resolver.getClassDeclarationByName("kotlin.DeprecationLevel.WARNING")!!.pretty())
+
+ results.sort()
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassWithCompanionProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassWithCompanionProcessor.kt
new file mode 100644
index 00000000..fb2b0e1e
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassWithCompanionProcessor.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSFile
+import com.google.devtools.ksp.symbol.KSVisitorVoid
+
+class ClassWithCompanionProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val visitor = CompanionVisitor()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach { it.accept(CompanionVisitor(), Unit) }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ inner class CompanionVisitor : KSVisitorVoid() {
+ override fun visitFile(file: KSFile, data: Unit) {
+ file.declarations.forEach { it.accept(this, Unit) }
+ }
+
+ override fun visitClassDeclaration(type: KSClassDeclaration, data: Unit) {
+ results.add("${type.simpleName.asString()}:${type.isCompanionObject}")
+ type.declarations.forEach { it.accept(this, Unit) }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstPropertiesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstPropertiesProcessor.kt
new file mode 100644
index 00000000..eebdafce
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstPropertiesProcessor.kt
@@ -0,0 +1,39 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class ConstPropertiesProcessor : AbstractTestProcessor() {
+ private val visitor = Visitor()
+
+ override fun toResult(): List<String> {
+ return visitor.constPropertiesNames.sorted()
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getDeclarationsFromPackage("foo.compiled").forEach {
+ it.accept(visitor, Unit)
+ }
+ resolver.getNewFiles().forEach { it.accept(visitor, Unit) }
+ return emptyList()
+ }
+
+ private class Visitor : KSTopDownVisitor<Unit, Unit>() {
+ val constPropertiesNames = arrayListOf<String>()
+
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ if (Modifier.CONST in property.modifiers) {
+ constPropertiesNames += property.simpleName.asString()
+ }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstructorDeclarationsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstructorDeclarationsProcessor.kt
new file mode 100644
index 00000000..ff51f80c
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstructorDeclarationsProcessor.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getConstructors
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+class ConstructorDeclarationsProcessor : AbstractTestProcessor() {
+ val visitor = ConstructorsVisitor()
+
+ override fun toResult(): List<String> {
+ return visitor.toResult()
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getAllFiles().forEach { it.accept(visitor, Unit) }
+ val classNames = visitor.classNames().toList() // copy
+ // each class has a cousin in the lib package, visit them as well, make sure
+ // we report the same structure when they are compiled code as well
+ classNames.forEach {
+ resolver
+ .getClassDeclarationByName("lib.${it.simpleName.asString()}")
+ ?.accept(visitor, Unit)
+ }
+ return emptyList()
+ }
+
+ class ConstructorsVisitor : KSVisitorVoid() {
+ private val declarationsByClass = LinkedHashMap<KSClassDeclaration, MutableList<String>>()
+ fun classNames() = declarationsByClass.keys
+ fun toResult(): List<String> {
+ return declarationsByClass.entries
+ .sortedBy {
+ // sort by simple name to get cousin classes next to each-other
+ // since we traverse the lib after main, lib will be the second one
+ // because sortedBy is stable sort
+ it.key.simpleName.asString()
+ }.flatMap {
+ listOf("class: " + it.key.qualifiedName!!.asString()) + it.value
+ }
+ }
+ fun KSFunctionDeclaration.toSignature(): String {
+ return this.simpleName.asString() +
+ "(${this.parameters.map {
+ buildString {
+ append(it.type.resolve().declaration.qualifiedName?.asString())
+ if (it.hasDefault) {
+ append("(hasDefault)")
+ }
+ }
+ }.joinToString(",")})" +
+ ": ${this.returnType?.resolve()?.declaration?.qualifiedName?.asString()
+ ?: "<no-return>"}"
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ val declarations = mutableListOf<String>()
+ declarations.addAll(
+ classDeclaration.getConstructors().map {
+ it.toSignature()
+ }.sorted()
+ )
+ // TODO add some assertions that if we go through he path of getDeclarations
+ // we still find the same constructors
+ declarationsByClass[classDeclaration] = declarations
+ }
+
+ override fun visitFile(file: KSFile, data: Unit) {
+ file.declarations.forEach { it.accept(this, Unit) }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CrossModuleTypeAliasTestProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CrossModuleTypeAliasTestProcessor.kt
new file mode 100644
index 00000000..36c8554c
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CrossModuleTypeAliasTestProcessor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+
+class CrossModuleTypeAliasTestProcessor : AbstractTestProcessor() {
+ private val results = mutableListOf<String>()
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val target = resolver.getClassDeclarationByName("TestTarget")
+ val classes = mutableSetOf<KSClassDeclaration>()
+ val classCollector = object : BaseVisitor() {
+ override fun visitClassDeclaration(type: KSClassDeclaration, data: Unit) {
+ if (classes.add(type)) {
+ super.visitClassDeclaration(type, data)
+ }
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ results.add(
+ property.type.resolve().declaration.let {
+ it.qualifiedName!!.asString() + "(${it.origin})"
+ }
+ )
+ }
+ }
+ target?.accept(classCollector, Unit)
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationInconsistencyProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationInconsistencyProcessor.kt
new file mode 100644
index 00000000..c580d037
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationInconsistencyProcessor.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+
+class DeclarationInconsistencyProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val numberClass = resolver.getClassDeclarationByName("kotlin.Number")!!
+ val serializable = numberClass.superTypes.first {
+ it.resolve().declaration.qualifiedName?.asString() == "java.io.Serializable"
+ }.resolve().declaration as KSClassDeclaration
+ val serizableDirect = resolver.getClassDeclarationByName("java.io.Serializable")!!
+ results.add("via type: ${serializable.qualifiedName?.asString()}")
+ serializable.getAllFunctions().forEach {
+ results.add(it.simpleName.asString())
+ }
+ results.add("via find declaration: ${serizableDirect.qualifiedName?.asString()}")
+ serizableDirect.getAllFunctions().forEach {
+ results.add(it.simpleName.asString())
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationOrderProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationOrderProcessor.kt
new file mode 100644
index 00000000..6d9b9f61
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationOrderProcessor.kt
@@ -0,0 +1,44 @@
+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.KSAnnotated
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+
+@KspExperimental
+class DeclarationOrderProcessor : AbstractTestProcessor() {
+ private val result = mutableListOf<String>()
+ override fun toResult() = result
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val classNames = listOf(
+ "lib.KotlinClass", "lib.JavaClass",
+ "KotlinClass", "JavaClass"
+ )
+ classNames.map {
+ checkNotNull(resolver.getClassDeclarationByName(it)) {
+ "cannot find $it"
+ }
+ }.forEach { klass ->
+ result.add(klass.qualifiedName!!.asString())
+ result.addAll(
+ resolver.getDeclarationsInSourceOrder(klass).filterIsInstance<KSPropertyDeclaration>().map {
+ it.toSignature(resolver)
+ }
+ )
+ result.addAll(
+ resolver.getDeclarationsInSourceOrder(klass).filterIsInstance<KSFunctionDeclaration>().map {
+ it.toSignature(resolver)
+ }
+ )
+ }
+ return emptyList()
+ }
+
+ private fun KSDeclaration.toSignature(
+ resolver: Resolver
+ ) = "${simpleName.asString()}:${resolver.mapToJvmSignature(this)}"
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationPackageNameProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationPackageNameProcessor.kt
new file mode 100644
index 00000000..7eb809fe
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationPackageNameProcessor.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class DeclarationPackageNameProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result.sorted()
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val visitor = NameCollector()
+ resolver.getNewFiles().forEach { it.accept(visitor, result) }
+ listOf("K1", "J1").mapNotNull {
+ resolver.getClassDeclarationByName(resolver.getKSNameFromString(it))
+ }.forEach {
+ it.accept(visitor, result)
+ }
+ return emptyList()
+ }
+}
+
+class NameCollector : KSTopDownVisitor<MutableCollection<String>, Unit>() {
+
+ override fun defaultHandler(node: KSNode, data: MutableCollection<String>) {}
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: MutableCollection<String>) {
+ classDeclaration.packageName.asString().let {
+ data.add("${if (it == "") "<no name>" else it}:${classDeclaration.simpleName.asString()}")
+ }
+ super.visitClassDeclaration(classDeclaration, data)
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: MutableCollection<String>) {
+ function.packageName.asString().let { packageName ->
+ val packageNamePrefix = if (packageName == "") "<no name>" else packageName
+ val parentDeclaration = function.parentDeclaration
+ val parentPrefix = if (parentDeclaration == null) {
+ ""
+ } else {
+ "${parentDeclaration.simpleName.asString()}."
+ }
+ data.add("$packageNamePrefix:$parentPrefix${function.simpleName.asString()}")
+ }
+ super.visitFunctionDeclaration(function, data)
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: MutableCollection<String>) {
+ property.packageName.asString().let {
+ data.add("${if (it == "") "<no name>" else it}:${property.simpleName.asString()}")
+ }
+ super.visitPropertyDeclaration(property, data)
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationUtilProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationUtilProcessor.kt
new file mode 100644
index 00000000..15bbf140
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationUtilProcessor.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.*
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class DeclarationUtilProcessor : AbstractTestProcessor() {
+ private val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val visitor = DeclarationCollector()
+ resolver.getNewFiles().forEach { it.accept(visitor, result) }
+ return emptyList()
+ }
+}
+
+class DeclarationCollector : KSTopDownVisitor<MutableCollection<String>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableCollection<String>) {
+ }
+
+ private fun KSDeclaration.toSignature(): String {
+ qualifiedName?.let {
+ return it.asString()
+ }
+ val parentSignature = parentDeclaration?.toSignature() ?: ""
+ return "$parentSignature / ${simpleName.asString()}"
+ }
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: MutableCollection<String>) {
+ data.add(
+ "${declaration.toSignature()}: " + listOf(
+ "internal" to declaration.isInternal(),
+ "local" to declaration.isLocal(),
+ "private" to declaration.isPrivate(),
+ "protected" to declaration.isProtected(),
+ "public" to declaration.isPublic(),
+ "open" to declaration.isOpen()
+ ).filter { it.second }.joinToString(" ") {
+ it.first
+ }
+ )
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclaredProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclaredProcessor.kt
new file mode 100644
index 00000000..23997b36
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclaredProcessor.kt
@@ -0,0 +1,25 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+class DeclaredProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val sub = resolver.getClassDeclarationByName("Sub")!!
+ val base = resolver.getClassDeclarationByName("Base")!!
+ val javasource = resolver.getClassDeclarationByName("JavaSource")!!
+ result.add("Base class declared functions:")
+ sub.declarations.forEach { result.add(it.toString()) }
+ result.add("Sub class declared functions:")
+ base.declarations.forEach { result.add(it.toString()) }
+ result.add("JavaSource class declared functions:")
+ javasource.declarations.forEach { result.add(it.toString()) }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DefaultFunctionProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DefaultFunctionProcessor.kt
new file mode 100644
index 00000000..7f3a6a97
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DefaultFunctionProcessor.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getDeclaredFunctions
+import com.google.devtools.ksp.isAbstract
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+
+class DefaultFunctionProcessor : AbstractTestProcessor() {
+
+ private val result = mutableListOf<String>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val ktInterface = resolver.getClassDeclarationByName(resolver.getKSNameFromString("KTInterface"))
+ as KSClassDeclaration
+ val javaInterface = resolver.getClassDeclarationByName(resolver.getKSNameFromString("C"))
+ as KSClassDeclaration
+ result.addAll(checkFunctions(ktInterface, listOf("funLiteral", "funWithBody", "emptyFun")))
+ result.addAll(checkFunctions(javaInterface, listOf("foo", "bar")))
+ val containsFun = ktInterface.getAllFunctions().single {
+ it.simpleName.asString() == "iterator"
+ }
+ result.add("${containsFun.simpleName.asString()}: ${containsFun.isAbstract}")
+ val equalsFun = ktInterface.getAllFunctions().single {
+ it.simpleName.asString() == "equals"
+ }
+ result.add("${equalsFun.simpleName.asString()}: ${equalsFun.isAbstract}")
+ val interfaceProperty = ktInterface.declarations.single {
+ it.simpleName.asString() == "interfaceProperty"
+ } as KSPropertyDeclaration
+ result.add(
+ "${interfaceProperty.simpleName.asString()}: isAbstract: ${interfaceProperty.isAbstract()}: " +
+ "isMutable: ${interfaceProperty.isMutable}"
+ )
+ val interfaceVar = ktInterface.declarations.single {
+ it.simpleName.asString() == "interfaceVar"
+ } as KSPropertyDeclaration
+ result.add(
+ "${interfaceVar.simpleName.asString()}: isAbstract: ${interfaceVar.isAbstract()}: " +
+ "isMutable: ${interfaceVar.isMutable}"
+ )
+ val nonAbstractInterfaceProp =
+ ktInterface.declarations.single { it.simpleName.asString() == "nonAbstractInterfaceProp" }
+ as KSPropertyDeclaration
+ result.add(
+ "${nonAbstractInterfaceProp.simpleName.asString()}: " +
+ "isAbstract: ${nonAbstractInterfaceProp.isAbstract()}: isMutable: ${nonAbstractInterfaceProp.isMutable}"
+ )
+ val abstractClass = resolver.getClassDeclarationByName(resolver.getKSNameFromString("B"))
+ as KSClassDeclaration
+ result.add("${abstractClass.simpleName.asString()}: ${abstractClass.isAbstract()}")
+ val parameterVal = abstractClass.declarations.single {
+ it.simpleName.asString() == "parameterVal"
+ } as KSPropertyDeclaration
+ result.add(
+ "${parameterVal.simpleName.asString()}: isAbstract: ${parameterVal.isAbstract()}: " +
+ "isMutable: ${parameterVal.isMutable}"
+ )
+ val parameterVar = abstractClass.declarations.single {
+ it.simpleName.asString() == "parameterVar"
+ } as KSPropertyDeclaration
+ result.add(
+ "${parameterVar.simpleName.asString()}: isAbstract: ${parameterVar.isAbstract()}: " +
+ "isMutable: ${parameterVar.isMutable}"
+ )
+ val abstractVar = abstractClass.declarations.single {
+ it.simpleName.asString() == "abstractVar"
+ } as KSPropertyDeclaration
+ result.add(
+ "${abstractVar.simpleName.asString()}: isAbstract: ${abstractVar.isAbstract()}: " +
+ "isMutable: ${abstractVar.isMutable}"
+ )
+ val abstractProperty = abstractClass.declarations.single {
+ it.simpleName.asString() == "abstractProperty"
+ } as KSPropertyDeclaration
+ result.add(
+ "${abstractProperty.simpleName.asString()}: isAbstract: ${abstractProperty.isAbstract()}: " +
+ "isMutable: ${abstractProperty.isMutable}"
+ )
+ val aProperty = abstractClass.declarations.single { it.simpleName.asString() == "a" } as KSPropertyDeclaration
+ result.add("${aProperty.simpleName.asString()}: ${aProperty.isAbstract()}")
+ val D = resolver.getClassDeclarationByName("D")!!
+ D.getAllProperties().forEach { result.add("${it.simpleName.asString()}: isMutable: ${it.isMutable}") }
+ return emptyList()
+ }
+
+ private fun checkFunctions(classDec: KSClassDeclaration, funList: List<String>): List<String> {
+ return classDec.getDeclaredFunctions()
+ .filter { funList.contains(it.simpleName.asString()) }
+ .map { "${it.simpleName.asString()}: ${it.isAbstract}" }
+ .toList()
+ }
+
+ override fun toResult(): List<String> {
+ return result
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DocStringProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DocStringProcessor.kt
new file mode 100644
index 00000000..e878a7ad
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DocStringProcessor.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class DocStringProcessor : AbstractTestProcessor() {
+ private val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ private class DeclarationCollector : KSTopDownVisitor<MutableCollection<String>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableCollection<String>) = Unit
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: MutableCollection<String>) {
+ data.add("${declaration.simpleName.asString()}: ${declaration.docString?.lines()?.joinToString("\\n")}")
+ }
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val visitor = DeclarationCollector()
+ resolver.getNewFiles().forEach { it.accept(visitor, result) }
+ result.sort()
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/EquivalentJavaWildcardProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/EquivalentJavaWildcardProcessor.kt
new file mode 100644
index 00000000..21039a7e
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/EquivalentJavaWildcardProcessor.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class EquivalentJavaWildcardProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach {
+ resolver.getNewFiles().forEach {
+ it.accept(RefVisitor(results, resolver), "")
+ }
+ }
+
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ private class RefVisitor(
+ val results: MutableList<String>,
+ val resolver: Resolver
+ ) : KSTopDownVisitor<String, Unit>() {
+ override fun defaultHandler(node: KSNode, data: String) = Unit
+
+ private fun KSTypeReference.pretty(): String {
+ return resolve().toString()
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun visitTypeReference(typeReference: KSTypeReference, data: String) {
+ val wildcard = resolver.getJavaWildcard(typeReference)
+ results.add(
+ data + typeReference.parent.toString() +
+ " : " + typeReference.pretty() +
+ " -> " + wildcard.pretty()
+ )
+ super.visitTypeReference(typeReference, data + "- ")
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ErrorTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ErrorTypeProcessor.kt
new file mode 100644
index 00000000..956aa16d
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ErrorTypeProcessor.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSType
+
+class ErrorTypeProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val classC = resolver.getClassDeclarationByName(resolver.getKSNameFromString("C"))!!
+ val errorAtTop = classC.declarations.single { it.simpleName.asString() == "errorAtTop" }
+ as KSPropertyDeclaration
+ val errorInComponent = classC.declarations.single { it.simpleName.asString() == "errorInComponent" }
+ as KSPropertyDeclaration
+ result.add(errorAtTop.type.resolve().print() ?: "")
+ result.add(errorInComponent.type.resolve().print() ?: "")
+ errorInComponent.type.resolve().arguments.forEach { result.add(it.type!!.resolve().print()) }
+ result.add(
+ "errorInComponent is assignable from errorAtTop: ${
+ errorAtTop.type.resolve().isAssignableFrom(errorAtTop.type.resolve())
+ }"
+ )
+ result.add(
+ "errorInComponent is assignable from class C: ${
+ errorAtTop.type.resolve().isAssignableFrom(classC.asStarProjectedType())
+ }"
+ )
+ result.add(
+ "Any is assignable from errorInComponent: ${
+ resolver.builtIns.anyType.isAssignableFrom(errorAtTop.type.resolve())
+ }"
+ )
+ result.add(
+ "class C is assignable from errorInComponent: ${
+ classC.asStarProjectedType().isAssignableFrom(errorAtTop.type.resolve())
+ }"
+ )
+ result.add(
+ "Any is assignable from class C: ${
+ resolver.builtIns.anyType.isAssignableFrom(classC.asStarProjectedType())
+ }"
+ )
+ val Cls = resolver.getClassDeclarationByName("Cls")!!
+ val type = Cls.superTypes.toList()[0].resolve()
+ result.add("Cls's super type is Error type: ${type.isError}")
+ Cls.annotations.forEach {
+ val annotation = it.annotationType.resolve()
+ result.add("Cls's annotation is Error type: ${annotation.isError}")
+ }
+ return emptyList()
+ }
+
+ private fun KSType.print(): String {
+ return if (this.isError) {
+ if (this.declaration.qualifiedName == null) "ERROR TYPE" else
+ throw IllegalStateException("Error type should resolve to KSErrorTypeClassDeclaration")
+ } else this.declaration.qualifiedName!!.asString()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAliasProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAliasProcessor.kt
new file mode 100644
index 00000000..69f70ab9
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAliasProcessor.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class FunctionTypeAliasProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val typeRefCollector = RefCollector()
+ val refs = mutableSetOf<KSTypeReference>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(typeRefCollector, refs)
+ }
+
+ val types = refs.mapNotNull { it.resolve() }.sortedBy { it.toString() }.distinctBy { it.toString() }
+
+ for (i in types) {
+ for (j in types) {
+ results.add("$i ?= $j : ${i.isAssignableFrom(j)} / ${i == j}")
+ }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
+
+open class RefCollector : KSTopDownVisitor<MutableCollection<KSTypeReference>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableCollection<KSTypeReference>) = Unit
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: MutableCollection<KSTypeReference>) {
+ super.visitTypeReference(typeReference, data)
+ data.add(typeReference)
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAnnotationProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAnnotationProcessor.kt
new file mode 100644
index 00000000..c35d156e
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAnnotationProcessor.kt
@@ -0,0 +1,36 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class FunctionTypeAnnotationProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(
+ object : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) = Unit
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ val type = property.type.resolve()
+ val propertyName = property.simpleName.asString()
+ val typeName = type.declaration.simpleName.asString()
+ results.add("$propertyName: $typeName ${type.annotations.joinToString { it.toString() }}")
+ }
+ },
+ Unit
+ )
+ }
+ return emptyList()
+ }
+}
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
new file mode 100644
index 00000000..f361599b
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeProcessor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class FunctionTypeProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val types = mutableSetOf<KSType>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(
+ object : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) = Unit
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ val type = property.type.resolve()
+ val propertyName = property.simpleName.asString()
+ val typeName = type.declaration.simpleName.asString()
+ results.add("$propertyName: $typeName : ${type.isFunctionType}, ${type.isSuspendFunctionType}")
+ }
+ },
+ Unit
+ )
+ }
+
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results.sorted()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetAnnotationByTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetAnnotationByTypeProcessor.kt
new file mode 100644
index 00000000..8615cdb8
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetAnnotationByTypeProcessor.kt
@@ -0,0 +1,36 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getAnnotationsByType
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+
+annotation class KotlinAnnotationWithInnerDefaults(
+ val innerAnnotationVal: InnerAnnotation = InnerAnnotation(innerAnnotationDefault = 7)
+) {
+ annotation class InnerAnnotation(
+ val innerAnnotationDefault: Int,
+ val moreInnerAnnotation: MoreInnerAnnotation = MoreInnerAnnotation("OK")
+ ) {
+ annotation class MoreInnerAnnotation(val moreInnerAnnotationDefault: String)
+ }
+}
+
+class GetAnnotationByTypeProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ private val annotationKClass = KotlinAnnotationWithInnerDefaults::class
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val decl = resolver.getAllFiles().single().declarations
+ .single { it.simpleName.asString() == "A" } as KSClassDeclaration
+ val anno = decl.getAnnotationsByType(annotationKClass).first()
+ results.add(anno.innerAnnotationVal.toString())
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetByNameProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetByNameProcessor.kt
new file mode 100644
index 00000000..c7e49eec
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetByNameProcessor.kt
@@ -0,0 +1,63 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getFunctionDeclarationsByName
+import com.google.devtools.ksp.getPropertyDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+class GetByNameProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val classNames = listOf(
+ "lib1.Foo",
+ "lib1.Foo.FooNested",
+ "source.FooInSource",
+ "source.FooInSource.FooInSourceNested"
+ )
+ val funNames = listOf(
+ "lib1.Foo.lib1MemberFun",
+ "lib1.lib1TopFun",
+ "lib1.Bar.lib1JavaMemberFun",
+ "lib2.Foo.lib2MemberFun",
+ "source.FooInSource.sourceMemberFun"
+ )
+ val overloadFunctionNames = listOf("lib1.Foo.overload")
+ val propNames = listOf(
+ "lib1.Foo.lib1MemberProp",
+ "lib1.lib1TopProp",
+ "lib2.Foo.lib2MemberProp",
+ "source.FooInSource.sourceMemberProp",
+ "source.propInSource",
+ )
+ for (className in classNames) {
+ if (resolver.getClassDeclarationByName(className) == null) {
+ results.add("failed to get $className")
+ }
+ }
+ for (funName in funNames) {
+ if (resolver.getFunctionDeclarationsByName(funName, true).none()) {
+ results.add("failed to get $funName")
+ }
+ }
+ for (funName in overloadFunctionNames) {
+ if (resolver.getFunctionDeclarationsByName(funName, true).toList().size != 2) {
+ results.add("failed to get all $funName")
+ }
+ }
+ for (propName in propNames) {
+ if (resolver.getPropertyDeclarationByName(propName, true) == null) {
+ results.add("failed to get $propName")
+ }
+ }
+ if (results.isEmpty()) {
+ results.add("all success")
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetPackageProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetPackageProcessor.kt
new file mode 100644
index 00000000..5af50859
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetPackageProcessor.kt
@@ -0,0 +1,29 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+class GetPackageProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ addPackage("lib1", resolver)
+ addPackage("lib2", resolver)
+ addPackage("main.test", resolver)
+ return emptyList()
+ }
+
+ @KspExperimental
+ private fun addPackage(name: String, resolver: Resolver) {
+ results.add("symbols from package $name")
+ resolver.getDeclarationsFromPackage(name).forEach {
+ results.add("${it.qualifiedName?.asString() ?: "error"} ${it.origin}")
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetSymbolsFromAnnotationProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetSymbolsFromAnnotationProcessor.kt
new file mode 100644
index 00000000..97b44309
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetSymbolsFromAnnotationProcessor.kt
@@ -0,0 +1,35 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+class GetSymbolsFromAnnotationProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+ override fun toResult(): List<String> = result
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ result.add("==== Anno superficial====")
+ resolver.getSymbolsWithAnnotation("Anno").forEach { result.add(toString(it)) }
+ result.add("==== Anno in depth ====")
+ resolver.getSymbolsWithAnnotation("Anno", true).forEach { result.add(toString(it)) }
+ result.add("==== Bnno superficial====")
+ resolver.getSymbolsWithAnnotation("Bnno").forEach { result.add(toString(it)) }
+ result.add("==== Bnno in depth ====")
+ resolver.getSymbolsWithAnnotation("Bnno", true).forEach { result.add(toString(it)) }
+ result.add("==== A1 superficial====")
+ resolver.getSymbolsWithAnnotation("A1").forEach { result.add(toString(it)) }
+ result.add("==== A1 in depth ====")
+ resolver.getSymbolsWithAnnotation("A1", true).forEach { result.add(toString(it)) }
+ result.add("==== A2 superficial====")
+ resolver.getSymbolsWithAnnotation("A2").forEach { result.add(toString(it)) }
+ result.add("==== A2 in depth ====")
+ resolver.getSymbolsWithAnnotation("A2", true).forEach { result.add(toString(it)) }
+ result.add("==== Cnno in depth ====")
+ resolver.getSymbolsWithAnnotation("Cnno", true).forEach { result.add(toString(it)) }
+ return emptyList()
+ }
+
+ fun toString(annotated: KSAnnotated): String {
+ return "$annotated:${annotated::class.supertypes.first().classifier.toString().substringAfterLast('.')}"
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/HelloProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/HelloProcessor.kt
new file mode 100644
index 00000000..c8793d89
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/HelloProcessor.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+class HelloProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val visitor = HelloVisitor()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val symbols = resolver.getSymbolsWithAnnotation("test.Anno")
+ results.add(symbols.toList().size.toString())
+ symbols.forEach { it.accept(visitor, Unit) }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results.sorted()
+ }
+
+ inner class HelloVisitor : KSVisitorVoid() {
+ override fun visitClassDeclaration(type: KSClassDeclaration, data: Unit) {
+ results.add(type.qualifiedName?.asString() ?: "<error>")
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ results.add(function.qualifiedName?.asString() ?: "<error>")
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ results.add(property.qualifiedName?.asString() ?: "<error>")
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitElementProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitElementProcessor.kt
new file mode 100644
index 00000000..4273671c
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitElementProcessor.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getConstructors
+import com.google.devtools.ksp.getDeclaredFunctions
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+
+class ImplicitElementProcessor : AbstractTestProcessor() {
+ val result: MutableList<String> = mutableListOf()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ private fun nameAndOrigin(declaration: KSDeclaration) =
+ "${declaration.simpleName.asString()}: ${declaration.origin}"
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val ClsClass = resolver.getClassDeclarationByName(resolver.getKSNameFromString("Cls"))!!
+ result.add(
+ "${
+ ClsClass.primaryConstructor?.simpleName?.asString() ?: "<null>"
+ }; origin: ${ClsClass.primaryConstructor?.origin}"
+ )
+ result.add(ClsClass.getConstructors().map { it.toString() }.joinToString(","))
+ val ITF = resolver.getClassDeclarationByName(resolver.getKSNameFromString("ITF"))!!
+ result.add(ITF.primaryConstructor?.simpleName?.asString() ?: "<null>")
+ val JavaClass = resolver.getClassDeclarationByName("JavaClass")!!
+ result.add(JavaClass.primaryConstructor?.simpleName?.asString() ?: "<null>")
+ result.add(JavaClass.getDeclaredFunctions().map { it.simpleName.asString() }.joinToString(","))
+ val readOnly = ClsClass.declarations.single { it.simpleName.asString() == "readOnly" } as KSPropertyDeclaration
+ readOnly.getter?.let {
+ result.add(
+ "readOnly.get(): ${it.origin} annotations from property: ${
+ it.annotations.map { it.shortName.asString() }.joinToString(",")
+ }"
+ )
+ }
+ readOnly.getter?.receiver?.let { result.add("readOnly.getter.owner: " + nameAndOrigin(it)) }
+ readOnly.setter?.let { result.add("readOnly.set(): ${it.origin}") }
+ readOnly.setter?.receiver?.let { result.add("readOnly.setter.owner: " + nameAndOrigin(it)) }
+ val readWrite =
+ ClsClass.declarations.single { it.simpleName.asString() == "readWrite" } as KSPropertyDeclaration
+ readWrite.getter?.let { result.add("readWrite.get(): ${it.origin}") }
+ readWrite.setter?.let {
+ result.add(
+ "readWrite.set(): ${it.origin} annotations from property: ${
+ it.annotations.map {
+ it.shortName.asString()
+ }.joinToString(",")
+ }"
+ )
+ }
+ val dataClass = resolver.getClassDeclarationByName(resolver.getKSNameFromString("Data"))!!
+ result.add(dataClass.getConstructors().map { it.toString() }.joinToString(","))
+ val comp1 = dataClass.declarations.single { it.simpleName.asString() == "comp1" } as KSPropertyDeclaration
+ comp1.getter?.let { result.add("comp1.get(): ${it.origin}") }
+ comp1.setter?.let { result.add("comp1.set(): ${it.origin}") }
+ val comp2 = dataClass.declarations.single { it.simpleName.asString() == "comp2" } as KSPropertyDeclaration
+ comp2.getter?.let { result.add("comp2.get(): ${it.origin}") }
+ comp2.setter?.let { result.add("comp2.set(): ${it.origin}") }
+ val annotationType = comp1.getter?.let {
+ result.add(it.annotations.first().annotationType.resolve().declaration.qualifiedName!!.asString())
+ }
+ val ClassWithoutImplicitPrimaryConstructor =
+ resolver.getClassDeclarationByName("ClassWithoutImplicitPrimaryConstructor")!!
+ result.add(
+ ClassWithoutImplicitPrimaryConstructor.getConstructors().map { it.toString() }.joinToString(",")
+ )
+ val ImplictConstructorJava = resolver.getClassDeclarationByName("ImplictConstructorJava")!!
+ result.add(ImplictConstructorJava.getConstructors().map { it.toString() }.joinToString(","))
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitPropertyAccessorProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitPropertyAccessorProcessor.kt
new file mode 100644
index 00000000..cef47f3c
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitPropertyAccessorProcessor.kt
@@ -0,0 +1,26 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+
+class ImplicitPropertyAccessorProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val foo = resolver.getClassDeclarationByName("Foo")!!
+ foo.declarations.filterIsInstance<KSPropertyDeclaration>().forEach { prop ->
+ result.add(prop.getter?.returnType.toString())
+ prop.setter?.parameter?.let {
+ result.add(it.toString())
+ result.add(it.type.toString())
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InheritedTypeAliasProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InheritedTypeAliasProcessor.kt
new file mode 100644
index 00000000..9b1704bf
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InheritedTypeAliasProcessor.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+class InheritedTypeAliasProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val sub = resolver.getClassDeclarationByName("Sub")!!
+ val sup = resolver.getClassDeclarationByName("Super")!!
+ sub.getAllFunctions().single { it.simpleName.asString() == "foo" }.let { func ->
+ func.parameters.forEach {
+ it.type.element?.typeArguments?.joinToString(prefix = "sub: ${it.name?.asString()} :") {
+ it.toString()
+ }?.let { results.add(it) }
+ }
+ }
+ sub.getAllProperties().forEach { prop ->
+ prop.type.element?.typeArguments?.joinToString(prefix = "sub: ${prop.simpleName.asString()} :") {
+ it.toString()
+ }?.let { results.add(it) }
+ }
+ sup.getAllFunctions().single { it.simpleName.asString() == "foo" }.let { func ->
+ func.parameters.forEach {
+ it.type.element?.typeArguments?.joinToString(prefix = "super: ${it.name?.asString()} :") {
+ it.toString()
+ }?.let { results.add(it) }
+ }
+ }
+ sup.getAllProperties().forEach { prop ->
+ prop.type.element?.typeArguments?.joinToString(prefix = "super: ${prop.simpleName.asString()} :") {
+ it.toString()
+ }?.let { results.add(it) }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InnerTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InnerTypeProcessor.kt
new file mode 100644
index 00000000..7e1556e7
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InnerTypeProcessor.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.innerArguments
+import com.google.devtools.ksp.outerType
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+open class InnerTypeProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val typeCollector = TypeCollector()
+ val types = mutableSetOf<KSType>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+ val ignoredNames = mutableSetOf<String>()
+
+ files.forEach {
+ it.accept(typeCollector, types)
+ it.annotations.forEach {
+ if (it.shortName.asString() == "Suppress") {
+ it.arguments.forEach {
+ (it.value as List<String>).forEach {
+ ignoredNames.add(it)
+ }
+ }
+ }
+ }
+ }
+
+ val sortedTypes = types.filterNot { it.declaration.simpleName.asString() in ignoredNames }.sortedBy {
+ it.toString()
+ }
+
+ fun KSType.breakDown(): List<String> {
+ var current: KSType? = this
+ val brokenDown = mutableListOf<String>()
+ do {
+ val innerArgs = current!!.innerArguments.joinToString(", ")
+ brokenDown.add("${current.declaration.qualifiedName!!.asString()}<$innerArgs>")
+ current = current.outerType
+ } while (current != null)
+ return brokenDown
+ }
+
+ for (i in sortedTypes) {
+ results.add("$i: ${i.breakDown()}")
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
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
new file mode 100644
index 00000000..9a6cbf65
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class JavaModifierProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getSymbolsWithAnnotation("Test")
+ .map {
+ it as KSClassDeclaration
+ }
+ .forEach {
+ it.superTypes.single().resolve().declaration.accept(ModifierVisitor(resolver), Unit)
+ }
+ return emptyList()
+ }
+
+ inner class ModifierVisitor(val resolver: Resolver) : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ results.add(classDeclaration.toSignature())
+ classDeclaration.declarations.forEach { it.accept(this, data) }
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ results.add(property.toSignature())
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ results.add(function.toSignature())
+ }
+
+ @OptIn(KspExperimental::class)
+ private fun KSDeclaration.toSignature(): String {
+ val parent = parentDeclaration
+ val id = if (parent == null) {
+ ""
+ } else {
+ "${parent.simpleName.asString()}."
+ } + simpleName.asString()
+ val modifiersSignature = modifiers.map { it.toString() }.sorted().joinToString(" ")
+ val extras = resolver.effectiveJavaModifiers(this).map { it.toString() }.sorted().joinToString(" ").trim()
+ return "$id: $modifiersSignature".trim() + " : " + extras
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaNonNullProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaNonNullProcessor.kt
new file mode 100644
index 00000000..35462894
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaNonNullProcessor.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.isConstructor
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSValueParameter
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class JavaNonNullProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach {
+ it.accept(
+ object : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ if (function.isConstructor()) {
+ return
+ }
+ results.add("${function.simpleName.asString()}: ${function.returnType?.resolve()?.nullability}")
+ super.visitFunctionDeclaration(function, data)
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ results.add("${property.simpleName.asString()}: ${property.type.resolve().nullability}")
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: Unit) {
+ results.add("${valueParameter.name?.asString()}: ${valueParameter.type.resolve().nullability}")
+ }
+ },
+ Unit
+ )
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaSubtypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaSubtypeProcessor.kt
new file mode 100644
index 00000000..f04b2b5e
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaSubtypeProcessor.kt
@@ -0,0 +1,78 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getJavaClassByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.Variance
+
+class JavaSubtypeProcessor : AbstractTestProcessor() {
+ var isOk = true
+ override fun toResult(): List<String> {
+ return listOf(isOk.toString())
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val javaCollection = resolver.getJavaClassByName("kotlin.collections.Collection")!!.asStarProjectedType()
+ val javaSet = resolver.getJavaClassByName("kotlin.collections.Set")!!.asStarProjectedType()
+ val ktFunctionJava = resolver.getJavaClassByName("kotlin.jvm.functions.Function0")!!.asStarProjectedType()
+ val ktCollection = resolver.getClassDeclarationByName("kotlin.collections.Collection")!!.asStarProjectedType()
+ val ktSet = resolver.getClassDeclarationByName("kotlin.collections.Set")!!.asStarProjectedType()
+ val ktFunction = resolver.getClassDeclarationByName("kotlin.jvm.functions.Function0")!!.asStarProjectedType()
+ val javaCollectionRef = resolver.createKSTypeReferenceFromKSType(javaCollection)
+ val ktCollectionRef = resolver.createKSTypeReferenceFromKSType(ktCollection)
+ val javaSetRef = resolver.createKSTypeReferenceFromKSType(javaSet)
+ val ktSetRef = resolver.createKSTypeReferenceFromKSType(ktSet)
+ val javaSetOfJavaSet = javaSet.replace(listOf(resolver.getTypeArgument(javaSetRef, Variance.INVARIANT)))
+ val javaSetOfKtSet = javaSet.replace(listOf(resolver.getTypeArgument(ktSetRef, Variance.INVARIANT)))
+ val ktSetOfJavaSet = ktSet.replace(listOf(resolver.getTypeArgument(javaSetRef, Variance.INVARIANT)))
+ val ktSetOfKtSet = ktSet.replace(listOf(resolver.getTypeArgument(ktSetRef, Variance.INVARIANT)))
+ val javaCollectionOfJavaSet = javaCollection
+ .replace(listOf(resolver.getTypeArgument(javaSetRef, Variance.INVARIANT)))
+ val javaCollectionOfKtSet = javaCollection
+ .replace(listOf(resolver.getTypeArgument(ktSetRef, Variance.INVARIANT)))
+ val ktCollectionOfJavaSet = ktCollection
+ .replace(listOf(resolver.getTypeArgument(javaSetRef, Variance.INVARIANT)))
+ val ktCollectionOfKtSet = ktCollection
+ .replace(listOf(resolver.getTypeArgument(ktSetRef, Variance.INVARIANT)))
+ val ktCollectionOfJavaCollection = ktCollection
+ .replace(listOf(resolver.getTypeArgument(javaCollectionRef, Variance.INVARIANT)))
+ val javaSetOfKtCollection = javaSet
+ .replace(listOf(resolver.getTypeArgument(ktCollectionRef, Variance.INVARIANT)))
+ val container = resolver.getClassDeclarationByName("Container")!!
+ val strRef = resolver.getTypeArgument(
+ (container.declarations.single { it.simpleName.asString() == "str" } as KSPropertyDeclaration).type,
+ Variance.INVARIANT
+ )
+ val javaStrCollection = javaCollection.replace(listOf(strRef))
+ val javaStrSet = javaSet.replace(listOf(strRef))
+ val kotlinFunctionImplementorJava = resolver.getClassDeclarationByName("IntSupplier")!!.asStarProjectedType()
+ isOk = isOk && javaCollection.isAssignableFrom(javaSet)
+ isOk = isOk && javaCollection.isAssignableFrom(javaStrCollection)
+ isOk = isOk && !javaStrCollection.isAssignableFrom(javaCollection)
+ isOk = isOk && !javaStrSet.isAssignableFrom(javaStrCollection)
+ isOk = isOk && javaStrCollection.isAssignableFrom(javaStrSet)
+ isOk = isOk && javaSet.isAssignableFrom(javaStrSet)
+ isOk = isOk && javaCollection.isAssignableFrom(ktCollection)
+ isOk = isOk && ktCollection.isAssignableFrom(javaCollection)
+ isOk = isOk && javaSetOfJavaSet.isAssignableFrom(ktSetOfJavaSet)
+ isOk = isOk && ktSetOfJavaSet.isAssignableFrom(javaSetOfJavaSet)
+ isOk = isOk && javaSetOfJavaSet.isAssignableFrom(javaSetOfKtSet)
+ isOk = isOk && javaSetOfKtSet.isAssignableFrom(javaSetOfJavaSet)
+ isOk = isOk && ktSetOfKtSet.isAssignableFrom(ktSetOfJavaSet)
+ isOk = isOk && ktSetOfJavaSet.isAssignableFrom(ktSetOfKtSet)
+ isOk = isOk && javaCollectionOfJavaSet.isAssignableFrom(ktCollectionOfJavaSet)
+ isOk = isOk && ktCollectionOfJavaSet.isAssignableFrom(javaCollectionOfJavaSet)
+ isOk = isOk && javaCollectionOfKtSet.isAssignableFrom(ktCollectionOfKtSet)
+ isOk = isOk && javaCollectionOfKtSet.isAssignableFrom(ktCollectionOfJavaSet)
+ isOk = isOk && ktCollectionOfJavaCollection.isAssignableFrom(javaSetOfKtCollection)
+ isOk = isOk && !javaSetOfKtCollection.isAssignableFrom(ktCollectionOfJavaCollection)
+ isOk = isOk && ktFunction.isAssignableFrom(kotlinFunctionImplementorJava)
+ isOk = isOk && ktFunctionJava.isAssignableFrom(ktFunction) && ktFunction.isAssignableFrom(ktFunctionJava)
+ isOk = isOk && ktFunctionJava.isAssignableFrom(kotlinFunctionImplementorJava)
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaToKotlinMapProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaToKotlinMapProcessor.kt
new file mode 100644
index 00000000..37978d0b
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaToKotlinMapProcessor.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getJavaClassByName
+import com.google.devtools.ksp.getKotlinClassByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+@KspExperimental
+open class JavaToKotlinMapProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val typeCollector = TypeCollectorNoAccessor()
+ val types = mutableSetOf<KSType>()
+
+ val javaClasses = listOf(
+ "java.lang.String",
+ "java.lang.Integer",
+ "java.util.List",
+ "java.util.Map.Entry",
+ "java.lang.Void",
+ )
+
+ val kotlinClasses = listOf(
+ "kotlin.Throwable",
+ "kotlin.Int",
+ "kotlin.Nothing",
+ "kotlin.IntArray",
+ )
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ javaClasses.forEach {
+ val k = resolver.mapJavaNameToKotlin(
+ resolver.getKSNameFromString(it)
+ )?.asString()
+ results.add("$it -> $k")
+ }
+
+ kotlinClasses.forEach {
+ val j = resolver.mapKotlinNameToJava(
+ resolver.getKSNameFromString(it)
+ )?.asString()
+ results.add("$it -> $j")
+ }
+
+ if (resolver.getClassDeclarationByName("java.lang.String") != resolver.getJavaClassByName("kotlin.String"))
+ results.add("Error: getJavaClassByName")
+
+ if (resolver.getClassDeclarationByName("kotlin.String") != resolver.getKotlinClassByName("java.lang.String"))
+ results.add("Error: getKotlinClassByName")
+
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaWildcard2Processor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaWildcard2Processor.kt
new file mode 100644
index 00000000..a72cc00c
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaWildcard2Processor.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class JavaWildcard2Processor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach {
+ resolver.getNewFiles().forEach {
+ it.accept(RefVisitor(results, resolver), "")
+ }
+ }
+
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ private class RefVisitor(
+ val results: MutableList<String>,
+ val resolver: Resolver
+ ) : KSTopDownVisitor<String, Unit>() {
+ override fun defaultHandler(node: KSNode, data: String) = Unit
+
+ private fun KSTypeReference.pretty(): String {
+ return resolve().toString()
+ }
+
+ override fun visitTypeArgument(typeArgument: KSTypeArgument, data: String) = Unit
+
+ override fun visitAnnotation(annotation: KSAnnotation, data: String) = Unit
+
+ @OptIn(KspExperimental::class)
+ override fun visitTypeReference(typeReference: KSTypeReference, data: String) {
+ val wildcard = resolver.getJavaWildcard(typeReference)
+ results.add(
+ data + typeReference.parent.toString() + " : " + wildcard.pretty()
+ )
+ super.visitTypeReference(typeReference, data + "- ")
+ }
+ }
+}
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
new file mode 100644
index 00000000..25c2546c
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LateinitPropertiesProcessor.kt
@@ -0,0 +1,39 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class LateinitPropertiesProcessor : AbstractTestProcessor() {
+ private val visitor = Visitor()
+
+ override fun toResult(): List<String> {
+ return visitor.lateinitPropertiesNames.sorted()
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getDeclarationsFromPackage("test.compiled").forEach {
+ it.accept(visitor, Unit)
+ }
+ resolver.getNewFiles().forEach { it.accept(visitor, Unit) }
+ return emptyList()
+ }
+
+ private class Visitor : KSTopDownVisitor<Unit, Unit>() {
+ val lateinitPropertiesNames = arrayListOf<String>()
+
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ if (Modifier.LATEINIT in property.modifiers) {
+ lateinitPropertiesNames += property.simpleName.asString()
+ }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LibOriginsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LibOriginsProcessor.kt
new file mode 100644
index 00000000..e0a8db99
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LibOriginsProcessor.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.containingFile
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class LibOriginsProcessor : AbstractTestProcessor() {
+ private val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ inner class MyCollector : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) = Unit
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: Unit) {
+ result.add(
+ "declaration: ${
+ declaration.qualifiedName?.asString() ?: declaration.simpleName.asString()
+ }: ${declaration.origin.name}"
+ )
+ super.visitDeclaration(declaration, data)
+ }
+
+ override fun visitAnnotation(annotation: KSAnnotation, data: Unit) {
+ result.add("annotation: ${annotation.shortName.asString()}: ${annotation.origin.name}")
+ super.visitAnnotation(annotation, data)
+ }
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: Unit) {
+ result.add("reference: $typeReference: ${typeReference.origin.name}")
+ super.visitTypeReference(typeReference, data)
+ }
+
+ override fun visitClassifierReference(reference: KSClassifierReference, data: Unit) {
+ result.add("classifier ref: $reference: ${reference.origin.name}")
+ super.visitClassifierReference(reference, data)
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: Unit) {
+ result.add("value param: $valueParameter: ${valueParameter.origin.name}")
+ super.visitValueParameter(valueParameter, data)
+ }
+
+ override fun visitTypeArgument(typeArgument: KSTypeArgument, data: Unit) {
+ result.add("type arg: $typeArgument: ${typeArgument.origin.name}")
+ super.visitTypeArgument(typeArgument, data)
+ }
+
+ override fun visitPropertyAccessor(accessor: KSPropertyAccessor, data: Unit) {
+ result.add("property accessor: $accessor: ${accessor.origin.name}")
+ super.visitPropertyAccessor(accessor, data)
+ }
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val visitor = MyCollector()
+
+ // FIXME: workaround for https://github.com/google/ksp/issues/418
+ resolver.getDeclarationsFromPackage("foo.bar").forEach {
+ if (it.containingFile == null) {
+ it.accept(visitor, Unit)
+ }
+ }
+
+ resolver.getNewFiles().forEach {
+ it.accept(visitor, Unit)
+ }
+
+ result.sort()
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MakeNullableProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MakeNullableProcessor.kt
new file mode 100644
index 00000000..6d4484d8
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MakeNullableProcessor.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+open class MakeNullableProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val typeCollector = TypeCollector()
+ val types = mutableSetOf<KSType>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+ val ignoredNames = mutableSetOf<String>()
+
+ files.forEach {
+ it.accept(typeCollector, types)
+ }
+
+ val sortedTypes = types.flatMap { setOf(it, it.makeNullable(), it.makeNotNullable()) }.sortedBy {
+ it.toString()
+ }
+
+ for (i in sortedTypes) {
+ for (j in sortedTypes) {
+ results.add("$i ?= $j : ${i.isAssignableFrom(j)}")
+ }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MangledNamesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MangledNamesProcessor.kt
new file mode 100644
index 00000000..956c8ed2
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MangledNamesProcessor.kt
@@ -0,0 +1,81 @@
+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.visitor.KSTopDownVisitor
+
+@KspExperimental
+@Suppress("unused") // used by the test code
+class MangledNamesProcessor : AbstractTestProcessor() {
+ private val results = mutableListOf<String>()
+ override fun toResult() = results
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val mangleSourceNames = mutableMapOf<String, String?>()
+ resolver.getAllFiles().sortedBy { it.fileName }.forEach {
+ it.accept(MangledNamesVisitor(resolver), mangleSourceNames)
+ }
+ val mangledDependencyNames = LinkedHashMap<String, String?>()
+ // also collect results from library dependencies to ensure we resolve module name property
+ resolver.getClassDeclarationByName("libPackage.Foo")?.accept(
+ MangledNamesVisitor(resolver), mangledDependencyNames
+ )
+ resolver.getClassDeclarationByName("libPackage.AbstractKotlinClass")?.accept(
+ MangledNamesVisitor(resolver), mangledDependencyNames
+ )
+ resolver.getClassDeclarationByName("libPackage.MyInterface")?.accept(
+ MangledNamesVisitor(resolver), mangledDependencyNames
+ )
+ results.addAll(
+ mangleSourceNames.entries.map { (decl, name) ->
+ "$decl -> $name"
+ }
+ )
+ results.addAll(
+ mangledDependencyNames.entries.map { (decl, name) ->
+ "$decl -> $name"
+ }
+ )
+ return emptyList()
+ }
+
+ private class MangledNamesVisitor(
+ val resolver: Resolver
+ ) : KSTopDownVisitor<MutableMap<String, String?>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableMap<String, String?>) {
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: MutableMap<String, String?>) {
+ if (classDeclaration.modifiers.contains(Modifier.INLINE)) {
+ // do not visit inline classes
+ return
+ }
+ // put a header for readable output
+ data[classDeclaration.qualifiedName!!.asString()] = "declarations"
+ super.visitClassDeclaration(classDeclaration, data)
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: MutableMap<String, String?>) {
+ if (function.simpleName.asString() in IGNORED_FUNCTIONS) return
+ super.visitFunctionDeclaration(function, data)
+ data[function.simpleName.asString()] = resolver.getJvmName(function)
+ }
+
+ override fun visitPropertyGetter(getter: KSPropertyGetter, data: MutableMap<String, String?>) {
+ super.visitPropertyGetter(getter, data)
+ data["get-${getter.receiver.simpleName.asString()}"] = resolver.getJvmName(getter)
+ }
+
+ override fun visitPropertySetter(setter: KSPropertySetter, data: MutableMap<String, String?>) {
+ super.visitPropertySetter(setter, data)
+ data["set-${setter.receiver.simpleName.asString()}"] = resolver.getJvmName(setter)
+ }
+
+ companion object {
+ // do not report these functions as they are generated only in byte code and do not affect the test.
+ val IGNORED_FUNCTIONS = listOf("equals", "hashCode", "toString")
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MapSignatureProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MapSignatureProcessor.kt
new file mode 100644
index 00000000..1eb0cfc1
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MapSignatureProcessor.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+@KspExperimental
+class MapSignatureProcessor : AbstractTestProcessor() {
+ private val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ listOf("Cls", "JavaIntefaceWithVoid", "JavaClass", "JavaAnno")
+ .map { className ->
+ resolver.getClassDeclarationByName(className)!!
+ }.forEach { subject ->
+ result.add(resolver.mapToJvmSignature(subject)!!)
+ subject.declarations.forEach {
+ result.add(it.simpleName.asString() + ": " + resolver.mapToJvmSignature(it))
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MultiModuleTestProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MultiModuleTestProcessor.kt
new file mode 100644
index 00000000..cd5bfee0
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MultiModuleTestProcessor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+class MultiModuleTestProcessor : AbstractTestProcessor() {
+ private val results = mutableListOf<String>()
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val target = resolver.getClassDeclarationByName("TestTarget")
+ val classes = mutableSetOf<KSClassDeclaration>()
+ val classCollector = object : BaseVisitor() {
+ override fun visitClassDeclaration(type: KSClassDeclaration, data: Unit) {
+ if (classes.add(type)) {
+ super.visitClassDeclaration(type, data)
+ }
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ (property.type.resolve().declaration as? KSClassDeclaration)?.accept(this, Unit)
+ }
+ }
+ target?.accept(classCollector, Unit)
+ results.addAll(classes.map { it.toSignature() }.sorted())
+ return emptyList()
+ }
+
+ private fun KSClassDeclaration.toSignature(): String {
+ val id = qualifiedName?.asString() ?: "no-qual-name:($this)"
+ return "$id[${origin.name}]"
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NestedClassTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NestedClassTypeProcessor.kt
new file mode 100644
index 00000000..7c5b982a
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NestedClassTypeProcessor.kt
@@ -0,0 +1,31 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+
+class NestedClassTypeProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val c = resolver.getClassDeclarationByName("C")!!
+ c.declarations.filterIsInstance<KSPropertyDeclaration>()
+ .forEach {
+ result.add(it.simpleName.asString())
+ result.add(
+ it.type.resolve().arguments.map {
+ it.type?.annotations?.joinToString(separator = ",") {
+ it.toString()
+ }
+ }.joinToString()
+ )
+ result.add(it.type.resolve().arguments.joinToString(separator = ",") { it.toString() })
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NullableTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NullableTypeProcessor.kt
new file mode 100644
index 00000000..8e986967
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NullableTypeProcessor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class NullableTypeProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val types = mutableSetOf<KSType>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(
+ object : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) = Unit
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ val modifiers = property.type.modifiers.map { it.toString() }.toList().sorted()
+ val annotations = property.type.annotations.map { it.toString() }.toList().sorted()
+ val propertyName = property.simpleName.asString()
+ results.add("$propertyName: $modifiers, $annotations")
+ }
+ },
+ Unit
+ )
+ }
+
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results.sorted()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/OverrideeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/OverrideeProcessor.kt
new file mode 100644
index 00000000..9015f41b
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/OverrideeProcessor.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.closestClassDeclaration
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+@Suppress("unused") // used by tests
+class OverrideeProcessor : AbstractTestProcessor() {
+ private val results = mutableListOf<String>()
+
+ override fun toResult() = results
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ logSubject(resolver, "NoOverride")
+ logSubject(resolver, "Subject")
+ logSubject(resolver, "JavaSubject.Subject")
+ logSubject(resolver, "lib.Subject")
+ logSubject(resolver, "ConflictingSubject1")
+ logSubject(resolver, "ConflictingSubject2")
+ logSubject(resolver, "ConflictingSubject3")
+ logSubject(resolver, "ConflictingSubject4")
+ logSubject(resolver, "OverrideOrder1")
+ logSubject(resolver, "OverrideOrder2")
+ logSubject(resolver, "JavaAccessorImpl")
+ logSubject(resolver, "JavaAnno")
+ logSubject(resolver, "JavaAnnos")
+ logSubject(resolver, "PrimaryConstructorOverride")
+ return emptyList()
+ }
+
+ private fun logSubject(resolver: Resolver, qName: String) {
+ results.add("$qName:")
+ val subject = resolver.getClassDeclarationByName(qName)!!
+ subject.declarations.filterIsInstance<KSClassDeclaration>().forEach {
+ logClass(it)
+ }
+ logClass(subject)
+ }
+
+ private fun logClass(subject: KSClassDeclaration) {
+ subject.declarations.filterIsInstance<KSPropertyDeclaration>()
+ .forEach {
+ checkOverridee(it)
+ }
+ subject.declarations.filterIsInstance<KSFunctionDeclaration>()
+ .filterNot { it.simpleName.asString() in IGNORED_METHOD_NAMES }
+ .forEach {
+ checkOverridee(it)
+ }
+ }
+
+ private fun checkOverridee(declaration: KSDeclaration) {
+ val signature = if (declaration is KSPropertyDeclaration) declaration.toSignature() else
+ (declaration as KSFunctionDeclaration).toSignature()
+ val overrideeSignature = if (declaration is KSPropertyDeclaration) declaration.findOverridee()?.toSignature()
+ else (declaration as KSFunctionDeclaration).findOverridee()?.toSignature()
+ results.add("$signature -> $overrideeSignature")
+ }
+
+ private fun KSDeclaration.toSignature(): String {
+ return when (this) {
+ is KSFunctionDeclaration -> this.toSignature()
+ is KSPropertyDeclaration -> this.toSignature()
+ else -> throw IllegalStateException()
+ }
+ }
+
+ private fun KSFunctionDeclaration.toSignature(): String {
+ val self = this
+ return buildString {
+ append(self.closestClassDeclaration()?.simpleName?.asString())
+ append(".")
+ append(self.simpleName.asString())
+ append(
+ self.parameters.joinToString(", ", prefix = "(", postfix = ")") {
+ "${it.name?.asString()}:${it.type.resolve().declaration.simpleName.asString()}"
+ }
+ )
+ }
+ }
+
+ private fun KSPropertyDeclaration.toSignature(): String {
+ val self = this
+ return buildString {
+ append(self.closestClassDeclaration()?.simpleName?.asString())
+ append(".")
+ append(self.simpleName.asString())
+ }
+ }
+
+ companion object {
+ // ignore these methods as we receive syntetics of it from compiled code
+ private val IGNORED_METHOD_NAMES = listOf("equals", "hashCode", "toString", "<init>")
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParameterTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParameterTypeProcessor.kt
new file mode 100644
index 00000000..55e1eec7
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParameterTypeProcessor.kt
@@ -0,0 +1,32 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSValueParameter
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class ParameterTypeProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result.sorted()
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach {
+ it.accept(
+ object : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: Unit) {
+ result.add("${valueParameter.name?.asString()}: ${valueParameter.type.resolve()}")
+ }
+ },
+ Unit
+ )
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParentProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParentProcessor.kt
new file mode 100644
index 00000000..1b028fe8
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParentProcessor.kt
@@ -0,0 +1,34 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class ParentProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val collector = AllSymbolProcessor()
+ val nodes = mutableSetOf<KSNode>()
+ resolver.getAllFiles().forEach { it.accept(collector, nodes) }
+ for (e in listOf("YUV", "HSV")) {
+ resolver.getClassDeclarationByName(e)!!.accept(collector, nodes)
+ }
+ nodes.forEach {
+ result.add("parent of $it: ${it.parent}")
+ }
+ return emptyList()
+ }
+
+ class AllSymbolProcessor : KSTopDownVisitor<MutableSet<KSNode>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableSet<KSNode>) {
+ data.add(node)
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/PlatformDeclarationProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/PlatformDeclarationProcessor.kt
new file mode 100644
index 00000000..b8f65468
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/PlatformDeclarationProcessor.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.containingFile
+import com.google.devtools.ksp.isConstructor
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class PlatformDeclarationProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val collector = EverythingVisitor()
+ val declarations = mutableListOf<KSDeclaration>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(collector, declarations)
+ }
+
+ declarations
+ .filterNot {
+ // TODO we should figure out how constructors work in expect-actual world
+ // expand this test to include constructors
+ it is KSFunctionDeclaration && it.isConstructor()
+ }
+ .sortedBy { "${it.containingFile?.fileName} : ${it.qualifiedName?.asString()}" }.forEach {
+ val r = mutableListOf<Any?>()
+ r.add(it.containingFile?.fileName)
+ r.add(it.qualifiedName?.asString())
+ r.add(it.isActual)
+ r.add(it.isExpect)
+ r.add(it.findActuals().joinToString(", ", "[", "]") { it.containingFile?.fileName.toString() })
+ r.add(it.findExpects().joinToString(", ", "[", "]") { it.containingFile?.fileName.toString() })
+ results.add(r.map { it.toString() }.joinToString(" : "))
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
+
+class EverythingVisitor : KSTopDownVisitor<MutableList<KSDeclaration>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableList<KSDeclaration>) = Unit
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: MutableList<KSDeclaration>) {
+ super.visitDeclaration(declaration, data)
+ data.add(declaration)
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RawTypesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RawTypesProcessor.kt
new file mode 100644
index 00000000..aa2af3f5
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RawTypesProcessor.kt
@@ -0,0 +1,48 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class RawTypesProcessor : AbstractTestProcessor() {
+ private val rawTypedEntityNames = arrayListOf<String>()
+
+ override fun toResult(): List<String> {
+ return rawTypedEntityNames.sorted()
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val visitor = object : KSTopDownVisitor<Unit, Unit>() {
+ private val KSType.isRawType
+ get() = resolver.isJavaRawType(this)
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ function.parameters.forEach { param ->
+ val type = param.type.resolve()
+ if (type.isRawType) {
+ rawTypedEntityNames += param.name?.asString() ?: "???"
+ }
+ }
+ val returnType = function.returnType?.resolve() ?: return
+ if (returnType.isRawType) {
+ rawTypedEntityNames += function.simpleName.asString()
+ }
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ val type = property.type.resolve()
+ if (type.isRawType) {
+ rawTypedEntityNames += property.simpleName.asString()
+ }
+ }
+
+ override fun defaultHandler(node: KSNode, data: Unit) = Unit
+ }
+
+ resolver.getDeclarationsFromPackage("").forEach { it.accept(visitor, Unit) }
+
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaAsMemberOfProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaAsMemberOfProcessor.kt
new file mode 100644
index 00000000..8da0f726
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaAsMemberOfProcessor.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+
+class RecordJavaAsMemberOfProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ val finalResult = mutableListOf(results[0])
+ finalResult.addAll(results.subList(1, results.size).sorted())
+ return finalResult
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ var function: KSFunctionDeclaration? = null
+ var type: KSType? = null
+ resolver.getAllFiles().forEach {
+ if (it.fileName == "C.kt") {
+ type = (
+ it.declarations.single {
+ it is KSPropertyDeclaration && it.simpleName.asString() == "a"
+ } as KSPropertyDeclaration
+ ).type.resolve()
+ } else if (it.fileName == "B.java") {
+ function = (
+ it.declarations.single {
+ it is KSClassDeclaration && it.simpleName.asString() == "B"
+ } as KSClassDeclaration
+ ).declarations.single {
+ it is KSFunctionDeclaration && it.simpleName.asString() == "f"
+ } as KSFunctionDeclaration
+ }
+ }
+
+ function!!.asMemberOf(type!!)
+
+ if (resolver is ResolverImpl) {
+ val m = resolver.incrementalContext.dumpLookupRecords()
+ m.toSortedMap().forEach { symbol, files ->
+ files.filter { it.endsWith(".java") }.sorted().forEach {
+ results.add("$symbol: $it")
+ }
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaGetAllMembersProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaGetAllMembersProcessor.kt
new file mode 100644
index 00000000..e172e0ee
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaGetAllMembersProcessor.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+
+class RecordJavaGetAllMembersProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ val finalResult = mutableListOf(results[0])
+ finalResult.addAll(results.subList(1, results.size).sorted())
+ return finalResult
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getAllFiles().forEach {
+ if (it.fileName == "A.kt") {
+ val c = it.declarations.single {
+ it is KSClassDeclaration && it.simpleName.asString() == "A"
+ } as KSClassDeclaration
+ c.getAllFunctions()
+ c.getAllProperties()
+ }
+ }
+
+ if (resolver is ResolverImpl) {
+ val m = resolver.incrementalContext.dumpLookupRecords().toSortedMap()
+ m.toSortedMap().forEach { symbol, files ->
+ files.filter { it.endsWith(".java") }.sorted().forEach {
+ results.add("$symbol: $it")
+ }
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaOverridesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaOverridesProcessor.kt
new file mode 100644
index 00000000..a1872e85
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaOverridesProcessor.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+
+class RecordJavaOverridesProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ val finalResult = mutableListOf(results[0])
+ finalResult.addAll(results.subList(1, results.size).sorted())
+ return finalResult
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ var A_f1: KSFunctionDeclaration? = null
+ var A_f2: KSFunctionDeclaration? = null
+ var C_f1: KSFunctionDeclaration? = null
+ resolver.getAllFiles().forEach {
+ if (it.fileName == "A.java") {
+ val c = it.declarations.single {
+ it is KSClassDeclaration && it.simpleName.asString() == "A"
+ } as KSClassDeclaration
+ A_f1 = c.declarations.single {
+ it is KSFunctionDeclaration && it.simpleName.asString() == "f1"
+ } as KSFunctionDeclaration
+ A_f2 = c.declarations.single {
+ it is KSFunctionDeclaration && it.simpleName.asString() == "f2"
+ } as KSFunctionDeclaration
+ } else if (it.fileName == "C.java") {
+ val c = it.declarations.single {
+ it is KSClassDeclaration && it.simpleName.asString() == "C"
+ } as KSClassDeclaration
+ C_f1 = c.declarations.single {
+ it is KSFunctionDeclaration && it.simpleName.asString() == "f1"
+ } as KSFunctionDeclaration
+ }
+ }
+
+ resolver.overrides(A_f1!!, C_f1!!)
+ A_f2!!.findOverridee()
+
+ if (resolver is ResolverImpl) {
+ val m = resolver.incrementalContext.dumpLookupRecords().toSortedMap()
+ m.toSortedMap().forEach { symbol, files ->
+ files.filter { it.endsWith(".java") }.sorted().forEach {
+ results.add("$symbol: $it")
+ }
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaProcessor.kt
new file mode 100644
index 00000000..15f06bf2
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaProcessor.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.validate
+
+class RecordJavaProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ val finalResult = mutableListOf(results[0])
+ finalResult.addAll(results.subList(1, results.size).sorted())
+ return finalResult
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getAllFiles().forEach {
+ it.declarations.forEach {
+ it.validate()
+ }
+ }
+ if (resolver is ResolverImpl) {
+ val m = resolver.incrementalContext.dumpLookupRecords().toSortedMap()
+ m.forEach { symbol, files ->
+ files.filter { it.endsWith(".java") }.sorted().forEach {
+ results.add("$symbol: $it")
+ }
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaSupertypesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaSupertypesProcessor.kt
new file mode 100644
index 00000000..a3f5528d
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaSupertypesProcessor.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+
+class RecordJavaSupertypesProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ val finalResult = mutableListOf(results[0])
+ finalResult.addAll(results.subList(1, results.size).sorted())
+ return finalResult
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val types = mutableSetOf<KSType>()
+ resolver.getAllFiles().forEach {
+ it.accept(TypeCollectorNoAccessor(), types)
+ }
+ types.forEach {
+ resolver.builtIns.anyType.isAssignableFrom(it)
+ }
+ if (resolver is ResolverImpl) {
+ val m = resolver.incrementalContext.dumpLookupRecords().toSortedMap()
+ m.forEach { symbol, files ->
+ files.filter { it.endsWith(".java") }.sorted().forEach {
+ results.add("$symbol: $it")
+ }
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReferenceElementProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReferenceElementProcessor.kt
new file mode 100644
index 00000000..c0843f36
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReferenceElementProcessor.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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getPropertyDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class ReferenceElementProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val collector = ReferenceCollector()
+ val references = mutableSetOf<KSTypeReference>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(collector, references)
+ }
+
+ resolver.getPropertyDeclarationByName("z", true)!!.accept(collector, references)
+ resolver.getPropertyDeclarationByName("w", true)!!.accept(collector, references)
+
+ fun refName(it: KSTypeReference) = (it.element as KSClassifierReference).referencedName()
+
+ val sortedReferences =
+ references.filter { it.element is KSClassifierReference && it.origin == Origin.KOTLIN }.sortedBy(::refName)
+ for (i in sortedReferences)
+ results.add(
+ "KSClassifierReferenceImpl: Qualifier of ${i.element} is ${
+ (i.element as KSClassifierReference).qualifier
+ }"
+ )
+
+ // FIXME: References in getters and type arguments are not compared to equal.
+ val descriptorReferences =
+ references.filter { it.element is KSClassifierReference && it.origin == Origin.KOTLIN_LIB }
+ .distinctBy(::refName).sortedBy(::refName)
+ for (i in descriptorReferences) {
+ results.add(
+ "KSClassifierReferenceDescriptorImpl: Qualifier of ${i.element} is ${
+ (i.element as KSClassifierReference).qualifier
+ }"
+ )
+ }
+
+ val defNonNullReferences =
+ references.filter { it.element is KSDefNonNullReference && it.origin == Origin.KOTLIN }
+ .sortedBy { it.toString() }
+
+ defNonNullReferences.forEach {
+ results.add(
+ "KSDefNonNullReferenceImpl: Enclosed type of ${(it.element as KSDefNonNullReference).enclosedType}"
+ )
+ }
+
+ val javaReferences = references.filter { it.element is KSClassifierReference && it.origin == Origin.JAVA }
+ .sortedBy(::refName)
+ for (i in javaReferences) {
+ results.add(
+ "KSClassifierReferenceJavaImpl: Qualifier of ${i.element} is ${
+ (i.element as KSClassifierReference).qualifier}"
+ )
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
+
+class ReferenceCollector : KSTopDownVisitor<MutableSet<KSTypeReference>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableSet<KSTypeReference>) = Unit
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: MutableSet<KSTypeReference>) {
+ super.visitTypeReference(typeReference, data)
+ data.add(typeReference)
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReplaceWithErrorTypeArgsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReplaceWithErrorTypeArgsProcessor.kt
new file mode 100644
index 00000000..f248b34a
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReplaceWithErrorTypeArgsProcessor.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+open class ReplaceWithErrorTypeArgsProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val decls = listOf(
+ // Those have 2 type parameters
+ resolver.getClassDeclarationByName("KS")!!,
+ resolver.getClassDeclarationByName("KL")!!,
+ resolver.getClassDeclarationByName("JS")!!,
+ resolver.getClassDeclarationByName("JL")!!,
+ // Those have 0 or 1 parameters
+ resolver.getClassDeclarationByName("KS1")!!,
+ resolver.getClassDeclarationByName("KL1")!!,
+ resolver.getClassDeclarationByName("JS1")!!,
+ resolver.getClassDeclarationByName("JL1")!!,
+ resolver.getClassDeclarationByName("JSE")!!,
+ resolver.getClassDeclarationByName("JSE.E")!!,
+ resolver.getClassDeclarationByName("JLE")!!,
+ resolver.getClassDeclarationByName("JLE.E")!!,
+ resolver.getClassDeclarationByName("KSE")!!,
+ resolver.getClassDeclarationByName("KSE.E")!!,
+ resolver.getClassDeclarationByName("KLE")!!,
+ resolver.getClassDeclarationByName("KLE.E")!!,
+ )
+ val x = resolver.getPropertyDeclarationByName(resolver.getKSNameFromString("x"), true)!!
+ val xargs = x.type.element!!.typeArguments
+ val y = resolver.getPropertyDeclarationByName(resolver.getKSNameFromString("y"), true)!!
+ val yargs = y.type.element!!.typeArguments
+
+ for (decl in decls) {
+ val declName = decl.qualifiedName!!.asString()
+ results.add("$declName.star.replace($xargs): ${decl.asStarProjectedType().replace(xargs)}")
+ results.add("$declName.star.replace($yargs): ${decl.asStarProjectedType().replace(yargs)}")
+ results.add("$declName.asType($xargs): ${decl.asType(xargs)}")
+ results.add("$declName.asType($yargs): ${decl.asType(yargs)}")
+ results.add("$declName.asType(emptyList()): ${decl.asType(emptyList())}")
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ResolveJavaTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ResolveJavaTypeProcessor.kt
new file mode 100644
index 00000000..b38a800c
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ResolveJavaTypeProcessor.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.Nullability
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.Variance
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class ResolveJavaTypeProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val visitor = ResolveJavaTypeVisitor()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val symbol = resolver.getClassDeclarationByName(resolver.getKSNameFromString("C"))
+ val symbolTypeParameter = resolver.getClassDeclarationByName(resolver.getKSNameFromString("Base"))
+ val another = resolver.getClassDeclarationByName(resolver.getKSNameFromString("Another"))
+ val javaEnum = resolver.getClassDeclarationByName(resolver.getKSNameFromString("JavaEnum"))
+ assert(symbol?.origin == Origin.JAVA)
+ symbol!!.accept(visitor, Unit)
+ symbolTypeParameter!!.accept(visitor, Unit)
+ another!!.accept(visitor, Unit)
+ javaEnum!!.accept(visitor, Unit)
+ return emptyList()
+ }
+
+ inner class ResolveJavaTypeVisitor : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ classDeclaration.declarations.forEach { it.accept(this, Unit) }
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ function.parameters.forEach {
+ it.type.accept(this, Unit)
+ }
+ function.returnType?.accept(this, Unit)
+ }
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: Unit) {
+ if (typeReference.origin == Origin.JAVA) {
+ results.add(typeReference.render())
+ }
+ }
+ }
+
+ fun KSTypeReference.render(): String {
+ val sb = StringBuilder(this.resolve().declaration.qualifiedName?.asString() ?: "<ERROR>")
+ if (this.resolve().arguments.toList().isNotEmpty()) {
+ sb.append(
+ "<${this.resolve().arguments.map {
+ when (it.variance) {
+ Variance.STAR -> "*"
+ Variance.INVARIANT -> ""
+ Variance.CONTRAVARIANT -> "in "
+ Variance.COVARIANT -> "out "
+ } + it.type?.render()
+ }.joinToString(", ")}>"
+ )
+ }
+ if (this.resolve().nullability != Nullability.NOT_NULL) {
+ sb.append("?")
+ }
+ return sb.toString()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SealedClassProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SealedClassProcessor.kt
new file mode 100644
index 00000000..9cb6ea70
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SealedClassProcessor.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+class SealedClassProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ result.add("from lib")
+ resolver.getClassDeclarationByName("lib.Expr")!!.let {
+ result.add(
+ it.getSealedSubclasses().map { sub ->
+ "${sub.simpleName.asString()}: ${sub.origin}"
+ }.toList().sorted().toString()
+ )
+ }
+
+ result.add("from source")
+ resolver.getNewFiles().forEach { f ->
+ f.declarations.forEach {
+ if (it is KSClassDeclaration) {
+ val subs = it.getSealedSubclasses().map { sub ->
+ "${sub.simpleName.asString()}: ${sub.origin}"
+ }.toList().sorted()
+ result.add("${it.simpleName.asString()} : $subs")
+ }
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SuperTypesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SuperTypesProcessor.kt
new file mode 100644
index 00000000..0752e34e
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SuperTypesProcessor.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+open class SuperTypesProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ fun KSClassDeclaration.toResult(): String {
+ val supers = superTypes.map { it.resolve().declaration.qualifiedName!!.asString() }.joinToString(", ")
+ return "${qualifiedName!!.asString()}: $supers"
+ }
+
+ fun show(decl: String) = results.add(resolver.getClassDeclarationByName(decl)!!.toResult())
+
+ show("KotlinInterfaceInLib")
+ show("KotlinInterfaceInLibWithSuper")
+ show("AbstractKotlinClassInLib")
+ show("AbstractKotlinClassInLibWithSuperClass")
+ show("AbstractKotlinClassInLibWithSuperInterface")
+ show("KotlinClassInLib")
+ show("KotlinClassInLibWithSuperAbstract")
+ show("KotlinClassInLibWithSuperClass")
+ show("KotlinClassInLibWithSuperInterface")
+ show("JavaInterfaceInLib")
+ show("JavaInterfaceInLibWithSuper")
+ show("AbstractJavaClassInLib")
+ show("AbstractJavaClassInLibWithSuperInterface")
+ show("AbstractJavaClassInLibWithSuperClass")
+ show("JavaClassInLib")
+ show("JavaClassInLibWithSuperInterface")
+ show("JavaClassInLibWithSuperAbstract")
+ show("JavaClassInLibWithSuperClass")
+
+ show("KotlinInterfaceInSource")
+ show("KotlinInterfaceInSourceWithSuper")
+ show("AbstractKotlinClassInSource")
+ show("AbstractKotlinClassInSourceWithSuperClass")
+ show("AbstractKotlinClassInSourceWithSuperInterface")
+ show("KotlinClassInSource")
+ show("KotlinClassInSourceWithSuperAbstract")
+ show("KotlinClassInSourceWithSuperClass")
+ show("KotlinClassInSourceWithSuperInterface")
+ show("JavaInterfaceInSource")
+ show("JavaInterfaceInSourceWithSuper")
+ show("AbstractJavaClassInSource")
+ show("AbstractJavaClassInSourceWithSuperInterface")
+ show("AbstractJavaClassInSourceWithSuperClass")
+ show("JavaClassInSource")
+ show("JavaClassInSourceWithSuperInterface")
+ show("JavaClassInSourceWithSuperAbstract")
+ show("JavaClassInSourceWithSuperClass")
+
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ThrowListProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ThrowListProcessor.kt
new file mode 100644
index 00000000..8750151b
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ThrowListProcessor.kt
@@ -0,0 +1,71 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getConstructors
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSType
+
+@KspExperimental
+class ThrowListProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val klass = resolver.getClassDeclarationByName("ThrowsKt")!!
+ val jlass = resolver.getClassDeclarationByName("ThrowsException")!!
+ result.add(
+ resolver.getJvmCheckedException(
+ klass.declarations.single {
+ it.simpleName.asString() == "throwsKT"
+ } as KSFunctionDeclaration
+ ).toResult()
+ )
+ result.add(
+ resolver.getJvmCheckedException(
+ (
+ jlass.declarations.single {
+ it.simpleName.asString() == "foo"
+ } as KSFunctionDeclaration
+ )
+ ).toResult()
+ )
+ val propertyA = klass.declarations.single { it.simpleName.asString() == "a" } as KSPropertyDeclaration
+ result.add(resolver.getJvmCheckedException(propertyA.getter!!).toResult())
+ result.add(resolver.getJvmCheckedException(propertyA.setter!!).toResult())
+ val jlib = resolver.getClassDeclarationByName("JavaLib")!!
+ val klib = resolver.getClassDeclarationByName("KtLib")!!
+ klib.declarations.filter { it.simpleName.asString() == "throwsLibKt" }.map {
+ resolver.getJvmCheckedException(it as KSFunctionDeclaration).toResult()
+ }.forEach { result.add(it) }
+ klib.declarations.filter { it.simpleName.asString() == "getterThrows" }.map {
+ resolver.getJvmCheckedException((it as KSPropertyDeclaration).getter!!).toResult()
+ }.forEach { result.add(it) }
+ klib.declarations.filter { it.simpleName.asString() == "setterThrows" }.map {
+ resolver.getJvmCheckedException((it as KSPropertyDeclaration).setter!!).toResult()
+ }.forEach { result.add(it) }
+ klib.declarations.filter { it.simpleName.asString() == "bothThrows" }.map {
+ resolver.getJvmCheckedException((it as KSPropertyDeclaration).getter!!).toResult()
+ }.forEach { result.add(it) }
+ klib.declarations.filter { it.simpleName.asString() == "bothThrows" }.map {
+ resolver.getJvmCheckedException((it as KSPropertyDeclaration).setter!!).toResult()
+ }.forEach { result.add(it) }
+ jlib.declarations.filter { it.simpleName.asString() == "foo" }.map {
+ resolver.getJvmCheckedException(it as KSFunctionDeclaration).toResult()
+ }.forEach { result.add(it) }
+ jlib.getConstructors().map {
+ resolver.getJvmCheckedException(it).toResult()
+ }.forEach { result.add(it) }
+ return emptyList()
+ }
+
+ private fun Sequence<KSType>.toResult() = this.joinToString(separator = ",") {
+ it.declaration.qualifiedName!!.asString()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TopLevelMemberProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TopLevelMemberProcessor.kt
new file mode 100644
index 00000000..05cc4d02
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TopLevelMemberProcessor.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+@OptIn(KspExperimental::class)
+open class TopLevelMemberProcessor : AbstractTestProcessor() {
+ lateinit var results: List<String>
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ results = listOf("lib", "main").flatMap { pkg ->
+ resolver.getDeclarationsFromPackage(pkg)
+ .flatMap { declaration ->
+ val declarations = mutableListOf<KSDeclaration>()
+ declaration.accept(AllMembersVisitor(), declarations)
+ declarations
+ }.map {
+ "$pkg : ${it.simpleName.asString()} -> ${resolver.getSyntheticJvmClass(it)}"
+ }.sorted()
+ }
+ return emptyList()
+ }
+
+ private fun Resolver.getSyntheticJvmClass(
+ declaration: KSDeclaration
+ ) = when (declaration) {
+ is KSPropertyDeclaration -> this.getOwnerJvmClassName(declaration)
+ is KSFunctionDeclaration -> this.getOwnerJvmClassName(declaration)
+ else -> error("unexpected declaration $declaration")
+ }
+
+ private class AllMembersVisitor : KSTopDownVisitor<MutableList<KSDeclaration>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableList<KSDeclaration>) {
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: MutableList<KSDeclaration>) {
+ data.add(property)
+ super.visitPropertyDeclaration(property, data)
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: MutableList<KSDeclaration>) {
+ data.add(function)
+ super.visitFunctionDeclaration(function, data)
+ }
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasComparisonProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasComparisonProcessor.kt
new file mode 100644
index 00000000..ac952ce9
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasComparisonProcessor.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class TypeAliasComparisonProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val typeRefCollector = TypeRefCollector()
+ val refs = mutableSetOf<KSTypeReference>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(typeRefCollector, refs)
+ }
+
+ fun KSType.aliases(): List<KSType> =
+ listOf(this) + ((this.declaration as? KSTypeAlias)?.type?.resolve()?.aliases() ?: emptyList())
+
+ val interesting = setOf("Anno", "Bnno")
+ val iRefs = refs.filterNot {
+ it.origin != Origin.KOTLIN || it.annotations.all { it.shortName.asString() !in interesting }
+ }
+ val types = iRefs.map { it.resolve()!! }.flatMap { it.aliases() }
+
+ for (i in types) {
+ for (j in types) {
+ results.add("$i = $j : ${i.isAssignableFrom(j)}")
+ }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results.sorted()
+ }
+}
+
+open class TypeRefCollector : KSTopDownVisitor<MutableCollection<KSTypeReference>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableCollection<KSTypeReference>) = Unit
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: MutableCollection<KSTypeReference>) {
+ super.visitTypeReference(typeReference, data)
+ data.add(typeReference)
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasProcessor.kt
new file mode 100644
index 00000000..40581584
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasProcessor.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+open class TypeAliasProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val types = mutableListOf<KSType>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val byFinalSignature = mutableMapOf<String, MutableList<KSType>>()
+ resolver.getNewFiles().flatMap { file ->
+ file.declarations.filterIsInstance<KSPropertyDeclaration>().map { prop ->
+ buildString {
+ append(prop.simpleName.asString())
+ append(" : ")
+ val propType = prop.type.resolve()
+ val signatures = propType.typeAliasSignatures()
+ append(signatures.joinToString(" = "))
+ byFinalSignature.getOrPut(signatures.last()) {
+ mutableListOf()
+ }.add(propType)
+ }
+ }
+ }.forEach(results::add)
+ byFinalSignature.forEach { (signature, sameTypeAliases) ->
+ // exclude List<T> case from the test because they lose a type argument when resolving aliases, so they
+ // are not the same anymore as we traverse the declarations.
+ if (signature != "List<T>") {
+ for (i in sameTypeAliases) {
+ for (j in sameTypeAliases) {
+ assert(i == j) {
+ "$i and $j both map to $signature, equals should return true"
+ }
+ }
+ }
+ assert(sameTypeAliases.map { it.hashCode() }.distinct().size == 1) {
+ "different hashcodes for members of $signature"
+ }
+ }
+ }
+ return emptyList()
+ }
+
+ private fun KSType.typeAliasSignatures(): List<String> {
+ var self: KSType? = this
+ return buildList {
+ while (self != null) {
+ add(self!!.toSignature())
+ self = (self?.declaration as? KSTypeAlias)?.type?.resolve()
+ }
+ }
+ }
+
+ private fun KSType.toSignature(): String = buildString {
+ append(declaration.simpleName.asString())
+ if (arguments.isNotEmpty()) {
+ append("<")
+ arguments.map {
+ it.type?.resolve()?.toSignature() ?: "<error>"
+ }.forEach(this::append)
+ append(">")
+ }
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComparisonProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComparisonProcessor.kt
new file mode 100644
index 00000000..f5850b7b
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComparisonProcessor.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class TypeComparisonProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val typeCollector = TypeCollector()
+ val types = mutableSetOf<KSType>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+ val ignoredNames = mutableSetOf<String>()
+
+ files.forEach {
+ it.accept(typeCollector, types)
+ it.annotations.forEach {
+ if (it.shortName.asString() == "Suppress") {
+ it.arguments.forEach {
+ (it.value as List<String>).forEach {
+ ignoredNames.add(it)
+ }
+ }
+ }
+ }
+ }
+
+ val sortedTypes = types.filterNot { it.declaration.simpleName.asString() in ignoredNames }.sortedBy {
+ it.toString()
+ }
+
+ for (i in sortedTypes) {
+ for (j in sortedTypes) {
+ results.add("$i ?= $j : ${i.isAssignableFrom(j)}")
+ }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
+
+class TypeCollectorNoAccessor : TypeCollector() {
+ override fun visitPropertyGetter(getter: KSPropertyGetter, data: MutableCollection<KSType>) {
+ }
+
+ override fun visitPropertySetter(setter: KSPropertySetter, data: MutableCollection<KSType>) {
+ }
+}
+
+open class TypeCollector : KSTopDownVisitor<MutableCollection<KSType>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableCollection<KSType>) = Unit
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: MutableCollection<KSType>) {
+ super.visitTypeReference(typeReference, data)
+ typeReference.resolve().let { data.add(it) }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComposureProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComposureProcessor.kt
new file mode 100644
index 00000000..78e2dc0e
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComposureProcessor.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class TypeComposureProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+ val classes = mutableSetOf<KSClassDeclaration>()
+ val references = mutableSetOf<KSTypeReference>()
+
+ files.forEach {
+ it.accept(
+ object : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) = Unit
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ super.visitClassDeclaration(classDeclaration, Unit)
+ classes.add(classDeclaration)
+ }
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: Unit) {
+ super.visitTypeReference(typeReference, data)
+ references.add(typeReference)
+ }
+ },
+ Unit
+ )
+ }
+
+ val composed = mutableSetOf<KSType>()
+ val types = references.filter { it.resolve().arguments.toList().size == 1 }.map { it.resolve() }
+ // TODO: there is a mismatched behavior between 2 implementations, AA implementation has an upperbound of
+ // Any? for unbounded type parameter.
+ val refs0Arg = references.filter { it.resolve().arguments.toList().size == 0 && !it.resolve().isMarkedNullable }
+
+ for (c in classes) {
+ for (ref in refs0Arg) {
+ composed.add(c.asType(listOf(resolver.getTypeArgument(ref, Variance.INVARIANT))))
+ composed.add(c.asType(listOf(resolver.getTypeArgument(ref, Variance.COVARIANT))))
+ composed.add(c.asType(listOf(resolver.getTypeArgument(ref, Variance.CONTRAVARIANT))))
+ composed.add(c.asType(listOf(resolver.getTypeArgument(ref, Variance.STAR))))
+ }
+ }
+
+ for (t in types) {
+ for (ref in refs0Arg) {
+ composed.add(t.replace(listOf(resolver.getTypeArgument(ref, Variance.INVARIANT))))
+ composed.add(t.replace(listOf(resolver.getTypeArgument(ref, Variance.COVARIANT))))
+ composed.add(t.replace(listOf(resolver.getTypeArgument(ref, Variance.CONTRAVARIANT))))
+ composed.add(t.starProjection())
+ }
+ }
+
+ val sorted = composed.sortedBy { it.toString() }
+ for (i in sorted) {
+ for (j in sorted) {
+ results.add("$i ?= $j : ${i.isAssignableFrom(j)}")
+ }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterEqualsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterEqualsProcessor.kt
new file mode 100644
index 00000000..b7fa16cb
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterEqualsProcessor.kt
@@ -0,0 +1,22 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getDeclaredProperties
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+class TypeParameterEqualsProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<Boolean>()
+
+ override fun toResult(): List<String> {
+ return result.map { it.toString() }
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val foo = resolver.getClassDeclarationByName("Foo")!!
+ val i = resolver.getClassDeclarationByName("I")!!
+ result.add(foo.typeParameters.first() == foo.getDeclaredProperties().first().type.resolve().declaration)
+ result.add(i.typeParameters[0] == i.typeParameters[1].bounds.single().resolve().declaration)
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterReferenceProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterReferenceProcessor.kt
new file mode 100644
index 00000000..58208d80
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterReferenceProcessor.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getDeclaredFunctions
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+open class TypeParameterReferenceProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val collector = ReferenceCollector()
+ val references = mutableSetOf<KSTypeReference>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(collector, references)
+ }
+
+ val sortedReferences = references.filter { it.element is KSClassifierReference && it.origin == Origin.KOTLIN }
+ .sortedBy { (it.element as KSClassifierReference).referencedName() }
+
+ for (i in sortedReferences) {
+ val r = i.resolve()
+ results.add("${r.declaration.qualifiedName?.asString()}: ${r.isMarkedNullable}")
+ }
+ val libFoo = resolver.getClassDeclarationByName("LibFoo")!!
+ libFoo.declarations.filterIsInstance<KSPropertyDeclaration>().forEach { results.add(it.type.toString()) }
+ val javaLib = resolver.getClassDeclarationByName("JavaLib")!!
+ javaLib.declarations.filterIsInstance<KSFunctionDeclaration>().forEach { results.add(it.returnType.toString()) }
+ val srj = resolver.getClassDeclarationByName("SelfReferencingJava")!!
+ srj.asStarProjectedType().declaration.typeParameters.single().bounds
+ .forEach { results.add(it.resolve().toString()) }
+ val boundedTypeParameter = resolver.getClassDeclarationByName("BoundedTypeParameter")!!
+ boundedTypeParameter.getDeclaredFunctions().filter { it.origin == Origin.JAVA }.forEach {
+ (it.returnType!!.resolve().declaration as KSTypeParameter).bounds.forEach {
+ results.add(it.resolve().toString())
+ }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ValidateProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ValidateProcessor.kt
new file mode 100644
index 00000000..16afc8c2
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ValidateProcessor.kt
@@ -0,0 +1,60 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSDeclaration
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.validate
+
+class ValidateProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ private fun validate(symbol: KSDeclaration, predicate: (KSNode?, KSNode) -> Boolean = { _, _ -> true }) {
+ if (symbol.validate(predicate)) {
+ results.add("${symbol.simpleName.asString()} valid")
+ } else {
+ results.add("${symbol.simpleName.asString()} invalid")
+ }
+ }
+
+ override fun toResult(): List<String> = results
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val ErrorInMember = resolver.getClassDeclarationByName("ErrorInMember")!!
+ val SkipErrorInMember = resolver.getClassDeclarationByName("SkipErrorInMember")!!
+ val GoodClass = resolver.getClassDeclarationByName("GoodClass")!!
+ val C = resolver.getClassDeclarationByName("C")!!
+ val BadJavaClass = resolver.getClassDeclarationByName("BadJavaClass")!!
+ val ErrorAnnotationType = resolver.getClassDeclarationByName("ErrorAnnotationType")!!
+ val ErrorInAnnotationArgumentSingleType =
+ resolver.getClassDeclarationByName("ErrorInAnnotationArgumentSingleType")!!
+ val ErrorInAnnotationArgumentMultipleTypes =
+ resolver.getClassDeclarationByName("ErrorInAnnotationArgumentMultipleTypes")!!
+ val ErrorInAnnotationArgumentComposed =
+ resolver.getClassDeclarationByName("ErrorInAnnotationArgumentComposed")!!
+ val ValidAnnotationArgumentType =
+ resolver.getClassDeclarationByName("ValidAnnotationArgumentType")!!
+ validate(ErrorInMember)
+ ErrorInMember.declarations.forEach { validate(it) }
+ validate(SkipErrorInMember) { node, _ ->
+ node !is KSPropertyDeclaration && node !is KSFunctionDeclaration
+ }
+ SkipErrorInMember.declarations.forEach {
+ validate(it) { node, _ ->
+ node !is KSPropertyDeclaration && node !is KSFunctionDeclaration
+ }
+ }
+ validate(GoodClass)
+ validate(C)
+ validate(BadJavaClass)
+ validate(ErrorAnnotationType)
+ validate(ErrorInAnnotationArgumentSingleType)
+ validate(ErrorInAnnotationArgumentMultipleTypes)
+ validate(ErrorInAnnotationArgumentComposed)
+ validate(ValidAnnotationArgumentType)
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/VisibilityProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/VisibilityProcessor.kt
new file mode 100644
index 00000000..4489f346
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/VisibilityProcessor.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getVisibility
+import com.google.devtools.ksp.isVisibleFrom
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+
+class VisibilityProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val symbolA = resolver.getSymbolsWithAnnotation("TestA").single() as KSClassDeclaration
+ val symbolB = resolver.getSymbolsWithAnnotation("TestB").single() as KSClassDeclaration
+ val symbolD = resolver.getSymbolsWithAnnotation("TestD").single() as KSClassDeclaration
+ val allFunctions = (symbolA.superTypes.single().resolve()!!.declaration as KSClassDeclaration)
+ .declarations.filterIsInstance<KSFunctionDeclaration>()
+ allFunctions.map {
+ "${it.simpleName.asString()}: ${it.getVisibility()},visible in A, B, D: " +
+ "${it.isVisibleFrom(symbolA)}, ${it.isVisibleFrom(symbolB)}, ${it.isVisibleFrom(symbolD)}"
+ }.forEach { results.add(it) }
+ val javaClass = resolver.getClassDeclarationByName("JavaClass")!!
+ val kotlinClass = resolver.getClassDeclarationByName("KotlinClass")!!
+ val kotlinSubClass = resolver.getClassDeclarationByName("KotlinSubClass")!!
+ val javaLibEnum = resolver.getClassDeclarationByName("LibEnumJava")!!
+ val kotlinLibEnum = resolver.getClassDeclarationByName("LibEnum")!!
+ val javaEnum = resolver.getClassDeclarationByName("Enum")!!
+ val kotlinEnum = resolver.getClassDeclarationByName("KtEnum")!!
+ val kotlinEnumWithVal = resolver.getClassDeclarationByName("KtEnumWithVal")!!
+ javaClass.declarations.filterIsInstance<KSPropertyDeclaration>().map {
+ "${it.simpleName.asString()}: ${it.getVisibility()},visible in A, B, D: " +
+ "${it.isVisibleFrom(symbolA)}, ${it.isVisibleFrom(symbolB)}, ${it.isVisibleFrom(symbolD)}"
+ }.forEach { results.add(it) }
+ kotlinClass.declarations.filterIsInstance<KSPropertyDeclaration>().map {
+ "${it.simpleName.asString()}: ${it.getVisibility()},visible in A, B, D: " +
+ "${it.isVisibleFrom(symbolA)}, ${it.isVisibleFrom(symbolB)}, ${it.isVisibleFrom(symbolD)}"
+ }.forEach { results.add(it) }
+ kotlinSubClass.declarations.filterIsInstance<KSPropertyDeclaration>().map {
+ "${it.simpleName.asString()}: ${it.getVisibility()},visible in A, B, D: " +
+ "${it.isVisibleFrom(symbolA)}, ${it.isVisibleFrom(symbolB)}, ${it.isVisibleFrom(symbolD)}"
+ }.forEach { results.add(it) }
+ javaLibEnum.declarations.filterIsInstance<KSFunctionDeclaration>().map {
+ "${javaLibEnum.simpleName.asString()}: ${it.simpleName.asString()}: ${it.getVisibility() }"
+ }.forEach { results.add(it) }
+ kotlinLibEnum.declarations.filterIsInstance<KSFunctionDeclaration>().map {
+ "${kotlinLibEnum.simpleName.asString()}: ${it.simpleName.asString()}: ${it.getVisibility() }"
+ }.forEach { results.add(it) }
+ javaEnum.declarations.filterIsInstance<KSFunctionDeclaration>().map {
+ "${javaEnum.simpleName.asString()}: ${it.simpleName.asString()}: ${it.getVisibility() }"
+ }.forEach { results.add(it) }
+ kotlinEnum.declarations.filterIsInstance<KSFunctionDeclaration>().map {
+ "${kotlinEnum.simpleName.asString()}: ${it.simpleName.asString()}: ${it.getVisibility() }"
+ }.forEach { results.add(it) }
+ kotlinEnumWithVal.declarations.filterIsInstance<KSFunctionDeclaration>().map {
+ "${kotlinEnumWithVal.simpleName.asString()}: ${it.simpleName.asString()}: ${it.getVisibility() }"
+ }.forEach { results.add(it) }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/testutils/AbstractKSPTest.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/testutils/AbstractKSPTest.kt
new file mode 100644
index 00000000..b2d89bfb
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/testutils/AbstractKSPTest.kt
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.ksp.testutils
+
+import com.google.devtools.ksp.processor.AbstractTestProcessor
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.Disposer
+import com.intellij.testFramework.TestDataFile
+import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
+import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
+import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoot
+import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
+import org.jetbrains.kotlin.codegen.GenerationUtils
+import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.test.ExecutionListenerBasedDisposableProvider
+import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
+import org.jetbrains.kotlin.test.builders.testConfiguration
+import org.jetbrains.kotlin.test.compileJavaFiles
+import org.jetbrains.kotlin.test.directives.ConfigurationDirectives
+import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
+import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
+import org.jetbrains.kotlin.test.model.DependencyKind
+import org.jetbrains.kotlin.test.model.FrontendKind
+import org.jetbrains.kotlin.test.model.ResultingArtifact
+import org.jetbrains.kotlin.test.model.TestModule
+import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerTest
+import org.jetbrains.kotlin.test.services.*
+import org.jetbrains.kotlin.test.services.configuration.CommonEnvironmentConfigurator
+import org.jetbrains.kotlin.test.services.configuration.JvmEnvironmentConfigurator
+import org.jetbrains.kotlin.test.services.impl.TemporaryDirectoryManagerImpl
+import org.jetbrains.kotlin.test.util.KtTestUtil
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.TestInfo
+import java.io.File
+
+abstract class DisposableTest {
+ private var _disposable: Disposable? = null
+ protected val disposable: Disposable get() = _disposable!!
+
+ @BeforeEach
+ private fun initDisposable(testInfo: TestInfo) {
+ _disposable = Disposer.newDisposable("disposable for ${testInfo.displayName}")
+ }
+
+ @AfterEach
+ private fun disposeDisposable() {
+ _disposable?.let { Disposer.dispose(it) }
+ _disposable = null
+ }
+}
+
+abstract class AbstractKSPTest(frontend: FrontendKind<*>) : DisposableTest() {
+ companion object {
+ val TEST_PROCESSOR = "// TEST PROCESSOR:"
+ val EXPECTED_RESULTS = "// EXPECTED:"
+ }
+
+ val kspTestRoot = KtTestUtil.tmpDir("test")
+ fun rootDirForModule(name: String) = File(kspTestRoot, name)
+ fun outDirForModule(name: String) = File(rootDirForModule(name), "out")
+ fun javaDirForModule(name: String) = File(rootDirForModule(name), "javaSrc")
+ val TestModule.testRoot: File
+ get() = rootDirForModule(name)
+ val TestModule.outDir: File
+ get() = outDirForModule(name)
+ val TestModule.javaDir: File
+ get() = javaDirForModule(name)
+
+ protected lateinit var testInfo: KotlinTestInfo
+ private set
+
+ @BeforeEach
+ fun initTestInfo(testInfo: TestInfo) {
+ this.testInfo = KotlinTestInfo(
+ className = testInfo.testClass.orElseGet(null)?.name ?: "_undefined_",
+ methodName = testInfo.testMethod.orElseGet(null)?.name ?: "_testUndefined_",
+ tags = testInfo.tags
+ )
+ }
+
+ open fun configureTest(builder: TestConfigurationBuilder) = Unit
+
+ abstract fun runTest(
+ testServices: TestServices,
+ mainModule: TestModule,
+ libModules: List<TestModule>,
+ testProcessor: AbstractTestProcessor,
+ ): List<String>
+
+ private val configure: TestConfigurationBuilder.() -> Unit = {
+ globalDefaults {
+ this@globalDefaults.frontend = frontend
+ targetPlatform = JvmPlatforms.defaultJvmPlatform
+ dependencyKind = DependencyKind.Source
+ }
+ useConfigurators(
+ ::CommonEnvironmentConfigurator,
+ ::JvmEnvironmentConfigurator,
+ )
+ assertions = JUnit5Assertions
+ useAdditionalService<TemporaryDirectoryManager>(::TemporaryDirectoryManagerImpl)
+ useAdditionalService<ApplicationDisposableProvider> { ExecutionListenerBasedDisposableProvider() }
+ useAdditionalService<KotlinStandardLibrariesPathProvider> { StandardLibrariesPathProviderForKotlinProject }
+
+ useDirectives(*AbstractKotlinCompilerTest.defaultDirectiveContainers.toTypedArray())
+ useDirectives(JvmEnvironmentConfigurationDirectives)
+
+ defaultDirectives {
+ +JvmEnvironmentConfigurationDirectives.FULL_JDK
+ // SourceFileProviderImpl doesn't group files by module. Let's load them manually.
+ +JvmEnvironmentConfigurationDirectives.SKIP_JAVA_SOURCES
+ +ConfigurationDirectives.WITH_STDLIB
+ +LanguageSettingsDirectives.ALLOW_KOTLIN_PACKAGE
+ }
+
+ configureTest(this)
+
+ startingArtifactFactory = { ResultingArtifact.Source() }
+ this.testInfo = this@AbstractKSPTest.testInfo
+ }
+
+ fun TestModule.loadKtFiles(project: Project): List<KtFile> {
+ return files.filter { it.isKtFile }.map {
+ KtTestUtil.createFile(it.name, it.originalContent, project)
+ }
+ }
+
+ fun TestModule.writeJavaFiles(): List<File> {
+ javaDir.mkdirs()
+ val files = javaFiles.map { it to File(javaDir, it.relativePath) }
+ files.forEach { (testFile, file) ->
+ file.parentFile.mkdirs()
+ file.writeText(testFile.originalContent)
+ }
+ return files.map { it.second }
+ }
+
+ // No, this is far from complete. It only works for our test cases.
+ //
+ // No, neither CompiledLibraryProvider nor LibraryEnvironmentConfigurator can be used. They rely on
+ // dist/kotlinc/lib/*
+ //
+ // No, sourceFileProvider doesn't group files by module unfortunately. Let's do it by ourselves.
+ open fun compileModule(module: TestModule, testServices: TestServices) {
+ val javaFiles = module.writeJavaFiles()
+ val compilerConfiguration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
+ val dependencies = module.allDependencies.map { outDirForModule(it.moduleName) }
+ compilerConfiguration.addJvmClasspathRoots(dependencies)
+ compilerConfiguration.addJavaSourceRoot(module.javaDir)
+
+ // TODO: other platforms
+ val kotlinCoreEnvironment = KotlinCoreEnvironment.createForTests(
+ disposable,
+ compilerConfiguration,
+ EnvironmentConfigFiles.JVM_CONFIG_FILES
+ )
+ val ktFiles = module.loadKtFiles(kotlinCoreEnvironment.project)
+ GenerationUtils.compileFilesTo(ktFiles, kotlinCoreEnvironment, module.outDir)
+
+ if (module.javaFiles.isEmpty())
+ return
+
+ val classpath = (dependencies + KtTestUtil.getAnnotationsJar() + module.outDir)
+ .joinToString(File.pathSeparator) { it.absolutePath }
+ val options = listOf(
+ "-classpath", classpath,
+ "-d", module.outDir.path
+ )
+ compileJavaFiles(javaFiles, options, assertions = JUnit5Assertions)
+ }
+
+ fun runTest(@TestDataFile path: String) {
+ val testConfiguration = testConfiguration(path, configure)
+ Disposer.register(disposable, testConfiguration.rootDisposable)
+ val testServices = testConfiguration.testServices
+ val moduleStructure = testConfiguration.moduleStructureExtractor.splitTestDataByModules(
+ path,
+ testConfiguration.directives,
+ )
+ val mainModule = moduleStructure.modules.last()
+ val libModules = moduleStructure.modules.dropLast(1)
+
+ for (lib in libModules) {
+ compileModule(lib, testServices)
+ }
+ val compilerConfigurationMain = testServices.compilerConfigurationProvider.getCompilerConfiguration(mainModule)
+ compilerConfigurationMain.addJvmClasspathRoots(libModules.map { it.outDir })
+
+ val contents = mainModule.files.first().originalFile.readLines()
+
+ val testProcessorName = contents
+ .filter { it.startsWith(TEST_PROCESSOR) }
+ .single()
+ .substringAfter(TEST_PROCESSOR)
+ .trim()
+ val testProcessor: AbstractTestProcessor =
+ Class.forName("com.google.devtools.ksp.processor.$testProcessorName")
+ .getDeclaredConstructor().newInstance() as AbstractTestProcessor
+
+ val expectedResults = contents
+ .dropWhile { !it.startsWith(EXPECTED_RESULTS) }
+ .drop(1)
+ .takeWhile { !it.startsWith("// END") }
+ .map { it.substring(3).trim() }
+
+ val results = runTest(testServices, mainModule, libModules, testProcessor)
+ Assertions.assertEquals(expectedResults.joinToString("\n"), results.joinToString("\n"))
+ }
+}
diff --git a/test-utils/testData/api/abstractFunctions.kt b/test-utils/testData/api/abstractFunctions.kt
new file mode 100644
index 00000000..477f6369
--- /dev/null
+++ b/test-utils/testData/api/abstractFunctions.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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: AbstractFunctionsProcessor
+// EXPECTED:
+// abstractF01
+// abstractF02
+// abstractF04
+// abstractF05
+// END
+// FILE: AbstractClassKotlin.kt
+abstract class AbstractClassKotlin {
+ abstract fun abstractF01()
+ fun concreteF01() = Unit
+ companion object {
+ fun concreteF02() = Unit
+ @JvmStatic fun concreteF02() = Unit
+ }
+}
+
+// FILE: InterfaceKotlin.kt
+interface InterfaceKotlin {
+ fun abstractF02()
+ fun abstractWithDefaultF03() { /*default*/ Unit }
+ companion object {
+ fun concreteF03() = Unit
+ @JvmStatic fun concreteF04() = Unit
+ }
+}
+
+// FILE: AbstractClassJava.java
+public abstract class AbstractClassJava {
+ public abstract void abstractF04();
+ public void concreteF05() {}
+ public static void staticF01() {}
+}
+
+// FILE: InterfaceJava.java
+public interface InterfaceJava {
+ public void abstractF05();
+ public default void abstractWithDefaultF06() { /* default */ }
+ public static void staticF02() {}
+}
diff --git a/test-utils/testData/api/allFunctions_java_inherits_kt.kt b/test-utils/testData/api/allFunctions_java_inherits_kt.kt
new file mode 100644
index 00000000..bd1303a1
--- /dev/null
+++ b/test-utils/testData/api/allFunctions_java_inherits_kt.kt
@@ -0,0 +1,46 @@
+/*
+ * 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: AllFunctionsProcessor
+// EXPECTED:
+// class: JavaImplOfKotlinInterface
+// x
+// <init>(): JavaImplOfKotlinInterface
+// equals(kotlin.Any): kotlin.Boolean
+// hashCode(): kotlin.Int
+// toString(): kotlin.String
+// class: KotlinInterfaceWithProperty
+// x
+// equals(kotlin.Any): kotlin.Boolean
+// hashCode(): kotlin.Int
+// toString(): kotlin.String
+// END
+
+// FILE: KotlinInterfaceWithProperty.kt
+interface KotlinInterfaceWithProperty {
+ var x:Int
+}
+
+// FILE: JavaImplOfKotlinInterface.java
+class JavaImplOfKotlinInterface implements KotlinInterfaceWithProperty {
+ public int getX() {
+ return 1;
+ }
+ public void setX(int value) {
+ }
+}
diff --git a/test-utils/testData/api/allFunctions_kotlin.kt b/test-utils/testData/api/allFunctions_kotlin.kt
new file mode 100644
index 00000000..febbac12
--- /dev/null
+++ b/test-utils/testData/api/allFunctions_kotlin.kt
@@ -0,0 +1,72 @@
+/*
+ * 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: AllFunctionsProcessor
+// class: Data
+// a
+// <init>(kotlin.String): Data
+// component1(): kotlin.String
+// copy(kotlin.String(hasDefault)): Data
+// equals(kotlin.Any): kotlin.Boolean
+// hashCode(): kotlin.Int
+// toString(): kotlin.String
+// class: Sub
+// equals(kotlin.Any): kotlin.Boolean
+// foo(kotlin.String ...): kotlin.Unit
+// hashCode(): kotlin.Int
+// toString(): kotlin.String
+// class: SubAbstract
+// <init>(): SubAbstract
+// equals(kotlin.Any): kotlin.Boolean
+// foo(kotlin.String ...): kotlin.Unit
+// hashCode(): kotlin.Int
+// toString(): kotlin.String
+// class: Super
+// equals(kotlin.Any): kotlin.Boolean
+// foo(kotlin.String ...): kotlin.Unit
+// hashCode(): kotlin.Int
+// toString(): kotlin.String
+// class: SuperAbstract
+// <init>(): SuperAbstract
+// equals(kotlin.Any): kotlin.Boolean
+// foo(kotlin.String ...): kotlin.Unit
+// hashCode(): kotlin.Int
+// toString(): kotlin.String
+// EXPECTED:
+// END
+// FILE: a.kt
+data class Data(val a: String) {
+ override fun equals(other: Any?): Boolean {
+ return false
+ }
+}
+
+interface Super {
+ fun foo(vararg values: String)
+}
+
+interface Sub : Super
+
+class SubAbstract: SuperAbstract()
+
+abstract class SuperAbstract {
+ fun foo(vararg values: String) {
+
+ }
+}
+
diff --git a/test-utils/testData/api/allFunctions_kt_inherits_java.kt b/test-utils/testData/api/allFunctions_kt_inherits_java.kt
new file mode 100644
index 00000000..02000432
--- /dev/null
+++ b/test-utils/testData/api/allFunctions_kt_inherits_java.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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: AllFunctionsProcessor
+// EXPECTED:
+// class: C
+// aFromC
+// bFromC
+// cFromC
+// <init>(): C
+// equals(kotlin.Any): kotlin.Boolean
+// hashCode(): kotlin.Int
+// javaListFun(): kotlin.collections.MutableCollection
+// javaPrivateFun(): kotlin.Unit
+// javaStrFun(): kotlin.String
+// toString(): kotlin.String
+// class: Foo
+// aFromC
+// cFromC
+// size
+// <init>(): Foo
+// bar(): kotlin.Boolean
+// baz(kotlin.String,kotlin.String(hasDefault),kotlin.String(hasDefault)): kotlin.Boolean
+// contains(kotlin.Number): kotlin.Boolean
+// containsAll(kotlin.collections.Collection): kotlin.Boolean
+// equals(kotlin.Any): kotlin.Boolean
+// forEach(java.util.function.Consumer): kotlin.Unit
+// get(kotlin.Int): kotlin.Number
+// hashCode(): kotlin.Int
+// indexOf(kotlin.Number): kotlin.Int
+// isEmpty(): kotlin.Boolean
+// iterator(): kotlin.collections.Iterator
+// javaListFun(): kotlin.collections.List
+// javaStrFun(): kotlin.String
+// lastIndexOf(kotlin.Number): kotlin.Int
+// listIterator(): kotlin.collections.ListIterator
+// listIterator(kotlin.Int): kotlin.collections.ListIterator
+// parallelStream(): java.util.stream.Stream
+// spliterator(): java.util.Spliterator
+// stream(): java.util.stream.Stream
+// subList(kotlin.Int,kotlin.Int): kotlin.collections.List
+// toArray(java.util.function.IntFunction): kotlin.Array
+// toString(): kotlin.String
+// END
+// FILE: a.kt
+abstract class Foo : C(), List<out Number> {
+ override fun javaListFun(): List<Int> {
+ throw java.lang.IllegalStateException()
+ }
+
+ fun bar(): Boolean {
+ return false
+ }
+
+ fun baz(input: String, input2: String? = null, input3: String = ""): Boolean {
+ return false
+ }
+}
+
+// FILE: C.java
+import java.util.Collection;
+
+class C {
+ public int aFromC = 1;
+ private int bFromC = 2;
+ protected int cFromC = 3;
+ private void javaPrivateFun() {
+
+ }
+
+ protected Collection<Integer> javaListFun() {
+ return Arrays.asList(1,2,3)
+ }
+
+ public String javaStrFun() {
+ return "str"
+ }
+}
diff --git a/test-utils/testData/api/annotatedUtil.kt b/test-utils/testData/api/annotatedUtil.kt
new file mode 100644
index 00000000..bbd05785
--- /dev/null
+++ b/test-utils/testData/api/annotatedUtil.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: AnnotatedUtilProcessor
+// EXPECTED:
+// Test: OnlyTestAnnotation
+// Test: ParametersTestAnnotationWithValuesTest
+// IsPresent: class com.google.devtools.ksp.processor.ParametersTestAnnotation
+// ByType: com.google.devtools.ksp.processor.ParametersTestAnnotation[booleanValue=true, byteValue=5, shortValue=202, charValue=k, doubleValue=5.12, floatValue=123.3, intValue=2, longValue=4, stringValue=someValue, kClassValue=class java.lang.Throwable, enumValue=VALUE1]
+// Test: ParametersTestAnnotationWithDefaultsTest
+// IsPresent: class com.google.devtools.ksp.processor.ParametersTestAnnotation
+// ByType: com.google.devtools.ksp.processor.ParametersTestAnnotation[booleanValue=false, byteValue=2, shortValue=3, charValue=b, doubleValue=4.0, floatValue=5.0, intValue=6, longValue=7, stringValue=emptystring, kClassValue=interface com.google.devtools.ksp.processor.ParametersTestAnnotation, enumValue=NONE]
+// ByType: com.google.devtools.ksp.processor.ParametersTestAnnotation[booleanValue=false, byteValue=2, shortValue=3, charValue=b, doubleValue=4.0, floatValue=5.0, intValue=6, longValue=7, stringValue=emptystring, kClassValue=interface com.google.devtools.ksp.processor.ParametersTestAnnotation, enumValue=NONE]
+// Test: ParametersTestWithNegativeDefaultsAnnotationTest
+// IsPresent: class com.google.devtools.ksp.processor.ParametersTestWithNegativeDefaultsAnnotation
+// ByType: com.google.devtools.ksp.processor.ParametersTestWithNegativeDefaultsAnnotation[byteValue=-2, shortValue=-3, doubleValue=-4.0, floatValue=-5.0, intValue=-6, longValue=-7]
+// ByType: com.google.devtools.ksp.processor.ParametersTestWithNegativeDefaultsAnnotation[byteValue=-2, shortValue=-3, doubleValue=-4.0, floatValue=-5.0, intValue=-6, longValue=-7]
+// Test: ParameterArraysTestAnnotationWithDefaultTest
+// IsPresent: class com.google.devtools.ksp.processor.ParameterArraysTestAnnotation
+// ByType: ParameterArraysTestAnnotation[booleanArrayValue=[true, false],byteArrayValue=[-2, 4],shortArrayValue=[-1, 2, 3],charArrayValue=[a, b, c],doubleArrayValue=[1.1, 2.2, 3.3],floatArrayValue=[1.0, 2.0, 3.3],intArrayValue=[1, 2, 4, 8, 16],longArrayValue=[1, 2, 4, 8, 16, 32],stringArrayValue=[first, second, third],kClassArrayValue=[class kotlin.Throwable, class com.google.devtools.ksp.processor.ParametersTestAnnotation],enumArrayValue=[VALUE1, VALUE2, VALUE1, VALUE2]]
+// Test: AnnotationWithinAnAnnotationTest
+// IsPresent: class com.google.devtools.ksp.processor.OuterAnnotation
+// ByType: com.google.devtools.ksp.processor.OuterAnnotation[innerAnnotation=com.google.devtools.ksp.processor.InnerAnnotation[value=hello from the other side]]
+// END
+// MODULE: annotations
+// FILE: com/google/devtools/ksp/processor/a.kt
+package com.google.devtools.ksp.processor
+
+import kotlin.reflect.KClass
+import java.lang.Throwable
+
+annotation class Test
+
+@Suppress("LongParameterList")
+annotation class ParametersTestAnnotation(
+ val booleanValue: Boolean = false,
+ val byteValue: Byte = 2,
+ val shortValue: Short = 3,
+ val charValue: Char = 'b',
+ val doubleValue: Double = 4.0,
+ val floatValue: Float = 5.0f,
+ val intValue: Int = 6,
+ val longValue: Long = 7L,
+ val stringValue: String = "emptystring",
+ val kClassValue: KClass<*> = ParametersTestAnnotation::class,
+ val enumValue: TestEnum = TestEnum.NONE,
+)
+
+@Suppress("LongParameterList")
+annotation class ParameterArraysTestAnnotation(
+ val booleanArrayValue: BooleanArray = booleanArrayOf(),
+ val byteArrayValue: ByteArray = byteArrayOf(),
+ val shortArrayValue: ShortArray = shortArrayOf(),
+ val charArrayValue: CharArray = charArrayOf(),
+ val doubleArrayValue: DoubleArray = doubleArrayOf(),
+ val floatArrayValue: FloatArray = floatArrayOf(),
+ val intArrayValue: IntArray = intArrayOf(),
+ val longArrayValue: LongArray = longArrayOf(),
+ val stringArrayValue: Array<String> = emptyArray(),
+ val kClassArrayValue: Array<KClass<*>> = emptyArray(),
+ val enumArrayValue: Array<TestEnum> = emptyArray(),
+)
+
+annotation class ParametersTestWithNegativeDefaultsAnnotation(
+ val byteValue: Byte = -2,
+ val shortValue: Short = -3,
+ val doubleValue: Double = -4.0,
+ val floatValue: Float = -5.0f,
+ val intValue: Int = -6,
+ val longValue: Long = -7L,
+)
+
+enum class TestEnum {
+ NONE, VALUE1, VALUE2
+}
+
+annotation class InnerAnnotation(val value: String = "default")
+
+annotation class OuterAnnotation(
+ val innerAnnotation : InnerAnnotation = InnerAnnotation()
+)
+
+/////////////////////////////////////////////////////////
+// Tests
+/////////////////////////////////////////////////////////
+
+@Test
+@Test
+class OnlyTestAnnotation
+
+@ParametersTestAnnotation(
+ booleanValue = true,
+ byteValue = 5,
+ shortValue = 202,
+ charValue = 'k',
+ doubleValue = 5.12,
+ floatValue = 123.3f,
+ intValue = 2,
+ longValue = 4L,
+ stringValue = "someValue",
+ java.lang.Throwable::class,
+ TestEnum.VALUE1,
+)
+@Test
+class ParametersTestAnnotationWithValuesTest
+
+@ParametersTestAnnotation
+@ParametersTestAnnotation
+@Test
+class ParametersTestAnnotationWithDefaultsTest
+
+@ParametersTestWithNegativeDefaultsAnnotation
+@ParametersTestWithNegativeDefaultsAnnotation
+@Test
+class ParametersTestWithNegativeDefaultsAnnotationTest
+
+@ParameterArraysTestAnnotation(
+ booleanArrayValue = booleanArrayOf(true, false),
+ byteArrayValue = byteArrayOf(-2, 4),
+ shortArrayValue = shortArrayOf(-1, 2, 3),
+ charArrayValue = charArrayOf('a', 'b', 'c'),
+ doubleArrayValue = doubleArrayOf(1.1, 2.2, 3.3),
+ floatArrayValue = floatArrayOf(1.0f, 2.0f, 3.3f),
+ intArrayValue = intArrayOf(1, 2, 4, 8, 16),
+ longArrayValue = longArrayOf(1L, 2L, 4L, 8L, 16, 32L),
+ stringArrayValue = arrayOf("first", "second", "third"),
+ kClassArrayValue = arrayOf(Throwable::class, ParametersTestAnnotation::class),
+ enumArrayValue = arrayOf(TestEnum.VALUE1, TestEnum.VALUE2, TestEnum.VALUE1, TestEnum.VALUE2),
+)
+@Test
+class ParameterArraysTestAnnotationWithDefaultTest
+
+@OuterAnnotation(innerAnnotation = InnerAnnotation("hello from the other side"))
+@Test
+class AnnotationWithinAnAnnotationTest
diff --git a/test-utils/testData/api/annotationInDependencies.kt b/test-utils/testData/api/annotationInDependencies.kt
new file mode 100644
index 00000000..705bc560
--- /dev/null
+++ b/test-utils/testData/api/annotationInDependencies.kt
@@ -0,0 +1,202 @@
+/*
+ * 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: AnnotationsInDependenciesProcessor
+// EXPECTED:
+// main.KotlinClass ->
+// class main.KotlinClass : annotations.ClassTarget{[value = onClass]}
+// class main.KotlinClass : annotations.NoTargetAnnotation{[value = onClass]}
+// function myFun : annotations.FunctionTarget{[value = onMyFun]}
+// function myFun : annotations.NoTargetAnnotation{[value = onMyFun]}
+// getter of property prop : annotations.PropertyGetterTarget{[value = get:]}
+// parameter <set-?> : annotations.ValueParameterTarget{[value = onPropSetter]}
+// parameter <set-?> : annotations.ValueParameterTarget{[value = onProp]}
+// parameter param1 : annotations.NoTargetAnnotation{[value = onParam1]}
+// parameter param1 : annotations.ValueParameterTarget{[value = onParam1]}
+// parameter param2 : annotations.NoTargetAnnotation{[value = onParam2]}
+// parameter param2 : annotations.ValueParameterTarget{[value = onParam2]}
+// property prop : annotations.FieldTarget2{[value = field:]}
+// property prop : annotations.FieldTarget{[value = onProp]}
+// property prop : annotations.NoTargetAnnotation{[value = onProp]}
+// property prop : annotations.PropertyTarget{[value = onProp]}
+// setter of property prop : annotations.PropertySetterTarget{[value = set:]}
+// lib.KotlinClass ->
+// class lib.KotlinClass : annotations.ClassTarget{[value = onClass]}
+// class lib.KotlinClass : annotations.NoTargetAnnotation{[value = onClass]}
+// function myFun : annotations.FunctionTarget{[value = onMyFun]}
+// function myFun : annotations.NoTargetAnnotation{[value = onMyFun]}
+// getter of property prop : annotations.PropertyGetterTarget{[value = get:]}
+// parameter param1 : annotations.NoTargetAnnotation{[value = onParam1]}
+// parameter param1 : annotations.ValueParameterTarget{[value = onParam1]}
+// parameter param2 : annotations.NoTargetAnnotation{[value = onParam2]}
+// parameter param2 : annotations.ValueParameterTarget{[value = onParam2]}
+// parameter propInConstructor : annotations.ValueParameterTarget{[value = propInConstructor]}
+// property prop : annotations.FieldTarget2{[value = field:]}
+// property prop : annotations.FieldTarget{[value = onProp]}
+// property prop : annotations.NoTargetAnnotation{[value = onProp]}
+// property prop : annotations.PropertyTarget{[value = onProp]}
+// setter of property prop : annotations.PropertySetterTarget{[value = set:]}
+// main.DataClass ->
+// class main.DataClass : annotations.ClassTarget{[value = onDataClass]}
+// class main.DataClass : annotations.NoTargetAnnotation{[value = onDataClass]}
+// getter of property constructorParam : annotations.PropertyGetterTarget{[value = get:]}
+// parameter <set-?> : annotations.ValueParameterTarget{[value = onConstructorParam]}
+// parameter constructorParam : annotations.NoTargetAnnotation{[value = onConstructorParam]}
+// parameter constructorParam : annotations.ValueParameterTarget{[value = onConstructorParam]}
+// property constructorParam : annotations.FieldTarget2{[value = field:]}
+// property constructorParam : annotations.FieldTarget{[value = onConstructorParam]}
+// property constructorParam : annotations.NoTargetAnnotation{[value = onConstructorParam]}
+// property constructorParam : annotations.PropertyTarget{[value = onConstructorParam]}
+// property constructorParam : annotations.ValueParameterAndFieldTarget{[value = valueParameterAndField]}
+// setter of property constructorParam : annotations.PropertySetterTarget{[value = set:]}
+// lib.DataClass ->
+// class lib.DataClass : annotations.ClassTarget{[value = onDataClass]}
+// class lib.DataClass : annotations.NoTargetAnnotation{[value = onDataClass]}
+// getter of property constructorParam : annotations.PropertyGetterTarget{[value = get:]}
+// parameter constructorParam : annotations.NoTargetAnnotation{[value = onConstructorParam]}
+// property constructorParam : annotations.FieldTarget2{[value = field:]}
+// property constructorParam : annotations.FieldTarget{[value = onConstructorParam]}
+// property constructorParam : annotations.PropertyTarget{[value = onConstructorParam]}
+// setter of property constructorParam : annotations.PropertySetterTarget{[value = set:]}
+// END
+// MODULE: annotations
+// FILE: Annotations.kt
+package annotations;
+annotation class NoTargetAnnotation(val value:String)
+
+@Target(AnnotationTarget.FIELD)
+annotation class FieldTarget(val value:String)
+
+@Target(AnnotationTarget.FIELD)
+annotation class FieldTarget2(val value:String)
+
+@Target(AnnotationTarget.PROPERTY)
+annotation class PropertyTarget(val value:String)
+
+@Target(AnnotationTarget.PROPERTY_SETTER)
+annotation class PropertySetterTarget(val value:String)
+
+@Target(AnnotationTarget.PROPERTY_GETTER)
+annotation class PropertyGetterTarget(val value:String)
+
+@Target(AnnotationTarget.CLASS)
+annotation class ClassTarget(val value:String)
+
+@Target(AnnotationTarget.FUNCTION)
+annotation class FunctionTarget(val value:String)
+
+@Target(AnnotationTarget.VALUE_PARAMETER)
+annotation class ValueParameterTarget(val value:String)
+
+@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD)
+annotation class ValueParameterAndFieldTarget(val value: String)
+
+// MODULE: lib(annotations)
+// FILE: ClassInLib.kt
+package lib;
+import annotations.*;
+@NoTargetAnnotation("onClass")
+@ClassTarget("onClass")
+class KotlinClass(@ValueParameterTarget("propInConstructor") val propInConstructor: String ) {
+ @NoTargetAnnotation("onProp")
+ @FieldTarget("onProp")
+ @PropertyTarget("onProp")
+ @set:PropertySetterTarget("set:")
+ @get:PropertyGetterTarget("get:")
+ @field:FieldTarget2("field:")
+ var prop : String = ""
+
+ @NoTargetAnnotation("onMyFun")
+ @FunctionTarget("onMyFun")
+ fun myFun(
+ @NoTargetAnnotation("onParam1")
+ @ValueParameterTarget("onParam1")
+ param1: String,
+ @NoTargetAnnotation("onParam2")
+ @ValueParameterTarget("onParam2")
+ param2: Int
+ ) {
+ }
+}
+
+@NoTargetAnnotation("onDataClass")
+@ClassTarget("onDataClass")
+class DataClass(
+ @NoTargetAnnotation("onConstructorParam")
+ @FieldTarget("onConstructorParam")
+ @PropertyTarget("onConstructorParam")
+ @set:PropertySetterTarget("set:")
+ @get:PropertyGetterTarget("get:")
+ @field:FieldTarget2("field:")
+ var constructorParam : String = ""
+)
+// FILE: lib/JavaClass.java
+package lib;
+import annotations.*;
+public class JavaClass {}
+// MODULE: main(lib, annotations)
+// FILE: ClassInModule2.kt
+package main;
+import annotations.*;
+@NoTargetAnnotation("onClass")
+@ClassTarget("onClass")
+class KotlinClass {
+ @NoTargetAnnotation("onProp")
+ @FieldTarget("onProp")
+ @PropertyTarget("onProp")
+ @set:PropertySetterTarget("set:")
+ @get:PropertyGetterTarget("get:")
+ @field:FieldTarget2("field:")
+ @setparam:ValueParameterTarget("onProp")
+ var prop : String = ""
+ @setparam:ValueParameterTarget("onPropSetter")
+ set
+
+ @NoTargetAnnotation("onMyFun")
+ @FunctionTarget("onMyFun")
+ fun myFun(
+ @NoTargetAnnotation("onParam1")
+ @ValueParameterTarget("onParam1")
+ param1: String,
+ @NoTargetAnnotation("onParam2")
+ @ValueParameterTarget("onParam2")
+ param2: Int
+ ) {
+ }
+}
+
+@NoTargetAnnotation("onDataClass")
+@ClassTarget("onDataClass")
+class DataClass(
+ @NoTargetAnnotation("onConstructorParam")
+ @FieldTarget("onConstructorParam")
+ @PropertyTarget("onConstructorParam")
+ @set:PropertySetterTarget("set:")
+ @get:PropertyGetterTarget("get:")
+ @field:FieldTarget2("field:")
+ @field:ValueParameterAndFieldTarget("valueParameterAndField")
+ @setparam:ValueParameterTarget("onConstructorParam")
+ @ValueParameterTarget("onConstructorParam")
+ var constructorParam : String = ""
+)
+// FILE: main/JavaClassInModule2.java
+pakage main;
+import annotations.*;
+@NoTargetAnnotation
+class JavaClassInMain {
+}
diff --git a/test-utils/testData/api/annotationOnConstructorParameter.kt b/test-utils/testData/api/annotationOnConstructorParameter.kt
new file mode 100644
index 00000000..9122c287
--- /dev/null
+++ b/test-utils/testData/api/annotationOnConstructorParameter.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: AnnotationOnConstructorParameterProcessor
+// EXPECTED:
+// Anno
+// true
+// true
+// END
+//FILE: a.kt
+annotation class Anno
+
+data class Sample(
+ @Anno val fullName: String
+) {
+ fun foo() = 0
+}
diff --git a/test-utils/testData/api/annotationValue_java.kt b/test-utils/testData/api/annotationValue_java.kt
new file mode 100644
index 00000000..448ea5e0
--- /dev/null
+++ b/test-utils/testData/api/annotationValue_java.kt
@@ -0,0 +1,77 @@
+/*
+ * 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:
+// Str
+// 42
+// Foo
+// File
+// Error type synthetic declaration
+// Array
+// @Foo
+// @Suppress
+// G
+// ONE
+// 31
+// [warning1, warning 2]
+// END
+// FILE: a.kt
+
+enum class RGB {
+ R, G, B
+}
+
+annotation class Foo(val s: Int)
+
+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 argAnnoUser: Foo,
+ val argAnnoLib: Suppress,
+ val argEnum: RGB,
+ val argJavaNum: JavaEnum,
+ val argDef: Int = 31
+)
+
+// FILE: C.java
+
+@SuppressWarnings({"warning1", "warning 2"})
+class C {
+
+}
+// FILE: JavaAnnotated.java
+@Bar(argStr = "Str",
+ argInt = 40 + 2,
+ argClsUser = Foo.class,
+ argClsLib = java.io.File.class,
+ argClsLocal = Local.class, // intentional error type
+ argClsArray = kotlin.Array.class,
+ argAnnoUser = @Foo(s = 17),
+ argAnnoLib = @Suppress(names = {"name1", "name2"}),
+ argEnum = RGB.G,
+ argJavaNum = JavaEnum.ONE)
+public class JavaAnnotated {}
+
+// FILE: JavaEnum.java
+
+enum JavaEnum { ONE, TWO, THREE }
diff --git a/test-utils/testData/api/annotationValue_kt.kt b/test-utils/testData/api/annotationValue_kt.kt
new file mode 100644
index 00000000..28c28772
--- /dev/null
+++ b/test-utils/testData/api/annotationValue_kt.kt
@@ -0,0 +1,73 @@
+/*
+ * 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
+// Str
+// 42
+// Foo
+// File
+// Local
+// Array
+// @Foo
+// @Suppress
+// G
+// 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")
+}
+
+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 argAnnoUser: Foo,
+ val argAnnoLib: Suppress,
+ val argEnum: RGB,
+ val argJavaNum: JavaEnum,
+ val argDef: Int = 31
+)
+
+fun Fun() {
+ @Foo.Nested
+ @Bar("Str", 40 + 2, Foo::class, java.io.File::class, Local::class, Array<String>::class, Foo(17), Suppress("name1", "name2"), RGB.G, JavaEnum.ONE)
+ class Local
+}
+
+// FILE: JavaEnum.java
+
+enum JavaEnum { ONE, TWO, THREE }
diff --git a/test-utils/testData/api/annotationWithArbitraryClassValue.kt b/test-utils/testData/api/annotationWithArbitraryClassValue.kt
new file mode 100644
index 00000000..34e3fd2e
--- /dev/null
+++ b/test-utils/testData/api/annotationWithArbitraryClassValue.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// TEST PROCESSOR: AnnotationArbitraryClassValueProcessor
+// EXPECTED:
+// User
+// String, Company, IntArray, Array<User>
+// END
+// FILE: a.kt
+package com.google.devtools.ksp.processor
+
+import kotlin.reflect.KClass
+
+annotation class ClassValueAnnotation(
+ val classValue: KClass<*>,
+ val classValues: Array<KClass<*>>)
+
+data class User(val id: Long, val name: String)
+data class Company(val id: Long, val name: String, val location: String)
+
+@ClassValueAnnotation(
+ classValue = User::class,
+ classValues = [String::class, Company::class, IntArray::class, Array<User>::class]
+)
+class ClassValueAnnotated
diff --git a/test-utils/testData/api/annotationWithArrayValue.kt b/test-utils/testData/api/annotationWithArrayValue.kt
new file mode 100644
index 00000000..3637429f
--- /dev/null
+++ b/test-utils/testData/api/annotationWithArrayValue.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// TEST PROCESSOR: AnnotationArrayValueProcessor
+// EXPECTED:
+// KotlinAnnotated
+// KotlinAnnotation ->
+// stringArray = [a, b, null, c]
+// classArray = [Any, List<*>]
+// JavaAnnotation ->
+// stringArray = [x, y, null, z]
+// classArray = [String, Long]
+// JavaAnnotated
+// KotlinAnnotation ->
+// stringArray = [j-a, j-b, null, j-c]
+// classArray = [Object, List<*>]
+// JavaAnnotation ->
+// stringArray = [j-x, j-y, null, j-z]
+// classArray = [Integer, Character]
+// END
+// FILE: a.kt
+
+annotation class KotlinAnnotation(val stringArray: Array<String?>, val classArray: Array<KClass<*>?>)
+
+@KotlinAnnotation(
+ stringArray = ["a", "b", null, "c"],
+ classArray = [Any::class, List::class]
+)
+@JavaAnnotation(
+ stringArray = ["x", "y", null, "z"],
+ classArray = [String::class, Long::class]
+)
+class KotlinAnnotated
+
+// FILE: JavaAnnotation.java
+public @interface JavaAnnotation {
+ String[] stringArray();
+ Class[] classArray();
+}
+
+// FILE: JavaAnnotated.java
+import java.util.*;
+@KotlinAnnotation(
+ stringArray = {"j-a", "j-b", null, "j-c"},
+ classArray = {Object.class, List.class}
+)
+@JavaAnnotation(
+ stringArray = {"j-x", "j-y", null, "j-z"},
+ classArray = {Integer.class, Character.class}
+)
+public class JavaAnnotated {
+}
diff --git a/test-utils/testData/api/annotationWithDefault.kt b/test-utils/testData/api/annotationWithDefault.kt
new file mode 100644
index 00000000..ae2d0945
--- /dev/null
+++ b/test-utils/testData/api/annotationWithDefault.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: AnnotationDefaultValueProcessor
+// EXPECTED:
+// KotlinAnnotation -> a:debugKt:false,b:default:true,kClassValue:Array<Array<InnerObj>>:true,topLevelProp:foo:true,companionProp:companion:true
+// JavaAnnotation -> debug:debug:false,withDefaultValue:OK:true,nested:@Nested:true
+// JavaAnnotation2 -> y:y-kotlin:false,x:x-kotlin:false,z:z-default:true
+// KotlinAnnotation2 -> y:y-kotlin:false,x:x-kotlin:false,z:z-default:true,kotlinEnumVal:VALUE_1:true
+// KotlinAnnotationLib -> a:debugLibKt:false,b:defaultInLib:true,kClassValue:OtherKotlinAnnotation:true,topLevelProp:bar:true
+// JavaAnnotationWithDefaults -> stringVal:foo:true,stringArrayVal:[x, y]:true,typeVal:HashMap<*, *>:true,typeArrayVal:[LinkedHashMap<*, *>]:true,intVal:3:true,intArrayVal:[1, 3, 5]:true,enumVal:JavaEnum.DEFAULT:true,enumArrayVal:[JavaEnum.VAL1, JavaEnum.VAL2]:true,localEnumVal:JavaAnnotationWithDefaults.LocalEnum.LOCAL1:true,otherAnnotationVal:@OtherAnnotation:true,otherAnnotationArrayVal:[@OtherAnnotation]:true,kotlinAnnotationLibVal:@OtherKotlinAnnotation:true
+// KotlinAnnotationWithDefaults -> stringVal:foo:false,stringArrayVal:[x, y]:true,typeVal:HashMap<*, *>:true,typeArrayVal:[LinkedHashMap<*, *>]:true,intVal:3:true,intArrayVal:[1, 3, 5]:true,enumVal:JavaEnum.DEFAULT:true,enumArrayVal:[JavaEnum.VAL1, JavaEnum.VAL2]:true,otherAnnotationVal:@OtherAnnotation:true,otherAnnotationArrayVal:[@OtherAnnotation]:true,kotlinAnnotationLibVal:@OtherKotlinAnnotation:true
+// KotlinAnnotation -> a:debugKt:false,b:default:true,kClassValue:Array<Array<InnerObj>>:true,topLevelProp:foo:true,companionProp:companion:true
+// JavaAnnotation -> debug:debugJava2:false,withDefaultValue:OK:true,nested:@Nested:true
+// JavaAnnotation2 -> y:y-java:false,x:x-java:false,z:z-default:true
+// KotlinAnnotation2 -> y:y-java:false,x:x-java:false,z:z-default:true,kotlinEnumVal:VALUE_1:true
+// END
+// MODULE: lib
+// FILE: Default.kt
+const val Bar = "bar"
+annotation class KotlinAnnotationLib(val a: String, val b: String = "defaultInLib", val kClassValue: kotlin.reflect.KClass<*> = OtherKotlinAnnotation::class, val topLevelProp:String = Bar)
+
+annotation class OtherKotlinAnnotation(val b: String = "otherKotlinAnnotationDefault")
+
+// FILE: JavaEnum.java
+public enum JavaEnum {
+ VAL1,
+ VAL2,
+ DEFAULT
+}
+
+// FILE: OtherAnnotation.java
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+@Retention(RetentionPolicy.RUNTIME)
+public @interface OtherAnnotation {
+ String value();
+}
+
+// FILE: JavaAnnotationWithDefaults.java
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+public @interface JavaAnnotationWithDefaults {
+ String stringVal() default "foo";
+ String[] stringArrayVal() default {"x", "y"};
+ Class<?> typeVal() default HashMap.class;
+ Class[] typeArrayVal() default {LinkedHashMap.class};
+ int intVal() default 3;
+ int[] intArrayVal() default {1, 3, 5};
+ JavaEnum enumVal() default JavaEnum.DEFAULT;
+ JavaEnum[] enumArrayVal() default {JavaEnum.VAL1, JavaEnum.VAL2};
+ LocalEnum localEnumVal() default LocalEnum.LOCAL1;
+ OtherAnnotation otherAnnotationVal() default @OtherAnnotation("def");
+ OtherAnnotation[] otherAnnotationArrayVal() default {@OtherAnnotation("v1")};
+ OtherKotlinAnnotation kotlinAnnotationLibVal() default @OtherKotlinAnnotation(b = "JavaAnnotationWithDefaults");
+ enum LocalEnum {
+ LOCAL1,
+ LOCAL2
+ }
+}
+
+// FILE: KotlinAnnotationWithDefaults.kt
+import kotlin.reflect.KClass
+
+annotation class KotlinAnnotationWithDefaults(
+ val stringVal: String = "foo",
+ val stringArrayVal: Array<String> = ["x", "y"],
+ val typeVal: KClass<*> = java.util.HashMap::class,
+ val typeArrayVal: Array<KClass<*>> = [java.util.LinkedHashMap::class],
+ val intVal: Int = 3,
+ val intArrayVal: IntArray = [1, 3, 5],
+ val enumVal: JavaEnum = JavaEnum.DEFAULT,
+ val enumArrayVal: Array<JavaEnum> = [JavaEnum.VAL1, JavaEnum.VAL2],
+ val otherAnnotationVal: OtherAnnotation = OtherAnnotation("def"),
+ val otherAnnotationArrayVal: Array<OtherAnnotation> = [OtherAnnotation("v1")],
+ val kotlinAnnotationLibVal: OtherKotlinAnnotation = OtherKotlinAnnotation("1")
+)
+// MODULE: main(lib)
+// FILE: Const.kt
+const val Foo = "foo"
+const val DebugKt = "debugKt"
+
+class Container {
+ companion object {
+ const val comp = "companion"
+ }
+}
+
+// FILE: a.kt
+import test.KotlinEnum
+import Container.Companion.comp
+
+
+annotation class KotlinAnnotation(val a: String, val b:String = "default", val kClassValue: kotlin.reflect.KClass<*> = Array<Array<InnerObj>>::class, val topLevelProp: String = Foo, val companionProp: String = comp) {
+ object InnerObj
+}
+annotation class KotlinAnnotation2(val x: String, val y:String = "y-default", val z:String = "z-default", val kotlinEnumVal: KotlinEnum = KotlinEnum.VALUE_1)
+
+@KotlinAnnotation(DebugKt)
+@JavaAnnotation("debug")
+@JavaAnnotation2(y="y-kotlin", x="x-kotlin")
+@KotlinAnnotation2(y="y-kotlin", x="x-kotlin")
+@KotlinAnnotationLib("debugLibKt")
+@JavaAnnotationWithDefaults
+@KotlinAnnotationWithDefaults(stringVal="foo") //set the value to the same as the default
+class A
+
+// FILE: test.kt
+package test
+
+enum class KotlinEnum {
+ VALUE_1,
+ VALUE2
+}
+
+// FILE: JavaAnnotation.java
+public @interface JavaAnnotation {
+ String debug();
+ String withDefaultValue() default "OK";
+ @interface Nested {
+ String nestedX() default "nested";
+ }
+ Nested nested() default @Nested();
+}
+
+// FILE: JavaAnnotation2.java
+public @interface JavaAnnotation2 {
+ String x() default "x-default";
+ String y() default "y-default";
+ String z() default "z-default";
+}
+
+// FILE: JavaAnnotated.java
+
+@KotlinAnnotation(ConstKt.DebugKt)
+@JavaAnnotation("debugJava2")
+@JavaAnnotation2(y="y-java", x="x-java")
+@KotlinAnnotation2(y="y-java", x="x-java")
+public class JavaAnnotated {
+
+}
diff --git a/test-utils/testData/api/annotationWithDefaultValues.kt b/test-utils/testData/api/annotationWithDefaultValues.kt
new file mode 100644
index 00000000..94a21dae
--- /dev/null
+++ b/test-utils/testData/api/annotationWithDefaultValues.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: AnnotationDefaultValuesProcessor
+// EXPECTED:
+// KotlinAnnotation -> b:default,kClassValue:Array<Array<InnerObj>>,topLevelProp:foo,companionProp:companion
+// JavaAnnotation -> withDefaultValue:OK,nested:@Nested
+// JavaAnnotation2 -> x:x-default,y:y-default,z:z-default
+// KotlinAnnotation2 -> y:y-default,z:z-default,kotlinEnumVal:VALUE_1
+// KotlinAnnotationLib -> b:defaultInLib,kClassValue:OtherKotlinAnnotation,topLevelProp:bar
+// JavaAnnotationWithDefaults -> stringVal:foo,stringArrayVal:[x, y],typeVal:HashMap<*, *>,typeArrayVal:[LinkedHashMap<*, *>],intVal:3,intArrayVal:[1, 3, 5],enumVal:JavaEnum.DEFAULT,enumArrayVal:[JavaEnum.VAL1, JavaEnum.VAL2],localEnumVal:JavaAnnotationWithDefaults.LocalEnum.LOCAL1,otherAnnotationVal:@OtherAnnotation,otherAnnotationArrayVal:[@OtherAnnotation],kotlinAnnotationLibVal:@OtherKotlinAnnotation
+// KotlinAnnotationWithDefaults -> stringVal:foo,stringArrayVal:[x, y],typeVal:HashMap<*, *>,typeArrayVal:[LinkedHashMap<*, *>],intVal:3,intArrayVal:[1, 3, 5],enumVal:JavaEnum.DEFAULT,enumArrayVal:[JavaEnum.VAL1, JavaEnum.VAL2],otherAnnotationVal:@OtherAnnotation,otherAnnotationArrayVal:[@OtherAnnotation],kotlinAnnotationLibVal:@OtherKotlinAnnotation
+// KotlinAnnotation -> b:default,kClassValue:Array<Array<InnerObj>>,topLevelProp:foo,companionProp:companion
+// JavaAnnotation -> withDefaultValue:OK,nested:@Nested
+// JavaAnnotation2 -> x:x-default,y:y-default,z:z-default
+// KotlinAnnotation2 -> y:y-default,z:z-default,kotlinEnumVal:VALUE_1
+// END
+// MODULE: lib
+// FILE: Default.kt
+const val Bar = "bar"
+annotation class KotlinAnnotationLib(val a: String, val b: String = "defaultInLib", val kClassValue: kotlin.reflect.KClass<*> = OtherKotlinAnnotation::class, val topLevelProp:String = Bar)
+
+annotation class OtherKotlinAnnotation(val b: String = "otherKotlinAnnotationDefault")
+
+// FILE: JavaEnum.java
+public enum JavaEnum {
+ VAL1,
+ VAL2,
+ DEFAULT
+}
+
+// FILE: OtherAnnotation.java
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+@Retention(RetentionPolicy.RUNTIME)
+public @interface OtherAnnotation {
+ String value();
+}
+
+// FILE: JavaAnnotationWithDefaults.java
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+public @interface JavaAnnotationWithDefaults {
+ String stringVal() default "foo";
+ String[] stringArrayVal() default {"x", "y"};
+ Class<?> typeVal() default HashMap.class;
+ Class[] typeArrayVal() default {LinkedHashMap.class};
+ int intVal() default 3;
+ int[] intArrayVal() default {1, 3, 5};
+ JavaEnum enumVal() default JavaEnum.DEFAULT;
+ JavaEnum[] enumArrayVal() default {JavaEnum.VAL1, JavaEnum.VAL2};
+ LocalEnum localEnumVal() default LocalEnum.LOCAL1;
+ OtherAnnotation otherAnnotationVal() default @OtherAnnotation("def");
+ OtherAnnotation[] otherAnnotationArrayVal() default {@OtherAnnotation("v1")};
+ OtherKotlinAnnotation kotlinAnnotationLibVal() default @OtherKotlinAnnotation(b = "JavaAnnotationWithDefaults");
+ enum LocalEnum {
+ LOCAL1,
+ LOCAL2
+ }
+}
+
+// FILE: KotlinAnnotationWithDefaults.kt
+import kotlin.reflect.KClass
+
+annotation class KotlinAnnotationWithDefaults(
+ val stringVal: String = "foo",
+ val stringArrayVal: Array<String> = ["x", "y"],
+ val typeVal: KClass<*> = java.util.HashMap::class,
+ val typeArrayVal: Array<KClass<*>> = [java.util.LinkedHashMap::class],
+ val intVal: Int = 3,
+ val intArrayVal: IntArray = [1, 3, 5],
+ val enumVal: JavaEnum = JavaEnum.DEFAULT,
+ val enumArrayVal: Array<JavaEnum> = [JavaEnum.VAL1, JavaEnum.VAL2],
+ val otherAnnotationVal: OtherAnnotation = OtherAnnotation("def"),
+ val otherAnnotationArrayVal: Array<OtherAnnotation> = [OtherAnnotation("v1")],
+ val kotlinAnnotationLibVal: OtherKotlinAnnotation = OtherKotlinAnnotation("1")
+)
+// MODULE: main(lib)
+// FILE: Const.kt
+const val Foo = "foo"
+const val DebugKt = "debugKt"
+
+class Container {
+ companion object {
+ const val comp = "companion"
+ }
+}
+
+// FILE: a.kt
+import test.KotlinEnum
+import Container.Companion.comp
+
+
+annotation class KotlinAnnotation(val a: String, val b:String = "default", val kClassValue: kotlin.reflect.KClass<*> = Array<Array<InnerObj>>::class, val topLevelProp: String = Foo, val companionProp: String = comp) {
+ object InnerObj
+}
+annotation class KotlinAnnotation2(val x: String, val y:String = "y-default", val z:String = "z-default", val kotlinEnumVal: KotlinEnum = KotlinEnum.VALUE_1)
+
+@KotlinAnnotation(DebugKt)
+@JavaAnnotation("debug")
+@JavaAnnotation2(y="y-kotlin", x="x-kotlin")
+@KotlinAnnotation2(y="y-kotlin", x="x-kotlin")
+@KotlinAnnotationLib("debugLibKt")
+@JavaAnnotationWithDefaults
+@KotlinAnnotationWithDefaults
+class A
+
+// FILE: test.kt
+package test
+
+enum class KotlinEnum {
+ VALUE_1,
+ VALUE2
+}
+
+// FILE: JavaAnnotation.java
+public @interface JavaAnnotation {
+ String debug();
+ String withDefaultValue() default "OK";
+ @interface Nested {
+ String nestedX() default "nested";
+ }
+ Nested nested() default @Nested();
+}
+
+// FILE: JavaAnnotation2.java
+public @interface JavaAnnotation2 {
+ String x() default "x-default";
+ String y() default "y-default";
+ String z() default "z-default";
+}
+
+// FILE: JavaAnnotated.java
+
+@KotlinAnnotation(ConstKt.DebugKt)
+@JavaAnnotation("debugJava2")
+@JavaAnnotation2(y="y-java", x="x-java")
+@KotlinAnnotation2(y="y-java", x="x-java")
+public class JavaAnnotated {
+
+}
diff --git a/test-utils/testData/api/annotationWithJavaTypeValue.kt b/test-utils/testData/api/annotationWithJavaTypeValue.kt
new file mode 100644
index 00000000..98610371
--- /dev/null
+++ b/test-utils/testData/api/annotationWithJavaTypeValue.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// TEST PROCESSOR: AnnotationJavaTypeValueProcessor
+// EXPECTED:
+// JavaAnnotated
+// JavaAnnotation ->
+// primitives = [Character, Boolean, Byte, Short, Integer, Long, Float, Double]
+// objects = [Character, Boolean, Byte, Short, Integer, Long, Float, Double]
+// primitiveArrays = [Array<Character>, Array<Boolean>, Array<Byte>, Array<Short>, Array<Integer>, Array<Long>, Array<Float>, Array<Double>]
+// objectArrays = [Array<Character>, Array<Boolean>, Array<Byte>, Array<Short>, Array<Integer>, Array<Long>, Array<Float>, Array<Double>, Array<String>, Array<Object>]
+// END
+// FILE: a.kt
+
+
+// FILE: JavaAnnotation.java
+
+public @ interface JavaAnnotation {
+ Class[] primitives(); // PsiPrimitiveType
+ Class[] objects(); // PsiType
+ Class[] primitiveArrays(); // PsiArrayType
+ Class[] objectArrays(); // PsiArrayType
+}
+
+// FILE: JavaAnnotated.java
+
+import java.util.*;
+
+@JavaAnnotation(
+ primitives = { char.class, boolean .class, byte.class, short.class, int.class, long.class, float.class, double.class },
+ objects = { Character.class, Boolean .class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class },
+ primitiveArrays = { char[].class, boolean [].class, byte[].class, short[].class, int[].class, long[].class, float[].class, double[].class },
+ objectArrays = { Character[].class, Boolean [].class, Byte[].class, Short[].class, Integer[].class, Long[].class, Float[].class, Double[].class, String[].class, Object[].class }
+)
+public class JavaAnnotated {
+}
diff --git a/test-utils/testData/api/asMemberOf.kt b/test-utils/testData/api/asMemberOf.kt
new file mode 100644
index 00000000..d96346cc
--- /dev/null
+++ b/test-utils/testData/api/asMemberOf.kt
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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: AsMemberOfProcessor
+// EXPECTED:
+// Child1!!
+// intType: kotlin.Int!!
+// baseTypeArg1: kotlin.Int!!
+// baseTypeArg2: kotlin.String?
+// typePair: kotlin.Pair!!<kotlin.String?, kotlin.Int!!>
+// errorType: <Error>?
+// extensionProperty: kotlin.String?
+// returnInt: () -> kotlin.Int!!
+// returnArg1: () -> kotlin.Int!!
+// returnArg1Nullable: () -> kotlin.Int?
+// returnArg2: () -> kotlin.String?
+// returnArg2Nullable: () -> kotlin.String?
+// receiveArgs: (kotlin.Int?, kotlin.Int!!, kotlin.String?) -> kotlin.Unit!!
+// receiveArgsPair: (kotlin.Pair!!<kotlin.Int!!, kotlin.String?>, kotlin.Pair?<kotlin.Int?, kotlin.String?>) -> kotlin.Unit!!
+// functionArgType: <BaseTypeArg1: kotlin.Any?>(Base.functionArgType.BaseTypeArg1?) -> kotlin.String?
+// functionArgTypeWithBounds: <in T: kotlin.Int!!>(Base.functionArgTypeWithBounds.T?) -> kotlin.String?
+// extensionFunction: kotlin.Int!!.() -> kotlin.Int?
+// Child2!!<kotlin.Any?>
+// intType: kotlin.Int!!
+// baseTypeArg1: kotlin.Any?
+// baseTypeArg2: kotlin.Any?
+// typePair: kotlin.Pair!!<kotlin.Any?, kotlin.Any?>
+// errorType: <Error>?
+// extensionProperty: kotlin.Any?
+// returnInt: () -> kotlin.Int!!
+// returnArg1: () -> kotlin.Any?
+// returnArg1Nullable: () -> kotlin.Any?
+// returnArg2: () -> kotlin.Any?
+// returnArg2Nullable: () -> kotlin.Any?
+// receiveArgs: (kotlin.Int?, kotlin.Any?, kotlin.Any?) -> kotlin.Unit!!
+// receiveArgsPair: (kotlin.Pair!!<kotlin.Any?, kotlin.Any?>, kotlin.Pair?<kotlin.Any?, kotlin.Any?>) -> kotlin.Unit!!
+// functionArgType: <BaseTypeArg1: kotlin.Any?>(Base.functionArgType.BaseTypeArg1?) -> kotlin.Any?
+// functionArgTypeWithBounds: <in T: kotlin.Any?>(Base.functionArgTypeWithBounds.T?) -> kotlin.Any?
+// extensionFunction: kotlin.Any?.() -> kotlin.Any?
+// Child2!!<kotlin.String!!>
+// intType: kotlin.Int!!
+// baseTypeArg1: kotlin.String!!
+// baseTypeArg2: kotlin.String?
+// typePair: kotlin.Pair!!<kotlin.String?, kotlin.String!!>
+// errorType: <Error>?
+// extensionProperty: kotlin.String?
+// returnInt: () -> kotlin.Int!!
+// returnArg1: () -> kotlin.String!!
+// returnArg1Nullable: () -> kotlin.String?
+// returnArg2: () -> kotlin.String?
+// returnArg2Nullable: () -> kotlin.String?
+// receiveArgs: (kotlin.Int?, kotlin.String!!, kotlin.String?) -> kotlin.Unit!!
+// receiveArgsPair: (kotlin.Pair!!<kotlin.String!!, kotlin.String?>, kotlin.Pair?<kotlin.String?, kotlin.String?>) -> kotlin.Unit!!
+// functionArgType: <BaseTypeArg1: kotlin.Any?>(Base.functionArgType.BaseTypeArg1?) -> kotlin.String?
+// functionArgTypeWithBounds: <in T: kotlin.String!!>(Base.functionArgTypeWithBounds.T?) -> kotlin.String?
+// extensionFunction: kotlin.String!!.() -> kotlin.String?
+// NotAChild!!
+// intType: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `intType` (Base)
+// baseTypeArg1: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `baseTypeArg1` (Base)
+// baseTypeArg2: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `baseTypeArg2` (Base)
+// typePair: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `typePair` (Base)
+// errorType: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `errorType` (Base)
+// extensionProperty: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `extensionProperty` (Base)
+// returnInt: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `returnInt` (Base)
+// returnArg1: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `returnArg1` (Base)
+// returnArg1Nullable: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `returnArg1Nullable` (Base)
+// returnArg2: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `returnArg2` (Base)
+// returnArg2Nullable: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `returnArg2Nullable` (Base)
+// receiveArgs: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `receiveArgs` (Base)
+// receiveArgsPair: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `receiveArgsPair` (Base)
+// functionArgType: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `functionArgType` (Base)
+// functionArgTypeWithBounds: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `functionArgTypeWithBounds` (Base)
+// extensionFunction: java.lang.IllegalArgumentException: NotAChild is not a sub type of the class/interface that contains `extensionFunction` (Base)
+// List#get
+// listOfStrings: (kotlin.Int!!) -> kotlin.String!!
+// setOfStrings: java.lang.IllegalArgumentException: Set<String> is not a sub type of the class/interface that contains `get` (List)
+// Set#contains
+// listOfStrings: java.lang.IllegalArgumentException: List<String> is not a sub type of the class/interface that contains `contains` (Set)
+// setOfStrings: (kotlin.String!!) -> kotlin.Boolean!!
+// JavaChild1!!
+// intType: kotlin.Int!!
+// typeArg1: kotlin.String
+// typeArg2: kotlin.Int
+// errorType: <Error>?
+// returnArg1: () -> kotlin.Int
+// receiveArgs: (kotlin.String, kotlin.Int, kotlin.Int!!) -> kotlin.Unit!!
+// methodArgType: <BaseTypeArg1: kotlin.Any>(JavaBase.methodArgType.BaseTypeArg1, kotlin.Int) -> kotlin.Unit!!
+// methodArgTypeWithBounds: <T: kotlin.String>(JavaBase.methodArgTypeWithBounds.T) -> kotlin.Unit!!
+// 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: (<Error>?) -> <Error>?
+// expected comparison failures
+// <BaseTypeArg1: kotlin.Any?>(Base.functionArgType.BaseTypeArg1?) -> kotlin.String?
+// () -> kotlin.Int!!
+// () -> kotlin.Int!!
+// (kotlin.Int!!) -> kotlin.Unit!!
+// END
+// FILE: Input.kt
+open class Base<BaseTypeArg1, BaseTypeArg2> {
+ val intType: Int = 0
+ val baseTypeArg1: BaseTypeArg1 = TODO()
+ val baseTypeArg2: BaseTypeArg2 = TODO()
+ val typePair: Pair<BaseTypeArg2, BaseTypeArg1> = TODO()
+ val errorType: NonExistType = TODO()
+ fun returnInt():Int = TODO()
+ fun returnArg1(): BaseTypeArg1 = TODO()
+ fun returnArg1Nullable(): BaseTypeArg1? = TODO()
+ fun returnArg2(): BaseTypeArg2 = TODO()
+ fun returnArg2Nullable(): BaseTypeArg2? = TODO()
+ fun receiveArgs(intArg:Int?, arg1: BaseTypeArg1, arg2:BaseTypeArg2):Unit = TODO()
+ fun receiveArgsPair(
+ pairs: Pair<BaseTypeArg1, BaseTypeArg2>,
+ pairNullable: Pair<BaseTypeArg1?, BaseTypeArg2?>?,
+ ):Unit = TODO()
+ // intentional type argument name conflict here to ensure it does not get replaced by mistake
+ fun <BaseTypeArg1> functionArgType(t:BaseTypeArg1?): BaseTypeArg2 = TODO()
+ fun <in T: BaseTypeArg1> functionArgTypeWithBounds(t:T?): BaseTypeArg2 = TODO()
+ fun BaseTypeArg1.extensionFunction():BaseTypeArg1? = TODO()
+ val BaseTypeArg2.extensionProperty:BaseTypeArg2? = TODO()
+}
+
+open class Child1 : Base<Int, String?>() {
+}
+
+open class Child2<ChildTypeArg1> : Base<ChildTypeArg1, ChildTypeArg1?>() {
+}
+
+class NotAChild
+val child2WithString: Child2<String> = TODO()
+val listOfStrings: List<String> = TODO()
+val setOfStrings: Set<String> = TODO()
+
+fun <T>List<T>.fileLevelExtensionFunction():Unit = TODO()
+fun <T>fileLevelFunction():Unit = TODO()
+val fileLevelProperty:Int = 3
+val errorType: NonExistingType
+
+interface KotlinInterface {
+ val x:Int
+ var y:Int
+}
+
+// FILE: JavaInput.java
+class JavaBase<BaseTypeArg1, BaseTypeArg2> {
+ int intType;
+ BaseTypeArg1 typeArg1;
+ BaseTypeArg2 typeArg2;
+ NonExist errorType;
+ BaseTypeArg2 returnArg1() {
+ return null;
+ }
+ void receiveArgs(BaseTypeArg1 arg1, BaseTypeArg2 arg2, int intArg) {
+ }
+ <BaseTypeArg1> void methodArgType(BaseTypeArg1 arg1, BaseTypeArg2 arg2) {
+ }
+ <T extends BaseTypeArg1> void methodArgTypeWithBounds(T arg1) {
+ }
+}
+
+class JavaChild1 extends JavaBase<String, Integer> {
+}
+
+class JavaImpl implements KotlinInterface {
+ public int getX() {
+ return 1;
+ }
+ public int getY() {
+ return 1;
+ }
+ public void setY(int value) {
+ }
+}
diff --git a/test-utils/testData/api/backingFields.kt b/test-utils/testData/api/backingFields.kt
new file mode 100644
index 00000000..30a681de
--- /dev/null
+++ b/test-utils/testData/api/backingFields.kt
@@ -0,0 +1,364 @@
+/*
+ * Copyright 2021 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: BackingFieldProcessor
+// EXPECTED:
+// lib.BaseClass.abstractProp_willBeBacked: false
+// lib.BaseClass.abstractProp_wontBeBacked: false
+// lib.BaseClass.lateinit_var_1: true
+// lib.BaseClass.lateinit_var_2: true
+// lib.BaseClass.notOverriddenAbstractProp: true
+// lib.BaseClass.overriddenBaseProp_willBeBacked: true
+// lib.BaseClass.overriddenBaseProp_wontBeBacked: true
+// lib.ChildClass.abstractProp_willBeBacked: true
+// lib.ChildClass.abstractProp_wontBeBacked: false
+// lib.ChildClass.interfaceProp_willBeBacked: true
+// lib.ChildClass.interfaceProp_wontBeBacked: false
+// lib.ChildClass.lateinit_var_1: false
+// lib.ChildClass.lateinit_var_2: true
+// lib.ChildClass.lateinit_var_3: true
+// lib.ChildClass.overriddenBaseProp_willBeBacked: true
+// lib.ChildClass.overriddenBaseProp_wontBeBacked: false
+// lib.ConstructorSetProp.propSetInConstructor: true
+// lib.DataClass.value_Param: true
+// lib.DataClass.variable_Param: true
+// lib.JavaClass.javaField: true
+// lib.JavaClass.javaFieldWithAccessors: true
+// lib.MyInterface.interfaceProp_willBeBacked: false
+// lib.MyInterface.interfaceProp_wontBeBacked: false
+// lib.MyInterface.lateinit_var_3: false
+// lib.NormalClass.Companion.companionVar: true
+// lib.NormalClass.Companion.companion_noBackingVal: false
+// lib.NormalClass.Companion.companion_noBackingVar: false
+// lib.NormalClass.Companion.companion_withBackingAndGetter: true
+// lib.NormalClass.Companion.staticVar: true
+// lib.NormalClass.Companion.static_noBackingVal: false
+// lib.NormalClass.Companion.static_noBackingVar: false
+// lib.NormalClass.Companion.static_withBackingAndGetter: true
+// lib.NormalClass.jvmField_withBacking: true
+// lib.NormalClass.lateinit_var: true
+// lib.NormalClass.value: true
+// lib.NormalClass.value_Param: true
+// lib.NormalClass.value_noBacking: false
+// lib.NormalClass.value_withBacking: true
+// lib.NormalClass.variable: true
+// lib.NormalClass.variable_Param: true
+// lib.NormalClass.variable_noBacking: false
+// lib.NormalClass.variable_withBacking: true
+// lib.lateinit_var: true
+// lib.value: true
+// lib.value_noBacking: false
+// lib.value_withBacking: true
+// lib.variable: true
+// lib.variable_noBacking: false
+// lib.variable_withBacking: true
+// main.BaseClass.abstractProp_willBeBacked: false
+// main.BaseClass.abstractProp_wontBeBacked: false
+// main.BaseClass.lateinit_var_1: true
+// main.BaseClass.lateinit_var_2: true
+// main.BaseClass.notOverriddenAbstractProp: true
+// main.BaseClass.overriddenBaseProp_willBeBacked: true
+// main.BaseClass.overriddenBaseProp_wontBeBacked: true
+// main.ChildClass.abstractProp_willBeBacked: true
+// main.ChildClass.abstractProp_wontBeBacked: false
+// main.ChildClass.interfaceProp_willBeBacked: true
+// main.ChildClass.interfaceProp_wontBeBacked: false
+// main.ChildClass.lateinit_var_1: false
+// main.ChildClass.lateinit_var_2: true
+// main.ChildClass.lateinit_var_3: true
+// main.ChildClass.overriddenBaseProp_willBeBacked: true
+// main.ChildClass.overriddenBaseProp_wontBeBacked: false
+// main.ConstructorSetProp.propSetInConstructor: true
+// main.DataClass.value_Param: true
+// main.DataClass.variable_Param: true
+// main.JavaClass.javaField: true
+// main.JavaClass.javaFieldWithAccessors: true
+// main.MyInterface.interfaceProp_willBeBacked: false
+// main.MyInterface.interfaceProp_wontBeBacked: false
+// main.MyInterface.lateinit_var_3: false
+// main.NormalClass.Companion.companionVar: true
+// main.NormalClass.Companion.companion_noBackingVal: false
+// main.NormalClass.Companion.companion_noBackingVar: false
+// main.NormalClass.Companion.companion_withBackingAndGetter: true
+// main.NormalClass.Companion.staticVar: true
+// main.NormalClass.Companion.static_noBackingVal: false
+// main.NormalClass.Companion.static_noBackingVar: false
+// main.NormalClass.Companion.static_withBackingAndGetter: true
+// main.NormalClass.lateinit_var: true
+// main.NormalClass.value: true
+// main.NormalClass.value_Param: true
+// main.NormalClass.value_noBacking: false
+// main.NormalClass.value_withBacking: true
+// main.NormalClass.variable: true
+// main.NormalClass.variable_Param: true
+// main.NormalClass.variable_noBacking: false
+// main.NormalClass.variable_withBacking: true
+// main.lateinit_var: true
+// main.value: true
+// main.value_noBacking: false
+// main.value_withBacking: true
+// main.variable: true
+// main.variable_noBacking: false
+// main.variable_withBacking: true
+// END
+
+// MODULE: lib
+// FILE: lib.kt
+package lib
+
+val value: String = ""
+var variable: String = ""
+val value_noBacking: String
+ get() = "aa"
+var variable_noBacking: String
+ get() = "aa"
+ set(value) {}
+val value_withBacking: String = ""
+ get() = field
+var variable_withBacking: String? = null
+ get() = field
+lateinit var lateinit_var: String
+
+data class DataClass(
+ val value_Param: String,
+ var variable_Param: String
+)
+
+class NormalClass(
+ val value_Param: String,
+ var variable_Param: String,
+ normalParam: String
+) {
+ val value: String = ""
+ var variable: String = ""
+ val value_noBacking: String
+ get() = "aa"
+ var variable_noBacking: String
+ get() = "aa"
+ set(value) {}
+ val value_withBacking: String = ""
+ get() = field
+ var variable_withBacking: String? = null
+ get() = field
+ val jvmField_withBacking: String = ""
+ lateinit var lateinit_var: String
+
+ companion object {
+ @JvmStatic
+ var staticVar: String = ""
+ @JvmStatic
+ val static_withBackingAndGetter: String = ""
+ get() = field
+ @JvmStatic
+ val static_noBackingVal: String
+ get() = ""
+ @JvmStatic
+ var static_noBackingVar: String
+ get() = ""
+ set(value) {}
+ var companionVar: String = ""
+ val companion_withBackingAndGetter: String = ""
+ get() = field
+ @JvmStatic
+ val companion_noBackingVal: String
+ get() = ""
+ @JvmStatic
+ var companion_noBackingVar: String
+ get() = ""
+ set(value) {}
+ }
+}
+
+abstract class BaseClass {
+ open val overriddenBaseProp_willBeBacked: String = ""
+ open val overriddenBaseProp_wontBeBacked: String = ""
+ open val notOverriddenAbstractProp: String = ""
+ abstract val abstractProp_willBeBacked: String
+ abstract val abstractProp_wontBeBacked: String
+ open lateinit var lateinit_var_1: String
+ open lateinit var lateinit_var_2: String
+}
+
+interface MyInterface {
+ val interfaceProp_willBeBacked: String
+ val interfaceProp_wontBeBacked: String
+ var lateinit_var_3: String
+}
+
+class ChildClass: BaseClass(), MyInterface {
+ override val overriddenBaseProp_willBeBacked: String = ""
+ override val overriddenBaseProp_wontBeBacked: String
+ get() = ""
+ override val abstractProp_willBeBacked: String = ""
+ override val abstractProp_wontBeBacked: String
+ get() = ""
+ override val interfaceProp_willBeBacked: String = ""
+ override val interfaceProp_wontBeBacked: String
+ get() = ""
+ override var lateinit_var_1: String
+ get() = ""
+ set(v: String) = Unit
+ override var lateinit_var_2: String = ""
+ override lateinit var lateinit_var_3: String
+}
+
+class ConstructorSetProp {
+ private val propSetInConstructor: Boolean
+ constructor(propSetInConstructor: Boolean) {
+ this.propSetInConstructor = propSetInConstructor
+ }
+}
+
+// FILE: lib/JavaClass.java
+package lib;
+public class JavaClass {
+ private String javaField;
+ private String javaFieldWithAccessors;
+
+ public String getJavaFieldWithAccessors()
+ { return ""; }
+ public void setJavaFieldWithAccessors(String value )
+ {}
+
+ public String getJavaAccessorWithoutField()
+ { return ""; }
+ public void setJavaAccessorWithoutField(String value )
+ {}
+}
+
+// MODULE: main(lib)
+// FILE: main.kt
+package main
+val value: String = ""
+var variable: String = ""
+val value_noBacking: String
+ get() = "aa"
+var variable_noBacking: String
+ get() = "aa"
+ set(value) {}
+val value_withBacking: String = ""
+ get() = field
+var variable_withBacking: String? = null
+ get() = field
+lateinit var lateinit_var: String
+
+data class DataClass(
+ val value_Param: String,
+ var variable_Param: String
+)
+
+class NormalClass(
+ val value_Param: String,
+ var variable_Param: String,
+ normalParam: String
+) {
+ val value: String = ""
+ var variable: String = ""
+ val value_noBacking: String
+ get() = "aa"
+ var variable_noBacking: String
+ get() = "aa"
+ set(value) {}
+ val value_withBacking: String = ""
+ get() = field
+ var variable_withBacking: String? = null
+ get() = field
+ lateinit var lateinit_var: String
+
+ companion object {
+ @JvmStatic
+ var staticVar: String = ""
+ @JvmStatic
+ val static_withBackingAndGetter: String = ""
+ get() = field
+ @JvmStatic
+ val static_noBackingVal: String
+ get() = ""
+ @JvmStatic
+ var static_noBackingVar: String
+ get() = ""
+ set(value) {}
+ var companionVar: String = ""
+ val companion_withBackingAndGetter: String = ""
+ get() = field
+ @JvmStatic
+ val companion_noBackingVal: String
+ get() = ""
+ @JvmStatic
+ var companion_noBackingVar: String
+ get() = ""
+ set(value) {}
+ }
+}
+
+abstract class BaseClass {
+ open val overriddenBaseProp_willBeBacked: String = ""
+ open val overriddenBaseProp_wontBeBacked: String = ""
+ open val notOverriddenAbstractProp: String = ""
+ abstract val abstractProp_willBeBacked: String
+ abstract val abstractProp_wontBeBacked: String
+ open lateinit var lateinit_var_1: String
+ open lateinit var lateinit_var_2: String
+}
+
+interface MyInterface {
+ val interfaceProp_willBeBacked: String
+ val interfaceProp_wontBeBacked: String
+ var lateinit_var_3: String
+}
+
+class ChildClass: BaseClass(), MyInterface {
+ override val overriddenBaseProp_willBeBacked: String = ""
+ override val overriddenBaseProp_wontBeBacked: String
+ get() = ""
+ override val abstractProp_willBeBacked: String = ""
+ override val abstractProp_wontBeBacked: String
+ get() = ""
+ override val interfaceProp_willBeBacked: String = ""
+ override val interfaceProp_wontBeBacked: String
+ get() = ""
+ override var lateinit_var_1: String
+ get() = ""
+ set(v: String) = Unit
+ override var lateinit_var_2: String = ""
+ override lateinit var lateinit_var_3: String
+}
+
+class ConstructorSetProp {
+ private val propSetInConstructor: Boolean
+ constructor(propSetInConstructor: Boolean) {
+ this.propSetInConstructor = propSetInConstructor
+ }
+}
+
+// FILE: main/JavaClass.java
+package main;
+public class JavaClass {
+ private String javaField;
+ private String javaFieldWithAccessors;
+
+ public String getJavaFieldWithAccessors()
+ { return ""; }
+ public void setJavaFieldWithAccessors(String value )
+ {}
+
+ public String getJavaAccessorWithoutField()
+ { return ""; }
+ public void setJavaAccessorWithoutField(String value )
+ {}
+}
diff --git a/test-utils/testData/api/builtInTypes.kt b/test-utils/testData/api/builtInTypes.kt
new file mode 100644
index 00000000..37ae4519
--- /dev/null
+++ b/test-utils/testData/api/builtInTypes.kt
@@ -0,0 +1,54 @@
+/*
+ * 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: BuiltInTypesProcessor
+// EXPECTED:
+// Annotation: OK
+// Any: OK
+// Array<*>: OK
+// Boolean: OK
+// Byte: OK
+// Char: OK
+// Double: OK
+// Float: OK
+// Int: OK
+// Iterable<*>: OK
+// Long: OK
+// Nothing: OK
+// Number: OK
+// Short: OK
+// String: OK
+// Unit: OK
+// END
+
+val a: Any = 0
+val b: Unit = Unit
+val c: Number = 0
+val d: Byte = 0
+val e: Short = 0
+val f: Int = 0
+val g: Long = 0
+val h: Float = 0.0f
+val i: Double = 0.0
+val j: Char = '0'
+val k: Boolean = false
+val l: String = ""
+val m: Iterable<*> = listOf<Any>()
+val n: Annotation = object: Annotation {}
+fun foo(): Nothing = throw Error()
+val o: Array<*> = arrayOf<Any>()
diff --git a/test-utils/testData/api/checkOverride.kt b/test-utils/testData/api/checkOverride.kt
new file mode 100644
index 00000000..435395bd
--- /dev/null
+++ b/test-utils/testData/api/checkOverride.kt
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: CheckOverrideProcessor
+// EXPECTED:
+// KotlinList.get overrides JavaList.get: false
+// KotlinList.foo overrides JavaList.foo: true
+// KotlinList.fooo overrides JavaList.foo: false
+// KotlinList.foo overrides KotlinList.foo: false
+// KotlinList.equals overrides JavaList.equals: true
+// KotlinList2.baz overrides KotlinList.baz: true
+// KotlinList2.baz overrides KotlinList.bazz: false
+// KotlinList2.bazz overrides KotlinList.bazz: true
+// KotlinList2.bazz overrides KotlinList.baz: false
+// KotlinList2.baz overrides KotlinList2.baz: false
+// JavaImpl.getY overrides JavaImpl.getX: false
+// JavaImpl.getY overrides MyInterface.x: false
+// JavaImpl.getX overrides MyInterface.x: true
+// JavaImpl.setY overrides MyInterface.y: true
+// JavaImpl.setX overrides MyInterface.x: false
+// JavaImpl.getY overrides JavaImpl.getY: false
+// MyInterface.x overrides JavaImpl.getY: false
+// MyInterface.x overrides JavaImpl.getX: false
+// MyInterface.y overrides JavaImpl.setY: false
+// MyInterface.y overrides MyInterface.y: false
+// MyInterface2.receiveList overrides MyInterface2ImplWithoutType.receiveList: false
+// MyInterface2ImplWithoutType.receiveList overrides MyInterface2.receiveList: true
+// MyInterface2ImplWithType.receiveList overrides MyInterface2.receiveList: true
+// MyInterface2ImplWithType.receiveList overrides MyInterface2ImplWithoutType.receiveList: true
+// JavaDifferentReturnType.foo overrides JavaList.foo: true
+// Base.f1 overrides MyInterface3.f1: true
+// Base.prop overrides MyInterface3.prop: true
+// JBase.getProp overrides MyInterface3.prop: true
+// END
+// FILE: a.kt
+
+annotation class GetAnno
+annotation class FooAnno
+annotation class BarAnno
+annotation class BazAnno
+annotation class Baz2Anno
+annotation class BazzAnno
+annotation class Bazz2Anno
+
+open class KotlinList(): JavaList() {
+ @GetAnno
+ fun get(): Double {
+ return 2.0
+ }
+
+ override fun equals(other: Any?): Boolean {
+ return false
+ }
+
+ @FooAnno
+ override fun foo(): Int {
+ return 2
+ }
+
+ @BarAnno
+ override fun fooo(): Int {
+ return 2
+ }
+
+ @Baz2Anno
+ open val baz: Int get() {
+ return 1
+ }
+
+ @Bazz2Anno
+ open val bazz: Int get() {
+ return 1
+ }
+}
+
+class KotlinList2(@BazzAnno override val bazz: Int = 2): KotlinList() {
+ @BazAnno
+ override val baz: Int get() {
+ return 2
+ }
+}
+
+interface MyInterface {
+ val x: Int
+ var y: Int
+}
+
+enum class EnumType {
+ FOO,
+ BAR;
+}
+
+interface MyInterface2<T> {
+ fun receiveList(argsInParent : List<T>):Unit
+}
+
+interface MyInterface2ImplWithoutType<T> : MyInterface2<T> {
+ override fun receiveList(argsInParent : List<T>):Unit
+}
+
+interface MyInterface2ImplWithType : MyInterface2ImplWithoutType<EnumType> {
+ override fun receiveList(argsInParent : List<EnumType>):Unit
+}
+
+interface MyInterface3 {
+ fun f1()
+ val prop: String
+}
+
+open class Base {
+ val prop: String = ""
+ fun f1() {
+ }
+}
+
+class BaseOverride: MyInterface3, Base() {
+ fun f2() {}
+}
+
+// FILE: JBaseOverride.java
+public class JBaseOverride extends JBase implements MyInterface3 {
+
+}
+
+// FILE: JBase.java
+
+public class JBase {
+ public String getProp() {
+ return "JBase";
+ }
+}
+
+// FILE: JavaList.java
+
+import java.util.*;
+
+public class JavaList extends List<String> {
+ @Override
+ public String get(int index) {
+ return "OK";
+ }
+
+ protected int foo() {
+ return 1;
+ }
+}
+
+// FILE: JavaImpl.java
+
+public class JavaImpl implements MyInterface {
+ public int getX() {
+ return 1;
+ }
+
+ public int getY() {
+ return 1;
+ }
+
+ public void setY(int value) {
+
+ }
+
+ // intentional override check for a val property
+ public void setX(int value) {
+ return value;
+ }
+}
+
+// FILE: JavaDifferentReturnType.java
+public abstract class JavaDifferentReturnType extends JavaList {
+ // intentional different return type
+ protected String foo() {
+ return "";
+ }
+}
diff --git a/test-utils/testData/api/classKinds.kt b/test-utils/testData/api/classKinds.kt
new file mode 100644
index 00000000..867cc8d9
--- /dev/null
+++ b/test-utils/testData/api/classKinds.kt
@@ -0,0 +1,55 @@
+/*
+ * 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: ClassKindsProcessor
+// EXPECTED:
+// JA: ANNOTATION_CLASS
+// JC: CLASS
+// JE.ENTRY: ENUM_ENTRY
+// JE: ENUM_CLASS
+// JI: INTERFACE
+// KA: ANNOTATION_CLASS
+// KC: CLASS
+// KE.ENTRY: ENUM_ENTRY
+// KE: ENUM_CLASS
+// KI: INTERFACE
+// KO: OBJECT
+// kotlin.Annotation: INTERFACE
+// kotlin.Any: CLASS
+// kotlin.Deprecated: ANNOTATION_CLASS
+// kotlin.DeprecationLevel.WARNING: ENUM_ENTRY
+// kotlin.DeprecationLevel: ENUM_CLASS
+// kotlin.Double.Companion: OBJECT
+// END
+
+// FILE: K.kt
+class KC
+interface KI
+annotation class KA
+object KO
+enum class KE {
+ ENTRY
+}
+
+// FILE: J.java
+class JC {}
+interface JI {}
+@interface JA {}
+enum JE {
+ ENTRY
+}
diff --git a/test-utils/testData/api/companion.kt b/test-utils/testData/api/companion.kt
new file mode 100644
index 00000000..1ca09b75
--- /dev/null
+++ b/test-utils/testData/api/companion.kt
@@ -0,0 +1,31 @@
+/*
+ * 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: ClassWithCompanionProcessor
+// EXPECTED:
+// Foo:false
+// companion:false
+// obj:false
+// K:true
+// END
+
+class Foo {
+ object companion {}
+ object obj {}
+ companion object K {}
+}
diff --git a/test-utils/testData/api/constProperties.kt b/test-utils/testData/api/constProperties.kt
new file mode 100644
index 00000000..18a601ca
--- /dev/null
+++ b/test-utils/testData/api/constProperties.kt
@@ -0,0 +1,57 @@
+// WITH_RUNTIME
+// TEST PROCESSOR: ConstPropertiesProcessor
+// EXPECTED:
+// insideCompanionConstCompiled
+// insideCompanionConstSource
+// insideObjectConstCompiled
+// insideObjectConstSource
+// topLevelConstCompiled
+// topLevelConstSource
+// END
+// MODULE: lib
+// FILE: compiledProperties.kt
+package foo.compiled
+
+const val topLevelConstCompiled: String = "hello"
+val topLevelCompiled: String = "hello"
+val topLevelDelegatedCompiled by lazy { "hello" }
+var topLevelVarCompiled: String = "hello"
+val topLevelCustomGetterCompiled: String get() = "hello"
+object TestObject {
+ const val insideObjectConstCompiled: Boolean = true
+ val insideObjectCompiled: String = "hello"
+ val insideObjectDelegatedCompiled by lazy { "hello" }
+ var insideVarObjectCompiled: String = "hello"
+ val insideObjectCustomGetterCompiled: String get() = "hello"
+}
+interface Foo {
+ val abstractCompiled: Long
+ val abstractWithDefaultCompiled: Long get() = 100L
+ companion object {
+ const val insideCompanionConstCompiled: Int = 34
+ }
+}
+
+// MODULE: main(lib)
+// FILE: sourceProperties.kt
+package foo.source
+
+const val topLevelConstSource: String = "hello"
+val topLevelSource: String = "hello"
+val topLevelDelegatedSource by lazy { "hello" }
+var topLevelVarSource: String = "hello"
+val topLevelCustomGetterSource: String get() = "hello"
+object TestObject {
+ const val insideObjectConstSource: Boolean = true
+ val insideObjectSource: String = "hello"
+ val insideObjectDelegatedSource by lazy { "hello" }
+ var insideVarObjectSource: String = "hello"
+ val insideObjectCustomGetterSource: String get() = "hello"
+}
+interface Foo {
+ val abstractSource: Long
+ val abstractWithDefaultSource: Long get() = 100L
+ companion object {
+ const val insideCompanionConstSource: Int = 34
+ }
+}
diff --git a/test-utils/testData/api/constructorDeclarations.kt b/test-utils/testData/api/constructorDeclarations.kt
new file mode 100644
index 00000000..43889271
--- /dev/null
+++ b/test-utils/testData/api/constructorDeclarations.kt
@@ -0,0 +1,349 @@
+/*
+ * 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: ConstructorDeclarationsProcessor
+// EXPECTED:
+// class: AbstractJavaClassWithExplicitConstructor
+// <init>(kotlin.Int): AbstractJavaClassWithExplicitConstructor
+// class: lib.AbstractJavaClassWithExplicitConstructor
+// <init>(kotlin.Int): lib.AbstractJavaClassWithExplicitConstructor
+// class: AbstractJavaClassWithExplicitEmptyConstructor
+// <init>(): AbstractJavaClassWithExplicitEmptyConstructor
+// class: lib.AbstractJavaClassWithExplicitEmptyConstructor
+// <init>(): lib.AbstractJavaClassWithExplicitEmptyConstructor
+// class: AbstractJavaClassWithMultipleConstructors1
+// <init>(): AbstractJavaClassWithMultipleConstructors1
+// <init>(kotlin.Int): AbstractJavaClassWithMultipleConstructors1
+// <init>(kotlin.String): AbstractJavaClassWithMultipleConstructors1
+// class: lib.AbstractJavaClassWithMultipleConstructors1
+// <init>(): lib.AbstractJavaClassWithMultipleConstructors1
+// <init>(kotlin.Int): lib.AbstractJavaClassWithMultipleConstructors1
+// <init>(kotlin.String): lib.AbstractJavaClassWithMultipleConstructors1
+// class: AbstractJavaClassWithoutExplicitConstructor
+// <init>(): AbstractJavaClassWithoutExplicitConstructor
+// class: lib.AbstractJavaClassWithoutExplicitConstructor
+// <init>(): lib.AbstractJavaClassWithoutExplicitConstructor
+// class: AbstractKotlinClassWithExplicitConstructor
+// <init>(kotlin.Int): AbstractKotlinClassWithExplicitConstructor
+// class: lib.AbstractKotlinClassWithExplicitConstructor
+// <init>(kotlin.Int): lib.AbstractKotlinClassWithExplicitConstructor
+// class: AbstractKotlinClassWithExplicitEmptyConstructor
+// <init>(): AbstractKotlinClassWithExplicitEmptyConstructor
+// class: lib.AbstractKotlinClassWithExplicitEmptyConstructor
+// <init>(): lib.AbstractKotlinClassWithExplicitEmptyConstructor
+// class: AbstractKotlinClassWithMultipleConstructors1
+// <init>(): AbstractKotlinClassWithMultipleConstructors1
+// <init>(kotlin.Int): AbstractKotlinClassWithMultipleConstructors1
+// <init>(kotlin.String): AbstractKotlinClassWithMultipleConstructors1
+// class: lib.AbstractKotlinClassWithMultipleConstructors1
+// <init>(): lib.AbstractKotlinClassWithMultipleConstructors1
+// <init>(kotlin.Int): lib.AbstractKotlinClassWithMultipleConstructors1
+// <init>(kotlin.String): lib.AbstractKotlinClassWithMultipleConstructors1
+// class: AbstractKotlinClassWithMultipleConstructors2
+// <init>(kotlin.Float): AbstractKotlinClassWithMultipleConstructors2
+// <init>(kotlin.Int): AbstractKotlinClassWithMultipleConstructors2
+// <init>(kotlin.String): AbstractKotlinClassWithMultipleConstructors2
+// class: lib.AbstractKotlinClassWithMultipleConstructors2
+// <init>(kotlin.Float): lib.AbstractKotlinClassWithMultipleConstructors2
+// <init>(kotlin.Int): lib.AbstractKotlinClassWithMultipleConstructors2
+// <init>(kotlin.String): lib.AbstractKotlinClassWithMultipleConstructors2
+// class: AbstractKotlinClassWithPrimaryConstructor
+// <init>(kotlin.Int): AbstractKotlinClassWithPrimaryConstructor
+// class: lib.AbstractKotlinClassWithPrimaryConstructor
+// <init>(kotlin.Int): lib.AbstractKotlinClassWithPrimaryConstructor
+// class: AbstractKotlinClassWithoutExplicitConstructor
+// <init>(): AbstractKotlinClassWithoutExplicitConstructor
+// class: lib.AbstractKotlinClassWithoutExplicitConstructor
+// <init>(): lib.AbstractKotlinClassWithoutExplicitConstructor
+// class: DataClass
+// <init>(kotlin.Int,kotlin.String): DataClass
+// class: lib.DataClass
+// <init>(kotlin.Int,kotlin.String): lib.DataClass
+// class: DataClassWithSecondaryConstructor
+// <init>(kotlin.Int): DataClassWithSecondaryConstructor
+// <init>(kotlin.Int,kotlin.String): DataClassWithSecondaryConstructor
+// class: lib.DataClassWithSecondaryConstructor
+// <init>(kotlin.Int): lib.DataClassWithSecondaryConstructor
+// <init>(kotlin.Int,kotlin.String): lib.DataClassWithSecondaryConstructor
+// class: JavaAnnotation
+// <init>(): JavaAnnotation
+// class: lib.JavaAnnotation
+// <init>(): lib.JavaAnnotation
+// class: JavaClassWithExplicitConstructor
+// <init>(kotlin.Int): JavaClassWithExplicitConstructor
+// class: lib.JavaClassWithExplicitConstructor
+// <init>(kotlin.Int): lib.JavaClassWithExplicitConstructor
+// class: JavaClassWithExplicitEmptyConstructor
+// <init>(): JavaClassWithExplicitEmptyConstructor
+// class: lib.JavaClassWithExplicitEmptyConstructor
+// <init>(): lib.JavaClassWithExplicitEmptyConstructor
+// class: JavaClassWithMultipleConstructors1
+// <init>(): JavaClassWithMultipleConstructors1
+// <init>(kotlin.Int): JavaClassWithMultipleConstructors1
+// <init>(kotlin.String): JavaClassWithMultipleConstructors1
+// class: lib.JavaClassWithMultipleConstructors1
+// <init>(): lib.JavaClassWithMultipleConstructors1
+// <init>(kotlin.Int): lib.JavaClassWithMultipleConstructors1
+// <init>(kotlin.String): lib.JavaClassWithMultipleConstructors1
+// class: JavaClassWithoutExplicitConstructor
+// <init>(): JavaClassWithoutExplicitConstructor
+// class: lib.JavaClassWithoutExplicitConstructor
+// <init>(): lib.JavaClassWithoutExplicitConstructor
+// class: JavaInterface
+// class: lib.JavaInterface
+// class: KotlinAnnotation
+// <init>(): KotlinAnnotation
+// class: lib.KotlinAnnotation
+// <init>(): lib.KotlinAnnotation
+// class: KotlinClassWithCompanion
+// <init>(): KotlinClassWithCompanion
+// class: lib.KotlinClassWithCompanion
+// <init>(): lib.KotlinClassWithCompanion
+// class: KotlinClassWithExplicitConstructor
+// <init>(kotlin.Int): KotlinClassWithExplicitConstructor
+// class: lib.KotlinClassWithExplicitConstructor
+// <init>(kotlin.Int): lib.KotlinClassWithExplicitConstructor
+// class: KotlinClassWithExplicitEmptyConstructor
+// <init>(): KotlinClassWithExplicitEmptyConstructor
+// class: lib.KotlinClassWithExplicitEmptyConstructor
+// <init>(): lib.KotlinClassWithExplicitEmptyConstructor
+// class: KotlinClassWithMultipleConstructors1
+// <init>(): KotlinClassWithMultipleConstructors1
+// <init>(kotlin.Int): KotlinClassWithMultipleConstructors1
+// <init>(kotlin.String): KotlinClassWithMultipleConstructors1
+// class: lib.KotlinClassWithMultipleConstructors1
+// <init>(): lib.KotlinClassWithMultipleConstructors1
+// <init>(kotlin.Int): lib.KotlinClassWithMultipleConstructors1
+// <init>(kotlin.String): lib.KotlinClassWithMultipleConstructors1
+// class: KotlinClassWithMultipleConstructors2
+// <init>(kotlin.Float): KotlinClassWithMultipleConstructors2
+// <init>(kotlin.Int): KotlinClassWithMultipleConstructors2
+// <init>(kotlin.String): KotlinClassWithMultipleConstructors2
+// class: lib.KotlinClassWithMultipleConstructors2
+// <init>(kotlin.Float): lib.KotlinClassWithMultipleConstructors2
+// <init>(kotlin.Int): lib.KotlinClassWithMultipleConstructors2
+// <init>(kotlin.String): lib.KotlinClassWithMultipleConstructors2
+// class: KotlinClassWithNamedCompanion
+// <init>(): KotlinClassWithNamedCompanion
+// class: lib.KotlinClassWithNamedCompanion
+// <init>(): lib.KotlinClassWithNamedCompanion
+// class: KotlinClassWithPrimaryConstructor
+// <init>(kotlin.Int): KotlinClassWithPrimaryConstructor
+// class: lib.KotlinClassWithPrimaryConstructor
+// <init>(kotlin.Int): lib.KotlinClassWithPrimaryConstructor
+// class: KotlinClassWithoutExplicitConstructor
+// <init>(): KotlinClassWithoutExplicitConstructor
+// class: lib.KotlinClassWithoutExplicitConstructor
+// <init>(): lib.KotlinClassWithoutExplicitConstructor
+// class: KotlinInterface
+// class: lib.KotlinInterface
+// class: KotlinObject
+// <init>(): KotlinObject
+// class: lib.KotlinObject
+// <init>(): lib.KotlinObject
+// END
+
+// MODULE: lib
+// FILE: lib/JavaInterface.java
+package lib;
+interface JavaInterface {
+}
+// FILE: lib/AbstractJavaClassWithoutExplicitConstructor.java
+package lib;
+abstract class AbstractJavaClassWithoutExplicitConstructor {
+}
+// FILE: lib/AbstractJavaClassWithExplicitEmptyConstructor.java
+package lib;
+abstract class AbstractJavaClassWithExplicitEmptyConstructor {
+ AbstractJavaClassWithExplicitEmptyConstructor() {}
+}
+// FILE: lib/AbstractJavaClassWithExplicitConstructor.java
+package lib;
+abstract class AbstractJavaClassWithExplicitConstructor {
+ AbstractJavaClassWithExplicitConstructor(int x) {}
+}
+// FILE: lib/AbstractJavaClassWithMultipleConstructors1.java
+package lib;
+abstract class AbstractJavaClassWithMultipleConstructors1 {
+ AbstractJavaClassWithMultipleConstructors1() {}
+ AbstractJavaClassWithMultipleConstructors1(int y) {}
+ AbstractJavaClassWithMultipleConstructors1(String x) {}
+}
+// FILE: lib/JavaClassWithoutExplicitConstructor.java
+package lib;
+class JavaClassWithoutExplicitConstructor {
+}
+// FILE: lib/JavaClassWithExplicitEmptyConstructor.java
+package lib;
+class JavaClassWithExplicitEmptyConstructor {
+ JavaClassWithExplicitEmptyConstructor() {}
+}
+// FILE: lib/JavaClassWithExplicitConstructor.java
+package lib;
+class JavaClassWithExplicitConstructor {
+ JavaClassWithExplicitConstructor(int x) {}
+}
+// FILE: lib/JavaClassWithMultipleConstructors1.java
+package lib;
+class JavaClassWithMultipleConstructors1 {
+ JavaClassWithMultipleConstructors1() {}
+ JavaClassWithMultipleConstructors1(int y) {}
+ JavaClassWithMultipleConstructors1(String x) {}
+}
+// FILE: JavaAnnotation.java
+package lib;
+public @interface JavaAnnotation {
+}
+// FILE: kotlin_lib.kt
+package lib
+interface KotlinInterface {}
+class KotlinClassWithoutExplicitConstructor {
+}
+class KotlinClassWithExplicitEmptyConstructor() {}
+class KotlinClassWithPrimaryConstructor(x:Int) {
+}
+class KotlinClassWithExplicitConstructor {
+ constructor(x:Int) {}
+}
+class KotlinClassWithMultipleConstructors1 {
+ constructor() {}
+ constructor(y:Int): this() {}
+ constructor(x: String) : this() {}
+}
+class KotlinClassWithMultipleConstructors2(z:Float) {
+ constructor(y:Int): this(0f) {}
+ constructor(x: String) : this(0f) {}
+}
+abstract class AbstractKotlinClassWithoutExplicitConstructor {
+}
+abstract class AbstractKotlinClassWithPrimaryConstructor(x:Int) {
+}
+abstract class AbstractKotlinClassWithExplicitEmptyConstructor() {}
+abstract class AbstractKotlinClassWithExplicitConstructor {
+ constructor(x:Int) {}
+}
+abstract class AbstractKotlinClassWithMultipleConstructors1 {
+ constructor() {}
+ constructor(y:Int): this() {}
+ constructor(x: String) : this() {}
+}
+abstract class AbstractKotlinClassWithMultipleConstructors2(z:Float) {
+ constructor(y:Int): this(0f) {}
+ constructor(x: String) : this(0f) {}
+}
+annotation class KotlinAnnotation
+object KotlinObject {}
+class KotlinClassWithCompanion {
+ companion object
+}
+class KotlinClassWithNamedCompanion {
+ companion object MyCompanion
+}
+data class DataClass(val x:Int, var y:String)
+data class DataClassWithSecondaryConstructor(val x:Int, val y:String) {
+ constructor(x:Int) : this(x, "")
+}
+// MODULE: main(lib)
+// FILE: JavaInterface.java
+interface JavaInterface {
+}
+// FILE: AbstractJavaClassWithoutExplicitConstructor.java
+abstract class AbstractJavaClassWithoutExplicitConstructor {
+}
+// FILE: AbstractJavaClassWithExplicitEmptyConstructor.java
+abstract class AbstractJavaClassWithExplicitEmptyConstructor {
+ AbstractJavaClassWithExplicitEmptyConstructor() {}
+}
+// FILE: AbstractJavaClassWithExplicitConstructor.java
+abstract class AbstractJavaClassWithExplicitConstructor {
+ AbstractJavaClassWithExplicitConstructor(int x) {}
+}
+// FILE: AbstractJavaClassWithMultipleConstructors1.java
+abstract class AbstractJavaClassWithMultipleConstructors1 {
+ AbstractJavaClassWithMultipleConstructors1() {}
+ AbstractJavaClassWithMultipleConstructors1(int y) {}
+ AbstractJavaClassWithMultipleConstructors1(String x) {}
+}
+// FILE: JavaClassWithoutExplicitConstructor.java
+class JavaClassWithoutExplicitConstructor {
+}
+// FILE: JavaClassWithExplicitEmptyConstructor.java
+class JavaClassWithExplicitEmptyConstructor {
+ JavaClassWithExplicitEmptyConstructor() {}
+}
+// FILE: JavaClassWithExplicitConstructor.java
+class JavaClassWithExplicitConstructor {
+ JavaClassWithExplicitConstructor(int x) {}
+}
+// FILE: JavaClassWithMultipleConstructors1.java
+class JavaClassWithMultipleConstructors1 {
+ JavaClassWithMultipleConstructors1() {}
+ JavaClassWithMultipleConstructors1(int y) {}
+ JavaClassWithMultipleConstructors1(String x) {}
+}
+// FILE: JavaAnnotation.java
+public @interface JavaAnnotation {
+}
+// FILE: kotlin.kt
+interface KotlinInterface {}
+class KotlinClassWithoutExplicitConstructor {
+}
+class KotlinClassWithExplicitEmptyConstructor() {}
+class KotlinClassWithPrimaryConstructor(x:Int) {
+}
+class KotlinClassWithExplicitConstructor {
+ constructor(x:Int) {}
+}
+class KotlinClassWithMultipleConstructors1 {
+ constructor() {}
+ constructor(y:Int): this() {}
+ constructor(x: String) : this() {}
+}
+class KotlinClassWithMultipleConstructors2(z:Float) {
+ constructor(y:Int): this(0f) {}
+ constructor(x: String) : this(0f) {}
+}
+abstract class AbstractKotlinClassWithoutExplicitConstructor {
+}
+abstract class AbstractKotlinClassWithPrimaryConstructor(x:Int) {
+}
+abstract class AbstractKotlinClassWithExplicitEmptyConstructor() {}
+abstract class AbstractKotlinClassWithExplicitConstructor {
+ constructor(x:Int) {}
+}
+abstract class AbstractKotlinClassWithMultipleConstructors1 {
+ constructor() {}
+ constructor(y:Int): this() {}
+ constructor(x: String) : this() {}
+}
+abstract class AbstractKotlinClassWithMultipleConstructors2(z:Float) {
+ constructor(y:Int): this(0f) {}
+ constructor(x: String) : this(0f) {}
+}
+annotation class KotlinAnnotation
+object KotlinObject {}
+class KotlinClassWithCompanion {
+ companion object
+}
+class KotlinClassWithNamedCompanion {
+ companion object MyCompanion
+}
+data class DataClass(val x:Int, var y:String)
+data class DataClassWithSecondaryConstructor(val x:Int, val y:String) {
+ constructor(x:Int) : this(x, "")
+} \ No newline at end of file
diff --git a/test-utils/testData/api/crossModuleTypeAlias.kt b/test-utils/testData/api/crossModuleTypeAlias.kt
new file mode 100644
index 00000000..92a86a0f
--- /dev/null
+++ b/test-utils/testData/api/crossModuleTypeAlias.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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: CrossModuleTypeAliasTestProcessor
+// EXPECTED:
+// A1(KOTLIN)
+// A2(KOTLIN_LIB)
+// M1(KOTLIN_LIB)
+// END
+
+// MODULE: module1
+// FILE: M1.kt
+class M1
+
+// MODULE: module2(module1)
+// FILE: M2.kt
+typealias A2 = M1
+
+// MODULE: main(module1, module2)
+// FILE: main.kt
+typealias A1 = M1
+
+class TestTarget {
+ val a1: A1 = TODO()
+ val a2: A2 = TODO()
+ val m1: M1 = TODO()
+}
diff --git a/test-utils/testData/api/declarationInconsistency.kt b/test-utils/testData/api/declarationInconsistency.kt
new file mode 100644
index 00000000..6f3b39b8
--- /dev/null
+++ b/test-utils/testData/api/declarationInconsistency.kt
@@ -0,0 +1,31 @@
+/*
+ * 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: DeclarationInconsistencyProcessor
+// EXPECTED:
+// via type: java.io.Serializable
+// equals
+// hashCode
+// toString
+// via find declaration: java.io.Serializable
+// equals
+// hashCode
+// toString
+// END
+//FILE: a.kt
+val x = 3
diff --git a/test-utils/testData/api/declarationOrder.kt b/test-utils/testData/api/declarationOrder.kt
new file mode 100644
index 00000000..7de65a23
--- /dev/null
+++ b/test-utils/testData/api/declarationOrder.kt
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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: DeclarationOrderProcessor
+// EXPECTED:
+// lib.KotlinClass
+// b:Ljava/lang/String;
+// a:Ljava/lang/String;
+// c:Ljava/lang/String;
+// isB:Ljava/lang/String;
+// isA:Ljava/lang/String;
+// isC:Ljava/lang/String;
+// noBackingB:Ljava/lang/String;
+// noBackingA:Ljava/lang/String;
+// noBackingC:Ljava/lang/String;
+// noBackingVarB:Ljava/lang/String;
+// noBackingVarA:Ljava/lang/String;
+// noBackingVarC:Ljava/lang/String;
+// overloaded:(Ljava/lang/String;)Ljava/lang/String;
+// overloaded:(I)Ljava/lang/String;
+// overloaded:()Ljava/lang/String;
+// overloaded:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+// <init>:()V
+// lib.JavaClass
+// b:Ljava/lang/String;
+// a:Ljava/lang/String;
+// c:Ljava/lang/String;
+// overloaded:(Ljava/lang/String;)V
+// overloaded:(I)V
+// overloaded:()V
+// overloaded:(Ljava/lang/String;Ljava/lang/String;)V
+// <init>:()V
+// KotlinClass
+// b:Ljava/lang/String;
+// a:Ljava/lang/String;
+// c:Ljava/lang/String;
+// isB:Ljava/lang/String;
+// isA:Ljava/lang/String;
+// isC:Ljava/lang/String;
+// noBackingB:Ljava/lang/String;
+// noBackingA:Ljava/lang/String;
+// noBackingC:Ljava/lang/String;
+// noBackingVarB:Ljava/lang/String;
+// noBackingVarA:Ljava/lang/String;
+// noBackingVarC:Ljava/lang/String;
+// overloaded:(Ljava/lang/String;)Ljava/lang/String;
+// overloaded:(I)Ljava/lang/String;
+// overloaded:()Ljava/lang/String;
+// overloaded:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+// <init>:()V
+// JavaClass
+// b:Ljava/lang/String;
+// a:Ljava/lang/String;
+// c:Ljava/lang/String;
+// overloaded:(Ljava/lang/String;)V
+// overloaded:(I)V
+// overloaded:()V
+// overloaded:(Ljava/lang/String;Ljava/lang/String;)V
+// <init>:()V
+// END
+// MODULE: module1
+// FILE: lib/KotlinClass.kt
+package lib;
+class KotlinClass {
+ val b: String = TODO()
+ val a: String = TODO()
+ val c: String = TODO()
+ val isB:String = TODO()
+ val isA:String = TODO()
+ val isC:String = TODO()
+ val noBackingB: String
+ get() = ""
+ val noBackingA: String
+ get() = ""
+ val noBackingC: String
+ get() = ""
+ var noBackingVarB: String
+ get() = ""
+ set(value) {}
+ var noBackingVarA: String
+ get() = ""
+ set(value) {}
+ var noBackingVarC: String
+ get() = ""
+ set(value) {}
+ fun overloaded(x:String): String = TODO()
+ fun overloaded(x:Int): String = TODO()
+ fun overloaded(): String = TODO()
+ fun overloaded(x:String, y:String): String = TODO()
+}
+// FILE: lib/JavaClass.java
+package lib;
+public class JavaClass {
+ // notice the non alphabetic order, which is triggering the problem
+ String b = "";
+ String a = "";
+ String c = "";
+ void overloaded(String x) {}
+ void overloaded(int x) {}
+ void overloaded() {}
+ void overloaded(String x, String y) {}
+}
+// MODULE: main(module1)
+// FILE: main.kt
+class KotlinClass {
+ val b: String? = TODO()
+ val a: String = TODO()
+ val c: String? = TODO()
+ val isB:String = TODO()
+ val isA:String = TODO()
+ val isC:String = TODO()
+ val noBackingB: String
+ get() = ""
+ val noBackingA: String
+ get() = ""
+ val noBackingC: String
+ get() = ""
+ var noBackingVarB: String
+ get() = ""
+ set(value) {}
+ var noBackingVarA: String
+ get() = ""
+ set(value) {}
+ var noBackingVarC: String
+ get() = ""
+ set(value) {}
+ fun overloaded(x:String): String = TODO()
+ fun overloaded(x:Int): String = TODO()
+ fun overloaded(): String = TODO()
+ fun overloaded(x:String, y:String): String = TODO()
+}
+// FILE: JavaClass.java
+public class JavaClass {
+ String b = "";
+ String a = "";
+ String c = "";
+ void overloaded(String x) {}
+ void overloaded(int x) {}
+ void overloaded() {}
+ void overloaded(String x, String y) {}
+}
diff --git a/test-utils/testData/api/declarationPackageName.kt b/test-utils/testData/api/declarationPackageName.kt
new file mode 100644
index 00000000..bf3df55f
--- /dev/null
+++ b/test-utils/testData/api/declarationPackageName.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: DeclarationPackageNameProcessor
+// EXPECTED:
+// <no name>:J1
+// <no name>:J1.<init>
+// <no name>:J2
+// <no name>:J2.<init>
+// <no name>:K1
+// <no name>:K1.<init>
+// <no name>:K2
+// <no name>:K2.<init>
+// test.java.pack:C
+// test.java.pack:C.<init>
+// test.java.pack:Inner
+// test.java.pack:Inner.<init>
+// test.java.pack:Nested
+// test.java.pack:Nested.<init>
+// test.pack:Inner
+// test.pack:Inner.<init>
+// test.pack:Inner.innerFoo
+// test.pack:InnerLocal
+// test.pack:InnerLocal.<init>
+// test.pack:Nested
+// test.pack:Nested.<init>
+// test.pack:Nested.nestedFoo
+// test.pack:Outer
+// test.pack:Outer.<init>
+// test.pack:Outer.Foo
+// test.pack:Val
+// test.pack:a
+// test.pack:innerVal
+// test.pack:nestedVal
+// END
+
+// MODULE: module1
+// FILE: K1.kt
+class K1
+
+// FILE: J1.java
+class J1 {
+}
+
+// MODULE: main(module1)
+// FILE: K2.kt
+class K2
+
+// FILE: J2.java
+class J2 {
+}
+
+// FILE: a.kt
+package test.pack
+
+class Outer {
+ val Val
+
+ fun Foo() {}
+
+ inner class Inner {
+ val innerVal: Int
+ fun innerFoo() {
+ class InnerLocal
+ }
+ }
+ class Nested {
+ private val nestedVal: Int
+ fun nestedFoo() {
+ val a = 1
+ }
+ }
+}
+
+//FILE: test/java/pack/C.java
+package test.java.pack;
+
+public class C {
+ class Inner {
+
+ }
+
+ static class Nested {}
+}
diff --git a/test-utils/testData/api/declarationUtil.kt b/test-utils/testData/api/declarationUtil.kt
new file mode 100644
index 00000000..368fb799
--- /dev/null
+++ b/test-utils/testData/api/declarationUtil.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: DeclarationUtilProcessor
+// FORMAT: <name>: isInternal: isLocal: isPrivate: isProtected: isPublic: isOpen
+// EXPECTED:
+// Cls: internal
+// Cls / <init>: public
+// Cls.b: public open
+// Cls / <init>: public
+// Cls / <init> / aaa: local
+// Cls.prop: public open
+// Cls.protectedProp: protected open
+// Cls.abstractITFFun: public open
+// Cls.pri: private
+// ITF: public open
+// ITF.prop: public open
+// ITF.protectedProp: protected open
+// ITF.b: public open
+// ITF.abstractITFFun: public open
+// ITF.nonAbstractITFFun: public open
+// ITF.nonAbstractITFFun / aa: local
+// NestedClassSubjects: public open
+// NestedClassSubjects.NestedDataClass: public
+// NestedClassSubjects.NestedDataClass / <init>: public
+// NestedClassSubjects.NestedDataClass.field: public
+// NestedClassSubjects.NestedFinalClass: public
+// NestedClassSubjects.NestedFinalClass / <init>: public
+// NestedClassSubjects.NestedFinalClass.field: public
+// NestedClassSubjects.NestedOpenClass: public open
+// NestedClassSubjects.NestedOpenClass / <init>: public
+// NestedClassSubjects.NestedOpenClass.field: public
+// NestedClassSubjects.NestedInterface: public open
+// SealedBase: public open
+// SealedBase.<init>: public
+// SealedImpl: public
+// SealedImpl.<init>: public
+// END
+// FILE: a.kt
+internal class Cls(override val b: Int) : ITF {
+ constructor() {
+ val aaa = 2
+ Cls(aaa)
+ }
+ override val prop: Int = 2
+
+ override val protectedProp: Int = 2
+
+ override fun abstractITFFun(): Int {
+ return 2
+ }
+
+ private val pri: Int = 3
+}
+
+interface ITF {
+ val prop: Int
+
+ protected val protectedProp: Int
+
+ val b: Int = 1
+
+ fun abstractITFFun(): Int
+
+ fun nonAbstractITFFun(): Int {
+ val aa = "local"
+ return 1
+ }
+}
+
+interface NestedClassSubjects {
+ data class NestedDataClass(
+ val field: String,
+ )
+ class NestedFinalClass(
+ val field: String,
+ )
+ open class NestedOpenClass(
+ val field: String,
+ )
+ interface NestedInterface
+}
+
+sealed class SealedBase
+
+class SealedImpl: SealedBase
diff --git a/test-utils/testData/api/declared.kt b/test-utils/testData/api/declared.kt
new file mode 100644
index 00000000..1eb567ce
--- /dev/null
+++ b/test-utils/testData/api/declared.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: DeclaredProcessor
+// EXPECTED:
+// Base class declared functions:
+// subFun
+// synthetic constructor for Sub
+// Sub class declared functions:
+// baseFun
+// <init>
+// JavaSource class declared functions:
+// javaSourceFun
+// synthetic constructor for JavaSource
+// END
+// MODULE: module1
+// FILE: lib.kt
+open class Base {
+ fun baseFun() {}
+}
+// MODULE: main(module1)
+// FILE: sub.kt
+class Sub: Base() {
+ fun subFun() {}
+}
+
+// FILE: JavaSource.java
+public class JavaSource {
+ public int javaSourceFun() {
+ return 1
+ }
+}
diff --git a/test-utils/testData/api/docString.kt b/test-utils/testData/api/docString.kt
new file mode 100644
index 00000000..1432c05a
--- /dev/null
+++ b/test-utils/testData/api/docString.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: DocStringProcessor
+// EXPECTED:
+// <init>: \n This is a java doc\n\n This is a second line\n\n more lines\n
+// <init>: \n inner class\n
+// <init>: \n nest class\n
+// <init>: \n top level class\n\n doc can have multiple lines\n\n third non-empty line\n
+// Inner: \n inner class\n
+// JavaSrc: \n This is a java doc\n\n This is a second line\n\n more lines\n
+// Nested: \n nest class\n
+// TopClass: \n top level class\n\n doc can have multiple lines\n\n third non-empty line\n
+// f1: \n top level function\n
+// f2: \n member function\n
+// foo: \n\n\n member function\n\n
+// j1: \n field\n
+// j2: null
+// j3: null
+// v1: \n\n top level property\n\n
+// v2: Irregular doc comment 1
+// v3: \n Irregular doc comment 2
+// v4: Irregular doc comment 3 *\n
+// v5: \n owned doc comment\n
+// v6: null
+// v7: null
+// v8: \n member property\n
+// END
+// FILE: KotlinSrc.kt
+
+/**
+ * top level function
+ */
+fun f1() = 0
+
+/**
+ *
+ * top level property
+ *
+ */
+val v1 = 0
+
+
+/** * Irregular doc comment 1***/
+val v2 = 0
+
+/**
+ * Irregular doc comment 2*/
+val v3 = 0
+
+/** Irregular doc comment 3 *
+ */
+val v4 = 0
+
+/**
+ * unassociated doc comment
+ */
+/**
+ * owned doc comment
+ */
+val v5 = 0
+
+/* Not doc comment 1 */
+val v6 = 0
+
+// Not doc comment 2
+val v7 = 0
+
+/**
+ * top level class
+ *
+ * doc can have multiple lines
+ *
+ * third non-empty line
+ */
+class TopClass {
+ /**
+ * nest class
+ */
+ class Nested
+
+ /**
+ * inner class
+ */
+ class Inner
+
+ /**
+ * member function
+ */
+ fun f2() = 0
+
+ /**
+ * member property
+ */
+ val v8 = 0
+}
+
+// FILE: JavaSrc.java
+/**
+ * This is a java doc
+ *
+ * This is a second line
+ *
+ * more lines
+ */
+class JavaSrc {
+ /**
+ *
+ *
+ * member function
+ *
+ */
+ int foo() {
+ return 0;
+ }
+
+ /**
+ * field
+ */
+ int j1 = 0;
+
+ // Not a doc
+ int j2 = 0;
+
+ /* Not a doc */
+ int j3 = 0;
+}
diff --git a/test-utils/testData/api/equivalentJavaWildcards.kt b/test-utils/testData/api/equivalentJavaWildcards.kt
new file mode 100644
index 00000000..c4f3ecf0
--- /dev/null
+++ b/test-utils/testData/api/equivalentJavaWildcards.kt
@@ -0,0 +1,208 @@
+/*
+ * 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: EquivalentJavaWildcardProcessor
+// EXPECTED:
+// X : Any -> Any
+// <init> : X -> X
+// Y : X -> X
+// <init> : Y -> Y
+// A : Any -> Any
+// T1 : Any? -> Any?
+// T2 : Any? -> Any?
+// <init> : A<T1, T2> -> A<T1, T2>
+// B : Any -> Any
+// T : Any? -> Any?
+// synthetic constructor for B : B<*> -> B<out Any?>
+// bar1 : [@kotlin.jvm.JvmSuppressWildcards] A<X, X> -> [@kotlin.jvm.JvmSuppressWildcards] A<X, X>
+// - INVARIANT X : X -> X
+// - INVARIANT X : X -> X
+// - @JvmSuppressWildcards : JvmSuppressWildcards -> JvmSuppressWildcards
+// bar2 : [@kotlin.jvm.JvmSuppressWildcards] A<X, X> -> [@kotlin.jvm.JvmSuppressWildcards] A<in X, out X>
+// - INVARIANT X : X -> X
+// - INVARIANT X : X -> X
+// - @JvmSuppressWildcards : JvmSuppressWildcards -> JvmSuppressWildcards
+// bar3 : [@kotlin.jvm.JvmWildcard] A<X, X> -> [@kotlin.jvm.JvmWildcard] A<X, X>
+// - INVARIANT X : X -> X
+// - INVARIANT X : X -> X
+// - @JvmWildcard : JvmWildcard -> JvmWildcard
+// p1 : A<in X, out X> -> A<X, X>
+// - CONTRAVARIANT X : X -> X
+// - COVARIANT X : X -> X
+// p1.getter() : A<in X, out X> -> A<X, X>
+// - CONTRAVARIANT X : X -> X
+// - COVARIANT X : X -> X
+// p2 : A<Any, Y> -> A<Any, Y>
+// - INVARIANT Any : Any -> Any
+// - INVARIANT Y : Y -> Y
+// p2.getter() : A<Any, Y> -> A<Any, Y>
+// - INVARIANT Any : Any -> Any
+// - INVARIANT Y : Y -> Y
+// p3 : A<*, *> -> A<Any?, Any?>
+// p3.getter() : A<*, *> -> A<Any?, Any?>
+// - STAR Any : Any? -> Any?
+// - STAR Any : Any? -> Any?
+// p4 : B<X> -> B<X>
+// - INVARIANT X : X -> X
+// p4.getter() : B<X> -> B<X>
+// - INVARIANT X : X -> X
+// p5 : B<in X> -> B<in X>
+// - CONTRAVARIANT X : X -> X
+// p5.getter() : B<in X> -> B<in X>
+// - CONTRAVARIANT X : X -> X
+// p6 : B<out X> -> B<out X>
+// - COVARIANT X : X -> X
+// p6.getter() : B<out X> -> B<out X>
+// - COVARIANT X : X -> X
+// p7 : B<*> -> B<out Any?>
+// p7.getter() : B<*> -> B<out Any?>
+// - STAR Any : Any? -> Any?
+// p8 : B<A<X, out Y>> -> B<A<X, Y>>
+// - INVARIANT A : A<X, out Y> -> A<X, Y>
+// - - INVARIANT X : X -> X
+// - - COVARIANT Y : Y -> Y
+// p8.getter() : B<A<X, out Y>> -> B<A<X, Y>>
+// - INVARIANT A<X, out Y> : A<X, out Y> -> A<in X, Y>
+// - - INVARIANT X : X -> X
+// - - COVARIANT Y : Y -> Y
+// v1 : A<X, X> -> A<in X, out X>
+// - INVARIANT X : X -> X
+// - INVARIANT X : X -> X
+// v2 : A<Any, Y> -> A<Any, Y>
+// - INVARIANT Any : Any -> Any
+// - INVARIANT Y : Y -> Y
+// v3 : A<*, *> -> A<out Any?, out Any?>
+// v4 : B<X> -> B<X>
+// - INVARIANT X : X -> X
+// v5 : B<in X> -> B<in X>
+// - CONTRAVARIANT X : X -> X
+// v6 : B<out X> -> B<out X>
+// - COVARIANT X : X -> X
+// v7 : B<*> -> B<out Any?>
+// v8 : B<A<X, out Y>> -> B<A<X, Y>>
+// - INVARIANT A : A<X, out Y> -> A<X, Y>
+// - - INVARIANT X : X -> X
+// - - COVARIANT Y : Y -> Y
+// foo : Unit -> Unit
+// r1 : A<X, X> -> A<X, X>
+// - INVARIANT X : X -> X
+// - INVARIANT X : X -> X
+// r2 : A<Any, Y> -> A<Any, Y>
+// - INVARIANT Any : Any -> Any
+// - INVARIANT Y : Y -> Y
+// r3 : A<*, *> -> A<Any?, Any?>
+// r4 : B<X> -> B<X>
+// - INVARIANT X : X -> X
+// r5 : B<in X> -> B<in X>
+// - CONTRAVARIANT X : X -> X
+// r6 : B<out X> -> B<out X>
+// - COVARIANT X : X -> X
+// r7 : B<*> -> B<out Any?>
+// r8 : B<A<X, out Y>> -> B<A<X, Y>>
+// - INVARIANT A : A<X, out Y> -> A<X, Y>
+// - - INVARIANT X : X -> X
+// - - COVARIANT Y : Y -> Y
+// C1 : A<X, X> -> A<X, X>
+// - INVARIANT X : X -> X
+// - INVARIANT X : X -> X
+// <init> : C1 -> C1
+// C2 : A<Any, Y> -> A<Any, Y>
+// - INVARIANT Any : Any -> Any
+// - INVARIANT Y : Y -> Y
+// <init> : C2 -> C2
+// C3 : B<X> -> B<X>
+// - INVARIANT X : X -> X
+// <init> : C3 -> C3
+// C4 : B<A<X, out Y>> -> B<A<in X, out Y>>
+// - INVARIANT A : A<X, out Y> -> A<in X, out Y>
+// - - INVARIANT X : X -> X
+// - - COVARIANT Y : Y -> Y
+// <init> : C4 -> C4
+// END
+
+open class X()
+final class Y() : X()
+
+open class A<in T1, out T2>()
+open class B<T>
+
+// FIXME: should this annotation propagate to the return type?
+// @JvmSuppressWildcards(false)
+// fun bar(): A<X, X> = TODO()
+
+// A<X, X>
+fun bar1(): @JvmSuppressWildcards(true) A<X, X> = TODO()
+// A<? super X, ? extends X>
+fun bar2(): @JvmSuppressWildcards(false) A<X, X> = TODO()
+// A<X, X>
+fun bar3(): @JvmWildcard A<X, X> = TODO()
+
+// A<X, X>
+val p1: A<in X, out X> = TODO()
+// A<java.lang.Object, Y>
+val p2: A<Any, Y> = TODO()
+// A<?, ?>
+val p3: A<*, *> = TODO()
+// B<X>
+val p4: B<X> = TODO()
+// B<? super X>
+val p5: B<in X> = TODO()
+// B<? extends X>
+val p6: B<out X> = TODO()
+// B<?>
+val p7: B<*> = TODO()
+// B<A<X, Y>>
+val p8: B<A<X, out Y>>
+
+// void foo(A<? super X, ? extends X>, A<java.lang.Object, Y>, A<?, ?>, B<X>, B<? super X>, B<? extends X>, B<?>, B<A<X, Y>>);
+fun foo(
+ v1: A<X, X>,
+ v2: A<Any, Y>,
+ v3: A<*, *>,
+ v4: B<X>,
+ v5: B<in X>,
+ v6: B<out X>,
+ v7: B<*>,
+ v8: B<A<X, out Y>>,
+): Unit = Unit
+
+// A<X, X>
+fun r1(): A<X, X> = TODO()
+// A<java.lang.Object, Y>
+fun r2(): A<Any, Y> = TODO()
+// A<?, ?>
+fun r3(): A<*, *> = TODO()
+// B<X>
+fun r4(): B<X> = TODO()
+// B<? super X>
+fun r5(): B<in X> = TODO()
+// B<? extends X>
+fun r6(): B<out X> = TODO()
+// B<?>
+fun r7(): B<*> = TODO()
+// B<A<X, Y>>
+fun r8(): B<A<X, out Y>> = TODO()
+
+// extends A<X, X>
+class C1() : A<X, X>()
+// A<java.lang.Object, Y>
+class C2() : A<Any, Y>()
+// B<X>
+class C3() : B<X>()
+// B<A<? super X, ? extends Y>>
+class C4() : B<A<X, out Y>>()
diff --git a/test-utils/testData/api/errorTypes.kt b/test-utils/testData/api/errorTypes.kt
new file mode 100644
index 00000000..ab2a4afe
--- /dev/null
+++ b/test-utils/testData/api/errorTypes.kt
@@ -0,0 +1,44 @@
+/*
+ * 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: ErrorTypeProcessor
+// EXPECTED:
+// ERROR TYPE
+// kotlin.collections.Map
+// kotlin.String
+// ERROR TYPE
+// errorInComponent is assignable from errorAtTop: false
+// errorInComponent is assignable from class C: false
+// Any is assignable from errorInComponent: false
+// class C is assignable from errorInComponent: false
+// Any is assignable from class C: true
+// Cls's super type is Error type: true
+// Cls's annotation is Error type: true
+// END
+// FILE: a.kt
+class C {
+ val errorAtTop = mutableMapOf<String, NonExistType, Int>()
+ val errorInComponent: Map<String, NonExistType>
+}
+
+// FILE: Cls.java
+
+@NonExistingAnnotation
+public class Cls extends NonExistType {
+
+}
diff --git a/test-utils/testData/api/functionTypeAlias.kt b/test-utils/testData/api/functionTypeAlias.kt
new file mode 100644
index 00000000..1e9f775a
--- /dev/null
+++ b/test-utils/testData/api/functionTypeAlias.kt
@@ -0,0 +1,41 @@
+/*
+ * 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: FunctionTypeAliasProcessor
+// EXPECTED:
+// Function1<String, String> ?= Function1<String, String> : true / true
+// Function1<String, String> ?= String : false / false
+// Function1<String, String> ?= [typealias F] : false / false
+// Function1<String, String> ?= [typealias Foo] : true / true
+// String ?= Function1<String, String> : false / false
+// String ?= String : true / true
+// String ?= [typealias F] : true / true
+// String ?= [typealias Foo] : false / false
+// [typealias F] ?= Function1<String, String> : false / false
+// [typealias F] ?= String : true / true
+// [typealias F] ?= [typealias F] : true / true
+// [typealias F] ?= [typealias Foo] : false / false
+// [typealias Foo] ?= Function1<String, String> : true / true
+// [typealias Foo] ?= String : false / false
+// [typealias Foo] ?= [typealias F] : false / false
+// [typealias Foo] ?= [typealias Foo] : true / true
+// END
+
+typealias F = String
+val y: Foo = { it }
+typealias Foo = (F) -> String
diff --git a/test-utils/testData/api/functionTypeAnnotation.kt b/test-utils/testData/api/functionTypeAnnotation.kt
new file mode 100644
index 00000000..900a700d
--- /dev/null
+++ b/test-utils/testData/api/functionTypeAnnotation.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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: FunctionTypeAnnotationProcessor
+// EXPECTED:
+// strExt0: Function1 @ExtensionFunctionType
+// strExt1: Function2 @ExtensionFunctionType
+// strWithAnnoExt0: Function1 @A, @ExtensionFunctionType
+// strWithAnnoExt1: Function2 @A, @ExtensionFunctionType
+// END
+// FILE: a.kt
+annotation class A
+
+val strExt0: String.() -> Unit = TODO()
+val strExt1: String.(Int) -> Unit = TODO()
+val strWithAnnoExt0: @A String.() -> Unit = TODO()
+val strWithAnnoExt1: @A String.(@A Int) -> Unit = TODO()
diff --git a/test-utils/testData/api/functionTypes.kt b/test-utils/testData/api/functionTypes.kt
new file mode 100644
index 00000000..69f8366f
--- /dev/null
+++ b/test-utils/testData/api/functionTypes.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2021 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: 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
+// END
+
+@file:Suppress("Boolean", "Byte", "Int", "Short", "Double", "Float", "Unit", "Suppress", "C")
+
+class C {
+ fun foo(): Boolean = true
+ suspend fun bar(): Int = 0
+ val vfoo = ::foo
+ val vbar = ::bar
+}
+
+fun foo() = Unit
+suspend fun bar() = Unit
+
+val a: () -> Unit = TODO()
+val b: (Int) -> Unit = TODO()
+val c: () -> Byte = TODO()
+val d: (Short, Float) -> Double = TODO()
+
+val e = C().vfoo
+val f = C().vbar
+val g = C::foo
+val h = C::bar
+
+val i: Int.() -> Boolean = TODO()
+val j: suspend Boolean.() -> Int = TODO()
+
+val k: suspend () -> Unit = TODO()
+val l: suspend (Int) -> Unit = TODO()
+val m: suspend () -> Byte = TODO()
+val n: suspend (Short, Float) -> Double = TODO()
+
+val o = ::foo
+val p = ::bar
diff --git a/test-utils/testData/api/getAnnotationByTypeWithInnerDefault.kt b/test-utils/testData/api/getAnnotationByTypeWithInnerDefault.kt
new file mode 100644
index 00000000..56346813
--- /dev/null
+++ b/test-utils/testData/api/getAnnotationByTypeWithInnerDefault.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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: GetAnnotationByTypeProcessor
+// EXPECTED:
+// com.google.devtools.ksp.processor.KotlinAnnotationWithInnerDefaults.InnerAnnotation[innerAnnotationDefault=7, moreInnerAnnotation=com.google.devtools.ksp.processor.KotlinAnnotationWithInnerDefaults.InnerAnnotation.MoreInnerAnnotation[moreInnerAnnotationDefault=OK]]
+// END
+// MODULE: lib
+// FILE: KotlinAnnotationWithInnerDefaults.kt
+package com.google.devtools.ksp.processor
+annotation class KotlinAnnotationWithInnerDefaults(
+ val innerAnnotationVal: InnerAnnotation = InnerAnnotation(innerAnnotationDefault = 7)
+) {
+ annotation class InnerAnnotation(
+ val innerAnnotationDefault: Int,
+ val moreInnerAnnotation: MoreInnerAnnotation = MoreInnerAnnotation("OK")
+ ) {
+ annotation class MoreInnerAnnotation(val moreInnerAnnotationDefault: String)
+ }
+}
+
+// MODULE: main(lib)
+// FILE: com/google/devtools/ksp/processor/a.kt
+package com.google.devtools.ksp.processor
+
+@KotlinAnnotationWithInnerDefaults
+class A
diff --git a/test-utils/testData/api/getByName.kt b/test-utils/testData/api/getByName.kt
new file mode 100644
index 00000000..51f826b0
--- /dev/null
+++ b/test-utils/testData/api/getByName.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: GetByNameProcessor
+// EXPECTED:
+// all success
+// END
+// MODULE: lib1
+// FILE: foo.kt
+package lib1
+
+open class Foo {
+ fun lib1MemberFun() = 1
+ fun overload(a: Int) = "Overload"
+ fun overload() = "Overload"
+ val lib1MemberProp = 1.0
+
+ class FooNested {}
+}
+
+fun lib1TopFun(): Int {
+ return 1
+}
+
+val lib1TopProp = "1"
+
+// FILE: Bar.java
+package lib1;
+
+class Bar {
+ public int lib1JavaMemberFun() {
+ return 1;
+ }
+}
+
+// MODULE: lib2
+// FILE: foo.kt
+package lib2
+
+class Foo {
+ fun lib2MemberFun() = 1
+ val lib2MemberProp = 1.0
+}
+
+// MODULE: main(lib1, lib2)
+// FILE: a.kt
+package source
+
+class FooInSource {
+ fun sourceMemberFun() = 1
+ val sourceMemberProp = 1.0
+ class FooInSourceNested
+}
+
+val propInSource = 1
+// FILE: main.kt
+package main
+import lib1.Foo
+
+class KotlinMain : Foo {
+ fun lib1MemberFun(a: Int) = 1
+}
+
diff --git a/test-utils/testData/api/getPackage.kt b/test-utils/testData/api/getPackage.kt
new file mode 100644
index 00000000..537be348
--- /dev/null
+++ b/test-utils/testData/api/getPackage.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: GetPackageProcessor
+// EXPECTED:
+// symbols from package lib1
+// lib1.FooInSource KOTLIN
+// lib1.propInSource KOTLIN
+// lib1.Bar JAVA_LIB
+// lib1.Foo KOTLIN_LIB
+// lib1.funcFoo KOTLIN_LIB
+// symbols from package lib2
+// lib2.Foo KOTLIN_LIB
+// lib2.a KOTLIN_LIB
+// symbols from package main.test
+// main.test.KotlinMain KOTLIN
+// main.test.C JAVA
+// main.test.D JAVA
+// END
+
+// MODULE: lib1
+// FILE: foo.kt
+package lib1
+
+class Foo
+
+fun funcFoo(): Int {
+ return 1
+}
+
+// FILE: Bar.java
+package lib1;
+
+class Bar {}
+
+// MODULE: lib2
+// FILE: foo.kt
+package lib2
+
+class Foo
+
+val a = 0
+
+// FILE: Bar.java
+
+class Bar {}
+
+// MODULE: main(lib1, lib2)
+// FILE: a.kt
+package lib1
+class FooInSource
+
+val propInSource = 1
+// FILE: main.kt
+package main.test
+
+class KotlinMain
+
+// FILE: main/test/C.java
+package main.test;
+
+public class C {
+
+}
+
+class D {
+
+}
+
+// FILE: wrongDir/K.java
+package main;
+
+public class K {
+
+}
+
+class KK {}
+
+
+// FILE: main/test/main/test/L.java
+package main.test;
+
+public class L {
+
+}
diff --git a/test-utils/testData/api/getSymbolsFromAnnotation.kt b/test-utils/testData/api/getSymbolsFromAnnotation.kt
new file mode 100644
index 00000000..587e3f59
--- /dev/null
+++ b/test-utils/testData/api/getSymbolsFromAnnotation.kt
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: GetSymbolsFromAnnotationProcessor
+// EXPECTED:
+// ==== Anno superficial====
+// Foo:KSClassDeclaration
+// <init>:KSFunctionDeclaration
+// constructorParameterFoo:KSValueParameter
+// param:KSValueParameter
+// constructorParameterFoo:KSPropertyDeclaration
+// propertyFoo:KSPropertyDeclaration
+// functionFoo:KSFunctionDeclaration
+// p1:KSValueParameter
+// Bar:KSClassDeclaration
+// Baz:KSClassDeclaration
+// Burp:KSClassDeclaration
+// Flux:KSTypeAlias
+// ==== Anno in depth ====
+// Foo:KSClassDeclaration
+// <init>:KSFunctionDeclaration
+// constructorParameterFoo:KSValueParameter
+// param:KSValueParameter
+// constructorParameterFoo:KSPropertyDeclaration
+// propertyFoo:KSPropertyDeclaration
+// functionFoo:KSFunctionDeclaration
+// p1:KSValueParameter
+// local:KSPropertyDeclaration
+// Bar:KSClassDeclaration
+// Baz:KSClassDeclaration
+// Burp:KSClassDeclaration
+// Flux:KSTypeAlias
+// ==== Bnno superficial====
+// File: Foo.kt:KSFile
+// <init>:KSFunctionDeclaration
+// propertyFoo.getter():KSPropertyAccessorImpl
+// p2:KSValueParameter
+// ==== Bnno in depth ====
+// File: Foo.kt:KSFile
+// <init>:KSFunctionDeclaration
+// propertyFoo.getter():KSPropertyAccessorImpl
+// p2:KSValueParameter
+// ==== A1 superficial====
+// Foo:KSClassDeclaration
+// <init>:KSFunctionDeclaration
+// constructorParameterFoo:KSValueParameter
+// param:KSValueParameter
+// constructorParameterFoo:KSPropertyDeclaration
+// propertyFoo:KSPropertyDeclaration
+// functionFoo:KSFunctionDeclaration
+// p1:KSValueParameter
+// Bar:KSClassDeclaration
+// Baz:KSClassDeclaration
+// Burp:KSClassDeclaration
+// Flux:KSTypeAlias
+// ==== A1 in depth ====
+// Foo:KSClassDeclaration
+// <init>:KSFunctionDeclaration
+// constructorParameterFoo:KSValueParameter
+// param:KSValueParameter
+// constructorParameterFoo:KSPropertyDeclaration
+// propertyFoo:KSPropertyDeclaration
+// functionFoo:KSFunctionDeclaration
+// p1:KSValueParameter
+// local:KSPropertyDeclaration
+// Bar:KSClassDeclaration
+// Baz:KSClassDeclaration
+// Burp:KSClassDeclaration
+// Flux:KSTypeAlias
+// ==== A2 superficial====
+// Foo:KSClassDeclaration
+// <init>:KSFunctionDeclaration
+// constructorParameterFoo:KSValueParameter
+// param:KSValueParameter
+// constructorParameterFoo:KSPropertyDeclaration
+// propertyFoo:KSPropertyDeclaration
+// functionFoo:KSFunctionDeclaration
+// p1:KSValueParameter
+// Bar:KSClassDeclaration
+// Baz:KSClassDeclaration
+// Burp:KSClassDeclaration
+// Flux:KSTypeAlias
+// ==== A2 in depth ====
+// Foo:KSClassDeclaration
+// <init>:KSFunctionDeclaration
+// constructorParameterFoo:KSValueParameter
+// param:KSValueParameter
+// constructorParameterFoo:KSPropertyDeclaration
+// propertyFoo:KSPropertyDeclaration
+// functionFoo:KSFunctionDeclaration
+// p1:KSValueParameter
+// local:KSPropertyDeclaration
+// Bar:KSClassDeclaration
+// Baz:KSClassDeclaration
+// Burp:KSClassDeclaration
+// Flux:KSTypeAlias
+// ==== Cnno in depth ====
+// constructorParameterFoo:KSValueParameter
+// <set-?>:KSValueParameter
+// x:KSValueParameter
+// x:KSPropertyDeclaration
+// END
+//FILE: annotations.kt
+annotation class Anno
+annotation class Bnno
+annotation class Cnno
+typealias A1 = Anno
+typealias A2 = A1
+
+//FILE: Foo.kt
+@file:Bnno
+
+import Anno
+import Anno as A3
+
+@Anno
+class Foo @Anno constructor(@Anno @param:Cnno val constructorParameterFoo: Int, @Anno param: Int){
+ @Bnno constructor() {
+
+ }
+
+ @Anno
+ val propertyFoo: String
+ @Bnno get() = TODO()
+
+ @Anno
+ fun functionFoo(@Anno p1: Int, @Bnno p2: Int) {
+ @Anno val local = 1
+ }
+
+ @setparam:Cnno
+ var a = 1
+}
+
+class C(@Cnno val x: Int)
+
+@A1
+class Bar
+
+@A2
+class Baz
+
+@A3
+class Burp
+
+@Anno
+typealias Flux = String
diff --git a/test-utils/testData/api/hello.kt b/test-utils/testData/api/hello.kt
new file mode 100644
index 00000000..f8949c69
--- /dev/null
+++ b/test-utils/testData/api/hello.kt
@@ -0,0 +1,116 @@
+/*
+ * 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: HelloProcessor
+// EXPECTED:
+// 8
+// AClass
+// Bar.BBB
+// Bar.list
+// C
+// C.f
+// C.javaFun
+// test.Foo
+// test.ITF
+// END
+//FILE: a.kt
+package test
+annotation class Anno
+
+
+@Anno
+class Foo() {
+ val k = "123"
+ var a : String = "123"
+ val aaa : (Int) -> Int = { a -> 1 }
+ fun bar(): Int {
+// val aa = 1234
+ return 3
+ }
+}
+
+@Anno
+interface ITF<T> {
+ fun fooITF() = 1
+}
+
+//FILE: b.kt
+import test.Anno
+import test.ITF
+
+class Bar<out S, out D>() : ITF<D> {
+ @Anno
+ val list : List<Int>? = null
+ val funInObj = foo()
+ open internal fun foo(c: C, dd: () -> D): Int {
+ val a = 1
+// fun <TTT> foo(c: C, dd: () -> TTT): Int {
+// return 1
+// }
+ return 1
+ }
+ @Anno
+ class BBB {
+ fun <TTA: String> fofo(c: C, dd: () -> TTA): Int {
+ return 1
+ }
+ fun <TTA: Int> fofofo(c: C, dd: () -> TTA): Int {
+ return 1
+ }
+ }
+ val a = 1
+
+ val kk
+ get() = 1
+
+ companion object {
+ val s = 1
+ fun foo() = 123
+ }
+}
+
+//FILE: c.kt
+import test.Anno
+
+@Anno
+class AClass(val a: Int, val b: String, c: Double) {
+ fun foo() = a + b.length + c
+}
+
+fun <D> foo(c: C, dd: () -> D) = 1
+
+class CC: C() {}
+
+// FILE: C.java
+import java.util.List;
+import java.util.ArrayList;
+import test.Foo;
+import test.ITF;
+import test.Anno;
+
+@Anno
+class C {
+ @Anno
+ public Foo f = new Foo();
+ List<? extends ITF> list = new ArrayList<>();
+
+ @Anno
+ public String javaFun() {
+ return f.k;
+ }
+}
diff --git a/test-utils/testData/api/implicitElements.kt b/test-utils/testData/api/implicitElements.kt
new file mode 100644
index 00000000..88d670c5
--- /dev/null
+++ b/test-utils/testData/api/implicitElements.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: ImplicitElementProcessor
+// EXPECTED:
+// <init>; origin: SYNTHETIC
+// synthetic constructor for Cls
+// <null>
+// <null>
+// <init>,<init>,<init>
+// readOnly.get(): SYNTHETIC annotations from property: GetAnno
+// readOnly.getter.owner: readOnly: KOTLIN
+// readWrite.get(): KOTLIN
+// readWrite.set(): SYNTHETIC annotations from property: SetAnno
+// <init>
+// comp1.get(): SYNTHETIC
+// comp2.get(): SYNTHETIC
+// comp2.set(): SYNTHETIC
+// GetAnno
+// <init>
+// synthetic constructor for ImplictConstructorJava
+// END
+// FILE: a.kt
+annotation class GetAnno
+annotation class SetAnno
+
+class Cls {
+ @get:GetAnno
+ val readOnly: Int = 1
+
+ @set:SetAnno
+ var readWrite: Int = 2
+ get() = 1
+}
+
+data class Data(@get:GetAnno val comp1: Int, var comp2: Int)
+
+class ClassWithoutImplicitPrimaryConstructor : ITF {
+ constructor(x: Int)
+}
+
+interface ITF
+
+// FILE: JavaClass.java
+public class JavaClass {
+ public JavaClass() { this(1); }
+ public JavaClass(int a) { this(a, "ok"); }
+ public JavaClass(int a, String s) { }
+}
+
+// FILE:ImplictConstructorJava.java
+
+public class ImplictConstructorJava {
+
+} \ No newline at end of file
diff --git a/test-utils/testData/api/implicitPropertyAccessors.kt b/test-utils/testData/api/implicitPropertyAccessors.kt
new file mode 100644
index 00000000..af885296
--- /dev/null
+++ b/test-utils/testData/api/implicitPropertyAccessors.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: ImplicitPropertyAccessorProcessor
+// EXPECTED:
+// Int
+// String
+// <set-?>
+// String
+// END
+// FILE: a.kt
+
+class Foo {
+ val privateGetterVal: Int
+ private get
+
+ var privateGetterVar: String
+ set
+ private get
+}
diff --git a/test-utils/testData/api/inheritedTypeAlias.kt b/test-utils/testData/api/inheritedTypeAlias.kt
new file mode 100644
index 00000000..9fa622c3
--- /dev/null
+++ b/test-utils/testData/api/inheritedTypeAlias.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: InheritedTypeAliasProcessor
+// EXPECTED:
+// sub: arg :INVARIANT Float
+// sub: prop :INVARIANT Int
+// super: arg :INVARIANT Float
+// super: prop :INVARIANT Int
+// END
+
+typealias AliasMap<T> = Map<String, T>
+typealias AliasFun<T> = (T) -> Double
+
+
+interface Sub : Super
+
+
+interface Super {
+ val prop: AliasMap<Int>
+ fun foo(arg: AliasFun<Float>)
+}
diff --git a/test-utils/testData/api/innerTypes.kt b/test-utils/testData/api/innerTypes.kt
new file mode 100644
index 00000000..ee3c5d80
--- /dev/null
+++ b/test-utils/testData/api/innerTypes.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2021 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: InnerTypeProcessor
+// EXPECTED:
+// C1<*>: [C1<STAR Any>]
+// C1<Int>: [C1<INVARIANT Int>]
+// C2<*, *>: [C1.C2<STAR Any>, C1<STAR Any>]
+// C2<Short, Int>: [C1.C2<INVARIANT Short>, C1<INVARIANT Int>]
+// C3<*, *, *>: [C1.C2.C3<STAR Any>, C1.C2<STAR Any>, C1<STAR Any>]
+// C3<Byte, Short, Int>: [C1.C2.C3<INVARIANT Byte>, C1.C2<INVARIANT Short>, C1<INVARIANT Int>]
+// C4<*>: [C1.C4<STAR Any>]
+// C4<Double>: [C1.C4<INVARIANT Double>]
+// C5<*, *>: [C1.C4.C5<STAR Any>, C1.C4<STAR Any>]
+// C5<Float, Double>: [C1.C4.C5<INVARIANT Float>, C1.C4<INVARIANT Double>]
+// END
+
+@file:Suppress("Byte", "Int", "Short", "Double", "Float", "Suppress", "Any")
+
+class C1<T1> {
+ inner class C2<T2> {
+ inner class C3<T3> {
+
+ }
+ }
+
+ class C4<T4> {
+ inner class C5<T5>
+ }
+}
+
+val c1 = C1<Int>()
+val c2 = c1.C2<Short>()
+val c3 = c2.C3<Byte>()
+val c4 = C1.C4<Double>()
+val c5 = c4.C5<Float>()
diff --git a/test-utils/testData/api/interfaceWithDefault.kt b/test-utils/testData/api/interfaceWithDefault.kt
new file mode 100644
index 00000000..75a005f1
--- /dev/null
+++ b/test-utils/testData/api/interfaceWithDefault.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: DefaultFunctionProcessor
+// EXPECTED:
+// funLiteral: false
+// funWithBody: false
+// emptyFun: true
+// foo: false
+// bar: true
+// iterator: true
+// equals: false
+// interfaceProperty: isAbstract: true: isMutable: false
+// interfaceVar: isAbstract: true: isMutable: true
+// nonAbstractInterfaceProp: isAbstract: false: isMutable: false
+// B: true
+// parameterVal: isAbstract: false: isMutable: false
+// parameterVar: isAbstract: false: isMutable: true
+// abstractVar: isAbstract: true: isMutable: true
+// abstractProperty: isAbstract: true: isMutable: false
+// a: false
+// normalField: isMutable: true
+// finalField: isMutable: false
+// END
+// FILE: a.kt
+interface KTInterface: Sequence<String> {
+ fun funLiteral() = 1
+
+ fun funWithBody(): Int {
+ return 1
+ }
+
+ fun emptyFun()
+
+ val interfaceProperty: String
+
+ var interfaceVar: Int
+
+ val nonAbstractInterfaceProp: Int
+ get() = 1
+}
+
+abstract class B(val parameterVal: String, var parameterVar: String) {
+ abstract var abstractVar: String
+ abstract val abstractProperty: String
+ val a: String = "str"
+}
+
+// FILE: C.java
+interface C {
+ default int foo() {
+ return 1;
+ }
+
+ int bar()
+}
+
+// FILE: D.java
+
+class D {
+ int normalField;
+
+ final int finalField;
+}
diff --git a/test-utils/testData/api/javaAnnotatedUtil.kt b/test-utils/testData/api/javaAnnotatedUtil.kt
new file mode 100644
index 00000000..e6da243a
--- /dev/null
+++ b/test-utils/testData/api/javaAnnotatedUtil.kt
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: AnnotatedUtilProcessor
+// EXPECTED:
+// Test: OnlyTestAnnotation
+// Test: ParametersTestAnnotationWithValuesTest
+// IsPresent: class com.google.devtools.ksp.processor.ParametersTestAnnotation
+// ByType: com.google.devtools.ksp.processor.ParametersTestAnnotation[booleanValue=true, byteValue=5, shortValue=202, charValue=k, doubleValue=5.12, floatValue=123.3, intValue=2, longValue=4, stringValue=someValue, kClassValue=class java.lang.Throwable, enumValue=VALUE1]
+// Test: ParametersTestAnnotationWithIntegerLiteralValuesTest
+// IsPresent: class com.google.devtools.ksp.processor.ParametersTestAnnotation
+// ByType: com.google.devtools.ksp.processor.ParametersTestAnnotation[booleanValue=true, byteValue=5, shortValue=202, charValue=k, doubleValue=5.0, floatValue=123.0, intValue=2, longValue=4, stringValue=someValue, kClassValue=class java.lang.Throwable, enumValue=VALUE1]
+// Test: ParametersTestAnnotationWithDefaultsTest
+// IsPresent: class com.google.devtools.ksp.processor.ParametersTestAnnotation
+// ByType: com.google.devtools.ksp.processor.ParametersTestAnnotation[booleanValue=false, byteValue=2, shortValue=3, charValue=b, doubleValue=4.0, floatValue=5.0, intValue=6, longValue=7, stringValue=emptystring, kClassValue=interface com.google.devtools.ksp.processor.ParametersTestAnnotation, enumValue=NONE]
+// ByType: com.google.devtools.ksp.processor.ParametersTestAnnotation[booleanValue=false, byteValue=2, shortValue=3, charValue=b, doubleValue=4.0, floatValue=5.0, intValue=6, longValue=7, stringValue=emptystring, kClassValue=interface com.google.devtools.ksp.processor.ParametersTestAnnotation, enumValue=NONE]
+// Test: ParametersTestWithNegativeDefaultsAnnotationTest
+// IsPresent: class com.google.devtools.ksp.processor.ParametersTestWithNegativeDefaultsAnnotation
+// ByType: com.google.devtools.ksp.processor.ParametersTestWithNegativeDefaultsAnnotation[byteValue=-2, shortValue=-3, doubleValue=-4.0, floatValue=-5.0, intValue=-6, longValue=-7]
+// ByType: com.google.devtools.ksp.processor.ParametersTestWithNegativeDefaultsAnnotation[byteValue=-2, shortValue=-3, doubleValue=-4.0, floatValue=-5.0, intValue=-6, longValue=-7]
+// Test: ParameterArraysTestAnnotationWithDefaultTest
+// IsPresent: class com.google.devtools.ksp.processor.ParameterArraysTestAnnotation
+// ByType: ParameterArraysTestAnnotation[booleanArrayValue=[true, false],byteArrayValue=[-2, 4],shortArrayValue=[-1, 2, 3],charArrayValue=[a, b, c],doubleArrayValue=[1.1, 2.2, 3.3],floatArrayValue=[1.0, 2.0, 3.3],intArrayValue=[1, 2, 4, 8, 16],longArrayValue=[1, 2, 4, 8, 16, 32],stringArrayValue=[first, second, third],kClassArrayValue=[class kotlin.Throwable, class com.google.devtools.ksp.processor.ParametersTestAnnotation],enumArrayValue=[VALUE1, VALUE2, VALUE1, VALUE2]]
+// Test: AnnotationWithinAnAnnotationTest
+// IsPresent: class com.google.devtools.ksp.processor.OuterAnnotation
+// ByType: com.google.devtools.ksp.processor.OuterAnnotation[innerAnnotation=com.google.devtools.ksp.processor.InnerAnnotation[value=hello from the other side]]
+// END
+// FILE: com/google/devtools/ksp/processor/A.java
+package com.google.devtools.ksp.processor;
+
+import kotlin.reflect.KClass
+
+public class A {}
+
+
+public @interface Test {}
+
+public @interface ParametersTestAnnotation {
+ Boolean booleanValue() default false;
+ Byte byteValue() default 2;
+ Short shortValue() default 3;
+ Char charValue() default 'b';
+ Double doubleValue() default 4.0;
+ Float floatValue() default 5.0f;
+ Int intValue() default 6;
+ Long longValue() default 7L;
+ String stringValue() default "emptystring";
+ Class<?> kClassValue() default ParametersTestAnnotation.class;
+ TestEnum enumValue() default TestEnum.NONE;
+}
+
+public @interface ParametersTestWithNegativeDefaultsAnnotation {
+ Byte byteValue() default -2;
+ Short shortValue() default -3;
+ Double doubleValue() default -4.0;
+ Float floatValue() default -5.0f;
+ Int intValue() default -6;
+ Long longValue() default -7L;
+}
+
+public @interface ParameterArraysTestAnnotation {
+ boolean[] booleanArrayValue();
+ byte[] byteArrayValue() default { };
+ short[] shortArrayValue() default { };
+ char[] charArrayValue() default { };
+ double[] doubleArrayValue() default { };
+ float[] floatArrayValue() default { };
+ int[] intArrayValue() default { };
+ long[] longArrayValue() default { };
+ string[] stringArrayValue() default { };
+ Class[] kClassArrayValue() default { };
+ TestEnum[] enumArrayValue() default { };
+}
+
+public enum TestEnum {
+ NONE, VALUE1, VALUE2;
+}
+
+public @interface InnerAnnotation {
+ String value() default "defaultValue";
+}
+
+public @interface OuterAnnotation {
+ InnerAnnotation innerAnnotation() default InnerAnnotation();
+}
+
+/////////////////////////////////////////////////////////
+// Tests
+/////////////////////////////////////////////////////////
+
+@Test
+@Test
+public class OnlyTestAnnotation {}
+
+@ParametersTestAnnotation(
+ booleanValue = true,
+ byteValue = 5,
+ shortValue = 202,
+ charValue = 'k',
+ doubleValue = 5.12,
+ floatValue = 123.3f,
+ intValue = 2,
+ longValue = 4L,
+ stringValue = "someValue",
+ kClassValue = java.lang.Throwable.class,
+ enumValue = TestEnum.VALUE1
+)
+@Test
+public class ParametersTestAnnotationWithValuesTest {}
+
+@ParametersTestAnnotation(
+ booleanValue = true,
+ byteValue = 5,
+ shortValue = 202,
+ charValue = 'k',
+ doubleValue = 5,
+ floatValue = 123,
+ intValue = 2,
+ longValue = 4,
+ stringValue = "someValue",
+ kClassValue = java.lang.Throwable.class,
+ enumValue = TestEnum.VALUE1
+)
+@Test
+public class ParametersTestAnnotationWithIntegerLiteralValuesTest {}
+
+@ParametersTestAnnotation
+@ParametersTestAnnotation
+@Test
+public class ParametersTestAnnotationWithDefaultsTest {}
+
+@ParametersTestWithNegativeDefaultsAnnotation
+@ParametersTestWithNegativeDefaultsAnnotation
+@Test
+public class ParametersTestWithNegativeDefaultsAnnotationTest {}
+
+@ParameterArraysTestAnnotation(
+ booleanArrayValue = {true, false},
+ byteArrayValue = {-2, 4},
+ shortArrayValue = {-1, 2, 3},
+ charArrayValue = {'a', 'b', 'c'},
+ doubleArrayValue = {1.1, 2.2, 3.3},
+ floatArrayValue = {1.0f, 2.0f, 3.3f},
+ intArrayValue = {1, 2, 4, 8, 16},
+ longArrayValue = {1L, 2L, 4L, 8L, 16, 32L},
+ stringArrayValue = {"first", "second", "third"},
+ kClassArrayValue = {java.lang.Throwable.class, ParametersTestAnnotation.class},
+ enumArrayValue = {TestEnum.VALUE1, TestEnum.VALUE2, TestEnum.VALUE1, TestEnum.VALUE2}
+)
+@Test
+public class ParameterArraysTestAnnotationWithDefaultTest {}
+
+@OuterAnnotation(innerAnnotation = @InnerAnnotation(value = "hello from the other side"))
+@Test
+public class AnnotationWithinAnAnnotationTest {}
+
+// FILE: Annotations.kt
diff --git a/test-utils/testData/api/javaModifiers.kt b/test-utils/testData/api/javaModifiers.kt
new file mode 100644
index 00000000..04aa1c0d
--- /dev/null
+++ b/test-utils/testData/api/javaModifiers.kt
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: JavaModifierProcessor
+// EXPECTED:
+// C: ABSTRACT PUBLIC : ABSTRACT PUBLIC
+// C.staticStr: PRIVATE : PRIVATE
+// C.s1: FINAL JAVA_TRANSIENT : FINAL JAVA_TRANSIENT
+// C.i1: JAVA_STATIC JAVA_VOLATILE PROTECTED : JAVA_STATIC JAVA_VOLATILE PROTECTED
+// C.NestedC: JAVA_STATIC PUBLIC : JAVA_STATIC PUBLIC
+// NestedC.<init>: FINAL PUBLIC : FINAL PUBLIC
+// C.InnerC: PUBLIC : PUBLIC
+// InnerC.<init>: FINAL PUBLIC : FINAL PUBLIC
+// C.intFun: JAVA_DEFAULT JAVA_SYNCHRONIZED : JAVA_DEFAULT JAVA_SYNCHRONIZED
+// C.foo: ABSTRACT JAVA_STRICT : ABSTRACT JAVA_STRICT
+// C.<init>: FINAL PUBLIC : FINAL PUBLIC
+// OuterJavaClass: PUBLIC : PUBLIC
+// OuterJavaClass.staticPublicField: JAVA_STATIC PUBLIC : JAVA_STATIC PUBLIC
+// OuterJavaClass.staticPackageProtectedField: JAVA_STATIC : JAVA_STATIC
+// OuterJavaClass.staticProtectedField: JAVA_STATIC PROTECTED : JAVA_STATIC PROTECTED
+// OuterJavaClass.staticPrivateField: JAVA_STATIC PRIVATE : JAVA_STATIC PRIVATE
+// OuterJavaClass.InnerJavaClass: PUBLIC : PUBLIC
+// InnerJavaClass.<init>: FINAL PUBLIC : FINAL PUBLIC
+// OuterJavaClass.NestedJavaClass: JAVA_STATIC PUBLIC : JAVA_STATIC PUBLIC
+// NestedJavaClass.<init>: FINAL PUBLIC : FINAL PUBLIC
+// OuterJavaClass.staticPublicMethod: JAVA_STATIC PUBLIC : JAVA_STATIC PUBLIC
+// OuterJavaClass.staticPackageProtectedMethod: JAVA_STATIC : JAVA_STATIC
+// OuterJavaClass.staticProtectedMethod: JAVA_STATIC PROTECTED : JAVA_STATIC PROTECTED
+// OuterJavaClass.staticPrivateMethod: JAVA_STATIC PRIVATE : JAVA_STATIC PRIVATE
+// OuterJavaClass.<init>: FINAL PUBLIC : FINAL PUBLIC
+// OuterKotlinClass: OPEN : PUBLIC
+// OuterKotlinClass.InnerKotlinClass: INNER : FINAL PUBLIC
+// InnerKotlinClass.<init>: FINAL PUBLIC : FINAL PUBLIC
+// OuterKotlinClass.NestedKotlinClass: OPEN : PUBLIC
+// NestedKotlinClass.<init>: FINAL PUBLIC : FINAL PUBLIC
+// OuterKotlinClass.Companion: : FINAL JAVA_STATIC PUBLIC
+// Companion.companionMethod: : FINAL PUBLIC
+// Companion.companionField: CONST : FINAL PUBLIC
+// Companion.privateCompanionMethod: PRIVATE : FINAL PRIVATE
+// Companion.privateCompanionField: PRIVATE : FINAL PRIVATE
+// Companion.jvmStaticCompanionMethod: : FINAL JAVA_STATIC PUBLIC
+// Companion.jvmStaticCompanionField: : FINAL JAVA_STATIC PUBLIC
+// Companion.customJvmStaticCompanionMethod: : FINAL PUBLIC
+// Companion.customJvmStaticCompanionField: : FINAL PUBLIC
+// Companion.<init>: FINAL PUBLIC : FINAL PUBLIC
+// OuterKotlinClass.transientProperty: : FINAL JAVA_TRANSIENT PUBLIC
+// OuterKotlinClass.volatileProperty: : FINAL JAVA_VOLATILE PUBLIC
+// OuterKotlinClass.strictfpFun: : FINAL JAVA_STRICT PUBLIC
+// OuterKotlinClass.synchronizedFun: : FINAL JAVA_SYNCHRONIZED PUBLIC
+// OuterKotlinClass.<init>: FINAL PUBLIC : FINAL PUBLIC
+// DependencyOuterJavaClass: OPEN PUBLIC : PUBLIC
+// DependencyOuterJavaClass.DependencyNestedJavaClass: OPEN PUBLIC : PUBLIC
+// DependencyNestedJavaClass.<init>: FINAL PUBLIC : FINAL PUBLIC
+// DependencyOuterJavaClass.DependencyInnerJavaClass: INNER OPEN PUBLIC : PUBLIC
+// DependencyInnerJavaClass.<init>: FINAL PUBLIC : FINAL PUBLIC
+// DependencyOuterJavaClass.synchronizedFun: JAVA_SYNCHRONIZED OPEN : JAVA_SYNCHRONIZED
+// DependencyOuterJavaClass.strictfpFun: JAVA_STRICT OPEN : JAVA_STRICT
+// DependencyOuterJavaClass.transientField: FINAL JAVA_TRANSIENT : FINAL JAVA_TRANSIENT
+// DependencyOuterJavaClass.volatileField: FINAL JAVA_VOLATILE : FINAL JAVA_VOLATILE
+// DependencyOuterJavaClass.staticPublicMethod: JAVA_STATIC PUBLIC : JAVA_STATIC PUBLIC
+// DependencyOuterJavaClass.staticPackageProtectedMethod: JAVA_STATIC : JAVA_STATIC
+// DependencyOuterJavaClass.staticProtectedMethod: JAVA_STATIC PROTECTED : JAVA_STATIC PROTECTED
+// DependencyOuterJavaClass.staticPrivateMethod: JAVA_STATIC PRIVATE : JAVA_STATIC PRIVATE
+// DependencyOuterJavaClass.staticPublicField: FINAL JAVA_STATIC PUBLIC : FINAL JAVA_STATIC PUBLIC
+// DependencyOuterJavaClass.staticPackageProtectedField: FINAL JAVA_STATIC : FINAL JAVA_STATIC
+// DependencyOuterJavaClass.staticProtectedField: FINAL JAVA_STATIC PROTECTED : FINAL JAVA_STATIC PROTECTED
+// DependencyOuterJavaClass.staticPrivateField: FINAL JAVA_STATIC PRIVATE : FINAL JAVA_STATIC PRIVATE
+// DependencyOuterJavaClass.<init>: FINAL PUBLIC : FINAL PUBLIC
+// DependencyOuterKotlinClass: OPEN PUBLIC : PUBLIC
+// DependencyOuterKotlinClass.transientProperty: FINAL PUBLIC : FINAL JAVA_TRANSIENT PUBLIC
+// DependencyOuterKotlinClass.volatileProperty: FINAL PUBLIC : FINAL JAVA_VOLATILE PUBLIC
+// DependencyOuterKotlinClass.strictfpFun: FINAL PUBLIC : FINAL JAVA_STRICT PUBLIC
+// DependencyOuterKotlinClass.synchronizedFun: FINAL PUBLIC : FINAL JAVA_SYNCHRONIZED PUBLIC
+// DependencyOuterKotlinClass.Companion: FINAL PUBLIC : FINAL PUBLIC
+// Companion.companionField: FINAL PUBLIC : FINAL PUBLIC
+// Companion.customJvmStaticCompanionField: FINAL PUBLIC : FINAL PUBLIC
+// Companion.jvmStaticCompanionField: FINAL PUBLIC : FINAL PUBLIC
+// Companion.privateCompanionField: FINAL PUBLIC : FINAL PUBLIC
+// Companion.companionMethod: FINAL PUBLIC : FINAL PUBLIC
+// Companion.customJvmStaticCompanionMethod: FINAL PUBLIC : FINAL PUBLIC
+// Companion.jvmStaticCompanionMethod: FINAL PUBLIC : FINAL PUBLIC
+// Companion.privateCompanionMethod: FINAL PRIVATE : FINAL PRIVATE
+// Companion.<init>: FINAL PRIVATE : FINAL PRIVATE
+// DependencyOuterKotlinClass.DependencyInnerKotlinClass: FINAL INNER PUBLIC : FINAL PUBLIC
+// DependencyInnerKotlinClass.<init>: FINAL PUBLIC : FINAL PUBLIC
+// DependencyOuterKotlinClass.DependencyNestedKotlinClass: OPEN PUBLIC : PUBLIC
+// DependencyNestedKotlinClass.<init>: FINAL PUBLIC : FINAL PUBLIC
+// DependencyOuterKotlinClass.<init>: FINAL PUBLIC : FINAL PUBLIC
+// END
+// MODULE: module1
+// FILE: DependencyOuterJavaClass.java
+public class DependencyOuterJavaClass {
+ public class DependencyInnerJavaClass {}
+ public static class DependencyNestedJavaClass {}
+ public static void staticPublicMethod() {}
+ public static String staticPublicField;
+ static void staticPackageProtectedMethod() {}
+ static String staticPackageProtectedField;
+ protected static void staticProtectedMethod() {}
+ protected static String staticProtectedField;
+ private static void staticPrivateMethod() {}
+ private static String staticPrivateField;
+ transient String transientField = "";
+ volatile String volatileField = "";
+ synchronized String synchronizedFun() { return ""; }
+ strictfp String strictfpFun() { return ""; }
+}
+// FILE: DependencyOuterKotlinClass.kt
+typealias DependencyCustomJvmStatic=JvmStatic
+open class DependencyOuterKotlinClass {
+ inner class DependencyInnerKotlinClass
+ open class DependencyNestedKotlinClass
+ companion object {
+ fun companionMethod() {}
+ val companionField:String = ""
+ private fun privateCompanionMethod() {}
+ val privateCompanionField:String = ""
+ @JvmStatic
+ fun jvmStaticCompanionMethod() {}
+ @JvmStatic
+ val jvmStaticCompanionField:String = ""
+ @DependencyCustomJvmStatic
+ fun customJvmStaticCompanionMethod() {}
+ @DependencyCustomJvmStatic
+ val customJvmStaticCompanionField:String = ""
+ }
+
+ @Transient
+ val transientProperty: String = ""
+
+ @Volatile
+ var volatileProperty: String = ""
+
+ @Strictfp
+ fun strictfpFun(): String = ""
+
+ @Synchronized
+ fun synchronizedFun(): String = ""
+}
+// MODULE: main(module1)
+// FILE: a.kt
+annotation class Test
+
+@Test
+class Foo : C() {
+
+}
+
+@Test
+class Bar : OuterJavaClass()
+
+@Test
+class Baz : OuterKotlinClass()
+
+@Test
+class JavaDependency : DependencyOuterJavaClass()
+
+@Test
+class KotlinDependency : DependencyOuterKotlinClass()
+
+// FILE: C.java
+
+public abstract class C {
+
+ private String staticStr = "str"
+
+ final transient String s1;
+
+ protected static volatile int i1;
+
+ default synchronized int intFun() {
+ return 1;
+ }
+
+ abstract strictfp void foo() {}
+
+ public static class NestedC {
+
+ }
+
+ public class InnerC {
+
+ }
+}
+
+// FILE: OuterJavaClass.java
+public class OuterJavaClass {
+ public class InnerJavaClass {}
+ public static class NestedJavaClass {}
+ public static void staticPublicMethod() {}
+ public static String staticPublicField;
+ static void staticPackageProtectedMethod() {}
+ static String staticPackageProtectedField;
+ protected static void staticProtectedMethod() {}
+ protected static String staticProtectedField;
+ private static void staticPrivateMethod() {}
+ private static String staticPrivateField;
+}
+// FILE: OuterKotlinClass.kt
+typealias CustomJvmStatic=JvmStatic
+open class OuterKotlinClass {
+ inner class InnerKotlinClass
+ open class NestedKotlinClass
+ companion object {
+ fun companionMethod() {}
+ const val companionField:String = ""
+ private fun privateCompanionMethod() {}
+ private val privateCompanionField:String = ""
+ @JvmStatic
+ fun jvmStaticCompanionMethod() {}
+ @JvmStatic
+ val jvmStaticCompanionField:String = ""
+ @CustomJvmStatic
+ fun customJvmStaticCompanionMethod() {}
+ @CustomJvmStatic
+ val customJvmStaticCompanionField:String = ""
+ }
+
+ @Transient
+ val transientProperty: String = ""
+
+ @Volatile
+ var volatileProperty: String = ""
+
+ @Strictfp
+ fun strictfpFun(): String = ""
+
+ @Synchronized
+ fun synchronizedFun(): String = ""
+}
diff --git a/test-utils/testData/api/javaNonNullTypes.kt b/test-utils/testData/api/javaNonNullTypes.kt
new file mode 100644
index 00000000..7a383bf7
--- /dev/null
+++ b/test-utils/testData/api/javaNonNullTypes.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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: JavaNonNullProcessor
+// EXPECTED:
+// javaNotNullFieldRef: NOT_NULL
+// javaNullableFieldRef: NULLABLE
+// javaBothFieldRef: PLATFORM
+// javaNoneFieldRef: NULLABLE
+// bothField: PLATFORM
+// nullableField: NULLABLE
+// notNullField: NOT_NULL
+// noneField: PLATFORM
+// notNullFun: NOT_NULL
+// nullableParam: NULLABLE
+// END
+// MODULE: lib
+// FILE: dummy.kt
+class dummy
+
+// FILE: org/jetbrains/annotations/NotNull.java
+package org.jetbrains.annotations;
+
+public @interface NotNull {
+
+}
+
+// FILE: org/jetbrains/annotations/Nullable.java
+package org.jetbrains.annotations;
+
+public @interface Nullable {
+
+}
+
+// MODULE: main(lib)
+// FILE: a.kt
+val javaNotNullFieldRef = JavaNonNull().notNullField
+val javaNullableFieldRef = JavaNonNull().nullableField
+val javaBothFieldRef = JavaNonNull().bothField
+val javaNoneFieldRef = JavaNonNull().nonField
+
+
+// FILE: JavaNonNull.java
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+
+public class JavaNonNull {
+ @Nullable
+ @NotNull
+ public String bothField;
+
+ @Nullable
+ public String nullableField;
+
+ @NotNull
+ public String notNullField;
+
+ public String noneField;
+
+ @NotNull
+ public String notNullFun(@Nullable String nullableParam) {}
+}
diff --git a/test-utils/testData/api/javaSubtype.kt b/test-utils/testData/api/javaSubtype.kt
new file mode 100644
index 00000000..80c3b566
--- /dev/null
+++ b/test-utils/testData/api/javaSubtype.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: JavaSubtypeProcessor
+// EXPECTED:
+// true
+// END
+// FILE: a.kt
+class A
+
+// FILE: Container.java
+
+public class Container {
+ String str;
+}
+
+// FILE: IntSupplier.java
+import kotlin.jvm.functions.Function0;
+
+public class IntSupplier implements Function0<Integer> {
+ @Override public Integer invoke() { return 1; }
+}
diff --git a/test-utils/testData/api/javaToKotlinMapper.kt b/test-utils/testData/api/javaToKotlinMapper.kt
new file mode 100644
index 00000000..71aba602
--- /dev/null
+++ b/test-utils/testData/api/javaToKotlinMapper.kt
@@ -0,0 +1,32 @@
+/*
+ * 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: JavaToKotlinMapProcessor
+// EXPECTED:
+// java.lang.String -> kotlin.String
+// java.lang.Integer -> kotlin.Int
+// java.util.List -> kotlin.collections.List
+// java.util.Map.Entry -> kotlin.collections.Map.Entry
+// java.lang.Void -> null
+// kotlin.Throwable -> java.lang.Throwable
+// kotlin.Int -> java.lang.Integer
+// kotlin.Nothing -> java.lang.Void
+// kotlin.IntArray -> null
+// END
+
+val unused = Unit
diff --git a/test-utils/testData/api/javaTypes.kt b/test-utils/testData/api/javaTypes.kt
new file mode 100644
index 00000000..16ae1abd
--- /dev/null
+++ b/test-utils/testData/api/javaTypes.kt
@@ -0,0 +1,34 @@
+/*
+ * 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: TypeComparisonProcessor
+// EXPECTED:
+// (String..String?) ?= (String..String?) : true
+// (String..String?) ?= String : true
+// (String..String?) ?= String? : true
+// String ?= (String..String?) : true
+// String ?= String : true
+// String ?= String? : false
+// String? ?= (String..String?) : true
+// String? ?= String : true
+// String? ?= String? : true
+// END
+
+val j = java.lang.String.valueOf("")
+val x: String = j
+val y: String? = j
diff --git a/test-utils/testData/api/javaTypes2.kt b/test-utils/testData/api/javaTypes2.kt
new file mode 100644
index 00000000..b72d706c
--- /dev/null
+++ b/test-utils/testData/api/javaTypes2.kt
@@ -0,0 +1,47 @@
+/*
+ * 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: TypeComparisonProcessor
+// EXPECTED:
+// (Array<(C..C?)>..Array<out (C..C?)>?) ?= (Array<(C..C?)>..Array<out (C..C?)>?) : true
+// (Array<(C..C?)>..Array<out (C..C?)>?) ?= Array<C> : true
+// (Array<(C..C?)>..Array<out (C..C?)>?) ?= Array<D> : true
+// Array<C> ?= (Array<(C..C?)>..Array<out (C..C?)>?) : true
+// Array<C> ?= Array<C> : true
+// Array<C> ?= Array<D> : false
+// Array<D> ?= (Array<(C..C?)>..Array<out (C..C?)>?) : false
+// Array<D> ?= Array<C> : false
+// Array<D> ?= Array<D> : true
+// END
+
+// FILE: ArrayTest.java
+class ArrayTest {
+ public static C[] javaArrayOfC() {
+ return null;
+ }
+}
+
+// FILE: K.kt
+@file:kotlin.Suppress("C", "D", "Suppress", "Any", "ArrayTest")
+
+open class C
+open class D : C()
+
+val j = ArrayTest.javaArrayOfC()
+val c: Array<C> = arrayOf()
+val d: Array<D> = arrayOf()
diff --git a/test-utils/testData/api/javaWildcards2.kt b/test-utils/testData/api/javaWildcards2.kt
new file mode 100644
index 00000000..f84e274a
--- /dev/null
+++ b/test-utils/testData/api/javaWildcards2.kt
@@ -0,0 +1,108 @@
+/*
+ * 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: JavaWildcard2Processor
+// EXPECTED:
+// MyEnum : Any
+// <init> : MyEnum
+// VarianceSubjectSuppressed : Any
+// R : Any?
+// starList : List<Any?>
+// typeArgList : List<R>
+// numberList : List<Number>
+// stringList : List<String>
+// enumList : List<MyEnum>
+// jvmWildcard : List<out [@kotlin.jvm.JvmWildcard] String>
+// suppressJvmWildcard : List<[@kotlin.jvm.JvmSuppressWildcards] Number>
+// <init> : VarianceSubjectSuppressed<R>
+// propWithFinalType : String
+// propWithFinalType.getter() : String
+// <set-?> : String
+// propWithOpenType : Number
+// propWithOpenType.getter() : Number
+// <set-?> : Number
+// propWithFinalGeneric : List<String>
+// propWithFinalGeneric.getter() : List<String>
+// <set-?> : List<String>
+// propWithOpenGeneric : List<Number>
+// propWithOpenGeneric.getter() : List<Number>
+// <set-?> : List<Number>
+// propWithTypeArg : R
+// propWithTypeArg.getter() : R
+// <set-?> : R
+// propWithTypeArgGeneric : List<R>
+// propWithTypeArgGeneric.getter() : List<R>
+// <set-?> : List<R>
+// propWithOpenTypeButSuppressAnnotation : Number
+// propWithOpenTypeButSuppressAnnotation.getter() : Number
+// <set-?> : Number
+// list2 : List<Any?>
+// list1 : List<Any?>
+// list3 : List<R>
+// listTypeArg : List<R>
+// list4 : List<Number>
+// listTypeArgNumber : List<Number>
+// list5 : List<String>
+// listTypeArgString : List<String>
+// list6 : List<MyEnum>
+// listTypeArgEnum : List<MyEnum>
+// list7 : List<out [@kotlin.jvm.JvmWildcard] String>
+// explicitJvmWildcard : List<out [@kotlin.jvm.JvmWildcard] String>
+// list8 : List<[@kotlin.jvm.JvmSuppressWildcards] Number>
+// explicitJvmSuppressWildcard_OnType : List<[@kotlin.jvm.JvmSuppressWildcards] Number>
+// list9 : [@kotlin.jvm.JvmSuppressWildcards] List<Number>
+// explicitJvmSuppressWildcard_OnType2 : [@kotlin.jvm.JvmSuppressWildcards] List<Number>
+// END
+
+enum class MyEnum()
+
+@JvmSuppressWildcards
+class VarianceSubjectSuppressed<R>(
+ starList: List<*>,
+ typeArgList: List<R>,
+ numberList: List<Number>,
+ stringList: List<String>,
+ enumList: List<MyEnum>,
+ jvmWildcard: List<@JvmWildcard String>,
+ suppressJvmWildcard: List<@JvmSuppressWildcards Number>
+) {
+ var propWithFinalType: String = ""
+ var propWithOpenType: Number = 3
+ var propWithFinalGeneric: List<String> = TODO()
+ var propWithOpenGeneric: List<Number> = TODO()
+ var propWithTypeArg: R = TODO()
+ var propWithTypeArgGeneric: List<R> = TODO()
+ @JvmSuppressWildcards
+ var propWithOpenTypeButSuppressAnnotation: Number = 3
+ fun list1(list2: List<*>): List<*> { TODO() }
+ fun listTypeArg(list3: List<R>): List<R> { TODO() }
+ fun listTypeArgNumber(list4: List<Number>): List<Number> { TODO() }
+ fun listTypeArgString(list5: List<String>): List<String> { TODO() }
+ fun listTypeArgEnum(list6: List<MyEnum>): List<MyEnum> { TODO() }
+ fun explicitJvmWildcard(
+ list7: List<@JvmWildcard String>
+ ): List<@JvmWildcard String> { TODO() }
+
+ fun explicitJvmSuppressWildcard_OnType(
+ list8: List<@JvmSuppressWildcards Number>
+ ): List<@JvmSuppressWildcards Number> { TODO() }
+
+ fun explicitJvmSuppressWildcard_OnType2(
+ list9: @JvmSuppressWildcards List<Number>
+ ): @JvmSuppressWildcards List<Number> { TODO() }
+}
diff --git a/test-utils/testData/api/lateinitProperties.kt b/test-utils/testData/api/lateinitProperties.kt
new file mode 100644
index 00000000..af98f766
--- /dev/null
+++ b/test-utils/testData/api/lateinitProperties.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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: LateinitPropertiesProcessor
+// EXPECTED:
+// prop1
+// prop2
+// prop3
+// propSource1
+// propSource2
+// propSource3
+// END
+// MODULE: lib
+// FILE: compiledProperties.kt
+package test.compiled
+
+open class Foo {
+ lateinit var prop1: Any
+ companion object {
+ lateinit var prop2: Any
+ }
+}
+
+object Bar : Foo() {
+ lateinit var prop3: Any
+}
+
+// MODULE: main(lib)
+// FILE: sourceProperties.kt
+package test.source
+
+open class FooSource {
+ lateinit var propSource1: Any
+ companion object {
+ lateinit var propSource2: Any
+ }
+}
+
+object BarSource : Foo() {
+ lateinit var propSource3: Any
+}
diff --git a/test-utils/testData/api/libOrigins.kt b/test-utils/testData/api/libOrigins.kt
new file mode 100644
index 00000000..719b4810
--- /dev/null
+++ b/test-utils/testData/api/libOrigins.kt
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: LibOriginsProcessor
+// EXPECTED:
+// annotation: Anno1: KOTLIN_LIB
+// annotation: Anno2: JAVA_LIB
+// annotation: Anno3: KOTLIN
+// annotation: Anno4: JAVA
+// classifier ref: Anno1: KOTLIN_LIB
+// classifier ref: Anno1: KOTLIN_LIB
+// classifier ref: Anno2: JAVA_LIB
+// classifier ref: Anno2: KOTLIN_LIB
+// classifier ref: Anno3: KOTLIN
+// classifier ref: Anno3: KOTLIN_LIB
+// classifier ref: Anno4: JAVA
+// classifier ref: Anno4: KOTLIN_LIB
+// classifier ref: Annotation: KOTLIN_LIB
+// classifier ref: Annotation: KOTLIN_LIB
+// classifier ref: Annotation: KOTLIN_LIB
+// classifier ref: Annotation: KOTLIN_LIB
+// classifier ref: Any: JAVA_LIB
+// classifier ref: Any: JAVA_LIB
+// classifier ref: Any: JAVA_LIB
+// classifier ref: Any: KOTLIN_LIB
+// classifier ref: Any: KOTLIN_LIB
+// classifier ref: Any: KOTLIN_LIB
+// classifier ref: ArrayList<(T2..T2?)>: JAVA_LIB
+// classifier ref: Byte: JAVA_LIB
+// classifier ref: Byte: JAVA_LIB
+// classifier ref: Byte: JAVA_LIB
+// classifier ref: Int: KOTLIN_LIB
+// classifier ref: Int: KOTLIN_LIB
+// classifier ref: Int: KOTLIN_LIB
+// classifier ref: Int: KOTLIN_LIB
+// classifier ref: Int: KOTLIN_LIB
+// classifier ref: Int: KOTLIN_LIB
+// classifier ref: Int: KOTLIN_LIB
+// classifier ref: Int: KOTLIN_LIB
+// classifier ref: Int: KOTLIN_LIB
+// classifier ref: Int: KOTLIN_LIB
+// classifier ref: Int: KOTLIN_LIB
+// classifier ref: Int: KOTLIN_LIB
+// classifier ref: JavaLib: JAVA_LIB
+// classifier ref: JavaLib: JAVA_LIB
+// classifier ref: JavaLib: JAVA_LIB
+// classifier ref: JavaLib<T2>: JAVA_LIB
+// classifier ref: KotlinLibClass: KOTLIN_LIB
+// classifier ref: KotlinLibClass: KOTLIN_LIB
+// classifier ref: KotlinLibClass: KOTLIN_LIB
+// classifier ref: KotlinLibClass: KOTLIN_LIB
+// classifier ref: KotlinLibClass: KOTLIN_LIB
+// classifier ref: KotlinLibClass: KOTLIN_LIB
+// classifier ref: KotlinLibClass<T1>: KOTLIN_LIB
+// classifier ref: KotlinSrcClass: SYNTHETIC
+// classifier ref: List<Int>: KOTLIN_LIB
+// classifier ref: List<T1>: KOTLIN_LIB
+// classifier ref: List<T1>: KOTLIN_LIB
+// classifier ref: List<T1>: KOTLIN_LIB
+// classifier ref: List<T1>: KOTLIN_LIB
+// classifier ref: Long: JAVA
+// classifier ref: Long: JAVA
+// classifier ref: Long: JAVA
+// classifier ref: Object: JAVA
+// classifier ref: Set: KOTLIN
+// classifier ref: Set: KOTLIN
+// classifier ref: Set: KOTLIN
+// classifier ref: Set: KOTLIN
+// classifier ref: Set<T3>: SYNTHETIC
+// classifier ref: Short: KOTLIN
+// classifier ref: Short: KOTLIN
+// classifier ref: Short: KOTLIN
+// classifier ref: Short: KOTLIN
+// classifier ref: Short: KOTLIN
+// classifier ref: Short: KOTLIN
+// classifier ref: Short: KOTLIN
+// classifier ref: Short: KOTLIN
+// classifier ref: Short: KOTLIN
+// classifier ref: Short: SYNTHETIC
+// classifier ref: Short: SYNTHETIC
+// classifier ref: Short: SYNTHETIC
+// classifier ref: T1: KOTLIN_LIB
+// classifier ref: T1: KOTLIN_LIB
+// classifier ref: T1: KOTLIN_LIB
+// classifier ref: T1: KOTLIN_LIB
+// classifier ref: T1: KOTLIN_LIB
+// classifier ref: T1: KOTLIN_LIB
+// classifier ref: T2: JAVA_LIB
+// classifier ref: T2: JAVA_LIB
+// classifier ref: T2: JAVA_LIB
+// classifier ref: T3: KOTLIN
+// classifier ref: T3: KOTLIN
+// classifier ref: T3: KOTLIN
+// classifier ref: T3: KOTLIN
+// classifier ref: T3: SYNTHETIC
+// classifier ref: T4: JAVA
+// classifier ref: T4: JAVA
+// declaration: <init>: KOTLIN
+// declaration: foo.bar.Anno1.<init>: KOTLIN_LIB
+// declaration: foo.bar.Anno1: KOTLIN_LIB
+// declaration: foo.bar.Anno2.<init>: KOTLIN_LIB
+// declaration: foo.bar.Anno2: KOTLIN_LIB
+// declaration: foo.bar.Anno3.<init>: KOTLIN_LIB
+// declaration: foo.bar.Anno3: KOTLIN_LIB
+// declaration: foo.bar.Anno4.<init>: KOTLIN_LIB
+// declaration: foo.bar.Anno4: KOTLIN_LIB
+// declaration: foo.bar.JavaLib.<init>: JAVA_LIB
+// declaration: foo.bar.JavaLib.T2: JAVA_LIB
+// declaration: foo.bar.JavaLib.T2: JAVA_LIB
+// declaration: foo.bar.JavaLib.f1: JAVA_LIB
+// declaration: foo.bar.JavaLib.javaLibField: JAVA_LIB
+// declaration: foo.bar.JavaLib.javaLibFunction: JAVA_LIB
+// declaration: foo.bar.JavaLib: JAVA_LIB
+// declaration: foo.bar.JavaSrc.<init>: SYNTHETIC
+// declaration: foo.bar.JavaSrc.LinkedList: JAVA
+// declaration: foo.bar.JavaSrc.f2: JAVA
+// declaration: foo.bar.JavaSrc.javaSrcField: JAVA
+// declaration: foo.bar.JavaSrc.javaSrcFunction: JAVA
+// declaration: foo.bar.JavaSrc.p0: JAVA
+// declaration: foo.bar.JavaSrc: JAVA
+// declaration: foo.bar.KotlinLibClass.<init>: KOTLIN_LIB
+// declaration: foo.bar.KotlinLibClass.T1: KOTLIN_LIB
+// declaration: foo.bar.KotlinLibClass.T1: KOTLIN_LIB
+// declaration: foo.bar.KotlinLibClass.f1: KOTLIN_LIB
+// declaration: foo.bar.KotlinLibClass.f2: KOTLIN_LIB
+// declaration: foo.bar.KotlinLibClass.f3: KOTLIN_LIB
+// declaration: foo.bar.KotlinLibClass.p1: KOTLIN_LIB
+// declaration: foo.bar.KotlinLibClass.p2: KOTLIN_LIB
+// declaration: foo.bar.KotlinLibClass.p3: KOTLIN_LIB
+// declaration: foo.bar.KotlinLibClass: KOTLIN_LIB
+// declaration: foo.bar.KotlinSrcClass.T3: KOTLIN
+// declaration: foo.bar.KotlinSrcClass.g1: KOTLIN
+// declaration: foo.bar.KotlinSrcClass.g2: KOTLIN
+// declaration: foo.bar.KotlinSrcClass.g3: KOTLIN
+// declaration: foo.bar.KotlinSrcClass.q1: KOTLIN
+// declaration: foo.bar.KotlinSrcClass.q2: KOTLIN
+// declaration: foo.bar.KotlinSrcClass.q3: KOTLIN
+// declaration: foo.bar.KotlinSrcClass: KOTLIN
+// declaration: foo.bar.kotlinLibFuntion: KOTLIN_LIB
+// declaration: foo.bar.kotlinLibProperty: KOTLIN_LIB
+// declaration: foo.bar.kotlinSrcFuntion: KOTLIN
+// declaration: foo.bar.kotlinSrcProperty: KOTLIN
+// property accessor: kotlinLibProperty.getter(): KOTLIN_LIB
+// property accessor: kotlinSrcProperty.getter(): SYNTHETIC
+// property accessor: p1.getter(): KOTLIN_LIB
+// property accessor: p2.getter(): KOTLIN_LIB
+// property accessor: p3.getter(): KOTLIN_LIB
+// property accessor: q1.getter(): SYNTHETIC
+// property accessor: q2.getter(): SYNTHETIC
+// property accessor: q3.getter(): SYNTHETIC
+// reference: Anno1: KOTLIN_LIB
+// reference: Anno1: KOTLIN_LIB
+// reference: Anno2: JAVA_LIB
+// reference: Anno2: KOTLIN_LIB
+// reference: Anno3: KOTLIN
+// reference: Anno3: KOTLIN_LIB
+// reference: Anno4: JAVA
+// reference: Anno4: KOTLIN_LIB
+// reference: Annotation: KOTLIN_LIB
+// reference: Annotation: KOTLIN_LIB
+// reference: Annotation: KOTLIN_LIB
+// reference: Annotation: KOTLIN_LIB
+// reference: Any: JAVA_LIB
+// reference: Any: JAVA_LIB
+// reference: Any: JAVA_LIB
+// reference: Any: KOTLIN_LIB
+// reference: Any: KOTLIN_LIB
+// reference: Any: KOTLIN_LIB
+// reference: Any: SYNTHETIC
+// reference: Any?: SYNTHETIC
+// reference: ArrayList<(T2..T2?)>: JAVA_LIB
+// reference: Byte: JAVA_LIB
+// reference: Byte: JAVA_LIB
+// reference: Byte: JAVA_LIB
+// reference: Int: KOTLIN_LIB
+// reference: Int: KOTLIN_LIB
+// reference: Int: KOTLIN_LIB
+// reference: Int: KOTLIN_LIB
+// reference: Int: KOTLIN_LIB
+// reference: Int: KOTLIN_LIB
+// reference: Int: KOTLIN_LIB
+// reference: Int: KOTLIN_LIB
+// reference: Int: KOTLIN_LIB
+// reference: Int: KOTLIN_LIB
+// reference: Int: KOTLIN_LIB
+// reference: Int: KOTLIN_LIB
+// reference: JavaLib<T2>: JAVA_LIB
+// reference: JavaSrc: SYNTHETIC
+// reference: KotlinLibClass<T1>: KOTLIN_LIB
+// reference: KotlinSrcClass<T3>: KOTLIN
+// reference: List<Int>: KOTLIN_LIB
+// reference: List<T1>: KOTLIN_LIB
+// reference: List<T1>: KOTLIN_LIB
+// reference: List<T1>: KOTLIN_LIB
+// reference: List<T1>: KOTLIN_LIB
+// reference: Long: JAVA
+// reference: Long: JAVA
+// reference: Long: JAVA
+// reference: Object: JAVA
+// reference: Set: KOTLIN
+// reference: Set: KOTLIN
+// reference: Set: KOTLIN
+// reference: Set: KOTLIN
+// reference: Set<T3>: SYNTHETIC
+// reference: Short: KOTLIN
+// reference: Short: KOTLIN
+// reference: Short: KOTLIN
+// reference: Short: KOTLIN
+// reference: Short: KOTLIN
+// reference: Short: KOTLIN
+// reference: Short: KOTLIN
+// reference: Short: KOTLIN
+// reference: Short: KOTLIN
+// reference: Short: SYNTHETIC
+// reference: Short: SYNTHETIC
+// reference: Short: SYNTHETIC
+// reference: T1: KOTLIN_LIB
+// reference: T1: KOTLIN_LIB
+// reference: T1: KOTLIN_LIB
+// reference: T1: KOTLIN_LIB
+// reference: T1: KOTLIN_LIB
+// reference: T1: KOTLIN_LIB
+// reference: T2: JAVA_LIB
+// reference: T2: JAVA_LIB
+// reference: T2: JAVA_LIB
+// reference: T3: KOTLIN
+// reference: T3: KOTLIN
+// reference: T3: KOTLIN
+// reference: T3: KOTLIN
+// reference: T3: SYNTHETIC
+// reference: T4: JAVA
+// reference: T4: JAVA
+// type arg: INVARIANT Int: KOTLIN_LIB
+// type arg: INVARIANT Short: KOTLIN
+// type arg: INVARIANT T1: KOTLIN_LIB
+// type arg: INVARIANT T1: KOTLIN_LIB
+// type arg: INVARIANT T1: KOTLIN_LIB
+// type arg: INVARIANT T1: KOTLIN_LIB
+// type arg: INVARIANT T1: KOTLIN_LIB
+// type arg: INVARIANT T2: JAVA_LIB
+// type arg: INVARIANT T2: JAVA_LIB
+// type arg: INVARIANT T3: KOTLIN
+// type arg: INVARIANT T3: KOTLIN
+// type arg: INVARIANT T3: KOTLIN
+// type arg: INVARIANT T3: SYNTHETIC
+// value param: p0: JAVA_LIB
+// value param: p1: JAVA_LIB
+// value param: p1: KOTLIN_LIB
+// value param: p2: KOTLIN_LIB
+// value param: p4: KOTLIN_LIB
+// value param: p5: KOTLIN_LIB
+// value param: p6: KOTLIN_LIB
+// value param: q1: KOTLIN
+// value param: q2: KOTLIN
+// value param: q4: KOTLIN
+// value param: q5: KOTLIN
+// value param: q6: KOTLIN
+// END
+// MODULE: module1
+// FILE: KotlinLib.kt
+package foo.bar
+
+val kotlinLibProperty: Int = 0
+fun kotlinLibFuntion(): Int = 0
+
+annotation class Anno1
+annotation class Anno2
+annotation class Anno3
+annotation class Anno4
+
+@Anno1
+class KotlinLibClass<T1>(val p1: List<T1>, val p2: Int) {
+ val p3: Int = 0
+ fun f1(p4: T1): Int = 0
+ fun f2(p5: List<T1>): Int = 0
+ fun f3(p6: List<Int>): Int = 0
+}
+
+// FILE: JavaLib.java
+package foo.bar;
+
+import java.util.ArrayList;
+
+@Anno2
+class JavaLib<T2> {
+ Byte javaLibField = 0;
+ Byte javaLibFunction() {
+ return 0;
+ }
+ Byte f1(T2 p0, ArrayList<T2> p1) {
+ return 0;
+ }
+}
+
+// MODULE: main(module1)
+// FILE: KotlinSrc.kt
+package foo.bar
+val kotlinSrcProperty: Short = 0
+fun kotlinSrcFuntion(): Short = 0
+
+@Anno3
+class KotlinSrcClass<T3>(val q1: Set<T3>, val q2: Short) {
+ val q3: Short = 0
+ fun g1(q4: T3): Short = 0
+ fun g2(q5: Set<T3>): Short = 0
+ fun g3(q6: Set<Short>): Short = 0
+}
+
+// FILE: JavaSrc.java
+package foo.bar;
+
+import java.util.LinkedList;
+
+@Anno4
+class JavaSrc {
+ Long javaSrcField = 0;
+ Long javaSrcFunction() {
+ return 0;
+ }
+ Long f2<T4>(T4 p0, LinkedList<T4> p1) {
+ return 0;
+ }
+}
+
diff --git a/test-utils/testData/api/makeNullable.kt b/test-utils/testData/api/makeNullable.kt
new file mode 100644
index 00000000..2321e959
--- /dev/null
+++ b/test-utils/testData/api/makeNullable.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// WITH_RUNTIME
+// TEST PROCESSOR: MakeNullableProcessor
+// EXPECTED:
+// Int ?= Int : true
+// Int ?= Int? : false
+// Int ?= String : false
+// Int ?= String? : false
+// Int? ?= Int : true
+// Int? ?= Int? : true
+// Int? ?= String : false
+// Int? ?= String? : false
+// String ?= Int : false
+// String ?= Int? : false
+// String ?= String : true
+// String ?= String? : false
+// String? ?= Int : false
+// String? ?= Int? : false
+// String? ?= String : true
+// String? ?= String? : true
+// END
+
+val x: String = ""
+val y: Int? = 0
diff --git a/test-utils/testData/api/mangledNames.kt b/test-utils/testData/api/mangledNames.kt
new file mode 100644
index 00000000..cb00475a
--- /dev/null
+++ b/test-utils/testData/api/mangledNames.kt
@@ -0,0 +1,194 @@
+/*
+ * 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: MangledNamesProcessor
+// EXPECTED:
+// JavaEnum -> declarations
+// JavaEnum.VAL1 -> declarations
+// JavaEnum.VAL2 -> declarations
+// values -> values
+// valueOf -> valueOf
+// <init> -> <init>
+// JavaInput -> declarations
+// javaFunction -> javaFunction
+// staticJavaFunction -> staticJavaFunction
+// getX -> getX
+// getY -> getY
+// setY -> setY
+// mainPackage.Foo -> declarations
+// get-normalProp -> getNormalProp
+// set-normalProp -> setNormalProp
+// get-inlineProp -> getInlineProp-HRn7Rpw
+// set-inlineProp -> setInlineProp-E03SJzc
+// get-internalProp -> getInternalProp$mainModule
+// set-internalProp -> setInternalProp$mainModule
+// get-internalInlineProp -> getInternalInlineProp-HRn7Rpw$mainModule
+// set-internalInlineProp -> setInternalInlineProp-E03SJzc$mainModule
+// get-jvmNameProp -> explicitGetterName
+// set-jvmNameProp -> explicitSetterName
+// normalFun -> normalFun
+// hasJvmName -> explicitJvmName
+// inlineReceivingFun -> inlineReceivingFun-E03SJzc
+// inlineReturningFun -> inlineReturningFun-HRn7Rpw
+// internalInlineReceivingFun -> internalInlineReceivingFun-E03SJzc$mainModule
+// internalInlineReturningFun -> internalInlineReturningFun-HRn7Rpw$mainModule
+// mainPackage.AbstractKotlinClass -> declarations
+// get-abstractVar -> getAbstractVar
+// set-abstractVar -> setAbstractVar
+// get-abstractVal -> getAbstractVal
+// get-internalAbstractVar -> getInternalAbstractVar$mainModule
+// set-internalAbstractVar -> setInternalAbstractVar$mainModule
+// get-internalAbstractVal -> getInternalAbstractVal$mainModule
+// set-internalAbstractVal -> setInternalAbstractVal$mainModule
+// fileLevelInternalFun -> fileLevelInternalFun
+// fileLevelInlineReceivingFun -> fileLevelInlineReceivingFun-E03SJzc
+// fileLevelInlineReturningFun -> fileLevelInlineReturningFun
+// fileLevelInternalInlineReceivingFun -> fileLevelInternalInlineReceivingFun-E03SJzc
+// fileLevelInternalInlineReturningFun -> fileLevelInternalInlineReturningFun
+// mainPackage.MyInterface -> declarations
+// get-x -> getX
+// get-y -> getY
+// set-y -> setY
+// libPackage.Foo -> declarations
+// get-inlineProp -> getInlineProp-b_MPbnQ
+// set-inlineProp -> setInlineProp-mQ73O9w
+// get-internalInlineProp -> getInternalInlineProp-b_MPbnQ$lib
+// set-internalInlineProp -> setInternalInlineProp-mQ73O9w$lib
+// get-internalProp -> getInternalProp$lib
+// set-internalProp -> setInternalProp$lib
+// get-jvmNameProp -> explicitGetterName
+// set-jvmNameProp -> explicitSetterName
+// get-normalProp -> getNormalProp
+// set-normalProp -> setNormalProp
+// hasJvmName -> explicitJvmName
+// inlineReceivingFun -> inlineReceivingFun-mQ73O9w
+// inlineReturningFun -> inlineReturningFun-b_MPbnQ
+// internalInlineReceivingFun -> internalInlineReceivingFun-mQ73O9w$lib
+// internalInlineReturningFun -> internalInlineReturningFun-b_MPbnQ$lib
+// normalFun -> normalFun
+// <init> -> <init>
+// libPackage.AbstractKotlinClass -> declarations
+// get-abstractVal -> getAbstractVal
+// get-abstractVar -> getAbstractVar
+// set-abstractVar -> setAbstractVar
+// get-internalAbstractVal -> getInternalAbstractVal$lib
+// set-internalAbstractVal -> setInternalAbstractVal$lib
+// get-internalAbstractVar -> getInternalAbstractVar$lib
+// set-internalAbstractVar -> setInternalAbstractVar$lib
+// libPackage.MyInterface -> declarations
+// get-x -> getX
+// get-y -> getY
+// set-y -> setY
+// END
+// MODULE: lib
+// FILE: input.kt
+/**
+ * control group
+ */
+package libPackage;
+inline class Inline1(val value:String)
+class Foo {
+ var normalProp:String = TODO()
+ var inlineProp: Inline1 = TODO()
+ internal var internalProp: String = TODO()
+ internal var internalInlineProp: Inline1 = TODO()
+ @get:JvmName("explicitGetterName")
+ @set:JvmName("explicitSetterName")
+ var jvmNameProp:String
+ fun normalFun() {}
+ @JvmName("explicitJvmName")
+ fun hasJvmName() {}
+ fun inlineReceivingFun(value: Inline1) {}
+ fun inlineReturningFun(): Inline1 = TODO()
+ internal fun internalInlineReceivingFun(value: Inline1) {}
+ internal fun internalInlineReturningFun(): Inline1 = TODO()
+}
+
+abstract class AbstractKotlinClass {
+ abstract var abstractVar:String
+ abstract val abstractVal:String
+ internal abstract var internalAbstractVar:String
+ internal abstract var internalAbstractVal:String
+}
+
+interface MyInterface {
+ val x:Int
+ var y:Int
+}
+// MODULE: mainModule(lib)
+// FILE: input.kt
+package mainPackage;
+inline class Inline1(val value:String)
+class Foo {
+ var normalProp:String = TODO()
+ var inlineProp: Inline1 = TODO()
+ internal var internalProp: String = TODO()
+ internal var internalInlineProp: Inline1 = TODO()
+ @get:JvmName("explicitGetterName")
+ @set:JvmName("explicitSetterName")
+ var jvmNameProp:String
+ fun normalFun() {}
+ @JvmName("explicitJvmName")
+ fun hasJvmName() {}
+ fun inlineReceivingFun(value: Inline1) {}
+ fun inlineReturningFun(): Inline1 = TODO()
+ internal fun internalInlineReceivingFun(value: Inline1) {}
+ internal fun internalInlineReturningFun(): Inline1 = TODO()
+}
+
+abstract class AbstractKotlinClass {
+ abstract var abstractVar:String
+ abstract val abstractVal:String
+ internal abstract var internalAbstractVar:String
+ internal abstract var internalAbstractVal:String
+}
+
+internal fun fileLevelInternalFun(): Unit = TODO()
+fun fileLevelInlineReceivingFun(inline1: Inline1): Unit = TODO()
+fun fileLevelInlineReturningFun(): Inline1 = TODO()
+fun fileLevelInternalInlineReceivingFun(inline1: Inline1): Unit = TODO()
+fun fileLevelInternalInlineReturningFun(): Inline1 = TODO()
+
+interface MyInterface {
+ val x:Int
+ var y:Int
+}
+
+// FILE: JavaInput.java
+import mainPackage.MyInterface;
+
+class JavaInput implements MyInterface {
+ String javaField;
+ String javaFunction() {}
+ static String staticJavaField;
+ static void staticJavaFunction() {}
+ public int getX() {
+ return 1;
+ }
+ public int getY() {
+ return 1;
+ }
+ public void setY(int value) {
+ }
+}
+
+// FILE: JavaEnum.java
+public enum JavaEnum {
+ VAL1,
+ VAL2;
+}
diff --git a/test-utils/testData/api/multipleModules.kt b/test-utils/testData/api/multipleModules.kt
new file mode 100644
index 00000000..b33df4e2
--- /dev/null
+++ b/test-utils/testData/api/multipleModules.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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: MultiModuleTestProcessor
+// EXPECTED:
+// ClassInMainModule[KOTLIN]
+// ClassInModule1[KOTLIN_LIB]
+// ClassInModule2[KOTLIN_LIB]
+// JavaClassInMainModule[JAVA]
+// JavaClassInModule1[JAVA_LIB]
+// JavaClassInModule2[JAVA_LIB]
+// TestTarget[KOTLIN]
+// END
+// MODULE: module1
+// FILE: ClassInModule1.kt
+class ClassInModule1 {
+ val javaClassInModule1: JavaClassInModule1 = TODO()
+}
+// FILE: JavaClassInModule1.java
+public class JavaClassInModule1 {}
+// MODULE: module2(module1)
+// FILE: ClassInModule2.kt
+class ClassInModule2 {
+ val javaClassInModule2: JavaClassInModule2 = TODO()
+ val classInModule1: ClassInModule1 = TODO()
+}
+// FILE: JavaClassInModule2.java
+public class JavaClassInModule2 {}
+// MODULE: main(module1, module2)
+// FILE: main.kt
+class TestTarget {
+ val field: ClassInMainModule = TODO()
+}
+// FILE: ClassInMainModule.kt
+class ClassInMainModule {
+ val field: ClassInModule2 = TODO()
+ val javaClassInMainModule : JavaClassInMainModule = TODO()
+}
+// FILE: JavaClassInMainModule.java
+class JavaClassInMainModule {
+}
diff --git a/test-utils/testData/api/nestedClassType.kt b/test-utils/testData/api/nestedClassType.kt
new file mode 100644
index 00000000..fd2f8bf4
--- /dev/null
+++ b/test-utils/testData/api/nestedClassType.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: NestedClassTypeProcessor
+// EXPECTED:
+// foo
+// @TypeAnno1
+// COVARIANT String
+// bar
+// , @TypeAnno2
+// CONTRAVARIANT Int,INVARIANT String
+// END
+// FILE: a.kt
+annotation class TypeAnno1
+annotation class TypeAnno2
+
+class Outer<T> {
+ inner class InnerGeneric<P>
+ inner class Inner
+}
+
+class G<T>
+
+class C {
+ val foo: Outer<out @TypeAnno1 String>.Inner
+ val bar: Outer<@TypeAnno2 String>.InnerGeneric<in Int>
+}
diff --git a/test-utils/testData/api/nullableTypes.kt b/test-utils/testData/api/nullableTypes.kt
new file mode 100644
index 00000000..ed3eb6d7
--- /dev/null
+++ b/test-utils/testData/api/nullableTypes.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2021 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: NullableTypeProcessor
+// EXPECTED:
+// a: [], [@TA]
+// b: [SUSPEND], [@TA]
+// c: [], [@TA]
+// d: [SUSPEND], [@TA]
+// e: [], [@TA]
+// f: [], [@TA]
+// g: [], [@TA]
+// h: [], [@TA]
+// i: [], [@TA]
+// j: [], [@TA]
+// k: [], [@TA]
+// END
+
+@Target(AnnotationTarget.TYPE)
+annotation class TA
+
+val a: @TA (() -> Unit)? = {}
+val b: (@TA suspend () -> Unit)? = {}
+val c: @TA (() -> Unit) = {}
+val d: (@TA suspend () -> Unit) = {}
+val e: (@TA String)?
+
+// Parser doesn't allow `@TA (String)`
+val f: (@TA String)? = ""
+val g: (@TA String?) = ""
+val h: (@TA String?)? = ""
+val i: @TA String = ""
+val j: (@TA String) = ""
+val k: ((@TA String)?) = ""
diff --git a/test-utils/testData/api/overridee.kt b/test-utils/testData/api/overridee.kt
new file mode 100644
index 00000000..39173f93
--- /dev/null
+++ b/test-utils/testData/api/overridee.kt
@@ -0,0 +1,321 @@
+/*
+ * 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: OverrideeProcessor
+// EXPECTED:
+// NoOverride:
+// NoOverride.propInParam -> null
+// NoOverride.prop -> null
+// NoOverride.func(param:Int) -> null
+// Subject:
+// Companion.companionMethod() -> null
+// Subject.notOverridingProp -> null
+// Subject.overriddenBaseProp -> Base.overriddenBaseProp
+// Subject.overriddenAbstractBaseProp -> Base.overriddenAbstractBaseProp
+// Subject.openGrandBaseProp -> GrandBase.openGrandBaseProp
+// Subject.abstractGrandBaseProp -> GrandBase.abstractGrandBaseProp
+// Subject.overriddenGrandBaseProp -> Base.overriddenGrandBaseProp
+// Subject.overriddenAbstractGrandBaseProp -> Base.overriddenAbstractGrandBaseProp
+// Subject.openFun() -> Base.openFun()
+// Subject.abstractFun() -> Base.abstractFun()
+// Subject.openFunWithGenericArg(t:String) -> Base.openFunWithGenericArg(t:T)
+// Subject.abstractFunWithGenericArg(t:String) -> Base.abstractFunWithGenericArg(t:T)
+// Subject.nonOverridingMethod() -> null
+// Subject.overriddenGrandBaseFun() -> Base.overriddenGrandBaseFun()
+// Subject.overriddenAbstractGrandBaseFun() -> Base.overriddenAbstractGrandBaseFun()
+// Subject.openGrandBaseFun() -> GrandBase.openGrandBaseFun()
+// Subject.abstractGrandBaseFun() -> GrandBase.abstractGrandBaseFun()
+// JavaSubject.Subject:
+// Subject.openFun() -> Base.openFun()
+// Subject.abstractFun() -> Base.abstractFun()
+// Subject.openFunWithGenericArg(t:String) -> Base.openFunWithGenericArg(t:T)
+// Subject.abstractFunWithGenericArg(t:String) -> Base.abstractFunWithGenericArg(t:T)
+// Subject.nonOverridingMethod() -> null
+// Subject.overriddenGrandBaseFun() -> Base.overriddenGrandBaseFun()
+// Subject.overriddenAbstractGrandBaseFun() -> Base.overriddenAbstractGrandBaseFun()
+// Subject.openGrandBaseFun() -> GrandBase.openGrandBaseFun()
+// Subject.abstractGrandBaseFun() -> GrandBase.abstractGrandBaseFun()
+// Subject.staticMethod() -> null
+// lib.Subject:
+// Companion.companionMethod() -> null
+// Subject.abstractGrandBaseProp -> GrandBase.abstractGrandBaseProp
+// Subject.notOverridingProp -> null
+// Subject.openGrandBaseProp -> GrandBase.openGrandBaseProp
+// Subject.overriddenAbstractBaseProp -> Base.overriddenAbstractBaseProp
+// Subject.overriddenAbstractGrandBaseProp -> Base.overriddenAbstractGrandBaseProp
+// Subject.overriddenBaseProp -> Base.overriddenBaseProp
+// Subject.overriddenGrandBaseProp -> Base.overriddenGrandBaseProp
+// Subject.abstractFun() -> Base.abstractFun()
+// Subject.abstractFunWithGenericArg(t:String) -> Base.abstractFunWithGenericArg(t:T)
+// Subject.abstractGrandBaseFun() -> GrandBase.abstractGrandBaseFun()
+// Subject.nonOverridingMethod() -> null
+// Subject.openFun() -> Base.openFun()
+// Subject.openFunWithGenericArg(t:String) -> Base.openFunWithGenericArg(t:T)
+// Subject.openGrandBaseFun() -> GrandBase.openGrandBaseFun()
+// Subject.overriddenAbstractGrandBaseFun() -> Base.overriddenAbstractGrandBaseFun()
+// Subject.overriddenGrandBaseFun() -> Base.overriddenGrandBaseFun()
+// ConflictingSubject1:
+// ConflictingSubject1.absFoo() -> MyInterface.absFoo()
+// ConflictingSubject2:
+// ConflictingSubject2.absFoo() -> MyAbstract.absFoo()
+// ConflictingSubject3:
+// ConflictingSubject3.absFoo() -> MyInterface.absFoo()
+// ConflictingSubject4:
+// ConflictingSubject4.absFoo() -> MyInterface2.absFoo()
+// OverrideOrder1:
+// OverrideOrder1.foo() -> GrandBaseInterface2.foo()
+// OverrideOrder2:
+// OverrideOrder2.foo() -> GrandBaseInterface1.foo()
+// JavaAccessorImpl:
+// JavaAccessorImpl.getX() -> KtInterfaceWithProperty.x
+// JavaAccessorImpl.getY() -> KtInterfaceWithProperty.y
+// JavaAccessorImpl.setY(value:Int) -> KtInterfaceWithProperty.y
+// JavaAnno:
+// JavaAnno.intParam() -> null
+// JavaAnnos:
+// JavaAnnos.value() -> null
+// PrimaryConstructorOverride:
+// PrimaryConstructorOverride.x -> KtInterfaceWithProperty.x
+// PrimaryConstructorOverride.y -> KtInterfaceWithProperty.y
+// END
+// MODULE: lib
+// FILE: lib.kt
+package lib;
+abstract class GrandBase {
+ open var openGrandBaseProp: Int = 0
+ abstract var abstractGrandBaseProp: Int
+ open var overriddenGrandBaseProp: Int = 0
+ abstract var overriddenAbstractGrandBaseProp: Int
+ open fun openGrandBaseFun() {}
+ abstract fun abstractGrandBaseFun()
+ open fun overriddenGrandBaseFun() {}
+ abstract fun overriddenAbstractGrandBaseFun()
+}
+abstract class Base<T> : GrandBase() {
+ open var overriddenBaseProp: Int = 0
+ abstract var overriddenAbstractBaseProp: Int
+ override var overriddenGrandBaseProp:Int = 0
+ override var overriddenAbstractGrandBaseProp: Int = 0
+ open fun openFun() {}
+ abstract fun abstractFun():Unit
+ open fun openFunWithGenericArg(t:T):T = TODO()
+ abstract fun abstractFunWithGenericArg(t:T):T
+ override open fun overriddenGrandBaseFun() {}
+ override open fun overriddenAbstractGrandBaseFun() {}
+}
+
+abstract class Subject: Base<String>() {
+ var notOverridingProp: Int = 0
+ override open var overriddenBaseProp: Int = 0
+ override var overriddenAbstractBaseProp: Int = 0
+ override open var openGrandBaseProp: Int = 0
+ override var abstractGrandBaseProp: Int = 0
+ override var overriddenGrandBaseProp:Int = 0
+ override var overriddenAbstractGrandBaseProp: Int = 0
+ override fun openFun() {}
+ override fun abstractFun() {}
+ override fun openFunWithGenericArg(t:String):String = TODO()
+ override fun abstractFunWithGenericArg(t:String):String = TODO()
+ fun nonOverridingMethod(): String =TODO()
+ override fun overriddenGrandBaseFun() {}
+ override fun overriddenAbstractGrandBaseFun() {}
+ override fun openGrandBaseFun() {}
+ override fun abstractGrandBaseFun() {}
+ companion object {
+ fun companionMethod(): String =TODO()
+ }
+}
+// MODULE: main(lib)
+// FILE: a.kt
+class NoOverride(val propInParam: Int) {
+ val prop: Int
+ fun func(val param: Int) {
+
+ }
+}
+
+interface KtInterfaceWithProperty {
+ val x:Int
+ var y:Int
+}
+
+interface Intermediate: KtInterfaceWithProperty
+
+class PrimaryConstructorOverride(override val x: Int): Intermediate {
+ override val y: Int = 1
+}
+
+abstract class GrandBase {
+ open var openGrandBaseProp: Int = 0
+ abstract var abstractGrandBaseProp: Int = 0
+ open var overriddenGrandBaseProp: Int = 0
+ abstract var overriddenAbstractGrandBaseProp: Int = 0
+ open fun openGrandBaseFun() {}
+ abstract fun abstractGrandBaseFun()
+ open fun overriddenGrandBaseFun() {}
+ abstract fun overriddenAbstractGrandBaseFun()
+}
+abstract class Base<T> : GrandBase() {
+ open var overriddenBaseProp: Int = 0
+ var overriddenAbstractBaseProp: Int = 0
+ override var overriddenGrandBaseProp:Int = 0
+ override var overriddenAbstractGrandBaseProp: Int = 0
+ open fun openFun() {}
+ abstract fun abstractFun():Unit
+ open fun openFunWithGenericArg(t:T):T = TODO()
+ abstract fun abstractFunWithGenericArg(t:T):T
+ override open fun overriddenGrandBaseFun() {}
+ override open fun overriddenAbstractGrandBaseFun() {}
+}
+
+abstract class Subject: Base<String>() {
+ var notOverridingProp: Int = 0
+ override open var overriddenBaseProp: Int = 0
+ override var overriddenAbstractBaseProp: Int = 0
+ override open var openGrandBaseProp: Int = 0
+ override var abstractGrandBaseProp: Int = 0
+ override var overriddenGrandBaseProp:Int = 0
+ override var overriddenAbstractGrandBaseProp: Int = 0
+ override fun openFun() {}
+ override fun abstractFun() {}
+ override fun openFunWithGenericArg(t:String):String = TODO()
+ override fun abstractFunWithGenericArg(t:String):String = TODO()
+ fun nonOverridingMethod(): String =TODO()
+ override fun overriddenGrandBaseFun() {}
+ override fun overriddenAbstractGrandBaseFun() {}
+ override fun openGrandBaseFun() {}
+ override fun abstractGrandBaseFun() {}
+ companion object {
+ fun companionMethod(): String =TODO()
+ }
+}
+
+// FILE: conflictingOverrides.kt
+interface MyInterface {
+ fun absFoo(): Unit
+}
+
+interface MyInterface2 {
+ fun absFoo(): Unit
+}
+
+abstract class MyAbstract: MyInterface {
+ override fun absFoo(): Unit {val a = 1}
+}
+
+class ConflictingSubject1: MyInterface, MyAbstract() {
+ override fun absFoo(): Unit = TODO()
+}
+
+class ConflictingSubject2: MyAbstract(), MyInterface {
+ override fun absFoo(): Unit = TODO()
+}
+
+class ConflictingSubject3: MyInterface, MyInterface2 {
+ override fun absFoo(): Unit = TODO()
+}
+
+class ConflictingSubject4: MyInterface2, MyInterface {
+ override fun absFoo(): Unit = TODO()
+}
+
+// FILE: overrideOrder.kt
+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()
+}
+
+// FILE: JavaSubject.java
+public class JavaSubject {
+ static abstract class GrandBase {
+ void openGrandBaseFun() {}
+ abstract void abstractGrandBaseFun();
+ void overriddenGrandBaseFun() {}
+ abstract void overriddenAbstractGrandBaseFun();
+ }
+ static abstract class Base<T> extends GrandBase {
+ void openFun() {}
+ abstract void abstractFun();
+ T openFunWithGenericArg(T t) {
+ return null;
+ }
+ abstract T abstractFunWithGenericArg(T t);
+ void overriddenGrandBaseFun() {}
+ void overriddenAbstractGrandBaseFun() {}
+ }
+
+ static abstract class Subject extends Base<String> {
+ void openFun() {}
+ void abstractFun() {}
+ String openFunWithGenericArg(String t) {
+ return null;
+ }
+ String abstractFunWithGenericArg(String t) {
+ return null;
+ }
+ String nonOverridingMethod() {
+ return null;
+ }
+ void overriddenGrandBaseFun() {}
+ void overriddenAbstractGrandBaseFun() {}
+ void openGrandBaseFun() {}
+ void abstractGrandBaseFun() {}
+ static String staticMethod() {
+ return null;
+ }
+ }
+}
+
+// FILE: JavaImpl.java
+class JavaAccessorImpl implements KtInterfaceWithProperty {
+ public int getX() {
+ return 1;
+ }
+ public int getY() {
+ return 1;
+ }
+ public void setY(int value) {
+ }
+}
+
+// FILE: JavaAnno.java
+@java.lang.annotation.Repeatable(JavaAnnos.class)
+public @interface JavaAnno {
+ int intParam();
+}
+
+// FILE: JavaAnnos.java
+public @interface JavaAnnos {
+ JavaAnno[] value();
+}
diff --git a/test-utils/testData/api/parameterTypes.kt b/test-utils/testData/api/parameterTypes.kt
new file mode 100644
index 00000000..36fb2cdd
--- /dev/null
+++ b/test-utils/testData/api/parameterTypes.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: ParameterTypeProcessor
+// EXPECTED:
+// a: Int
+// b: <ERROR TYPE>
+// c: <ERROR TYPE>
+// errorValue: <ERROR TYPE>
+// v: String
+// value: Int
+// END
+
+class Foo {
+ var a: ErrorType
+ set(errorValue) {
+ a = errorValue
+ }
+ var x
+ get() = "OK"
+ set(v) = Unit
+ var a:Int
+ get() = a
+ set(value) { a = value }
+
+ fun foo(a: Int, b: NonExist, c)
+}
diff --git a/test-utils/testData/api/parent.kt b/test-utils/testData/api/parent.kt
new file mode 100644
index 00000000..5237289b
--- /dev/null
+++ b/test-utils/testData/api/parent.kt
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: ParentProcessor
+// EXPECTED:
+// parent of File: a.kt: null
+// parent of Any: Anno
+// parent of Anno: File: a.kt
+// parent of Anno: synthetic constructor for Anno
+// parent of synthetic constructor for Anno: Anno
+// parent of Int: Int
+// parent of Int: INVARIANT Int
+// parent of INVARIANT Int: Map
+// parent of T: T
+// parent of T: INVARIANT T
+// parent of INVARIANT T: Map
+// parent of Map: Map
+// parent of Map: Alias
+// parent of Any?: T
+// parent of T: Alias
+// parent of Alias: File: a.kt
+// parent of Int: Int
+// parent of Int: INVARIANT Int
+// parent of INVARIANT Int: List
+// parent of List: List
+// parent of List: topProp
+// parent of Int: Int
+// parent of Int: INVARIANT Int
+// parent of INVARIANT Int: List<Int>
+// parent of List<Int>: List<Int>
+// parent of List<Int>: topProp.getter()
+// parent of topProp.getter(): topProp
+// parent of Anno: Anno
+// parent of Anno: @Anno
+// parent of @Anno: topProp
+// parent of topProp: File: a.kt
+// parent of T: T
+// parent of T: topFun
+// parent of Any?: T
+// parent of T: topFun
+// parent of Anno: Anno
+// parent of Anno: @Anno
+// parent of @Anno: topFun
+// parent of topFun: File: a.kt
+// parent of Any: ITF
+// parent of ITF: File: a.kt
+// parent of ITF: ITF
+// parent of ITF: topClass
+// parent of Anno: Anno
+// parent of Anno: @Anno
+// parent of @Anno: topClass
+// parent of topClass: File: a.kt
+// parent of Int: Int
+// parent of Int: i
+// parent of i: memberFun
+// parent of Int: memberFun
+// parent of memberFun: topClass
+// parent of Any: InnerClass
+// parent of Any?: P
+// parent of P: InnerClass
+// parent of InnerClass: topClass
+// parent of P: P
+// parent of P: p
+// parent of p: innerFun
+// parent of Int: innerFun
+// parent of innerFun: InnerClass
+// parent of InnerClass<*>: synthetic constructor for InnerClass
+// parent of synthetic constructor for InnerClass: InnerClass
+// parent of Int: Int
+// parent of Int: a
+// parent of Int: Int
+// parent of Int: a.getter()
+// parent of a.getter(): a
+// parent of a: topClass
+// parent of String: String
+// parent of String: b
+// parent of b.getter(): b
+// parent of String: String
+// parent of String: <set-?>
+// parent of <set-?>: b.setter()
+// parent of b.setter(): b
+// parent of b: topClass
+// parent of topClass: synthetic constructor for topClass
+// parent of synthetic constructor for topClass: topClass
+// parent of Any: CMYK
+// parent of CMYK: File: a.kt
+// parent of Any: C
+// parent of C: CMYK
+// parent of C: synthetic constructor for C
+// parent of synthetic constructor for C: C
+// parent of Any: M
+// parent of M: CMYK
+// parent of M: synthetic constructor for M
+// parent of synthetic constructor for M: M
+// parent of Any: Y
+// parent of Y: CMYK
+// parent of Y: synthetic constructor for Y
+// parent of synthetic constructor for Y: Y
+// parent of Any: K
+// parent of K: CMYK
+// parent of K: synthetic constructor for K
+// parent of synthetic constructor for K: K
+// parent of CMYK: synthetic constructor for CMYK
+// parent of synthetic constructor for CMYK: CMYK
+// parent of File: Bnno.kt: null
+// parent of Any: Bnno
+// parent of Bnno: File: Bnno.kt
+// parent of Bnno: synthetic constructor for Bnno
+// parent of synthetic constructor for Bnno: Bnno
+// parent of File: B.java: null
+// parent of ITF: ITF
+// parent of ITF: B
+// parent of T: B
+// parent of Anno: Anno
+// parent of Anno: @Anno
+// parent of @Anno: B
+// parent of p: Bnno
+// parent of p.Bnno: Bnno
+// parent of Bnno: @Bnno
+// parent of @Bnno: B
+// parent of B: File: B.java
+// parent of T: T
+// parent of T: t
+// parent of t: B
+// parent of T: T
+// parent of T: t
+// parent of t: foo
+// parent of Int: Int
+// parent of Int: i
+// parent of i: foo
+// parent of Int: Int
+// parent of Int: foo
+// parent of foo: B
+// parent of B<*>: synthetic constructor for B
+// parent of synthetic constructor for B: B
+// parent of RGB: RGB
+// parent of RGB: INVARIANT RGB
+// parent of INVARIANT RGB: Enum<RGB>
+// parent of Enum<RGB>: Enum<RGB>
+// parent of Enum<RGB>: RGB
+// parent of RGB: File: B.java
+// parent of R: RGB
+// parent of G: RGB
+// parent of B: RGB
+// parent of RGB: RGB
+// parent of RGB: INVARIANT RGB
+// parent of INVARIANT RGB: Array<(RGB..RGB?)>
+// parent of Array<(RGB..RGB?)>: Array<(RGB..RGB?)>
+// parent of Array<(RGB..RGB?)>: values
+// parent of values: RGB
+// parent of java: String
+// parent of lang: String
+// parent of String: String
+// parent of String: name
+// parent of name: valueOf
+// parent of RGB: RGB
+// parent of RGB: valueOf
+// parent of valueOf: RGB
+// parent of RGB: synthetic constructor for RGB
+// parent of synthetic constructor for RGB: RGB
+// parent of YUV: YUV
+// parent of YUV: INVARIANT YUV
+// parent of INVARIANT YUV: Enum<YUV>
+// parent of Enum<YUV>: Enum<YUV>
+// parent of Enum<YUV>: YUV
+// parent of YUV: null
+// parent of YUV: YUV
+// parent of YUV: Y
+// parent of Y: YUV
+// parent of YUV: YUV
+// parent of YUV: U
+// parent of U: YUV
+// parent of YUV: YUV
+// parent of YUV: V
+// parent of V: YUV
+// parent of String: String
+// parent of String: value
+// parent of value: valueOf
+// parent of YUV: YUV
+// parent of YUV: valueOf
+// parent of valueOf: YUV
+// parent of YUV: YUV
+// parent of YUV: INVARIANT YUV
+// parent of INVARIANT YUV: Array<YUV>
+// parent of Array<YUV>: Array<YUV>
+// parent of Array<YUV>: values
+// parent of values: YUV
+// parent of YUV: YUV
+// parent of YUV: <init>
+// parent of <init>: YUV
+// parent of HSV: HSV
+// parent of HSV: INVARIANT HSV
+// parent of INVARIANT HSV: Enum<(HSV..HSV?)>
+// parent of Enum<(HSV..HSV?)>: Enum<(HSV..HSV?)>
+// parent of Enum<(HSV..HSV?)>: HSV
+// parent of HSV: null
+// parent of HSV: HSV
+// parent of HSV: H
+// parent of H: HSV
+// parent of HSV: HSV
+// parent of HSV: S
+// parent of S: HSV
+// parent of HSV: HSV
+// parent of HSV: V
+// parent of V: HSV
+// parent of String: String
+// parent of String: value
+// parent of value: valueOf
+// parent of HSV: HSV
+// parent of HSV: valueOf
+// parent of valueOf: HSV
+// parent of HSV: HSV
+// parent of HSV: INVARIANT HSV
+// parent of INVARIANT HSV: Array<HSV>
+// parent of Array<HSV>: Array<HSV>
+// parent of Array<HSV>: values
+// parent of values: HSV
+// parent of HSV: HSV
+// parent of HSV: <init>
+// parent of <init>: HSV
+// END
+
+// MODULE: lib
+// FILE: YUV.kt
+enum class YUV {
+ Y, U, V
+}
+
+// FILE: HSV.java
+enum HSV {
+ H, S, V
+}
+
+// MODULE: main(lib)
+
+// FILE: a.kt
+annotation class Anno
+
+typealias Alias<T> = Map<Int, T>
+
+@Anno
+val topProp : List<Int>? = null
+
+@Anno
+fun <T> topFun() : T? {
+ return null
+}
+
+interface ITF
+
+@Anno
+class topClass: ITF {
+ fun memberFun(i: Int) = 1
+ class InnerClass<P> {
+ fun innerFun(p: P) = 1
+ }
+
+ val a: Int = 1
+ var b: String
+ get() = "1"
+}
+
+enum class CMYK {
+ C, M, Y, K
+}
+
+// FILE: Bnno.kt
+package p
+
+annotation class Bnno
+
+// FILE: B.java
+@Anno
+@p.Bnno
+public class B<T> implements ITF {
+ private T t;
+ public int foo(T t, int i) {
+ return 1;
+ }
+}
+
+enum RGB {
+ R, G, B
+}
diff --git a/test-utils/testData/api/platformDeclaration.kt b/test-utils/testData/api/platformDeclaration.kt
new file mode 100644
index 00000000..40b8be1c
--- /dev/null
+++ b/test-utils/testData/api/platformDeclaration.kt
@@ -0,0 +1,103 @@
+/*
+ * 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: PlatformDeclarationProcessor
+// EXPECTED:
+// Actual.kt : Clazz : true : false : [] : [Expect.kt]
+// Actual.kt : Clazz.foo : true : false : [] : [Expect.kt]
+// Actual.kt : ExpectNotFoundClass : true : false : [] : []
+// Actual.kt : ExpectNotFoundFun : true : false : [] : []
+// Actual.kt : ExpectNotFoundVal : true : false : [] : []
+// Actual.kt : Klass : true : false : [] : [Expect.kt]
+// Actual.kt : RGB : true : false : [] : [Expect.kt]
+// Actual.kt : RGB.B : true : false : [] : [Expect.kt]
+// Actual.kt : RGB.G : true : false : [] : [Expect.kt]
+// Actual.kt : RGB.R : true : false : [] : [Expect.kt]
+// Actual.kt : RGB.v : false : false : [] : []
+// Actual.kt : bar : true : false : [] : [Expect.kt]
+// Actual.kt : baz : true : false : [] : [Expect.kt]
+// Coffee.java : Coffee : false : false : [] : []
+// Coffee.java : Coffee.baz : false : false : [] : []
+// Coffee.java : Coffee.foo : false : false : [] : []
+// Expect.kt : ActualNotFoundClass : false : true : [] : []
+// Expect.kt : ActualNotFoundFun : false : true : [] : []
+// Expect.kt : ActualNotFoundVal : false : true : [] : []
+// Expect.kt : Clazz : false : true : [Actual.kt] : []
+// Expect.kt : Clazz.foo : false : true : [Actual.kt] : []
+// Expect.kt : Klass : false : true : [Actual.kt] : []
+// Expect.kt : NormalClass : false : false : [] : []
+// Expect.kt : NormalFun : false : false : [] : []
+// Expect.kt : NormalVal : false : false : [] : []
+// Expect.kt : RGB : false : true : [Actual.kt] : []
+// Expect.kt : RGB.B : false : true : [Actual.kt] : []
+// Expect.kt : RGB.G : false : true : [Actual.kt] : []
+// Expect.kt : RGB.R : false : true : [Actual.kt] : []
+// Expect.kt : bar : false : true : [Actual.kt] : []
+// Expect.kt : baz : false : true : [Actual.kt] : []
+// END
+
+// FILE: Expect.kt
+expect class Clazz {
+ fun foo(): String
+}
+
+expect fun bar(): String
+expect val baz: String
+expect class Klass
+
+class NormalClass
+fun NormalFun(): String = ""
+val NormalVal: String = ""
+
+expect class ActualNotFoundClass
+expect fun ActualNotFoundFun(): String
+expect val ActualNotFoundVal: String
+
+expect enum class RGB {
+ R,
+ expect G,
+ B
+}
+
+// FILE: Actual.kt
+actual class Clazz {
+ actual fun foo(): String = "foo"
+}
+
+actual fun bar(): String = "bar"
+actual val baz: String = "baz"
+actual typealias Klass = String
+
+actual class ExpectNotFoundClass
+actual fun ExpectNotFoundFun(): String
+actual val ExpectNotFoundVal: String
+
+actual enum class RGB(val v: Int) {
+ actual R(0xFF0000),
+ actual G(0x00FF00),
+ actual B(0x0000FF)
+}
+
+// FILE: Coffee.java
+class Coffee {
+ String foo() {
+ return null
+ }
+
+ String baz = null
+}
diff --git a/test-utils/testData/api/rawTypes.kt b/test-utils/testData/api/rawTypes.kt
new file mode 100644
index 00000000..aa948a8f
--- /dev/null
+++ b/test-utils/testData/api/rawTypes.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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: RawTypesProcessor
+// EXPECTED:
+// barRaw
+// barRawField
+// barRawGet
+// barRawGetCompiled
+// fooRaw
+// fooRawField
+// fooRawGet
+// fooRawGetCompiled
+// p4
+// p5
+// END
+// MODULE: lib
+// FILE: dummy.kt
+// FILE: Api.java
+public interface Api {}
+
+// FILE: Foo.java
+public class Foo<T> {}
+
+// FILE: Bar.java
+public class Bar<T extends Api> {}
+
+// FILE: UsageCompiled.java
+public abstract class UsageCompiled {
+ public static void usage(
+ Foo<?> fooWildcardCompiled,
+ Foo<? super Api> fooWildcardExCompiled,
+ Bar<?> barWildcardCompiled,
+ Bar<? extends Api> barWildcardExCompiled,
+ Foo fooRawCompiled,
+ Bar barRawCompiled
+ ) {}
+
+ public abstract Foo<?> fooWildcardGetCompiled();
+ public abstract Foo<? super Api> fooWildcardExGetCompiled();
+ public abstract Bar<?> barWildcardGetCompiled();
+ public abstract Bar<? extends Api> barWildcardExGetCompiled();
+ public abstract Foo fooRawGetCompiled();
+ public abstract Bar barRawGetCompiled();
+}
+
+// MODULE: main(lib)
+// FILE: usage.kt
+fun usage(
+ fooStar: Foo<*>,
+ fooIn: Foo<in Api>,
+ fooOut: Foo<out Api>,
+ barStar: Bar<*>,
+) = Unit
+
+val fooStarProp: Foo<*>
+val fooInProp: Foo<in Api>
+val fooOutProp: Foo<out Api>
+val barStarProp: Bar<*>
+
+// FILE: Usage.java
+public abstract class Usage {
+ public Foo<?> fooWildcardField;
+ public Foo<? super Api> fooWildcardExField;
+ public Bar<?> barWildcardField;
+ public Bar<? extends Api> barWildcardExField;
+ public Foo fooRawField;
+ public Bar barRawField;
+
+ public static void usage(
+ Foo<?> fooWildcard,
+ Foo<? super Api> fooWildcardEx,
+ Bar<?> barWildcard,
+ Bar<? extends Api> barWildcardEx,
+ Foo fooRaw,
+ Bar barRaw
+ ) {}
+
+ public abstract Foo<?> fooWildcardGet();
+ public abstract Foo<? super Api> fooWildcardExGet();
+ public abstract Bar<?> barWildcardGet();
+ public abstract Bar<? extends Api> barWildcardExGet();
+ public abstract Foo fooRawGet();
+ public abstract Bar barRawGet();
+}
diff --git a/test-utils/testData/api/recordJavaAnnotationTypes.kt b/test-utils/testData/api/recordJavaAnnotationTypes.kt
new file mode 100644
index 00000000..c268f6a2
--- /dev/null
+++ b/test-utils/testData/api/recordJavaAnnotationTypes.kt
@@ -0,0 +1,46 @@
+/*
+ * 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: RecordJavaProcessor
+// EXPECTED:
+// java.util.List: javaSrc/p1/J.java
+// p1.Anno: javaSrc/p1/J.java
+// p1.Bnno: javaSrc/p1/J.java
+// p1.K: javaSrc/p1/J.java
+// END
+
+// FILE: p1/J.java
+package p1;
+
+import java.util.List;
+
+@interface Anno {
+}
+
+@Anno
+@Bnno
+public class J {
+ List<K> l = null;
+}
+
+// FILE: p1/K.kt
+package p1;
+
+annotation class Bnno
+
+class K
diff --git a/test-utils/testData/api/recordJavaAsMemberOf.kt b/test-utils/testData/api/recordJavaAsMemberOf.kt
new file mode 100644
index 00000000..4c06bc1c
--- /dev/null
+++ b/test-utils/testData/api/recordJavaAsMemberOf.kt
@@ -0,0 +1,47 @@
+/*
+ * 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: RecordJavaAsMemberOfProcessor
+// EXPECTED:
+// p1.A: javaSrc/p1/B.java
+// p1.B: javaSrc/p1/A.java
+// p1.C: javaSrc/p1/B.java
+// p1.D: javaSrc/p1/A.java
+// p1.D: javaSrc/p1/B.java
+// p1.E: javaSrc/p1/B.java
+// END
+
+// FILE: p1/A.java
+package p1;
+public class A<T> extends B<T, D> {
+}
+
+// FILE: p1/B.java
+package p1;
+public class B<T, R> {
+ public <T extends D> R f(A<? super C> p, E p2) {
+ return null;
+ }
+}
+
+// FILE: p1/C.kt
+package p1;
+class C
+class D
+class E
+val a = A<C>() \ No newline at end of file
diff --git a/test-utils/testData/api/recordJavaGetAllMembers.kt b/test-utils/testData/api/recordJavaGetAllMembers.kt
new file mode 100644
index 00000000..55da59d9
--- /dev/null
+++ b/test-utils/testData/api/recordJavaGetAllMembers.kt
@@ -0,0 +1,65 @@
+/*
+ * 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: RecordJavaGetAllMembersProcessor
+// EXPECTED:
+// p1.C: javaSrc/p1/B.java
+// p1.D: javaSrc/p1/C.java
+// p1.R2: javaSrc/p1/B.java
+// p1.R3: javaSrc/p1/C.java
+// p1.V2: javaSrc/p1/B.java
+// p1.V3: javaSrc/p1/C.java
+// END
+
+// FILE: p1/A.kt
+package p1;
+class A : B {
+ fun f1(): R1
+ val v1: V1 = TODO()
+}
+
+// FILE: p1/B.java
+package p1;
+public class B extends C {
+ R2 f2() { return null }
+ V2 v2 = null;
+}
+
+// FILE: p1/C.java
+package p1;
+public class C extends D {
+ R3 f3() { return null }
+ V3 v3 = null;
+}
+
+// FILE: p1/D.kt
+package p1;
+
+class D {
+ fun f4(): R4
+ val v4: V4 = TODO()
+}
+
+class R1
+class R2
+class R3
+class R4
+class V1
+class V2
+class V3
+class V4
diff --git a/test-utils/testData/api/recordJavaOverrides.kt b/test-utils/testData/api/recordJavaOverrides.kt
new file mode 100644
index 00000000..f8c9b88f
--- /dev/null
+++ b/test-utils/testData/api/recordJavaOverrides.kt
@@ -0,0 +1,71 @@
+/*
+ * 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: RecordJavaOverridesProcessor
+// EXPECTED:
+// p1.B: javaSrc/p1/A.java
+// p1.C: javaSrc/p1/B.java
+// p1.R1: javaSrc/p1/A.java
+// p1.R1: javaSrc/p1/C.java
+// p1.R2: javaSrc/p1/A.java
+// p1.R2: javaSrc/p1/C.java
+// p1.V1: javaSrc/p1/A.java
+// p1.V1: javaSrc/p1/C.java
+// p1.V2: javaSrc/p1/A.java
+// p1.V2: javaSrc/p1/C.java
+// END
+
+// FILE: p1/A.java
+package p1;
+public class A extends B {
+ R1 f1(V1 v) {
+ return null
+ }
+
+ R2 f2(V2 v) {
+ return null
+ }
+}
+
+// FILE: p1/B.java
+package p1;
+public class B extends C {
+ R1 f1(V1 v) {
+ return null
+ }
+}
+
+// FILE: p1/C.java
+package p1;
+public class C extends D {
+ R1 f1(V1 v) {
+ return null
+ }
+
+ R2 f2(V2 v) {
+ return null
+ }
+}
+
+// FILE: p1/D.kt
+package p1;
+
+class V1
+class V2
+class R1
+class R2
diff --git a/test-utils/testData/api/recordJavaResolutions.kt b/test-utils/testData/api/recordJavaResolutions.kt
new file mode 100644
index 00000000..4f535ce5
--- /dev/null
+++ b/test-utils/testData/api/recordJavaResolutions.kt
@@ -0,0 +1,90 @@
+/*
+ * 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: RecordJavaProcessor
+// EXPECTED:
+// p3.K3: javaSrc/p1/TestJ2K.java
+// p1.J1: javaSrc/p1/TestJ2J.java
+// p1.J3: javaSrc/p1/TestJ2J.java
+// p1.K1: javaSrc/p1/TestJ2K.java
+// p1.K3: javaSrc/p1/TestJ2K.java
+// p2.J2: javaSrc/p1/TestJ2J.java
+// p2.K2: javaSrc/p1/TestJ2K.java
+// p3.J3: javaSrc/p1/TestJ2J.java
+// END
+
+// FILE: p1/TestJ2K.java
+package p1;
+
+import p2.K2;
+import p3.*;
+
+public class TestJ2K {
+ K1 k1 = null;
+ K2 k2 = null;
+ K3 k3 = null;
+}
+
+// FILE: p1/TestJ2J.java
+package p1;
+
+import p2.J2;
+import p3.*;
+
+public class TestJ2J {
+ J1 j1 = null;
+ J2 j2 = null;
+ J3 j3 = null;
+}
+
+// FILE: p1/K1.kt
+package p1
+class K1
+// FILE: p1/K2.kt
+package p1
+class K2
+// FILE: p2/K2.kt
+package p2
+class K2
+// FILE: p3/K1.kt
+package p3
+class K1
+// FILE: p3/K2.kt
+package p3
+class K2
+// FILE: p3/K3.kt
+package p3
+class K3
+// FILE: p1/J1.java
+package p1;
+public class J1 {}
+// FILE: p1/J2.java
+package p1;
+public class J2 {}
+// FILE: p2/J2.java
+package p2;
+public class J2 {}
+// FILE: p3/J1.java
+package p3;
+public class J1 {}
+// FILE: p3/J2.java
+package p3;
+public class J2 {}
+// FILE: p3/J3.java
+package p3;
+public class J3 {}
diff --git a/test-utils/testData/api/recordJavaSupertypes.kt b/test-utils/testData/api/recordJavaSupertypes.kt
new file mode 100644
index 00000000..d7b7a37f
--- /dev/null
+++ b/test-utils/testData/api/recordJavaSupertypes.kt
@@ -0,0 +1,42 @@
+/*
+ * 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: RecordJavaSupertypesProcessor
+// EXPECTED:
+// <anonymous>.A: javaSrc/A.java
+// <anonymous>.B: javaSrc/A.java
+// <anonymous>.C: javaSrc/A.java
+// <anonymous>.D: javaSrc/C.java
+// END
+
+// FILE: A.java
+public class A extends B<C<A>> {
+}
+
+// FILE: B.kt
+open class B<T>() : C<T>()
+
+// FILE: C.java
+public class C<T> extends D {
+
+}
+
+// FILE: D.java
+public class D {
+
+} \ No newline at end of file
diff --git a/test-utils/testData/api/referenceElement.kt b/test-utils/testData/api/referenceElement.kt
new file mode 100644
index 00000000..513ad429
--- /dev/null
+++ b/test-utils/testData/api/referenceElement.kt
@@ -0,0 +1,75 @@
+/*
+ * 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: ReferenceElementProcessor
+// EXPECTED:
+// KSClassifierReferenceImpl: Qualifier of B is A
+// KSClassifierReferenceImpl: Qualifier of C is A
+// KSClassifierReferenceImpl: Qualifier of Int is null
+// KSClassifierReferenceImpl: Qualifier of String is null
+// KSClassifierReferenceDescriptorImpl: Qualifier of Int is null
+// KSClassifierReferenceDescriptorImpl: Qualifier of String is null
+// KSClassifierReferenceDescriptorImpl: Qualifier of Y is X
+// KSClassifierReferenceDescriptorImpl: Qualifier of Z<Int> is X<String>
+// KSDefNonNullReferenceImpl: Enclosed type of T
+// KSClassifierReferenceJavaImpl: Qualifier of H is J<String>
+// KSClassifierReferenceJavaImpl: Qualifier of I is J
+// KSClassifierReferenceJavaImpl: Qualifier of Object is null
+// KSClassifierReferenceJavaImpl: Qualifier of Object is null
+// KSClassifierReferenceJavaImpl: Qualifier of Object is null
+// KSClassifierReferenceJavaImpl: Qualifier of Object is null
+// KSClassifierReferenceJavaImpl: Qualifier of String is null
+// END
+
+// MODULE: lib
+// FILE: lib.kt
+class X<T1> {
+ class Y
+ inner class Z<T2>
+}
+
+val z: X.Y = X.Y()
+val w: X<String>.Z<Int> = X<String>().Z<Int>()
+
+// MODULE: main(lib)
+// FILE: reference.kt
+class A<T1> {
+ class B
+ inner class C<T2>
+}
+
+class DefNonNull<T> {
+ val u: T & Any
+}
+
+val x: A.B = A.B()
+val y: A<String>.C<Int> = A<String>().C<Int>()
+
+// FILE: J.java
+class J<T> {
+ class H {
+ }
+
+ static class I {
+ }
+}
+
+class K {
+ J<String>.H x = null;
+ J.I z = null;
+}
diff --git a/test-utils/testData/api/replaceWithErrorTypeArgs.kt b/test-utils/testData/api/replaceWithErrorTypeArgs.kt
new file mode 100644
index 00000000..4a4bd9b0
--- /dev/null
+++ b/test-utils/testData/api/replaceWithErrorTypeArgs.kt
@@ -0,0 +1,134 @@
+/*
+ * 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: ReplaceWithErrorTypeArgsProcessor
+// EXPECTED:
+// KS.star.replace([INVARIANT Int, INVARIANT String]): KS<Int, String>
+// KS.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KS.asType([INVARIANT Int, INVARIANT String]): KS<Int, String>
+// KS.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KS.asType(emptyList()): KS<T1, T2>
+// KL.star.replace([INVARIANT Int, INVARIANT String]): KL<Int, String>
+// KL.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KL.asType([INVARIANT Int, INVARIANT String]): KL<Int, String>
+// KL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KL.asType(emptyList()): KL<T1, T2>
+// JS.star.replace([INVARIANT Int, INVARIANT String]): JS<Int, String>
+// JS.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JS.asType([INVARIANT Int, INVARIANT String]): JS<Int, String>
+// JS.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JS.asType(emptyList()): JS<T1, T2>
+// JL.star.replace([INVARIANT Int, INVARIANT String]): JL<Int, String>
+// JL.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JL.asType([INVARIANT Int, INVARIANT String]): JL<Int, String>
+// JL.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JL.asType(emptyList()): JL<T1, T2>
+// KS1.star.replace([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// KS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KS1.asType([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// KS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KS1.asType(emptyList()): KS1<T>
+// KL1.star.replace([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// KL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KL1.asType([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// KL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KL1.asType(emptyList()): KL1<T>
+// JS1.star.replace([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// JS1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JS1.asType([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// JS1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JS1.asType(emptyList()): JS1<T>
+// JL1.star.replace([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// JL1.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JL1.asType([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// JL1.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JL1.asType(emptyList()): JL1<T>
+// JSE.star.replace([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// JSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JSE.asType([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// JSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JSE.asType(emptyList()): JSE
+// JSE.E.star.replace([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// JSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JSE.E.asType([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// JSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JSE.E.asType(emptyList()): JSE.E
+// JLE.star.replace([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// JLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JLE.asType([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// JLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JLE.asType(emptyList()): JLE
+// JLE.E.star.replace([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// JLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JLE.E.asType([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// JLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// JLE.E.asType(emptyList()): JLE.E
+// KSE.star.replace([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// KSE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KSE.asType([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// KSE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KSE.asType(emptyList()): KSE
+// KSE.E.star.replace([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// KSE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KSE.E.asType([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// KSE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KSE.E.asType(emptyList()): E
+// KLE.star.replace([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// KLE.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KLE.asType([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// KLE.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KLE.asType(emptyList()): KLE
+// KLE.E.star.replace([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// KLE.E.star.replace([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KLE.E.asType([INVARIANT Int, INVARIANT String]): <ERROR TYPE>
+// KLE.E.asType([INVARIANT NotExist1, INVARIANT NotExist2]): <ERROR TYPE>
+// KLE.E.asType(emptyList()): KLE.E
+// END
+
+// MODULE: lib
+// FILE: JL.java
+class JL<T1, T2> {}
+class JL1<T> {}
+enum JLE {
+ E
+}
+
+// FILE: KL.kt
+class KL<T1, T2>
+class KL1<T>
+enum class KLE {
+ E
+}
+
+// MODULE: main(lib)
+// FILE: JS.java
+class JS<T1, T2> {}
+class JS1<T> {}
+enum JSE {
+ E
+}
+
+// FILE: KS.kt
+class KS<T1, T2>
+class KS1<T>
+enum class KSE {
+ E
+}
+
+val x: KS<Int, String> = TODO()
+val y: KS<NotExist1, NotExist2> = TODO()
diff --git a/test-utils/testData/api/resolveJavaType.kt b/test-utils/testData/api/resolveJavaType.kt
new file mode 100644
index 00000000..b732b270
--- /dev/null
+++ b/test-utils/testData/api/resolveJavaType.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: ResolveJavaTypeProcessor
+// EXPECTED:
+// C<*kotlin.Any?>
+// C.<init>.X?
+// C<*kotlin.Any?>
+// kotlin.Int
+// kotlin.String?
+// kotlin.collections.MutableSet<*kotlin.Any?>?
+// kotlin.Unit
+// kotlin.IntArray?
+// C.T?
+// C.PFun.P?
+// kotlin.collections.MutableList<out kotlin.collections.MutableSet<kotlin.Double?>?>?
+// kotlin.collections.MutableList<in kotlin.collections.MutableList<out kotlin.Double?>?>?
+// Bar?
+// kotlin.Array<Bar?>?
+// Foo<Base.T?, Base.Inner.P?>?
+// Bar<Base.Inner.P?, Base.T?>?
+// kotlin.collections.MutableList<Base.T?>?
+// kotlin.Unit
+// Base.T?
+// kotlin.Unit
+// kotlin.Array<Base.T?>?
+// kotlin.Unit
+// kotlin.Array<Base.T?>?
+// kotlin.Unit
+// kotlin.collections.MutableList<Base.T?>?
+// kotlin.Unit
+// Base.T?
+// kotlin.Unit
+// kotlin.Array<Base.T?>?
+// kotlin.Unit
+// kotlin.Array<Base.T?>?
+// kotlin.Unit
+// Base<Another.T?, Another.T?>?
+// kotlin.Int
+// kotlin.Int
+// JavaEnum
+// kotlin.Unit
+// kotlin.Array<JavaEnum?>?
+// kotlin.String?
+// JavaEnum?
+// END
+// FILE: a.kt
+annotation class Test
+@Test
+class Foo<P>: C<P>() {
+
+}
+
+class Bar
+
+// FILE: C.java
+import java.util.List;
+import java.util.Set;
+
+public class C<T> {
+ public C() {}
+ // to reproduce the case where type reference is owned by a constructor
+ public <X> C(X x) {}
+ public int intFun() {}
+
+ public String strFun() {}
+
+ public void wildcardParam(Set<?> param1) {}
+
+ public int[] intArrayFun() {}
+
+ public T TFoo() {}
+
+ public <P> P PFun() {}
+
+ public List<? extends Set<Double>> extendsSetFun() {}
+
+ public List<? super List<? extends Double>> extendsListTFun() {}
+
+ public Bar BarFun() {}
+
+ public Bar[] BarArryFun() {}
+}
+
+// FILE: Base.java
+import java.util.List;
+
+class Foo<T1,T2> {}
+class Bar<T1, T2> {}
+
+class Base<T,P> {
+ void genericT(List<T> t){};
+ void singleT(T t){};
+ void varargT(T... t){};
+ void arrayT(T[] t){};
+
+ class Inner<P> {
+ void genericT(List<T> t){};
+ void singleT(T t){};
+ void varargT(T... t){};
+ void arrayT(T[] t){};
+ Foo<T, P> foo;
+ Bar<P, T> bar;
+ }
+}
+
+class Another<T> {
+ Base<T, T> base;
+}
+
+public enum JavaEnum {
+ VAL1(1),
+ VAL2(2);
+
+ private int x;
+
+ JavaEnum(int x) {
+ this.x = x;
+ }
+ void enumMethod() {}
+}
diff --git a/test-utils/testData/api/sealedClass.kt b/test-utils/testData/api/sealedClass.kt
new file mode 100644
index 00000000..1af34fcd
--- /dev/null
+++ b/test-utils/testData/api/sealedClass.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: SealedClassProcessor
+// EXPECTED:
+// from lib
+// [Const: KOTLIN_LIB, NotANumber: KOTLIN_LIB, Sum: KOTLIN_LIB]
+// from source
+// Expr : [Const: KOTLIN, NotANumber: KOTLIN, Sum: KOTLIN]
+// Const : []
+// Sum : []
+// NotANumber : []
+// END
+
+// MODULE: lib
+// FILE: lib.kt
+package lib
+sealed class Expr
+data class Const(val number: Double) : Expr()
+data class Sum(val e1: Expr, val e2: Expr) : Expr()
+object NotANumber : Expr()
+
+// MODULE: main(lib)
+// FILE: sealed.kt
+sealed class Expr
+data class Const(val number: Double) : Expr()
+data class Sum(val e1: Expr, val e2: Expr) : Expr()
+object NotANumber : Expr()
diff --git a/test-utils/testData/api/signatureMapper.kt b/test-utils/testData/api/signatureMapper.kt
new file mode 100644
index 00000000..dab48bb6
--- /dev/null
+++ b/test-utils/testData/api/signatureMapper.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: MapSignatureProcessor
+// EXPECTED:
+// LCls;
+// a: I
+// foo: ()Ljava/lang/String;
+// <init>: ()V
+// LJavaIntefaceWithVoid;
+// getVoid: ()Ljava/lang/Void;
+// LJavaClass;
+// <init>: ()V
+// LJavaAnno;
+// intParam: I
+// <init>: (I)V
+// END
+
+// FILE: Cls.kt
+class Cls {
+ val a: Int = 1
+
+ fun foo(): String { return "1" }
+}
+
+// FILE: JavaIntefaceWithVoid.java
+interface JavaIntefaceWithVoid {
+ Void getVoid();
+}
+
+// FILE: JavaClass.java
+class JavaClass {
+ JavaClass() {}
+}
+
+// FILE: JavaAnno.java
+@interface JavaAnno {
+ int intParam();
+}
diff --git a/test-utils/testData/api/superTypes.kt b/test-utils/testData/api/superTypes.kt
new file mode 100644
index 00000000..ce944f0a
--- /dev/null
+++ b/test-utils/testData/api/superTypes.kt
@@ -0,0 +1,112 @@
+/*
+ * 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: SuperTypesProcessor
+// EXPECTED:
+// KotlinInterfaceInLib: kotlin.Any
+// KotlinInterfaceInLibWithSuper: KotlinInterfaceInLib
+// AbstractKotlinClassInLib: kotlin.Any
+// AbstractKotlinClassInLibWithSuperClass: AbstractKotlinClassInLib
+// AbstractKotlinClassInLibWithSuperInterface: KotlinInterfaceInLib
+// KotlinClassInLib: kotlin.Any
+// KotlinClassInLibWithSuperAbstract: AbstractKotlinClassInLib
+// KotlinClassInLibWithSuperClass: KotlinClassInLib
+// KotlinClassInLibWithSuperInterface: KotlinInterfaceInLib
+// JavaInterfaceInLib: kotlin.Any
+// JavaInterfaceInLibWithSuper: JavaInterfaceInLib
+// AbstractJavaClassInLib: kotlin.Any
+// AbstractJavaClassInLibWithSuperInterface: JavaInterfaceInLib
+// AbstractJavaClassInLibWithSuperClass: AbstractJavaClassInLib
+// JavaClassInLib: kotlin.Any
+// JavaClassInLibWithSuperInterface: JavaInterfaceInLib
+// JavaClassInLibWithSuperAbstract: AbstractJavaClassInLib
+// JavaClassInLibWithSuperClass: JavaClassInLib
+// KotlinInterfaceInSource: kotlin.Any
+// KotlinInterfaceInSourceWithSuper: KotlinInterfaceInSource
+// AbstractKotlinClassInSource: kotlin.Any
+// AbstractKotlinClassInSourceWithSuperClass: AbstractKotlinClassInSource
+// AbstractKotlinClassInSourceWithSuperInterface: KotlinInterfaceInSource
+// KotlinClassInSource: kotlin.Any
+// KotlinClassInSourceWithSuperAbstract: AbstractKotlinClassInSource
+// KotlinClassInSourceWithSuperClass: KotlinClassInSource
+// KotlinClassInSourceWithSuperInterface: KotlinInterfaceInSource
+// JavaInterfaceInSource: kotlin.Any
+// JavaInterfaceInSourceWithSuper: JavaInterfaceInSource
+// AbstractJavaClassInSource: kotlin.Any
+// AbstractJavaClassInSourceWithSuperInterface: JavaInterfaceInSource
+// AbstractJavaClassInSourceWithSuperClass: AbstractJavaClassInSource
+// JavaClassInSource: kotlin.Any
+// JavaClassInSourceWithSuperInterface: JavaInterfaceInSource
+// JavaClassInSourceWithSuperAbstract: AbstractJavaClassInSource
+// JavaClassInSourceWithSuperClass: JavaClassInSource
+// END
+
+// MODULE: lib
+// FILE: KotlinLib.kt
+interface KotlinInterfaceInLib
+interface KotlinInterfaceInLibWithSuper : KotlinInterfaceInLib
+
+abstract class AbstractKotlinClassInLib
+abstract class AbstractKotlinClassInLibWithSuperClass : AbstractKotlinClassInLib()
+abstract class AbstractKotlinClassInLibWithSuperInterface : KotlinInterfaceInLib
+
+open class KotlinClassInLib
+open class KotlinClassInLibWithSuperAbstract : AbstractKotlinClassInLib()
+open class KotlinClassInLibWithSuperClass : KotlinClassInLib()
+open class KotlinClassInLibWithSuperInterface : KotlinInterfaceInLib
+
+// FILE: JavaLib.java
+interface JavaInterfaceInLib {}
+interface JavaInterfaceInLibWithSuper extends JavaInterfaceInLib {}
+
+abstract class AbstractJavaClassInLib {}
+abstract class AbstractJavaClassInLibWithSuperInterface implements JavaInterfaceInLib {}
+abstract class AbstractJavaClassInLibWithSuperClass extends AbstractJavaClassInLib {}
+
+class JavaClassInLib {}
+class JavaClassInLibWithSuperInterface implements JavaInterfaceInLib {}
+class JavaClassInLibWithSuperAbstract extends AbstractJavaClassInLib {}
+class JavaClassInLibWithSuperClass extends JavaClassInLib {}
+
+// MODULE: main(lib)
+// FILE: KotlinSource.kt
+interface KotlinInterfaceInSource
+interface KotlinInterfaceInSourceWithSuper : KotlinInterfaceInSource
+
+abstract class AbstractKotlinClassInSource
+abstract class AbstractKotlinClassInSourceWithSuperClass : AbstractKotlinClassInSource()
+abstract class AbstractKotlinClassInSourceWithSuperInterface : KotlinInterfaceInSource
+
+open class KotlinClassInSource
+open class KotlinClassInSourceWithSuperAbstract : AbstractKotlinClassInSource()
+open class KotlinClassInSourceWithSuperClass : KotlinClassInSource()
+open class KotlinClassInSourceWithSuperInterface : KotlinInterfaceInSource
+
+// FILE: JavaSource.java
+interface JavaInterfaceInSource {}
+interface JavaInterfaceInSourceWithSuper extends JavaInterfaceInSource {}
+
+abstract class AbstractJavaClassInSource {}
+abstract class AbstractJavaClassInSourceWithSuperInterface implements JavaInterfaceInSource {}
+abstract class AbstractJavaClassInSourceWithSuperClass extends AbstractJavaClassInSource {}
+
+class JavaClassInSource {}
+class JavaClassInSourceWithSuperInterface implements JavaInterfaceInSource {}
+class JavaClassInSourceWithSuperAbstract extends AbstractJavaClassInSource {}
+class JavaClassInSourceWithSuperClass extends JavaClassInSource {}
+
diff --git a/test-utils/testData/api/throwList.kt b/test-utils/testData/api/throwList.kt
new file mode 100644
index 00000000..56431756
--- /dev/null
+++ b/test-utils/testData/api/throwList.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// TEST PROCESSOR: ThrowListProcessor
+// EXPECTED:
+// java.io.IOException,java.util.NoSuchElementException
+// java.io.IOException,java.lang.IndexOutOfBoundsException
+// java.io.IOException,java.util.NoSuchElementException
+// java.lang.IndexOutOfBoundsException
+// java.io.IOException
+// java.io.IOException,java.lang.IndexOutOfBoundsException
+// java.lang.IndexOutOfBoundsException
+// java.lang.IllegalArgumentException
+// java.lang.IllegalStateException
+// java.io.IOException
+// java.lang.IllegalStateException,java.lang.IllegalArgumentException
+// java.io.IOException
+// java.lang.IndexOutOfBoundsException
+// java.io.IOException,java.lang.IndexOutOfBoundsException
+// java.io.IOException
+// END
+// MODULE: lib
+// FILE: JavaLib.java
+import java.io.IOException;
+import java.lang.IndexOutOfBoundsException;
+public class JavaLib {
+ public JavaLib() throws IOException {
+
+ }
+
+ public void foo() throws IOException {
+ throw new IOException();
+ }
+ public void foo(int i) throws IndexOutOfBoundsException {
+ throw new IndexOutOfBoundsException();
+ }
+ public void foo(String[] s) throws IOException, IndexOutOfBoundsException {
+ throw new IOException();
+ }
+}
+// FILE: KtLib.kt
+import java.io.IOException
+import java.lang.IllegalArgumentException
+import java.lang.IllegalStateException
+
+class KtLib {
+ @Throws(java.io.IOException::class)
+ fun throwsLibKt() {
+ throw java.io.IOException()
+ }
+ @Throws(java.lang.IndexOutOfBoundsException::class)
+ fun throwsLibKt(i: Int) {
+ throw java.lang.IndexOutOfBoundsException()
+ }
+ @Throws(java.io.IOException::class, java.lang.IndexOutOfBoundsException::class)
+ fun throwsLibKt(s: Array<String>) {
+ throw java.io.IOException()
+ }
+
+ @get:Throws(IllegalArgumentException::class)
+ val getterThrows: Int = 3
+ @set:Throws(IllegalStateException::class)
+ var setterThrows: Int = 3
+ @get:Throws(IOException::class)
+ @set:Throws(IllegalStateException::class, IllegalArgumentException::class)
+ var bothThrows: Int = 3
+}
+// MODULE: main(lib)
+// FILE: ThrowsException.java
+import java.io.IOException;
+import java.lang.IndexOutOfBoundsException;
+
+public class ThrowsException {
+ public int foo() throws IOException, IndexOutOfBoundsException{
+ return 1;
+ }
+}
+// FILE: a.kt
+class ThrowsKt {
+ @Throws(java.io.IOException::class, java.util.NoSuchElementException::class)
+ fun throwsKT()
+
+ @set:Throws(java.lang.IndexOutOfBoundsException::class)
+ var a: Int
+ @Throws(java.io.IOException::class, java.util.NoSuchElementException::class)
+ get() {
+ return 1
+ }
+ set(a: Int) {
+
+ }
+}
diff --git a/test-utils/testData/api/topLevelMembers.kt b/test-utils/testData/api/topLevelMembers.kt
new file mode 100644
index 00000000..aee7e330
--- /dev/null
+++ b/test-utils/testData/api/topLevelMembers.kt
@@ -0,0 +1,138 @@
+/*
+ * 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: TopLevelMemberProcessor
+// EXPECTED:
+// lib : <init> -> lib.LibJavaClass
+// lib : <init> -> lib.RealLibClass
+// lib : <init> -> lib.RealLibClass$Companion
+// lib : functionInLib -> lib.LibKt
+// lib : functionInLibCompanion -> lib.RealLibClass$Companion
+// lib : functionInLibJvmName -> lib.LibCustomClassName
+// lib : functionInLibRealClass -> lib.RealLibClass
+// lib : javaFieldInLib -> lib.LibJavaClass
+// lib : javaMethodInLib -> lib.LibJavaClass
+// lib : jvmStaticFunctionInLibCompanion -> lib.RealLibClass$Companion
+// lib : jvmStaticValueInLibCompanion -> lib.RealLibClass$Companion
+// lib : jvmStaticVariableInLibCompanion -> lib.RealLibClass$Companion
+// lib : valueInLib -> lib.LibKt
+// lib : valueInLibCompanion -> lib.RealLibClass$Companion
+// lib : valueInLibJvmName -> lib.LibCustomClassName
+// lib : valueInLibRealClass -> lib.RealLibClass
+// lib : variableInLib -> lib.LibKt
+// lib : variableInLibCompanion -> lib.RealLibClass$Companion
+// lib : variableInLibJvmName -> lib.LibCustomClassName
+// lib : variableInLibRealClass -> lib.RealLibClass
+// main : <init> -> main.MainJavaClass
+// main : <init> -> main.RealMainClass
+// main : <init> -> main.RealMainClass$Companion
+// main : functionInMain -> main.MainKt
+// main : functionInMainCompanion -> main.RealMainClass$Companion
+// main : functionInMainJvmName -> main.MainCustomClassName
+// main : functionInMainRealClass -> main.RealMainClass
+// main : javaFieldInMain -> main.MainJavaClass
+// main : javaMethodInMain -> main.MainJavaClass
+// main : jvmStaticFunctionInMainCompanion -> main.RealMainClass$Companion
+// main : jvmStaticValueInMainCompanion -> main.RealMainClass$Companion
+// main : jvmStaticVariableInMainCompanion -> main.RealMainClass$Companion
+// main : valueInMain -> main.MainKt
+// main : valueInMainCompanion -> main.RealMainClass$Companion
+// main : valueInMainJvmName -> main.MainCustomClassName
+// main : valueInMainRealClass -> main.RealMainClass
+// main : variableInMain -> main.MainKt
+// main : variableInMainCompanion -> main.RealMainClass$Companion
+// main : variableInMainJvmName -> main.MainCustomClassName
+// main : variableInMainRealClass -> main.RealMainClass
+// END
+
+// MODULE: lib
+// FILE: lib.kt
+package lib
+fun functionInLib() {}
+val valueInLib: String = ""
+var variableInLib: String = ""
+class RealLibClass {
+ fun functionInLibRealClass() {}
+ val valueInLibRealClass: String = ""
+ var variableInLibRealClass: String = ""
+
+ companion object {
+ fun functionInLibCompanion() {}
+ val valueInLibCompanion: String = ""
+ var variableInLibCompanion: String = ""
+ @JvmStatic
+ fun jvmStaticFunctionInLibCompanion() {}
+ @JvmStatic
+ val jvmStaticValueInLibCompanion: String = ""
+ @JvmStatic
+ var jvmStaticVariableInLibCompanion: String = ""
+ }
+}
+// FILE: customName.kt
+@file:JvmName("LibCustomClassName")
+package lib
+fun functionInLibJvmName() {}
+val valueInLibJvmName: String = ""
+var variableInLibJvmName: String = ""
+
+// FILE: lib/LibJavaClass.java
+package lib;
+public class LibJavaClass {
+ public LibJavaClass() {}
+ private String javaFieldInLib;
+ private void javaMethodInLib() {
+ }
+}
+
+// MODULE: main(lib)
+// FILE: main.kt
+package main
+fun functionInMain() {}
+val valueInMain: String = ""
+var variableInMain: String = ""
+class RealMainClass {
+ fun functionInMainRealClass() {}
+ val valueInMainRealClass: String = ""
+ var variableInMainRealClass: String = ""
+
+ companion object {
+ fun functionInMainCompanion() {}
+ val valueInMainCompanion: String = ""
+ var variableInMainCompanion: String = ""
+ @JvmStatic
+ fun jvmStaticFunctionInMainCompanion() {}
+ @JvmStatic
+ val jvmStaticValueInMainCompanion: String = ""
+ @JvmStatic
+ var jvmStaticVariableInMainCompanion: String = ""
+ }
+}
+// FILE: customName.kt
+@file:JvmName("MainCustomClassName")
+package main
+fun functionInMainJvmName() {}
+val valueInMainJvmName: String = ""
+var variableInMainJvmName: String = ""
+// FILE: main/MainJavaClass.java
+package main;
+public class MainJavaClass {
+ public MainJavaClass() {}
+ private String javaFieldInMain;
+ private void javaMethodInMain() {
+ }
+}
diff --git a/test-utils/testData/api/typeAlias.kt b/test-utils/testData/api/typeAlias.kt
new file mode 100644
index 00000000..3d1e2777
--- /dev/null
+++ b/test-utils/testData/api/typeAlias.kt
@@ -0,0 +1,55 @@
+/*
+ * 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: TypeAliasProcessor
+// EXPECTED:
+// a : A = String
+// b : B = String
+// c : CC = A = String
+// d : String
+// listOfInt : ListOfInt = List<Int>
+// listOfInt_B : ListOfInt_B = ListOfInt = List<Int>
+// listOfInt_C : ListOfInt_C = ListOfInt_B = ListOfInt = List<Int>
+// myList : MyList<Long> = List<T>
+// myList_B : List<Number>
+// myList_String : MyList_String = MyList<String> = List<T>
+// myList_b_String : MyList_B_String = MyList_B<String> = MyList<R> = List<T>
+// END
+
+typealias A = String
+typealias B = String
+typealias CC = A
+typealias ListOfInt = List<Int>
+typealias ListOfInt_B = ListOfInt
+typealias ListOfInt_C = ListOfInt_B
+typealias MyList<T> = List<T>
+typealias MyList_B<R> = MyList<R>
+typealias MyList_String = MyList<String>
+typealias MyList_B_String = MyList_B<String>
+
+val a: A = ""
+val b: B = ""
+val c: CC = ""
+val d: String = ""
+val listOfInt: ListOfInt = TODO()
+val listOfInt_B: ListOfInt_B = TODO()
+val listOfInt_C: ListOfInt_C = TODO()
+val myList: MyList<Long> = TODO()
+val myList_B: List<Number> = TODO()
+val myList_String: MyList_String = TODO()
+val myList_b_String: MyList_B_String = TODO()
diff --git a/test-utils/testData/api/typeAliasComparison.kt b/test-utils/testData/api/typeAliasComparison.kt
new file mode 100644
index 00000000..63262c5b
--- /dev/null
+++ b/test-utils/testData/api/typeAliasComparison.kt
@@ -0,0 +1,46 @@
+/*
+ * 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: TypeAliasComparisonProcessor
+// EXPECTED:
+// String = String : true
+// String = String : true
+// String = String : true
+// String = String : true
+// String = [@Anno] [typealias F] : true
+// String = [@Anno] [typealias F] : true
+// String = [@Bnno] [typealias F] : true
+// String = [@Bnno] [typealias F] : true
+// [@Anno] [typealias F] = String : true
+// [@Anno] [typealias F] = String : true
+// [@Anno] [typealias F] = [@Anno] [typealias F] : true
+// [@Anno] [typealias F] = [@Bnno] [typealias F] : true
+// [@Bnno] [typealias F] = String : true
+// [@Bnno] [typealias F] = String : true
+// [@Bnno] [typealias F] = [@Anno] [typealias F] : true
+// [@Bnno] [typealias F] = [@Bnno] [typealias F] : true
+// END
+
+annotation class Anno
+annotation class Bnno
+
+typealias F = String
+typealias Foo = (@Anno F) -> String
+
+fun bar(arg: @Bnno F) {
+}
diff --git a/test-utils/testData/api/typeComposure.kt b/test-utils/testData/api/typeComposure.kt
new file mode 100644
index 00000000..cf4666b8
--- /dev/null
+++ b/test-utils/testData/api/typeComposure.kt
@@ -0,0 +1,127 @@
+/*
+ * 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: TypeComposureProcessor
+// EXPECTED:
+// C<*> ?= C<*> : true
+// C<*> ?= C<Any> : true
+// C<*> ?= C<Int> : true
+// C<*> ?= C<Number> : true
+// C<*> ?= C<in Any> : true
+// C<*> ?= C<in Int> : true
+// C<*> ?= C<in Number> : true
+// C<*> ?= C<out Any> : true
+// C<*> ?= C<out Int> : true
+// C<*> ?= C<out Number> : true
+// C<Any> ?= C<*> : false
+// C<Any> ?= C<Any> : true
+// C<Any> ?= C<Int> : false
+// C<Any> ?= C<Number> : false
+// C<Any> ?= C<in Any> : false
+// C<Any> ?= C<in Int> : false
+// C<Any> ?= C<in Number> : false
+// C<Any> ?= C<out Any> : false
+// C<Any> ?= C<out Int> : false
+// C<Any> ?= C<out Number> : false
+// C<Int> ?= C<*> : false
+// C<Int> ?= C<Any> : false
+// C<Int> ?= C<Int> : true
+// C<Int> ?= C<Number> : false
+// C<Int> ?= C<in Any> : false
+// C<Int> ?= C<in Int> : false
+// C<Int> ?= C<in Number> : false
+// C<Int> ?= C<out Any> : false
+// C<Int> ?= C<out Int> : false
+// C<Int> ?= C<out Number> : false
+// C<Number> ?= C<*> : false
+// C<Number> ?= C<Any> : false
+// C<Number> ?= C<Int> : false
+// C<Number> ?= C<Number> : true
+// C<Number> ?= C<in Any> : false
+// C<Number> ?= C<in Int> : false
+// C<Number> ?= C<in Number> : false
+// C<Number> ?= C<out Any> : false
+// C<Number> ?= C<out Int> : false
+// C<Number> ?= C<out Number> : false
+// C<in Any> ?= C<*> : false
+// C<in Any> ?= C<Any> : true
+// C<in Any> ?= C<Int> : false
+// C<in Any> ?= C<Number> : false
+// C<in Any> ?= C<in Any> : true
+// C<in Any> ?= C<in Int> : false
+// C<in Any> ?= C<in Number> : false
+// C<in Any> ?= C<out Any> : false
+// C<in Any> ?= C<out Int> : false
+// C<in Any> ?= C<out Number> : false
+// C<in Int> ?= C<*> : false
+// C<in Int> ?= C<Any> : true
+// C<in Int> ?= C<Int> : true
+// C<in Int> ?= C<Number> : true
+// C<in Int> ?= C<in Any> : true
+// C<in Int> ?= C<in Int> : true
+// C<in Int> ?= C<in Number> : true
+// C<in Int> ?= C<out Any> : false
+// C<in Int> ?= C<out Int> : false
+// C<in Int> ?= C<out Number> : false
+// C<in Number> ?= C<*> : false
+// C<in Number> ?= C<Any> : true
+// C<in Number> ?= C<Int> : false
+// C<in Number> ?= C<Number> : true
+// C<in Number> ?= C<in Any> : true
+// C<in Number> ?= C<in Int> : false
+// C<in Number> ?= C<in Number> : true
+// C<in Number> ?= C<out Any> : false
+// C<in Number> ?= C<out Int> : false
+// C<in Number> ?= C<out Number> : false
+// C<out Any> ?= C<*> : false
+// C<out Any> ?= C<Any> : true
+// C<out Any> ?= C<Int> : true
+// C<out Any> ?= C<Number> : true
+// C<out Any> ?= C<in Any> : false
+// C<out Any> ?= C<in Int> : false
+// C<out Any> ?= C<in Number> : false
+// C<out Any> ?= C<out Any> : true
+// C<out Any> ?= C<out Int> : true
+// C<out Any> ?= C<out Number> : true
+// C<out Int> ?= C<*> : false
+// C<out Int> ?= C<Any> : false
+// C<out Int> ?= C<Int> : true
+// C<out Int> ?= C<Number> : false
+// C<out Int> ?= C<in Any> : false
+// C<out Int> ?= C<in Int> : false
+// C<out Int> ?= C<in Number> : false
+// C<out Int> ?= C<out Any> : false
+// C<out Int> ?= C<out Int> : true
+// C<out Int> ?= C<out Number> : false
+// C<out Number> ?= C<*> : false
+// C<out Number> ?= C<Any> : false
+// C<out Number> ?= C<Int> : true
+// C<out Number> ?= C<Number> : true
+// C<out Number> ?= C<in Any> : false
+// C<out Number> ?= C<in Int> : false
+// C<out Number> ?= C<in Number> : false
+// C<out Number> ?= C<out Any> : false
+// C<out Number> ?= C<out Int> : true
+// C<out Number> ?= C<out Number> : true
+// END
+
+open class C<T>
+
+val a: Int = 0
+val b: Number = 0
+val c: C<Int> = C<Int>()
diff --git a/test-utils/testData/api/typeParameterEquals.kt b/test-utils/testData/api/typeParameterEquals.kt
new file mode 100644
index 00000000..93060cb7
--- /dev/null
+++ b/test-utils/testData/api/typeParameterEquals.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: TypeParameterEqualsProcessor
+// EXPECTED:
+// true
+// true
+// END
+
+
+// FILE: a.kt
+
+interface Foo<T> {
+ val t: T
+}
+
+interface I<T, K: T>
diff --git a/test-utils/testData/api/typeParameterReference.kt b/test-utils/testData/api/typeParameterReference.kt
new file mode 100644
index 00000000..bc1428d2
--- /dev/null
+++ b/test-utils/testData/api/typeParameterReference.kt
@@ -0,0 +1,82 @@
+/*
+ * 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: TypeParameterReferenceProcessor
+// EXPECTED:
+// LibFoo: false
+// SelfReferencing: false
+// kotlin.String: false
+// SelfReferencing.T: false
+// Foo.T1: true
+// Foo.bar.T2: false
+// foo.T3: false
+// T
+// List<T>
+// T
+// MutableList<(T..T?)>
+// (SelfReferencingJava<(T..T?)>..SelfReferencingJava<(T..T?)>?)
+// (T1..T1?)
+// END
+
+// MODULE: lib
+// FILE: lib.kt
+interface LibFoo<T> {
+ val v: T
+ val w: List<T>
+}
+
+// FILE: LibSR.kt
+package lib;
+class SelfReferencing<T : SelfReferencing<T>>
+
+// FILE: JavaLib.java
+import java.util.List;
+
+interface JavaLib<T> {
+ public T genericFun();
+ public List<T> list();
+}
+
+// MODULE: main(lib)
+// FILE: main.kt
+
+class SelfReferencing<T : SelfReferencing<T>>
+
+class Foo<T1> {
+ inner class Bar {
+ val v: T1?
+ }
+
+ fun <T2> bar(p: T2) = 1
+
+ val libFoo: LibFoo<String>
+}
+
+fun <T3> foo(p: T3) = 1
+
+// FILE: SelfReferencingJava.java
+public class SelfReferencingJava<T extends SelfReferencingJava<T>> {
+}
+
+// FILE: BoundedTypeParameter.java
+
+public class BoundedTypeParameter {
+ static <T1, T2 extends T1> T2 method(T1 input) {
+ return null;
+ }
+}
diff --git a/test-utils/testData/api/validateTypes.kt b/test-utils/testData/api/validateTypes.kt
new file mode 100644
index 00000000..2a592307
--- /dev/null
+++ b/test-utils/testData/api/validateTypes.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2022 Google LLC
+ * Copyright 2010-2022 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: ValidateProcessor
+// EXPECTED:
+// ErrorInMember invalid
+// goodProp valid
+// badProp invalid
+// errorFun invalid
+// <init> valid
+// SkipErrorInMember valid
+// skipProp valid
+// skipFun valid
+// <init> valid
+// GoodClass valid
+// C valid
+// BadJavaClass invalid
+// ErrorAnnotationType invalid
+// ErrorInAnnotationArgumentSingleType invalid
+// ErrorInAnnotationArgumentMultipleTypes invalid
+// ErrorInAnnotationArgumentComposed invalid
+// ValidAnnotationArgumentType valid
+// END
+// FILE: a.kt
+annotation class Anno(val i: Int)
+
+annotation class AnnoWithTypes(
+ val type: KClass<*> = Any::class,
+ val types: Array<KClass<*>> = []
+)
+
+annotation class AnnoComposed(
+ val composed: AnnoWithTypes
+)
+
+@Anno(1)
+class ErrorInMember : C {
+ val goodProp: Int
+ val badProp: () -> NonExistType
+ fun errorFun(): NonExistType {
+
+ }
+}
+
+class SkipErrorInMember {
+ val skipProp: NonExistType
+ fun skipFun(): NonExitType {
+
+ }
+}
+
+@NonExistAnnotation
+class ErrorAnnotationType {
+}
+
+@Anno(1)
+open class GoodClass {
+ val a: Int = 1
+
+ fun foo(): Int = 1
+
+ fun bar() {
+ val x = a
+ }
+}
+
+@AnnoWithTypes(type = NonExistType::class)
+class ErrorInAnnotationArgumentSingleType {
+
+}
+
+@AnnoWithTypes(types = [ GoodClass::class, NonExistType::class ])
+class ErrorInAnnotationArgumentMultipleTypes {
+
+}
+
+@AnnoComposed(composed = AnnoWithTypes(type = NonExistType::class))
+class ErrorInAnnotationArgumentComposed {
+
+}
+
+@AnnoWithTypes(type = GoodClass::class)
+class ValidAnnotationArgumentType {
+
+}
+
+// FILE: C.java
+
+public class C extends GoodClass {}
+
+class BadJavaClass extends NonExistType {
+
+}
diff --git a/test-utils/testData/api/varianceTypeCheck.kt b/test-utils/testData/api/varianceTypeCheck.kt
new file mode 100644
index 00000000..a644570b
--- /dev/null
+++ b/test-utils/testData/api/varianceTypeCheck.kt
@@ -0,0 +1,84 @@
+/*
+ * 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: TypeComparisonProcessor
+// EXPECTED:
+// Any ?= Any : true
+// Any ?= Any? : false
+// Any ?= Foo<*> : true
+// Any ?= Foo<A> : true
+// Any ?= Foo<C> : true
+// Any ?= Foo<in B> : true
+// Any ?= Foo<out B> : true
+// Any? ?= Any : true
+// Any? ?= Any? : true
+// Any? ?= Foo<*> : true
+// Any? ?= Foo<A> : true
+// Any? ?= Foo<C> : true
+// Any? ?= Foo<in B> : true
+// Any? ?= Foo<out B> : true
+// Foo<*> ?= Any : false
+// Foo<*> ?= Any? : false
+// Foo<*> ?= Foo<*> : true
+// Foo<*> ?= Foo<A> : true
+// Foo<*> ?= Foo<C> : true
+// Foo<*> ?= Foo<in B> : true
+// Foo<*> ?= Foo<out B> : true
+// Foo<A> ?= Any : false
+// Foo<A> ?= Any? : false
+// Foo<A> ?= Foo<*> : false
+// Foo<A> ?= Foo<A> : true
+// Foo<A> ?= Foo<C> : false
+// Foo<A> ?= Foo<in B> : false
+// Foo<A> ?= Foo<out B> : false
+// Foo<C> ?= Any : false
+// Foo<C> ?= Any? : false
+// Foo<C> ?= Foo<*> : false
+// Foo<C> ?= Foo<A> : false
+// Foo<C> ?= Foo<C> : true
+// Foo<C> ?= Foo<in B> : false
+// Foo<C> ?= Foo<out B> : false
+// Foo<in B> ?= Any : false
+// Foo<in B> ?= Any? : false
+// Foo<in B> ?= Foo<*> : false
+// Foo<in B> ?= Foo<A> : true
+// Foo<in B> ?= Foo<C> : false
+// Foo<in B> ?= Foo<in B> : true
+// Foo<in B> ?= Foo<out B> : false
+// Foo<out B> ?= Any : false
+// Foo<out B> ?= Any? : false
+// Foo<out B> ?= Foo<*> : false
+// Foo<out B> ?= Foo<A> : false
+// Foo<out B> ?= Foo<C> : true
+// Foo<out B> ?= Foo<in B> : false
+// Foo<out B> ?= Foo<out B> : true
+// END
+
+@file:kotlin.Suppress("A", "B", "C", "Suppress")
+
+open class A
+open class B: A()
+open class C: B()
+
+class Foo<T>
+
+var ib: Foo<in B> = Foo<B>()
+var ob: Foo<out B> = Foo<B>()
+
+var a: Foo<A> = Foo<A>()
+var c: Foo<C> = Foo<C>()
diff --git a/test-utils/testData/api/visibilities.kt b/test-utils/testData/api/visibilities.kt
new file mode 100644
index 00000000..cc650894
--- /dev/null
+++ b/test-utils/testData/api/visibilities.kt
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TEST PROCESSOR: VisibilityProcessor
+// EXPECTED:
+// publicFun: PUBLIC,visible in A, B, D: true, true, true
+// packageFun: JAVA_PACKAGE,visible in A, B, D: true, false, true
+// privateFun: PRIVATE,visible in A, B, D: false, false, false
+// protectedFun: PROTECTED,visible in A, B, D: true, false, true
+// <init>: PUBLIC,visible in A, B, D: true, true, true
+// javaPackageField: JAVA_PACKAGE,visible in A, B, D: true, false, true
+// x: INTERNAL,visible in A, B, D: false, false, false
+// y: PROTECTED,visible in A, B, D: true, false, true
+// y: PUBLIC,visible in A, B, D: true, true, true
+// LibEnumJava: valueOf: PUBLIC
+// LibEnumJava: values: PUBLIC
+// LibEnumJava: <init>: PRIVATE
+// LibEnum: valueOf: PUBLIC
+// LibEnum: values: PUBLIC
+// LibEnum: <init>: PRIVATE
+// Enum: <init>: PRIVATE
+// Enum: values: PUBLIC
+// Enum: valueOf: PUBLIC
+// KtEnum: <init>: PRIVATE
+// KtEnumWithVal: <init>: PRIVATE
+// END
+
+// MODULE: lib
+// FILE: JavaClass.java
+public class JavaClass {
+ int javaPackageField;
+}
+
+// FILE: LibEnumJava.java
+public enum LibEnumJava {
+ R(0),G(1),B(2);
+ private final int v;
+ LibEnumJava(int v) {
+ this.v = v;
+ }
+}
+
+// FILE: lib.kt
+open class KotlinClass {
+ open internal val x: Int = 0
+ open protected val y: Int = 0
+}
+
+enum class LibEnum(val value: Int) {
+ A(0), B(1), C(2);
+}
+
+// MODULE: main(lib)
+// FILE: a.kt
+annotation class TestA
+annotation class TestB
+annotation class TestD
+
+@TestA
+class A : C() {
+}
+
+@TestD
+class D {}
+
+class KotlinSubClass : KotlinClass() {
+ public override val y = 1
+}
+
+enum class KtEnum {
+ A,B,C
+}
+
+enum class KtEnumWithVal(val a: Int) {
+ A(0), B(1), C(2)
+}
+
+// FILE: C.java
+class C {
+ public int publicFun() {
+ return 1;
+ }
+
+ int packageFun() {
+ return 1;
+ }
+
+ private int privateFun() {
+ return 1;
+ }
+
+ protected int protectedFun() {
+ return 1;
+ }
+}
+
+// FILE: Enum.java
+public enum Enum {
+ Y,U,V;
+ private final int v;
+ Enum(int v) {
+ this.v = v;
+ }
+}
+// FILE: b.kt
+package somePackage
+
+import TestB
+
+@TestB
+class B