1 /*
   2  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 package com.sun.tools.javah;
  28 
  29 import java.io.OutputStream;
  30 import java.io.PrintWriter;
  31 import java.util.ArrayList;
  32 import java.util.HashSet;
  33 import java.util.List;
  34 
  35 import java.util.Set;
  36 import javax.lang.model.element.Element;
  37 import javax.lang.model.element.ExecutableElement;
  38 import javax.lang.model.element.Modifier;
  39 import javax.lang.model.element.Name;
  40 import javax.lang.model.element.TypeElement;
  41 import javax.lang.model.element.VariableElement;
  42 import javax.lang.model.type.ArrayType;
  43 import javax.lang.model.type.PrimitiveType;
  44 import javax.lang.model.type.TypeKind;
  45 import javax.lang.model.type.TypeMirror;
  46 import javax.lang.model.type.TypeVisitor;
  47 import javax.lang.model.util.ElementFilter;
  48 import javax.lang.model.util.SimpleTypeVisitor7;
  49 
  50 /*
  51  * <p><b>This is NOT part of any supported API.
  52  * If you write code that depends on this, you do so at your own
  53  * risk.  This code and its internal interfaces are subject to change
  54  * or deletion without notice.</b></p>
  55  *
  56  * @author  Sucheta Dambalkar(Revised)
  57  */
  58 public class LLNI extends Gen {
  59 
  60     protected final char  innerDelim = '$';     /* For inner classes */
  61     protected Set<String>  doneHandleTypes;
  62     List<VariableElement> fields;
  63     List<ExecutableElement> methods;
  64     private boolean       doubleAlign;
  65     private int           padFieldNum = 0;
  66 
  67     LLNI(boolean doubleAlign, Util util) {
  68         super(util);
  69         this.doubleAlign = doubleAlign;
  70     }
  71 
  72     protected String getIncludes() {
  73         return "";
  74     }
  75 
  76     protected void write(OutputStream o, TypeElement clazz) throws Util.Exit {
  77         try {
  78             String cname     = mangleClassName(clazz.getQualifiedName().toString());
  79             PrintWriter pw   = wrapWriter(o);
  80             fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
  81             methods = ElementFilter.methodsIn(clazz.getEnclosedElements());
  82             generateDeclsForClass(pw, clazz, cname);
  83             // FIXME check if errors occurred on the PrintWriter and throw exception if so
  84         } catch (TypeSignature.SignatureException e) {
  85             util.error("llni.sigerror", e.getMessage());
  86         }
  87     }
  88 
  89     protected void generateDeclsForClass(PrintWriter pw,
  90             TypeElement clazz, String cname)
  91             throws TypeSignature.SignatureException, Util.Exit {
  92         doneHandleTypes  = new HashSet<String>();
  93         /* The following handle types are predefined in "typedefs.h". Suppress
  94            inclusion in the output by generating them "into the blue" here. */
  95         genHandleType(null, "java.lang.Class");
  96         genHandleType(null, "java.lang.ClassLoader");
  97         genHandleType(null, "java.lang.Object");
  98         genHandleType(null, "java.lang.String");
  99         genHandleType(null, "java.lang.Thread");
 100         genHandleType(null, "java.lang.ThreadGroup");
 101         genHandleType(null, "java.lang.Throwable");
 102 
 103         pw.println("/* LLNI Header for class " + clazz.getQualifiedName() + " */" + lineSep);
 104         pw.println("#ifndef _Included_" + cname);
 105         pw.println("#define _Included_" + cname);
 106         pw.println("#include \"typedefs.h\"");
 107         pw.println("#include \"llni.h\"");
 108         pw.println("#include \"jni.h\"" + lineSep);
 109 
 110         forwardDecls(pw, clazz);
 111         structSectionForClass(pw, clazz, cname);
 112         methodSectionForClass(pw, clazz, cname);
 113         pw.println("#endif");
 114     }
 115 
 116     protected void genHandleType(PrintWriter pw, String clazzname) {
 117         String cname = mangleClassName(clazzname);
 118         if (!doneHandleTypes.contains(cname)) {
 119             doneHandleTypes.add(cname);
 120             if (pw != null) {
 121                 pw.println("#ifndef DEFINED_" + cname);
 122                 pw.println("    #define DEFINED_" + cname);
 123                 pw.println("    GEN_HANDLE_TYPES(" + cname + ");");
 124                 pw.println("#endif" + lineSep);
 125             }
 126         }
 127     }
 128 
 129     protected String mangleClassName(String s) {
 130         return s.replace('.', '_')
 131             .replace('/', '_')
 132             .replace(innerDelim, '_');
 133     }
 134 
 135     protected void forwardDecls(PrintWriter pw, TypeElement clazz)
 136             throws TypeSignature.SignatureException {
 137         TypeElement object = elems.getTypeElement("java.lang.Object");
 138         if (clazz.equals(object))
 139             return;
 140 
 141         genHandleType(pw, clazz.getQualifiedName().toString());
 142         TypeElement superClass = (TypeElement) (types.asElement(clazz.getSuperclass()));
 143 
 144         if (superClass != null) {
 145             String superClassName = superClass.getQualifiedName().toString();
 146             forwardDecls(pw, superClass);
 147         }
 148 
 149         for (VariableElement field: fields) {
 150 
 151             if (!field.getModifiers().contains(Modifier.STATIC)) {
 152                 TypeMirror t = types.erasure(field.asType());
 153                 TypeSignature newTypeSig = new TypeSignature(elems);
 154                 String tname = newTypeSig.qualifiedTypeName(t);
 155                 String sig = newTypeSig.getTypeSignature(tname);
 156 
 157                 if (sig.charAt(0) != '[')
 158                     forwardDeclsFromSig(pw, sig);
 159             }
 160         }
 161 
 162         for (ExecutableElement method: methods) {
 163 
 164             if (method.getModifiers().contains(Modifier.NATIVE)) {
 165                 TypeMirror retType = types.erasure(method.getReturnType());
 166                 String typesig = signature(method);
 167                 TypeSignature newTypeSig = new TypeSignature(elems);
 168                 String sig = newTypeSig.getTypeSignature(typesig, retType);
 169 
 170                 if (sig.charAt(0) != '[')
 171                     forwardDeclsFromSig(pw, sig);
 172 
 173             }
 174         }
 175     }
 176 
 177     protected void forwardDeclsFromSig(PrintWriter pw, String sig) {
 178         int    len = sig.length();
 179         int    i   = sig.charAt(0) == '(' ? 1 : 0;
 180 
 181         /* Skip the initial "(". */
 182         while (i < len) {
 183             if (sig.charAt(i) == 'L') {
 184                 int j = i + 1;
 185                 while (sig.charAt(j) != ';') j++;
 186                 genHandleType(pw, sig.substring(i + 1, j));
 187                 i = j + 1;
 188             } else {
 189                 i++;
 190             }
 191         }
 192     }
 193 
 194     protected void structSectionForClass(PrintWriter pw,
 195                                          TypeElement jclazz, String cname) {
 196 
 197         String jname = jclazz.getQualifiedName().toString();
 198 
 199         if (cname.equals("java_lang_Object")) {
 200             pw.println("/* struct java_lang_Object is defined in typedefs.h. */");
 201             pw.println();
 202             return;
 203         }
 204         pw.println("#if !defined(__i386)");
 205         pw.println("#pragma pack(4)");
 206         pw.println("#endif");
 207         pw.println();
 208         pw.println("struct " + cname + " {");
 209         pw.println("    ObjHeader h;");
 210         pw.print(fieldDefs(jclazz, cname));
 211 
 212         if (jname.equals("java.lang.Class"))
 213             pw.println("    Class *LLNI_mask(cClass);" +
 214                        "  /* Fake field; don't access (see oobj.h) */");
 215         pw.println("};" + lineSep + lineSep + "#pragma pack()");
 216         pw.println();
 217         return;
 218     }
 219 
 220     private static class FieldDefsRes {
 221         public String className;        /* Name of the current class. */
 222         public FieldDefsRes parent;
 223         public String s;
 224         public int byteSize;
 225         public boolean bottomMost;
 226         public boolean printedOne = false;
 227 
 228         FieldDefsRes(TypeElement clazz, FieldDefsRes parent, boolean bottomMost) {
 229             this.className = clazz.getQualifiedName().toString();
 230             this.parent = parent;
 231             this.bottomMost = bottomMost;
 232             int byteSize = 0;
 233             if (parent == null) this.s = "";
 234             else this.s = parent.s;
 235         }
 236     }
 237 
 238     /* Returns "true" iff added a field. */
 239     private boolean doField(FieldDefsRes res, VariableElement field,
 240                             String cname, boolean padWord) {
 241 
 242         String fieldDef = addStructMember(field, cname, padWord);
 243         if (fieldDef != null) {
 244             if (!res.printedOne) { /* add separator */
 245                 if (res.bottomMost) {
 246                     if (res.s.length() != 0)
 247                         res.s = res.s + "    /* local members: */" + lineSep;
 248                 } else {
 249                     res.s = res.s + "    /* inherited members from " +
 250                         res.className + ": */" + lineSep;
 251                 }
 252                 res.printedOne = true;
 253             }
 254             res.s = res.s + fieldDef;
 255             return true;
 256         }
 257 
 258         // Otherwise.
 259         return false;
 260     }
 261 
 262     private int doTwoWordFields(FieldDefsRes res, TypeElement clazz,
 263                                 int offset, String cname, boolean padWord) {
 264         boolean first = true;
 265         List<VariableElement> fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
 266 
 267         for (VariableElement field: fields) {
 268             TypeKind tk = field.asType().getKind();
 269             boolean twoWords = (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);
 270             if (twoWords && doField(res, field, cname, first && padWord)) {
 271                 offset += 8; first = false;
 272             }
 273         }
 274         return offset;
 275     }
 276 
 277     String fieldDefs(TypeElement clazz, String cname) {
 278         FieldDefsRes res = fieldDefs(clazz, cname, true);
 279         return res.s;
 280     }
 281 
 282     FieldDefsRes fieldDefs(TypeElement clazz, String cname,
 283                                      boolean bottomMost){
 284         FieldDefsRes res;
 285         int offset;
 286         boolean didTwoWordFields = false;
 287 
 288         TypeElement superclazz = (TypeElement) types.asElement(clazz.getSuperclass());
 289 
 290         if (superclazz != null) {
 291             String supername = superclazz.getQualifiedName().toString();
 292             res = new FieldDefsRes(clazz,
 293                                    fieldDefs(superclazz, cname, false),
 294                                    bottomMost);
 295             offset = res.parent.byteSize;
 296         } else {
 297             res = new FieldDefsRes(clazz, null, bottomMost);
 298             offset = 0;
 299         }
 300 
 301         List<VariableElement> fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
 302 
 303         for (VariableElement field: fields) {
 304 
 305             if (doubleAlign && !didTwoWordFields && (offset % 8) == 0) {
 306                 offset = doTwoWordFields(res, clazz, offset, cname, false);
 307                 didTwoWordFields = true;
 308             }
 309 
 310             TypeKind tk = field.asType().getKind();
 311             boolean twoWords = (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);
 312 
 313             if (!doubleAlign || !twoWords) {
 314                 if (doField(res, field, cname, false)) offset += 4;
 315             }
 316 
 317         }
 318 
 319         if (doubleAlign && !didTwoWordFields) {
 320             if ((offset % 8) != 0) offset += 4;
 321             offset = doTwoWordFields(res, clazz, offset, cname, true);
 322         }
 323 
 324         res.byteSize = offset;
 325         return res;
 326     }
 327 
 328     /* OVERRIDE: This method handles instance fields */
 329     protected String addStructMember(VariableElement member, String cname,
 330                                      boolean padWord) {
 331         String res = null;
 332 
 333         if (member.getModifiers().contains(Modifier.STATIC)) {
 334             res = addStaticStructMember(member, cname);
 335             //   if (res == null) /* JNI didn't handle it, print comment. */
 336             //  res = "    /* Inaccessible static: " + member + " */" + lineSep;
 337         } else {
 338             TypeMirror mt = types.erasure(member.asType());
 339             if (padWord) res = "    java_int padWord" + padFieldNum++ + ";" + lineSep;
 340             res = "    " + llniType(mt, false, false) + " " + llniFieldName(member);
 341             if (isLongOrDouble(mt)) res = res + "[2]";
 342             res = res + ";" + lineSep;
 343         }
 344         return res;
 345     }
 346 
 347     static private final boolean isWindows =
 348         System.getProperty("os.name").startsWith("Windows");
 349 
 350     /*
 351      * This method only handles static final fields.
 352      */
 353     protected String addStaticStructMember(VariableElement field, String cname) {
 354         String res = null;
 355         Object exp = null;
 356 
 357         if (!field.getModifiers().contains(Modifier.STATIC))
 358             return res;
 359         if (!field.getModifiers().contains(Modifier.FINAL))
 360             return res;
 361 
 362         exp = field.getConstantValue();
 363 
 364         if (exp != null) {
 365             /* Constant. */
 366 
 367             String     cn     = cname + "_" + field.getSimpleName();
 368             String     suffix = null;
 369             long           val = 0;
 370             /* Can only handle int, long, float, and double fields. */
 371             if (exp instanceof Byte
 372                 || exp instanceof Short
 373                 || exp instanceof Integer) {
 374                 suffix = "L";
 375                 val = ((Number)exp).intValue();
 376             }
 377             else if (exp instanceof Long) {
 378                 // Visual C++ supports the i64 suffix, not LL
 379                 suffix = isWindows ? "i64" : "LL";
 380                 val = ((Long)exp).longValue();
 381             }
 382             else if (exp instanceof Float)  suffix = "f";
 383             else if (exp instanceof Double) suffix = "";
 384             else if (exp instanceof Character) {
 385                 suffix = "L";
 386                 Character ch = (Character) exp;
 387                 val = ((int) ch) & 0xffff;
 388             }
 389             if (suffix != null) {
 390                 // Some compilers will generate a spurious warning
 391                 // for the integer constants for Integer.MIN_VALUE
 392                 // and Long.MIN_VALUE so we handle them specially.
 393                 if ((suffix.equals("L") && (val == Integer.MIN_VALUE)) ||
 394                     (suffix.equals("LL") && (val == Long.MIN_VALUE))) {
 395                     res = "    #undef  " + cn + lineSep
 396                         + "    #define " + cn
 397                         + " (" + (val + 1) + suffix + "-1)" + lineSep;
 398                 } else if (suffix.equals("L") || suffix.endsWith("LL")) {
 399                     res = "    #undef  " + cn + lineSep
 400                         + "    #define " + cn + " " + val + suffix + lineSep;
 401                 } else {
 402                     res = "    #undef  " + cn + lineSep
 403                         + "    #define " + cn + " " + exp + suffix + lineSep;
 404                 }
 405             }
 406         }
 407         return res;
 408     }
 409 
 410     protected void methodSectionForClass(PrintWriter pw,
 411             TypeElement clazz, String cname)
 412             throws TypeSignature.SignatureException, Util.Exit {
 413         String methods = methodDecls(clazz, cname);
 414 
 415         if (methods.length() != 0) {
 416             pw.println("/* Native method declarations: */" + lineSep);
 417             pw.println("#ifdef __cplusplus");
 418             pw.println("extern \"C\" {");
 419             pw.println("#endif" + lineSep);
 420             pw.println(methods);
 421             pw.println("#ifdef __cplusplus");
 422             pw.println("}");
 423             pw.println("#endif");
 424         }
 425     }
 426 
 427     protected String methodDecls(TypeElement clazz, String cname)
 428             throws TypeSignature.SignatureException, Util.Exit {
 429 
 430         String res = "";
 431         for (ExecutableElement method: methods) {
 432             if (method.getModifiers().contains(Modifier.NATIVE))
 433                 res = res + methodDecl(method, clazz, cname);
 434         }
 435         return res;
 436     }
 437 
 438     protected String methodDecl(ExecutableElement method,
 439                                 TypeElement clazz, String cname)
 440             throws TypeSignature.SignatureException, Util.Exit {
 441         String res = null;
 442 
 443         TypeMirror retType = types.erasure(method.getReturnType());
 444         String typesig = signature(method);
 445         TypeSignature newTypeSig = new TypeSignature(elems);
 446         String sig = newTypeSig.getTypeSignature(typesig, retType);
 447         boolean longName = needLongName(method, clazz);
 448 
 449         if (sig.charAt(0) != '(')
 450             util.error("invalid.method.signature", sig);
 451 
 452 
 453         res = "JNIEXPORT " + jniType(retType) + " JNICALL" + lineSep + jniMethodName(method, cname, longName)
 454             + "(JNIEnv *, " + cRcvrDecl(method, cname);
 455         List<? extends VariableElement> params = method.getParameters();
 456         List<TypeMirror> argTypes = new ArrayList<TypeMirror>();
 457         for (VariableElement p: params){
 458             argTypes.add(types.erasure(p.asType()));
 459         }
 460 
 461         /* It would have been nice to include the argument names in the
 462            declaration, but there seems to be a bug in the "BinaryField"
 463            class, causing the getArguments() method to return "null" for
 464            most (non-constructor) methods. */
 465         for (TypeMirror argType: argTypes)
 466             res = res + ", " + jniType(argType);
 467         res = res + ");" + lineSep;
 468         return res;
 469     }
 470 
 471     protected final boolean needLongName(ExecutableElement method,
 472                                          TypeElement clazz) {
 473         Name methodName = method.getSimpleName();
 474         for (ExecutableElement memberMethod: methods) {
 475             if ((memberMethod != method) &&
 476                 memberMethod.getModifiers().contains(Modifier.NATIVE) &&
 477                     (methodName.equals(memberMethod.getSimpleName())))
 478                 return true;
 479         }
 480         return false;
 481     }
 482 
 483     protected final String jniMethodName(ExecutableElement method, String cname,
 484                                          boolean longName)
 485                 throws TypeSignature.SignatureException {
 486         String res = "Java_" + cname + "_" + method.getSimpleName();
 487 
 488         if (longName) {
 489             TypeMirror mType =  types.erasure(method.getReturnType());
 490             List<? extends VariableElement> params = method.getParameters();
 491             List<TypeMirror> argTypes = new ArrayList<TypeMirror>();
 492             for (VariableElement param: params) {
 493                 argTypes.add(types.erasure(param.asType()));
 494             }
 495 
 496             res = res + "__";
 497             for (TypeMirror t: argTypes) {
 498                 String tname = t.toString();
 499                 TypeSignature newTypeSig = new TypeSignature(elems);
 500                 String sig = newTypeSig.getTypeSignature(tname);
 501                 res = res + nameToIdentifier(sig);
 502             }
 503         }
 504         return res;
 505     }
 506 
 507     // copied from JNI.java
 508     protected final String jniType(TypeMirror t) throws Util.Exit {
 509         TypeElement throwable = elems.getTypeElement("java.lang.Throwable");
 510         TypeElement jClass = elems.getTypeElement("java.lang.Class");
 511         TypeElement jString = elems.getTypeElement("java.lang.String");
 512         Element tclassDoc = types.asElement(t);
 513 
 514         switch (t.getKind()) {
 515             case ARRAY: {
 516                 TypeMirror ct = ((ArrayType) t).getComponentType();
 517                 switch (ct.getKind()) {
 518                     case BOOLEAN:  return "jbooleanArray";
 519                     case BYTE:     return "jbyteArray";
 520                     case CHAR:     return "jcharArray";
 521                     case SHORT:    return "jshortArray";
 522                     case INT:      return "jintArray";
 523                     case LONG:     return "jlongArray";
 524                     case FLOAT:    return "jfloatArray";
 525                     case DOUBLE:   return "jdoubleArray";
 526                     case ARRAY:
 527                     case DECLARED: return "jobjectArray";
 528                     default: throw new Error(ct.toString());
 529                 }
 530             }
 531 
 532             case VOID:     return "void";
 533             case BOOLEAN:  return "jboolean";
 534             case BYTE:     return "jbyte";
 535             case CHAR:     return "jchar";
 536             case SHORT:    return "jshort";
 537             case INT:      return "jint";
 538             case LONG:     return "jlong";
 539             case FLOAT:    return "jfloat";
 540             case DOUBLE:   return "jdouble";
 541 
 542             case DECLARED: {
 543                 if (tclassDoc.equals(jString))
 544                     return "jstring";
 545                 else if (types.isAssignable(t, throwable.asType()))
 546                     return "jthrowable";
 547                 else if (types.isAssignable(t, jClass.asType()))
 548                     return "jclass";
 549                 else
 550                     return "jobject";
 551             }
 552         }
 553 
 554         util.bug("jni.unknown.type");
 555         return null; /* dead code. */
 556     }
 557 
 558     protected String llniType(TypeMirror t, boolean handleize, boolean longDoubleOK) {
 559         String res = null;
 560 
 561         switch (t.getKind()) {
 562             case ARRAY: {
 563                 TypeMirror ct = ((ArrayType) t).getComponentType();
 564                 switch (ct.getKind()) {
 565                     case BOOLEAN:  res = "IArrayOfBoolean"; break;
 566                     case BYTE:     res = "IArrayOfByte";    break;
 567                     case CHAR:     res = "IArrayOfChar";    break;
 568                     case SHORT:    res = "IArrayOfShort";   break;
 569                     case INT:      res = "IArrayOfInt";     break;
 570                     case LONG:     res = "IArrayOfLong";    break;
 571                     case FLOAT:    res = "IArrayOfFloat";   break;
 572                     case DOUBLE:   res = "IArrayOfDouble";  break;
 573                     case ARRAY:
 574                     case DECLARED: res = "IArrayOfRef";     break;
 575                     default: throw new Error(ct.getKind() + " " + ct);
 576                 }
 577                 if (!handleize) res = "DEREFERENCED_" + res;
 578                 break;
 579             }
 580 
 581             case VOID:
 582                 res = "void";
 583                 break;
 584 
 585             case BOOLEAN:
 586             case BYTE:
 587             case CHAR:
 588             case SHORT:
 589             case INT:
 590                 res = "java_int" ;
 591                 break;
 592 
 593             case LONG:
 594                 res = longDoubleOK ? "java_long" : "val32 /* java_long */";
 595                 break;
 596 
 597             case FLOAT:
 598                 res =  "java_float";
 599                 break;
 600 
 601             case DOUBLE:
 602                 res = longDoubleOK ? "java_double" : "val32 /* java_double */";
 603                 break;
 604 
 605             case DECLARED:
 606                 TypeElement e  = (TypeElement) types.asElement(t);
 607                 res = "I" +  mangleClassName(e.getQualifiedName().toString());
 608                 if (!handleize) res = "DEREFERENCED_" + res;
 609                 break;
 610 
 611             default:
 612                 throw new Error(t.getKind() + " " + t); // FIXME
 613         }
 614 
 615         return res;
 616     }
 617 
 618     protected final String cRcvrDecl(Element field, String cname) {
 619         return (field.getModifiers().contains(Modifier.STATIC) ? "jclass" : "jobject");
 620     }
 621 
 622     protected String maskName(String s) {
 623         return "LLNI_mask(" + s + ")";
 624     }
 625 
 626     protected String llniFieldName(VariableElement field) {
 627         return maskName(field.getSimpleName().toString());
 628     }
 629 
 630     protected final boolean isLongOrDouble(TypeMirror t) {
 631         TypeVisitor<Boolean,Void> v = new SimpleTypeVisitor7<Boolean,Void>() {
 632             public Boolean defaultAction(TypeMirror t, Void p){
 633                 return false;
 634             }
 635             public Boolean visitArray(ArrayType t, Void p) {
 636                 return visit(t.getComponentType(), p);
 637             }
 638             public Boolean visitPrimitive(PrimitiveType t, Void p) {
 639                 TypeKind tk = t.getKind();
 640                 return (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);
 641             }
 642         };
 643         return v.visit(t, null);
 644     }
 645 
 646     /* Do unicode to ansi C identifier conversion.
 647        %%% This may not be right, but should be called more often. */
 648     protected final String nameToIdentifier(String name) {
 649         int len = name.length();
 650         StringBuffer buf = new StringBuffer(len);
 651         for (int i = 0; i < len; i++) {
 652             char c = name.charAt(i);
 653             if (isASCIILetterOrDigit(c))
 654                 buf.append(c);
 655             else if (c == '/')
 656                 buf.append('_');
 657             else if (c == '.')
 658                 buf.append('_');
 659             else if (c == '_')
 660                 buf.append("_1");
 661             else if (c == ';')
 662                 buf.append("_2");
 663             else if (c == '[')
 664                 buf.append("_3");
 665             else
 666                 buf.append("_0" + ((int)c));
 667         }
 668         return new String(buf);
 669     }
 670 
 671     protected final boolean isASCIILetterOrDigit(char c) {
 672         if (((c >= 'A') && (c <= 'Z')) ||
 673             ((c >= 'a') && (c <= 'z')) ||
 674             ((c >= '0') && (c <= '9')))
 675             return true;
 676         else
 677             return false;
 678     }
 679 }
 680