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
19731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarimport android.databinding.tool.processing.Scope;
20fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.Callable;
21fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.Callable.Type;
22fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer;
23fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelClass;
24fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelMethod;
25fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.L;
26d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
27d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.ArrayList;
28d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.Arrays;
29d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.List;
30019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarimport static android.databinding.tool.reflection.Callable.STATIC;
31019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarimport static android.databinding.tool.reflection.Callable.DYNAMIC;
32019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarimport static android.databinding.tool.reflection.Callable.CAN_BE_INVALIDATED;
33019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
34d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
35d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarpublic class MethodCallExpr extends Expr {
36d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    final String mName;
37d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
38e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount    Callable mGetter;
39d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
402611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    static List<Expr> concat(Expr e, List<Expr> list) {
412611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> merged = new ArrayList<>();
422611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        merged.add(e);
432611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        merged.addAll(list);
442611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return merged;
452611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    }
462611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar
47d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    MethodCallExpr(Expr target, String name, List<Expr> args) {
482611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        super(concat(target, args));
49d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mName = name;
50d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
51d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
52d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Override
5318243f6f1b7527272ef4feccdf4327d80d9f2241George Mount    public void updateExpr(ModelAnalyzer modelAnalyzer) {
54731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar        try {
55731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar            Scope.enter(this);
56731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar            resolveType(modelAnalyzer);
57731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar            super.updateExpr(modelAnalyzer);
58731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar        } finally {
59731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar            Scope.exit();
60731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar        }
6118243f6f1b7527272ef4feccdf4327d80d9f2241George Mount    }
6218243f6f1b7527272ef4feccdf4327d80d9f2241George Mount
6318243f6f1b7527272ef4feccdf4327d80d9f2241George Mount    @Override
6479fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount    protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
65d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mGetter == null) {
66895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar            List<ModelClass> args = new ArrayList<ModelClass>();
677920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount            for (Expr expr : getArgs()) {
68d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                args.add(expr.getResolvedType());
69d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
7018243f6f1b7527272ef4feccdf4327d80d9f2241George Mount
7118243f6f1b7527272ef4feccdf4327d80d9f2241George Mount            Expr target = getTarget();
72a70fed6415aa1e8bbbe929aee776402ac3b81c86George Mount            boolean isStatic = target instanceof StaticIdentifierExpr;
73fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            ModelMethod method = target.getResolvedType().getMethod(mName, args, isStatic);
74fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            if (method == null) {
75fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                String message = "cannot find method '" + mName + "' in class " +
76fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                        target.getResolvedType().toJavaCode();
77fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                IllegalArgumentException e = new IllegalArgumentException(message);
78fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                L.e(e, "cannot find method %s in class %s", mName,
79fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                        target.getResolvedType().toJavaCode());
80fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                throw e;
81fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            }
82ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            if (!isStatic && method.isStatic()) {
83ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                // found a static method on an instance. Use class instead
84ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                target.getParents().remove(this);
85ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                getChildren().remove(target);
86ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                StaticIdentifierExpr staticId = getModel()
87ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                        .staticIdentifierFor(target.getResolvedType());
88ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                getChildren().add(staticId);
89ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                staticId.getParents().add(this);
90ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                // make sure we update this in case we access it below
91ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                target = getTarget();
92ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            }
93019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            int flags = DYNAMIC;
94019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            if (method.isStatic()) {
95019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                flags |= STATIC;
96019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            }
97019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            mGetter = new Callable(Type.METHOD, method.getName(), method.getReturnType(args), flags);
98d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
99d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mGetter.resolvedType;
100d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
101d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
102d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Override
103d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected List<Dependency> constructDependencies() {
104dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        final List<Dependency> dependencies = constructDynamicChildrenDependencies();
105dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        for (Dependency dependency : dependencies) {
1067920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount            if (dependency.getOther() == getTarget()) {
107dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar                dependency.setMandatory(true);
108dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar            }
109dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        }
110dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        return dependencies;
111d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
112d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
113d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Override
114d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected String computeUniqueKey() {
1152611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return join(getTarget().computeUniqueKey(), mName,
1167920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount                super.computeUniqueKey());
117d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
118d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
119d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public Expr getTarget() {
1207920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount        return getChildren().get(0);
121d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
122d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
123d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String getName() {
124d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mName;
125d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
126d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
127d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Expr> getArgs() {
1287920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount        return getChildren().subList(1, getChildren().size());
129d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
130d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
131e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount    public Callable getGetter() {
132d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mGetter;
133d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
134d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
135