summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYigit Boyar <yboyar@google.com>2015-03-27 14:10:13 -0700
committerYigit Boyar <yboyar@google.com>2015-04-03 10:00:25 -0700
commit3695b1aae95b289302cbbf9c38f0bd595bfc6ccb (patch)
tree5610ea4d6614ad592737ecd7d9de4ca9fa93bec3
parent53a6b1bde897f8a837cdf628201d8341aecb3a61 (diff)
downloadframeworks_base-3695b1aae95b289302cbbf9c38f0bd595bfc6ccb.zip
frameworks_base-3695b1aae95b289302cbbf9c38f0bd595bfc6ccb.tar.gz
frameworks_base-3695b1aae95b289302cbbf9c38f0bd595bfc6ccb.tar.bz2
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
-rw-r--r--tools/data-binding/compiler/src/main/java/android/databinding/tool/ExpressionVisitor.java2
-rw-r--r--tools/data-binding/compiler/src/main/java/android/databinding/tool/expr/Expr.java16
-rw-r--r--tools/data-binding/compiler/src/main/java/android/databinding/tool/expr/ExprModel.java9
-rw-r--r--tools/data-binding/compiler/src/main/kotlin/android/databinding/tool/writer/LayoutBinderWriter.kt5
-rw-r--r--tools/data-binding/compiler/src/test/java/android/databinding/tool/expr/ExprModelTest.java103
-rw-r--r--tools/data-binding/grammarBuilder/src/test/java/android/databinding/BindingExpressionParserTest.java38
-rw-r--r--tools/data-binding/integration-tests/TestApp/app/src/androidTest/java/android/databinding/testapp/InnerCannotReadDependencyTest.java49
-rw-r--r--tools/data-binding/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/BasicObject.java45
-rw-r--r--tools/data-binding/integration-tests/TestApp/app/src/main/res/layout/find_method_test.xml4
-rw-r--r--tools/data-binding/integration-tests/TestApp/app/src/main/res/layout/inner_cannot_read_dependency.xml11
10 files changed, 224 insertions, 58 deletions
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<Expr> {
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<Dependency> hasNestedCannotRead = new Predicate<Dependency>() {
@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<Expr> filterShouldRead(Iterable<Expr> exprs) {
- return Iterables.filter(exprs, sShouldReadPred);
+ public static Iterable<Expr> filterShouldRead(Iterable<Expr> exprs) {
+ return toCollection(Iterables.filter(exprs, sShouldReadPred));
}
- public Iterable<Expr> filterCanBeReadNow(Iterable<Expr> exprs) {
- return Iterables.filter(exprs, sReadNowPred);
+ public static List<Expr> toCollection(Iterable<Expr> iterable) {
+ return Arrays.asList(Iterables.toArray(iterable, Expr.class));
}
private static final Predicate<Expr> sShouldReadPred = new Predicate<Expr>() {
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<Expr>()
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<Expr> 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<Expr> toRead = getShouldRead();
+ Iterable<Expr> readNow = getReadFirst(toRead);
+ assertEquals(1, Iterables.size(readNow));
+ assertSame(user, Iterables.getFirst(readNow, null));
+ List<Expr> justRead = new ArrayList<Expr>();
+ 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<Expr> 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<Expr> shouldRead = getShouldRead();
// a and a == null
@@ -217,7 +278,6 @@ public class ExprModelTest {
assertTrue(d.getShouldReadFlags().isEmpty());
assertTrue(e.getShouldReadFlags().isEmpty());
-
Iterable<Expr> 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<Expr> 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<Expr> 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<Expr> getReadFirst(Iterable<Expr> shouldRead) {
-// return mExprModel.filterCanBeReadNow(shouldRead);
-// }
-
private Iterable<Expr> getReadFirst(Iterable<Expr> shouldRead) {
return getReadFirst(shouldRead, null);
}
+
private Iterable<Expr> getReadFirst(Iterable<Expr> shouldRead, final Iterable<Expr> justRead) {
return Iterables.filter(shouldRead, new Predicate<Expr>() {
@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<InnerCannotReadDependencyBinding> {
+
+ 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 @@
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content" android:layout_height="wrap_content"
- android:text="@{obj.method(1.25f}"/>
+ android:text="@{obj.method(1.25f)}"/>
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content" android:layout_height="wrap_content"
- android:text="@{obj.method(`hello`}"/>
+ android:text="@{obj.method(`hello`)}"/>
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content" android:layout_height="wrap_content"
diff --git a/tools/data-binding/integration-tests/TestApp/app/src/main/res/layout/inner_cannot_read_dependency.xml b/tools/data-binding/integration-tests/TestApp/app/src/main/res/layout/inner_cannot_read_dependency.xml
new file mode 100644
index 0000000..2ad1980
--- /dev/null
+++ b/tools/data-binding/integration-tests/TestApp/app/src/main/res/layout/inner_cannot_read_dependency.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical" android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <variable name="obj" type="android.databinding.testapp.vo.BasicObject"/>
+ <TextView
+ android:id="@+id/text_view"
+ android:text='@{obj.field1 + " " + (obj.field2 ?? "")}'
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+</LinearLayout> \ No newline at end of file