Skip to content

Commit 495decd

Browse files
committed
fix: handle malformed binding includes
1 parent 9aec337 commit 495decd

5 files changed

Lines changed: 68 additions & 8 deletions

File tree

‎compiler-core/src/main/kotlin/com/github/donglua/layoutx2c/codegen/BindingFacadeGeneratorV2.kt‎

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -365,13 +365,24 @@ class BindingFacadeGeneratorV2(
365365
"Missing required view with ID: ${field.idName}"
366366
)
367367
}
368-
builder.addStatement(
369-
"val %L: %T = %T.bind(%L)",
370-
field.propertyName,
371-
field.viewClass,
372-
field.nestedBindingX2CClassName(),
373-
rootVarName
374-
)
368+
if (field.useNestedX2CBinding) {
369+
builder.addStatement(
370+
"val %L: %T = %T.bind(%L)",
371+
field.propertyName,
372+
field.viewClass,
373+
field.nestedBindingX2CClassName(),
374+
rootVarName
375+
)
376+
} else {
377+
builder.addStatement(
378+
"val %L: %T = %T.bind(%L)\n⇥?: error(%S)⇤",
379+
field.propertyName,
380+
field.viewClass,
381+
ClassName("androidx.databinding", "DataBindingUtil"),
382+
rootVarName,
383+
"Missing required binding with ID: ${field.idName}"
384+
)
385+
}
375386
} else if (field.isRoot) {
376387
builder.addStatement(
377388
"val %L = rootView as? %T\n⇥?: error(%S)⇤",

‎compiler-core/src/main/kotlin/com/github/donglua/layoutx2c/codegen/BindingFieldCollector.kt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ data class BindingField(
1010
val viewClass: ClassName,
1111
val isRoot: Boolean = false,
1212
val isNestedBinding: Boolean = false,
13+
val useNestedX2CBinding: Boolean = true,
1314
val nestedBindingLayoutName: String? = null
1415
)
1516

@@ -48,6 +49,7 @@ class BindingFieldCollector(
4849
viewClass = bindingViewClass(node, isNestedBinding),
4950
isRoot = isRoot,
5051
isNestedBinding = isNestedBinding,
52+
useNestedX2CBinding = includeNode?.isMalformedDataBindingLayout != true,
5153
nestedBindingLayoutName = includeNode?.layoutRef?.takeIf { isNestedBinding }
5254
)
5355
}

‎compiler-core/src/main/kotlin/com/github/donglua/layoutx2c/parser/LayoutNodeTypes.kt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ sealed class LayoutNodeType {
1010
val layoutRef: String,
1111
val resolutionError: String? = null,
1212
val isDataBindingLayout: Boolean = false,
13+
val isMalformedDataBindingLayout: Boolean = false,
1314
val includeAttributes: Map<String, String> = emptyMap()
1415
) : LayoutNodeType()
1516
object Merge : LayoutNodeType()

‎compiler-core/src/main/kotlin/com/github/donglua/layoutx2c/parser/XmlLayoutParser.kt‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ class XmlLayoutParser(
100100
is IncludeResult.Success -> {
101101
val includedRoot = resolved.tree.root
102102
val resolvedNodeType = nodeType.copy(
103-
isDataBindingLayout = resolved.tree.rootMetadata.isDataBindingLayout
103+
isDataBindingLayout = resolved.tree.rootMetadata.isDataBindingLayout,
104+
isMalformedDataBindingLayout = resolved.tree.rootMetadata.isMalformedDataBindingLayout
104105
)
105106

106107
// If the included root is a <merge> tag, native Android ignores

‎compiler-core/src/test/kotlin/com/github/donglua/layoutx2c/codegen/BindingFacadeGeneratorV2Test.kt‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,51 @@ class BindingFacadeGeneratorV2Test {
109109
assertThat(generated).doesNotContain("public val viewText: TextView")
110110
}
111111

112+
@Test
113+
fun `malformed data binding include uses native binding instead of missing x2c facade`() {
114+
tempFolder.newFile("broken_child.xml").writeText(
115+
"""
116+
<layout xmlns:android="http://schemas.android.com/apk/res/android">
117+
<data>
118+
<variable
119+
name="title"
120+
type="java.lang.String" />
121+
</data>
122+
</layout>
123+
""".trimIndent()
124+
)
125+
val includeParser = XmlLayoutParser(includeResolver = IncludeResolver(tempFolder.root))
126+
val tree = includeParser.parse(
127+
"""
128+
<layout xmlns:android="http://schemas.android.com/apk/res/android">
129+
<FrameLayout
130+
android:layout_width="match_parent"
131+
android:layout_height="match_parent">
132+
<include
133+
android:id="@+id/broken"
134+
layout="@layout/broken_child"
135+
android:layout_width="match_parent"
136+
android:layout_height="wrap_content" />
137+
</FrameLayout>
138+
</layout>
139+
""".trimIndent(),
140+
"host_with_broken_include"
141+
)
142+
val analyzed = analyzer.analyze(tree.root)
143+
144+
val generated = generator.generate(
145+
analyzedRoot = analyzed,
146+
layoutName = "host_with_broken_include",
147+
layoutResId = "R.layout.host_with_broken_include",
148+
useFastPath = true,
149+
dataBindingVariables = tree.rootMetadata.dataBindingVariables
150+
).toString()
151+
152+
assertThat(generated).contains("val broken: BrokenChildBinding = DataBindingUtil.bind(brokenRoot)")
153+
assertThat(generated).doesNotContain("BrokenChildX2CBinding.bind")
154+
assertThat(generated).contains("setContainedBinding(broken)")
155+
}
156+
112157
@Test
113158
fun `generated binding binds root id field from root view directly`() {
114159
val xml = """

0 commit comments

Comments
 (0)