11b9940e612fc73202837fbe9db2f9035f307b5d1George Mount/*
21b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * Copyright (C) 2015 The Android Open Source Project
31b9940e612fc73202837fbe9db2f9035f307b5d1George Mount *
41b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * Licensed under the Apache License, Version 2.0 (the "License");
51b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * you may not use this file except in compliance with the License.
61b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * You may obtain a copy of the License at
71b9940e612fc73202837fbe9db2f9035f307b5d1George Mount *
81b9940e612fc73202837fbe9db2f9035f307b5d1George Mount *      http://www.apache.org/licenses/LICENSE-2.0
91b9940e612fc73202837fbe9db2f9035f307b5d1George Mount *
101b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * Unless required by applicable law or agreed to in writing, software
111b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * distributed under the License is distributed on an "AS IS" BASIS,
121b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * See the License for the specific language governing permissions and
141b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * limitations under the License.
151b9940e612fc73202837fbe9db2f9035f307b5d1George Mount */
16fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool.reflection;
171b9940e612fc73202837fbe9db2f9035f307b5d1George Mount
18fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.Bindable;
19fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount
201b9940e612fc73202837fbe9db2f9035f307b5d1George Mountimport java.util.List;
211b9940e612fc73202837fbe9db2f9035f307b5d1George Mount
22fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mountpublic abstract class ModelMethod {
23fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public abstract ModelClass getDeclaringClass();
24fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount
25fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public abstract ModelClass[] getParameterTypes();
26fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount
27fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public abstract String getName();
281b9940e612fc73202837fbe9db2f9035f307b5d1George Mount
29fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public abstract ModelClass getReturnType(List<ModelClass> args);
301b9940e612fc73202837fbe9db2f9035f307b5d1George Mount
31fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public abstract boolean isVoid();
321b9940e612fc73202837fbe9db2f9035f307b5d1George Mount
33fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public abstract boolean isPublic();
341b9940e612fc73202837fbe9db2f9035f307b5d1George Mount
35bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    public abstract boolean isProtected();
36bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount
37fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public abstract boolean isStatic();
381b9940e612fc73202837fbe9db2f9035f307b5d1George Mount
39716ba89e7f459f49ea85070d4710c1d79d715298George Mount    public abstract boolean isAbstract();
40716ba89e7f459f49ea85070d4710c1d79d715298George Mount
41fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    /**
42fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount     * @return whether or not this method has been given the {@link Bindable} annotation.
43fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount     */
44fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public abstract boolean isBindable();
4597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar
4697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar    /**
4797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar     * Since when this method is available. Important for Binding expressions so that we don't
4897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar     * call non-existing APIs when setting UI.
4997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar     *
5097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar     * @return The SDK_INT where this method was added. If it is not a framework method, should
5197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar     * return 1.
5297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar     */
53fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public abstract int getMinApi();
5497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar
5597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar    /**
5697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar     * Returns the JNI description of the method which can be used to lookup it in SDK.
57fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount     * @see TypeUtil
5897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar     */
59fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public abstract String getJniDescription();
60fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount
61fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    /**
62fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount     * @return true if the final parameter is a varargs parameter.
63fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount     */
64fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public abstract boolean isVarArgs();
65fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount
66fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    /**
67fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount     * @param args The arguments to the method
68fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount     * @return Whether the arguments would be accepted as parameters to this method.
69fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount     */
70fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public boolean acceptsArguments(List<ModelClass> args) {
71fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        boolean isVarArgs = isVarArgs();
72fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        ModelClass[] parameterTypes = getParameterTypes();
73fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        if ((!isVarArgs && args.size() != parameterTypes.length) ||
74fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                (isVarArgs && args.size() < parameterTypes.length - 1)) {
75fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return false; // The wrong number of parameters
76fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        }
77fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        boolean parametersMatch = true;
78fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        for (int i = 0; i < args.size(); i++) {
79fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            ModelClass parameterType = getParameter(i, parameterTypes);
80fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            ModelClass arg = args.get(i);
81bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount            if (parameterType.isIncomplete()) {
82bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount                parameterType = parameterType.erasure();
83bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount            }
84fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            if (!parameterType.isAssignableFrom(arg) && !isImplicitConversion(arg, parameterType)) {
85fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                parametersMatch = false;
86fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                break;
87fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            }
88fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        }
89fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        return parametersMatch;
90fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    }
91fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount
92fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public boolean isBetterArgMatchThan(ModelMethod other, List<ModelClass> args) {
93fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        final ModelClass[] parameterTypes = getParameterTypes();
94fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        final ModelClass[] otherParameterTypes = other.getParameterTypes();
95fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        for (int i = 0; i < args.size(); i++) {
96fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            final ModelClass arg = args.get(i);
97fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            final ModelClass thisParameter = getParameter(i, parameterTypes);
98fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            final ModelClass thatParameter = other.getParameter(i, otherParameterTypes);
9911df39c91611b9ff2d7c87a9a9829251a015bccfGeorge Mount            if (thisParameter.equals(thatParameter)) {
10011df39c91611b9ff2d7c87a9a9829251a015bccfGeorge Mount                continue;
10111df39c91611b9ff2d7c87a9a9829251a015bccfGeorge Mount            }
102fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            final int diff = compareParameter(arg, thisParameter, thatParameter);
103fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            if (diff != 0) {
104fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                return diff < 0;
105fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            }
106fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        }
107fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        return false;
108fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    }
109fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount
1106047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public ModelClass getReturnType() {
1116047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return getReturnType(null);
1126047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
1136047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
114fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    private ModelClass getParameter(int index, ModelClass[] parameterTypes) {
115fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        int normalParamCount = isVarArgs() ? parameterTypes.length - 1 : parameterTypes.length;
116fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        if (index < normalParamCount) {
117fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return parameterTypes[index];
118fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else {
119fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return parameterTypes[parameterTypes.length - 1].getComponentType();
120fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        }
121fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    }
122fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount
123fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    private static int compareParameter(ModelClass arg, ModelClass thisParameter,
124fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            ModelClass thatParameter) {
125fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        if (thatParameter.equals(arg)) {
126fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return 1;
127fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else if (thisParameter.equals(arg)) {
128fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return -1;
129fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else if (isBoxingConversion(thatParameter, arg)) {
130fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return 1;
131fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else if (isBoxingConversion(thisParameter, arg)) {
132fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            // Boxing/unboxing is second best
133fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return -1;
134fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else {
135fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            int argConversionLevel = getImplicitConversionLevel(arg);
136fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            if (argConversionLevel != -1) {
137fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                int oldConversionLevel = getImplicitConversionLevel(thatParameter);
138fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                int newConversionLevel = getImplicitConversionLevel(thisParameter);
139fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                if (newConversionLevel != -1 &&
140fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                        (oldConversionLevel == -1 || newConversionLevel < oldConversionLevel)) {
141fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                    return -1;
142fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                } else if (oldConversionLevel != -1) {
143fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                    return 1;
144fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                }
145fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            }
146fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            // Look for more exact match
147fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            if (thatParameter.isAssignableFrom(thisParameter)) {
148fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                return -1;
149fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            }
150fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        }
151fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        return 0; // no difference
152fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    }
153fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount
154fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public static boolean isBoxingConversion(ModelClass class1, ModelClass class2) {
155fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        if (class1.isPrimitive() != class2.isPrimitive()) {
156fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return (class1.box().equals(class2.box()));
157fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else {
158fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return false;
159fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        }
160fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    }
161fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount
162fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public static int getImplicitConversionLevel(ModelClass primitive) {
163fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        if (primitive == null) {
164fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return -1;
165fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else if (primitive.isByte()) {
166fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return 0;
167fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else if (primitive.isChar()) {
168fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return 1;
169fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else if (primitive.isShort()) {
170fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return 2;
171fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else if (primitive.isInt()) {
172fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return 3;
173fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else if (primitive.isLong()) {
174fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return 4;
175fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else if (primitive.isFloat()) {
176fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return 5;
177fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else if (primitive.isDouble()) {
178fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return 6;
179fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else {
180fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return -1;
181fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        }
182fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    }
183fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount
184fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    public static boolean isImplicitConversion(ModelClass from, ModelClass to) {
185fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        if (from != null && to != null && from.isPrimitive() && to.isPrimitive()) {
186fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            if (from.isBoolean() || to.isBoolean() || to.isChar()) {
187fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount                return false;
188fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            }
189fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            int fromConversionLevel = getImplicitConversionLevel(from);
190fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            int toConversionLevel = getImplicitConversionLevel(to);
191fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return fromConversionLevel < toConversionLevel;
192fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        } else {
193fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount            return false;
194fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        }
195fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount    }
1961b9940e612fc73202837fbe9db2f9035f307b5d1George Mount}
197