# HG changeset patch # User jjg # Date 1291760005 28800 # Node ID 3c32c90031fd5f82eb7e189c0556b944cf07c2fc # Parent 536ee9f126b12c6fd38d364db870f110bfcd6476 6999210: javac should be able to warn of anomalous conditions in classfiles Reviewed-by: mcimadamore, darcy diff -r 536ee9f126b1 -r 3c32c90031fd src/share/classes/com/sun/tools/javac/code/Lint.java --- a/src/share/classes/com/sun/tools/javac/code/Lint.java Mon Dec 06 11:51:02 2010 +0000 +++ b/src/share/classes/com/sun/tools/javac/code/Lint.java Tue Dec 07 14:13:25 2010 -0800 @@ -134,6 +134,11 @@ CAST("cast"), /** + * Warn about issues related to classfile contents + */ + CLASSFILE("classfile"), + + /** * Warn about use of deprecated items. */ DEPRECATION("deprecation"), diff -r 536ee9f126b1 -r 3c32c90031fd src/share/classes/com/sun/tools/javac/jvm/ClassReader.java --- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Dec 06 11:51:02 2010 +0000 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Tue Dec 07 14:13:25 2010 -0800 @@ -32,6 +32,7 @@ import java.util.Arrays; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.lang.model.SourceVersion; @@ -44,11 +45,13 @@ import com.sun.tools.javac.comp.Annotate; import com.sun.tools.javac.code.*; +import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.file.BaseFileObject; import com.sun.tools.javac.util.*; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.*; @@ -102,6 +105,10 @@ */ boolean allowAnnotations; + /** Lint option: warn about classfile issues + */ + boolean lintClassfile; + /** Switch: preserve parameter names from the variable table. */ public boolean saveParameterNames; @@ -207,6 +214,11 @@ */ boolean haveParameterNameIndices; + /** + * The set of attribute names for which warnings have been generated for the current class + */ + Set warnedAttrs = new HashSet(); + /** Get the ClassReader instance for this invocation. */ public static ClassReader instance(Context context) { ClassReader instance = context.get(classReaderKey); @@ -279,6 +291,8 @@ typevars = new Scope(syms.noSymbol); debugJSR308 = options.isSet("TA:reader"); + lintClassfile = Lint.instance(context).isEnabled(LintCategory.CLASSFILE); + initAttributeReaders(); } @@ -870,7 +884,22 @@ } boolean accepts(AttributeKind kind) { - return kinds.contains(kind) && majorVersion >= version.major; + if (kinds.contains(kind)) { + if (majorVersion > version.major || (majorVersion == version.major && minorVersion >= version.minor)) + return true; + + if (lintClassfile && !warnedAttrs.contains(name)) { + JavaFileObject prev = log.useSource(currentClassFile); + try { + log.warning(LintCategory.CLASSFILE, (DiagnosticPosition) null, "future.attr", + name, version.major, version.minor, majorVersion, minorVersion); + } finally { + log.useSource(prev); + } + warnedAttrs.add(name); + } + } + return false; } abstract void read(Symbol sym, int attrLen); @@ -889,7 +918,7 @@ protected Map attributeReaders = new HashMap(); - protected void initAttributeReaders() { + private void initAttributeReaders() { AttributeReader[] readers = { // v45.3 attributes @@ -1561,7 +1590,7 @@ public void accept(Visitor v) { ((ProxyVisitor)v).visitCompoundAnnotationProxy(this); } @Override public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append("@"); buf.append(type.tsym.getQualifiedName()); buf.append("/*proxy*/{"); @@ -2286,6 +2315,7 @@ throw new CompletionFailure(c, "user-selected completion failure by class name"); } currentOwner = c; + warnedAttrs.clear(); JavaFileObject classfile = c.classfile; if (classfile != null) { JavaFileObject previousClassFile = currentClassFile; diff -r 536ee9f126b1 -r 3c32c90031fd src/share/classes/com/sun/tools/javac/resources/compiler.properties --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Dec 06 11:51:02 2010 +0000 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Tue Dec 07 14:13:25 2010 -0800 @@ -767,6 +767,9 @@ compiler.warn.source.no.bootclasspath=\ bootstrap class path not set in conjunction with -source {0} +compiler.warn.future.attr=\ + {0} attribute introduced in version {1}.{2} class files is ignored in version {3}.{4} class files + # Warnings related to annotation processing compiler.warn.proc.package.does.not.exist=\ package {0} does not exist diff -r 536ee9f126b1 -r 3c32c90031fd src/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java --- a/src/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java Mon Dec 06 11:51:02 2010 +0000 +++ b/src/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java Tue Dec 07 14:13:25 2010 -0800 @@ -27,6 +27,7 @@ import java.util.Collection; import java.util.EnumSet; import java.util.Locale; +import javax.tools.JavaFileObject; import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.*; import com.sun.tools.javac.api.Formattable; @@ -62,7 +63,7 @@ //provide common default formats public String formatDiagnostic(JCDiagnostic d, Locale l) { try { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); if (d.getPosition() != Position.NOPOS) { buf.append(formatSource(d, false, null)); buf.append(':'); @@ -71,16 +72,22 @@ buf.append(formatPosition(d, COLUMN, null)); buf.append(':'); } + else if (d.getSource() != null && d.getSource().getKind() == JavaFileObject.Kind.CLASS) { + buf.append(formatSource(d, false, null)); + buf.append(":-:-:"); + } else buf.append('-'); buf.append(' '); buf.append(formatMessage(d, null)); - if (displaySource(d)) - buf.append("\n" + formatSourceLine(d, 0)); + if (displaySource(d)) { + buf.append("\n"); + buf.append(formatSourceLine(d, 0)); + } return buf.toString(); } catch (Exception e) { - e.printStackTrace(); + //e.printStackTrace(); return null; } } @@ -96,7 +103,9 @@ buf.append(",{"); for (String sub : formatSubdiagnostics(d, null)) { buf.append(sep); - buf.append("(" + sub + ")"); + buf.append("("); + buf.append(sub); + buf.append(")"); sep = ","; } buf.append('}'); diff -r 536ee9f126b1 -r 3c32c90031fd test/tools/javac/T6999210.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/T6999210.java Tue Dec 07 14:13:25 2010 -0800 @@ -0,0 +1,124 @@ +/* + * 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 6999210 + * @summary javac should be able to warn of anomalous conditions in classfiles + */ + +import java.io.*; +import java.util.*; + +public class T6999210 { + public static void main(String... args) throws Exception { + new T6999210().run(); + } + + void run() throws Exception { + File srcDir = new File("src"); + File classesDir = new File("classes"); + classesDir.mkdirs(); + + File c_java = writeFile(srcDir, "C.java", "class C { }"); + compile("-d", classesDir.getPath(), c_java.getPath()); + File c_class = new File(classesDir, "C.class"); + setMajorVersion(c_class, 48); + File d_java = writeFile(srcDir, "D.java", "class D { C c; }"); + + // verify no warning if -Xlint:classfile not enabled + String out1 = compile( + "-d", classesDir.getPath(), + "-classpath", classesDir.getPath(), + d_java.getPath()); + if (out1.length() > 0) + error("unexpected output from javac"); + + // sanity check of warning when -XDrawDiagnostics not used + String out2 = compile( + "-d", classesDir.getPath(), + "-classpath", classesDir.getPath(), + "-Xlint:classfile", + d_java.getPath()); + if (!out2.contains("[classfile]")) + error("expected output \"[classfile]\" not found"); + + // check specific details, using -XDrawDiagnostics + String out3 = compile( + "-d", classesDir.getPath(), + "-classpath", classesDir.getPath(), + "-Xlint:classfile", "-XDrawDiagnostics", + d_java.getPath()); + String expect = "C.class:-:-: compiler.warn.future.attr: Signature, 49, 0, 48, 0"; + if (!out3.contains(expect)) + error("expected output \"" + expect + "\" not found"); + + if (errors > 0) + throw new Exception(errors + " errors occurred"); + } + + String compile(String... args) throws Exception { + System.err.println("compile: " + Arrays.asList(args)); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(args, pw); + pw.close(); + String out = sw.toString(); + if (out.length() > 0) + System.err.println(out); + if (rc != 0) + throw new Exception("compilation failed, rc=" + rc); + return out; + } + + void setMajorVersion(File f, int major) throws IOException { + int len = (int) f.length(); + byte[] data = new byte[len]; + try (DataInputStream in = new DataInputStream(new FileInputStream(f))) { + in.readFully(data); + } + // u4 magic + // u2 minor + data[6] = (byte) (major >> 8); + data[7] = (byte) (major & 0xff); + try (FileOutputStream out = new FileOutputStream(f)) { + out.write(data); + } + } + + File writeFile(File dir, String path, String body) throws IOException { + File f = new File(dir, path); + f.getParentFile().mkdirs(); + try (FileWriter out = new FileWriter(f)) { + out.write(body); + } + return f; + } + + void error(String msg) { + System.err.println("Error: " + msg); + errors++; + } + + int errors; +} diff -r 536ee9f126b1 -r 3c32c90031fd test/tools/javac/annotations/6214965/T6214965.out --- a/test/tools/javac/annotations/6214965/T6214965.out Mon Dec 06 11:51:02 2010 +0000 +++ b/test/tools/javac/annotations/6214965/T6214965.out Tue Dec 07 14:13:25 2010 -0800 @@ -1,2 +1,2 @@ -- compiler.warn.annotation.method.not.found: CompilerAnnotationTest2, name2 +CompilerAnnotationTest.class:-:-: compiler.warn.annotation.method.not.found: CompilerAnnotationTest2, name2 1 warning diff -r 536ee9f126b1 -r 3c32c90031fd test/tools/javac/annotations/6365854/test1.out --- a/test/tools/javac/annotations/6365854/test1.out Mon Dec 06 11:51:02 2010 +0000 +++ b/test/tools/javac/annotations/6365854/test1.out Tue Dec 07 14:13:25 2010 -0800 @@ -1,2 +1,2 @@ -- compiler.warn.annotation.method.not.found.reason: test.annotation.TestAnnotation, test, (compiler.misc.class.file.not.found: test.annotation.TestAnnotation) +TestCore.class:-:-: compiler.warn.annotation.method.not.found.reason: test.annotation.TestAnnotation, test, (compiler.misc.class.file.not.found: test.annotation.TestAnnotation) 1 warning diff -r 536ee9f126b1 -r 3c32c90031fd test/tools/javac/annotations/6365854/test2.out --- a/test/tools/javac/annotations/6365854/test2.out Mon Dec 06 11:51:02 2010 +0000 +++ b/test/tools/javac/annotations/6365854/test2.out Tue Dec 07 14:13:25 2010 -0800 @@ -1,2 +1,2 @@ -- compiler.warn.annotation.method.not.found: test.annotation.TestAnnotation, test +TestCore.class:-:-: compiler.warn.annotation.method.not.found: test.annotation.TestAnnotation, test 1 warning diff -r 536ee9f126b1 -r 3c32c90031fd test/tools/javac/diags/examples.not-yet.txt --- a/test/tools/javac/diags/examples.not-yet.txt Mon Dec 06 11:51:02 2010 +0000 +++ b/test/tools/javac/diags/examples.not-yet.txt Tue Dec 07 14:13:25 2010 -0800 @@ -104,6 +104,7 @@ compiler.warn.annotation.method.not.found # ClassReader compiler.warn.annotation.method.not.found.reason # ClassReader compiler.warn.big.major.version # ClassReader +compiler.warn.future.attr # ClassReader compiler.warn.illegal.char.for.encoding compiler.warn.invalid.archive.file compiler.warn.override.bridge