Fix broken static import with alias.
Added tests to ensure they don't break again.
This commit is contained in:
@@ -71,4 +71,24 @@ public class FindMethodTest
|
||||
TextView textView = mBinder.getTextView8();
|
||||
assertEquals("hello world", textView.getText().toString());
|
||||
}
|
||||
|
||||
public void testImportStaticMethod() throws Throwable {
|
||||
TextView textView = mBinder.getTextView9();
|
||||
assertEquals("world", textView.getText().toString());
|
||||
}
|
||||
|
||||
public void testImportStaticField() throws Throwable {
|
||||
TextView textView = mBinder.getTextView10();
|
||||
assertEquals("hello world", textView.getText().toString());
|
||||
}
|
||||
|
||||
public void testAliasStaticMethod() throws Throwable {
|
||||
TextView textView = mBinder.getTextView11();
|
||||
assertEquals("world", textView.getText().toString());
|
||||
}
|
||||
|
||||
public void testAliasStaticField() throws Throwable {
|
||||
TextView textView = mBinder.getTextView12();
|
||||
assertEquals("hello world", textView.getText().toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<variable name="obj" type="com.android.databinding.testapp.vo.FindMethodBindingObject"/>
|
||||
<!--
|
||||
<import name="FMBO" type=""/>
|
||||
-->
|
||||
<import type="com.android.databinding.testapp.vo.FindMethodBindingObject"/>
|
||||
<import type="com.android.databinding.testapp.vo.FindMethodBindingObject" alias="FMBO"/>
|
||||
<TextView
|
||||
android:id="@+id/textView0"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
@@ -43,4 +42,29 @@
|
||||
android:id="@+id/textView8"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:text="@{com.android.databinding.testapp.vo.FindMethodBindingObject.foo.bar}"/>
|
||||
<TextView
|
||||
android:id="@+id/textView9"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:text="@{FindMethodBindingObject.staticMethod()}"/>
|
||||
<TextView
|
||||
android:id="@+id/textView10"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:text="@{FindMethodBindingObject.foo.bar}"/>
|
||||
<TextView
|
||||
android:id="@+id/textView11"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:text="@{FMBO.staticMethod()}"/>
|
||||
<TextView
|
||||
android:id="@+id/textView12"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:text="@{FMBO.foo.bar}"/>
|
||||
<!-- The following are just to test duplicate expressions -->
|
||||
<TextView
|
||||
android:id="@+id/textView13"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:text="@{FMBO.staticMethod()}"/>
|
||||
<TextView
|
||||
android:id="@+id/textView14"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:text="@{FMBO.foo.bar}"/>
|
||||
</LinearLayout>
|
||||
@@ -575,17 +575,18 @@ abstract public class Expr {
|
||||
}
|
||||
}
|
||||
|
||||
protected void replaceStaticAccess(ModelAnalyzer modelAnalyzer) {
|
||||
protected void replaceStaticIdentifiers(ModelAnalyzer modelAnalyzer) {
|
||||
for (int i = 0; i < mChildren.size(); i++) {
|
||||
Expr child = mChildren.get(i);
|
||||
String packageName = child.asPackage();
|
||||
if (packageName != null) {
|
||||
ModelClass modelClass = modelAnalyzer.findClass(packageName);
|
||||
if (modelClass != null) {
|
||||
Expr staticAccessExpr = getModel().staticAccessExpr(modelClass);
|
||||
child.removeParentAndUnregisterIfOrphan(this);
|
||||
StaticIdentifierExpr staticAccessExpr = getModel().staticIdentifier(packageName);
|
||||
staticAccessExpr.setUserDefinedType(packageName);
|
||||
staticAccessExpr.getParents().add(this);
|
||||
mChildren.set(i, staticAccessExpr);
|
||||
child.removeParentAndUnregisterIfOrphan(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -595,11 +596,11 @@ abstract public class Expr {
|
||||
while (mParents.remove(parent)) {
|
||||
}
|
||||
if (getParents().isEmpty()) {
|
||||
getModel().unregister(this);
|
||||
for (Expr expr : mChildren) {
|
||||
expr.removeParentAndUnregisterIfOrphan(this);
|
||||
}
|
||||
mChildren.clear();
|
||||
getModel().unregister(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -146,10 +146,6 @@ public class ExprModel {
|
||||
return register(new BracketExpr(variableExpr, argExpr));
|
||||
}
|
||||
|
||||
public Expr staticAccessExpr(ModelClass modelClass) {
|
||||
return register(new StaticAccessExpr(modelClass));
|
||||
}
|
||||
|
||||
public Expr castExpr(String type, Expr expr) {
|
||||
return register(new CastExpr(type, expr));
|
||||
}
|
||||
@@ -166,7 +162,9 @@ public class ExprModel {
|
||||
public Expr bindingExpr(Expr bindingExpr) {
|
||||
Preconditions.checkArgument(mExprMap.containsKey(bindingExpr.getUniqueKey()),
|
||||
"Main expression should already be registered");
|
||||
mBindingExpressions.add(bindingExpr);
|
||||
if (!mBindingExpressions.contains(bindingExpr)) {
|
||||
mBindingExpressions.add(bindingExpr);
|
||||
}
|
||||
return bindingExpr;
|
||||
}
|
||||
|
||||
@@ -257,6 +255,9 @@ public class ExprModel {
|
||||
}
|
||||
|
||||
// non-dynamic binding expressions receive some ids so that they can be invalidated
|
||||
for (int i = 0; i < mBindingExpressions.size(); i++) {
|
||||
L.d("[" + i + "] " + mBindingExpressions.get(i));
|
||||
}
|
||||
for (Expr expr : mBindingExpressions) {
|
||||
if (!(expr.isDynamic() || !expr.hasId())) {
|
||||
L.d("Expr " + expr + " is dynamic? " + expr.isDynamic() + ", has ID? " + expr.hasId());
|
||||
@@ -348,7 +349,7 @@ public class ExprModel {
|
||||
public boolean apply(Expr input) {
|
||||
return input instanceof IdentifierExpr
|
||||
&& !input.hasId()
|
||||
&& !modelAnalyzer.isObservable(input.getResolvedType())
|
||||
&& !input.isObservable()
|
||||
&& input.isDynamic();
|
||||
}
|
||||
});
|
||||
@@ -358,7 +359,7 @@ public class ExprModel {
|
||||
return Iterables.filter(mExprMap.values(), new Predicate<Expr>() {
|
||||
@Override
|
||||
public boolean apply(Expr input) {
|
||||
return modelAnalyzer.isObservable(input.getResolvedType());
|
||||
return input.isObservable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class FieldAccessExpr extends Expr {
|
||||
mIsObservableField = isObservableField;
|
||||
}
|
||||
|
||||
public Expr getParent() {
|
||||
public Expr getChild() {
|
||||
return getChildren().get(0);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class FieldAccessExpr extends Expr {
|
||||
|
||||
@Override
|
||||
public boolean isDynamic() {
|
||||
if (!getParent().isDynamic()) {
|
||||
if (!getChild().isDynamic()) {
|
||||
return false;
|
||||
}
|
||||
if (mGetter == null) {
|
||||
@@ -66,7 +66,7 @@ public class FieldAccessExpr extends Expr {
|
||||
protected List<Dependency> constructDependencies() {
|
||||
final List<Dependency> dependencies = constructDynamicChildrenDependencies();
|
||||
for (Dependency dependency : dependencies) {
|
||||
if (dependency.getOther() == getParent()) {
|
||||
if (dependency.getOther() == getChild()) {
|
||||
dependency.setMandatory(true);
|
||||
}
|
||||
}
|
||||
@@ -94,16 +94,17 @@ public class FieldAccessExpr extends Expr {
|
||||
@Override
|
||||
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
if (mGetter == null) {
|
||||
replaceStaticAccess(modelAnalyzer);
|
||||
Expr parent = getParent();
|
||||
boolean isStatic = parent instanceof StaticAccessExpr;
|
||||
mGetter = modelAnalyzer.findMethodOrField(parent.getResolvedType(), mName, isStatic);
|
||||
replaceStaticIdentifiers(modelAnalyzer);
|
||||
Expr child = getChild();
|
||||
child.resolveType(modelAnalyzer);
|
||||
boolean isStatic = child instanceof StaticIdentifierExpr;
|
||||
mGetter = modelAnalyzer.findMethodOrField(child.getResolvedType(), mName, isStatic);
|
||||
if (modelAnalyzer.isObservableField(mGetter.resolvedType)) {
|
||||
// Make this the ".get()" and add an extra field access for the observable field
|
||||
parent.getParents().remove(this);
|
||||
getChildren().remove(parent);
|
||||
child.getParents().remove(this);
|
||||
getChildren().remove(child);
|
||||
|
||||
FieldAccessExpr observableField = getModel().observableField(parent, mName);
|
||||
FieldAccessExpr observableField = getModel().observableField(child, mName);
|
||||
observableField.mGetter = mGetter;
|
||||
|
||||
getChildren().add(observableField);
|
||||
@@ -117,7 +118,7 @@ public class FieldAccessExpr extends Expr {
|
||||
|
||||
@Override
|
||||
protected String asPackage() {
|
||||
String parentPackage = getParent().asPackage();
|
||||
String parentPackage = getChild().asPackage();
|
||||
return parentPackage == null ? null : parentPackage + "." + mName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,14 +45,14 @@ public class MethodCallExpr extends Expr {
|
||||
@Override
|
||||
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
if (mGetter == null) {
|
||||
replaceStaticAccess(modelAnalyzer);
|
||||
replaceStaticIdentifiers(modelAnalyzer);
|
||||
List<ModelClass> args = new ArrayList<>();
|
||||
for (Expr expr : getArgs()) {
|
||||
args.add(expr.getResolvedType());
|
||||
}
|
||||
|
||||
Expr target = getTarget();
|
||||
boolean isStatic = target instanceof StaticAccessExpr;
|
||||
boolean isStatic = target instanceof StaticIdentifierExpr;
|
||||
mGetter = modelAnalyzer.findMethod(target.getResolvedType(), mName, args, isStatic);
|
||||
}
|
||||
return mGetter.resolvedType;
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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 com.android.databinding.expr;
|
||||
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class StaticAccessExpr extends Expr {
|
||||
private ModelClass mStaticClass;
|
||||
|
||||
public StaticAccessExpr(ModelClass modelClass) {
|
||||
mStaticClass = modelClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
return mStaticClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Dependency> constructDependencies() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
protected String computeUniqueKey() {
|
||||
return mStaticClass.toJavaCode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,6 +22,11 @@ public class StaticIdentifierExpr extends IdentifierExpr {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isObservable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDynamic() {
|
||||
return false;
|
||||
|
||||
@@ -46,7 +46,6 @@ import com.android.databinding.expr.ResourceExpr
|
||||
import com.android.databinding.expr.BracketExpr
|
||||
import com.android.databinding.reflection.Callable
|
||||
import com.android.databinding.expr.CastExpr
|
||||
import com.android.databinding.expr.StaticAccessExpr
|
||||
|
||||
fun String.stripNonJava() = this.split("[^a-zA-Z0-9]").map{ it.trim() }.joinToCamelCaseAsVar()
|
||||
|
||||
@@ -161,7 +160,7 @@ fun Expr.toCode(full : Boolean = false) : KCode {
|
||||
app("", it.getRight().toCode())
|
||||
}
|
||||
is FieldAccessExpr -> kcode("") {
|
||||
app("", it.getParent().toCode())
|
||||
app("", it.getChild().toCode())
|
||||
if (it.getGetter().type == Callable.Type.FIELD) {
|
||||
app(".", it.getGetter().name)
|
||||
} else {
|
||||
@@ -222,9 +221,6 @@ fun Expr.toCode(full : Boolean = false) : KCode {
|
||||
app("(", it.getCastType())
|
||||
app(") ", it.getCastExpr().toCode())
|
||||
}
|
||||
is StaticAccessExpr -> kcode("") {
|
||||
app("", it.getResolvedType().toJavaCode())
|
||||
}
|
||||
else -> kcode("//NOT IMPLEMENTED YET")
|
||||
}
|
||||
|
||||
|
||||
@@ -139,8 +139,8 @@ public class ExpressionVisitorTest {
|
||||
@Test
|
||||
public void testInheritedFieldResolution() {
|
||||
final FieldAccessExpr parsed = parse("myStr.length", FieldAccessExpr.class);
|
||||
assertTrue(parsed.getParent() instanceof IdentifierExpr);
|
||||
final IdentifierExpr id = (IdentifierExpr) parsed.getParent();
|
||||
assertTrue(parsed.getChild() instanceof IdentifierExpr);
|
||||
final IdentifierExpr id = (IdentifierExpr) parsed.getChild();
|
||||
id.setUserDefinedType("java.lang.String");
|
||||
assertSame(int.class, parsed.getResolvedType());
|
||||
Callable getter = parsed.getGetter();
|
||||
@@ -155,8 +155,8 @@ public class ExpressionVisitorTest {
|
||||
@Test
|
||||
public void testGetterResolution() {
|
||||
final FieldAccessExpr parsed = parse("myStr.bytes", FieldAccessExpr.class);
|
||||
assertTrue(parsed.getParent() instanceof IdentifierExpr);
|
||||
final IdentifierExpr id = (IdentifierExpr) parsed.getParent();
|
||||
assertTrue(parsed.getChild() instanceof IdentifierExpr);
|
||||
final IdentifierExpr id = (IdentifierExpr) parsed.getChild();
|
||||
id.setUserDefinedType("java.lang.String");
|
||||
assertSame(byte[].class, parsed.getResolvedType());
|
||||
Callable getter = parsed.getGetter();
|
||||
|
||||
@@ -93,7 +93,7 @@ public class LayoutBinderTest {
|
||||
fa.getResolvedType();
|
||||
final Callable getter = fa.getGetter();
|
||||
assertTrue(getter.type == Callable.Type.METHOD);
|
||||
assertSame(id, fa.getParent());
|
||||
assertSame(id, fa.getChild());
|
||||
assertTrue(fa.isDynamic());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user