Tue, 07 Dec 2010 14:13:25 -0800
6999210: javac should be able to warn of anomalous conditions in classfiles
Reviewed-by: mcimadamore, darcy
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