android.databinding.tool.expr.BracketExpr Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of compiler Show documentation
Show all versions of compiler Show documentation
The annotation processor for Data Binding. Generates binding classes for runtime.
The newest version!
/*
* 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.tool.expr;
import android.databinding.tool.reflection.ModelAnalyzer;
import android.databinding.tool.reflection.ModelClass;
import android.databinding.tool.solver.ExecutionPath;
import android.databinding.tool.writer.KCode;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.List;
public class BracketExpr extends Expr {
public enum BracketAccessor {
ARRAY,
LIST,
MAP,
}
private BracketAccessor mAccessor;
BracketExpr(Expr target, Expr arg) {
super(target, arg);
}
@Override
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
ModelClass targetType = getTarget().getResolvedType();
if (targetType.isArray()) {
mAccessor = BracketAccessor.ARRAY;
} else if (targetType.isList()) {
mAccessor = BracketAccessor.LIST;
} else if (targetType.isMap()) {
mAccessor = BracketAccessor.MAP;
} else {
throw new IllegalArgumentException("Cannot determine variable type used in [] " +
"expression. Cast the value to List, Map, " +
"or array. Type detected: " + targetType.toJavaCode());
}
return targetType.getComponentType();
}
@Override
public List toExecutionPath(List paths) {
final List targetPaths = getTarget().toExecutionPath(paths);
// after this, we need a null check.
List result = new ArrayList();
if (getTarget() instanceof StaticIdentifierExpr) {
result.addAll(toExecutionPathInOrder(paths, getTarget()));
} else {
for (ExecutionPath path : targetPaths) {
Expr cmp = getModel().comparison("!=", getTarget(),
getModel().symbol("null", Object.class));
cmp.setUnwrapObservableFields(false);
path.addPath(cmp);
final ExecutionPath subPath = path.addBranch(cmp, true);
if (subPath != null) {
final List argPath = getArg().toExecutionPath(subPath);
result.addAll(addJustMeToExecutionPath(argPath));
}
}
}
return result;
}
@Override
protected List constructDependencies() {
final List dependencies = constructDynamicChildrenDependencies();
for (Dependency dependency : dependencies) {
if (dependency.getOther() == getTarget()) {
dependency.setMandatory(true);
}
}
return dependencies;
}
protected String computeUniqueKey() {
return join(getTarget() + "[" + getArg() + "]");
}
@Override
public String getInvertibleError() {
return null;
}
public Expr getTarget() {
return getChildren().get(0);
}
public Expr getArg() {
return getChildren().get(1);
}
public BracketAccessor getAccessor() {
return mAccessor;
}
public boolean argCastsInteger() {
return mAccessor != BracketAccessor.MAP && getArg().getResolvedType().isObject();
}
@Override
public void injectSafeUnboxing(ModelAnalyzer modelAnalyzer, ExprModel model) {
Expr arg = getArg();
ModelClass resolvedType = arg.getResolvedType();
if (resolvedType.isNullable()) {
safeUnboxChild(model, arg);
}
}
@Override
protected KCode generateCode() {
String cast = argCastsInteger() ? "(Integer) " : "";
switch (getAccessor()) {
case ARRAY: {
return new KCode().
app("getFromArray(", getTarget().toCode()).
app(", ").
app(cast, getArg().toCode()).app(")");
}
case LIST: {
ModelClass listType = ModelAnalyzer.getInstance().findClass(java.util.List.class).
erasure();
ModelClass targetType = getTarget().getResolvedType().erasure();
if (listType.isAssignableFrom(targetType)) {
return new KCode().
app("getFromList(", getTarget().toCode()).
app(", ").
app(cast, getArg().toCode()).
app(")");
} else {
return new KCode().
app("", getTarget().toCode()).
app(".get(").
app(cast, getArg().toCode()).
app(")");
}
}
case MAP:
return new KCode().
app("", getTarget().toCode()).
app(".get(", getArg().toCode()).
app(")");
}
throw new IllegalStateException("Invalid BracketAccessor type");
}
@Override
public Expr generateInverse(ExprModel model, Expr value, String bindingClassName) {
Expr arg = getArg().cloneToModel(model);
arg = argCastsInteger()
? model.castExpr("int", model.castExpr("Integer", arg))
: arg;
StaticIdentifierExpr viewDataBinding =
model.staticIdentifier(ModelAnalyzer.VIEW_DATA_BINDING);
viewDataBinding.setUserDefinedType(ModelAnalyzer.VIEW_DATA_BINDING);
ModelClass targetType = getTarget().getResolvedType();
if ((targetType.isList() || targetType.isMap()) &&
value.getResolvedType().isPrimitive()) {
ModelClass boxed = value.getResolvedType().box();
value = model.castExpr(boxed.toJavaCode(), value);
}
List args = Lists.newArrayList(getTarget().cloneToModel(model), arg, value);
MethodCallExpr setter = model.methodCall(viewDataBinding, "setTo", args);
setter.setAllowProtected();
return setter;
}
@Override
public Expr cloneToModel(ExprModel model) {
return model.bracketExpr(getTarget().cloneToModel(model), getArg().cloneToModel(model));
}
@Override
public String toString() {
return getTarget().toString() + '[' + getArg() + ']';
}
}