MethodCallExpr.java revision d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01
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