Skip to content
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

Add support for context-receivers #1233

Merged
merged 22 commits into from Apr 18, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ebd4464
Add API for context receivers
DRSchlaubi Apr 12, 2022
f0d23a2
Use existing opt-in annotation and make context-receivers not nullable
DRSchlaubi Apr 12, 2022
fe97e3f
Remove collection overloads
DRSchlaubi Apr 12, 2022
37aef5e
Revert unwanted code style changes
DRSchlaubi Apr 12, 2022
a505feb
Add wrongly remove @JvmOverloads annotation
DRSchlaubi Apr 12, 2022
f5f0784
Add code generator and tests
DRSchlaubi Apr 12, 2022
6350d54
Apply requested changes
DRSchlaubi Apr 12, 2022
1e0f847
Update kotlinpoet/src/main/java/com/squareup/kotlinpoet/FunSpec.kt
DRSchlaubi Apr 12, 2022
7f61d7a
Apply requested changes
DRSchlaubi Apr 13, 2022
95eba91
Merge branch 'feature/context-receivers' of github.com:DRSchlaubi/kot…
DRSchlaubi Apr 13, 2022
4d5792e
Update test for suggestion
DRSchlaubi Apr 13, 2022
f2ace6f
Apply suggestions from code review
DRSchlaubi Apr 15, 2022
e6316a0
Apply requested changes
DRSchlaubi Apr 15, 2022
1b1a5d9
Rename contextReceiver to contextReceivers
DRSchlaubi Apr 15, 2022
ec31e4e
Fix compiler error
DRSchlaubi Apr 16, 2022
53d0af2
Update kotlinpoet/src/main/java/com/squareup/kotlinpoet/FunSpec.kt
DRSchlaubi Apr 18, 2022
57f9941
Fix compiler errors in tests
DRSchlaubi Apr 18, 2022
cabea6b
Run spotless
DRSchlaubi Apr 18, 2022
ad2ec58
Update kotlinpoet/src/main/java/com/squareup/kotlinpoet/LambdaTypeNam…
DRSchlaubi Apr 18, 2022
92d9956
Apply requested changes
DRSchlaubi Apr 18, 2022
ef4909d
Don't emit context receiver spacing if there are no context receivers
DRSchlaubi Apr 18, 2022
c97af64
Apply suggestions from code review
DRSchlaubi Apr 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,10 @@
package com.squareup.kotlinpoet

/**
* Annotation marking APIs for the [KEEP-259](https://github.com/Kotlin/KEEP/blob/master/proposals/context-receivers.md)
* prototype in Kotlin 1.6.20
*/
@RequiresOptIn
@MustBeDocumented
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.PROPERTY)
public annotation class ContextReceivers
DRSchlaubi marked this conversation as resolved.
Show resolved Hide resolved
62 changes: 47 additions & 15 deletions kotlinpoet/src/main/java/com/squareup/kotlinpoet/FunSpec.kt
Expand Up @@ -13,13 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:OptIn(ContextReceivers::class)
package com.squareup.kotlinpoet

import com.squareup.kotlinpoet.KModifier.ABSTRACT
import com.squareup.kotlinpoet.KModifier.EXPECT
import com.squareup.kotlinpoet.KModifier.EXTERNAL
import com.squareup.kotlinpoet.KModifier.INLINE
import com.squareup.kotlinpoet.KModifier.VARARG
import com.squareup.kotlinpoet.KModifier.*
DRSchlaubi marked this conversation as resolved.
Show resolved Hide resolved
import java.lang.reflect.Type
import javax.lang.model.element.Element
import javax.lang.model.element.ExecutableElement
Expand All @@ -45,6 +42,8 @@ public class FunSpec private constructor(
public val modifiers: Set<KModifier> = builder.modifiers.toImmutableSet()
public val typeVariables: List<TypeVariableName> = builder.typeVariables.toImmutableList()
public val receiverType: TypeName? = builder.receiverType
@ContextReceivers
public val contextReceiverTypes: List<TypeName> = builder.contextReceiverTypes.toImmutableList()
public val returnType: TypeName? = builder.returnType
public val parameters: List<ParameterSpec> = builder.parameters.toImmutableList()
public val delegateConstructor: String? = builder.delegateConstructor
Expand Down Expand Up @@ -285,6 +284,7 @@ public class FunSpec private constructor(
internal var returnKdoc = CodeBlock.EMPTY
internal var receiverKdoc = CodeBlock.EMPTY
internal var receiverType: TypeName? = null
internal val contextReceiverTypes: MutableList<TypeName> = mutableListOf()
internal var returnType: TypeName? = null
internal var delegateConstructor: String? = null
internal var delegateConstructorArguments = listOf<CodeBlock>()
Expand Down Expand Up @@ -359,7 +359,30 @@ public class FunSpec private constructor(
typeVariables += typeVariable
}

@JvmOverloads public fun receiver(
public fun contextReceiver(receiverTypes: Collection<TypeName>): Builder = apply {
DRSchlaubi marked this conversation as resolved.
Show resolved Hide resolved
Egorand marked this conversation as resolved.
Show resolved Hide resolved
DRSchlaubi marked this conversation as resolved.
Show resolved Hide resolved
check(!name.isConstructor) { "$name cannot have receiver type" }
DRSchlaubi marked this conversation as resolved.
Show resolved Hide resolved
contextReceiverTypes += receiverTypes
}
public fun contextReceiver(vararg receiverType: TypeName): Builder = contextReceiver(receiverType.toList())
DRSchlaubi marked this conversation as resolved.
Show resolved Hide resolved

@ContextReceivers
@JvmName("contextReceiverByType")
public fun contextReceiver(receiverTypes: List<Type>): Builder =
contextReceiver(receiverTypes.map { it.asTypeName() })
@ContextReceivers
public fun contextReceiver(vararg receiverType: Type): Builder =
DRSchlaubi marked this conversation as resolved.
Show resolved Hide resolved
contextReceiver(receiverType.toList())

@ContextReceivers
@JvmName("contextReceiverKClass")
public fun contextReceiver(receiverTypes: List<KClass<*>>): Builder =
contextReceiver(receiverTypes.map { it.asTypeName() })
@ContextReceivers
public fun contextReceiver(vararg receiverType: KClass<*>): Builder =
contextReceiver(receiverType.toList())

@JvmOverloads
public fun receiver(
receiverType: TypeName,
kdoc: CodeBlock = CodeBlock.EMPTY
): Builder = apply {
Expand All @@ -368,7 +391,8 @@ public class FunSpec private constructor(
this.receiverKdoc = kdoc
}

@JvmOverloads public fun receiver(
@JvmOverloads
DRSchlaubi marked this conversation as resolved.
Show resolved Hide resolved
public fun receiver(
receiverType: Type,
kdoc: CodeBlock = CodeBlock.EMPTY
): Builder = receiver(receiverType.asTypeName(), kdoc)
Expand All @@ -379,7 +403,8 @@ public class FunSpec private constructor(
vararg args: Any
): Builder = receiver(receiverType, CodeBlock.of(kdoc, args))

@JvmOverloads public fun receiver(
@JvmOverloads
public fun receiver(
receiverType: KClass<*>,
kdoc: CodeBlock = CodeBlock.EMPTY
): Builder = receiver(receiverType.asTypeName(), kdoc)
Expand All @@ -390,7 +415,8 @@ public class FunSpec private constructor(
vararg args: Any
): Builder = receiver(receiverType, CodeBlock.of(kdoc, args))

@JvmOverloads public fun returns(
@JvmOverloads
public fun returns(
returnType: TypeName,
kdoc: CodeBlock = CodeBlock.EMPTY
): Builder = apply {
Expand All @@ -399,13 +425,15 @@ public class FunSpec private constructor(
this.returnKdoc = kdoc
}

@JvmOverloads public fun returns(returnType: Type, kdoc: CodeBlock = CodeBlock.EMPTY): Builder =
@JvmOverloads
public fun returns(returnType: Type, kdoc: CodeBlock = CodeBlock.EMPTY): Builder =
returns(returnType.asTypeName(), kdoc)

public fun returns(returnType: Type, kdoc: String, vararg args: Any): Builder =
returns(returnType.asTypeName(), CodeBlock.of(kdoc, args))

@JvmOverloads public fun returns(
@JvmOverloads
public fun returns(
returnType: KClass<*>,
kdoc: CodeBlock = CodeBlock.EMPTY
): Builder = returns(returnType.asTypeName(), kdoc)
Expand Down Expand Up @@ -547,13 +575,17 @@ public class FunSpec private constructor(
private val THROW_EXPRESSION_BODY_PREFIX_SPACE = CodeBlock.of("throw ")
private val THROW_EXPRESSION_BODY_PREFIX_NBSP = CodeBlock.of("throw·")

@JvmStatic public fun builder(name: String): Builder = Builder(name)
@JvmStatic
public fun builder(name: String): Builder = Builder(name)

@JvmStatic public fun constructorBuilder(): Builder = Builder(CONSTRUCTOR)
@JvmStatic
public fun constructorBuilder(): Builder = Builder(CONSTRUCTOR)

@JvmStatic public fun getterBuilder(): Builder = Builder(GETTER)
@JvmStatic
public fun getterBuilder(): Builder = Builder(GETTER)

@JvmStatic public fun setterBuilder(): Builder = Builder(SETTER)
@JvmStatic
public fun setterBuilder(): Builder = Builder(SETTER)

@DelicateKotlinPoetApi(
message = "Element APIs don't give complete information on Kotlin types. Consider using" +
Expand Down
18 changes: 15 additions & 3 deletions kotlinpoet/src/main/java/com/squareup/kotlinpoet/LambdaTypeName.kt
Expand Up @@ -17,8 +17,11 @@ package com.squareup.kotlinpoet

import kotlin.reflect.KClass

@OptIn(ContextReceivers::class)
public class LambdaTypeName private constructor(
public val receiver: TypeName? = null,
@property:ContextReceivers
DRSchlaubi marked this conversation as resolved.
Show resolved Hide resolved
public val contextReceivers: List<TypeName>? = emptyList(),
DRSchlaubi marked this conversation as resolved.
Show resolved Hide resolved
parameters: List<ParameterSpec> = emptyList(),
public val returnType: TypeName = UNIT,
nullable: Boolean = false,
Expand Down Expand Up @@ -50,7 +53,7 @@ public class LambdaTypeName private constructor(
suspending: Boolean = this.isSuspending,
tags: Map<KClass<*>, Any> = this.tags.toMap()
): LambdaTypeName {
return LambdaTypeName(receiver, parameters, returnType, nullable, suspending, annotations, tags)
return LambdaTypeName(receiver, contextReceivers, parameters, returnType, nullable, suspending, annotations, tags)
}

override fun emit(out: CodeWriter): CodeWriter {
Expand Down Expand Up @@ -80,12 +83,20 @@ public class LambdaTypeName private constructor(
}

public companion object {
/** Returns a lambda type with `returnType` and parameters listed in `parameters`. */
@ContextReceivers @JvmStatic public fun get(
receiver: TypeName? = null,
contextReceivers: List<TypeName> = emptyList(),
DRSchlaubi marked this conversation as resolved.
Show resolved Hide resolved
parameters: List<ParameterSpec> = emptyList(),
returnType: TypeName
): LambdaTypeName = LambdaTypeName(receiver, contextReceivers, parameters, returnType)

/** Returns a lambda type with `returnType` and parameters listed in `parameters`. */
@JvmStatic public fun get(
receiver: TypeName? = null,
parameters: List<ParameterSpec> = emptyList(),
returnType: TypeName
): LambdaTypeName = LambdaTypeName(receiver, parameters, returnType)
): LambdaTypeName = LambdaTypeName(receiver, emptyList(), parameters, returnType)

/** Returns a lambda type with `returnType` and parameters listed in `parameters`. */
@JvmStatic public fun get(
Expand All @@ -95,6 +106,7 @@ public class LambdaTypeName private constructor(
): LambdaTypeName {
return LambdaTypeName(
receiver,
emptyList(),
parameters.toList().map { ParameterSpec.unnamed(it) },
returnType
)
Expand All @@ -105,6 +117,6 @@ public class LambdaTypeName private constructor(
receiver: TypeName? = null,
vararg parameters: ParameterSpec = emptyArray(),
returnType: TypeName
): LambdaTypeName = LambdaTypeName(receiver, parameters.toList(), returnType)
): LambdaTypeName = LambdaTypeName(receiver, emptyList(), parameters.toList(), returnType)
}
}