[go: nahoru, domu]

[GH] Fix upper/lowercase locale issues

## Proposed Changes

  - Get rid of all `toUpperCase()`, `toLowerCase()`, `capitalize()` and `decapitalize()` calls inside Room without a `Locale` to avoid localization issues (specifically with Turkish).

## Testing

Test: Added one test that verifies this fix (similar to the issue mentioned in the ticket, test fails without my changes)

## Issues Fixed

Fixes: 68159494

This is an imported pull request from https://github.com/androidx/androidx/pull/70.

Resolves #70
Github-Pr-Head-Sha: 937fcb76f264b10e7277025f74f4febebb899251
GitOrigin-RevId: 74697ccb895897266e374e40bfd5bd9bed370002
Change-Id: Ibea01d68d55be46db1a98655d69066409b463e99
diff --git a/room/compiler/src/main/kotlin/androidx/room/ext/string_ext.kt b/room/compiler/src/main/kotlin/androidx/room/ext/string_ext.kt
index a91bbd0..2d537f0 100644
--- a/room/compiler/src/main/kotlin/androidx/room/ext/string_ext.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/ext/string_ext.kt
@@ -1,3 +1,5 @@
+import java.util.Locale
+
 /*
  * Copyright (C) 2016 The Android Open Source Project
  *
@@ -17,7 +19,7 @@
 private fun String.toCamelCase(): String {
     val split = this.split("_")
     if (split.isEmpty()) return ""
-    if (split.size == 1) return split[0].capitalize()
+    if (split.size == 1) return split[0].capitalize(Locale.US)
     return split.joinToCamelCase()
 }
 
@@ -46,3 +48,17 @@
             .map(String::trim)
             .joinToCamelCaseAsVar()
 }
+
+// TODO: Replace this with the function from the Kotlin stdlib once the API becomes stable
+fun String.capitalize(locale: Locale): String = if (isNotEmpty() && this[0].isLowerCase()) {
+    substring(0, 1).toUpperCase(locale) + substring(1)
+} else {
+    this
+}
+
+// TODO: Replace this with the function from the Kotlin stdlib once the API becomes stable
+fun String.decapitalize(locale: Locale): String = if (isNotEmpty() && this[0].isUpperCase()) {
+    substring(0, 1).toLowerCase(locale) + substring(1)
+} else {
+    this
+}
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
index 129aa5b..aed5aea 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
@@ -32,8 +32,10 @@
 import androidx.room.vo.Warning
 import androidx.room.vo.findFieldByColumnName
 import androidx.room.writer.FieldReadWriteWriter
+import capitalize
 import com.squareup.javapoet.TypeName
 import stripNonJava
+import java.util.Locale
 
 /**
  * Creates the entity from the given info.
@@ -117,7 +119,8 @@
 
     override fun onCursorReady(cursorVarName: String, scope: CodeGenScope) {
         mapping.fieldsWithIndices = mapping.matchedFields.map {
-            val indexVar = scope.getTmpVar("_cursorIndexOf${it.name.stripNonJava().capitalize()}")
+            val indexVar = scope.getTmpVar(
+                "_cursorIndexOf${it.name.stripNonJava().capitalize(Locale.US)}")
             val indexMethod = if (info == null) {
                 "getColumnIndex"
             } else {
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/types/CustomTypeConverterWrapper.kt b/room/compiler/src/main/kotlin/androidx/room/solver/types/CustomTypeConverterWrapper.kt
index 90bef99..aa1e4e5 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/types/CustomTypeConverterWrapper.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/types/CustomTypeConverterWrapper.kt
@@ -24,6 +24,8 @@
 import androidx.room.writer.ClassWriter
 import com.squareup.javapoet.ClassName
 import com.squareup.javapoet.FieldSpec
+import decapitalize
+import java.util.Locale
 import javax.lang.model.element.Modifier
 
 /**
@@ -51,7 +53,7 @@
     }
 
     fun typeConverter(scope: CodeGenScope): FieldSpec {
-        val baseName = (custom.typeName as ClassName).simpleName().decapitalize()
+        val baseName = (custom.typeName as ClassName).simpleName().decapitalize(Locale.US)
         return scope.writer.getOrCreateField(object : ClassWriter.SharedFieldSpec(
                 baseName, custom.typeName) {
             override fun getUniqueKey(): String {
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/types/PrimitiveColumnTypeAdapter.kt b/room/compiler/src/main/kotlin/androidx/room/solver/types/PrimitiveColumnTypeAdapter.kt
index 2dc78b2..22b6cf3 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/types/PrimitiveColumnTypeAdapter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/types/PrimitiveColumnTypeAdapter.kt
@@ -22,6 +22,7 @@
 import androidx.room.compiler.processing.XProcessingEnv
 import androidx.room.compiler.processing.XType
 import androidx.room.solver.CodeGenScope
+import capitalize
 import com.squareup.javapoet.TypeName.BYTE
 import com.squareup.javapoet.TypeName.CHAR
 import com.squareup.javapoet.TypeName.DOUBLE
@@ -29,6 +30,7 @@
 import com.squareup.javapoet.TypeName.INT
 import com.squareup.javapoet.TypeName.LONG
 import com.squareup.javapoet.TypeName.SHORT
+import java.util.Locale
 
 /**
  * Adapters for all primitives that has direct cursor mappings.
@@ -39,7 +41,7 @@
     val stmtSetter: String,
     typeAffinity: SQLTypeAffinity
 ) : ColumnTypeAdapter(out, typeAffinity) {
-    val cast = if (cursorGetter == "get${out.typeName.toString().capitalize()}")
+    val cast = if (cursorGetter == "get${out.typeName.toString().capitalize(Locale.US)}")
                     ""
                 else
                     "(${out.typeName}) "
diff --git a/room/compiler/src/main/kotlin/androidx/room/verifier/jdbc_ext.kt b/room/compiler/src/main/kotlin/androidx/room/verifier/jdbc_ext.kt
index 4e07439..c1a7c33 100644
--- a/room/compiler/src/main/kotlin/androidx/room/verifier/jdbc_ext.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/verifier/jdbc_ext.kt
@@ -20,6 +20,7 @@
 import java.sql.ResultSet
 import java.sql.ResultSetMetaData
 import java.sql.SQLException
+import java.util.Locale
 
 internal fun <T> ResultSet.collect(f: (ResultSet) -> T): List<T> {
     val result = arrayListOf<T>()
@@ -50,7 +51,7 @@
 
 private fun PreparedStatement.tryGetAffinity(columnIndex: Int): SQLTypeAffinity {
     return try {
-        SQLTypeAffinity.valueOf(metaData.getColumnTypeName(columnIndex).capitalize())
+        SQLTypeAffinity.valueOf(metaData.getColumnTypeName(columnIndex).capitalize(Locale.US))
     } catch (ex: IllegalArgumentException) {
         SQLTypeAffinity.NULL
     }
diff --git a/room/compiler/src/main/kotlin/androidx/room/vo/Field.kt b/room/compiler/src/main/kotlin/androidx/room/vo/Field.kt
index c5eca64..529bebd 100644
--- a/room/compiler/src/main/kotlin/androidx/room/vo/Field.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/vo/Field.kt
@@ -24,7 +24,10 @@
 import androidx.room.compiler.processing.XVariableElement
 import androidx.room.solver.types.CursorValueReader
 import androidx.room.solver.types.StatementValueBinder
+import capitalize
 import com.squareup.javapoet.TypeName
+import decapitalize
+import java.util.Locale
 
 // used in cache matching, must stay as a data class or implement equals
 data class Field(
@@ -93,15 +96,15 @@
                 result.add(name.substring(1))
             }
             if (name.startsWith("m") && name[1].isUpperCase()) {
-                result.add(name.substring(1).decapitalize())
+                result.add(name.substring(1).decapitalize(Locale.US))
             }
 
             if (typeName == TypeName.BOOLEAN || typeName == TypeName.BOOLEAN.box()) {
                 if (name.length > 2 && name.startsWith("is") && name[2].isUpperCase()) {
-                    result.add(name.substring(2).decapitalize())
+                    result.add(name.substring(2).decapitalize(Locale.US))
                 }
                 if (name.length > 3 && name.startsWith("has") && name[3].isUpperCase()) {
-                    result.add(name.substring(3).decapitalize())
+                    result.add(name.substring(3).decapitalize(Locale.US))
                 }
             }
         }
@@ -109,10 +112,10 @@
     }
 
     val getterNameWithVariations by lazy {
-        nameWithVariations.map { "get${it.capitalize()}" } +
+        nameWithVariations.map { "get${it.capitalize(Locale.US)}" } +
                 if (typeName == TypeName.BOOLEAN || typeName == TypeName.BOOLEAN.box()) {
                     nameWithVariations.flatMap {
-                        listOf("is${it.capitalize()}", "has${it.capitalize()}")
+                        listOf("is${it.capitalize(Locale.US)}", "has${it.capitalize(Locale.US)}")
                     }
                 } else {
                     emptyList()
@@ -120,7 +123,7 @@
     }
 
     val setterNameWithVariations by lazy {
-        nameWithVariations.map { "set${it.capitalize()}" }
+        nameWithVariations.map { "set${it.capitalize(Locale.US)}" }
     }
 
     /**
diff --git a/room/compiler/src/main/kotlin/androidx/room/vo/FtsOptions.kt b/room/compiler/src/main/kotlin/androidx/room/vo/FtsOptions.kt
index c886887..36819e6 100644
--- a/room/compiler/src/main/kotlin/androidx/room/vo/FtsOptions.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/vo/FtsOptions.kt
@@ -19,6 +19,7 @@
 import androidx.room.FtsOptions.MatchInfo
 import androidx.room.FtsOptions.Order
 import androidx.room.migration.bundle.FtsOptionsBundle
+import java.util.Locale
 
 data class FtsOptions(
     val tokenizer: String,
@@ -62,7 +63,7 @@
             }
 
             if (matchInfo != MatchInfo.FTS4) {
-                add("matchinfo=${matchInfo.name.toLowerCase()}")
+                add("matchinfo=${matchInfo.name.toLowerCase(Locale.US)}")
             }
 
             notIndexedColumns.forEach {
diff --git a/room/compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt b/room/compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
index e90359c..f182418 100644
--- a/room/compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
@@ -37,6 +37,7 @@
 import androidx.room.verifier.DatabaseVerificationErrors
 import androidx.room.writer.QueryWriter
 import androidx.room.writer.RelationCollectorMethodWriter
+import capitalize
 import com.squareup.javapoet.ClassName
 import com.squareup.javapoet.CodeBlock
 import com.squareup.javapoet.ParameterizedTypeName
@@ -45,6 +46,7 @@
 import java.nio.ByteBuffer
 import java.util.ArrayList
 import java.util.HashSet
+import java.util.Locale
 
 /**
  * Internal class that is used to manage fetching 1/N to N relationships.
@@ -66,7 +68,7 @@
 
     fun writeInitCode(scope: CodeGenScope) {
         varName = scope.getTmpVar(
-                "_collection${relation.field.getPath().stripNonJava().capitalize()}")
+                "_collection${relation.field.getPath().stripNonJava().capitalize(Locale.US)}")
         scope.builder().apply {
             addStatement("final $T $L = new $T()", mapTypeName, varName, mapTypeName)
         }
@@ -85,7 +87,7 @@
             readKey(cursorVarName, indexVar, scope) { tmpVar ->
                 if (relationTypeIsCollection) {
                     val tmpCollectionVar = scope.getTmpVar(
-                        "_tmp${relation.field.name.stripNonJava().capitalize()}Collection")
+                        "_tmp${relation.field.name.stripNonJava().capitalize(Locale.US)}Collection")
                     addStatement("$T $L = $L.get($L)", relationTypeName, tmpCollectionVar,
                         varName, tmpVar)
                     beginControlFlow("if ($L == null)", tmpCollectionVar).apply {
@@ -111,7 +113,7 @@
         }?.indexVar
         val tmpvarNameSuffix = if (relationTypeIsCollection) "Collection" else ""
         val tmpRelationVar = scope.getTmpVar(
-                "_tmp${relation.field.name.stripNonJava().capitalize()}$tmpvarNameSuffix")
+                "_tmp${relation.field.name.stripNonJava().capitalize(Locale.US)}$tmpvarNameSuffix")
         scope.builder().apply {
             addStatement("$T $L = null", relationTypeName, tmpRelationVar)
             readKey(cursorVarName, indexVar, scope) { tmpVar ->
diff --git a/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt b/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt
index d63b495..82ca796 100644
--- a/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt
@@ -16,6 +16,8 @@
 
 package androidx.room.vo
 
+import java.util.Locale
+
 /**
  * Internal representation of supported warnings
  */
@@ -48,7 +50,7 @@
     companion object {
         val PUBLIC_KEY_MAP = values().associateBy { it.publicKey }
         fun fromPublicKey(publicKey: String): Warning? {
-            return PUBLIC_KEY_MAP[publicKey.toUpperCase()]
+            return PUBLIC_KEY_MAP[publicKey.toUpperCase(Locale.US)]
         }
     }
 }
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
index 8f9be1c..d4d0af7 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
@@ -40,6 +40,7 @@
 import androidx.room.vo.ShortcutMethod
 import androidx.room.vo.TransactionMethod
 import androidx.room.vo.WriteQueryMethod
+import capitalize
 import com.squareup.javapoet.ClassName
 import com.squareup.javapoet.CodeBlock
 import com.squareup.javapoet.FieldSpec
@@ -49,6 +50,7 @@
 import com.squareup.javapoet.TypeName
 import com.squareup.javapoet.TypeSpec
 import stripNonJava
+import java.util.Locale
 import javax.lang.model.element.Modifier.FINAL
 import javax.lang.model.element.Modifier.PRIVATE
 import javax.lang.model.element.Modifier.PUBLIC
@@ -508,7 +510,7 @@
     }
 
     class PreparedStatementField(val method: QueryMethod) : SharedFieldSpec(
-        "preparedStmtOf${method.name.capitalize()}", RoomTypeNames.SHARED_SQLITE_STMT
+        "preparedStmtOf${method.name.capitalize(Locale.US)}", RoomTypeNames.SHARED_SQLITE_STMT
     ) {
         override fun prepare(writer: ClassWriter, builder: FieldSpec.Builder) {
             builder.addModifiers(PRIVATE, FINAL)
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
index 518575e..0ad8ad1 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
@@ -36,6 +36,7 @@
 import com.squareup.javapoet.ParameterizedTypeName
 import com.squareup.javapoet.TypeName
 import com.squareup.javapoet.TypeSpec
+import decapitalize
 import stripNonJava
 import java.util.Locale
 import javax.lang.model.element.Modifier.FINAL
@@ -165,7 +166,7 @@
         val scope = CodeGenScope(this)
         builder.apply {
             database.daoMethods.forEach { method ->
-                val name = method.dao.typeName.simpleName().decapitalize().stripNonJava()
+                val name = method.dao.typeName.simpleName().decapitalize(Locale.US).stripNonJava()
                 val fieldName = scope.getTmpVar("_$name")
                 val field = FieldSpec.builder(method.dao.typeName, fieldName,
                         PRIVATE, VOLATILE).build()
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/EntityCursorConverterWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/EntityCursorConverterWriter.kt
index 2d37196..9a3b80f 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/EntityCursorConverterWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/EntityCursorConverterWriter.kt
@@ -24,11 +24,13 @@
 import androidx.room.solver.CodeGenScope
 import androidx.room.vo.Entity
 import androidx.room.vo.FieldWithIndex
+import capitalize
 import com.squareup.javapoet.CodeBlock
 import com.squareup.javapoet.MethodSpec
 import com.squareup.javapoet.ParameterSpec
 import com.squareup.javapoet.TypeName
 import stripNonJava
+import java.util.Locale
 import javax.lang.model.element.Modifier.PRIVATE
 
 class EntityCursorConverterWriter(val entity: Entity) : ClassWriter.SharedMethodSpec(
@@ -55,7 +57,7 @@
             scope.builder().addStatement("final $T $L", entity.typeName, entityVar)
             val fieldsWithIndices = entity.fields.map {
                 val indexVar = scope.getTmpVar(
-                        "_cursorIndexOf${it.name.stripNonJava().capitalize()}")
+                        "_cursorIndexOf${it.name.stripNonJava().capitalize(Locale.US)}")
                 scope.builder().addStatement("final $T $L = $N.getColumnIndex($S)",
                         TypeName.INT, indexVar, cursorParam, it.columnName)
                 FieldWithIndex(field = it,
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
index aa4e649..8296746 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
@@ -27,7 +27,9 @@
 import androidx.room.vo.FieldWithIndex
 import androidx.room.vo.Pojo
 import androidx.room.vo.RelationCollector
+import capitalize
 import com.squareup.javapoet.TypeName
+import java.util.Locale
 
 /**
  * Handles writing a field into statement or reading it from statement.
@@ -73,7 +75,7 @@
             rootNode.directFields = fieldsWithIndices.filter { it.field.parent == null }
             val parentNodes = allParents.associate {
                 Pair(it, Node(
-                        varName = scope.getTmpVar("_tmp${it.field.name.capitalize()}"),
+                        varName = scope.getTmpVar("_tmp${it.field.name.capitalize(Locale.US)}"),
                         fieldParent = it))
             }
             parentNodes.values.forEach { node ->
@@ -324,7 +326,8 @@
                                     indexVar, scope)
                         }
                         CallType.METHOD -> {
-                            val tmpField = scope.getTmpVar("_tmp${field.name.capitalize()}")
+                            val tmpField = scope.getTmpVar(
+                                "_tmp${field.name.capitalize(Locale.US)}")
                             addStatement("final $T $L", field.setter.type.typeName, tmpField)
                             reader.readFromCursor(tmpField, cursorVar, indexVar, scope)
                             addStatement("$L.$L($L)", ownerVar, field.setter.name, tmpField)
@@ -356,7 +359,7 @@
         typeName: TypeName,
         scope: CodeGenScope
     ): String {
-        val tmpField = scope.getTmpVar("_tmp${field.name.capitalize()}")
+        val tmpField = scope.getTmpVar("_tmp${field.name.capitalize(Locale.US)}")
         scope.builder().apply {
             addStatement("final $T $L", typeName, tmpField)
             if (alwaysExists) {
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/FtsTableInfoValidationWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/FtsTableInfoValidationWriter.kt
index 2d5ffa9..e76424b 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/FtsTableInfoValidationWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/FtsTableInfoValidationWriter.kt
@@ -24,13 +24,15 @@
 import androidx.room.ext.T
 import androidx.room.ext.typeName
 import androidx.room.vo.FtsEntity
+import capitalize
 import com.squareup.javapoet.ParameterSpec
 import com.squareup.javapoet.ParameterizedTypeName
 import stripNonJava
+import java.util.Locale
 
 class FtsTableInfoValidationWriter(val entity: FtsEntity) : ValidationWriter() {
     override fun write(dbParam: ParameterSpec, scope: CountingCodeGenScope) {
-        val suffix = entity.tableName.stripNonJava().capitalize()
+        val suffix = entity.tableName.stripNonJava().capitalize(Locale.US)
         val expectedInfoVar = scope.getTmpVar("_info$suffix")
         scope.builder().apply {
             val columnListVar = scope.getTmpVar("_columns$suffix")
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/TableInfoValidationWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/TableInfoValidationWriter.kt
index 578dd43..69923a9 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/TableInfoValidationWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/TableInfoValidationWriter.kt
@@ -26,12 +26,14 @@
 import androidx.room.parser.SQLTypeAffinity
 import androidx.room.vo.Entity
 import androidx.room.vo.columnNames
+import capitalize
 import com.squareup.javapoet.ParameterSpec
 import com.squareup.javapoet.ParameterizedTypeName
 import stripNonJava
 import java.util.Arrays
 import java.util.HashMap
 import java.util.HashSet
+import java.util.Locale
 
 class TableInfoValidationWriter(val entity: Entity) : ValidationWriter() {
 
@@ -40,7 +42,7 @@
     }
 
     override fun write(dbParam: ParameterSpec, scope: CountingCodeGenScope) {
-        val suffix = entity.tableName.stripNonJava().capitalize()
+        val suffix = entity.tableName.stripNonJava().capitalize(Locale.US)
         val expectedInfoVar = scope.getTmpVar("_info$suffix")
         scope.builder().apply {
             val columnListVar = scope.getTmpVar("_columns$suffix")
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/ViewInfoValidationWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/ViewInfoValidationWriter.kt
index 66c2892..16d68a5 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/ViewInfoValidationWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/ViewInfoValidationWriter.kt
@@ -22,13 +22,15 @@
 import androidx.room.ext.S
 import androidx.room.ext.T
 import androidx.room.vo.DatabaseView
+import capitalize
 import com.squareup.javapoet.ParameterSpec
 import stripNonJava
+import java.util.Locale
 
 class ViewInfoValidationWriter(val view: DatabaseView) : ValidationWriter() {
 
     override fun write(dbParam: ParameterSpec, scope: CountingCodeGenScope) {
-        val suffix = view.viewName.stripNonJava().capitalize()
+        val suffix = view.viewName.stripNonJava().capitalize(Locale.US)
         scope.builder().apply {
             val expectedInfoVar = scope.getTmpVar("_info$suffix")
             addStatement("final $T $L = new $T($S, $S)",
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/FieldProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/FieldProcessorTest.kt
index 25b6947..4c5939c 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/FieldProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/FieldProcessorTest.kt
@@ -38,6 +38,7 @@
 import org.junit.runners.JUnit4
 import org.mockito.Mockito.mock
 import simpleRun
+import java.util.Locale
 
 @Suppress("HasPlatformType")
 @RunWith(JUnit4::class)
@@ -181,7 +182,7 @@
     fun primitiveArray() {
         ALL_PRIMITIVES.forEach { primitive ->
             singleEntity("@TypeConverters(foo.bar.MyConverter.class) " +
-                    "${primitive.toString().toLowerCase()}[] arr;") { field, invocation ->
+                    "${primitive.toString().toLowerCase(Locale.US)}[] arr;") { field, invocation ->
                 assertThat(field, `is`(
                         Field(name = "arr",
                                 type = invocation.processingEnv.getArrayType(primitive),
diff --git a/room/compiler/src/test/kotlin/androidx/room/writer/DaoWriterTest.kt b/room/compiler/src/test/kotlin/androidx/room/writer/DaoWriterTest.kt
index 4370c29..0397a3f 100644
--- a/room/compiler/src/test/kotlin/androidx/room/writer/DaoWriterTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/writer/DaoWriterTest.kt
@@ -28,6 +28,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
+import java.util.Locale
 import javax.tools.JavaFileObject
 
 @RunWith(JUnit4::class)
@@ -44,6 +45,17 @@
     }
 
     @Test
+    fun complexDao_turkishLocale() {
+        val originalLocale = Locale.getDefault()
+        try {
+            Locale.setDefault(Locale("tr")) // Turkish has special upper/lowercase i chars
+            complexDao()
+        } finally {
+            Locale.setDefault(originalLocale)
+        }
+    }
+
+    @Test
     fun writerDao() {
         singleDao(
                 loadJavaCode("daoWriter/input/WriterDao.java", "foo.bar.WriterDao")