4942232: missing param class processes without error
authorjjg
Tue, 12 Oct 2010 13:19:47 -0700
changeset 6930 b6fea484cbb2
parent 6929 81a6a7c1bef1
child 6931 d6339142c51f
4942232: missing param class processes without error Reviewed-by: darcy
langtools/src/share/classes/com/sun/tools/javah/JNI.java
langtools/src/share/classes/com/sun/tools/javah/JavahTask.java
langtools/src/share/classes/com/sun/tools/javah/LLNI.java
langtools/src/share/classes/com/sun/tools/javah/Mangle.java
langtools/src/share/classes/com/sun/tools/javah/TypeSignature.java
langtools/src/share/classes/com/sun/tools/javah/resources/l10n.properties
langtools/test/tools/javah/4942232/ParamClassTest.java
langtools/test/tools/javah/4942232/Test.java
--- a/langtools/src/share/classes/com/sun/tools/javah/JNI.java	Tue Oct 12 13:15:46 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javah/JNI.java	Tue Oct 12 13:19:47 2010 -0700
@@ -59,72 +59,76 @@
     }
 
     public void write(OutputStream o, TypeElement clazz) throws Util.Exit {
-        String cname = mangler.mangle(clazz.getQualifiedName(), Mangle.Type.CLASS);
-        PrintWriter pw = wrapWriter(o);
-        pw.println(guardBegin(cname));
-        pw.println(cppGuardBegin());
+        try {
+            String cname = mangler.mangle(clazz.getQualifiedName(), Mangle.Type.CLASS);
+            PrintWriter pw = wrapWriter(o);
+            pw.println(guardBegin(cname));
+            pw.println(cppGuardBegin());
 
-        /* Write statics. */
-        List<VariableElement> classfields = getAllFields(clazz);
+            /* Write statics. */
+            List<VariableElement> classfields = getAllFields(clazz);
 
-        for (VariableElement v: classfields) {
-            if (!v.getModifiers().contains(Modifier.STATIC))
-                continue;
-            String s = null;
-            s = defineForStatic(clazz, v);
-            if (s != null) {
-                pw.println(s);
+            for (VariableElement v: classfields) {
+                if (!v.getModifiers().contains(Modifier.STATIC))
+                    continue;
+                String s = null;
+                s = defineForStatic(clazz, v);
+                if (s != null) {
+                    pw.println(s);
+                }
             }
-        }
 
-        /* Write methods. */
-        List<ExecutableElement> classmethods = ElementFilter.methodsIn(clazz.getEnclosedElements());
-        for (ExecutableElement md: classmethods) {
-            if(md.getModifiers().contains(Modifier.NATIVE)){
-                TypeMirror mtr = types.erasure(md.getReturnType());
-                String sig = signature(md);
-                TypeSignature newtypesig = new TypeSignature(elems);
-                CharSequence methodName = md.getSimpleName();
-                boolean longName = false;
-                for (ExecutableElement md2: classmethods) {
-                    if ((md2 != md)
-                        && (methodName.equals(md2.getSimpleName()))
-                        && (md2.getModifiers().contains(Modifier.NATIVE)))
-                        longName = true;
+            /* Write methods. */
+            List<ExecutableElement> classmethods = ElementFilter.methodsIn(clazz.getEnclosedElements());
+            for (ExecutableElement md: classmethods) {
+                if(md.getModifiers().contains(Modifier.NATIVE)){
+                    TypeMirror mtr = types.erasure(md.getReturnType());
+                    String sig = signature(md);
+                    TypeSignature newtypesig = new TypeSignature(elems);
+                    CharSequence methodName = md.getSimpleName();
+                    boolean longName = false;
+                    for (ExecutableElement md2: classmethods) {
+                        if ((md2 != md)
+                            && (methodName.equals(md2.getSimpleName()))
+                            && (md2.getModifiers().contains(Modifier.NATIVE)))
+                            longName = true;
 
+                    }
+                    pw.println("/*");
+                    pw.println(" * Class:     " + cname);
+                    pw.println(" * Method:    " +
+                               mangler.mangle(methodName, Mangle.Type.FIELDSTUB));
+                    pw.println(" * Signature: " + newtypesig.getTypeSignature(sig, mtr));
+                    pw.println(" */");
+                    pw.println("JNIEXPORT " + jniType(mtr) +
+                               " JNICALL " +
+                               mangler.mangleMethod(md, clazz,
+                                                   (longName) ?
+                                                   Mangle.Type.METHOD_JNI_LONG :
+                                                   Mangle.Type.METHOD_JNI_SHORT));
+                    pw.print("  (JNIEnv *, ");
+                    List<? extends VariableElement> paramargs = md.getParameters();
+                    List<TypeMirror> args = new ArrayList<TypeMirror>();
+                    for (VariableElement p: paramargs) {
+                        args.add(types.erasure(p.asType()));
+                    }
+                    if (md.getModifiers().contains(Modifier.STATIC))
+                        pw.print("jclass");
+                    else
+                        pw.print("jobject");
+
+                    for (TypeMirror arg: args) {
+                        pw.print(", ");
+                        pw.print(jniType(arg));
+                    }
+                    pw.println(");" + lineSep);
                 }
-                pw.println("/*");
-                pw.println(" * Class:     " + cname);
-                pw.println(" * Method:    " +
-                           mangler.mangle(methodName, Mangle.Type.FIELDSTUB));
-                pw.println(" * Signature: " + newtypesig.getTypeSignature(sig, mtr));
-                pw.println(" */");
-                pw.println("JNIEXPORT " + jniType(mtr) +
-                           " JNICALL " +
-                           mangler.mangleMethod(md, clazz,
-                                               (longName) ?
-                                               Mangle.Type.METHOD_JNI_LONG :
-                                               Mangle.Type.METHOD_JNI_SHORT));
-                pw.print("  (JNIEnv *, ");
-                List<? extends VariableElement> paramargs = md.getParameters();
-                List<TypeMirror> args = new ArrayList<TypeMirror>();
-                for (VariableElement p: paramargs) {
-                    args.add(types.erasure(p.asType()));
-                }
-                if (md.getModifiers().contains(Modifier.STATIC))
-                    pw.print("jclass");
-                else
-                    pw.print("jobject");
-
-                for (TypeMirror arg: args) {
-                    pw.print(", ");
-                    pw.print(jniType(arg));
-                }
-                pw.println(");" + lineSep);
             }
+            pw.println(cppGuardEnd());
+            pw.println(guardEnd(cname));
+        } catch (TypeSignature.SignatureException e) {
+            util.error("jni.sigerror", e.getMessage());
         }
-        pw.println(cppGuardEnd());
-        pw.println(guardEnd(cname));
     }
 
 
--- a/langtools/src/share/classes/com/sun/tools/javah/JavahTask.java	Tue Oct 12 13:15:46 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javah/JavahTask.java	Tue Oct 12 13:19:47 2010 -0700
@@ -46,9 +46,9 @@
 
 import javax.annotation.processing.AbstractProcessor;
 import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
 import javax.annotation.processing.RoundEnvironment;
 import javax.annotation.processing.SupportedAnnotationTypes;
-import javax.annotation.processing.SupportedSourceVersion;
 
 import javax.lang.model.SourceVersion;
 import javax.lang.model.element.ExecutableElement;
@@ -71,6 +71,9 @@
 import javax.tools.StandardJavaFileManager;
 import javax.tools.StandardLocation;
 import javax.tools.ToolProvider;
+import static javax.tools.Diagnostic.Kind.*;
+
+import com.sun.tools.javac.code.Symbol.CompletionFailure;
 
 /**
  * Javah generates support files for native methods.
@@ -233,6 +236,15 @@
                 task.doubleAlign = true;
             }
         },
+
+        new HiddenOption(false) {
+            boolean matches(String opt) {
+                return opt.startsWith("-XD");
+            }
+            void process(JavahTask task, String opt, String arg) {
+                task.javac_extras.add(opt);
+            }
+        },
     };
 
     JavahTask() {
@@ -326,6 +338,8 @@
         } catch (InternalError e) {
             diagnosticListener.report(createDiagnostic("err.internal.error", e.getMessage()));
             return 1;
+        } catch (Util.Exit e) {
+            return e.exitValue;
         } finally {
             log.flush();
         }
@@ -475,7 +489,9 @@
             ((JavahFileManager) fileManager).setIgnoreSymbolFile(true);
 
         JavaCompiler c = ToolProvider.getSystemJavaCompiler();
-        List<String> opts = Arrays.asList("-proc:only");
+        List<String> opts = new ArrayList<String>();
+        opts.add("-proc:only");
+        opts.addAll(javac_extras);
         CompilationTask t = c.getTask(log, fileManager, diagnosticListener, opts, internalize(classes), null);
         JavahProcessor p = new JavahProcessor(g);
         t.setProcessors(Collections.singleton(p));
@@ -642,6 +658,7 @@
     boolean doubleAlign;
     boolean force;
     boolean old;
+    Set<String> javac_extras = new LinkedHashSet<String>();
 
     PrintWriter log;
     JavaFileManager fileManager;
@@ -652,30 +669,45 @@
     private static final String progname = "javah";
 
     @SupportedAnnotationTypes("*")
-    @SupportedSourceVersion(SourceVersion.RELEASE_7)
     class JavahProcessor extends AbstractProcessor {
+        private Messager messager;
+
         JavahProcessor(Gen g) {
             this.g = g;
         }
 
-        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
-            Messager messager  = processingEnv.getMessager();
-            Set<TypeElement> classes = getAllClasses(ElementFilter.typesIn(roundEnv.getRootElements()));
-            if (classes.size() > 0) {
-                checkMethodParameters(classes);
-                g.setProcessingEnvironment(processingEnv);
-                g.setClasses(classes);
+        @Override
+        public SourceVersion getSupportedSourceVersion() {
+            // since this is co-bundled with javac, we can assume it supports
+            // the latest source version
+            return SourceVersion.latest();
+        }
+
+        @Override
+        public void init(ProcessingEnvironment pEnv) {
+            super.init(pEnv);
+            messager  = processingEnv.getMessager();
+        }
 
-                try {
+        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+            try {
+                Set<TypeElement> classes = getAllClasses(ElementFilter.typesIn(roundEnv.getRootElements()));
+                if (classes.size() > 0) {
+                    checkMethodParameters(classes);
+                    g.setProcessingEnvironment(processingEnv);
+                    g.setClasses(classes);
                     g.run();
-                } catch (ClassNotFoundException cnfe) {
-                    messager.printMessage(Diagnostic.Kind.ERROR, getMessage("class.not.found", cnfe.getMessage()));
-                } catch (IOException ioe) {
-                    messager.printMessage(Diagnostic.Kind.ERROR, getMessage("io.exception", ioe.getMessage()));
-                } catch (Util.Exit e) {
-                    exit = e;
                 }
+            } catch (CompletionFailure cf) {
+                messager.printMessage(ERROR, getMessage("class.not.found", cf.sym.getQualifiedName().toString()));
+            } catch (ClassNotFoundException cnfe) {
+                messager.printMessage(ERROR, getMessage("class.not.found", cnfe.getMessage()));
+            } catch (IOException ioe) {
+                messager.printMessage(ERROR, getMessage("io.exception", ioe.getMessage()));
+            } catch (Util.Exit e) {
+                exit = e;
             }
+
             return true;
         }
 
--- a/langtools/src/share/classes/com/sun/tools/javah/LLNI.java	Tue Oct 12 13:15:46 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javah/LLNI.java	Tue Oct 12 13:19:47 2010 -0700
@@ -74,16 +74,21 @@
     }
 
     protected void write(OutputStream o, TypeElement clazz) throws Util.Exit {
-        String cname     = mangleClassName(clazz.getQualifiedName().toString());
-        PrintWriter pw   = wrapWriter(o);
-        fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
-        methods = ElementFilter.methodsIn(clazz.getEnclosedElements());
-        generateDeclsForClass(pw, clazz, cname);
-        // FIXME check if errors occurred on the PrintWriter and throw exception if so
+        try {
+            String cname     = mangleClassName(clazz.getQualifiedName().toString());
+            PrintWriter pw   = wrapWriter(o);
+            fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
+            methods = ElementFilter.methodsIn(clazz.getEnclosedElements());
+            generateDeclsForClass(pw, clazz, cname);
+            // FIXME check if errors occurred on the PrintWriter and throw exception if so
+        } catch (TypeSignature.SignatureException e) {
+            util.error("llni.sigerror", e.getMessage());
+        }
     }
 
     protected void generateDeclsForClass(PrintWriter pw,
-            TypeElement clazz, String cname) throws Util.Exit {
+            TypeElement clazz, String cname)
+            throws TypeSignature.SignatureException, Util.Exit {
         doneHandleTypes  = new HashSet<String>();
         /* The following handle types are predefined in "typedefs.h". Suppress
            inclusion in the output by generating them "into the blue" here. */
@@ -127,7 +132,8 @@
             .replace(innerDelim, '_');
     }
 
-    protected void forwardDecls(PrintWriter pw, TypeElement clazz) {
+    protected void forwardDecls(PrintWriter pw, TypeElement clazz)
+            throws TypeSignature.SignatureException {
         TypeElement object = elems.getTypeElement("java.lang.Object");
         if (clazz.equals(object))
             return;
@@ -403,7 +409,7 @@
 
     protected void methodSectionForClass(PrintWriter pw,
             TypeElement clazz, String cname)
-            throws Util.Exit {
+            throws TypeSignature.SignatureException, Util.Exit {
         String methods = methodDecls(clazz, cname);
 
         if (methods.length() != 0) {
@@ -418,7 +424,8 @@
         }
     }
 
-    protected String methodDecls(TypeElement clazz, String cname) throws Util.Exit {
+    protected String methodDecls(TypeElement clazz, String cname)
+            throws TypeSignature.SignatureException, Util.Exit {
 
         String res = "";
         for (ExecutableElement method: methods) {
@@ -430,7 +437,7 @@
 
     protected String methodDecl(ExecutableElement method,
                                 TypeElement clazz, String cname)
-    throws Util.Exit {
+            throws TypeSignature.SignatureException, Util.Exit {
         String res = null;
 
         TypeMirror retType = types.erasure(method.getReturnType());
@@ -474,7 +481,8 @@
     }
 
     protected final String jniMethodName(ExecutableElement method, String cname,
-                                         boolean longName) {
+                                         boolean longName)
+                throws TypeSignature.SignatureException {
         String res = "Java_" + cname + "_" + method.getSimpleName();
 
         if (longName) {
--- a/langtools/src/share/classes/com/sun/tools/javah/Mangle.java	Tue Oct 12 13:15:46 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javah/Mangle.java	Tue Oct 12 13:19:47 2010 -0700
@@ -114,7 +114,7 @@
     }
 
     public String mangleMethod(ExecutableElement method, TypeElement clazz,
-                                      int mtype) {
+                                      int mtype) throws TypeSignature.SignatureException {
         StringBuffer result = new StringBuffer(100);
         result.append("Java_");
 
--- a/langtools/src/share/classes/com/sun/tools/javah/TypeSignature.java	Tue Oct 12 13:15:46 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javah/TypeSignature.java	Tue Oct 12 13:19:47 2010 -0700
@@ -51,7 +51,13 @@
  * @author Sucheta Dambalkar
  */
 
-public class TypeSignature{
+public class TypeSignature {
+    static class SignatureException extends Exception {
+        private static final long serialVersionUID = 1L;
+        SignatureException(String reason) {
+            super(reason);
+        }
+    }
 
     Elements elems;
 
@@ -78,14 +84,15 @@
     /*
      * Returns the type signature of a field according to JVM specs
      */
-    public String getTypeSignature(String javasignature){
+    public String getTypeSignature(String javasignature) throws SignatureException {
         return getParamJVMSignature(javasignature);
     }
 
     /*
      * Returns the type signature of a method according to JVM specs
      */
-    public String getTypeSignature(String javasignature, TypeMirror returnType){
+    public String getTypeSignature(String javasignature, TypeMirror returnType)
+            throws SignatureException {
         String signature = null; //Java type signature.
         String typeSignature = null; //Internal type signature.
         List<String> params = new ArrayList<String>(); //List of parameters.
@@ -166,7 +173,7 @@
     /*
      * Returns internal signature of a parameter.
      */
-    private String getParamJVMSignature(String paramsig) {
+    private String getParamJVMSignature(String paramsig) throws SignatureException {
         String paramJVMSig = "";
         String componentType ="";
 
@@ -197,7 +204,7 @@
     /*
      * Returns internal signature of a component.
      */
-    private String getComponentType(String componentType){
+    private String getComponentType(String componentType) throws SignatureException {
 
         String JVMSig = "";
 
@@ -216,8 +223,7 @@
                     TypeElement classNameDoc = elems.getTypeElement(componentType);
 
                     if(classNameDoc == null){
-                        System.out.println("Invalid class type for " + componentType);
-                        new Exception().printStackTrace();
+                        throw new SignatureException(componentType);
                     }else {
                         String classname = classNameDoc.getQualifiedName().toString();
                         String newclassname = classname.replace('.', '/');
--- a/langtools/src/share/classes/com/sun/tools/javah/resources/l10n.properties	Tue Oct 12 13:15:46 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javah/resources/l10n.properties	Tue Oct 12 13:19:47 2010 -0700
@@ -45,6 +45,8 @@
         Can''t mix options -jni and -llni.  Try -help.
 jni.no.stubs=\
         JNI does not require stubs, please refer to the JNI documentation.
+jni.sigerror=\
+        Cannot determine signature for {0}
 dir.file.mixed=\
         Can''t mix options -d and -o.  Try -help.
 no.classes.specified=\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javah/4942232/ParamClassTest.java	Tue Oct 12 13:19:47 2010 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public class ParamClassTest {
+    static {
+        System.loadLibrary("Test");
+    }
+
+    public native void method(Param s);
+
+    public static void main(String[] a) {
+    }
+}
+
+class Param {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javah/4942232/Test.java	Tue Oct 12 13:19:47 2010 -0700
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 4942232
+ * @summary missing param class processes without error
+ * @build ParamClassTest Test
+ * @run main Test
+ */
+
+import java.io.*;
+import java.util.*;
+
+public class Test {
+    public static void main(String... args) throws Exception {
+        new Test().run();
+    }
+
+    void run() throws Exception {
+        File testSrc = new File(System.getProperty("test.src"));
+        File testClasses = new File(System.getProperty("test.classes"));
+
+        // standard use of javah on valid class file
+        String[] test1Args = {
+            "-d", mkdir("test1/out").getPath(),
+            "-classpath", testClasses.getPath(),
+            "ParamClassTest"
+        };
+        test(test1Args, 0);
+
+        // extended use of javah on valid source file
+        String[] test2Args = {
+            "-d", mkdir("test2/out").getPath(),
+            "-classpath", testSrc.getPath(),
+            "ParamClassTest"
+        };
+        test(test2Args, 0);
+
+        // javah on class file with missing referents
+        File test3Classes = mkdir("test3/classes");
+        copy(new File(testClasses, "ParamClassTest.class"), test3Classes);
+        String[] test3Args = {
+            "-d", mkdir("test3/out").getPath(),
+            "-classpath", test3Classes.getPath(),
+            "ParamClassTest"
+        };
+        test(test3Args, 1);
+
+        // javah on source file with missing referents
+        File test4Src = mkdir("test4/src");
+        String paramClassTestSrc = readFile(new File(testSrc, "ParamClassTest.java"));
+        writeFile(new File(test4Src, "ParamClassTest.java"),
+                paramClassTestSrc.replaceAll("class Param \\{\\s+\\}", ""));
+        String[] test4Args = {
+            "-d", mkdir("test4/out").getPath(),
+            "-classpath", test4Src.getPath(),
+            "ParamClassTest"
+        };
+        test(test4Args, 15);
+
+        if (errors > 0)
+            throw new Exception(errors + " errors occurred");
+    }
+
+    void test(String[] args, int expect) {
+        System.err.println("test: " + Arrays.asList(args));
+        int rc = javah(args);
+        if (rc != expect)
+            error("Unexpected return code: " + rc + "; expected: " + expect);
+    }
+
+    int javah(String... args) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javah.Main.run(args, pw);
+        pw.close();
+        String out = sw.toString();
+        if (!out.isEmpty())
+            System.err.println(out);
+        return rc;
+    }
+
+    File mkdir(String path) {
+        File f = new File(path);
+        f.mkdirs();
+        return f;
+    }
+
+    void copy(File from, File to) throws IOException {
+        if (to.isDirectory())
+            to = new File(to, from.getName());
+        try (DataInputStream in = new DataInputStream(new FileInputStream(from));
+                FileOutputStream out = new FileOutputStream(to)) {
+            byte[] buf = new byte[(int) from.length()];
+            in.readFully(buf);
+            out.write(buf);
+        }
+    }
+
+    String readFile(File f) throws IOException {
+        try (DataInputStream in = new DataInputStream(new FileInputStream(f))) {
+            byte[] buf = new byte[(int) f.length()];
+            in.readFully(buf);
+            return new String(buf);
+        }
+    }
+
+    void writeFile(File f, String body) throws IOException {
+        try (FileWriter out = new FileWriter(f)) {
+            out.write(body);
+        }
+    }
+
+    void error(String msg) {
+        System.err.println(msg);
+        errors++;
+    }
+
+    int errors;
+}