Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build-logic-commons/build-platform/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ dependencies {
api("com.google.errorprone:error_prone_annotations:2.5.1")
api("com.google.code.gson:gson:2.8.9")
api("com.nhaarman:mockito-kotlin:1.6.0")
api("com.thoughtworks.qdox:qdox:2.0.0")
api("com.thoughtworks.qdox:qdox:2.0.3")
api("com.uwyn:jhighlight:1.0")
api("com.vladsch.flexmark:flexmark-all:0.34.60") {
because("Higher versions tested are either incompatible (0.62.2) or bring additional unwanted dependencies (0.36.8)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,37 @@
* limitations under the License.
*/

@file:JvmName("ApiExtensionsGenerator")

package org.gradle.kotlin.dsl.internal.sharedruntime.codegen

import org.gradle.kotlin.dsl.internal.sharedruntime.support.appendReproducibleNewLine
import java.io.File


/**
* Helper for reflective usage by `KotlinExtensionsForGradleApiFacade`.
*/
class ApiExtensionGeneratorFacade {
@Suppress("UNCHECKED_CAST")
fun generate(parameters: Map<String, Any>) {
generateKotlinDslApiExtensionsSourceTo(
parameters["asmLevel"] as Int,
parameters["platformClassLoader"] as ClassLoader,
parameters["incubatingAnnotationTypeDescriptor"] as String,
parameters["outputDirectory"] as File,
parameters["packageName"] as String,
parameters["sourceFilesBaseName"] as String,
parameters["hashTypeSourceName"] as java.util.function.Function<String, String>,
parameters["classPath"] as List<File>,
parameters["classPathDependencies"] as List<File>,
parameters["apiSpec"] as java.util.function.Function<String, Boolean>,
parameters["parameterNamesSupplier"] as java.util.function.Function<String, List<String>?>,
parameters["functionSinceSupplier"] as java.util.function.Function<String, String?>,
)
}
}


private
fun interface ApiSpec {
fun isApi(sourceName: String): Boolean
}
Expand All @@ -38,6 +61,7 @@ fun interface ApiSpec {
* @param classPathDependencies the api classpath dependencies
* @param apiSpec the api include/exclude spec
* @param parameterNamesSupplier the api function parameter names
* @param sinceSupplier the api functions `@since` values for binary signatures
*
* @return the list of generated source files
*/
Expand All @@ -48,24 +72,28 @@ fun generateKotlinDslApiExtensionsSourceTo(
outputDirectory: File,
packageName: String,
sourceFilesBaseName: String,
hashTypeSourceName: (String) -> String,
hashTypeSourceName: java.util.function.Function<String, String>,
classPath: List<File>,
classPathDependencies: List<File>,
apiSpec: ApiSpec,
parameterNamesSupplier: ParameterNamesSupplier,
apiSpec: java.util.function.Function<String, Boolean>,
parameterNamesSupplier: java.util.function.Function<String, List<String>?>,
sinceSupplier: java.util.function.Function<String, String?>,
): List<File> =

apiTypeProviderFor(
asmLevel,
platformClassLoader,
incubatingAnnotationTypeDescriptor,
classPath,
classPathDependencies,
parameterNamesSupplier
).use { api ->
classPathDependencies
) { parameterNamesSupplier.apply(it) }.use { api ->

val extensionsPerTarget =
kotlinDslApiExtensionsDeclarationsFor(api, apiSpec).groupedByTarget()
kotlinDslApiExtensionsDeclarationsFor(
api,
{ sinceSupplier.apply(it) },
{ apiSpec.apply(it) }
).groupedByTarget()

val sourceFiles =
ArrayList<File>(extensionsPerTarget.size)
Expand All @@ -80,8 +108,9 @@ fun generateKotlinDslApiExtensionsSourceTo(

for ((targetType, extensionsSubset) in extensionsPerTarget) {
writeExtensionsTo(
sourceFile("${sourceFilesBaseName}_${hashTypeSourceName(targetType.sourceName)}.kt"),
sourceFile("${sourceFilesBaseName}_${hashTypeSourceName.apply(targetType.sourceName)}.kt"),
packageName,
targetType,
extensionsSubset
)
}
Expand All @@ -96,9 +125,9 @@ fun Sequence<KotlinExtensionFunction>.groupedByTarget(): Map<ApiType, List<Kotli


private
fun writeExtensionsTo(outputFile: File, packageName: String, extensions: List<KotlinExtensionFunction>): Unit =
fun writeExtensionsTo(outputFile: File, packageName: String, targetType: ApiType, extensions: List<KotlinExtensionFunction>): Unit =
outputFile.bufferedWriter().use { writer ->
writer.write(fileHeaderFor(packageName))
writer.write(fileHeaderFor(packageName, targetType.isIncubating))
writer.write("\n")
extensions.forEach {
writer.write("\n${it.toKotlinString()}")
Expand All @@ -109,12 +138,13 @@ fun writeExtensionsTo(outputFile: File, packageName: String, extensions: List<Ko
private
fun kotlinDslApiExtensionsDeclarationsFor(
api: ApiTypeProvider,
sinceSupplier: (String) -> String?,
apiSpec: ApiSpec
): Sequence<KotlinExtensionFunction> =

api.allTypes()
.filter { type -> type.isPublic && apiSpec.isApi(type.sourceName) }
.flatMap { type -> kotlinExtensionFunctionsFor(type) }
.flatMap { type -> kotlinExtensionFunctionsFor(type, sinceSupplier) }
.distinctBy(::signatureKey)


Expand Down Expand Up @@ -145,7 +175,7 @@ fun apiTypeKey(usage: ApiTypeUsage): List<Any> = usage.run {
// 3. when overloading, prefer TypeOf over Class
// 4. in case the policy forbids your overloads, discuss
private
fun kotlinExtensionFunctionsFor(type: ApiType): Sequence<KotlinExtensionFunction> =
fun kotlinExtensionFunctionsFor(type: ApiType, sinceSupplier: (String) -> String?): Sequence<KotlinExtensionFunction> =
candidatesForExtensionFrom(type)
.sortedWithTypeOfTakingFunctionsFirst()
.flatMap { function ->
Expand All @@ -171,6 +201,7 @@ fun kotlinExtensionFunctionsFor(type: ApiType): Sequence<KotlinExtensionFunction
sequenceOf(
KotlinExtensionFunction(
description = "Kotlin extension function ${if (candidateFor.javaClassToKotlinClass) "taking [kotlin.reflect.KClass] " else ""}for [${type.sourceName}.${function.name}]",
since = sinceSupplier(function.binarySignature),
isIncubating = function.isIncubating,
isDeprecated = function.isDeprecated,
typeParameters = extensionTypeParameters,
Expand All @@ -191,7 +222,7 @@ fun ApiTypeUsage.hasJavaClass(): Boolean =


private
fun candidatesForExtensionFrom(type: ApiType) =
fun candidatesForExtensionFrom(type: ApiType): Sequence<ApiFunction> =
type.functions.filter(::isCandidateForExtension).asSequence()


Expand Down Expand Up @@ -274,6 +305,7 @@ fun List<MappedApiFunctionParameter>.javaClassToKotlinClass() =
private
data class KotlinExtensionFunction(
val description: String,
val since: String?,
val isIncubating: Boolean,
val isDeprecated: Boolean,
val typeParameters: List<ApiTypeUsage>,
Expand All @@ -290,7 +322,7 @@ data class KotlinExtensionFunction(
/**
* $description.
*
* @see ${targetType.sourceName}.$name
* @see ${targetType.sourceName}.$name${if (since != null) "\n * @since $since" else ""}
*/
""".trimIndent()
)
Expand Down Expand Up @@ -364,7 +396,7 @@ fun ApiTypeUsage.toCollectionOfKotlinClasses() =


private
fun ApiTypeUsage.singleTypeArgumentRawToStarProjection() =
fun ApiTypeUsage.singleTypeArgumentRawToStarProjection(): List<ApiTypeUsage> =
if (isRaw) singletonListOfStarProjectionTypeUsage
else typeArguments.also { it.single() }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ class ApiType internal constructor(
private val context: ApiTypeProvider.Context
) {

internal
val binaryName: String
get() = binaryNameOfInternalName(delegate.name)

val isPublic: Boolean
get() = delegate.access.isPublic

Expand Down Expand Up @@ -294,6 +298,10 @@ class ApiFunction internal constructor(
context.apiTypeUsageForReturnType(delegate, visitedSignature?.returnType)
}

internal
val binarySignature: String
get() = "${owner.binaryName}.$name(${parameters.joinToString(",") { it.typeBinaryName }})"

private
val visitedSignature: MethodSignatureVisitor? by unsafeLazy {
delegate.signature?.let { signature ->
Expand Down Expand Up @@ -348,6 +356,7 @@ data class ApiFunctionParameter internal constructor(
internal val index: Int,
internal val isVarargs: Boolean,
private val nameSupplier: () -> String?,
internal val typeBinaryName: String,
val type: ApiTypeUsage
) {

Expand Down Expand Up @@ -416,13 +425,14 @@ fun ApiTypeProvider.Context.apiFunctionParametersFor(function: ApiFunction, dele
val signatureParameter = visitedSignature?.parameters?.get(idx)
val parameterTypeName = signatureParameter?.binaryName ?: parameterTypeBinaryName
val variance = signatureParameter?.variance ?: Variance.INVARIANT
val typeArguments = signatureParameter?.typeArguments ?: emptyList<TypeSignatureVisitor>()
val typeArguments = signatureParameter?.typeArguments ?: emptyList()
ApiFunctionParameter(
index = idx,
isVarargs = idx == parameterTypesBinaryNames.lastIndex && delegate.access.isVarargs,
nameSupplier = {
names?.get(idx) ?: delegate.parameters?.get(idx)?.name
},
typeBinaryName = parameterTypeBinaryName,
type = apiTypeUsageFor(parameterTypeName, isNullable, variance, typeArguments)
)
}
Expand Down Expand Up @@ -601,7 +611,7 @@ val mappedTypeStrings =
"java.lang.Cloneable" to "kotlin.Cloneable",
"java.lang.Comparable" to "kotlin.Comparable",
"java.lang.Enum" to "kotlin.Enum",
"java.lang.Annotation" to "kotlin.Annotation",
"java.lang.annotation.Annotation" to "kotlin.Annotation",
"java.lang.Deprecated" to "kotlin.Deprecated",
"java.lang.CharSequence" to "kotlin.CharSequence",
"java.lang.Number" to "kotlin.Number",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,41 @@
* limitations under the License.
*/

package gradlebuild.kotlindsl.generator.codegen
package org.gradle.kotlin.dsl.internal.sharedruntime.codegen

import org.gradle.kotlin.dsl.internal.sharedruntime.codegen.fileHeader
import org.gradle.kotlin.dsl.internal.sharedruntime.codegen.pluginEntriesFrom
import org.gradle.kotlin.dsl.internal.sharedruntime.support.appendReproducibleNewLine
import org.gradle.plugin.use.PluginDependenciesSpec
import org.gradle.plugin.use.PluginDependencySpec
import java.io.File


fun writeBuiltinPluginIdExtensionsTo(file: File, gradleJars: Iterable<File>) {
/**
* Helper for reflective usage by `KotlinExtensionsForGradleApiFacade`.
*/
class PluginIdExtensionsFacade {
@Suppress("UNCHECKED_CAST")
fun generate(parameters: Map<String, Any>) {
writeBuiltinPluginIdExtensionsTo(
parameters["file"] as File,
parameters["gradleJars"] as Iterable<File>,
parameters["pluginDependenciesSpecQualifiedName"] as String,
parameters["pluginDependencySpecQualifiedName"] as String,
)
}
}


fun writeBuiltinPluginIdExtensionsTo(
file: File,
gradleJars: Iterable<File>,
pluginDependenciesSpecQualifiedName: String,
pluginDependencySpecQualifiedName: String,
) {
file.bufferedWriter().use { writer ->
writer.appendReproducibleNewLine(fileHeader)
pluginIdExtensionDeclarationsFor(gradleJars).forEach { extension ->
pluginIdExtensionDeclarationsFor(
gradleJars,
pluginDependenciesSpecQualifiedName,
pluginDependencySpecQualifiedName
).forEach { extension ->
writer.write("\n")
writer.appendReproducibleNewLine(extension)
}
Expand All @@ -36,9 +57,11 @@ fun writeBuiltinPluginIdExtensionsTo(file: File, gradleJars: Iterable<File>) {


private
fun pluginIdExtensionDeclarationsFor(jars: Iterable<File>): Sequence<String> {
val extendedType = PluginDependenciesSpec::class.qualifiedName!!
val extensionType = PluginDependencySpec::class.qualifiedName!!
fun pluginIdExtensionDeclarationsFor(
jars: Iterable<File>,
pluginDependenciesSpecQualifiedName: String,
pluginDependencySpecQualifiedName: String,
): Sequence<String> {
return pluginExtensionsFrom(jars)
.map { (memberName, pluginId, implementationClass) ->
"""
Expand All @@ -47,7 +70,7 @@ fun pluginIdExtensionDeclarationsFor(jars: Iterable<File>): Sequence<String> {
*
* @see $implementationClass
*/
inline val $extendedType.`$memberName`: $extensionType
inline val $pluginDependenciesSpecQualifiedName.`$memberName`: $pluginDependencySpecQualifiedName
get() = id("$pluginId")
""".trimIndent()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ val fileHeader: String
get() = fileHeaderFor(kotlinDslPackageName)


fun fileHeaderFor(packageName: String) =
fun fileHeaderFor(packageName: String, isIncubating: Boolean = false) =
"""$licenseHeader

@file:Suppress(
Expand All @@ -35,7 +35,7 @@ fun fileHeaderFor(packageName: String) =
"ObjectPropertyName",
"deprecation"
)
@file:org.gradle.api.Generated
@file:org.gradle.api.Generated${if (isIncubating) "\n@file:org.gradle.api.Incubating" else ""}

/* ktlint-disable */

Expand Down
1 change: 1 addition & 0 deletions build-logic/kotlin-dsl/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ dependencies {
implementation(kotlin("gradle-plugin"))
implementation(kotlin("sam-with-receiver"))
implementation("org.ow2.asm:asm")
implementation("com.thoughtworks.qdox:qdox")

testImplementation("junit:junit")
testImplementation("com.nhaarman:mockito-kotlin")
Expand Down
Loading