build/annotationProcessors/utils/Utils.java

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/build/annotationProcessors/utils/Utils.java	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,639 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +package org.mozilla.gecko.annotationProcessors.utils;
     1.9 +
    1.10 +import java.lang.annotation.Annotation;
    1.11 +import java.lang.reflect.Constructor;
    1.12 +import java.lang.reflect.Field;
    1.13 +import java.lang.reflect.Member;
    1.14 +import java.lang.reflect.Method;
    1.15 +import java.lang.reflect.Modifier;
    1.16 +import java.util.HashMap;
    1.17 +
    1.18 +/**
    1.19 + * A collection of utility methods used by CodeGenerator. Largely used for translating types.
    1.20 + */
    1.21 +public class Utils {
    1.22 +
    1.23 +    // A collection of lookup tables to simplify the functions to follow...
    1.24 +    private static final HashMap<String, String> sBasicCTypes = new HashMap<String, String>();
    1.25 +
    1.26 +    static {
    1.27 +        sBasicCTypes.put("void", "void");
    1.28 +        sBasicCTypes.put("int", "int32_t");
    1.29 +        sBasicCTypes.put("boolean", "bool");
    1.30 +        sBasicCTypes.put("long", "int64_t");
    1.31 +        sBasicCTypes.put("double", "jdouble");
    1.32 +        sBasicCTypes.put("float", "jfloat");
    1.33 +        sBasicCTypes.put("char", "uint16_t");
    1.34 +        sBasicCTypes.put("byte", "int8_t");
    1.35 +        sBasicCTypes.put("short", "int16_t");
    1.36 +    }
    1.37 +
    1.38 +    private static final HashMap<String, String> sArrayCTypes = new HashMap<String, String>();
    1.39 +
    1.40 +    static {
    1.41 +        sArrayCTypes.put("int", "jintArray");
    1.42 +        sArrayCTypes.put("boolean", "jbooleanArray");
    1.43 +        sArrayCTypes.put("long", "jlongArray");
    1.44 +        sArrayCTypes.put("double", "jdoubleArray");
    1.45 +        sArrayCTypes.put("float", "jfloatArray");
    1.46 +        sArrayCTypes.put("char", "jcharArray");
    1.47 +        sArrayCTypes.put("byte", "jbyteArray");
    1.48 +        sArrayCTypes.put("short", "jshortArray");
    1.49 +    }
    1.50 +
    1.51 +    private static final HashMap<String, String> sStaticCallTypes = new HashMap<String, String>();
    1.52 +
    1.53 +    static {
    1.54 +        sStaticCallTypes.put("void", "CallStaticVoidMethod");
    1.55 +        sStaticCallTypes.put("int", "CallStaticIntMethod");
    1.56 +        sStaticCallTypes.put("boolean", "CallStaticBooleanMethod");
    1.57 +        sStaticCallTypes.put("long", "CallStaticLongMethod");
    1.58 +        sStaticCallTypes.put("double", "CallStaticDoubleMethod");
    1.59 +        sStaticCallTypes.put("float", "CallStaticFloatMethod");
    1.60 +        sStaticCallTypes.put("char", "CallStaticCharMethod");
    1.61 +        sStaticCallTypes.put("byte", "CallStaticByteMethod");
    1.62 +        sStaticCallTypes.put("short", "CallStaticShortMethod");
    1.63 +    }
    1.64 +
    1.65 +    private static final HashMap<String, String> sInstanceCallTypes = new HashMap<String, String>();
    1.66 +
    1.67 +    static {
    1.68 +        sInstanceCallTypes.put("void", "CallVoidMethod");
    1.69 +        sInstanceCallTypes.put("int", "CallIntMethod");
    1.70 +        sInstanceCallTypes.put("boolean", "CallBooleanMethod");
    1.71 +        sInstanceCallTypes.put("long", "CallLongMethod");
    1.72 +        sInstanceCallTypes.put("double", "CallDoubleMethod");
    1.73 +        sInstanceCallTypes.put("float", "CallFloatMethod");
    1.74 +        sInstanceCallTypes.put("char", "CallCharMethod");
    1.75 +        sInstanceCallTypes.put("byte", "CallByteMethod");
    1.76 +        sInstanceCallTypes.put("short", "CallShortMethod");
    1.77 +    }
    1.78 +
    1.79 +    private static final HashMap<String, String> sFieldTypes = new HashMap<String, String>();
    1.80 +
    1.81 +    static {
    1.82 +        sFieldTypes.put("int", "Int");
    1.83 +        sFieldTypes.put("boolean", "Boolean");
    1.84 +        sFieldTypes.put("long", "Long");
    1.85 +        sFieldTypes.put("double", "Double");
    1.86 +        sFieldTypes.put("float", "Float");
    1.87 +        sFieldTypes.put("char", "Char");
    1.88 +        sFieldTypes.put("byte", "Byte");
    1.89 +        sFieldTypes.put("short", "Short");
    1.90 +    }
    1.91 +
    1.92 +    private static final HashMap<String, String> sFailureReturns = new HashMap<String, String>();
    1.93 +
    1.94 +    static {
    1.95 +        sFailureReturns.put("java.lang.Void", "");
    1.96 +        sFailureReturns.put("void", "");
    1.97 +        sFailureReturns.put("int", " 0");
    1.98 +        sFailureReturns.put("boolean", " false");
    1.99 +        sFailureReturns.put("long", " 0");
   1.100 +        sFailureReturns.put("double", " 0.0");
   1.101 +        sFailureReturns.put("float", " 0.0");
   1.102 +        sFailureReturns.put("char", " 0");
   1.103 +        sFailureReturns.put("byte", " 0");
   1.104 +        sFailureReturns.put("short", " 0");
   1.105 +    }
   1.106 +
   1.107 +    private static final HashMap<String, String> sCanonicalSignatureParts = new HashMap<String, String>();
   1.108 +
   1.109 +    static {
   1.110 +        sCanonicalSignatureParts.put("java/lang/Void", "V");
   1.111 +        sCanonicalSignatureParts.put("void", "V");
   1.112 +        sCanonicalSignatureParts.put("int", "I");
   1.113 +        sCanonicalSignatureParts.put("boolean", "Z");
   1.114 +        sCanonicalSignatureParts.put("long", "J");
   1.115 +        sCanonicalSignatureParts.put("double", "D");
   1.116 +        sCanonicalSignatureParts.put("float", "F");
   1.117 +        sCanonicalSignatureParts.put("char", "C");
   1.118 +        sCanonicalSignatureParts.put("byte", "B");
   1.119 +        sCanonicalSignatureParts.put("short", "S");
   1.120 +    }
   1.121 +
   1.122 +
   1.123 +    private static final HashMap<String, String> sDefaultParameterValues = new HashMap<String, String>();
   1.124 +
   1.125 +    static {
   1.126 +        sDefaultParameterValues.put("int", "0");
   1.127 +        sDefaultParameterValues.put("boolean", "false");
   1.128 +        sDefaultParameterValues.put("long", "0");
   1.129 +        sDefaultParameterValues.put("double", "0");
   1.130 +        sDefaultParameterValues.put("float", "0.0");
   1.131 +        sDefaultParameterValues.put("char", "0");
   1.132 +        sDefaultParameterValues.put("byte", "0");
   1.133 +        sDefaultParameterValues.put("short", "0");
   1.134 +    }
   1.135 +
   1.136 +    /**
   1.137 +     * Get the C type corresponding to the provided type parameter. Used for generating argument
   1.138 +     * types for the wrapper method.
   1.139 +     *
   1.140 +     * @param type Class to determine the corresponding JNI type for.
   1.141 +     * @return true if the type an object type, false otherwise.
   1.142 +     */
   1.143 +    public static String getCParameterType(Class<?> type) {
   1.144 +        String name = type.getCanonicalName();
   1.145 +        if (sBasicCTypes.containsKey(name)) {
   1.146 +            return sBasicCTypes.get(name);
   1.147 +        }
   1.148 +        // Are we dealing with an array type?
   1.149 +        int len = name.length();
   1.150 +        if (name.endsWith("[]")) {
   1.151 +            // Determine if it is a 2D array - these map to jobjectArrays
   1.152 +            name = name.substring(0, len - 2);
   1.153 +            if (name.endsWith("[]")) {
   1.154 +                return "jobjectArray";
   1.155 +            } else {
   1.156 +                // Which flavour of Array is it?
   1.157 +                if (sArrayCTypes.containsKey(name)) {
   1.158 +                    return sArrayCTypes.get(name);
   1.159 +                }
   1.160 +                return "jobjectArray";
   1.161 +            }
   1.162 +        }
   1.163 +        // Not an array type, check the remaining possibilities before we fall back to jobject
   1.164 +
   1.165 +        // Check for CharSequences (Strings and things that are string-like)
   1.166 +        if (isCharSequence(type)) {
   1.167 +            return "const nsAString&";
   1.168 +        }
   1.169 +
   1.170 +        if (name.equals("java.lang.Class")) {
   1.171 +            // You're doing reflection on Java objects from inside C, returning Class objects
   1.172 +            // to C, generating the corresponding code using this Java program. Really?!
   1.173 +            return "jclass";
   1.174 +        }
   1.175 +        if (name.equals("java.lang.Throwable")) {
   1.176 +            return "jthrowable";
   1.177 +        }
   1.178 +        return "jobject";
   1.179 +    }
   1.180 +
   1.181 +    /**
   1.182 +     * For a given Java type, get the corresponding C++ type if we're returning it from a function.
   1.183 +     *
   1.184 +     * @param type The Java return type.
   1.185 +     * @return A string representation of the C++ return type.
   1.186 +     */
   1.187 +    public static String getCReturnType(Class<?> type) {
   1.188 +        if (type.getCanonicalName().equals("java.lang.Void")) {
   1.189 +            return "void";
   1.190 +        }
   1.191 +        String cParameterType = getCParameterType(type);
   1.192 +        if (cParameterType.equals("const nsAString&")) {
   1.193 +            return "jstring";
   1.194 +        } else {
   1.195 +            return cParameterType;
   1.196 +        }
   1.197 +    }
   1.198 +
   1.199 +    /**
   1.200 +     * Gets the type-specific part of the  JNI function to use to get or set a field of a given type.
   1.201 +     *
   1.202 +     * @param aFieldType The Java type of the field.
   1.203 +     * @return A string representation of the JNI call function substring to use.
   1.204 +     */
   1.205 +    public static String getFieldType(Class<?> aFieldType) {
   1.206 +        String name = aFieldType.getCanonicalName();
   1.207 +
   1.208 +        if (sFieldTypes.containsKey(name)) {
   1.209 +            return sFieldTypes.get(name);
   1.210 +        }
   1.211 +        return "Object";
   1.212 +    }
   1.213 +
   1.214 +    /**
   1.215 +     * Gets the appropriate JNI call function to use to invoke a Java method with the given return
   1.216 +     * type. This, plus a call postfix (Such as "A") forms a complete JNI call function name.
   1.217 +     *
   1.218 +     * @param aReturnType The Java return type of the method being generated.
   1.219 +     * @param isStatic Boolean indicating if the underlying Java method is declared static.
   1.220 +     * @return A string representation of the JNI call function prefix to use.
   1.221 +     */
   1.222 +    public static String getCallPrefix(Class<?> aReturnType, boolean isStatic) {
   1.223 +        String name = aReturnType.getCanonicalName();
   1.224 +        if (isStatic) {
   1.225 +            if (sStaticCallTypes.containsKey(name)) {
   1.226 +                return sStaticCallTypes.get(name);
   1.227 +            }
   1.228 +            return "CallStaticObjectMethod";
   1.229 +        } else {
   1.230 +            if (sInstanceCallTypes.containsKey(name)) {
   1.231 +                return sInstanceCallTypes.get(name);
   1.232 +            }
   1.233 +            return "CallObjectMethod";
   1.234 +        }
   1.235 +    }
   1.236 +
   1.237 +    /**
   1.238 +     * On failure, the generated method returns a null-esque value. This helper method gets the
   1.239 +     * appropriate failure return value for a given Java return type, plus a leading space.
   1.240 +     *
   1.241 +     * @param type Java return type of method being generated
   1.242 +     * @return String representation of the failure return value to be used in the generated code.
   1.243 +     */
   1.244 +    public static String getFailureReturnForType(Class<?> type) {
   1.245 +        String name = type.getCanonicalName();
   1.246 +        if (sFailureReturns.containsKey(name)) {
   1.247 +            return sFailureReturns.get(name);
   1.248 +        }
   1.249 +        return " nullptr";
   1.250 +    }
   1.251 +
   1.252 +    /**
   1.253 +     * Helper method to get the type signature for methods, given argument and return type.
   1.254 +     * Allows for the near-identical logic needed for constructors and methods to be shared.
   1.255 +     * (Alas, constructor does not extend method)
   1.256 +     *
   1.257 +     * @param arguments Argument types of the underlying method.
   1.258 +     * @param returnType Return type of the underlying method.
   1.259 +     * @return The canonical Java type string for the method. eg. (IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;
   1.260 +     */
   1.261 +    private static String getTypeSignatureInternal(Class<?>[] arguments, Class<?> returnType) {
   1.262 +        StringBuilder sb = new StringBuilder();
   1.263 +        sb.append('(');
   1.264 +
   1.265 +        // For each argument, write its signature component to the buffer..
   1.266 +        for (int i = 0; i < arguments.length; i++) {
   1.267 +            writeTypeSignature(sb, arguments[i]);
   1.268 +        }
   1.269 +        sb.append(')');
   1.270 +
   1.271 +        // Write the return value's signature..
   1.272 +        writeTypeSignature(sb, returnType);
   1.273 +        return sb.toString();
   1.274 +    }
   1.275 +
   1.276 +    /**
   1.277 +     * Get the canonical JNI type signature for a Field.
   1.278 +     *
   1.279 +     * @param aField The field to generate a signature for.
   1.280 +     * @return The canonical JNI type signature for this method.
   1.281 +     */
   1.282 +    protected static String getTypeSignatureStringForField(Field aField) {
   1.283 +        StringBuilder sb = new StringBuilder();
   1.284 +        writeTypeSignature(sb, aField.getType());
   1.285 +        return sb.toString();
   1.286 +    }
   1.287 +
   1.288 +    /**
   1.289 +     * Get the canonical JNI type signature for a method.
   1.290 +     *
   1.291 +     * @param aMethod The method to generate a signature for.
   1.292 +     * @return The canonical JNI type signature for this method.
   1.293 +     */
   1.294 +    protected static String getTypeSignatureStringForMethod(Method aMethod) {
   1.295 +        Class<?>[] arguments = aMethod.getParameterTypes();
   1.296 +        Class<?> returnType = aMethod.getReturnType();
   1.297 +        return getTypeSignatureInternal(arguments, returnType);
   1.298 +    }
   1.299 +
   1.300 +    /**
   1.301 +     * Get the canonical JNI type signature for a Constructor.
   1.302 +     *
   1.303 +     * @param aConstructor The Constructor to generate a signature for.
   1.304 +     * @return The canonical JNI type signature for this method.
   1.305 +     */
   1.306 +    protected static String getTypeSignatureStringForConstructor(Constructor aConstructor) {
   1.307 +        Class<?>[] arguments = aConstructor.getParameterTypes();
   1.308 +        return getTypeSignatureInternal(arguments, Void.class);
   1.309 +    }
   1.310 +
   1.311 +    public static String getTypeSignatureStringForMember(Member aMember) {
   1.312 +        if (aMember instanceof Method) {
   1.313 +            return getTypeSignatureStringForMethod((Method) aMember);
   1.314 +        } else if (aMember instanceof Field) {
   1.315 +            return getTypeSignatureStringForField((Field) aMember);
   1.316 +        } else {
   1.317 +            return getTypeSignatureStringForConstructor((Constructor) aMember);
   1.318 +        }
   1.319 +    }
   1.320 +
   1.321 +    public static String getTypeSignatureString(Constructor aConstructor) {
   1.322 +        Class<?>[] arguments = aConstructor.getParameterTypes();
   1.323 +        StringBuilder sb = new StringBuilder();
   1.324 +        sb.append('(');
   1.325 +
   1.326 +        // For each argument, write its signature component to the buffer..
   1.327 +        for (int i = 0; i < arguments.length; i++) {
   1.328 +            writeTypeSignature(sb, arguments[i]);
   1.329 +        }
   1.330 +
   1.331 +        // Constructors always return Void.
   1.332 +        sb.append(")V");
   1.333 +        return sb.toString();
   1.334 +    }
   1.335 +
   1.336 +    /**
   1.337 +     * Helper method used by getTypeSignatureStringForMethod to build the signature. Write the subsignature
   1.338 +     * of a given type into the buffer.
   1.339 +     *
   1.340 +     * @param sb The buffer to write into.
   1.341 +     * @param c  The type of the element to write the subsignature of.
   1.342 +     */
   1.343 +    private static void writeTypeSignature(StringBuilder sb, Class<?> c) {
   1.344 +        String name = c.getCanonicalName().replaceAll("\\.", "/");
   1.345 +
   1.346 +        // Determine if this is an array type and, if so, peel away the array operators..
   1.347 +        int len = name.length();
   1.348 +        while (name.endsWith("[]")) {
   1.349 +            sb.append('[');
   1.350 +            name = name.substring(0, len - 2);
   1.351 +            len = len - 2;
   1.352 +        }
   1.353 +
   1.354 +        if (c.isArray()) {
   1.355 +            c = c.getComponentType();
   1.356 +        }
   1.357 +
   1.358 +        Class<?> containerClass = c.getDeclaringClass();
   1.359 +        if (containerClass != null) {
   1.360 +            // Is an inner class. Add the $ symbol.
   1.361 +            final int lastSlash = name.lastIndexOf('/');
   1.362 +            name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1);
   1.363 +        }
   1.364 +
   1.365 +        // Look in the hashmap for the remainder...
   1.366 +        if (sCanonicalSignatureParts.containsKey(name)) {
   1.367 +            // It was a primitive type, so lookup was a success.
   1.368 +            sb.append(sCanonicalSignatureParts.get(name));
   1.369 +        } else {
   1.370 +            // It was a reference type - generate.
   1.371 +            sb.append('L');
   1.372 +            sb.append(name);
   1.373 +            sb.append(';');
   1.374 +        }
   1.375 +    }
   1.376 +
   1.377 +    /**
   1.378 +     * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both
   1.379 +     * generating header files and method bodies.
   1.380 +     *
   1.381 +     * @param aArgumentTypes Argument types of the Java method being wrapped.
   1.382 +     * @param aReturnType Return type of the Java method being wrapped.
   1.383 +     * @param aCMethodName Name of the method to generate in the C++ class.
   1.384 +     * @param aCClassName Name of the C++ class into which the method is declared.
   1.385 +     * @return The C++ method implementation signature for the method described.
   1.386 +     */
   1.387 +    public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType, String aCMethodName, String aCClassName) {
   1.388 +        StringBuilder retBuffer = new StringBuilder();
   1.389 +
   1.390 +        retBuffer.append(getCReturnType(aReturnType));
   1.391 +        retBuffer.append(' ');
   1.392 +        retBuffer.append(aCClassName);
   1.393 +        retBuffer.append("::");
   1.394 +        retBuffer.append(aCMethodName);
   1.395 +        retBuffer.append('(');
   1.396 +
   1.397 +        // Write argument types...
   1.398 +        for (int aT = 0; aT < aArgumentTypes.length; aT++) {
   1.399 +            retBuffer.append(getCParameterType(aArgumentTypes[aT]));
   1.400 +            retBuffer.append(" a");
   1.401 +            // We, imaginatively, call our arguments a1, a2, a3...
   1.402 +            // The only way to preserve the names from Java would be to parse the
   1.403 +            // Java source, which would be computationally hard.
   1.404 +            retBuffer.append(aT);
   1.405 +            if (aT != aArgumentTypes.length - 1) {
   1.406 +                retBuffer.append(", ");
   1.407 +            }
   1.408 +        }
   1.409 +        retBuffer.append(')');
   1.410 +        return retBuffer.toString();
   1.411 +    }
   1.412 +
   1.413 +    /**
   1.414 +     * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both
   1.415 +     * generating header files and method bodies.
   1.416 +     *
   1.417 +     * @param aArgumentTypes Argument types of the Java method being wrapped.
   1.418 +     * @param aArgumentAnnotations The annotations on the Java method arguments. Used to specify
   1.419 +     *                             default values etc.
   1.420 +     * @param aReturnType Return type of the Java method being wrapped.
   1.421 +     * @param aCMethodName Name of the method to generate in the C++ class.
   1.422 +     * @param aCClassName Name of the C++ class into which the method is declared.e
   1.423 +     * @param aIsStaticStub true if the generated C++ method should be static, false otherwise.
   1.424 +     * @return The generated C++ header method signature for the method described.
   1.425 +     */
   1.426 +    public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aIsStaticStub) {
   1.427 +        StringBuilder retBuffer = new StringBuilder();
   1.428 +
   1.429 +        // Add the static keyword, if applicable.
   1.430 +        if (aIsStaticStub) {
   1.431 +            retBuffer.append("static ");
   1.432 +        }
   1.433 +
   1.434 +        // Write return type..
   1.435 +        retBuffer.append(getCReturnType(aReturnType));
   1.436 +        retBuffer.append(' ');
   1.437 +        retBuffer.append(aCMethodName);
   1.438 +        retBuffer.append('(');
   1.439 +
   1.440 +        // Write argument types...
   1.441 +        for (int aT = 0; aT < aArgumentTypes.length; aT++) {
   1.442 +            retBuffer.append(getCParameterType(aArgumentTypes[aT]));
   1.443 +            retBuffer.append(" a");
   1.444 +            // We, imaginatively, call our arguments a1, a2, a3...
   1.445 +            // The only way to preserve the names from Java would be to parse the
   1.446 +            // Java source, which would be computationally hard.
   1.447 +            retBuffer.append(aT);
   1.448 +
   1.449 +            // Append the default value, if there is one..
   1.450 +            retBuffer.append(getDefaultValueString(aArgumentTypes[aT], aArgumentAnnotations[aT]));
   1.451 +
   1.452 +            if (aT != aArgumentTypes.length - 1) {
   1.453 +                retBuffer.append(", ");
   1.454 +            }
   1.455 +        }
   1.456 +        retBuffer.append(')');
   1.457 +        return retBuffer.toString();
   1.458 +    }
   1.459 +
   1.460 +    /**
   1.461 +     * If the given Annotation[] contains an OptionalGeneratedParameter annotation then return a
   1.462 +     * string assigning an argument of type aArgumentType to the default value for that type.
   1.463 +     * Otherwise, return the empty string.
   1.464 +     *
   1.465 +     * @param aArgumentType        The type of the argument to consider.
   1.466 +     * @param aArgumentAnnotations The annotations on the argument to consider.
   1.467 +     * @return An appropriate string to append to the signature of this argument assigning it to a
   1.468 +     *         default value (Or not, as applicable).
   1.469 +     */
   1.470 +    public static String getDefaultValueString(Class<?> aArgumentType, Annotation[] aArgumentAnnotations) {
   1.471 +        for (int i = 0; i < aArgumentAnnotations.length; i++) {
   1.472 +            Class<? extends Annotation> annotationType = aArgumentAnnotations[i].annotationType();
   1.473 +            final String annotationTypeName = annotationType.getName();
   1.474 +            if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter")) {
   1.475 +                return " = " + getDefaultParameterValueForType(aArgumentType);
   1.476 +            }
   1.477 +        }
   1.478 +        return "";
   1.479 +    }
   1.480 +
   1.481 +    /**
   1.482 +     * Helper method to return an appropriate default parameter value for an argument of a given type.
   1.483 +     * The lookup table contains values for primitive types and strings. All other object types default
   1.484 +     * to null pointers.
   1.485 +     *
   1.486 +     * @param aArgumentType The parameter type for which a default value is desired.
   1.487 +     * @return An appropriate string representation of the default value selected, for use in generated
   1.488 +     *         C++ code.
   1.489 +     */
   1.490 +    private static String getDefaultParameterValueForType(Class<?> aArgumentType) {
   1.491 +        String typeName = aArgumentType.getCanonicalName();
   1.492 +        if (sDefaultParameterValues.containsKey(typeName)) {
   1.493 +            return sDefaultParameterValues.get(typeName);
   1.494 +        } else if (isCharSequence(aArgumentType)) {
   1.495 +            return "EmptyString()";
   1.496 +        } else {
   1.497 +            return "nullptr";
   1.498 +        }
   1.499 +    }
   1.500 +
   1.501 +    /**
   1.502 +     * Helper method that returns the number of reference types in the arguments of m.
   1.503 +     *
   1.504 +     * @param aArgs The method arguments to consider.
   1.505 +     * @return How many of the arguments of m are nonprimitive.
   1.506 +     */
   1.507 +    public static int enumerateReferenceArguments(Class<?>[] aArgs) {
   1.508 +        int ret = 0;
   1.509 +        for (int i = 0; i < aArgs.length; i++) {
   1.510 +            String name = aArgs[i].getCanonicalName();
   1.511 +            if (!sBasicCTypes.containsKey(name)) {
   1.512 +                ret++;
   1.513 +            }
   1.514 +        }
   1.515 +        return ret;
   1.516 +    }
   1.517 +
   1.518 +    /**
   1.519 +     * Helper method that returns true iff the given method has a string argument.
   1.520 +     *
   1.521 +     * @param m The method to consider.
   1.522 +     * @return True if the given method has a string argument, false otherwise.
   1.523 +     */
   1.524 +    public static boolean hasStringArgument(Method m) {
   1.525 +        Class<?>[] args = m.getParameterTypes();
   1.526 +        for (int i = 0; i < args.length; i++) {
   1.527 +            if (isCharSequence(args[i])) {
   1.528 +                return true;
   1.529 +            }
   1.530 +        }
   1.531 +        return false;
   1.532 +    }
   1.533 +
   1.534 +    /**
   1.535 +     * Write the argument array assignment line for the given argument type. Does not support array
   1.536 +     * types.
   1.537 +     *
   1.538 +     * @param type    Type of this argument according to the target Java method's signature.
   1.539 +     * @param argName Wrapper function argument name corresponding to this argument.
   1.540 +     */
   1.541 +    public static String getArrayArgumentMashallingLine(Class<?> type, String argName) {
   1.542 +        StringBuilder sb = new StringBuilder();
   1.543 +
   1.544 +        String name = type.getCanonicalName();
   1.545 +        if (sCanonicalSignatureParts.containsKey(name)) {
   1.546 +            sb.append(sCanonicalSignatureParts.get(name).toLowerCase());
   1.547 +            sb.append(" = ").append(argName).append(";\n");
   1.548 +        } else {
   1.549 +            if (isCharSequence(type)) {
   1.550 +                sb.append("l = AndroidBridge::NewJavaString(env, ").append(argName).append(");\n");
   1.551 +            } else {
   1.552 +                sb.append("l = ").append(argName).append(";\n");
   1.553 +            }
   1.554 +        }
   1.555 +
   1.556 +        return sb.toString();
   1.557 +    }
   1.558 +
   1.559 +    /**
   1.560 +     * Returns true if the type provided is an object type. Returns false otherwise
   1.561 +     *
   1.562 +     * @param aType The type to consider.
   1.563 +     * @return true if the method provided is an object type, false otherwise.
   1.564 +     */
   1.565 +    public static boolean isObjectType(Class<?> aType) {
   1.566 +        return !sBasicCTypes.containsKey(aType.getCanonicalName());
   1.567 +    }
   1.568 +
   1.569 +    /**
   1.570 +     * For a given Java class, get the name of the value in C++ which holds a reference to it.
   1.571 +     *
   1.572 +     * @param aClass Target Java class.
   1.573 +     * @return The name of the C++ jclass entity referencing the given class.
   1.574 +     */
   1.575 +    public static String getClassReferenceName(Class<?> aClass) {
   1.576 +        String className = aClass.getSimpleName();
   1.577 +        return 'm' + className + "Class";
   1.578 +    }
   1.579 +
   1.580 +    /**
   1.581 +     * Generate a line to get a global reference to the Java class given.
   1.582 +     *
   1.583 +     * @param aClass The target Java class.
   1.584 +     * @return The generated code to populate the reference to the class.
   1.585 +     */
   1.586 +    public static String getStartupLineForClass(Class<?> aClass) {
   1.587 +        StringBuilder sb = new StringBuilder();
   1.588 +        sb.append("    ");
   1.589 +        sb.append(getClassReferenceName(aClass));
   1.590 +        sb.append(" = getClassGlobalRef(\"");
   1.591 +
   1.592 +        String name = aClass.getCanonicalName().replaceAll("\\.", "/");
   1.593 +        Class<?> containerClass = aClass.getDeclaringClass();
   1.594 +        if (containerClass != null) {
   1.595 +            // Is an inner class. Add the $ symbol.
   1.596 +            final int lastSlash = name.lastIndexOf('/');
   1.597 +            name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1);
   1.598 +        }
   1.599 +
   1.600 +        sb.append(name);
   1.601 +        sb.append("\");\n");
   1.602 +        return sb.toString();
   1.603 +    }
   1.604 +
   1.605 +    /**
   1.606 +     * Helper method to determine if this object implements CharSequence
   1.607 +     * @param aClass Class to check for CharSequence-esqueness
   1.608 +     * @return True if the given class implements CharSequence, false otherwise.
   1.609 +     */
   1.610 +    public static boolean isCharSequence(Class<?> aClass) {
   1.611 +        if (aClass.getCanonicalName().equals("java.lang.CharSequence")) {
   1.612 +            return true;
   1.613 +        }
   1.614 +        Class<?>[] interfaces = aClass.getInterfaces();
   1.615 +        for (Class<?> c : interfaces) {
   1.616 +            if (c.getCanonicalName().equals("java.lang.CharSequence")) {
   1.617 +                return true;
   1.618 +            }
   1.619 +        }
   1.620 +        return false;
   1.621 +    }
   1.622 +
   1.623 +    /**
   1.624 +     * Helper method to read the modifier bits of the given method to determine if it is static.
   1.625 +     * @param aMember The Member to check.
   1.626 +     * @return true of the method is declared static, false otherwise.
   1.627 +     */
   1.628 +    public static boolean isMemberStatic(Member aMember) {
   1.629 +        int aMethodModifiers = aMember.getModifiers();
   1.630 +        return Modifier.isStatic(aMethodModifiers);
   1.631 +    }
   1.632 +
   1.633 +    /**
   1.634 +     * Helper method to read the modifier bits of the given method to determine if it is static.
   1.635 +     * @param aMember The Member to check.
   1.636 +     * @return true of the method is declared static, false otherwise.
   1.637 +     */
   1.638 +    public static boolean isMemberFinal(Member aMember) {
   1.639 +        int aMethodModifiers = aMember.getModifiers();
   1.640 +        return Modifier.isFinal(aMethodModifiers);
   1.641 +    }
   1.642 +}

mercurial