Skip to content

Commit

Permalink
[J2KT] Extracts NameRenderer out of Renderer.
Browse files Browse the repository at this point in the history
This is the first CL in a chain. The follow-up CL will extract other types of renderers into their own classes:
- CompilationUnitRenderer,
- TypeRenderer,
- MemberRenderer,
- StatementRenderer,
- ExpressionRenderer.

PiperOrigin-RevId: 587693421
  • Loading branch information
Googler authored and copybara-github committed Dec 4, 2023
1 parent b2aa3cf commit 09994e8
Show file tree
Hide file tree
Showing 14 changed files with 204 additions and 154 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,21 @@ private val Renderer.fileAnnotationsSource: Source
get() = newLineSeparated(fileOptInAnnotationSource, suppressFileAnnotationSource)

private fun Renderer.fileOptInAnnotationSource(features: List<Source>): Source =
fileAnnotation(topLevelQualifiedNameSource("kotlin.OptIn"), features)
fileAnnotation(nameRenderer.topLevelQualifiedNameSource("kotlin.OptIn"), features)

internal val Renderer.fileOptInAnnotationSource: Source
get() =
environment.importedOptInQualifiedNamesSet
nameRenderer.environment.importedOptInQualifiedNamesSet
.takeIf { it.isNotEmpty() }
?.map { KotlinSource.classLiteral(topLevelQualifiedNameSource(it)) }
?.map { KotlinSource.classLiteral(nameRenderer.topLevelQualifiedNameSource(it)) }
?.let { fileOptInAnnotationSource(it) }
.orEmpty()

/** Returns source with file suppress annotation. */
private val Renderer.suppressFileAnnotationSource: Source
get() =
fileAnnotation(
topLevelQualifiedNameSource("kotlin.Suppress"),
nameRenderer.topLevelQualifiedNameSource("kotlin.Suppress"),
listOf(
"ALWAYS_NULL",
"PARAMETER_NAME_CHANGED_ON_OVERRIDE",
Expand All @@ -74,7 +74,7 @@ private val Renderer.suppressFileAnnotationSource: Source

/** Returns source with package declaration and imports for [compilationUnit]. */
internal fun Renderer.packageAndImportsSource(compilationUnit: CompilationUnit): Source =
emptyLineSeparated(packageSource(compilationUnit), importsSource)
emptyLineSeparated(packageSource(compilationUnit), nameRenderer.importsSource)

/** Returns package declaration source for [compilationUnit]. */
private fun packageSource(compilationUnit: CompilationUnit): Source =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,17 +169,17 @@ private fun Renderer.arrayLiteralSource(arrayLiteral: ArrayLiteral): Source =
arrayLiteral.typeDescriptor.typeArgument.let { typeArgument ->
join(
when (typeArgument.typeDescriptor) {
PrimitiveTypes.BOOLEAN -> topLevelQualifiedNameSource("kotlin.booleanArrayOf")
PrimitiveTypes.CHAR -> topLevelQualifiedNameSource("kotlin.charArrayOf")
PrimitiveTypes.BYTE -> topLevelQualifiedNameSource("kotlin.byteArrayOf")
PrimitiveTypes.SHORT -> topLevelQualifiedNameSource("kotlin.shortArrayOf")
PrimitiveTypes.INT -> topLevelQualifiedNameSource("kotlin.intArrayOf")
PrimitiveTypes.LONG -> topLevelQualifiedNameSource("kotlin.longArrayOf")
PrimitiveTypes.FLOAT -> topLevelQualifiedNameSource("kotlin.floatArrayOf")
PrimitiveTypes.DOUBLE -> topLevelQualifiedNameSource("kotlin.doubleArrayOf")
PrimitiveTypes.BOOLEAN -> nameRenderer.topLevelQualifiedNameSource("kotlin.booleanArrayOf")
PrimitiveTypes.CHAR -> nameRenderer.topLevelQualifiedNameSource("kotlin.charArrayOf")
PrimitiveTypes.BYTE -> nameRenderer.topLevelQualifiedNameSource("kotlin.byteArrayOf")
PrimitiveTypes.SHORT -> nameRenderer.topLevelQualifiedNameSource("kotlin.shortArrayOf")
PrimitiveTypes.INT -> nameRenderer.topLevelQualifiedNameSource("kotlin.intArrayOf")
PrimitiveTypes.LONG -> nameRenderer.topLevelQualifiedNameSource("kotlin.longArrayOf")
PrimitiveTypes.FLOAT -> nameRenderer.topLevelQualifiedNameSource("kotlin.floatArrayOf")
PrimitiveTypes.DOUBLE -> nameRenderer.topLevelQualifiedNameSource("kotlin.doubleArrayOf")
else ->
join(
topLevelQualifiedNameSource("kotlin.arrayOf"),
nameRenderer.topLevelQualifiedNameSource("kotlin.arrayOf"),
typeArgumentsSource(listOf(typeArgument))
)
},
Expand Down Expand Up @@ -227,7 +227,7 @@ private fun Renderer.castExpressionSource(castExpression: CastExpression): Sourc
dotSeparated(
inParentheses(expressionSource(castExpression.expression)),
spaceSeparated(
extensionMemberQualifiedNameSource("kotlin.let"),
nameRenderer.extensionMemberQualifiedNameSource("kotlin.let"),
inInlineCurlyBrackets(
semicolonSeparated(
castTypeDescriptor.intersectionTypeDescriptors
Expand Down Expand Up @@ -392,7 +392,7 @@ private fun Renderer.jsDocCastExpressionSource(expression: JsDocCastExpression):

private fun Renderer.instanceOfTestTypeDescriptorSource(typeDescriptor: TypeDescriptor): Source =
if (typeDescriptor is ArrayTypeDescriptor && !typeDescriptor.isPrimitiveArray) {
join(topLevelQualifiedNameSource("kotlin.Array"), inAngleBrackets(source("*")))
join(nameRenderer.topLevelQualifiedNameSource("kotlin.Array"), inAngleBrackets(source("*")))
} else {
typeDescriptorSource(typeDescriptor.toNonNullable(), projectRawToWildcards = true)
}
Expand All @@ -414,11 +414,11 @@ private fun stringLiteralSource(stringLiteral: StringLiteral): Source = literal(

private fun Renderer.typeLiteralSource(typeLiteral: TypeLiteral): Source =
dotSeparated(
classLiteral(qualifiedNameSource(typeLiteral.referencedTypeDescriptor)),
classLiteral(nameRenderer.qualifiedNameSource(typeLiteral.referencedTypeDescriptor)),
if (typeLiteral.referencedTypeDescriptor.isPrimitive) {
nonNull(extensionMemberQualifiedNameSource("kotlin.jvm.javaPrimitiveType"))
nonNull(nameRenderer.extensionMemberQualifiedNameSource("kotlin.jvm.javaPrimitiveType"))
} else {
extensionMemberQualifiedNameSource("kotlin.jvm.javaObjectType")
nameRenderer.extensionMemberQualifiedNameSource("kotlin.jvm.javaObjectType")
}
)

Expand All @@ -443,14 +443,14 @@ private fun Renderer.methodInvocationSource(expression: MethodCall): Source =
// getExtension(extension) call.
1 ->
join(
extensionMemberQualifiedNameSource("com.google.protobuf.kotlin.get"),
nameRenderer.extensionMemberQualifiedNameSource("com.google.protobuf.kotlin.get"),
invocationSource(expression)
)
// getExtension(extension, index) call.
2 ->
dotSeparated(
join(
extensionMemberQualifiedNameSource("com.google.protobuf.kotlin.get"),
nameRenderer.extensionMemberQualifiedNameSource("com.google.protobuf.kotlin.get"),
inParentheses(expressionSource(expression.arguments[0]))
),
join(source("get"), inParentheses(expressionSource(expression.arguments[1])))
Expand All @@ -461,7 +461,7 @@ private fun Renderer.methodInvocationSource(expression: MethodCall): Source =
identifierSource(computeProtobufPropertyName(expression.target.name!!))
methodDescriptor.isProtoExtensionChecker() ->
join(
extensionMemberQualifiedNameSource("com.google.protobuf.kotlin.contains"),
nameRenderer.extensionMemberQualifiedNameSource("com.google.protobuf.kotlin.contains"),
invocationSource(expression)
)
else ->
Expand Down Expand Up @@ -491,7 +491,7 @@ internal fun Renderer.invocationSource(invocation: Invocation) =

private fun Renderer.multiExpressionSource(multiExpression: MultiExpression): Source =
spaceSeparated(
extensionMemberQualifiedNameSource("kotlin.run"),
nameRenderer.extensionMemberQualifiedNameSource("kotlin.run"),
block(newLineSeparated(multiExpression.expressions.map(::expressionSource)))
)

Expand Down Expand Up @@ -521,7 +521,7 @@ private fun Renderer.newArraySource(
else
spaceSeparated(
join(
topLevelQualifiedNameSource("kotlin.Array"),
nameRenderer.topLevelQualifiedNameSource("kotlin.Array"),
typeArgumentsSource(listOf(typeArgument)),
inParentheses(expressionSource(firstDimension))
),
Expand All @@ -543,7 +543,7 @@ private fun Renderer.primitiveArrayOfSource(
dimension: Expression
): Source =
join(
topLevelQualifiedNameSource(
nameRenderer.topLevelQualifiedNameSource(
when (componentTypeDescriptor) {
PrimitiveTypes.BOOLEAN -> "kotlin.BooleanArray"
PrimitiveTypes.CHAR -> "kotlin.CharArray"
Expand All @@ -563,12 +563,12 @@ private fun Renderer.arrayOfNullsSource(typeArgument: TypeArgument, dimension: E
join(
if (typeArgument.typeDescriptor.isNullable) {
join(
extensionMemberQualifiedNameSource("kotlin.arrayOfNulls"),
nameRenderer.extensionMemberQualifiedNameSource("kotlin.arrayOfNulls"),
typeArgumentsSource(listOf(typeArgument.toNonNullable()))
)
} else {
join(
extensionMemberQualifiedNameSource("javaemul.lang.uninitializedArrayOf"),
nameRenderer.extensionMemberQualifiedNameSource("javaemul.lang.uninitializedArrayOf"),
typeArgumentsSource(listOf(typeArgument))
)
},
Expand Down Expand Up @@ -606,7 +606,7 @@ private fun Renderer.newInstanceTypeDescriptorSource(
if (typeDeclaration.isCapturingEnclosingInstance) {
identifierSource(typeDeclaration.ktSimpleName(asSuperType = true))
} else {
qualifiedNameSource(typeDescriptor, asSuperType = true)
nameRenderer.qualifiedNameSource(typeDescriptor, asSuperType = true)
},
invocationTypeArgumentsSource(typeDescriptor.typeArguments())
)
Expand Down Expand Up @@ -652,7 +652,7 @@ private fun Renderer.superReferenceSource(
join(
SUPER_KEYWORD,
superTypeDescriptor
?.let { inAngleBrackets(qualifiedNameSource(it, asSuperType = true)) }
?.let { inAngleBrackets(nameRenderer.qualifiedNameSource(it, asSuperType = true)) }
.orEmpty(),
qualifierTypeDescriptor?.let { labelReferenceSource(it) }.orEmpty()
)
Expand Down Expand Up @@ -685,7 +685,7 @@ private fun Renderer.variableDeclarationExpressionSource(
)

private fun Renderer.variableReferenceSource(variableReference: VariableReference): Source =
nameSource(variableReference.target)
nameRenderer.nameSource(variableReference.target)

private fun Renderer.variableDeclarationFragmentSource(
fragment: VariableDeclarationFragment
Expand All @@ -697,7 +697,7 @@ private fun Renderer.variableDeclarationFragmentSource(

private fun Renderer.variableSource(variable: Variable): Source =
colonSeparated(
nameSource(variable),
nameRenderer.nameSource(variable),
variable.typeDescriptor
.takeIf { it.isKtDenotableNonWildcard }
?.let { typeDescriptorSource(it) }
Expand All @@ -713,9 +713,9 @@ private fun Renderer.qualifierSource(memberReference: MemberReference): Source =
val ktCompanionQualifiedName =
enclosingTypeDescriptor.typeDeclaration.ktCompanionQualifiedName
if (ktCompanionQualifiedName != null) {
topLevelQualifiedNameSource(ktCompanionQualifiedName)
nameRenderer.topLevelQualifiedNameSource(ktCompanionQualifiedName)
} else {
qualifiedNameSource(enclosingTypeDescriptor)
nameRenderer.qualifiedNameSource(enclosingTypeDescriptor)
}
} else {
Source.EMPTY
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2021 Google Inc.
* Copyright 2023 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
Expand All @@ -15,50 +15,26 @@
*/
package com.google.j2cl.transpiler.backend.kotlin

import com.google.j2cl.transpiler.ast.HasName
import com.google.j2cl.transpiler.backend.kotlin.ast.Keywords
import com.google.j2cl.transpiler.backend.kotlin.common.inBackTicks
import com.google.j2cl.transpiler.backend.kotlin.common.letIf
import com.google.j2cl.transpiler.backend.kotlin.common.orIfNull
import com.google.j2cl.transpiler.backend.kotlin.source.Source
import com.google.j2cl.transpiler.backend.kotlin.source.Source.Companion.dotSeparated
import com.google.j2cl.transpiler.backend.kotlin.source.Source.Companion.source

internal fun Renderer.nameSource(hasName: HasName) =
identifierSource(environment.identifier(hasName))

internal fun identifierSource(identifier: String): Source = source(identifier.identifierString)

internal val String.identifierString
internal fun qualifiedIdentifierSource(identifier: String): Source =
dotSeparated(identifier.qualifiedNameComponents().map(::identifierSource))

private val String.identifierString
get() =
replace("$", "___").let { withoutDollars ->
withoutDollars.letIf(Keywords.isHard(withoutDollars) || !withoutDollars.isValidIdentifier) {
withoutDollars.inBackTicks
}
}

internal fun Renderer.topLevelQualifiedNameSource(
qualifiedName: String,
optInQualifiedName: String? = null
): Source =
qualifiedName.qualifiedNameToSimpleName().let { simpleName ->
if (localNames.contains(simpleName) || environment.containsIdentifier(simpleName)) {
qualifiedIdentifierSource(qualifiedName)
} else {
environment
.qualifiedToNonAliasedSimpleName(qualifiedName)
?.let { identifierSource(it) }
.orIfNull { qualifiedIdentifierSource(qualifiedName) }
.also { optInQualifiedName?.let { environment.addOptInQualifiedName(it) } }
}
}

internal fun Renderer.extensionMemberQualifiedNameSource(qualifiedName: String): Source =
identifierSource(environment.qualifiedToSimpleName(qualifiedName))

internal fun qualifiedIdentifierSource(identifier: String): Source =
dotSeparated(identifier.qualifiedNameComponents().map(::identifierSource))

private val String.isValidIdentifier: Boolean
get() = first().isValidIdentifierFirstChar && all { it.isValidIdentifierChar }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ import com.google.j2cl.transpiler.backend.kotlin.source.Source.Companion.spaceSe
import com.google.j2cl.transpiler.backend.kotlin.source.orEmpty

/** Source with rendered imports. */
internal val Renderer.importsSource: Source
internal val NameRenderer.importsSource: Source
get() = newLineSeparated(imports.map { it.source })

/** A set of default imports. */
private val defaultImports: Set<Import>
get() = setOf(starImport("javaemul", "lang"))

/** A list of imports to render. */
private val Renderer.imports: List<Import>
private val NameRenderer.imports: List<Import>
get() = defaultImports.plus(environment.importsSet).sortedWith(lexicographicalOrder())

/** Source for this import. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ internal fun Renderer.jsInteropAnnotationsSource(methodDescriptor: MethodDescrip
internal fun Renderer.jsInteropAnnotationsSource(parameterDescriptor: ParameterDescriptor): Source =
parameterDescriptor
.takeIf { it.isJsOptional }
?.let { annotation(topLevelQualifiedNameSource("jsinterop.annotations.JsOptional")) }
?.let {
annotation(nameRenderer.topLevelQualifiedNameSource("jsinterop.annotations.JsOptional"))
}
.orEmpty()

private fun Renderer.jsPropertyAnnotationSource(memberDescriptor: MemberDescriptor): Source =
Expand All @@ -63,19 +65,23 @@ private fun Renderer.jsPropertyAnnotationSource(memberDescriptor: MemberDescript
private fun Renderer.jsIgnoreAnnotationSource(memberDescriptor: MemberDescriptor): Source =
memberDescriptor
.takeIf { it.hasJsIgnoreAnnotation }
?.let { annotation(topLevelQualifiedNameSource("jsinterop.annotations.JsIgnore")) }
?.let { annotation(nameRenderer.topLevelQualifiedNameSource("jsinterop.annotations.JsIgnore")) }
.orEmpty()

private fun Renderer.jsOverlayAnnotationSource(memberDescriptor: MemberDescriptor): Source =
memberDescriptor
.takeIf { it.isJsOverlay }
?.let { annotation(topLevelQualifiedNameSource("jsinterop.annotations.JsOverlay")) }
?.let {
annotation(nameRenderer.topLevelQualifiedNameSource("jsinterop.annotations.JsOverlay"))
}
.orEmpty()

private fun Renderer.jsConstructorAnnotationSource(methodDescriptor: MethodDescriptor): Source =
methodDescriptor
.takeIf { it.hasJsConstructorAnnotation }
?.let { annotation(topLevelQualifiedNameSource("jsinterop.annotations.JsConstructor")) }
?.let {
annotation(nameRenderer.topLevelQualifiedNameSource("jsinterop.annotations.JsConstructor"))
}
.orEmpty()

private fun Renderer.jsMethodAnnotationSource(methodDescriptor: MethodDescriptor): Source =
Expand Down Expand Up @@ -107,7 +113,7 @@ private fun Renderer.jsInteropAnnotationSource(
?: if (it.isKtNameMangled) it.simpleJsName else null

annotation(
topLevelQualifiedNameSource(annotationQualifiedName),
nameRenderer.topLevelQualifiedNameSource(annotationQualifiedName),
nameParameterSource(nameParameterValue),
namespaceParameterSource(it.originalJsInfo.jsNamespace)
)
Expand All @@ -117,15 +123,17 @@ private fun Renderer.jsInteropAnnotationSource(
private fun Renderer.jsFunctionAnnotationSource(typeDeclaration: TypeDeclaration): Source =
typeDeclaration
.takeIf { it.isJsFunctionInterface }
?.let { annotation(topLevelQualifiedNameSource("jsinterop.annotations.JsFunction")) }
?.let {
annotation(nameRenderer.topLevelQualifiedNameSource("jsinterop.annotations.JsFunction"))
}
.orEmpty()

private fun Renderer.jsEnumAnnotationSource(typeDeclaration: TypeDeclaration): Source =
typeDeclaration
.takeIf { it.isJsEnum }
?.let {
annotation(
topLevelQualifiedNameSource("jsinterop.annotations.JsEnum"),
nameRenderer.topLevelQualifiedNameSource("jsinterop.annotations.JsEnum"),
nameParameterSource(it),
namespaceParameterSource(it),
isNativeParameterSource(it.isNative),
Expand All @@ -143,7 +151,7 @@ private fun Renderer.jsTypeAnnotationSource(typeDeclaration: TypeDeclaration): S
.takeIf { it.isJsType }
?.let {
annotation(
topLevelQualifiedNameSource("jsinterop.annotations.JsType"),
nameRenderer.topLevelQualifiedNameSource("jsinterop.annotations.JsType"),
nameParameterSource(it),
namespaceParameterSource(it),
isNativeParameterSource(it.isNative)
Expand Down Expand Up @@ -178,7 +186,7 @@ private fun Renderer.namespaceSource(namespace: String): Source =

private fun Renderer.globalNamespaceSource(): Source =
dotSeparated(
topLevelQualifiedNameSource("jsinterop.annotations.JsPackage"),
nameRenderer.topLevelQualifiedNameSource("jsinterop.annotations.JsPackage"),
identifierSource("GLOBAL")
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ class KotlinGeneratorStage(private val output: OutputUtils.Output, private val p
topLevelQualifiedNamesSet = compilationUnit.topLevelQualifiedNamesSet
)

val renderer = Renderer(environment)
val nameRenderer = NameRenderer(environment)

val renderer = Renderer(nameRenderer)

// Render types, collecting qualified names to import
val typesSource = renderer.typesSource(compilationUnit)
Expand Down
Loading

0 comments on commit 09994e8

Please sign in to comment.