build/annotationProcessors/utils/Utils.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 package org.mozilla.gecko.annotationProcessors.utils;
michael@0 6
michael@0 7 import java.lang.annotation.Annotation;
michael@0 8 import java.lang.reflect.Constructor;
michael@0 9 import java.lang.reflect.Field;
michael@0 10 import java.lang.reflect.Member;
michael@0 11 import java.lang.reflect.Method;
michael@0 12 import java.lang.reflect.Modifier;
michael@0 13 import java.util.HashMap;
michael@0 14
michael@0 15 /**
michael@0 16 * A collection of utility methods used by CodeGenerator. Largely used for translating types.
michael@0 17 */
michael@0 18 public class Utils {
michael@0 19
michael@0 20 // A collection of lookup tables to simplify the functions to follow...
michael@0 21 private static final HashMap<String, String> sBasicCTypes = new HashMap<String, String>();
michael@0 22
michael@0 23 static {
michael@0 24 sBasicCTypes.put("void", "void");
michael@0 25 sBasicCTypes.put("int", "int32_t");
michael@0 26 sBasicCTypes.put("boolean", "bool");
michael@0 27 sBasicCTypes.put("long", "int64_t");
michael@0 28 sBasicCTypes.put("double", "jdouble");
michael@0 29 sBasicCTypes.put("float", "jfloat");
michael@0 30 sBasicCTypes.put("char", "uint16_t");
michael@0 31 sBasicCTypes.put("byte", "int8_t");
michael@0 32 sBasicCTypes.put("short", "int16_t");
michael@0 33 }
michael@0 34
michael@0 35 private static final HashMap<String, String> sArrayCTypes = new HashMap<String, String>();
michael@0 36
michael@0 37 static {
michael@0 38 sArrayCTypes.put("int", "jintArray");
michael@0 39 sArrayCTypes.put("boolean", "jbooleanArray");
michael@0 40 sArrayCTypes.put("long", "jlongArray");
michael@0 41 sArrayCTypes.put("double", "jdoubleArray");
michael@0 42 sArrayCTypes.put("float", "jfloatArray");
michael@0 43 sArrayCTypes.put("char", "jcharArray");
michael@0 44 sArrayCTypes.put("byte", "jbyteArray");
michael@0 45 sArrayCTypes.put("short", "jshortArray");
michael@0 46 }
michael@0 47
michael@0 48 private static final HashMap<String, String> sStaticCallTypes = new HashMap<String, String>();
michael@0 49
michael@0 50 static {
michael@0 51 sStaticCallTypes.put("void", "CallStaticVoidMethod");
michael@0 52 sStaticCallTypes.put("int", "CallStaticIntMethod");
michael@0 53 sStaticCallTypes.put("boolean", "CallStaticBooleanMethod");
michael@0 54 sStaticCallTypes.put("long", "CallStaticLongMethod");
michael@0 55 sStaticCallTypes.put("double", "CallStaticDoubleMethod");
michael@0 56 sStaticCallTypes.put("float", "CallStaticFloatMethod");
michael@0 57 sStaticCallTypes.put("char", "CallStaticCharMethod");
michael@0 58 sStaticCallTypes.put("byte", "CallStaticByteMethod");
michael@0 59 sStaticCallTypes.put("short", "CallStaticShortMethod");
michael@0 60 }
michael@0 61
michael@0 62 private static final HashMap<String, String> sInstanceCallTypes = new HashMap<String, String>();
michael@0 63
michael@0 64 static {
michael@0 65 sInstanceCallTypes.put("void", "CallVoidMethod");
michael@0 66 sInstanceCallTypes.put("int", "CallIntMethod");
michael@0 67 sInstanceCallTypes.put("boolean", "CallBooleanMethod");
michael@0 68 sInstanceCallTypes.put("long", "CallLongMethod");
michael@0 69 sInstanceCallTypes.put("double", "CallDoubleMethod");
michael@0 70 sInstanceCallTypes.put("float", "CallFloatMethod");
michael@0 71 sInstanceCallTypes.put("char", "CallCharMethod");
michael@0 72 sInstanceCallTypes.put("byte", "CallByteMethod");
michael@0 73 sInstanceCallTypes.put("short", "CallShortMethod");
michael@0 74 }
michael@0 75
michael@0 76 private static final HashMap<String, String> sFieldTypes = new HashMap<String, String>();
michael@0 77
michael@0 78 static {
michael@0 79 sFieldTypes.put("int", "Int");
michael@0 80 sFieldTypes.put("boolean", "Boolean");
michael@0 81 sFieldTypes.put("long", "Long");
michael@0 82 sFieldTypes.put("double", "Double");
michael@0 83 sFieldTypes.put("float", "Float");
michael@0 84 sFieldTypes.put("char", "Char");
michael@0 85 sFieldTypes.put("byte", "Byte");
michael@0 86 sFieldTypes.put("short", "Short");
michael@0 87 }
michael@0 88
michael@0 89 private static final HashMap<String, String> sFailureReturns = new HashMap<String, String>();
michael@0 90
michael@0 91 static {
michael@0 92 sFailureReturns.put("java.lang.Void", "");
michael@0 93 sFailureReturns.put("void", "");
michael@0 94 sFailureReturns.put("int", " 0");
michael@0 95 sFailureReturns.put("boolean", " false");
michael@0 96 sFailureReturns.put("long", " 0");
michael@0 97 sFailureReturns.put("double", " 0.0");
michael@0 98 sFailureReturns.put("float", " 0.0");
michael@0 99 sFailureReturns.put("char", " 0");
michael@0 100 sFailureReturns.put("byte", " 0");
michael@0 101 sFailureReturns.put("short", " 0");
michael@0 102 }
michael@0 103
michael@0 104 private static final HashMap<String, String> sCanonicalSignatureParts = new HashMap<String, String>();
michael@0 105
michael@0 106 static {
michael@0 107 sCanonicalSignatureParts.put("java/lang/Void", "V");
michael@0 108 sCanonicalSignatureParts.put("void", "V");
michael@0 109 sCanonicalSignatureParts.put("int", "I");
michael@0 110 sCanonicalSignatureParts.put("boolean", "Z");
michael@0 111 sCanonicalSignatureParts.put("long", "J");
michael@0 112 sCanonicalSignatureParts.put("double", "D");
michael@0 113 sCanonicalSignatureParts.put("float", "F");
michael@0 114 sCanonicalSignatureParts.put("char", "C");
michael@0 115 sCanonicalSignatureParts.put("byte", "B");
michael@0 116 sCanonicalSignatureParts.put("short", "S");
michael@0 117 }
michael@0 118
michael@0 119
michael@0 120 private static final HashMap<String, String> sDefaultParameterValues = new HashMap<String, String>();
michael@0 121
michael@0 122 static {
michael@0 123 sDefaultParameterValues.put("int", "0");
michael@0 124 sDefaultParameterValues.put("boolean", "false");
michael@0 125 sDefaultParameterValues.put("long", "0");
michael@0 126 sDefaultParameterValues.put("double", "0");
michael@0 127 sDefaultParameterValues.put("float", "0.0");
michael@0 128 sDefaultParameterValues.put("char", "0");
michael@0 129 sDefaultParameterValues.put("byte", "0");
michael@0 130 sDefaultParameterValues.put("short", "0");
michael@0 131 }
michael@0 132
michael@0 133 /**
michael@0 134 * Get the C type corresponding to the provided type parameter. Used for generating argument
michael@0 135 * types for the wrapper method.
michael@0 136 *
michael@0 137 * @param type Class to determine the corresponding JNI type for.
michael@0 138 * @return true if the type an object type, false otherwise.
michael@0 139 */
michael@0 140 public static String getCParameterType(Class<?> type) {
michael@0 141 String name = type.getCanonicalName();
michael@0 142 if (sBasicCTypes.containsKey(name)) {
michael@0 143 return sBasicCTypes.get(name);
michael@0 144 }
michael@0 145 // Are we dealing with an array type?
michael@0 146 int len = name.length();
michael@0 147 if (name.endsWith("[]")) {
michael@0 148 // Determine if it is a 2D array - these map to jobjectArrays
michael@0 149 name = name.substring(0, len - 2);
michael@0 150 if (name.endsWith("[]")) {
michael@0 151 return "jobjectArray";
michael@0 152 } else {
michael@0 153 // Which flavour of Array is it?
michael@0 154 if (sArrayCTypes.containsKey(name)) {
michael@0 155 return sArrayCTypes.get(name);
michael@0 156 }
michael@0 157 return "jobjectArray";
michael@0 158 }
michael@0 159 }
michael@0 160 // Not an array type, check the remaining possibilities before we fall back to jobject
michael@0 161
michael@0 162 // Check for CharSequences (Strings and things that are string-like)
michael@0 163 if (isCharSequence(type)) {
michael@0 164 return "const nsAString&";
michael@0 165 }
michael@0 166
michael@0 167 if (name.equals("java.lang.Class")) {
michael@0 168 // You're doing reflection on Java objects from inside C, returning Class objects
michael@0 169 // to C, generating the corresponding code using this Java program. Really?!
michael@0 170 return "jclass";
michael@0 171 }
michael@0 172 if (name.equals("java.lang.Throwable")) {
michael@0 173 return "jthrowable";
michael@0 174 }
michael@0 175 return "jobject";
michael@0 176 }
michael@0 177
michael@0 178 /**
michael@0 179 * For a given Java type, get the corresponding C++ type if we're returning it from a function.
michael@0 180 *
michael@0 181 * @param type The Java return type.
michael@0 182 * @return A string representation of the C++ return type.
michael@0 183 */
michael@0 184 public static String getCReturnType(Class<?> type) {
michael@0 185 if (type.getCanonicalName().equals("java.lang.Void")) {
michael@0 186 return "void";
michael@0 187 }
michael@0 188 String cParameterType = getCParameterType(type);
michael@0 189 if (cParameterType.equals("const nsAString&")) {
michael@0 190 return "jstring";
michael@0 191 } else {
michael@0 192 return cParameterType;
michael@0 193 }
michael@0 194 }
michael@0 195
michael@0 196 /**
michael@0 197 * Gets the type-specific part of the JNI function to use to get or set a field of a given type.
michael@0 198 *
michael@0 199 * @param aFieldType The Java type of the field.
michael@0 200 * @return A string representation of the JNI call function substring to use.
michael@0 201 */
michael@0 202 public static String getFieldType(Class<?> aFieldType) {
michael@0 203 String name = aFieldType.getCanonicalName();
michael@0 204
michael@0 205 if (sFieldTypes.containsKey(name)) {
michael@0 206 return sFieldTypes.get(name);
michael@0 207 }
michael@0 208 return "Object";
michael@0 209 }
michael@0 210
michael@0 211 /**
michael@0 212 * Gets the appropriate JNI call function to use to invoke a Java method with the given return
michael@0 213 * type. This, plus a call postfix (Such as "A") forms a complete JNI call function name.
michael@0 214 *
michael@0 215 * @param aReturnType The Java return type of the method being generated.
michael@0 216 * @param isStatic Boolean indicating if the underlying Java method is declared static.
michael@0 217 * @return A string representation of the JNI call function prefix to use.
michael@0 218 */
michael@0 219 public static String getCallPrefix(Class<?> aReturnType, boolean isStatic) {
michael@0 220 String name = aReturnType.getCanonicalName();
michael@0 221 if (isStatic) {
michael@0 222 if (sStaticCallTypes.containsKey(name)) {
michael@0 223 return sStaticCallTypes.get(name);
michael@0 224 }
michael@0 225 return "CallStaticObjectMethod";
michael@0 226 } else {
michael@0 227 if (sInstanceCallTypes.containsKey(name)) {
michael@0 228 return sInstanceCallTypes.get(name);
michael@0 229 }
michael@0 230 return "CallObjectMethod";
michael@0 231 }
michael@0 232 }
michael@0 233
michael@0 234 /**
michael@0 235 * On failure, the generated method returns a null-esque value. This helper method gets the
michael@0 236 * appropriate failure return value for a given Java return type, plus a leading space.
michael@0 237 *
michael@0 238 * @param type Java return type of method being generated
michael@0 239 * @return String representation of the failure return value to be used in the generated code.
michael@0 240 */
michael@0 241 public static String getFailureReturnForType(Class<?> type) {
michael@0 242 String name = type.getCanonicalName();
michael@0 243 if (sFailureReturns.containsKey(name)) {
michael@0 244 return sFailureReturns.get(name);
michael@0 245 }
michael@0 246 return " nullptr";
michael@0 247 }
michael@0 248
michael@0 249 /**
michael@0 250 * Helper method to get the type signature for methods, given argument and return type.
michael@0 251 * Allows for the near-identical logic needed for constructors and methods to be shared.
michael@0 252 * (Alas, constructor does not extend method)
michael@0 253 *
michael@0 254 * @param arguments Argument types of the underlying method.
michael@0 255 * @param returnType Return type of the underlying method.
michael@0 256 * @return The canonical Java type string for the method. eg. (IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;
michael@0 257 */
michael@0 258 private static String getTypeSignatureInternal(Class<?>[] arguments, Class<?> returnType) {
michael@0 259 StringBuilder sb = new StringBuilder();
michael@0 260 sb.append('(');
michael@0 261
michael@0 262 // For each argument, write its signature component to the buffer..
michael@0 263 for (int i = 0; i < arguments.length; i++) {
michael@0 264 writeTypeSignature(sb, arguments[i]);
michael@0 265 }
michael@0 266 sb.append(')');
michael@0 267
michael@0 268 // Write the return value's signature..
michael@0 269 writeTypeSignature(sb, returnType);
michael@0 270 return sb.toString();
michael@0 271 }
michael@0 272
michael@0 273 /**
michael@0 274 * Get the canonical JNI type signature for a Field.
michael@0 275 *
michael@0 276 * @param aField The field to generate a signature for.
michael@0 277 * @return The canonical JNI type signature for this method.
michael@0 278 */
michael@0 279 protected static String getTypeSignatureStringForField(Field aField) {
michael@0 280 StringBuilder sb = new StringBuilder();
michael@0 281 writeTypeSignature(sb, aField.getType());
michael@0 282 return sb.toString();
michael@0 283 }
michael@0 284
michael@0 285 /**
michael@0 286 * Get the canonical JNI type signature for a method.
michael@0 287 *
michael@0 288 * @param aMethod The method to generate a signature for.
michael@0 289 * @return The canonical JNI type signature for this method.
michael@0 290 */
michael@0 291 protected static String getTypeSignatureStringForMethod(Method aMethod) {
michael@0 292 Class<?>[] arguments = aMethod.getParameterTypes();
michael@0 293 Class<?> returnType = aMethod.getReturnType();
michael@0 294 return getTypeSignatureInternal(arguments, returnType);
michael@0 295 }
michael@0 296
michael@0 297 /**
michael@0 298 * Get the canonical JNI type signature for a Constructor.
michael@0 299 *
michael@0 300 * @param aConstructor The Constructor to generate a signature for.
michael@0 301 * @return The canonical JNI type signature for this method.
michael@0 302 */
michael@0 303 protected static String getTypeSignatureStringForConstructor(Constructor aConstructor) {
michael@0 304 Class<?>[] arguments = aConstructor.getParameterTypes();
michael@0 305 return getTypeSignatureInternal(arguments, Void.class);
michael@0 306 }
michael@0 307
michael@0 308 public static String getTypeSignatureStringForMember(Member aMember) {
michael@0 309 if (aMember instanceof Method) {
michael@0 310 return getTypeSignatureStringForMethod((Method) aMember);
michael@0 311 } else if (aMember instanceof Field) {
michael@0 312 return getTypeSignatureStringForField((Field) aMember);
michael@0 313 } else {
michael@0 314 return getTypeSignatureStringForConstructor((Constructor) aMember);
michael@0 315 }
michael@0 316 }
michael@0 317
michael@0 318 public static String getTypeSignatureString(Constructor aConstructor) {
michael@0 319 Class<?>[] arguments = aConstructor.getParameterTypes();
michael@0 320 StringBuilder sb = new StringBuilder();
michael@0 321 sb.append('(');
michael@0 322
michael@0 323 // For each argument, write its signature component to the buffer..
michael@0 324 for (int i = 0; i < arguments.length; i++) {
michael@0 325 writeTypeSignature(sb, arguments[i]);
michael@0 326 }
michael@0 327
michael@0 328 // Constructors always return Void.
michael@0 329 sb.append(")V");
michael@0 330 return sb.toString();
michael@0 331 }
michael@0 332
michael@0 333 /**
michael@0 334 * Helper method used by getTypeSignatureStringForMethod to build the signature. Write the subsignature
michael@0 335 * of a given type into the buffer.
michael@0 336 *
michael@0 337 * @param sb The buffer to write into.
michael@0 338 * @param c The type of the element to write the subsignature of.
michael@0 339 */
michael@0 340 private static void writeTypeSignature(StringBuilder sb, Class<?> c) {
michael@0 341 String name = c.getCanonicalName().replaceAll("\\.", "/");
michael@0 342
michael@0 343 // Determine if this is an array type and, if so, peel away the array operators..
michael@0 344 int len = name.length();
michael@0 345 while (name.endsWith("[]")) {
michael@0 346 sb.append('[');
michael@0 347 name = name.substring(0, len - 2);
michael@0 348 len = len - 2;
michael@0 349 }
michael@0 350
michael@0 351 if (c.isArray()) {
michael@0 352 c = c.getComponentType();
michael@0 353 }
michael@0 354
michael@0 355 Class<?> containerClass = c.getDeclaringClass();
michael@0 356 if (containerClass != null) {
michael@0 357 // Is an inner class. Add the $ symbol.
michael@0 358 final int lastSlash = name.lastIndexOf('/');
michael@0 359 name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1);
michael@0 360 }
michael@0 361
michael@0 362 // Look in the hashmap for the remainder...
michael@0 363 if (sCanonicalSignatureParts.containsKey(name)) {
michael@0 364 // It was a primitive type, so lookup was a success.
michael@0 365 sb.append(sCanonicalSignatureParts.get(name));
michael@0 366 } else {
michael@0 367 // It was a reference type - generate.
michael@0 368 sb.append('L');
michael@0 369 sb.append(name);
michael@0 370 sb.append(';');
michael@0 371 }
michael@0 372 }
michael@0 373
michael@0 374 /**
michael@0 375 * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both
michael@0 376 * generating header files and method bodies.
michael@0 377 *
michael@0 378 * @param aArgumentTypes Argument types of the Java method being wrapped.
michael@0 379 * @param aReturnType Return type of the Java method being wrapped.
michael@0 380 * @param aCMethodName Name of the method to generate in the C++ class.
michael@0 381 * @param aCClassName Name of the C++ class into which the method is declared.
michael@0 382 * @return The C++ method implementation signature for the method described.
michael@0 383 */
michael@0 384 public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType, String aCMethodName, String aCClassName) {
michael@0 385 StringBuilder retBuffer = new StringBuilder();
michael@0 386
michael@0 387 retBuffer.append(getCReturnType(aReturnType));
michael@0 388 retBuffer.append(' ');
michael@0 389 retBuffer.append(aCClassName);
michael@0 390 retBuffer.append("::");
michael@0 391 retBuffer.append(aCMethodName);
michael@0 392 retBuffer.append('(');
michael@0 393
michael@0 394 // Write argument types...
michael@0 395 for (int aT = 0; aT < aArgumentTypes.length; aT++) {
michael@0 396 retBuffer.append(getCParameterType(aArgumentTypes[aT]));
michael@0 397 retBuffer.append(" a");
michael@0 398 // We, imaginatively, call our arguments a1, a2, a3...
michael@0 399 // The only way to preserve the names from Java would be to parse the
michael@0 400 // Java source, which would be computationally hard.
michael@0 401 retBuffer.append(aT);
michael@0 402 if (aT != aArgumentTypes.length - 1) {
michael@0 403 retBuffer.append(", ");
michael@0 404 }
michael@0 405 }
michael@0 406 retBuffer.append(')');
michael@0 407 return retBuffer.toString();
michael@0 408 }
michael@0 409
michael@0 410 /**
michael@0 411 * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both
michael@0 412 * generating header files and method bodies.
michael@0 413 *
michael@0 414 * @param aArgumentTypes Argument types of the Java method being wrapped.
michael@0 415 * @param aArgumentAnnotations The annotations on the Java method arguments. Used to specify
michael@0 416 * default values etc.
michael@0 417 * @param aReturnType Return type of the Java method being wrapped.
michael@0 418 * @param aCMethodName Name of the method to generate in the C++ class.
michael@0 419 * @param aCClassName Name of the C++ class into which the method is declared.e
michael@0 420 * @param aIsStaticStub true if the generated C++ method should be static, false otherwise.
michael@0 421 * @return The generated C++ header method signature for the method described.
michael@0 422 */
michael@0 423 public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aIsStaticStub) {
michael@0 424 StringBuilder retBuffer = new StringBuilder();
michael@0 425
michael@0 426 // Add the static keyword, if applicable.
michael@0 427 if (aIsStaticStub) {
michael@0 428 retBuffer.append("static ");
michael@0 429 }
michael@0 430
michael@0 431 // Write return type..
michael@0 432 retBuffer.append(getCReturnType(aReturnType));
michael@0 433 retBuffer.append(' ');
michael@0 434 retBuffer.append(aCMethodName);
michael@0 435 retBuffer.append('(');
michael@0 436
michael@0 437 // Write argument types...
michael@0 438 for (int aT = 0; aT < aArgumentTypes.length; aT++) {
michael@0 439 retBuffer.append(getCParameterType(aArgumentTypes[aT]));
michael@0 440 retBuffer.append(" a");
michael@0 441 // We, imaginatively, call our arguments a1, a2, a3...
michael@0 442 // The only way to preserve the names from Java would be to parse the
michael@0 443 // Java source, which would be computationally hard.
michael@0 444 retBuffer.append(aT);
michael@0 445
michael@0 446 // Append the default value, if there is one..
michael@0 447 retBuffer.append(getDefaultValueString(aArgumentTypes[aT], aArgumentAnnotations[aT]));
michael@0 448
michael@0 449 if (aT != aArgumentTypes.length - 1) {
michael@0 450 retBuffer.append(", ");
michael@0 451 }
michael@0 452 }
michael@0 453 retBuffer.append(')');
michael@0 454 return retBuffer.toString();
michael@0 455 }
michael@0 456
michael@0 457 /**
michael@0 458 * If the given Annotation[] contains an OptionalGeneratedParameter annotation then return a
michael@0 459 * string assigning an argument of type aArgumentType to the default value for that type.
michael@0 460 * Otherwise, return the empty string.
michael@0 461 *
michael@0 462 * @param aArgumentType The type of the argument to consider.
michael@0 463 * @param aArgumentAnnotations The annotations on the argument to consider.
michael@0 464 * @return An appropriate string to append to the signature of this argument assigning it to a
michael@0 465 * default value (Or not, as applicable).
michael@0 466 */
michael@0 467 public static String getDefaultValueString(Class<?> aArgumentType, Annotation[] aArgumentAnnotations) {
michael@0 468 for (int i = 0; i < aArgumentAnnotations.length; i++) {
michael@0 469 Class<? extends Annotation> annotationType = aArgumentAnnotations[i].annotationType();
michael@0 470 final String annotationTypeName = annotationType.getName();
michael@0 471 if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter")) {
michael@0 472 return " = " + getDefaultParameterValueForType(aArgumentType);
michael@0 473 }
michael@0 474 }
michael@0 475 return "";
michael@0 476 }
michael@0 477
michael@0 478 /**
michael@0 479 * Helper method to return an appropriate default parameter value for an argument of a given type.
michael@0 480 * The lookup table contains values for primitive types and strings. All other object types default
michael@0 481 * to null pointers.
michael@0 482 *
michael@0 483 * @param aArgumentType The parameter type for which a default value is desired.
michael@0 484 * @return An appropriate string representation of the default value selected, for use in generated
michael@0 485 * C++ code.
michael@0 486 */
michael@0 487 private static String getDefaultParameterValueForType(Class<?> aArgumentType) {
michael@0 488 String typeName = aArgumentType.getCanonicalName();
michael@0 489 if (sDefaultParameterValues.containsKey(typeName)) {
michael@0 490 return sDefaultParameterValues.get(typeName);
michael@0 491 } else if (isCharSequence(aArgumentType)) {
michael@0 492 return "EmptyString()";
michael@0 493 } else {
michael@0 494 return "nullptr";
michael@0 495 }
michael@0 496 }
michael@0 497
michael@0 498 /**
michael@0 499 * Helper method that returns the number of reference types in the arguments of m.
michael@0 500 *
michael@0 501 * @param aArgs The method arguments to consider.
michael@0 502 * @return How many of the arguments of m are nonprimitive.
michael@0 503 */
michael@0 504 public static int enumerateReferenceArguments(Class<?>[] aArgs) {
michael@0 505 int ret = 0;
michael@0 506 for (int i = 0; i < aArgs.length; i++) {
michael@0 507 String name = aArgs[i].getCanonicalName();
michael@0 508 if (!sBasicCTypes.containsKey(name)) {
michael@0 509 ret++;
michael@0 510 }
michael@0 511 }
michael@0 512 return ret;
michael@0 513 }
michael@0 514
michael@0 515 /**
michael@0 516 * Helper method that returns true iff the given method has a string argument.
michael@0 517 *
michael@0 518 * @param m The method to consider.
michael@0 519 * @return True if the given method has a string argument, false otherwise.
michael@0 520 */
michael@0 521 public static boolean hasStringArgument(Method m) {
michael@0 522 Class<?>[] args = m.getParameterTypes();
michael@0 523 for (int i = 0; i < args.length; i++) {
michael@0 524 if (isCharSequence(args[i])) {
michael@0 525 return true;
michael@0 526 }
michael@0 527 }
michael@0 528 return false;
michael@0 529 }
michael@0 530
michael@0 531 /**
michael@0 532 * Write the argument array assignment line for the given argument type. Does not support array
michael@0 533 * types.
michael@0 534 *
michael@0 535 * @param type Type of this argument according to the target Java method's signature.
michael@0 536 * @param argName Wrapper function argument name corresponding to this argument.
michael@0 537 */
michael@0 538 public static String getArrayArgumentMashallingLine(Class<?> type, String argName) {
michael@0 539 StringBuilder sb = new StringBuilder();
michael@0 540
michael@0 541 String name = type.getCanonicalName();
michael@0 542 if (sCanonicalSignatureParts.containsKey(name)) {
michael@0 543 sb.append(sCanonicalSignatureParts.get(name).toLowerCase());
michael@0 544 sb.append(" = ").append(argName).append(";\n");
michael@0 545 } else {
michael@0 546 if (isCharSequence(type)) {
michael@0 547 sb.append("l = AndroidBridge::NewJavaString(env, ").append(argName).append(");\n");
michael@0 548 } else {
michael@0 549 sb.append("l = ").append(argName).append(";\n");
michael@0 550 }
michael@0 551 }
michael@0 552
michael@0 553 return sb.toString();
michael@0 554 }
michael@0 555
michael@0 556 /**
michael@0 557 * Returns true if the type provided is an object type. Returns false otherwise
michael@0 558 *
michael@0 559 * @param aType The type to consider.
michael@0 560 * @return true if the method provided is an object type, false otherwise.
michael@0 561 */
michael@0 562 public static boolean isObjectType(Class<?> aType) {
michael@0 563 return !sBasicCTypes.containsKey(aType.getCanonicalName());
michael@0 564 }
michael@0 565
michael@0 566 /**
michael@0 567 * For a given Java class, get the name of the value in C++ which holds a reference to it.
michael@0 568 *
michael@0 569 * @param aClass Target Java class.
michael@0 570 * @return The name of the C++ jclass entity referencing the given class.
michael@0 571 */
michael@0 572 public static String getClassReferenceName(Class<?> aClass) {
michael@0 573 String className = aClass.getSimpleName();
michael@0 574 return 'm' + className + "Class";
michael@0 575 }
michael@0 576
michael@0 577 /**
michael@0 578 * Generate a line to get a global reference to the Java class given.
michael@0 579 *
michael@0 580 * @param aClass The target Java class.
michael@0 581 * @return The generated code to populate the reference to the class.
michael@0 582 */
michael@0 583 public static String getStartupLineForClass(Class<?> aClass) {
michael@0 584 StringBuilder sb = new StringBuilder();
michael@0 585 sb.append(" ");
michael@0 586 sb.append(getClassReferenceName(aClass));
michael@0 587 sb.append(" = getClassGlobalRef(\"");
michael@0 588
michael@0 589 String name = aClass.getCanonicalName().replaceAll("\\.", "/");
michael@0 590 Class<?> containerClass = aClass.getDeclaringClass();
michael@0 591 if (containerClass != null) {
michael@0 592 // Is an inner class. Add the $ symbol.
michael@0 593 final int lastSlash = name.lastIndexOf('/');
michael@0 594 name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1);
michael@0 595 }
michael@0 596
michael@0 597 sb.append(name);
michael@0 598 sb.append("\");\n");
michael@0 599 return sb.toString();
michael@0 600 }
michael@0 601
michael@0 602 /**
michael@0 603 * Helper method to determine if this object implements CharSequence
michael@0 604 * @param aClass Class to check for CharSequence-esqueness
michael@0 605 * @return True if the given class implements CharSequence, false otherwise.
michael@0 606 */
michael@0 607 public static boolean isCharSequence(Class<?> aClass) {
michael@0 608 if (aClass.getCanonicalName().equals("java.lang.CharSequence")) {
michael@0 609 return true;
michael@0 610 }
michael@0 611 Class<?>[] interfaces = aClass.getInterfaces();
michael@0 612 for (Class<?> c : interfaces) {
michael@0 613 if (c.getCanonicalName().equals("java.lang.CharSequence")) {
michael@0 614 return true;
michael@0 615 }
michael@0 616 }
michael@0 617 return false;
michael@0 618 }
michael@0 619
michael@0 620 /**
michael@0 621 * Helper method to read the modifier bits of the given method to determine if it is static.
michael@0 622 * @param aMember The Member to check.
michael@0 623 * @return true of the method is declared static, false otherwise.
michael@0 624 */
michael@0 625 public static boolean isMemberStatic(Member aMember) {
michael@0 626 int aMethodModifiers = aMember.getModifiers();
michael@0 627 return Modifier.isStatic(aMethodModifiers);
michael@0 628 }
michael@0 629
michael@0 630 /**
michael@0 631 * Helper method to read the modifier bits of the given method to determine if it is static.
michael@0 632 * @param aMember The Member to check.
michael@0 633 * @return true of the method is declared static, false otherwise.
michael@0 634 */
michael@0 635 public static boolean isMemberFinal(Member aMember) {
michael@0 636 int aMethodModifiers = aMember.getModifiers();
michael@0 637 return Modifier.isFinal(aMethodModifiers);
michael@0 638 }
michael@0 639 }

mercurial