Skip to content

Commit fa72468

Browse files
authored
Do not check already checked fragments in checkCapitalizedFields, to avoid a StackOverflow (#6718) (#6721)
1 parent 16b9ce2 commit fa72468

File tree

2 files changed

+28
-23
lines changed

2 files changed

+28
-23
lines changed

libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/internal/checkCapitalizedFields.kt

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ internal fun checkCapitalizedFields(definitions: List<GQLDefinition>, checkFragm
2020

2121
definitions.forEach { definition ->
2222
when {
23-
definition is GQLOperationDefinition && !checkFragmentsOnly -> scope.checkCapitalizedFields(definition.selections)
24-
definition is GQLFragmentDefinition -> scope.checkCapitalizedFields(definition.selections)
23+
definition is GQLOperationDefinition && !checkFragmentsOnly -> scope.checkCapitalizedFields(definition.selections, emptyList())
24+
definition is GQLFragmentDefinition -> scope.checkCapitalizedFields(definition.selections, emptyList())
2525
}
2626
}
2727

@@ -31,7 +31,7 @@ internal fun checkCapitalizedFields(definitions: List<GQLDefinition>, checkFragm
3131
/**
3232
* Fields named with a capital first letter clash with the corresponding model name, unless flatten.
3333
*/
34-
private fun ValidationScope.checkCapitalizedFields(selections: List<GQLSelection>) {
34+
private fun ValidationScope.checkCapitalizedFields(selections: List<GQLSelection>, checkedFragments: List<String>) {
3535
selections.forEach {
3636
when (it) {
3737
is GQLField -> {
@@ -42,26 +42,34 @@ private fun ValidationScope.checkCapitalizedFields(selections: List<GQLSelection
4242
val alias = it.alias
4343
if (alias != null) {
4444
if (isFirstLetterUpperCase(alias)) {
45-
issues.add(UpperCaseField(message = """
45+
issues.add(
46+
UpperCaseField(
47+
message = """
4648
Capitalized alias '$alias' is not supported as it causes name clashes with the generated models. Use '${decapitalizeFirstLetter(alias)}' instead.
4749
""".trimIndent(),
48-
sourceLocation = it.sourceLocation)
50+
sourceLocation = it.sourceLocation
51+
)
4952
)
5053
}
5154
} else if (isFirstLetterUpperCase(it.name)) {
52-
issues.add(UpperCaseField(message = """
53-
Capitalized field '${it.name}' is not supported as it causes name clashes with the generated models. Use an alias instead or the 'flattenModels' or 'decapitalizeFields' compiler option.
54-
""".trimIndent(),
55-
sourceLocation = it.sourceLocation)
55+
issues.add(
56+
UpperCaseField(
57+
message = """
58+
Capitalized field '${it.name}' is not supported as it causes name clashes with the generated models. Use an alias instead or the 'flattenModels' or 'decapitalizeFields' compiler option.
59+
""".trimIndent(),
60+
sourceLocation = it.sourceLocation
61+
)
5662
)
5763
}
58-
checkCapitalizedFields(it.selections)
64+
checkCapitalizedFields(it.selections, checkedFragments)
5965
}
6066

61-
is GQLInlineFragment -> checkCapitalizedFields(it.selections)
67+
is GQLInlineFragment -> checkCapitalizedFields(it.selections, checkedFragments)
6268
// it might be that the fragment is defined in an upstream module. In that case, it is validated
6369
// already, no need to check it again
64-
is GQLFragmentSpread -> fragmentsByName[it.name]?.let { fragment -> checkCapitalizedFields(fragment.selections) }
70+
is GQLFragmentSpread -> if (!checkedFragments.contains(it.name)) {
71+
fragmentsByName[it.name]?.let { fragment -> checkCapitalizedFields(fragment.selections, checkedFragments + it.name) }
72+
}
6573
}
6674
}
6775
}
@@ -79,12 +87,14 @@ private fun decapitalizeFirstLetter(name: String): String {
7987
val builder = StringBuilder(name.length)
8088
var isDecapitalized = false
8189
name.forEach {
82-
builder.append(if (!isDecapitalized && it.isLetter()) {
83-
isDecapitalized = true
84-
it.toString().lowercase()
85-
} else {
86-
it.toString()
87-
})
90+
builder.append(
91+
if (!isDecapitalized && it.isLetter()) {
92+
isDecapitalized = true
93+
it.toString().lowercase()
94+
} else {
95+
it.toString()
96+
}
97+
)
8898
}
8999
return builder.toString()
90100
}

libraries/apollo-compiler/src/test/kotlin/com/apollographql/apollo/compiler/ValidationTest.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,7 @@ class ValidationTest(name: String, private val graphQLFile: File) {
3333
if (graphQLFile.name == "capitalized_fields_disallowed.graphql") {
3434
checkCapitalizedFields(parseResult.value!!.definitions, checkFragmentsOnly = false)
3535
} else {
36-
emptyList()
37-
} +
38-
if (graphQLFile.name == "capitalized_fields_allowed_with_fragment_spread.graphql") {
3936
checkCapitalizedFields(parseResult.value!!.definitions, checkFragmentsOnly = true)
40-
} else {
41-
emptyList()
4237
}
4338
}
4439
} else {

0 commit comments

Comments
 (0)