{"id":15110458,"url":"https://github.com/android/kotlin","last_synced_at":"2025-09-27T13:30:36.281Z","repository":{"id":65983270,"uuid":"263405600","full_name":"android/kotlin","owner":"android","description":"Kotlin Symbol Processing API","archived":true,"fork":true,"pushed_at":"2020-09-15T06:08:55.000Z","size":752037,"stargazers_count":321,"open_issues_count":0,"forks_count":40,"subscribers_count":19,"default_branch":"ksp","last_synced_at":"2024-09-26T23:44:57.538Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://goo.gle/ksp","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"JetBrains/kotlin","license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/android.png","metadata":{"files":{"readme":"ReadMe.md","changelog":"ChangeLog.md","contributing":"docs/contributing.md","funding":null,"license":null,"code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-12T17:30:27.000Z","updated_at":"2024-07-01T04:41:43.000Z","dependencies_parsed_at":"2023-02-19T19:01:37.080Z","dependency_job_id":null,"html_url":"https://github.com/android/kotlin","commit_stats":null,"previous_names":[],"tags_count":100,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/android%2Fkotlin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/android%2Fkotlin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/android%2Fkotlin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/android%2Fkotlin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/android","download_url":"https://codeload.github.com/android/kotlin/tar.gz/refs/heads/ksp","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234438004,"owners_count":18832602,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-25T23:45:14.188Z","updated_at":"2025-09-27T13:30:31.204Z","avatar_url":"https://github.com/android.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# A Branch for Kotlin Symbol Processing\n\nThis is a branch for [Kotlin Symbol Processing](libraries/tools/kotlin-symbol-processing-api), a light weight Kotlin compiler plugin API.\n\nFor general information about Kotlin project, please see [JetBrains/kotlin](https://github.com/JetBrains/kotlin).\n\nThe following contents are copied from [libraries/tools/kotlin-symbol-processing-api](libraries/tools/kotlin-symbol-processing-api).\n\n# Kotlin Symbol Processing API\n\nCompiler plugins are powerful metaprogramming tools that can greatly enhance\nhow you write code. Compiler plugins call compilers directly as libraries to\nanalyze and edit input programs. These plugins can also generate output for\nvarious uses. For example, they can generate boilerplate code, and they can\neven generate full implementations for specially-marked program elements,\nsuch as `Parcelable`. Plugins have a variety of other uses and can even be used\nto implement and fine-tune features that are not provided directly in a\nlanguage.\n\nWhile compiler plugins are powerful, this power comes at a price. To write\neven the simplest plugin, you need to have some compiler background\nknowledge, as well as a certain level of familiarity with the\nimplementation details of your specific compiler. Another practical\nissue is that plugins are often closely tied to specific compiler\nversions, meaning you might need to update your plugin each time you\nwant to support a newer version of the compiler.\n\n## KSP makes creating lightweight compiler plugins easier\n\nKotlin Symbol Processing (KSP) is an API that you can use to develop\nlightweight compiler plugins. KSP provides a simplified compiler plugin\nAPI that leverages the power of Kotlin while keeping the learning curve at\na minimum. KSP is designed to hide compiler changes, minimizing maintenance\nefforts for processors that use it. KSP is designed not to be tied to the\nJVM so that it can be adapted to other platforms more easily in the future.\nKSP is also designed to minimize build times. For some processors, such as\n[Glide](https://github.com/bumptech/glide), KSP reduces full compilation\ntimes by up to 25% when compared to KAPT.\n\nKSP is itself implemented as a compiler plugin, and the experimental KSP\nrepository is a fork of JetBrains/kotlin. There are also prebuilt packages\non Google's Maven repository that you can download and use without having\nto build the project yourself. For more information, see\n[Try it out](#try)!\n\nThe KSP API processes Kotlin programs idiomatically. KSP understands\nKotlin-specific features, such as extension functions, declaration-site\nvariance, and local functions. KSP also models types explicitly and\nprovides basic type checking, such as equivalence and assign-compatibility.\n\nThe API models Kotlin program structures at the symbol level according to\n[Kotlin grammar](https://kotlinlang.org/docs/reference/grammar.html). When\nKSP-based plugins process source programs, constructs like classes, class\nmembers, functions, and associated parameters are easily accessible for the\nprocessors, while things like if blocks and for loops are not.\n\nConceptually, KSP is similar to\n[KType](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-type/)\nin Kotlin reflection. The API allows processors to navigate from class\ndeclarations to corresponding types with specific type arguments and\nvice-versa. Substituting type arguments, specifying variances, applying\nstar projections, and marking nullabilities of types are also possible.\n\nAnother way to think of KSP is as a pre-processor framework of Kotlin\nprograms. If we refer to KSP-based plugins as _symbol processors_, or\nsimply _processors_, then the data flow in a compilation can be described\nin the following steps:\n\n1. Processors read and analyze source programs and resources.\n1. Processors generate code or other forms of output.\n1. The Kotlin compiler compiles the source programs together with the\n   generated code.\n\nUnlike a full-fledged compiler plugin, processors cannot modify the code.\nA compiler plugin that changes language semantics can sometimes be very\nconfusing. KSP avoids that by treating the source programs as read-only.\n\n## How KSP looks at source files\n\nMost processors navigate through the various program structures of the\ninput source code. Before diving into usage of the API, let's look at how\na file might look from KSP's point of view:\n\n```kotlin\nKSFile\n  packageName: KSName\n  fileName: String\n  annotations: List\u003cKSAnnotation\u003e  (File annotations)\n  declarations: List\u003cKSDeclaration\u003e\n    KSClassDeclaration // class, interface, object\n      simpleName: KSName\n      qualifiedName: KSName\n      containingFile: String\n      typeParameters: KSTypeParameter\n      parentDeclaration: KSDeclaration\n      classKind: ClassKind\n      primaryConstructor: KSFunctionDeclaration\n      superTypes: List\u003cKSTypeReference\u003e\n      // contains inner classes, member functions, properties, etc.\n      declarations: List\u003cKSDeclaration\u003e\n    KSFunctionDeclaration // top level function\n      simpleName: KSName\n      qualifiedName: KSName\n      containingFile: String\n      typeParameters: KSTypeParameter\n      parentDeclaration: KSDeclaration\n      functionKind: FunctionKind\n      extensionReceiver: KSTypeReference?\n      returnType: KSTypeReference\n      parameters: List\u003cKSVariableParameter\u003e\n      // contains local classes, local functions, local variables, etc.\n      declarations: List\u003cKSDeclaration\u003e\n    KSPropertyDeclaration // global variable\n      simpleName: KSName\n      qualifiedName: KSName\n      containingFile: String\n      typeParameters: KSTypeParameter\n      parentDeclaration: KSDeclaration\n      extensionReceiver: KSTypeReference?\n      type: KSTypeReference\n      getter: KSPropertyGetter\n        returnType: KSTypeReference\n      setter: KSPropertySetter\n        parameter: KSVariableParameter\n    KSEnumEntryDeclaration\n      // same as KSClassDeclaration\n```\n\nThis view lists common things that are declared in the file--classes,\nfunctions, properties, enums, and so on.\n\n## SymbolProcessor: The entry point\n\nEvery processor in KSP implements `SymbolProcessor`:\n\n```kotlin\ninterface SymbolProcessor {\n    fun init(options: Map\u003cString, String\u003e,\n             kotlinVersion: KotlinVersion,\n             codeGenerator: CodeGenerator,\n             logger: KSPLogger)\n    fun process(resolver: Resolver) // Let's focus on this\n    fun finish()\n}\n```\n\nA `Resolver` provides `SymbolProcessor` with access to compiler details\nsuch as symbols. A processor that finds all top-level functions and non-local functions in top-level\nclasses might look something like this:\n\n```kotlin\nclass HelloFunctionFinderProcessor : SymbolProcessor() {\n    ...\n    val functions = mutableListOf\u003cString\u003e()\n    val visitor = FindFunctionsVisitor()\n\n    override fun process(resolver: Resolver) {\n        resolver.getAllFiles().map { it.accept(visitor, Unit) }\n    }\n\n    inner class FindFunctionsVisitor : KSVisitorVoid() {\n        override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {\n            classDeclaration.getDeclaredFunctions().map { it.accept(this, Unit) }\n        }\n\n        override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {\n            functions.add(function)\n        }\n\n        override fun visitFile(file: KSFile, data: Unit) {\n            file.declarations.map { it.accept(this, Unit) }\n        }\n    }\n    ...\n}\n```\n\n## Examples\n\nGet all member functions that are declared directly within a class:\n\n```kotlin\nfun KSClassDeclaration.getDeclaredFunctions(): List\u003cKSFunctionDeclaration\u003e {\n    return this.declarations.filterIsInstance\u003cKSFunctionDeclaration\u003e()\n}\n```\n\nDetermine whether a class or function is local to another function:\n\n```kotlin\nfun KSDeclaration.isLocal(): Boolean {\n    return this.parentDeclaration != null \u0026\u0026 this.parentDeclaration !is KSClassDeclaration\n}\n```\n\nDetermine whether a class member is visible to another:\n\n```kotlin\nfun KSDeclaration.isVisibleFrom(other: KSDeclaration): Boolean {\n    return when {\n        // locals are limited to lexical scope\n        this.isLocal() -\u003e this.parentDeclaration == other\n        // file visibility or member\n        this.isPrivate() -\u003e {\n            this.parentDeclaration == other.parentDeclaration\n                    || this.parentDeclaration == other\n                    || (\n                        this.parentDeclaration == null\n                            \u0026\u0026 other.parentDeclaration == null\n                            \u0026\u0026 this.containingFile == other.containingFile\n                    )\n        }\n        this.isPublic() -\u003e true\n        this.isInternal() \u0026\u0026 other.containingFile != null \u0026\u0026 this.containingFile != null -\u003e true\n        else -\u003e false\n    }\n}\n```\n\n### Example annotations\n\n```kotlin\n// Find out suppressed names in a file annotation:\n// @file:kotlin.Suppress(\"Example1\", \"Example2\")\nfun KSFile.suppressedNames(): List\u003cString\u003e {\n    val ignoredNames = mutableListOf\u003cString\u003e()\n    annotations.forEach {\n        if (it.shortName.asString() == \"Suppress\" \u0026\u0026 it.annotationType.resolve()?.declaration?.qualifiedName?.asString() == \"kotlin.Suppress\") {\n            it.arguments.forEach {\n                (it.value as List\u003cString\u003e).forEach { ignoredNames.add(it) }\n            }\n        }\n    }\n    return ignoredNames\n}\n```\n\n## Additional details\n\nThe API definition can be found [here](libraries/tools/kotlin-symbol-processing-api/src/org/jetbrains/kotlin/ksp/).\nThe diagram below is an overview of how Kotlin is [modeled](libraries/tools/kotlin-symbol-processing-api/src/org/jetbrains/kotlin/ksp/symbol/) in KSP:\n![class diagram](libraries/tools/kotlin-symbol-processing-api/ClassDiagram.png)\n\n### Type and resolution\n\nIn KSP, references to types are designed to be resolved by processors\nexplicitly (with a few exceptions) because most of the cost of the\nunderlying API implementation is in resolution. When a _type_ is referenced,\nsuch as `KSFunctionDeclaration.returnType` or `KSAnnotation.annotationType`,\nit is always a `KSTypeReference`, which is a `KSReferenceElement` with\nannotations and modifiers.\n\n```kotlin\ninterface KSFunctionDeclaration : ... {\n  val returnType: KSTypeReference?\n  ...\n}\n\ninterface KSTypeReference : KSAnnotated, KSModifierListOwner {\n  val type: KSReferenceElement\n}\n```\n\nA `KSTypeReference` can be resolved to a `KSType`, which refers to a type in\nKotlin's type system.\n\nA `KSTypeReference` has a `KSReferenceElement`, which models Kotlin‘s program\nstructure: namely, how the reference is written. It corresponds to the\n[`type`](https://kotlinlang.org/docs/reference/grammar.html#type) element in\nKotlin's grammar.\n\nA `KSReferenceElement` can be a `KSClassifierReference` or\n`KSCallableReference`, which contains a lot of useful information without\nthe need for resolution. For example, `KSClassifierReference` has\n`referencedName`, while `KSCallableReference` has `receiverType`,\n`functionArguments`, and `returnType`.\n\nIf the original declaration referenced by a `KSTypeReference` is needed,\nit can usually be found by resolving to `KSType` and accessing through\n`KSType.declaration`. Moving from where a type is mentioned to where its\nclass is defined looks like this:\n\n```kotlin\nKSTypeReference -\u003e .resolve() -\u003e KSType -\u003e .declaration -\u003e KSDeclaration\n```\n\nType resolution is costly and is therefore made explicit. Some of the\ninformation obtained from resolution is already available in\n`KSReferenceElement`. For example, `KSClassifierReference.referencedName`\ncan filter out a lot of elements that are not interesting. You should\nresolve type only if you need specific information from `KSDeclaration`\nor `KSType`.\n\nNote that a `KSTypeReference` pointing to a function type has most of its\ninformation in its element. Although it can be resolved to the family of\n`Function0`, `Function1`, and so on, these resolutions don‘t bring any\nmore information than `KSCallableReference`. One use case for resolving\nfunction type references is dealing with the identity of the function's\nprototype.\n\n## Comparison to `kotlinc` compiler plugins\n\n`kotlinc` compiler plugins have access to almost everything from the compiler\nand therefore have maximum power and flexibility. On the other hand, because\nthese plugins can potentially depend on anything in the compiler, they are\nsensitive to compiler changes and need to be maintained frequently. These plugins\nalso require a deep understanding of `kotlinc`’s implementation, so the learning\ncurve can be steep.\n\nKSP aims to hide most compiler changes through a well-defined API, though major\nchanges in compiler or even the Kotlin language might still require to be\nexposed to API users.\n\nKSP tries to fulfill common use cases by providing an API that trades power for\nsimplicity. Its capability is a strict subset of a general `kotlinc` plugin.\nFor example, while `kotlinc` can examine expressions and statements and can even\nmodify code, KSP cannot.\n\nWhile writing a `kotlinc` plugin can be a lot of fun, it can also take a lot of\ntime. If you aren't in a position to learn `kotlinc`’s implementation and do\nnot need to modify source code or read expressions, KSP might be a good fit.\n\n## Comparison to reflection\n\nKSP's API looks similar to `kotlin.reflect`. The major difference between\nthem is that type references in KSP need to be resolved explicitly. This is\none of the reasons why the interfaces are not shared.\n\n## Comparison to KAPT\n\n[KAPT](https://kotlinlang.org/docs/reference/kapt.html) is a remarkable\nsolution which makes a large amount of Java annotation processors work\nfor Kotlin programs out-of-box. The major advantages of KSP over KAPT are\nimproved build performance, not tied to JVM, a more idiomatic Kotlin\nAPI, and the ability to understand Kotlin-only symbols.\n\nTo run Java annotation processors unmodified, KAPT compiles Kotlin code\ninto Java stubs that retain information that Java annotation processors\ncare about. To create these stubs, KAPT needs to resolve all symbols in\nthe Kotlin program. The stub generation costs roughly 1/3 of a full\n`kotlinc` analysis and the same order of `kotlinc` code-generation. For\nmany annotation processors, this is much longer than the time spent in\nthe processors themselves. For example, Glide looks at a very limited\nnumber of classes with a predefined annotation, and its code generation\nis fairly quick. Almost all of the build overhead resides in the stub\ngeneration phase. Switching to KSP would immediately reduce the time\nspent in the compiler by 25%.\n\nFor performance evaluation, we implemented a\n[simplified version](https://github.com/android/kotlin/releases/download/sample/miniGlide.zip)\nof [Glide](https://github.com/bumptech/glide) in KSP to make it generate code\nfor the [Tachiyomi](https://github.com/inorichi/tachiyomi) project. While\nthe total Kotlin compilation time of the project is 21.55 seconds on our\ntest device, it took 8.67 seconds for KAPT to generate the code, and it\ntook 1.15 seconds for our KSP implementation to generate the code.\n\nUnlike KAPT, processors in KSP do not see input programs from Java's point\nof view. The API is more natural to Kotlin, especially for Kotlin-specific\nfeatures such as top-level functions. Because KSP doesn't delegate to\n`javac` like KAPT, it doesn't assume JVM-specific behaviors and can be\nused with other platforms potentially.\n\n## Limitations\n\nWhile KSP tries to be a simple solution for most common use cases, it has made\nseveral trade-offs compared to other plugin solutions. The following are not\ngoals of KSP:\n\n* Examining expression-level information of source code.\n* Modifying source code.\n* 100% compatibility with the Java Annotation Processing API.\n\nWe are also exploring several additional features. Note that these features are\ncurrently unavailable:\n\n* IDE integration: Currently IDEs know nothing about the generated code.\n* We are still investigating how to provide interoperability between processors.\n\n## For Java Annotation Processor Authors\n\nIf you are familiar with the Java Annotation Processing API, see the\n[Java annotation processing to KSP reference](libraries/tools/kotlin-symbol-processing-api/reference.md) for how to\nimplement most functions and data structures that are provided by Java's\nAPI.\n\n## Development status\n\nThe API is still under development and is likely to change in the future.\nPlease do not use it in production yet. The purpose of this preview is\nto get your feedback.\n[Please let us know what you think about KSP by filing a Github issue](https://github.com/android/kotlin/issues)\nor connecting with our team in the `#ksp` channel in the\n[Kotlin Slack workspace](https://surveys.jetbrains.com/s3/kotlin-slack-sign-up?_ga=2.185732459.358956950.1590619123-888878822.1567025441)!\n\nHere are some planned features that have not yet been implemented:\n\n* Passing options to processors in Gradle.\n* Incremental processing.\n* Improved support for reading Java source code.\n* Make the IDE aware of the generated code.\n\n\u003ca name=\"try\"\u003e\u003c/a\u003e\n## Try it out!\n\nHere's a sample processor that you can check out: https://github.com/android/kotlin/releases/download/1.4.0-dev-experimental-20200914/playground-ksp-1.4.0-dev-experimental-20200914.zip\n\n### Create a processor of your own\n\n* Create an empty gradle project.\n* Specify version `1.4.0` of the Kotlin plugin in the root project for use in other project modules.\n\n  ```\n  plugins {\n      kotlin(\"jvm\") version \"1.4.0\" apply false\n  }\n\n  buildscript {\n      dependencies {\n          classpath(kotlin(\"gradle-plugin\", version = \"1.4.0\"))\n      }\n\n      repositories {\n          maven(\"https://dl.bintray.com/kotlin/kotlin-eap\")\n      }\n  }\n  ```\n\n* Add a module for hosting the processor.\n* In the module's `build.gradle.kts` file, do the following:\n    * Add `google()` to repositories so that Gradle can find our plugins.\n    * Apply Kotlin plugin\n    * Add the KSP API to the `dependencies` block.\n\n  ```\n  repositories {\n      google()\n      maven(\"https://dl.bintray.com/kotlin/kotlin-eap\")\n      mavenCentral()\n  }\n\n  plugins {\n      kotlin(\"jvm\")\n  }\n\n  dependencies {\n      implementation(\"org.jetbrains.kotlin:kotlin-symbol-processing-api:1.4.0-dev-experimental-20200914\")\n  }\n  ```\n\n* The processor you're writing needs to implement `org.jetbrains.kotlin.ksp.processing.SymbolProcessor`.\n  Note the following:\n  * Your main logic should be in the `process()` method.\n  * Use `CodeGenerator` in the `init()` method for code generation. You can also save\n    the `CodeGenerator` instance for later use in either `process()` or `finish()`.\n  * Use `resolver.getSymbolsWithAnnotation()` to get the symbols you want to process, given\n    the fully-qualified name of an annotation.\n  * A common use case for KSP is to implement a customized visitor (interface\n    `org.jetbrains.kotlin.ksp.symbol.KSVisitor`) for operating on symbols. A simple template\n    visitor is `org.jetbrains.kotlin.ksp.symbol.KSDefaultVisitor`.\n  * For sample implementations of the `SymbolProcessor` interface, see the following files\n    in the sample project.\n    * `src/main/kotlin/BuilderProcessor.kt`\n    * `src/main/kotlin/TestProcessor.kt`\n  * After writing your own processor, register your processor to the package by including\n    the fully-qualified name of that processor in\n    `resources/META-INF/services/org.jetbrains.kotlin.ksp.processing.SymbolProcessor`.\n  * Here's a sample `build.gradle.kts` file for writing a processor.\n\n    ```\n    plugins {\n        kotlin(\"jvm\") \n    }\n\n    repositories {\n        mavenCentral()\n        google()\n    }\n\n    dependencies {\n        implementation(\"org.jetbrains.kotlin:kotlin-symbol-processing-api:1.4.0-dev-experimental-20200914\")\n    }\n    ```\n\n### Use your own processor in a project\n\n* Create another module that contains a workload where you want to try out your processor.\n* In the project's `setting.gradle.kts`, override `resolutionStrategy` for the KSP plugin.\n  This is necessary because KSP is still in preview and there is no plugin marker published yet.\n  \n  ```\n  pluginManagement {\n      resolutionStrategy {\n          eachPlugin {\n              when (requested.id.id) {\n                  \"kotlin-ksp\",\n                  \"org.jetbrains.kotlin.kotlin-ksp\",\n                  \"org.jetbrains.kotlin.ksp\" -\u003e\n                      useModule(\"org.jetbrains.kotlin:kotlin-ksp:${requested.version}\")\n              }\n          }\n      }\n\n      repositories {\n              gradlePluginPortal()\n              maven(\"https://dl.bintray.com/kotlin/kotlin-eap\")\n              google()\n      }\n  }\n  ```\n\n* In the new module's `build.gradle.kts`, do the following:\n  * Apply the `kotlin-ksp` plugin with the specified version.\n  * Add `ksp(\u003cyour processor\u003e)` to the list of dependencies.\n* Run `./gradlew build`. You can find the generated code under\n  `build/generated/source/ksp`.\n* Here's a `sample build.gradle.kts` to apply the KSP plugin to a workload. \n\n  ```\n  plugins {\n      id(\"kotlin-ksp\") version \"1.4.0-dev-experimental-20200914\"\n      kotlin(\"jvm\") \n  }\n\n  version = \"1.0-SNAPSHOT\"\n\n  repositories {\n      mavenCentral()\n      maven(\"https://dl.bintray.com/kotlin/kotlin-eap\")\n      google()\n  }\n\n  dependencies {\n      implementation(kotlin(\"stdlib-jdk8\"))\n      implementation(project(\":test-processor\"))\n      ksp(project(\":test-processor\"))\n  }\n  ```\n\n### Pass Options to Processors\nProcessor options in `SymbolProcessor.init(options: Map\u003cString, String\u003e, ...)` are specified in gradle build scripts:\n```\n  ksp {\n    arg(\"option1\", \"value1\")\n    arg(\"option2\", \"value2\")\n    ...\n  }\n```\n\n### Make IDE Aware Of Generated Code\nBy default, IntelliJ or other IDEs don't know about the generated code and therefore\nreferences to those generated symbols will be marked unresolvable.\nTo make, for example, IntelliJ be able to reason about the generated symbols,\nthe following paths need to be marked as generated source root:\n\n```\nbuild/generated/ksp/src/main/kotlin/\nbuild/generated/ksp/src/main/java/\n```\n\nand perhaps also resource directory if your IDE supports them:\n```\nbuild/generated/ksp/src/main/resources\n```\n\n## How to contribute\nPull requests are welcome!\n\nFor incoming PRs, we would like to request changes covered by tests for good practice.\n\nWe do end to end test for KSP, which means you need to write a lightweight processor to be loaded with KSP for testing.\n\nThe form of the test itself is flexible as long as the logic is being covered. \n\nHere are some [sample test processors](plugins/ksp/src/org/jetbrains/kotlin/ksp/processor) for your reference.\n\n#### Steps for writing a test\n* Create a test processor under the sample processor folder.\nit should be extending [AbstractTestProcessor](plugins/ksp/src/org/jetbrains/kotlin/ksp/processor/AbstractTestProcessor.kt)\n* Write your logic by overriding corresponding functions. \n    * Test is performed by running test processor and get a collection of test results in the form of List\u003cString\u003e.\n    * Make sure you override toResult() function to collect test result. \n    * Leverage visitors for easy traverse of the test case.\n    * To help with easy testing, you can create an annotation for test, and annotate the specific part of the code to avoid doing \n    excess filtering when traveling along the program.\n* Write your test case to work with test processor.\n    * Create a test kt file under [testData](plugins/ksp/testData/api) folder. \n    Every kt file under this folder corrsponds to a test case.\n    * Inside the test file:\n        * [optional] Add ```// WITH_RUNTIME``` to the top if you need access to standard library.\n        * Add ```// TEST PROCESSOR:\u003cYour test processor name\u003e``` to provide the test processor for this test case. Processors can \n        be reused if necessary.\n        * Immediately after test processor line, start your expected result lines. Every line should start with\n         ```// ```(with a space after //)\n        * Add ```// END``` to indicate end of expected test result.\n        * Then follows virtual files section till the end of test file.\n        * You can use ```// FILE: \u003cfile name\u003e``` to create files that will be available at run time of the test.\n            * E.g. ```// FILE: a.kt``` will result in a file named ```a.kt``` at run time.\n* Generate test using gradle.\n    * After you have finished writing your test file, you can generate the test case in TestSuite by running \n    ```generateTests```gradle task. It can take a while. \n    * After generating, make sure there is no other tests generated by checking git status, you should include only tests in \n    [KotlinKSPTestGenerated](plugins/ksp/test/org/jetbrains/kotlin/ksp/test/KotlinKSPTestGenerated.java) in your PR.\n* Run generated tests with ```:kotlin-symbol-processing:test``` gradle task.\n    * This will execute all tests in KSP test suite. To run your test only, specify the test name with \n    ```--tests \"org.jetbrains.kotlin.ksp.test.KotlinKSPTestGenerated.\u003cname of your generated test\u003e\"```\n    * Make sure your change is not breaking any existing test as well :).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandroid%2Fkotlin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandroid%2Fkotlin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandroid%2Fkotlin/lists"}