-
Notifications
You must be signed in to change notification settings - Fork 761
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Upstream KSP implementation #1393
Conversation
Some of these KSP - KotlinPoet bits definitely have a future in KotlinPoet itself, but that's for another day |
.../codegen/src/test/java/com/squareup/moshi/kotlin/codegen/ksp/JsonClassSymbolProcessorTest.kt
Outdated
Show resolved
Hide resolved
.../codegen/src/test/java/com/squareup/moshi/kotlin/codegen/ksp/JsonClassSymbolProcessorTest.kt
Outdated
Show resolved
Hide resolved
.../codegen/src/test/java/com/squareup/moshi/kotlin/codegen/ksp/JsonClassSymbolProcessorTest.kt
Outdated
Show resolved
Hide resolved
So tired of kapt oh my god
9616b4a
to
0bc41b2
Compare
kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/typeAliasUnwrapping.kt
Outdated
Show resolved
Hide resolved
kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/ksp/TargetTypes.kt
Outdated
Show resolved
Hide resolved
addAnnotation(Transient::class) | ||
} | ||
addAnnotations( | ||
this@toPropertySpec.annotations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't know if there's an intention to support this, but I noticed a difference from kapt if you qualify the annotation with get
/set
, ex:
class ClassWithQualiifer(@get:MyQualifier val a: Int)
will see the qualifier in kapt, but ignore it in ksp.
If you do want to look at these, you need to check getter.annotations
and/or setter.annotations
as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup we don't really have a clear story there as far as what we check, but officially our stance in other issues has been that only properties are supported and anything else is undefined
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to straighten it out more but will save that for a later PR
kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/ksp/KspUtil.kt
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New annotation methods look much cleaner!
Thanks for the review! |
* * `"javax.annotation.processing.Generated"` (JRE 9+) | ||
* * `"javax.annotation.Generated"` (JRE <9) | ||
*/ | ||
const val OPTION_GENERATED: String = "moshi.generated" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🏻
kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/typeAliasUnwrapping.kt
Show resolved
Hide resolved
kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/typeAliasUnwrapping.kt
Show resolved
Hide resolved
kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/typeAliasUnwrapping.kt
Show resolved
Hide resolved
deepCopy(TypeName::unwrapTypeAlias) | ||
} | ||
} | ||
else -> throw UnsupportedOperationException("Type '${javaClass.simpleName}' is illegal. Only classes, parameterized types, wildcard types, or type variables are allowed.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t understand who this message is for.
If you’re blaming the caller it should be an IllegalStateException saying that this function doesn’t support its input.
If you’re blaming this function itself for being incomplete then it should be an AssertionError saying that the case is unexpected.
As is if I get this crash I don’t know where blame lies. As a reviewer I don’t even know!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(this feedback is on code that predates this PR)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is only possible for Dynamic
types, which we don't support here. I suppose we could support it in the future, but for now while we're JVM-only it's not even possible to reach this case. I can rename else
to Dynamic
to make it more explicit, but I don't know necessarily what the right way to rule that out is in future versions. wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made dynamic explicit here b62ec84
val adapterGenerator = adapterGenerator(logger, resolver, type) ?: return emptyList() | ||
try { | ||
val preparedAdapter = adapterGenerator | ||
.prepare(generateProguardRules) { spec -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this be simpler as two functions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the whole process()
function or splitting prepare and writing?
} | ||
} | ||
|
||
internal fun KSAnnotation.toAnnotationSpec(resolver: Resolver): AnnotationSpec { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah KotlinPoet wants to eat this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR for a later day!
else -> CodeBlock.of("%L", value) | ||
} | ||
|
||
internal inline fun KSPLogger.check(condition: Boolean, message: () -> String) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cute
kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/ksp/TargetTypes.kt
Show resolved
Hide resolved
kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/ksp/TargetTypes.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Lots of feedback; I might send PRs to address some. (Also please feel free to send your own follow ups!)
parameter = parameter, | ||
visibility = property.getVisibility().toKModifier() ?: KModifier.PUBLIC, | ||
jsonName = parameter?.jsonName ?: property.jsonName() | ||
?: name.escapeDollarSigns() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This escapeDollarSigns
call reads very suspicious to me . .. why doesn’t it escape when it comes from a parameter or property JSON name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is leftover from kapt (which didn't escape them) and I believe is still necessary here too. I can test, basically it shows fine in the annotation string but doesn't play nice in generated code because of Kotlin templating
kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/ksp/shadedUtil.kt
Show resolved
Hide resolved
|
||
internal fun <T : Annotation> KSAnnotated.getAnnotationsByType(annotationKClass: KClass<T>): Sequence<T> { | ||
return this.annotations.filter { | ||
it.shortName.getShortName() == annotationKClass.simpleName && it.annotationType.resolve().declaration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any idea what the utility of the short name check is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simple early check before doing a more expensive resolve() call in the second check
getAnnotationsByType(annotationKClass).firstOrNull() != null | ||
|
||
@Suppress("UNCHECKED_CAST") | ||
private fun <T : Annotation> KSAnnotation.toAnnotation(annotationClass: Class<T>): T { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoa, I dislike this. What the heck are we doing instantiating an annotation instance from the processed code inside the processor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let’s clean this up to definitely not use a dynamic proxy to create an annotation instance; this is a ton of mechanism to just read the properties of @Json
and @JsonClass
and @Retention
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it in our code and not KSP?
import kotlin.reflect.full.createType | ||
|
||
/** Execute kotlinc to confirm that either files are generated or errors are printed. */ | ||
class JsonClassSymbolProcessorTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great test
.../codegen/src/test/java/com/squareup/moshi/kotlin/codegen/ksp/JsonClassSymbolProcessorTest.kt
Show resolved
Hide resolved
|
||
// We're checking here that we only generate one `stringAdapter` that's used for both the | ||
// regular string properties as well as the the aliased ones. | ||
// TODO loading compiled classes from results not supported in KSP yet |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace this assertion with confirming how many files were generated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
number of files wouldn't verify anything. This is about the number of adapter properties in a file
} | ||
|
||
@Test | ||
fun `Processor should generate comprehensive proguard rules`() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not a good test, but it serves as nice raw material from which good tests could be created. Rather than covering an assortment of features in one scattershot test, we aught to test each of the interesting features each in their own tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do a dedicated PR for that, the existing apt tests are the same and it'd be pretty involved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That'd be great! I'm more ranting than anything.
alias(libs.plugins.ksp) apply false | ||
} | ||
|
||
val useKsp = hasProperty("useKsp") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
COOL
kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/DualKotlinTest.kt
Show resolved
Hide resolved
I thiiiiiink I've covered most of them in #1448, and responded to a few others |
* Rename to unwrapTypeAliasInternal + simplify * Move down isAnyNullable * Make dynamic explicit * Clean up supertypes doc and filtering * Switch to invoke extensions * Just best guess the annotation * Clean up redundant sequence and use a regular loop * element -> type * supertypes -> superclasses * Spotless * Fix copyright * Add multiple messages check * Link issue Co-authored-by: Jesse Wilson <jesse@swank.ca>
This upstreams the
moshi-ksp
implementation from https://github.com/zacsweers/moshix.Highlights
codegen.ksp
subpackage alongside the existing apt version:moshi:kotlin:tests
. The KSP implementation is functionally compatible!One is presented but commented out until next KotlinPoet release as we ported the same fix there - Fix self-referencing type variables in metadata parsing kotlinpoet#1137Some other things to do:
Consolidate processor tests with a parameterized form?Will save this for a later PR afterDescriptor wasn't found for declaration CLASS
when processing generated code in a later round google/ksp#621 is resolved