Skip to content

Commit

Permalink
[J2KT] Add -objCNamePrefix option to the transpiler, which defaults…
Browse files Browse the repository at this point in the history
… to `"J2kt"` to preserve compatibility with existing clients. When ObjC name prefix is empty, ObjC compatibility aliases won't be rendered.

PiperOrigin-RevId: 734100724
  • Loading branch information
Googler authored and copybara-github committed Mar 6, 2025
1 parent 605e0ee commit 6a16779
Show file tree
Hide file tree
Showing 10 changed files with 33 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ final class BazelJ2clBuilder extends BazelWorker {
@Option(name = "-experimentalDefineForWasm", handler = MapOptionHandler.class, hidden = true)
Map<String, String> definesForWasm = new HashMap<>();

@Option(name = "-objCNamePrefix", hidden = true)
String objCNamePrefix = "J2kt";

@Override
protected void run() {
problems.abortIfCancelled();
Expand Down Expand Up @@ -225,6 +228,7 @@ private J2clTranspilerOptions createOptions(Output output) {
.setNullMarkedSupported(this.enableJSpecifySupport)
.setKotlincOptions(kotlincOptions)
.setForbiddenAnnotations(forbiddenAnnotations)
.setObjCNamePrefix(objCNamePrefix)
.build(problems);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ public final class J2clCommandLineRunner extends CommandLineTool {
@Option(name = "-defineForWasm", handler = MapOptionHandler.class, hidden = true)
Map<String, String> definesForWasm = new HashMap<>();

@Option(name = "-objCNamePrefix", hidden = true)
String objCNamePrefix = "J2kt";

private J2clCommandLineRunner() {
super("j2cl");
}
Expand Down Expand Up @@ -201,6 +204,7 @@ private J2clTranspilerOptions createOptions(Output output) {
.setNullMarkedSupported(this.enableJSpecifySupport)
.setKotlincOptions(kotlincOptions)
.setForbiddenAnnotations(forbiddenAnnotations)
.setObjCNamePrefix("J2kt")
.build(problems);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ public Builder setWasmEntryPointStrings(List<String> wasmEntryPoints) {

public abstract Builder setForbiddenAnnotations(List<String> forbiddenAnnotations);

public abstract Builder setObjCNamePrefix(String objCNamePrefix);

abstract J2clTranspilerOptions autoBuild();

public J2clTranspilerOptions build(Problems problems) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ public boolean isWasm() {
KOTLIN {
@Override
public void generateOutputs(BackendOptions options, Library library, Problems problems) {
new KotlinGeneratorStage(options.getOutput(), problems, /* withJ2ktPrefix= */ true)
new KotlinGeneratorStage(options.getOutput(), problems, options.getObjCNamePrefix())
.generateOutputs(library);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,6 @@ public interface BackendOptions {
boolean getGenerateKytheIndexingMetadata();

boolean isNullMarkedSupported();

String getObjCNamePrefix();
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ import com.google.j2cl.transpiler.backend.kotlin.source.Source.Companion.join
import com.google.j2cl.transpiler.backend.kotlin.source.Source.Companion.source
import com.google.j2cl.transpiler.backend.kotlin.source.Source.Companion.spaceSeparated

internal class J2ObjCCompatRenderer(private val withJ2ktPrefix: Boolean) {
internal class J2ObjCCompatRenderer(private val objCNamePrefix: String) {
internal fun source(compilationUnit: CompilationUnit): Source =
dependenciesAndDeclarationsSource(compilationUnit).ifNotEmpty {
emptyLineSeparated(fileCommentSource(compilationUnit), it) + Source.NEW_LINE
Expand All @@ -113,9 +113,11 @@ internal class J2ObjCCompatRenderer(private val withJ2ktPrefix: Boolean) {
private fun shouldRender(type: Type): Boolean = shouldRender(type.declaration)

private fun declarationsRenderers(type: Type): List<Renderer<Source>> = buildList {
add(aliasDeclarationRenderer(type.declaration))

type.toCompanionObjectOrNull()?.let { add(aliasDeclarationRenderer(it.declaration)) }
// Don't render compatibility aliases if ObjC name prefix is empty.
if (objCNamePrefix.isNotEmpty()) {
add(aliasDeclarationRenderer(type.declaration))
type.toCompanionObjectOrNull()?.let { add(aliasDeclarationRenderer(it.declaration)) }
}

if (type.isEnum) {
add(nsEnumTypedefRenderer(type))
Expand Down Expand Up @@ -388,7 +390,7 @@ internal class J2ObjCCompatRenderer(private val withJ2ktPrefix: Boolean) {
rendererOf(source(variable.name.objCName.escapeObjCKeyword))

private fun objCNameRenderer(companionDeclaration: CompanionDeclaration): Renderer<Source> =
className(companionDeclaration.objCName(withJ2ktPrefix))
className(companionDeclaration.objCName(objCNamePrefix))

private fun sharedRenderer(companionDeclaration: CompanionDeclaration): Renderer<Source> =
getProperty(objCNameRenderer(companionDeclaration), "shared")
Expand All @@ -412,7 +414,7 @@ internal class J2ObjCCompatRenderer(private val withJ2ktPrefix: Boolean) {
}

private fun nonMappedObjCNameRenderer(typeDeclaration: TypeDeclaration): Renderer<Source> =
objCNameRenderer(typeDeclaration.kind, typeDeclaration.objCName(withPrefix = withJ2ktPrefix))
objCNameRenderer(typeDeclaration.kind, typeDeclaration.objCName(prefix = objCNamePrefix))

private fun objCNameRenderer(kind: TypeDeclaration.Kind, name: String): Renderer<Source> =
when (kind) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ import com.google.j2cl.transpiler.backend.kotlin.source.Source
*
* @property output output for generated sources
* @property problems problems collected during generation
* @property objCNamePrefix ObjCName prefix for types
*/
class KotlinGeneratorStage(
private val output: OutputUtils.Output,
private val problems: Problems,
private val withJ2ktPrefix: Boolean,
private val objCNamePrefix: String,
) {
/** Generate outputs for a library. */
fun generateOutputs(library: Library) {
Expand All @@ -61,7 +62,7 @@ class KotlinGeneratorStage(

/** Generate ObjC outputs for a compilation unit. */
private fun generateObjCOutputs(compilationUnit: CompilationUnit) {
val source = J2ObjCCompatRenderer(withJ2ktPrefix).source(compilationUnit)
val source = J2ObjCCompatRenderer(objCNamePrefix).source(compilationUnit)
if (source.isNotEmpty()) {
val path = compilationUnit.packageRelativePath.replace(".java", "+J2ObjCCompat.h")
output.write(path, source.buildString())
Expand All @@ -81,7 +82,7 @@ class KotlinGeneratorStage(
)

val nameRenderer =
NameRenderer(environment, withJ2ktPrefix).plusLocalTypeNameMap(compilationUnit.localTypeNames)
NameRenderer(environment, objCNamePrefix).plusLocalTypeNameMap(compilationUnit.localTypeNames)

val compilationUnitRenderer = CompilationUnitRenderer(nameRenderer)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ import com.google.j2cl.transpiler.backend.kotlin.source.Source
internal data class NameRenderer
private constructor(
val environment: Environment,
val withJ2ktPrefix: Boolean,
val objCNamePrefix: String,
private val localTypeNameMap: Map<String, String>,
private val localFieldNames: Set<String>,
) {
constructor(
environment: Environment,
withJ2ktPrefix: Boolean,
objCNamePrefix: String,
) : this(
environment,
withJ2ktPrefix = withJ2ktPrefix,
objCNamePrefix = objCNamePrefix,
localTypeNameMap = mapOf(),
localFieldNames = setOf(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ internal class ObjCNameRenderer(val nameRenderer: NameRenderer) {
fun objCAnnotationSource(typeDeclaration: TypeDeclaration): Source =
Source.emptyUnless(needsObjCNameAnnotation(typeDeclaration)) {
objCNameAnnotationSource(
typeDeclaration.objCName(nameRenderer.withJ2ktPrefix),
typeDeclaration.objCName(nameRenderer.objCNamePrefix),
swiftName = typeDeclaration.objCNameWithoutPrefix,
exact = true,
)
Expand All @@ -64,7 +64,7 @@ internal class ObjCNameRenderer(val nameRenderer: NameRenderer) {
fun objCAnnotationSource(companionObject: CompanionObject): Source =
Source.emptyUnless(needsObjCNameAnnotation(companionObject)) {
objCNameAnnotationSource(
companionObject.declaration.objCName(nameRenderer.withJ2ktPrefix),
companionObject.declaration.objCName(nameRenderer.objCNamePrefix),
swiftName = companionObject.declaration.objCNameWithoutPrefix,
exact = true,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,19 +113,16 @@ internal fun Method.toNonConstructorObjCNames(): MethodObjCNames =
private val String.objCMethodParameterNames: List<String>
get() = letIf(lastOrNull() == ':') { dropLast(1) }.split(":")

private const val OBJC_TYPE_NAME_PREFIX: String = "J2kt"

internal fun TypeDeclaration.objCName(withPrefix: Boolean): String =
objCNameWithoutPrefix.letIf(withPrefix) { OBJC_TYPE_NAME_PREFIX + it }
internal fun TypeDeclaration.objCName(prefix: String): String = prefix + objCNameWithoutPrefix

internal val TypeDeclaration.objCNameWithoutPrefix: String
get() = mappedObjCName ?: nonMappedObjCName

private val String.objCCompanionTypeName: String
get() = this + "Companion"

internal fun CompanionDeclaration.objCName(withPrefix: Boolean) =
enclosingTypeDeclaration.objCName(withPrefix).objCCompanionTypeName
internal fun CompanionDeclaration.objCName(prefix: String) =
enclosingTypeDeclaration.objCName(prefix).objCCompanionTypeName

internal val CompanionDeclaration.objCNameWithoutPrefix
get() = enclosingTypeDeclaration.objCNameWithoutPrefix.objCCompanionTypeName
Expand Down

0 comments on commit 6a16779

Please sign in to comment.