Kotlin 符号处理 API

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 two times faster.

  • To learn more about how KSP compares to kapt, check out why KSP.
  • To get started writing a KSP processor, take a look at the KSP quickstart.

Overview

The KSP API processes Kotlin programs idiomatically. KSP understands Kotlin-specific features, such as extension functions, declaration-site variance, and local functions. It also models types explicitly and provides basic type checking, such as equivalence and assign-compatibility.

The API models Kotlin program structures at the symbol level according to Kotlin grammar. When KSP-based plugins process source programs, constructs like classes, class members, functions, and associated parameters are accessible for the processors, while things like if blocks and for loops are not.

Conceptually, KSP is similar to KType in Kotlin reflection. The API allows processors to navigate from class declarations to corresponding types with specific type arguments and vice-versa. You can also substitute type arguments, specify variances, apply star projections, and mark nullabilities of types.

Another way to think of KSP is as a preprocessor framework of Kotlin programs. By considering KSP-based plugins as symbol processors, or simply processors, the data flow in a compilation can be described in the following steps:

  1. Processors read and analyze source programs and resources.
  2. Processors generate code or other forms of output.
  3. The Kotlin compiler compiles the source programs together with the generated code.

Unlike a full-fledged compiler plugin, processors cannot modify the code. A compiler plugin that changes language semantics can sometimes be very confusing. KSP avoids that by treating the source programs as read-only.

You can also get an overview of KSP in this video:

YouTube 视频:Kotlin Symbol Processing (KSP)

How KSP looks at source files

Most processors navigate through the various program structures of the input source code. Before diving into usage of the API, let’s see at how a file might look from KSP’s point of view:

  1. KSFile
  2. packageName: KSName
  3. fileName: String
  4. annotations: List<KSAnnotation> (File annotations)
  5. declarations: List<KSDeclaration>
  6. KSClassDeclaration // class, interface, object
  7. simpleName: KSName
  8. qualifiedName: KSName
  9. containingFile: String
  10. typeParameters: KSTypeParameter
  11. parentDeclaration: KSDeclaration
  12. classKind: ClassKind
  13. primaryConstructor: KSFunctionDeclaration
  14. superTypes: List<KSTypeReference>
  15. // contains inner classes, member functions, properties, etc.
  16. declarations: List<KSDeclaration>
  17. KSFunctionDeclaration // top level function
  18. simpleName: KSName
  19. qualifiedName: KSName
  20. containingFile: String
  21. typeParameters: KSTypeParameter
  22. parentDeclaration: KSDeclaration
  23. functionKind: FunctionKind
  24. extensionReceiver: KSTypeReference?
  25. returnType: KSTypeReference
  26. parameters: List<KSValueParameter>
  27. // contains local classes, local functions, local variables, etc.
  28. declarations: List<KSDeclaration>
  29. KSPropertyDeclaration // global variable
  30. simpleName: KSName
  31. qualifiedName: KSName
  32. containingFile: String
  33. typeParameters: KSTypeParameter
  34. parentDeclaration: KSDeclaration
  35. extensionReceiver: KSTypeReference?
  36. type: KSTypeReference
  37. getter: KSPropertyGetter
  38. returnType: KSTypeReference
  39. setter: KSPropertySetter
  40. parameter: KSValueParameter

This view lists common things that are declared in the file: classes, functions, properties, and so on.

SymbolProcessorProvider: the entry point

KSP expects an implementation of the SymbolProcessorProvider interface to instantiate SymbolProcessor:

  1. interface SymbolProcessorProvider {
  2. fun create(environment: SymbolProcessorEnvironment): SymbolProcessor
  3. }

While SymbolProcessor is defined as:

  1. interface SymbolProcessor {
  2. fun process(resolver: Resolver): List<KSAnnotated> // Let's focus on this
  3. fun finish() {}
  4. fun onError() {}
  5. }

A Resolver provides SymbolProcessor with access to compiler details such as symbols. A processor that finds all top-level functions and non-local functions in top-level classes might look something like the following:

  1. class HelloFunctionFinderProcessor : SymbolProcessor() {
  2. // ...
  3. val functions = mutableListOf<KSClassDeclaration>()
  4. val visitor = FindFunctionsVisitor()
  5. override fun process(resolver: Resolver) {
  6. resolver.getAllFiles().forEach { it.accept(visitor, Unit) }
  7. }
  8. inner class FindFunctionsVisitor : KSVisitorVoid() {
  9. override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
  10. classDeclaration.getDeclaredFunctions().forEach { it.accept(this, Unit) }
  11. }
  12. override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
  13. functions.add(function)
  14. }
  15. override fun visitFile(file: KSFile, data: Unit) {
  16. file.declarations.forEach { it.accept(this, Unit) }
  17. }
  18. }
  19. // ...
  20. class Provider : SymbolProcessorProvider {
  21. override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = TODO()
  22. }
  23. }

Resources

Supported libraries

The table includes a list of popular libraries on Android and their various stages of support for KSP:

LibraryStatus
RoomOfficially supported
MoshiOfficially supported
RxHttpOfficially supported
KotshiOfficially supported
LyricistOfficially supported
Lich SavedStateOfficially supported
gRPC DekoratorOfficially supported
EasyAdapterOfficially supported
Koin AnnotationsOfficially supported
GlideOfficially supported
MicronautOfficially supported
EpoxyOfficially supported
ParisOfficially supported
Auto DaggerOfficially supported
SealedXOfficially supported
DeeplinkDispatchSupported via airbnb/DeepLinkDispatch#323
DaggerAlpha
HiltIn progress
Auto FactoryNot yet supported