From 3695b1aae95b289302cbbf9c38f0bd595bfc6ccb Mon Sep 17 00:00:00 2001 From: Yigit Boyar Date: Fri, 27 Mar 2015 14:10:13 -0700 Subject: Fix bugs related to how we handle Ternary ops This CL fixes two bugs. 1) When a Ternary operation was inside another operation, we were not handling dependecies properly and model would think that the container expression can be evaluated before Ternary is evaluated, eventually causing an exception in code-gen because Ternay is not calculated yet. 2) This also fixes another bug where when ?? is used, we would put ifTrue and ifFalse statements in wrong order and eventually evaluate !??. Bug: 19939148 Change-Id: I3e1d2bee172e47412bb8ef9e7c785aef47337155 --- .../databinding/tool/ExpressionVisitor.java | 2 +- .../java/android/databinding/tool/expr/Expr.java | 16 ++-- .../android/databinding/tool/expr/ExprModel.java | 9 +- .../databinding/tool/writer/LayoutBinderWriter.kt | 5 +- .../databinding/tool/expr/ExprModelTest.java | 103 ++++++++++++++++----- .../databinding/BindingExpressionParserTest.java | 38 ++++---- .../testapp/InnerCannotReadDependencyTest.java | 49 ++++++++++ .../databinding/testapp/vo/BasicObject.java | 45 +++++++++ .../app/src/main/res/layout/find_method_test.xml | 4 +- .../res/layout/inner_cannot_read_dependency.xml | 11 +++ 10 files changed, 224 insertions(+), 58 deletions(-) create mode 100644 tools/data-binding/integration-tests/TestApp/app/src/androidTest/java/android/databinding/testapp/InnerCannotReadDependencyTest.java create mode 100644 tools/data-binding/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/BasicObject.java create mode 100644 tools/data-binding/integration-tests/TestApp/app/src/main/res/layout/inner_cannot_read_dependency.xml (limited to 'tools') diff --git a/tools/data-binding/compiler/src/main/java/android/databinding/tool/ExpressionVisitor.java b/tools/data-binding/compiler/src/main/java/android/databinding/tool/ExpressionVisitor.java index 879c439..a30f59b 100644 --- a/tools/data-binding/compiler/src/main/java/android/databinding/tool/ExpressionVisitor.java +++ b/tools/data-binding/compiler/src/main/java/android/databinding/tool/ExpressionVisitor.java @@ -93,7 +93,7 @@ public class ExpressionVisitor extends BindingExpressionBaseVisitor { public Expr visitQuestionQuestionOp(@NotNull BindingExpressionParser.QuestionQuestionOpContext ctx) { final Expr left = ctx.left.accept(this); return mModel.ternary(mModel.comparison("==", left, mModel.symbol("null", Object.class)), - left, ctx.right.accept(this)); + ctx.right.accept(this), left); } @Override diff --git a/tools/data-binding/compiler/src/main/java/android/databinding/tool/expr/Expr.java b/tools/data-binding/compiler/src/main/java/android/databinding/tool/expr/Expr.java index a7cd412..09b96d8 100644 --- a/tools/data-binding/compiler/src/main/java/android/databinding/tool/expr/Expr.java +++ b/tools/data-binding/compiler/src/main/java/android/databinding/tool/expr/Expr.java @@ -400,17 +400,12 @@ abstract public class Expr { return mRead; } - public boolean considerElevatingConditionals(Expr cond) { + public boolean considerElevatingConditionals(Expr justRead) { boolean elevated = false; for (Dependency dependency : mDependencies) { - if (dependency.isConditional() && dependency.getCondition() == cond) { + if (dependency.isConditional() && dependency.getCondition() == justRead) { dependency.elevate(); - // silent elevate because it is not necessary anymore (already calculated) - // but need to mark dependencies elevated so that we can decide to calculate - // this expression when all dependencies are elevated - if (!dependency.getOther().isRead()) { - elevated = true; - } + elevated = true; } } return elevated; @@ -433,7 +428,7 @@ abstract public class Expr { Predicate hasNestedCannotRead = new Predicate() { @Override public boolean apply(Dependency input) { - return input.getOther().hasNestedCannotRead(); + return input.isConditional() || input.getOther().hasNestedCannotRead(); } }; @@ -470,6 +465,9 @@ abstract public class Expr { } } + if (mRead) { + mShouldReadFlags = null; // if we've been marked as read, clear should read flags + } return mRead; } diff --git a/tools/data-binding/compiler/src/main/java/android/databinding/tool/expr/ExprModel.java b/tools/data-binding/compiler/src/main/java/android/databinding/tool/expr/ExprModel.java index e3ec30a..0f8a935 100644 --- a/tools/data-binding/compiler/src/main/java/android/databinding/tool/expr/ExprModel.java +++ b/tools/data-binding/compiler/src/main/java/android/databinding/tool/expr/ExprModel.java @@ -26,6 +26,7 @@ import android.databinding.tool.util.L; import android.databinding.tool.writer.FlagSet; import java.util.ArrayList; +import java.util.Arrays; import java.util.BitSet; import java.util.HashMap; import java.util.List; @@ -437,12 +438,12 @@ public class ExprModel { return elevated; } - public Iterable filterShouldRead(Iterable exprs) { - return Iterables.filter(exprs, sShouldReadPred); + public static Iterable filterShouldRead(Iterable exprs) { + return toCollection(Iterables.filter(exprs, sShouldReadPred)); } - public Iterable filterCanBeReadNow(Iterable exprs) { - return Iterables.filter(exprs, sReadNowPred); + public static List toCollection(Iterable iterable) { + return Arrays.asList(Iterables.toArray(iterable, Expr.class)); } private static final Predicate sShouldReadPred = new Predicate() { diff --git a/tools/data-binding/compiler/src/main/kotlin/android/databinding/tool/writer/LayoutBinderWriter.kt b/tools/data-binding/compiler/src/main/kotlin/android/databinding/tool/writer/LayoutBinderWriter.kt index 228e759..763c94b 100644 --- a/tools/data-binding/compiler/src/main/kotlin/android/databinding/tool/writer/LayoutBinderWriter.kt +++ b/tools/data-binding/compiler/src/main/kotlin/android/databinding/tool/writer/LayoutBinderWriter.kt @@ -679,7 +679,7 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { } do { - val batch = model.filterShouldRead(model.getPendingExpressions()).toArrayList() + val batch = ExprModel.filterShouldRead(model.getPendingExpressions()).toArrayList() val mJustRead = arrayListOf() while (!batch.none()) { val readNow = batch.filter { it.shouldReadNow(mJustRead) } @@ -758,8 +758,7 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { // create an if case for all dependencies that might be null val nullables = expr.getDependencies().filter { it.isMandatory() && it.getOther().getResolvedType().isNullable() - } - .map { it.getOther() } + }.map { it.getOther() } if (!expr.isEqualityCheck() && nullables.isNotEmpty()) { tab ("if ( ${nullables.map { "${it.localName} != null" }.joinToString(" && ")}) {") { tab("${expr.localName}").app(" = ", expr.toCode(true)).app(";") diff --git a/tools/data-binding/compiler/src/test/java/android/databinding/tool/expr/ExprModelTest.java b/tools/data-binding/compiler/src/test/java/android/databinding/tool/expr/ExprModelTest.java index ed9934d..7bccd6e 100644 --- a/tools/data-binding/compiler/src/test/java/android/databinding/tool/expr/ExprModelTest.java +++ b/tools/data-binding/compiler/src/test/java/android/databinding/tool/expr/ExprModelTest.java @@ -34,6 +34,8 @@ import android.databinding.tool.reflection.ModelClass; import android.databinding.tool.reflection.java.JavaAnalyzer; import android.databinding.tool.util.L; +import java.util.ArrayList; +import java.util.Arrays; import java.util.BitSet; import java.util.List; @@ -45,8 +47,11 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; public class ExprModelTest { + private static class DummyExpr extends Expr { + String mKey; + public DummyExpr(String key, DummyExpr... children) { super(children); mKey = key; @@ -76,7 +81,7 @@ public class ExprModelTest { protected void failed(Throwable e, Description description) { if (mExprModel != null && mExprModel.getFlagMapping() != null) { final String[] mapping = mExprModel.getFlagMapping(); - for (int i = 0; i < mapping.length; i ++) { + for (int i = 0; i < mapping.length; i++) { L.d("flag %d: %s", i, mapping[i]); } } @@ -96,6 +101,7 @@ public class ExprModelTest { assertSame(d, mExprModel.register(d)); assertEquals(1, mExprModel.mExprMap.size()); } + @Test public void testAddDupe1() { final DummyExpr d = new DummyExpr("a"); @@ -131,8 +137,8 @@ public class ExprModelTest { IdentifierExpr a = lb.addVariable("a", "java.lang.String"); IdentifierExpr b = lb.addVariable("b", "java.lang.String"); IdentifierExpr c = lb.addVariable("c", "java.lang.String"); - final Expr ternary = lb.parse("a == null ? b : c"); - final Expr equality = mExprModel.comparison("==", a, mExprModel.symbol("null", Object.class)); + lb.parse("a == null ? b : c"); + mExprModel.comparison("==", a, mExprModel.symbol("null", Object.class)); lb.getModel().seal(); Iterable shouldRead = getShouldRead(); // a and a == null @@ -147,6 +153,59 @@ public class ExprModelTest { } @Test + public void testTernaryWithPlus() { + LayoutBinder lb = new MockLayoutBinder(); + mExprModel = lb.getModel(); + IdentifierExpr user = lb + .addVariable("user", "android.databinding.tool.expr.ExprModelTest.User"); + MathExpr parsed = parse(lb, "user.name + \" \" + (user.lastName ?? \"\")", MathExpr.class); + mExprModel.seal(); + Iterable toRead = getShouldRead(); + Iterable readNow = getReadFirst(toRead); + assertEquals(1, Iterables.size(readNow)); + assertSame(user, Iterables.getFirst(readNow, null)); + List justRead = new ArrayList(); + justRead.add(user); + readNow = filterOut(getReadFirst(toRead, justRead), justRead); + assertEquals(2, Iterables.size(readNow)); //user.name && user.lastName + Iterables.addAll(justRead, readNow); + // user.lastname (T, F), user.name + " " + readNow = filterOut(getReadFirst(toRead, justRead), justRead); + assertEquals(2, Iterables.size(readNow)); //user.name && user.lastName + Iterables.addAll(justRead, readNow); + readNow = filterOut(getReadFirst(toRead, justRead), justRead); + assertEquals(0, Iterables.size(readNow)); + mExprModel.markBitsRead(); + + toRead = getShouldRead(); + assertEquals(2, Iterables.size(toRead)); + justRead.clear(); + readNow = filterOut(getReadFirst(toRead, justRead), justRead); + assertEquals(1, Iterables.size(readNow)); + assertSame(parsed.getRight(), Iterables.getFirst(readNow, null)); + Iterables.addAll(justRead, readNow); + + readNow = filterOut(getReadFirst(toRead, justRead), justRead); + assertEquals(1, Iterables.size(readNow)); + assertSame(parsed, Iterables.getFirst(readNow, null)); + Iterables.addAll(justRead, readNow); + + readNow = filterOut(getReadFirst(toRead, justRead), justRead); + assertEquals(0, Iterables.size(readNow)); + mExprModel.markBitsRead(); + assertEquals(0, Iterables.size(getShouldRead())); + } + + private List filterOut(Iterable itr, final Iterable exclude) { + return Arrays.asList(Iterables.toArray(Iterables.filter(itr, new Predicate() { + @Override + public boolean apply(Object input) { + return !Iterables.contains(exclude, input); + } + }), Expr.class)); + } + + @Test public void testTernaryInsideTernary() { LayoutBinder lb = new MockLayoutBinder(); mExprModel = lb.getModel(); @@ -202,10 +261,12 @@ public class ExprModelTest { IdentifierExpr e = lb.addVariable("e", "java.lang.String"); final Expr aTernary = lb.parse("a == null ? b == null ? c : d : e"); assertTrue(aTernary instanceof TernaryExpr); - final Expr bTernary = ((TernaryExpr)aTernary).getIfTrue(); + final Expr bTernary = ((TernaryExpr) aTernary).getIfTrue(); assertTrue(bTernary instanceof TernaryExpr); - final Expr aIsNull = mExprModel.comparison("==", a, mExprModel.symbol("null", Object.class)); - final Expr bIsNull = mExprModel.comparison("==", b, mExprModel.symbol("null", Object.class)); + final Expr aIsNull = mExprModel + .comparison("==", a, mExprModel.symbol("null", Object.class)); + final Expr bIsNull = mExprModel + .comparison("==", b, mExprModel.symbol("null", Object.class)); lb.getModel().seal(); Iterable shouldRead = getShouldRead(); // a and a == null @@ -217,7 +278,6 @@ public class ExprModelTest { assertTrue(d.getShouldReadFlags().isEmpty()); assertTrue(e.getShouldReadFlags().isEmpty()); - Iterable readFirst = getReadFirst(shouldRead, null); assertEquals(1, Iterables.size(readFirst)); final Expr first = Iterables.getFirst(readFirst, null); @@ -267,7 +327,6 @@ public class ExprModelTest { LayoutBinder lb = new MockLayoutBinder(); mExprModel = lb.getModel(); - IdentifierExpr u1 = lb.addVariable("u1", User.class.getCanonicalName()); IdentifierExpr u2 = lb.addVariable("u2", User.class.getCanonicalName()); IdentifierExpr a = lb.addVariable("a", int.class.getCanonicalName()); @@ -276,7 +335,8 @@ public class ExprModelTest { IdentifierExpr d = lb.addVariable("d", int.class.getCanonicalName()); IdentifierExpr e = lb.addVariable("e", int.class.getCanonicalName()); TernaryExpr abTernary = parse(lb, "a > b ? u1.name : u2.name", TernaryExpr.class); - TernaryExpr bcTernary = parse(lb, "b > c ? u1.getCond(d) ? u1.lastName : u2.lastName : `xx` + u2.getCond(e) ", TernaryExpr.class); + TernaryExpr bcTernary = parse(lb, "b > c ? u1.getCond(d) ? u1.lastName : u2.lastName : `xx`" + + " + u2.getCond(e) ", TernaryExpr.class); Expr abCmp = abTernary.getPred(); Expr bcCmp = bcTernary.getPred(); Expr u1GetCondD = ((TernaryExpr) bcTernary.getIfTrue()).getPred(); @@ -287,7 +347,6 @@ public class ExprModelTest { Expr u1LastName = ((TernaryExpr) bcTernary.getIfTrue()).getIfTrue(); Expr u2LastName = ((TernaryExpr) bcTernary.getIfTrue()).getIfFalse(); - mExprModel.seal(); Iterable shouldRead = getShouldRead(); @@ -314,8 +373,10 @@ public class ExprModelTest { assertFlags(d, bcTernary.getRequirementFlagIndex(true)); assertFlags(e, bcTernary.getRequirementFlagIndex(false)); - assertFlags(u1, bcTernary.getRequirementFlagIndex(true), abTernary.getRequirementFlagIndex(true)); - assertFlags(u2, bcTernary.getRequirementFlagIndex(false), abTernary.getRequirementFlagIndex(false)); + assertFlags(u1, bcTernary.getRequirementFlagIndex(true), + abTernary.getRequirementFlagIndex(true)); + assertFlags(u2, bcTernary.getRequirementFlagIndex(false), + abTernary.getRequirementFlagIndex(false)); assertFlags(u1GetCondD, bcTernary.getRequirementFlagIndex(true)); assertFlags(u2GetCondE, bcTernary.getRequirementFlagIndex(false)); @@ -342,8 +403,6 @@ public class ExprModelTest { assertFlags(bcTernary, b, c, u1, u2, d, u1LastName, u2LastName, e); } - - @Test public void testCircularDependency() { LayoutBinder lb = new MockLayoutBinder(); @@ -442,11 +501,13 @@ public class ExprModelTest { int i = 0; log("list", iterable); for (Expr expr : exprs) { - assertTrue((i++) + ":must contain " + expr.getUniqueKey(), Iterables.contains(iterable, expr)); + assertTrue((i++) + ":must contain " + expr.getUniqueKey(), + Iterables.contains(iterable, expr)); } i = 0; for (Expr expr : iterable) { - assertTrue((i++) + ":must be expected " + expr.getUniqueKey(), ArrayUtils.contains(exprs, expr)); + assertTrue((i++) + ":must be expected " + expr.getUniqueKey(), + ArrayUtils.contains(exprs, expr)); } } @@ -459,18 +520,16 @@ public class ExprModelTest { private void log(String s, Iterable iterable) { L.d(s); for (Expr e : iterable) { - L.d(": %s : %s allFlags: %s readSoFar: %s", e.getUniqueKey(), e.getShouldReadFlags(), e.getShouldReadFlagsWithConditionals(), e.getReadSoFar()); + L.d(": %s : %s allFlags: %s readSoFar: %s", e.getUniqueKey(), e.getShouldReadFlags(), + e.getShouldReadFlagsWithConditionals(), e.getReadSoFar()); } L.d("end of %s", s); } -// private Iterable getReadFirst(Iterable shouldRead) { -// return mExprModel.filterCanBeReadNow(shouldRead); -// } - private Iterable getReadFirst(Iterable shouldRead) { return getReadFirst(shouldRead, null); } + private Iterable getReadFirst(Iterable shouldRead, final Iterable justRead) { return Iterables.filter(shouldRead, new Predicate() { @Override @@ -485,7 +544,9 @@ public class ExprModelTest { } public static class User { + String name; + String lastName; public String getName() { diff --git a/tools/data-binding/grammarBuilder/src/test/java/android/databinding/BindingExpressionParserTest.java b/tools/data-binding/grammarBuilder/src/test/java/android/databinding/BindingExpressionParserTest.java index 31f041f..9197ccf 100644 --- a/tools/data-binding/grammarBuilder/src/test/java/android/databinding/BindingExpressionParserTest.java +++ b/tools/data-binding/grammarBuilder/src/test/java/android/databinding/BindingExpressionParserTest.java @@ -1,23 +1,25 @@ package android.databinding; -import android.databinding.BindingExpressionParser.AndOrOpContext; -import android.databinding.BindingExpressionParser.BinaryOpContext; -import android.databinding.BindingExpressionParser.BindingSyntaxContext; -import android.databinding.BindingExpressionParser.BitShiftOpContext; -import android.databinding.BindingExpressionParser.ComparisonOpContext; -import android.databinding.BindingExpressionParser.DefaultsContext; -import android.databinding.BindingExpressionParser.DotOpContext; -import android.databinding.BindingExpressionParser.ExpressionContext; -import android.databinding.BindingExpressionParser.GroupingContext; -import android.databinding.BindingExpressionParser.LiteralContext; -import android.databinding.BindingExpressionParser.MathOpContext; -import android.databinding.BindingExpressionParser.PrimaryContext; -import android.databinding.BindingExpressionParser.PrimitiveTypeContext; -import android.databinding.BindingExpressionParser.QuestionQuestionOpContext; -import android.databinding.BindingExpressionParser.ResourceContext; -import android.databinding.BindingExpressionParser.StringLiteralContext; -import android.databinding.BindingExpressionParser.TernaryOpContext; -import android.databinding.BindingExpressionParser.UnaryOpContext; +import android.databinding.parser.BindingExpressionLexer; +import android.databinding.parser.BindingExpressionParser; +import android.databinding.parser.BindingExpressionParser.AndOrOpContext; +import android.databinding.parser.BindingExpressionParser.BinaryOpContext; +import android.databinding.parser.BindingExpressionParser.BindingSyntaxContext; +import android.databinding.parser.BindingExpressionParser.BitShiftOpContext; +import android.databinding.parser.BindingExpressionParser.ComparisonOpContext; +import android.databinding.parser.BindingExpressionParser.DefaultsContext; +import android.databinding.parser.BindingExpressionParser.DotOpContext; +import android.databinding.parser.BindingExpressionParser.ExpressionContext; +import android.databinding.parser.BindingExpressionParser.GroupingContext; +import android.databinding.parser.BindingExpressionParser.LiteralContext; +import android.databinding.parser.BindingExpressionParser.MathOpContext; +import android.databinding.parser.BindingExpressionParser.PrimaryContext; +import android.databinding.parser.BindingExpressionParser.PrimitiveTypeContext; +import android.databinding.parser.BindingExpressionParser.QuestionQuestionOpContext; +import android.databinding.parser.BindingExpressionParser.ResourceContext; +import android.databinding.parser.BindingExpressionParser.StringLiteralContext; +import android.databinding.parser.BindingExpressionParser.TernaryOpContext; +import android.databinding.parser.BindingExpressionParser.UnaryOpContext; import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.CommonTokenStream; diff --git a/tools/data-binding/integration-tests/TestApp/app/src/androidTest/java/android/databinding/testapp/InnerCannotReadDependencyTest.java b/tools/data-binding/integration-tests/TestApp/app/src/androidTest/java/android/databinding/testapp/InnerCannotReadDependencyTest.java new file mode 100644 index 0000000..68cf06b --- /dev/null +++ b/tools/data-binding/integration-tests/TestApp/app/src/androidTest/java/android/databinding/testapp/InnerCannotReadDependencyTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.databinding.testapp; + +import android.databinding.testapp.databinding.InnerCannotReadDependencyBinding; +import android.databinding.testapp.vo.BasicObject; +import android.os.Debug; +import android.test.UiThreadTest; + +import org.junit.Test; + +public class InnerCannotReadDependencyTest extends + BaseDataBinderTest { + + public InnerCannotReadDependencyTest() { + super(InnerCannotReadDependencyBinding.class); + } + + @UiThreadTest + public void testBinding() { + BasicObject object = new BasicObject(); + object.setField1("a"); + mBinder.setObj(object); + mBinder.executePendingBindings(); + assertEquals("a ", mBinder.textView.getText().toString()); + object.setField1(null); + mBinder.executePendingBindings(); + assertEquals("null ", mBinder.textView.getText().toString()); + object.setField2("b"); + mBinder.executePendingBindings(); + assertEquals("null b", mBinder.textView.getText().toString()); + object.setField1("c"); + mBinder.executePendingBindings(); + assertEquals("c b", mBinder.textView.getText().toString()); + } +} diff --git a/tools/data-binding/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/BasicObject.java b/tools/data-binding/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/BasicObject.java new file mode 100644 index 0000000..450f7fb --- /dev/null +++ b/tools/data-binding/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/BasicObject.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.databinding.testapp.vo; +import android.databinding.BaseObservable; +import android.databinding.Bindable; +import android.databinding.testapp.BR; + +public class BasicObject extends BaseObservable { + @Bindable + private String mField1; + @Bindable + private String mField2; + + public String getField1() { + return mField1; + } + + public void setField1(String field1) { + this.mField1 = field1; + notifyPropertyChanged(BR.field1); + } + + public String getField2() { + return mField2; + } + + public void setField2(String field2) { + this.mField2 = field2; + notifyPropertyChanged(BR.field1); + } +} diff --git a/tools/data-binding/integration-tests/TestApp/app/src/main/res/layout/find_method_test.xml b/tools/data-binding/integration-tests/TestApp/app/src/main/res/layout/find_method_test.xml index c65ee39..33a3746 100644 --- a/tools/data-binding/integration-tests/TestApp/app/src/main/res/layout/find_method_test.xml +++ b/tools/data-binding/integration-tests/TestApp/app/src/main/res/layout/find_method_test.xml @@ -15,11 +15,11 @@ + android:text="@{obj.method(1.25f)}"/> + android:text="@{obj.method(`hello`)}"/> + + + + \ No newline at end of file -- cgit v1.1