1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.databinding.tool.expr; 18 19import static android.databinding.tool.reflection.Callable.DYNAMIC; 20import static android.databinding.tool.reflection.Callable.STATIC; 21 22import android.databinding.tool.processing.Scope; 23import android.databinding.tool.reflection.Callable; 24import android.databinding.tool.reflection.Callable.Type; 25import android.databinding.tool.reflection.ModelAnalyzer; 26import android.databinding.tool.reflection.ModelClass; 27import android.databinding.tool.reflection.ModelMethod; 28import android.databinding.tool.util.L; 29import android.databinding.tool.writer.KCode; 30 31import java.util.ArrayList; 32import java.util.List; 33 34 35public class MethodCallExpr extends Expr { 36 final String mName; 37 38 Callable mGetter; 39 40 static List<Expr> concat(Expr e, List<Expr> list) { 41 List<Expr> merged = new ArrayList<Expr>(); 42 merged.add(e); 43 merged.addAll(list); 44 return merged; 45 } 46 47 MethodCallExpr(Expr target, String name, List<Expr> args) { 48 super(concat(target, args)); 49 mName = name; 50 } 51 52 @Override 53 public void updateExpr(ModelAnalyzer modelAnalyzer) { 54 try { 55 Scope.enter(this); 56 resolveType(modelAnalyzer); 57 super.updateExpr(modelAnalyzer); 58 } finally { 59 Scope.exit(); 60 } 61 } 62 63 @Override 64 protected KCode generateCode(boolean expand) { 65 KCode code = new KCode() 66 .app("", getTarget().toCode(expand)) 67 .app(".") 68 .app(getGetter().name) 69 .app("("); 70 boolean first = true; 71 for (Expr arg : getArgs()) { 72 if (first) { 73 first = false; 74 } else { 75 code.app(", "); 76 } 77 code.app("", arg.toCode(expand)); 78 } 79 code.app(")"); 80 return code; 81 } 82 83 @Override 84 protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) { 85 if (mGetter == null) { 86 List<ModelClass> args = new ArrayList<ModelClass>(); 87 for (Expr expr : getArgs()) { 88 args.add(expr.getResolvedType()); 89 } 90 91 Expr target = getTarget(); 92 boolean isStatic = target instanceof StaticIdentifierExpr; 93 ModelMethod method = target.getResolvedType().getMethod(mName, args, isStatic); 94 if (method == null) { 95 String message = "cannot find method '" + mName + "' in class " + 96 target.getResolvedType().toJavaCode(); 97 IllegalArgumentException e = new IllegalArgumentException(message); 98 L.e(e, "cannot find method %s in class %s", mName, 99 target.getResolvedType().toJavaCode()); 100 throw e; 101 } 102 if (!isStatic && method.isStatic()) { 103 // found a static method on an instance. Use class instead 104 target.getParents().remove(this); 105 getChildren().remove(target); 106 StaticIdentifierExpr staticId = getModel() 107 .staticIdentifierFor(target.getResolvedType()); 108 getChildren().add(staticId); 109 staticId.getParents().add(this); 110 // make sure we update this in case we access it below 111 target = getTarget(); 112 } 113 int flags = DYNAMIC; 114 if (method.isStatic()) { 115 flags |= STATIC; 116 } 117 mGetter = new Callable(Type.METHOD, method.getName(), null, method.getReturnType(args), 118 method.getParameterTypes().length, flags); 119 } 120 return mGetter.resolvedType; 121 } 122 123 @Override 124 protected List<Dependency> constructDependencies() { 125 final List<Dependency> dependencies = constructDynamicChildrenDependencies(); 126 for (Dependency dependency : dependencies) { 127 if (dependency.getOther() == getTarget()) { 128 dependency.setMandatory(true); 129 } 130 } 131 return dependencies; 132 } 133 134 @Override 135 protected String computeUniqueKey() { 136 return join(getTarget().computeUniqueKey(), mName, 137 super.computeUniqueKey()); 138 } 139 140 public Expr getTarget() { 141 return getChildren().get(0); 142 } 143 144 public String getName() { 145 return mName; 146 } 147 148 public List<Expr> getArgs() { 149 return getChildren().subList(1, getChildren().size()); 150 } 151 152 public Callable getGetter() { 153 return mGetter; 154 } 155 156 @Override 157 public String getInvertibleError() { 158 return "Method calls may not be used in two-way expressions"; 159 } 160} 161