Skip to content

Commit

Permalink
Consolidate and simplify kotlinx-metadata interop (#1151)
Browse files Browse the repository at this point in the history
* Remove immutable nodes

* Inline ReflectiveClassInspector and move off of immutable nodes API

* Inline ElementsClassInspector and move off of immutable nodes API

* Nix old comment

Can't be a value class anyway since it's nullable

* Use stable comparators for Km types as keys

Km types don't usually implement equals/hashcode

* Update specs tests

* Unify impls to single interop:kotlinx-metadata

* Consolidate in specs tests

* Consolidate kmTypes and standardize plurals naming

* Clean up internal tools now that we can use `internal`

* Rename Flags to lowercase plural flags

* More package cleanups

* Add missing copyright headers

* Update docs

* Doc fixes

* Point to package

* Make guava and autocommon implementation deps
  • Loading branch information
ZacSweers authored Sep 20, 2021
1 parent 6d2f2e4 commit ce6c873
Show file tree
Hide file tree
Showing 42 changed files with 771 additions and 1,609 deletions.
48 changes: 0 additions & 48 deletions docs/interop-kotlinx-metadata-specs.md

This file was deleted.

63 changes: 46 additions & 17 deletions docs/interop-kotlinx-metadata.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
KotlinPoet-metadata
===================

`interop:kotlinx-metadata:core` is an API for working with Kotlin `@Metadata` annotations. Its API
sits atop [kotlinx-metadata](https://github.com/JetBrains/kotlin/tree/master/libraries/kotlinx-metadata/jvm),
offering immutable versions of its types + JVM metadata information. This can be used to read
`interop:kotlinx-metadata` is an API for working with Kotlin `@Metadata` annotations. Its API
sits atop [kotlinx-metadata](https://github.com/JetBrains/kotlin/tree/master/libraries/kotlinx-metadata/jvm),
offering extensions for its types + JVM metadata information. This can be used to read
Kotlin language semantics off of `Class` or `TypeElement` `@Metadata` annotations.

### Example

```kotlin
data class Taco(val seasoning: String, val soft: Boolean) {
fun prepare() {

}
}

val kmClass = Taco::class.toImmutableKmClass()
val kmClass = Taco::class.toKmClass()

// Now you can access misc information about Taco from a Kotlin lens
println(kmClass.name)
Expand All @@ -25,7 +25,7 @@ kmClass.functions.forEach { println(it.name) }

### Flags

There are a number of boolean flags available to types as well under `Flags.kt`. These read the
There are a number of boolean flags available to types as well under `Flags.kt`. These read the
underlying kotlinx-metadata `Flags` property.

Using the Taco example above, we can glean certain information:
Expand All @@ -35,21 +35,50 @@ println("Is class? ${kmClass.isClass}")
println("Is data class? ${kmClass.isData}")
```

### Interop with kotlinx-metadata
### Interop with KotlinPoet

`interop:kotlinx-metadata` offers an API for converting core kotlinx-metadata `Km` types to
KotlinPoet source representations of their APIs. This includes full type resolution, signatures,
enclosed elements, and general stub source representations of the underlying API.

To convert a kotlinx-metadata type to its analogous immutable type, simply call `toImmutable()`
### Example

```kotlin
val immutableKmClass: ImmutableKmClass = kmClass.toImmutable()
```
data class Taco(val seasoning: String, val soft: Boolean) {
fun prepare() {
}
}

To convert an immutable type back to its analogous kotlinx-metadata type, call `toMutable()`.
val typeSpec = Taco::class.toTypeSpec()

```kotlin
val mutableKmClass: KmClass = kmClass.toMutable()
// Or FileSpec
val fileSpec = Taco::class.toFileSpec()
```

### Interop with KotlinPoet

There is a separate `interop:kotlinx-metadata:specs` artifact that offers interop APIs to create
`TypeSpec`/`FileSpec` representations of classes using this artifact for intermediary parsing.
### Source representation

The generated representations are a _best effort_ representation of the underlying source code.
This means that synthetic elements will be excluded from generation. Kotlin-specific language
features like lambdas or delegation will be coerced to their idiomatic source form.

To aid with this, `toTypeSpec()` and `toFileSpec()` accept optional `ClassInspector` instances
to assist in parsing/understanding the underlying JVM code. This is important for things like
annotations, companion objects, certain JVM modifiers, overrides, and more. While it is optional,
represented sources can be incomplete without this information available. Reflective and javax
`Elements` implementations are available under the
`com.squareup.kotlinpoet.metadata.classinspectors` package.

Generated sources are solely _stub_ implementations, meaning implementation details of elements
like functions, property getters, and delegated properties are simply stubbed with `TODO()`
placeholders.

### Known limitations

- Only `KotlinClassMetadata.Class` and `KotlinClassMetadata.FileFacade` are supported for now. No support for `SyntheticClass`, `MultiFileClassFacade`, or `MultiFileClassPart`
- `@JvmOverloads` annotations are only supported with `ElementsClassInspector` and not reflection.
- Non-const literal values are only supported with `ElementsClassInspector` and not reflection.
- ClassInspector data sourced from `synthetic` constructs are only supported with
`ReflectiveClassInspector` and not elements. This is because the javax Elements API does not model
synthetic constructs. This can yield some missing information, like static companion object properties
or `property:` site target annotations.
- Annotations annotated with `AnnotationRetention.SOURCE` are not parsable in reflection nor javax elements.
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,24 @@

tasks.jar {
manifest {
attributes("Automatic-Module-Name" to "com.squareup.kotlinpoet.metadata.specs")
attributes("Automatic-Module-Name" to "com.squareup.kotlinpoet.metadata")
}
}

tasks.compileTestKotlin {
kotlinOptions {
freeCompilerArgs = listOf("-Xjvm-default=all")
}
}

dependencies {
implementation(libs.autoCommon)
implementation(libs.guava)
api(libs.kotlin.metadata)
api(project(":kotlinpoet"))
api(project(":interop:kotlinx-metadata:core"))

testImplementation(libs.kotlin.junit)
testImplementation(libs.truth)
testImplementation(libs.compileTesting)
testImplementation(libs.kotlinCompileTesting)
}

This file was deleted.

This file was deleted.

Loading

0 comments on commit ce6c873

Please sign in to comment.