Skip to content

Commit def0fcc

Browse files
committed
fix(databinding): reject unsupported two-way adapters
Treat two-way BindingAdapter expressions as unsupported until an inverse adapter contract and reverse listener can be generated. Tested: ./gradlew test :demo:assembleDebug --warning-mode all --no-daemon
1 parent a167e46 commit def0fcc

5 files changed

Lines changed: 59 additions & 4 deletions

File tree

‎README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ object LayoutX2CConfig {
236236

237237
例如 `app:stateColorRes="@{R.color.sample_state}"` 和 `app:stateSizeDp="@{3F}"`
238238
会生成类似 `SampleBindingAdapters.setViewState(view, R.color.sample_state, 3f)`。
239+
当前白名单只描述正向 `BindingAdapter`。`@={}` 双向表达式还需要 inverse adapter
240+
和反向监听器契约,因此会标记为 unsupported 并继续 fallback。
239241
`attrs` 推荐写 XML 完整属性名;自定义 `app:` 属性也兼容无前缀写法,
240242
例如 `"stateColorRes"` 会按 `app:stateColorRes` 匹配。
241243

‎compiler-core/src/main/kotlin/com/github/donglua/layoutx2c/analyzer/LayoutAnalyzerV2.kt‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,8 @@ class LayoutAnalyzerV2(
185185
isXmlnsAttribute(attrName) -> { /* 忽略 */ }
186186
isToolsAttribute(attrName) -> supported.add(attrName)
187187
(isOneWay || isTwoWay) && isDeclaredBindingAdapterAttribute(attrName) -> {
188-
if (isSupportedBindingAdapterExpression(attrValue)) {
188+
if (!isTwoWay && isSupportedBindingAdapterExpression(attrValue)) {
189189
dataBinding.add(attrName)
190-
if (isTwoWay) twoWayBinding.add(attrName)
191190
} else {
192191
unsupported.add(attrName)
193192
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.github.donglua.layoutx2c.codegen
2+
3+
import com.github.donglua.layoutx2c.analyzer.LayoutAnalyzerV2
4+
import com.github.donglua.layoutx2c.parser.XmlLayoutParser
5+
import com.google.common.truth.Truth.assertThat
6+
import org.junit.Test
7+
8+
class TwoWayBindingAdapterBoundaryTest {
9+
10+
@Test
11+
fun `two-way binding adapter is unsupported without an inverse adapter contract`() {
12+
val bindingAdapters = listOf(
13+
BindingAdapterDescriptor(
14+
attrs = listOf("app:stateColorRes"),
15+
methodClassName = "com.example.databinding.SampleBindingAdapters",
16+
methodName = "setStateColor"
17+
)
18+
)
19+
val tree = XmlLayoutParser().parse(
20+
"""
21+
<layout xmlns:android="http://schemas.android.com/apk/res/android"
22+
xmlns:app="http://schemas.android.com/apk/res-auto">
23+
<data>
24+
<variable name="vm" type="com.example.StateViewModel" />
25+
</data>
26+
<View
27+
android:id="@+id/state_indicator"
28+
android:layout_width="6dp"
29+
android:layout_height="6dp"
30+
app:stateColorRes="@={vm.colorRes}" />
31+
</layout>
32+
""".trimIndent(),
33+
"item_two_way_binding_adapter"
34+
)
35+
val analyzed = LayoutAnalyzerV2(bindingAdapters = bindingAdapters).analyze(tree.root)
36+
37+
val generated = BindingFacadeGeneratorV2(
38+
packageName = "com.example.generated",
39+
rPackageName = "com.example",
40+
bindingAdapters = bindingAdapters
41+
).generate(
42+
analyzedRoot = analyzed,
43+
layoutName = "item_two_way_binding_adapter",
44+
layoutResId = "R.layout.item_two_way_binding_adapter",
45+
useFastPath = true,
46+
dataBindingVariables = tree.rootMetadata.dataBindingVariables
47+
).toString()
48+
49+
assertThat(analyzed.unsupportedAttributes).contains("app:stateColorRes")
50+
assertThat(analyzed.twoWayBindingAttributes).doesNotContain("app:stateColorRes")
51+
assertThat(generated).doesNotContain("SampleBindingAdapters.setStateColor")
52+
}
53+
}

‎runtime/src/main/java/com/github/donglua/layoutx2c/runtime/annotation/FastBindingAdapter.kt‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ package com.github.donglua.layoutx2c.runtime.annotation
33
import kotlin.reflect.KClass
44

55
/**
6-
* Declares one DataBinding BindingAdapter method that LayoutX2C may call directly.
6+
* Declares one one-way DataBinding BindingAdapter method that LayoutX2C may call directly.
7+
* Two-way expressions require an inverse adapter contract and are not generated.
78
*/
89
@PublicApi
910
@MustBeDocumented

‎runtime/src/main/java/com/github/donglua/layoutx2c/runtime/annotation/FastBindingAdapters.kt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.github.donglua.layoutx2c.runtime.annotation
22

33
/**
4-
* Declares DataBinding BindingAdapter methods that LayoutX2C may call directly.
4+
* Declares one-way DataBinding BindingAdapter methods that LayoutX2C may call directly.
55
*/
66
@PublicApi
77
@MustBeDocumented

0 commit comments

Comments
 (0)