MethodCallExpr.java revision 2611838bffef5a009ca71e3e9e59a93f29b098ed
1d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar/*
2d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Copyright (C) 2015 The Android Open Source Project
3d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
4d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * you may not use this file except in compliance with the License.
6d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * You may obtain a copy of the License at
7d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
8d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
10d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * See the License for the specific language governing permissions and
14d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * limitations under the License.
15d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar */
16d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
17fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool.expr;
18d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
19fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.Callable;
20fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.Callable.Type;
21fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer;
22fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelClass;
23fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelMethod;
24fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.L;
25d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
26d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.ArrayList;
27d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.Arrays;
28d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.List;
29019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarimport static android.databinding.tool.reflection.Callable.STATIC;
30019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarimport static android.databinding.tool.reflection.Callable.DYNAMIC;
31019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarimport static android.databinding.tool.reflection.Callable.CAN_BE_INVALIDATED;
32019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
33d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
34d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarpublic class MethodCallExpr extends Expr {
35d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    final String mName;
36d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
37e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount    Callable mGetter;
38d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
392611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    static List<Expr> concat(Expr e, List<Expr> list) {
402611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> merged = new ArrayList<>();
412611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        merged.add(e);
422611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        merged.addAll(list);
432611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return merged;
442611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    }
452611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar
46d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    MethodCallExpr(Expr target, String name, List<Expr> args) {
472611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        super(concat(target, args));
48d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mName = name;
49d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
50d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
51d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Override
5218243f6f1b7527272ef4feccdf4327d80d9f2241George Mount    public void updateExpr(ModelAnalyzer modelAnalyzer) {
5318243f6f1b7527272ef4feccdf4327d80d9f2241George Mount        resolveType(modelAnalyzer);
5418243f6f1b7527272ef4feccdf4327d80d9f2241George Mount        super.updateExpr(modelAnalyzer);
5518243f6f1b7527272ef4feccdf4327d80d9f2241George Mount    }
5618243f6f1b7527272ef4feccdf4327d80d9f2241George Mount
5718243f6f1b7527272ef4feccdf4327d80d9f2241George Mount    @Override
5879fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount    protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
59d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mGetter == null) {
60895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar            List<ModelClass> args = new ArrayList<ModelClass>();
617920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount            for (Expr expr : getArgs()) {
62d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                args.add(expr.getResolvedType());
63d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
6418243f6f1b7527272ef4feccdf4327d80d9f2241George Mount
6518243f6f1b7527272ef4feccdf4327d80d9f2241George Mount            Expr target = getTarget();
66a70fed6415aa1e8bbbe929aee776402ac3b81c86George Mount            boolean isStatic = target instanceof StaticIdentifierExpr;
67fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            ModelMethod method = target.getResolvedType().getMethod(mName, args, isStatic);
68fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            if (method == null) {
69fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                String message = "cannot find method '" + mName + "' in class " +
70fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                        target.getResolvedType().toJavaCode();
71fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                IllegalArgumentException e = new IllegalArgumentException(message);
72fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                L.e(e, "cannot find method %s in class %s", mName,
73fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                        target.getResolvedType().toJavaCode());
74fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                throw e;
75fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            }
76ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            if (!isStatic && method.isStatic()) {
77ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                // found a static method on an instance. Use class instead
78ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                target.getParents().remove(this);
79ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                getChildren().remove(target);
80ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                StaticIdentifierExpr staticId = getModel()
81ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                        .staticIdentifierFor(target.getResolvedType());
82ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                getChildren().add(staticId);
83ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                staticId.getParents().add(this);
84ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                // make sure we update this in case we access it below
85ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                target = getTarget();
86ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            }
87019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            int flags = DYNAMIC;
88019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            if (method.isStatic()) {
89019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                flags |= STATIC;
90019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            }
91019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            mGetter = new Callable(Type.METHOD, method.getName(), method.getReturnType(args), flags);
92d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
93d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mGetter.resolvedType;
94d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
95d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
96d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Override
97d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected List<Dependency> constructDependencies() {
98dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        final List<Dependency> dependencies = constructDynamicChildrenDependencies();
99dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        for (Dependency dependency : dependencies) {
1007920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount            if (dependency.getOther() == getTarget()) {
101dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar                dependency.setMandatory(true);
102dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar            }
103dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        }
104dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        return dependencies;
105d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
106d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
107d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Override
108d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected String computeUniqueKey() {
1092611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return join(getTarget().computeUniqueKey(), mName,
1107920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount                super.computeUniqueKey());
111d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
112d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
113d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public Expr getTarget() {
1147920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount        return getChildren().get(0);
115d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
116d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
117d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String getName() {
118d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mName;
119d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
120d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
121d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Expr> getArgs() {
1227920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount        return getChildren().subList(1, getChildren().size());
123d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
124d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
125e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount    public Callable getGetter() {
126d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mGetter;
127d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
128d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
129