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 17 package android.databinding.tool.expr; 18 19 import android.databinding.tool.processing.Scope; 20 import android.databinding.tool.reflection.Callable; 21 import android.databinding.tool.reflection.Callable.Type; 22 import android.databinding.tool.reflection.ModelAnalyzer; 23 import android.databinding.tool.reflection.ModelClass; 24 import android.databinding.tool.reflection.ModelMethod; 25 import android.databinding.tool.util.L; 26 27 import java.util.ArrayList; 28 import java.util.Arrays; 29 import java.util.List; 30 import static android.databinding.tool.reflection.Callable.STATIC; 31 import static android.databinding.tool.reflection.Callable.DYNAMIC; 32 import static android.databinding.tool.reflection.Callable.CAN_BE_INVALIDATED; 33 34 35 public 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<>(); 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 ModelClass resolveType(ModelAnalyzer modelAnalyzer) { 65 if (mGetter == null) { 66 List<ModelClass> args = new ArrayList<ModelClass>(); 67 for (Expr expr : getArgs()) { 68 args.add(expr.getResolvedType()); 69 } 70 71 Expr target = getTarget(); 72 boolean isStatic = target instanceof StaticIdentifierExpr; 73 ModelMethod method = target.getResolvedType().getMethod(mName, args, isStatic); 74 if (method == null) { 75 String message = "cannot find method '" + mName + "' in class " + 76 target.getResolvedType().toJavaCode(); 77 IllegalArgumentException e = new IllegalArgumentException(message); 78 L.e(e, "cannot find method %s in class %s", mName, 79 target.getResolvedType().toJavaCode()); 80 throw e; 81 } 82 if (!isStatic && method.isStatic()) { 83 // found a static method on an instance. Use class instead 84 target.getParents().remove(this); 85 getChildren().remove(target); 86 StaticIdentifierExpr staticId = getModel() 87 .staticIdentifierFor(target.getResolvedType()); 88 getChildren().add(staticId); 89 staticId.getParents().add(this); 90 // make sure we update this in case we access it below 91 target = getTarget(); 92 } 93 int flags = DYNAMIC; 94 if (method.isStatic()) { 95 flags |= STATIC; 96 } 97 mGetter = new Callable(Type.METHOD, method.getName(), method.getReturnType(args), flags); 98 } 99 return mGetter.resolvedType; 100 } 101 102 @Override 103 protected List<Dependency> constructDependencies() { 104 final List<Dependency> dependencies = constructDynamicChildrenDependencies(); 105 for (Dependency dependency : dependencies) { 106 if (dependency.getOther() == getTarget()) { 107 dependency.setMandatory(true); 108 } 109 } 110 return dependencies; 111 } 112 113 @Override 114 protected String computeUniqueKey() { 115 return join(getTarget().computeUniqueKey(), mName, 116 super.computeUniqueKey()); 117 } 118 119 public Expr getTarget() { 120 return getChildren().get(0); 121 } 122 123 public String getName() { 124 return mName; 125 } 126 127 public List<Expr> getArgs() { 128 return getChildren().subList(1, getChildren().size()); 129 } 130 131 public Callable getGetter() { 132 return mGetter; 133 } 134 } 135