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

Differentiate escaping of Java or Kotlin keywords #3630

Merged
merged 7 commits into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.apollographql.apollo3.compiler

// Reference:
// https://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html
private val JAVA_RESERVED_WORDS = arrayOf(
"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default",
"do", "double", "else", "enum", "extends", "false", "final", "finally", "float", "for", "goto", "if", "implements",
Expand All @@ -8,15 +10,20 @@ private val JAVA_RESERVED_WORDS = arrayOf(
"transient", "try", "true", "void", "volatile", "while"
)

// Reference:
// https://kotlinlang.org/docs/keyword-reference.html#operators-and-special-symbols
// Note: "yield" is not in this reference, but is in fact reserved (https://github.com/apollographql/apollo-android/issues/1957)
martinbonnin marked this conversation as resolved.
Show resolved Hide resolved
private val KOTLIN_RESERVED_WORDS = arrayOf(
"as", "break", "class", "continue", "do", "else", "false", "for", "fun", "if", "in", "interface", "is", "null", "object", "package",
"return", "super", "this", "throw", "true", "try", "typealias", "typeof", "val", "var", "when", "while", "yield", "it", "field"
"return", "super", "this", "throw", "true", "try", "typealias", "typeof", "val", "var", "when", "while", "yield"
)

private val RESERVED_ENUM_VALUE_NAMES = arrayOf("name", "ordinal")
// Reference:
// https://kotlinlang.org/docs/enum-classes.html#working-with-enum-constants:~:text=properties%20for%20obtaining%20its%20name%20and%20position
private val KOTLIN_RESERVED_ENUM_VALUE_NAMES = arrayOf("name", "ordinal")

fun String.escapeJavaReservedWord() = if (this in JAVA_RESERVED_WORDS) "${this}_" else this

fun String.escapeKotlinReservedWord() = if (this in (JAVA_RESERVED_WORDS + KOTLIN_RESERVED_WORDS)) "${this}_" else this
fun String.escapeKotlinReservedWord() = if (this in KOTLIN_RESERVED_WORDS) "${this}_" else this

fun String.escapeKotlinReservedEnumValueNames() = if (this in (JAVA_RESERVED_WORDS + KOTLIN_RESERVED_WORDS + RESERVED_ENUM_VALUE_NAMES)) "${this}_" else this
fun String.escapeKotlinReservedEnumValueNames() = if (this in (KOTLIN_RESERVED_WORDS + KOTLIN_RESERVED_ENUM_VALUE_NAMES)) "${this}_" else this
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@


package com.apollographql.apollo3.compiler.codegen

import com.apollographql.apollo3.compiler.PackageNameGenerator
import com.apollographql.apollo3.compiler.capitalizeFirstLetter
import com.apollographql.apollo3.compiler.decapitalizeFirstLetter
import com.apollographql.apollo3.compiler.escapeKotlinReservedEnumValueNames
import com.apollographql.apollo3.compiler.escapeKotlinReservedWord
import com.apollographql.apollo3.compiler.ir.IrFieldInfo
import com.apollographql.apollo3.compiler.ir.IrListType
import com.apollographql.apollo3.compiler.ir.IrNonNullType
Expand All @@ -18,11 +14,9 @@ import com.apollographql.apollo3.compiler.singularize
/**
* The central place where the names/packages of the different classes are decided and escape rules done.
*
* Inputs should always be GraphQL identifiers and outputs are valid Kotlin identifiers.
*
* Inputs should always be GraphQL identifiers and outputs are valid Kotlin/Java identifiers.
*/

class CodegenLayout(
abstract class CodegenLayout(
private val packageNameGenerator: PackageNameGenerator,
schemaPackageName: String,
private val useSemanticNaming: Boolean,
Expand Down Expand Up @@ -61,7 +55,6 @@ class CodegenLayout(
// We used to write upper case enum values but the server can define different values with different cases
// See https://github.com/apollographql/apollo-android/issues/3035
internal fun enumValueName(name: String) = regularIdentifier(name)
internal fun sealedClassValueName(name: String) = name.escapeKotlinReservedEnumValueNames()
internal fun enumResponseAdapterName(name: String) = enumName(name) + "_ResponseAdapter"

internal fun operationName(operation: IrOperation): String {
Expand Down Expand Up @@ -97,9 +90,12 @@ class CodegenLayout(
internal fun schemaName() = "__Schema"

// ------------------------ Helpers ---------------------------------
private fun regularIdentifier(name: String) = name.escapeKotlinReservedWord()

abstract fun escapeReservedWord(word: String): String

private fun regularIdentifier(name: String) = escapeReservedWord(name)
private fun capitalizedIdentifier(name: String): String {
return name.capitalizeFirstLetter().escapeKotlinReservedWord()
return escapeReservedWord(name.capitalizeFirstLetter())
}

fun rootSelectionsPropertyName() = "root"
Expand All @@ -113,6 +109,7 @@ class CodegenLayout(
it.capitalizeFirstLetter()
}.joinToString("")
}

fun lowerCamelCaseIgnoringNonLetters(strings: Collection<String>): String {
return strings.map {
it.decapitalizeFirstLetter()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.apollographql.apollo3.compiler.codegen.java

import com.apollographql.apollo3.compiler.APOLLO_VERSION
import com.apollographql.apollo3.compiler.PackageNameGenerator
import com.apollographql.apollo3.compiler.codegen.CodegenLayout
import com.apollographql.apollo3.compiler.codegen.ResolverInfo
import com.apollographql.apollo3.compiler.codegen.java.adapter.EnumResponseAdapterBuilder
import com.apollographql.apollo3.compiler.codegen.java.file.CustomScalarBuilder
Expand All @@ -20,12 +19,11 @@ import com.apollographql.apollo3.compiler.codegen.java.file.OperationBuilder
import com.apollographql.apollo3.compiler.codegen.java.file.OperationResponseAdapterBuilder
import com.apollographql.apollo3.compiler.codegen.java.file.OperationSelectionsBuilder
import com.apollographql.apollo3.compiler.codegen.java.file.OperationVariablesAdapterBuilder
import com.apollographql.apollo3.compiler.codegen.java.file.UnionBuilder
import com.apollographql.apollo3.compiler.codegen.java.file.SchemaBuilder
import com.apollographql.apollo3.compiler.codegen.java.file.UnionBuilder
import com.apollographql.apollo3.compiler.ir.Ir
import com.apollographql.apollo3.compiler.operationoutput.OperationOutput
import com.apollographql.apollo3.compiler.operationoutput.findOperationId
import com.squareup.javapoet.ClassName
import com.squareup.javapoet.CodeBlock
import com.squareup.javapoet.JavaFile
import java.io.File
Expand Down Expand Up @@ -61,7 +59,7 @@ class JavaCodeGen(
JavaResolver(resolverInfo.entries, acc)
}

val layout = CodegenLayout(
val layout = JavaCodegenLayout(
useSemanticNaming = useSemanticNaming,
packageNameGenerator = packageNameGenerator,
schemaPackageName = schemaPackageName
Expand Down Expand Up @@ -212,4 +210,4 @@ fun CodeBlock.isNotEmpty() = isEmpty().not()

internal const val T = "${'$'}T"
internal const val L = "${'$'}L"
internal const val S = "${'$'}S"
internal const val S = "${'$'}S"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.apollographql.apollo3.compiler.codegen.java

import com.apollographql.apollo3.compiler.PackageNameGenerator
import com.apollographql.apollo3.compiler.codegen.CodegenLayout
import com.apollographql.apollo3.compiler.escapeJavaReservedWord

class JavaCodegenLayout(
packageNameGenerator: PackageNameGenerator,
schemaPackageName: String,
useSemanticNaming: Boolean,
) : CodegenLayout(packageNameGenerator, schemaPackageName, useSemanticNaming) {
override fun escapeReservedWord(word: String): String = word.escapeJavaReservedWord()
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.apollographql.apollo3.compiler.codegen.java

import com.apollographql.apollo3.compiler.codegen.CodegenLayout

class JavaContext(
val layout : CodegenLayout,
val resolver: JavaResolver
)
val layout: JavaCodegenLayout,
val resolver: JavaResolver,
)
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,4 @@ class ModelBuilder(
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.apollographql.apollo3.compiler.codegen.kotlin
import com.apollographql.apollo3.compiler.APOLLO_VERSION
import com.apollographql.apollo3.compiler.PackageNameGenerator
import com.apollographql.apollo3.compiler.TargetLanguage
import com.apollographql.apollo3.compiler.codegen.CodegenLayout
import com.apollographql.apollo3.compiler.codegen.ResolverInfo
import com.apollographql.apollo3.compiler.codegen.kotlin.file.CustomScalarBuilder
import com.apollographql.apollo3.compiler.codegen.kotlin.file.EnumAsEnumBuilder
Expand Down Expand Up @@ -69,7 +68,7 @@ class KotlinCodeGen(
KotlinResolver(resolverInfo.entries, acc)
}

val layout = CodegenLayout(
val layout = KotlinCodegenLayout(
useSemanticNaming = useSemanticNaming,
packageNameGenerator = packageNameGenerator,
schemaPackageName = schemaPackageName
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.apollographql.apollo3.compiler.codegen.kotlin

import com.apollographql.apollo3.compiler.PackageNameGenerator
import com.apollographql.apollo3.compiler.codegen.CodegenLayout
import com.apollographql.apollo3.compiler.escapeKotlinReservedEnumValueNames
import com.apollographql.apollo3.compiler.escapeKotlinReservedWord

class KotlinCodegenLayout(
packageNameGenerator: PackageNameGenerator,
schemaPackageName: String,
useSemanticNaming: Boolean,
) : CodegenLayout(packageNameGenerator, schemaPackageName, useSemanticNaming) {

override fun escapeReservedWord(word: String): String = word.escapeKotlinReservedWord()

internal fun sealedClassValueName(name: String) = name.escapeKotlinReservedEnumValueNames()
martinbonnin marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package com.apollographql.apollo3.compiler.codegen.kotlin

import com.apollographql.apollo3.compiler.TargetLanguage
import com.apollographql.apollo3.compiler.codegen.CodegenLayout

class KotlinContext(
val layout: CodegenLayout,
val layout: KotlinCodegenLayout,
val resolver: KotlinResolver,
val targetLanguageVersion: TargetLanguage,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.apollographql.apollo3.compiler.codegen.kotlin.file

import com.apollographql.apollo3.ast.GQLType
import com.apollographql.apollo3.compiler.codegen.ClassNames
import com.apollographql.apollo3.compiler.codegen.CodegenLayout
import com.apollographql.apollo3.compiler.codegen.Identifier
import com.apollographql.apollo3.compiler.codegen.Identifier.Data
import com.apollographql.apollo3.compiler.codegen.Identifier.block
Expand All @@ -11,9 +10,10 @@ import com.apollographql.apollo3.compiler.codegen.Identifier.fromJson
import com.apollographql.apollo3.compiler.codegen.Identifier.testResolver
import com.apollographql.apollo3.compiler.codegen.kotlin.CgFile
import com.apollographql.apollo3.compiler.codegen.kotlin.CgTestFileBuilder
import com.apollographql.apollo3.compiler.codegen.kotlin.KotlinSymbols
import com.apollographql.apollo3.compiler.codegen.kotlin.KotlinCodegenLayout
import com.apollographql.apollo3.compiler.codegen.kotlin.KotlinContext
import com.apollographql.apollo3.compiler.codegen.kotlin.KotlinMemberNames
import com.apollographql.apollo3.compiler.codegen.kotlin.KotlinSymbols
import com.apollographql.apollo3.compiler.codegen.kotlin.test.TBuilderBuilder
import com.apollographql.apollo3.compiler.decapitalizeFirstLetter
import com.apollographql.apollo3.compiler.ir.IrModel
Expand Down Expand Up @@ -206,7 +206,7 @@ private fun resolveNameClashes(usedNames: MutableSet<String>, modelName: String)
}


internal fun IrModel.toTBuilder(layout: CodegenLayout): TBuilder {
internal fun IrModel.toTBuilder(layout: KotlinCodegenLayout): TBuilder {
val nestedBuilders = modelGroups.flatMap { it.toTBuilders(layout) }
return TBuilder(
kotlinName = layout.testBuilder(modelName),
Expand All @@ -217,7 +217,7 @@ internal fun IrModel.toTBuilder(layout: CodegenLayout): TBuilder {
)
}

internal fun IrModelGroup.toTBuilders(layout: CodegenLayout): List<TBuilder> {
internal fun IrModelGroup.toTBuilders(layout: KotlinCodegenLayout): List<TBuilder> {
return models.filter { !it.isInterface }.map {
it.toTBuilder(layout)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,4 +478,4 @@ private fun OperationField.toProperty(): IrProperty {
requiresBuffering = fieldSet?.fields?.any { it.isSynthetic } ?: false,
hidden = hide
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -535,4 +535,4 @@ private fun List<GQLSelection>.collectFragments(): Set<String> {
is GQLFragmentSpread -> return@flatMap setOf(it.name)
}
}.toSet()
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading