6999210: javac should be able to warn of anomalous conditions in classfiles

Tue, 07 Dec 2010 14:13:25 -0800

author
jjg
date
Tue, 07 Dec 2010 14:13:25 -0800
changeset 776
3c32c90031fd
parent 775
536ee9f126b1
child 777
acb02e1d5119

6999210: javac should be able to warn of anomalous conditions in classfiles
Reviewed-by: mcimadamore, darcy

src/share/classes/com/sun/tools/javac/code/Lint.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/jvm/ClassReader.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/resources/compiler.properties file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java file | annotate | diff | comparison | revisions
test/tools/javac/T6999210.java file | annotate | diff | comparison | revisions
test/tools/javac/annotations/6214965/T6214965.out file | annotate | diff | comparison | revisions
test/tools/javac/annotations/6365854/test1.out file | annotate | diff | comparison | revisions
test/tools/javac/annotations/6365854/test2.out file | annotate | diff | comparison | revisions
test/tools/javac/diags/examples.not-yet.txt file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/code/Lint.java	Mon Dec 06 11:51:02 2010 +0000
     1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Lint.java	Tue Dec 07 14:13:25 2010 -0800
     1.3 @@ -134,6 +134,11 @@
     1.4          CAST("cast"),
     1.5  
     1.6          /**
     1.7 +         * Warn about issues related to classfile contents
     1.8 +         */
     1.9 +        CLASSFILE("classfile"),
    1.10 +
    1.11 +        /**
    1.12           * Warn about use of deprecated items.
    1.13           */
    1.14          DEPRECATION("deprecation"),
     2.1 --- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Mon Dec 06 11:51:02 2010 +0000
     2.2 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Tue Dec 07 14:13:25 2010 -0800
     2.3 @@ -32,6 +32,7 @@
     2.4  import java.util.Arrays;
     2.5  import java.util.EnumSet;
     2.6  import java.util.HashMap;
     2.7 +import java.util.HashSet;
     2.8  import java.util.Map;
     2.9  import java.util.Set;
    2.10  import javax.lang.model.SourceVersion;
    2.11 @@ -44,11 +45,13 @@
    2.12  
    2.13  import com.sun.tools.javac.comp.Annotate;
    2.14  import com.sun.tools.javac.code.*;
    2.15 +import com.sun.tools.javac.code.Lint.LintCategory;
    2.16  import com.sun.tools.javac.code.Type.*;
    2.17  import com.sun.tools.javac.code.Symbol.*;
    2.18  import com.sun.tools.javac.code.Symtab;
    2.19  import com.sun.tools.javac.file.BaseFileObject;
    2.20  import com.sun.tools.javac.util.*;
    2.21 +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    2.22  
    2.23  import static com.sun.tools.javac.code.Flags.*;
    2.24  import static com.sun.tools.javac.code.Kinds.*;
    2.25 @@ -102,6 +105,10 @@
    2.26       */
    2.27      boolean allowAnnotations;
    2.28  
    2.29 +    /** Lint option: warn about classfile issues
    2.30 +     */
    2.31 +    boolean lintClassfile;
    2.32 +
    2.33      /** Switch: preserve parameter names from the variable table.
    2.34       */
    2.35      public boolean saveParameterNames;
    2.36 @@ -207,6 +214,11 @@
    2.37       */
    2.38      boolean haveParameterNameIndices;
    2.39  
    2.40 +    /**
    2.41 +     * The set of attribute names for which warnings have been generated for the current class
    2.42 +     */
    2.43 +    Set<Name> warnedAttrs = new HashSet<Name>();
    2.44 +
    2.45      /** Get the ClassReader instance for this invocation. */
    2.46      public static ClassReader instance(Context context) {
    2.47          ClassReader instance = context.get(classReaderKey);
    2.48 @@ -279,6 +291,8 @@
    2.49          typevars = new Scope(syms.noSymbol);
    2.50          debugJSR308 = options.isSet("TA:reader");
    2.51  
    2.52 +        lintClassfile = Lint.instance(context).isEnabled(LintCategory.CLASSFILE);
    2.53 +
    2.54          initAttributeReaders();
    2.55      }
    2.56  
    2.57 @@ -870,7 +884,22 @@
    2.58          }
    2.59  
    2.60          boolean accepts(AttributeKind kind) {
    2.61 -            return kinds.contains(kind) && majorVersion >= version.major;
    2.62 +            if (kinds.contains(kind)) {
    2.63 +                if (majorVersion > version.major || (majorVersion == version.major && minorVersion >= version.minor))
    2.64 +                    return true;
    2.65 +
    2.66 +                if (lintClassfile && !warnedAttrs.contains(name)) {
    2.67 +                    JavaFileObject prev = log.useSource(currentClassFile);
    2.68 +                    try {
    2.69 +                        log.warning(LintCategory.CLASSFILE, (DiagnosticPosition) null, "future.attr",
    2.70 +                                name, version.major, version.minor, majorVersion, minorVersion);
    2.71 +                    } finally {
    2.72 +                        log.useSource(prev);
    2.73 +                    }
    2.74 +                    warnedAttrs.add(name);
    2.75 +                }
    2.76 +            }
    2.77 +            return false;
    2.78          }
    2.79  
    2.80          abstract void read(Symbol sym, int attrLen);
    2.81 @@ -889,7 +918,7 @@
    2.82  
    2.83      protected Map<Name, AttributeReader> attributeReaders = new HashMap<Name, AttributeReader>();
    2.84  
    2.85 -    protected void initAttributeReaders() {
    2.86 +    private void initAttributeReaders() {
    2.87          AttributeReader[] readers = {
    2.88              // v45.3 attributes
    2.89  
    2.90 @@ -1561,7 +1590,7 @@
    2.91          public void accept(Visitor v) { ((ProxyVisitor)v).visitCompoundAnnotationProxy(this); }
    2.92          @Override
    2.93          public String toString() {
    2.94 -            StringBuffer buf = new StringBuffer();
    2.95 +            StringBuilder buf = new StringBuilder();
    2.96              buf.append("@");
    2.97              buf.append(type.tsym.getQualifiedName());
    2.98              buf.append("/*proxy*/{");
    2.99 @@ -2286,6 +2315,7 @@
   2.100              throw new CompletionFailure(c, "user-selected completion failure by class name");
   2.101          }
   2.102          currentOwner = c;
   2.103 +        warnedAttrs.clear();
   2.104          JavaFileObject classfile = c.classfile;
   2.105          if (classfile != null) {
   2.106              JavaFileObject previousClassFile = currentClassFile;
     3.1 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Dec 06 11:51:02 2010 +0000
     3.2 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Dec 07 14:13:25 2010 -0800
     3.3 @@ -767,6 +767,9 @@
     3.4  compiler.warn.source.no.bootclasspath=\
     3.5      bootstrap class path not set in conjunction with -source {0}
     3.6  
     3.7 +compiler.warn.future.attr=\
     3.8 +    {0} attribute introduced in version {1}.{2} class files is ignored in version {3}.{4} class files
     3.9 +
    3.10  # Warnings related to annotation processing
    3.11  compiler.warn.proc.package.does.not.exist=\
    3.12      package {0} does not exist
     4.1 --- a/src/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java	Mon Dec 06 11:51:02 2010 +0000
     4.2 +++ b/src/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java	Tue Dec 07 14:13:25 2010 -0800
     4.3 @@ -27,6 +27,7 @@
     4.4  import java.util.Collection;
     4.5  import java.util.EnumSet;
     4.6  import java.util.Locale;
     4.7 +import javax.tools.JavaFileObject;
     4.8  
     4.9  import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.*;
    4.10  import com.sun.tools.javac.api.Formattable;
    4.11 @@ -62,7 +63,7 @@
    4.12      //provide common default formats
    4.13      public String formatDiagnostic(JCDiagnostic d, Locale l) {
    4.14          try {
    4.15 -            StringBuffer buf = new StringBuffer();
    4.16 +            StringBuilder buf = new StringBuilder();
    4.17              if (d.getPosition() != Position.NOPOS) {
    4.18                  buf.append(formatSource(d, false, null));
    4.19                  buf.append(':');
    4.20 @@ -71,16 +72,22 @@
    4.21                  buf.append(formatPosition(d, COLUMN, null));
    4.22                  buf.append(':');
    4.23              }
    4.24 +            else if (d.getSource() != null && d.getSource().getKind() == JavaFileObject.Kind.CLASS) {
    4.25 +                buf.append(formatSource(d, false, null));
    4.26 +                buf.append(":-:-:");
    4.27 +            }
    4.28              else
    4.29                  buf.append('-');
    4.30              buf.append(' ');
    4.31              buf.append(formatMessage(d, null));
    4.32 -            if (displaySource(d))
    4.33 -                buf.append("\n" + formatSourceLine(d, 0));
    4.34 +            if (displaySource(d)) {
    4.35 +                buf.append("\n");
    4.36 +                buf.append(formatSourceLine(d, 0));
    4.37 +            }
    4.38              return buf.toString();
    4.39          }
    4.40          catch (Exception e) {
    4.41 -            e.printStackTrace();
    4.42 +            //e.printStackTrace();
    4.43              return null;
    4.44          }
    4.45      }
    4.46 @@ -96,7 +103,9 @@
    4.47                  buf.append(",{");
    4.48                  for (String sub : formatSubdiagnostics(d, null)) {
    4.49                      buf.append(sep);
    4.50 -                    buf.append("(" + sub + ")");
    4.51 +                    buf.append("(");
    4.52 +                    buf.append(sub);
    4.53 +                    buf.append(")");
    4.54                      sep = ",";
    4.55                  }
    4.56                  buf.append('}');
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/tools/javac/T6999210.java	Tue Dec 07 14:13:25 2010 -0800
     5.3 @@ -0,0 +1,124 @@
     5.4 +/*
     5.5 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
     5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 + *
     5.8 + * This code is free software; you can redistribute it and/or modify it
     5.9 + * under the terms of the GNU General Public License version 2 only, as
    5.10 + * published by the Free Software Foundation.
    5.11 + *
    5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.15 + * version 2 for more details (a copy is included in the LICENSE file that
    5.16 + * accompanied this code).
    5.17 + *
    5.18 + * You should have received a copy of the GNU General Public License version
    5.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.21 + *
    5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.23 + * or visit www.oracle.com if you need additional information or have any
    5.24 + * questions.
    5.25 + */
    5.26 +
    5.27 +/*
    5.28 + * @test
    5.29 + * @bug 6999210
    5.30 + * @summary javac should be able to warn of anomalous conditions in classfiles
    5.31 + */
    5.32 +
    5.33 +import java.io.*;
    5.34 +import java.util.*;
    5.35 +
    5.36 +public class T6999210 {
    5.37 +    public static void main(String... args) throws Exception {
    5.38 +        new T6999210().run();
    5.39 +    }
    5.40 +
    5.41 +    void run() throws Exception {
    5.42 +        File srcDir = new File("src");
    5.43 +        File classesDir = new File("classes");
    5.44 +        classesDir.mkdirs();
    5.45 +
    5.46 +        File c_java = writeFile(srcDir, "C.java", "class C<T> { }");
    5.47 +        compile("-d", classesDir.getPath(), c_java.getPath());
    5.48 +        File c_class = new File(classesDir, "C.class");
    5.49 +        setMajorVersion(c_class, 48);
    5.50 +        File d_java = writeFile(srcDir, "D.java", "class D { C c; }");
    5.51 +
    5.52 +        // verify no warning if -Xlint:classfile not enabled
    5.53 +        String out1 = compile(
    5.54 +            "-d", classesDir.getPath(),
    5.55 +            "-classpath", classesDir.getPath(),
    5.56 +            d_java.getPath());
    5.57 +        if (out1.length() > 0)
    5.58 +            error("unexpected output from javac");
    5.59 +
    5.60 +        // sanity check of warning when -XDrawDiagnostics not used
    5.61 +        String out2 = compile(
    5.62 +            "-d", classesDir.getPath(),
    5.63 +            "-classpath", classesDir.getPath(),
    5.64 +            "-Xlint:classfile",
    5.65 +            d_java.getPath());
    5.66 +        if (!out2.contains("[classfile]"))
    5.67 +            error("expected output \"[classfile]\" not found");
    5.68 +
    5.69 +        // check specific details, using -XDrawDiagnostics
    5.70 +        String out3 = compile(
    5.71 +            "-d", classesDir.getPath(),
    5.72 +            "-classpath", classesDir.getPath(),
    5.73 +            "-Xlint:classfile", "-XDrawDiagnostics",
    5.74 +            d_java.getPath());
    5.75 +        String expect = "C.class:-:-: compiler.warn.future.attr: Signature, 49, 0, 48, 0";
    5.76 +        if (!out3.contains(expect))
    5.77 +            error("expected output \"" + expect + "\" not found");
    5.78 +
    5.79 +        if (errors > 0)
    5.80 +            throw new Exception(errors + " errors occurred");
    5.81 +    }
    5.82 +
    5.83 +    String compile(String... args) throws Exception {
    5.84 +        System.err.println("compile: " + Arrays.asList(args));
    5.85 +        StringWriter sw = new StringWriter();
    5.86 +        PrintWriter pw = new PrintWriter(sw);
    5.87 +        int rc = com.sun.tools.javac.Main.compile(args, pw);
    5.88 +        pw.close();
    5.89 +        String out = sw.toString();
    5.90 +        if (out.length() > 0)
    5.91 +            System.err.println(out);
    5.92 +        if (rc != 0)
    5.93 +            throw new Exception("compilation failed, rc=" + rc);
    5.94 +        return out;
    5.95 +    }
    5.96 +
    5.97 +    void setMajorVersion(File f, int major) throws IOException {
    5.98 +        int len = (int) f.length();
    5.99 +        byte[] data = new byte[len];
   5.100 +        try (DataInputStream in = new DataInputStream(new FileInputStream(f))) {
   5.101 +            in.readFully(data);
   5.102 +        }
   5.103 +        // u4 magic
   5.104 +        // u2 minor
   5.105 +        data[6] = (byte) (major >> 8);
   5.106 +        data[7] = (byte) (major & 0xff);
   5.107 +        try (FileOutputStream out = new FileOutputStream(f)) {
   5.108 +            out.write(data);
   5.109 +        }
   5.110 +    }
   5.111 +
   5.112 +    File writeFile(File dir, String path, String body) throws IOException {
   5.113 +        File f = new File(dir, path);
   5.114 +        f.getParentFile().mkdirs();
   5.115 +        try (FileWriter out = new FileWriter(f)) {
   5.116 +            out.write(body);
   5.117 +        }
   5.118 +        return f;
   5.119 +    }
   5.120 +
   5.121 +    void error(String msg) {
   5.122 +        System.err.println("Error: " + msg);
   5.123 +        errors++;
   5.124 +    }
   5.125 +
   5.126 +    int errors;
   5.127 +}
     6.1 --- a/test/tools/javac/annotations/6214965/T6214965.out	Mon Dec 06 11:51:02 2010 +0000
     6.2 +++ b/test/tools/javac/annotations/6214965/T6214965.out	Tue Dec 07 14:13:25 2010 -0800
     6.3 @@ -1,2 +1,2 @@
     6.4 -- compiler.warn.annotation.method.not.found: CompilerAnnotationTest2, name2
     6.5 +CompilerAnnotationTest.class:-:-: compiler.warn.annotation.method.not.found: CompilerAnnotationTest2, name2
     6.6  1 warning
     7.1 --- a/test/tools/javac/annotations/6365854/test1.out	Mon Dec 06 11:51:02 2010 +0000
     7.2 +++ b/test/tools/javac/annotations/6365854/test1.out	Tue Dec 07 14:13:25 2010 -0800
     7.3 @@ -1,2 +1,2 @@
     7.4 -- compiler.warn.annotation.method.not.found.reason: test.annotation.TestAnnotation, test, (compiler.misc.class.file.not.found: test.annotation.TestAnnotation)
     7.5 +TestCore.class:-:-: compiler.warn.annotation.method.not.found.reason: test.annotation.TestAnnotation, test, (compiler.misc.class.file.not.found: test.annotation.TestAnnotation)
     7.6  1 warning
     8.1 --- a/test/tools/javac/annotations/6365854/test2.out	Mon Dec 06 11:51:02 2010 +0000
     8.2 +++ b/test/tools/javac/annotations/6365854/test2.out	Tue Dec 07 14:13:25 2010 -0800
     8.3 @@ -1,2 +1,2 @@
     8.4 -- compiler.warn.annotation.method.not.found: test.annotation.TestAnnotation, test
     8.5 +TestCore.class:-:-: compiler.warn.annotation.method.not.found: test.annotation.TestAnnotation, test
     8.6  1 warning
     9.1 --- a/test/tools/javac/diags/examples.not-yet.txt	Mon Dec 06 11:51:02 2010 +0000
     9.2 +++ b/test/tools/javac/diags/examples.not-yet.txt	Tue Dec 07 14:13:25 2010 -0800
     9.3 @@ -104,6 +104,7 @@
     9.4  compiler.warn.annotation.method.not.found               # ClassReader
     9.5  compiler.warn.annotation.method.not.found.reason        # ClassReader
     9.6  compiler.warn.big.major.version                         # ClassReader
     9.7 +compiler.warn.future.attr                               # ClassReader
     9.8  compiler.warn.illegal.char.for.encoding
     9.9  compiler.warn.invalid.archive.file
    9.10  compiler.warn.override.bridge

mercurial