Mercurial > hg > icedtea7-forest > langtools
changeset 537:ef07347428f2 jdk7-b86
Merge
author | lana |
---|---|
date | Tue, 09 Mar 2010 15:29:45 -0800 |
parents | b816baf594e3 (current diff) a4f3b97c8028 (diff) |
children | 409db93d19c0 6fad35d25b1e |
files | test/tools/javac/treepostests/TreePosTest.java |
diffstat | 61 files changed, 1674 insertions(+), 918 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/apt/comp/Apt.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/apt/comp/Apt.java Tue Mar 09 15:29:45 2010 -0800 @@ -457,8 +457,10 @@ throw new UsageMessageNeededException(); try { - for(AnnotationProcessorFactory apFactory: factoryToAnnotation.keySet()) { - AnnotationProcessor processor = apFactory.getProcessorFor(factoryToAnnotation.get(apFactory), + for(Map.Entry<AnnotationProcessorFactory, Set<AnnotationTypeDeclaration>> entry : + factoryToAnnotation.entrySet()) { + AnnotationProcessorFactory apFactory = entry.getKey(); + AnnotationProcessor processor = apFactory.getProcessorFor(entry.getValue(), trivAPE); if (processor != null) processors.add(processor);
--- a/src/share/classes/com/sun/tools/apt/main/CommandLine.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/apt/main/CommandLine.java Tue Mar 09 15:29:45 2010 -0800 @@ -82,7 +82,7 @@ st.commentChar('#'); st.quoteChar('"'); st.quoteChar('\''); - while (st.nextToken() != st.TT_EOF) { + while (st.nextToken() != StreamTokenizer.TT_EOF) { args.append(st.sval); } r.close();
--- a/src/share/classes/com/sun/tools/apt/mirror/declaration/AnnotationProxyMaker.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/apt/mirror/declaration/AnnotationProxyMaker.java Tue Mar 09 15:29:45 2010 -0800 @@ -270,7 +270,7 @@ * The toString, hashCode, and equals methods foward to the underlying * type. */ - private static class MirroredTypeExceptionProxy extends ExceptionProxy { + private static final class MirroredTypeExceptionProxy extends ExceptionProxy { private static final long serialVersionUID = 6662035281599933545L; private MirroredTypeException ex; @@ -312,7 +312,7 @@ * The toString, hashCode, and equals methods foward to the underlying * types. */ - private static class MirroredTypesExceptionProxy extends ExceptionProxy { + private static final class MirroredTypesExceptionProxy extends ExceptionProxy { private static final long serialVersionUID = -6670822532616693951L; private MirroredTypesException ex;
--- a/src/share/classes/com/sun/tools/apt/mirror/declaration/DeclarationImpl.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/apt/mirror/declaration/DeclarationImpl.java Tue Mar 09 15:29:45 2010 -0800 @@ -58,7 +58,7 @@ protected final AptEnv env; public final Symbol sym; - protected static DeclarationFilter identityFilter = + protected static final DeclarationFilter identityFilter = new DeclarationFilter();
--- a/src/share/classes/com/sun/tools/apt/mirror/type/TypeMirrorImpl.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/apt/mirror/type/TypeMirrorImpl.java Tue Mar 09 15:29:45 2010 -0800 @@ -71,6 +71,6 @@ * {@inheritDoc} */ public int hashCode() { - return env.jctypes.hashCode(type); + return Types.hashCode(type); } }
--- a/src/share/classes/com/sun/tools/classfile/ConstantPool.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/classfile/ConstantPool.java Tue Mar 09 15:29:45 2010 -0800 @@ -40,7 +40,7 @@ */ public class ConstantPool { - public class InvalidIndex extends ConstantPoolException { + public static class InvalidIndex extends ConstantPoolException { private static final long serialVersionUID = -4350294289300939730L; InvalidIndex(int index) { super(index); @@ -53,7 +53,7 @@ } } - public class UnexpectedEntry extends ConstantPoolException { + public static class UnexpectedEntry extends ConstantPoolException { private static final long serialVersionUID = 6986335935377933211L; UnexpectedEntry(int index, int expected_tag, int found_tag) { super(index); @@ -71,7 +71,7 @@ public final int found_tag; } - public class InvalidEntry extends ConstantPoolException { + public static class InvalidEntry extends ConstantPoolException { private static final long serialVersionUID = 1000087545585204447L; InvalidEntry(int index, int tag) { super(index); @@ -87,7 +87,7 @@ public final int tag; } - public class EntryNotFound extends ConstantPoolException { + public static class EntryNotFound extends ConstantPoolException { private static final long serialVersionUID = 2885537606468581850L; EntryNotFound(Object value) { super(-1); @@ -694,7 +694,7 @@ public int byteLength() { class SizeOutputStream extends OutputStream { @Override - public void write(int b) throws IOException { + public void write(int b) { size++; } int size;
--- a/src/share/classes/com/sun/tools/doclets/standard/Standard.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/doclets/standard/Standard.java Tue Mar 09 15:29:45 2010 -0800 @@ -31,23 +31,21 @@ public class Standard { - public static final HtmlDoclet htmlDoclet = new HtmlDoclet(); - public static int optionLength(String option) { - return htmlDoclet.optionLength(option); + return HtmlDoclet.optionLength(option); } public static boolean start(RootDoc root) { - return htmlDoclet.start(root); + return HtmlDoclet.start(root); } public static boolean validOptions(String[][] options, DocErrorReporter reporter) { - return htmlDoclet.validOptions(options, reporter); + return HtmlDoclet.validOptions(options, reporter); } public static LanguageVersion languageVersion() { - return htmlDoclet.languageVersion(); + return HtmlDoclet.languageVersion(); } }
--- a/src/share/classes/com/sun/tools/javac/Launcher.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/Launcher.java Tue Mar 09 15:29:45 2010 -0800 @@ -64,7 +64,7 @@ fileChooser.setSelectedFile(new File(fileName)); } } - if (fileChooser.showOpenDialog(null) == fileChooser.APPROVE_OPTION) { + if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { String fileName = fileChooser.getSelectedFile().getPath(); prefs.put("recent.file", fileName); javac.run(System.in, null, null, "-d", "/tmp", fileName);
--- a/src/share/classes/com/sun/tools/javac/api/JavacTool.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/api/JavacTool.java Tue Mar 09 15:29:45 2010 -0800 @@ -137,7 +137,7 @@ } private static boolean match(OptionKind clientKind, OptionKind optionKind) { - return (clientKind == (optionKind == OptionKind.HIDDEN ? optionKind.EXTENDED : optionKind)); + return (clientKind == (optionKind == OptionKind.HIDDEN ? OptionKind.EXTENDED : optionKind)); } public JavacFileManager getStandardFileManager(
--- a/src/share/classes/com/sun/tools/javac/code/Lint.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/Lint.java Tue Mar 09 15:29:45 2010 -0800 @@ -198,7 +198,12 @@ /** * Warn about Sun proprietary API that may be removed in a future release. */ - SUNAPI("sunapi", true); + SUNAPI("sunapi", true), + + /** + * Warn about issues relating to use of statics + */ + STATIC("static"); LintCategory(String option) { this(option, false);
--- a/src/share/classes/com/sun/tools/javac/code/Symbol.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java Tue Mar 09 15:29:45 2010 -0800 @@ -162,7 +162,7 @@ * the default package; otherwise, the owner symbol is returned */ public Symbol location() { - if (owner.name == null || (owner.name.isEmpty() && owner.kind != PCK)) { + if (owner.name == null || (owner.name.isEmpty() && owner.kind != PCK && owner.kind != TYP)) { return null; } return owner;
--- a/src/share/classes/com/sun/tools/javac/code/Types.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java Tue Mar 09 15:29:45 2010 -0800 @@ -2504,7 +2504,7 @@ } @Override public int hashCode() { - return 127 * Types.this.hashCode(t1) + Types.this.hashCode(t2); + return 127 * Types.hashCode(t1) + Types.hashCode(t2); } @Override public boolean equals(Object obj) { @@ -3375,7 +3375,7 @@ this.t = t; } public int hashCode() { - return Types.this.hashCode(t); + return Types.hashCode(t); } public boolean equals(Object obj) { return (obj instanceof SingletonType) &&
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Tue Mar 09 15:29:45 2010 -0800 @@ -2020,6 +2020,10 @@ tree.pos(), site, sym.name, true); } } + } else if (sym.kind != ERR && (sym.flags() & STATIC) != 0 && sym.name != names._class) { + // If the qualified item is not a type and the selected item is static, report + // a warning. Make allowance for the class of an array type e.g. Object[].class) + chk.warnStatic(tree, "static.not.qualified.by.type", Kinds.kindName(sym.kind), sym.owner); } // If we are selecting an instance member via a `super', ... @@ -2636,6 +2640,7 @@ if (tree.bounds.tail.nonEmpty()) { log.error(tree.bounds.tail.head.pos(), "type.var.may.not.be.followed.by.other.bounds"); + log.unrecoverableError = true; tree.bounds = List.of(tree.bounds.head); a.bound = bs.head; }
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/Check.java Tue Mar 09 15:29:45 2010 -0800 @@ -189,6 +189,11 @@ sunApiHandler.report(pos, msg, args); } + public void warnStatic(DiagnosticPosition pos, String msg, Object... args) { + if (lint.isEnabled(LintCategory.STATIC)) + log.warning(pos, msg, args); + } + /** * Report any deferred diagnostics. */
--- a/src/share/classes/com/sun/tools/javac/comp/Enter.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/Enter.java Tue Mar 09 15:29:45 2010 -0800 @@ -270,6 +270,7 @@ return ts.toList(); } + @Override public void visitTopLevel(JCCompilationUnit tree) { JavaFileObject prev = log.useSource(tree.sourcefile); boolean addEnv = false; @@ -289,13 +290,13 @@ tree.packge = syms.unnamedPackage; } tree.packge.complete(); // Find all classes in package. - Env<AttrContext> env = topLevelEnv(tree); + Env<AttrContext> topEnv = topLevelEnv(tree); // Save environment of package-info.java file. if (isPkgInfo) { Env<AttrContext> env0 = typeEnvs.get(tree.packge); if (env0 == null) { - typeEnvs.put(tree.packge, env); + typeEnvs.put(tree.packge, topEnv); } else { JCCompilationUnit tree0 = env0.toplevel; if (!fileManager.isSameFile(tree.sourcefile, tree0.sourcefile)) { @@ -306,7 +307,7 @@ if (addEnv || (tree0.packageAnnotations.isEmpty() && tree.docComments != null && tree.docComments.get(tree) != null)) { - typeEnvs.put(tree.packge, env); + typeEnvs.put(tree.packge, topEnv); } } } @@ -322,14 +323,15 @@ c.members_field = new Scope(c); tree.packge.package_info = c; } - classEnter(tree.defs, env); + classEnter(tree.defs, topEnv); if (addEnv) { - todo.append(env); + todo.append(topEnv); } log.useSource(prev); result = null; } + @Override public void visitClassDef(JCClassDecl tree) { Symbol owner = env.info.scope.owner; Scope enclScope = enterScope(env); @@ -435,6 +437,7 @@ * Enter a symbol for type parameter in local scope, after checking that it * is unique. */ + @Override public void visitTypeParameter(JCTypeParameter tree) { TypeVar a = (tree.type != null) ? (TypeVar)tree.type @@ -448,6 +451,7 @@ /** Default class enter visitor method: do nothing. */ + @Override public void visitTree(JCTree tree) { result = null; } @@ -489,10 +493,8 @@ for (JCCompilationUnit tree : trees) { if (tree.starImportScope.elems == null) { JavaFileObject prev = log.useSource(tree.sourcefile); - Env<AttrContext> env = typeEnvs.get(tree); - if (env == null) - env = topLevelEnv(tree); - memberEnter.memberEnter(tree, env); + Env<AttrContext> topEnv = topLevelEnv(tree); + memberEnter.memberEnter(tree, topEnv); log.useSource(prev); } }
--- a/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Tue Mar 09 15:29:45 2010 -0800 @@ -607,10 +607,12 @@ public void visitNewArray(JCNewArray tree) { tree.elemtype = translate(tree.elemtype, null); translate(tree.dims, syms.intType); - tree.elems = translate(tree.elems, - (tree.type == null) ? null - : erasure(types.elemtype(tree.type))); - tree.type = erasure(tree.type); + if (tree.type != null) { + tree.elems = translate(tree.elems, erasure(types.elemtype(tree.type))); + tree.type = erasure(tree.type); + } else { + tree.elems = translate(tree.elems, null); + } result = tree; }
--- a/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Tue Mar 09 15:29:45 2010 -0800 @@ -260,7 +260,7 @@ archive = openArchive(directory); } catch (IOException ex) { log.error("error.reading.file", - directory, ex.getLocalizedMessage()); + directory, getMessage(ex)); return; } } @@ -489,7 +489,7 @@ archive = new MissingArchive(zipFileName); } catch (IOException ex) { if (zipFileName.exists()) - log.error("error.reading.file", zipFileName, ex.getLocalizedMessage()); + log.error("error.reading.file", zipFileName, getMessage(ex)); archive = new MissingArchive(zipFileName); } @@ -838,4 +838,23 @@ } throw new IllegalArgumentException("Invalid relative path: " + file); } + + /** + * Get a detail message from an IOException. + * Most, but not all, instances of IOException provide a non-null result + * for getLocalizedMessage(). But some instances return null: in these + * cases, fallover to getMessage(), and if even that is null, return the + * name of the exception itself. + * @param e an IOException + * @return a string to include in a compiler diagnostic + */ + public static String getMessage(IOException e) { + String s = e.getLocalizedMessage(); + if (s != null) + return s; + s = e.getMessage(); + if (s != null) + return s; + return e.toString(); + } }
--- a/src/share/classes/com/sun/tools/javac/file/Paths.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/file/Paths.java Tue Mar 09 15:29:45 2010 -0800 @@ -320,7 +320,7 @@ addFile(f, warn); } } catch (IOException e) { - log.error("error.reading.file", jarFile, e.getLocalizedMessage()); + log.error("error.reading.file", jarFile, JavacFileManager.getMessage(e)); } } }
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Tue Mar 09 15:29:45 2010 -0800 @@ -1135,7 +1135,7 @@ self.name = simpleBinaryName(self.flatname, c.flatname) ; self.owner = m != null ? m : c; if (self.name.isEmpty()) - self.fullname = null; + self.fullname = names.empty; else self.fullname = ClassSymbol.formFullName(self.name, self.owner);
--- a/src/share/classes/com/sun/tools/javac/jvm/Gen.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/jvm/Gen.java Tue Mar 09 15:29:45 2010 -0800 @@ -808,8 +808,8 @@ code.resolve(secondJumps); CondItem second = genCond(tree.falsepart, CRT_FLOW_TARGET); CondItem result = items.makeCondItem(second.opcode, - code.mergeChains(trueJumps, second.trueJumps), - code.mergeChains(falseJumps, second.falseJumps)); + Code.mergeChains(trueJumps, second.trueJumps), + Code.mergeChains(falseJumps, second.falseJumps)); if (markBranches) result.tree = tree.falsepart; return result; } else { @@ -1322,7 +1322,7 @@ if (useJsrLocally) { if (tree.finalizer != null) { Code.State jsrState = code.state.dup(); - jsrState.push(code.jsrReturnValue); + jsrState.push(Code.jsrReturnValue); tryEnv.info.cont = new Chain(code.emitJump(jsr), tryEnv.info.cont, @@ -1375,7 +1375,7 @@ genFinalizer(env); if (hasFinalizer || l.tail.nonEmpty()) { code.statBegin(TreeInfo.endPos(env.tree)); - exitChain = code.mergeChains(exitChain, + exitChain = Code.mergeChains(exitChain, code.branch(goto_)); } endFinalizerGap(env); @@ -1963,7 +1963,7 @@ result = items. makeCondItem(rcond.opcode, rcond.trueJumps, - code.mergeChains(falseJumps, + Code.mergeChains(falseJumps, rcond.falseJumps)); } else { result = lcond; @@ -1976,7 +1976,7 @@ CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET); result = items. makeCondItem(rcond.opcode, - code.mergeChains(trueJumps, rcond.trueJumps), + Code.mergeChains(trueJumps, rcond.trueJumps), rcond.falseJumps); } else { result = lcond;
--- a/src/share/classes/com/sun/tools/javac/jvm/Items.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/jvm/Items.java Tue Mar 09 15:29:45 2010 -0800 @@ -792,25 +792,25 @@ } Chain jumpTrue() { - if (tree == null) return code.mergeChains(trueJumps, code.branch(opcode)); + if (tree == null) return Code.mergeChains(trueJumps, code.branch(opcode)); // we should proceed further in -Xjcov mode only int startpc = code.curPc(); - Chain c = code.mergeChains(trueJumps, code.branch(opcode)); + Chain c = Code.mergeChains(trueJumps, code.branch(opcode)); code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc()); return c; } Chain jumpFalse() { - if (tree == null) return code.mergeChains(falseJumps, code.branch(code.negate(opcode))); + if (tree == null) return Code.mergeChains(falseJumps, code.branch(Code.negate(opcode))); // we should proceed further in -Xjcov mode only int startpc = code.curPc(); - Chain c = code.mergeChains(falseJumps, code.branch(code.negate(opcode))); + Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode))); code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc()); return c; } CondItem negate() { - CondItem c = new CondItem(code.negate(opcode), falseJumps, trueJumps); + CondItem c = new CondItem(Code.negate(opcode), falseJumps, trueJumps); c.tree = tree; return c; }
--- a/src/share/classes/com/sun/tools/javac/main/CommandLine.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/main/CommandLine.java Tue Mar 09 15:29:45 2010 -0800 @@ -82,7 +82,7 @@ st.commentChar('#'); st.quoteChar('"'); st.quoteChar('\''); - while (st.nextToken() != st.TT_EOF) { + while (st.nextToken() != StreamTokenizer.TT_EOF) { args.append(st.sval); } r.close();
--- a/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Tue Mar 09 15:29:45 2010 -0800 @@ -549,12 +549,6 @@ return log.nwarnings; } - /** Whether or not any parse errors have occurred. - */ - public boolean parseErrors() { - return parseErrors; - } - /** Try to open input stream with given name. * Report an error if this fails. * @param filename The file name of the input stream to be opened. @@ -564,7 +558,7 @@ inputFiles.add(filename); return filename.getCharContent(false); } catch (IOException e) { - log.error("error.reading.file", filename, e.getLocalizedMessage()); + log.error("error.reading.file", filename, JavacFileManager.getMessage(e)); return null; } } @@ -588,7 +582,7 @@ int initialErrorCount = log.nerrors; Parser parser = parserFactory.newParser(content, keepComments(), genEndPos, lineDebugInfo); tree = parser.parseCompilationUnit(); - parseErrors |= (log.nerrors > initialErrorCount); + log.unrecoverableError |= (log.nerrors > initialErrorCount); if (verbose) { printVerbose("parsing.done", Long.toString(elapsed(msec))); } @@ -723,7 +717,7 @@ try { tree = parse(filename, filename.getCharContent(false)); } catch (IOException e) { - log.error("error.reading.file", filename, e); + log.error("error.reading.file", filename, JavacFileManager.getMessage(e)); tree = make.TopLevel(List.<JCTree.JCAnnotation>nil(), null, List.<JCTree>nil()); } finally { log.useSource(prev); @@ -768,9 +762,6 @@ private long start_msec = 0; public long elapsed_msec = 0; - /** Track whether any errors occurred while parsing source text. */ - private boolean parseErrors = false; - public void compile(List<JavaFileObject> sourceFileObject) throws Throwable { compile(sourceFileObject, List.<String>nil(), null); @@ -1114,7 +1105,7 @@ return env; if (verboseCompilePolicy) - log.printLines(log.noticeWriter, "[attribute " + env.enclClass.sym + "]"); + Log.printLines(log.noticeWriter, "[attribute " + env.enclClass.sym + "]"); if (verbose) printVerbose("checking.attribution", env.enclClass.sym);
--- a/src/share/classes/com/sun/tools/javac/model/AnnotationProxyMaker.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/model/AnnotationProxyMaker.java Tue Mar 09 15:29:45 2010 -0800 @@ -26,6 +26,8 @@ package com.sun.tools.javac.model; import com.sun.tools.javac.util.*; +import java.io.ObjectInputStream; +import java.io.IOException; import java.lang.annotation.*; import java.lang.reflect.Array; import java.lang.reflect.Method; @@ -268,10 +270,10 @@ * The toString, hashCode, and equals methods foward to the underlying * type. */ - private static class MirroredTypeExceptionProxy extends ExceptionProxy { + private static final class MirroredTypeExceptionProxy extends ExceptionProxy { static final long serialVersionUID = 269; - private transient final TypeMirror type; + private transient TypeMirror type; private final String typeString; MirroredTypeExceptionProxy(TypeMirror t) { @@ -296,6 +298,13 @@ protected RuntimeException generateException() { return new MirroredTypeException(type); } + + // Explicitly set all transient fields. + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + type = null; + } } @@ -304,10 +313,10 @@ * The toString, hashCode, and equals methods foward to the underlying * types. */ - private static class MirroredTypesExceptionProxy extends ExceptionProxy { + private static final class MirroredTypesExceptionProxy extends ExceptionProxy { static final long serialVersionUID = 269; - private transient final List<TypeMirror> types; + private transient List<TypeMirror> types; private final String typeStrings; MirroredTypesExceptionProxy(List<TypeMirror> ts) { @@ -333,5 +342,12 @@ protected RuntimeException generateException() { return new MirroredTypesException(types); } + + // Explicitly set all transient fields. + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + types = null; + } } }
--- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Tue Mar 09 15:29:45 2010 -0800 @@ -1561,7 +1561,10 @@ JCNewClass newClass = classCreatorRest(newpos, null, typeArgs, t); if (newClass.def != null) { assert newClass.def.mods.annotations.isEmpty(); - newClass.def.mods.annotations = List.convert(JCAnnotation.class, newAnnotations); + if (newAnnotations.nonEmpty()) { + newClass.def.mods.pos = earlier(newClass.def.mods.pos, newAnnotations.head.pos); + newClass.def.mods.annotations = List.convert(JCAnnotation.class, newAnnotations); + } } return newClass; } else { @@ -3016,6 +3019,18 @@ return (oc >= 0) ? TreeInfo.opPrec(oc) : -1; } + /** + * Return the lesser of two positions, making allowance for either one + * being unset. + */ + static int earlier(int pos1, int pos2) { + if (pos1 == Position.NOPOS) + return pos2; + if (pos2 == Position.NOPOS) + return pos1; + return (pos1 < pos2 ? pos1 : pos2); + } + /** Return operation tag of binary operator represented by token, * -1 if token is not a binary operator. */
--- a/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Tue Mar 09 15:29:45 2010 -0800 @@ -690,10 +690,12 @@ ProcessorState ps = psi.next(); Set<String> matchedNames = new HashSet<String>(); Set<TypeElement> typeElements = new LinkedHashSet<TypeElement>(); - for (String unmatchedAnnotationName : unmatchedAnnotations.keySet()) { + + for (Map.Entry<String, TypeElement> entry: unmatchedAnnotations.entrySet()) { + String unmatchedAnnotationName = entry.getKey(); if (ps.annotationSupported(unmatchedAnnotationName) ) { matchedNames.add(unmatchedAnnotationName); - TypeElement te = unmatchedAnnotations.get(unmatchedAnnotationName); + TypeElement te = entry.getValue(); if (te != null) typeElements.add(te); } @@ -790,16 +792,13 @@ List<JCCompilationUnit> roots, List<ClassSymbol> classSymbols, Iterable<? extends PackageSymbol> pckSymbols) - throws IOException { + throws IOException { log = Log.instance(context); // Writer for -XprintRounds and -XprintProcessorInfo data PrintWriter xout = context.get(Log.outKey); TaskListener taskListener = context.get(TaskListener.class); - - AnnotationCollector collector = new AnnotationCollector(); - JavaCompiler compiler = JavaCompiler.instance(context); compiler.todo.clear(); // free the compiler's resources @@ -878,7 +877,7 @@ roots = cleanTrees(roots).appendList(parsedFiles); // Check for errors after parsing - if (compiler.parseErrors()) { + if (log.unrecoverableError) { errorStatus = true; break runAround; } else { @@ -912,7 +911,7 @@ roots = runLastRound(xout, roundNumber, errorStatus, compiler, roots, taskListener); // Set error status for any files compiled and generated in // the last round - if (compiler.parseErrors()) + if (log.unrecoverableError) errorStatus = true; compiler.close(false); @@ -1218,45 +1217,6 @@ return false; } - private class AnnotationCollector extends TreeScanner { - List<JCTree> path = List.nil(); - static final boolean verbose = false; - List<JCAnnotation> annotations = List.nil(); - - public List<JCAnnotation> findAnnotations(List<? extends JCTree> nodes) { - annotations = List.nil(); - scan(nodes); - List<JCAnnotation> found = annotations; - annotations = List.nil(); - return found.reverse(); - } - - public void scan(JCTree node) { - if (node == null) - return; - Symbol sym = TreeInfo.symbolFor(node); - if (sym != null) - path = path.prepend(node); - super.scan(node); - if (sym != null) - path = path.tail; - } - - public void visitAnnotation(JCAnnotation node) { - annotations = annotations.prepend(node); - if (verbose) { - StringBuilder sb = new StringBuilder(); - for (JCTree tree : path.reverse()) { - System.err.print(sb); - System.err.println(TreeInfo.symbolFor(tree)); - sb.append(" "); - } - System.err.print(sb); - System.err.println(node); - } - } - } - private static <T extends JCTree> List<T> cleanTrees(List<T> nodes) { for (T node : nodes) treeCleaner.scan(node);
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Tue Mar 09 15:29:45 2010 -0800 @@ -720,6 +720,9 @@ {0}: major version {1} is newer than {2}, the highest major version supported by this compiler.\n\ It is recommended that the compiler be upgraded. +compiler.warn.static.not.qualified.by.type=\ + [static] static {0} should be qualified by type name, {1}, instead of by an expression + # Warnings related to annotation processing compiler.warn.proc.package.does.not.exist=\ package {0} does not exist
--- a/src/share/classes/com/sun/tools/javac/util/BasicDiagnosticFormatter.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/util/BasicDiagnosticFormatter.java Tue Mar 09 15:29:45 2010 -0800 @@ -201,7 +201,7 @@ private String selectFormat(JCDiagnostic d) { DiagnosticSource source = d.getDiagnosticSource(); String format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT); - if (source != null) { + if (source != null && source != DiagnosticSource.NO_SOURCE) { if (d.getIntPosition() != Position.NOPOS) { format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_POS_FORMAT); } else if (source.getFile() != null &&
--- a/src/share/classes/com/sun/tools/javac/util/Log.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javac/util/Log.java Tue Mar 09 15:29:45 2010 -0800 @@ -192,6 +192,12 @@ */ public int nwarnings = 0; + /** + * Whether or not an unrecoverable error has been seen. + * Unrecoverable errors prevent subsequent annotation processing. + */ + public boolean unrecoverableError; + /** A set of all errors generated so far. This is used to avoid printing an * error message more than once. For each error, a pair consisting of the * source file name and source code position of the error is added to the set.
--- a/src/share/classes/com/sun/tools/javadoc/DocEnv.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javadoc/DocEnv.java Tue Mar 09 15:29:45 2010 -0800 @@ -34,7 +34,6 @@ import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Type.ClassType; -import com.sun.tools.javac.comp.Attr; import com.sun.tools.javac.comp.Check; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.Context; @@ -73,10 +72,6 @@ /** Referenced directly in RootDocImpl. */ JavadocClassReader reader; - /** The compiler's attribution phase (needed to evaluate - * constant initializers). */ - Attr attr; - /** Javadoc's own version of the compiler's enter phase. */ JavadocEnter enter; @@ -91,8 +86,6 @@ /** Access filter (public, protected, ...). */ ModifierFilter showAccess; - private ClassDocImpl runtimeException; - /** True if we are using a sentence BreakIterator. */ boolean breakiterator; @@ -129,7 +122,6 @@ syms = Symtab.instance(context); reader = JavadocClassReader.instance0(context); enter = JavadocEnter.instance0(context); - attr = Attr.instance(context); names = Names.instance(context); externalizableSym = reader.enterClass(names.fromString("java.io.Externalizable")); chk = Check.instance(context);
--- a/src/share/classes/com/sun/tools/javadoc/SeeTagImpl.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javadoc/SeeTagImpl.java Tue Mar 09 15:29:45 2010 -0800 @@ -349,12 +349,12 @@ // (int i, String s) ==> [0] = "int", [1] = String // (int[][], String[]) ==> [0] = "int[][]" // [1] = "String[]" class ParameterParseMachine { - final int START = 0; - final int TYPE = 1; - final int NAME = 2; - final int TNSPACE = 3; // space between type and name - final int ARRAYDECORATION = 4; - final int ARRAYSPACE = 5; + static final int START = 0; + static final int TYPE = 1; + static final int NAME = 2; + static final int TNSPACE = 3; // space between type and name + static final int ARRAYDECORATION = 4; + static final int ARRAYSPACE = 5; String parameters;
--- a/src/share/classes/com/sun/tools/javah/JavahTask.java Thu Mar 04 13:50:33 2010 -0800 +++ b/src/share/classes/com/sun/tools/javah/JavahTask.java Tue Mar 09 15:29:45 2010 -0800 @@ -255,9 +255,11 @@ } this.classes = new ArrayList<String>(); - for (String classname: classes) { - classname.getClass(); // null-check - this.classes.add(classname); + if (classes != null) { + for (String classname: classes) { + classname.getClass(); // null-check + this.classes.add(classname); + } } } @@ -316,6 +318,12 @@ int run(String[] args) { try { handleOptions(args); + if (classes == null || classes.size() == 0) { + if (help || version || fullVersion) + return 0; + else + return 1; + } boolean ok = run(); return ok ? 0 : 1; } catch (BadArgs e) { @@ -347,8 +355,7 @@ fileManager = getDefaultFileManager(diagnosticListener, log); Iterator<String> iter = args.iterator(); - if (!iter.hasNext()) - help = true; + boolean noArgs = !iter.hasNext(); while (iter.hasNext()) { String arg = iter.next(); @@ -365,7 +372,7 @@ } if ((classes == null || classes.size() == 0) && - !(help || version || fullVersion)) { + !(noArgs || help || version || fullVersion)) { throw new BadArgs("err.no.classes.specified"); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/4880220/T4880220.error.out Tue Mar 09 15:29:45 2010 -0800 @@ -0,0 +1,9 @@ +T4880220.java:20:27: compiler.warn.static.not.qualified.by.type: kindname.method, T4880220.C +T4880220.java:21:27: compiler.warn.static.not.qualified.by.type: kindname.variable, T4880220.C +T4880220.java:22:27: compiler.warn.static.not.qualified.by.type: kindname.variable, T4880220.C +T4880220.java:24:29: compiler.warn.static.not.qualified.by.type: kindname.method, T4880220.C +T4880220.java:25:29: compiler.warn.static.not.qualified.by.type: kindname.variable, T4880220.C +T4880220.java:26:29: compiler.warn.static.not.qualified.by.type: kindname.variable, T4880220.C +- compiler.err.warnings.and.werror +1 error +6 warnings
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/4880220/T4880220.java Tue Mar 09 15:29:45 2010 -0800 @@ -0,0 +1,43 @@ +/* + * @test /nodynamiccopyright/ + * @bug 4880220 + * @summary Add a warning when accessing a static method via an reference + * + * @compile/ref=T4880220.empty.out T4880220.java + * @compile/ref=T4880220.warn.out -XDrawDiagnostics -Xlint:static T4880220.java + * @compile/ref=T4880220.warn.out -XDrawDiagnostics -Xlint:all T4880220.java + * @compile/ref=T4880220.empty.out -XDrawDiagnostics -Xlint:all,-static T4880220.java + * @compile/ref=T4880220.error.out/fail -XDrawDiagnostics -Werror -Xlint:all T4880220.java + */ + +public class T4880220 { + void m1() { + int good_1 = C.m(); + int good_2 = C.f; + int good_3 = C.x; + + C c = new C(); + int bad_inst_1 = c.m(); + int bad_inst_2 = c.f; + int bad_inst_3 = c.x; + + int bad_expr_1 = c().m(); + int bad_expr_2 = c().f; + int bad_expr_3 = c().x; + } + + void m2() { + Class<?> good_1 = C.class; + Class<?> good_2 = C[].class; + } + + C c() { + return new C(); + } + + static class C { + static int m() { return 0; } + static int f; + static final int x = 3; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/4880220/T4880220.warn.out Tue Mar 09 15:29:45 2010 -0800 @@ -0,0 +1,7 @@ +T4880220.java:20:27: compiler.warn.static.not.qualified.by.type: kindname.method, T4880220.C +T4880220.java:21:27: compiler.warn.static.not.qualified.by.type: kindname.variable, T4880220.C +T4880220.java:22:27: compiler.warn.static.not.qualified.by.type: kindname.variable, T4880220.C +T4880220.java:24:29: compiler.warn.static.not.qualified.by.type: kindname.method, T4880220.C +T4880220.java:25:29: compiler.warn.static.not.qualified.by.type: kindname.variable, T4880220.C +T4880220.java:26:29: compiler.warn.static.not.qualified.by.type: kindname.variable, T4880220.C +6 warnings
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/T6881645.java Tue Mar 09 15:29:45 2010 -0800 @@ -0,0 +1,38 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @summary Unchecked method call on a method declared inside anonymous inner causes javac to crash + * @compile -Xlint:unchecked T6881645.java + */ + +class T6881645 { + Object o = new Object() { + <Z> void m (Class<Z> x) {} + void test() { + m((Class)null); + } + }; +} +
--- a/test/tools/javac/ThrowsIntersection_1.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/ThrowsIntersection_1.java Tue Mar 09 15:29:45 2010 -0800 @@ -30,6 +30,8 @@ * @compile ThrowsIntersection_1.java */ +package ThrowsIntersection_1; + class Ex1 extends Exception {} class Ex2 extends Exception {}
--- a/test/tools/javac/ThrowsIntersection_2.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/ThrowsIntersection_2.java Tue Mar 09 15:29:45 2010 -0800 @@ -30,6 +30,8 @@ * @compile ThrowsIntersection_2.java */ +package ThrowsIntersection_2; + class Ex1 extends Exception {} class Ex2 extends Exception {} class Ex3 extends Exception {}
--- a/test/tools/javac/ThrowsIntersection_3.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/ThrowsIntersection_3.java Tue Mar 09 15:29:45 2010 -0800 @@ -30,6 +30,8 @@ * @run compile/fail ThrowsIntersection_3.java */ +package ThrowsIntersection_3; + class Ex1 extends Exception {} class Ex2 extends Exception {}
--- a/test/tools/javac/ThrowsIntersection_4.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/ThrowsIntersection_4.java Tue Mar 09 15:29:45 2010 -0800 @@ -30,6 +30,8 @@ * @run compile/fail ThrowsIntersection_4.java */ +package ThrowsIntersection_4; + // Note: This is the test that actually failed for 4042259. The others are for completeness. class Ex1 extends Exception {}
--- a/test/tools/javac/annotations/neg/Constant.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/annotations/neg/Constant.java Tue Mar 09 15:29:45 2010 -0800 @@ -30,7 +30,7 @@ * @compile/fail Constant.java */ -package test.tools.javac.annotation.Constant; +package Constant; @T(a = X.x) @interface T {
--- a/test/tools/javac/api/TestJavacTaskScanner.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/api/TestJavacTaskScanner.java Tue Mar 09 15:29:45 2010 -0800 @@ -34,7 +34,10 @@ import com.sun.tools.javac.parser.*; // XXX import com.sun.tools.javac.util.*; // XXX import java.io.*; +import java.net.*; import java.nio.*; +import java.nio.charset.Charset; +import java.util.Arrays; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; @@ -43,6 +46,10 @@ import javax.lang.model.util.Types; import javax.tools.*; +import static javax.tools.StandardLocation.CLASS_PATH; +import static javax.tools.StandardLocation.SOURCE_PATH; +import static javax.tools.StandardLocation.CLASS_OUTPUT; + public class TestJavacTaskScanner extends ToolTester { final JavacTaskImpl task; @@ -56,6 +63,7 @@ TestJavacTaskScanner(File file) { final Iterable<? extends JavaFileObject> compilationUnits = fm.getJavaFileObjects(new File[] {file}); + StandardJavaFileManager fm = getLocalFileManager(tool, null, null); task = (JavacTaskImpl)tool.getTask(null, fm, null, null, null, compilationUnits); task.getContext().put(Scanner.Factory.scannerFactoryKey, new MyScanner.Factory(task.getContext(), this)); @@ -83,7 +91,7 @@ System.out.println("#parseTypeElements: " + numParseTypeElements); System.out.println("#allMembers: " + numAllMembers); - check(numTokens, "#Tokens", 891); + check(numTokens, "#Tokens", 1222); check(numParseTypeElements, "#parseTypeElements", 136); check(numAllMembers, "#allMembers", 67); } @@ -117,6 +125,47 @@ numAllMembers++; } } + + /* Similar to ToolTester.getFileManager, except that this version also ensures + * javac classes will be available on the classpath. The javac classes are assumed + * to be on the classpath used to run this test (this is true when using jtreg). + * The classes are found by obtaining the URL for a sample javac class, using + * getClassLoader().getResource(), and then deconstructing the URL to find the + * underlying directory or jar file to place on the classpath. + */ + public StandardJavaFileManager getLocalFileManager(JavaCompiler tool, + DiagnosticListener<JavaFileObject> dl, + Charset encoding) { + File javac_classes; + try { + final String javacMainClass = "com/sun/tools/javac/Main.class"; + URL url = getClass().getClassLoader().getResource(javacMainClass); + if (url == null) + throw new Error("can't locate javac classes"); + URI uri = url.toURI(); + String scheme = uri.getScheme(); + String ssp = uri.getSchemeSpecificPart(); + if (scheme.equals("jar")) { + javac_classes = new File(new URI(ssp.substring(0, ssp.indexOf("!/")))); + } else if (scheme.equals("file")) { + javac_classes = new File(ssp.substring(0, ssp.indexOf(javacMainClass))); + } else + throw new Error("unknown URL: " + url); + } catch (URISyntaxException e) { + throw new Error(e); + } + System.err.println("javac_classes: " + javac_classes); + + StandardJavaFileManager fm = tool.getStandardFileManager(dl, null, encoding); + try { + fm.setLocation(SOURCE_PATH, Arrays.asList(test_src)); + fm.setLocation(CLASS_PATH, Arrays.asList(test_classes, javac_classes)); + fm.setLocation(CLASS_OUTPUT, Arrays.asList(test_classes)); + } catch (IOException e) { + throw new AssertionError(e); + } + return fm; + } } class MyScanner extends Scanner {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/api/TestResolveError.java Tue Mar 09 15:29:45 2010 -0800 @@ -0,0 +1,101 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6930108 + * @summary IllegalArgumentException in AbstractDiagnosticFormatter for tools/javac/api/TestJavacTaskScanner.java + * @library ./lib + * @build ToolTester + * @run main TestResolveError + */ + +import java.io.*; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import javax.tools.*; + +import com.sun.tools.javac.api.JavacTaskImpl; + +/* + * This is a cut down version of TestJavacTaskScanner, which as originally written + * caused an IllegalArgumentException in AbstractDiagnosticFormatter as a result + * of calling task.parseType with a name whose resolution depended on the setting + * of the bootclasspath. + * This test has the same call, task.parseType("List<String>", clazz), but checks + * that the error is handled in a reasonable way by javac. + */ +public class TestResolveError extends ToolTester { + public static void main(String... args) throws Exception { + new TestResolveError().run(); + } + + void run() throws Exception { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + File file = new File(test_src, "TestResolveError.java"); + final Iterable<? extends JavaFileObject> compilationUnits = + fm.getJavaFileObjects(new File[] {file}); + task = (JavacTaskImpl)tool.getTask(pw, fm, null, null, null, compilationUnits); + elements = task.getElements(); + types = task.getTypes(); + + Iterable<? extends TypeElement> toplevels; + try { + toplevels = task.enter(task.parse()); + } catch (IOException ex) { + throw new AssertionError(ex); + } + + for (TypeElement clazz : toplevels) { + System.out.format("Testing %s:%n%n", clazz.getSimpleName()); + // this should not cause any exception from the compiler, + // such as IllegalArgumentException + testParseType(clazz); + } + + pw.close(); + + String out = sw.toString(); + System.out.println(out); + + if (out.contains("com.sun.tools.javac.util")) + throw new Exception("Unexpected output from compiler"); + } + + void testParseType(TypeElement clazz) { + DeclaredType type = (DeclaredType)task.parseType("List<String>", clazz); + for (Element member : elements.getAllMembers((TypeElement)type.asElement())) { + TypeMirror mt = types.asMemberOf(type, member); + System.out.format("%s : %s -> %s%n", member.getSimpleName(), member.asType(), mt); + } + } + + JavacTaskImpl task; + Elements elements; + Types types; +}
--- a/test/tools/javac/generics/Casting.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/generics/Casting.java Tue Mar 09 15:29:45 2010 -0800 @@ -30,7 +30,7 @@ * @compile Casting.java */ -package test.tools.javac.generics.Casting; +package Casting; class Test {}
--- a/test/tools/javac/generics/Casting3.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/generics/Casting3.java Tue Mar 09 15:29:45 2010 -0800 @@ -30,7 +30,7 @@ * @compile Casting3.java */ -package test.tools.javac.generics.Casting3; +package Casting3; class A<T extends A<T>> { <U extends A<U>> void f() {
--- a/test/tools/javac/generics/Casting4.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/generics/Casting4.java Tue Mar 09 15:29:45 2010 -0800 @@ -30,7 +30,7 @@ * @compile -Werror -Xlint:unchecked Casting4.java */ -package test.tools.javac.generics.Casting4; +package Casting4; class Casting4 { <M> Integer f(Comparable<M> c) {
--- a/test/tools/javac/generics/InnerInterface1.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/generics/InnerInterface1.java Tue Mar 09 15:29:45 2010 -0800 @@ -30,7 +30,7 @@ * @compile InnerInterface1.java */ -package test.tools.javac.generics.InnerInterface1; +package InnerInterface1; interface Iterator<E> { }
--- a/test/tools/javac/generics/InnerInterface2.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/generics/InnerInterface2.java Tue Mar 09 15:29:45 2010 -0800 @@ -30,7 +30,7 @@ * @compile InnerInterface2.java */ -package test.tools.javac.generics.InnerInterface2; +package InnerInterface2; class Builder<Community> {
--- a/test/tools/javac/generics/Multibound1.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/generics/Multibound1.java Tue Mar 09 15:29:45 2010 -0800 @@ -30,7 +30,7 @@ * @compile/fail Multibound1.java */ -package test.tools.javac.generics.Multibound1; +package Multibound1; interface A {} interface B {}
--- a/test/tools/javac/generics/MultipleInheritance.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/generics/MultipleInheritance.java Tue Mar 09 15:29:45 2010 -0800 @@ -30,7 +30,7 @@ * @compile MultipleInheritance.java */ -package test.tools.javac.generics.MultipleInheritance; +package MultipleInheritance; import java.util.*;
--- a/test/tools/javac/generics/NameOrder.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/generics/NameOrder.java Tue Mar 09 15:29:45 2010 -0800 @@ -27,22 +27,22 @@ * @summary generics: type inference failure due to a bug in ClassSymbol.isLess * @author gafter * - * @compile NameOrder.java + * @compile NameOrder.java */ -package test.tools.javac.generics.NameOrder; +package NameOrder; interface a {} interface b {} interface c {} -class A implements a, b {} -class B implements c, a {} +class AB implements a, b {} +class CA implements c, a {} // this is how to trigger a symptom: -abstract class C { +abstract class X { <T> T f(T t1, T t2) { return null; } void g() { - a x = f( new A(), new B() ); + a x = f( new AB(), new CA() ); } }
--- a/test/tools/javac/generics/PermuteBound.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/generics/PermuteBound.java Tue Mar 09 15:29:45 2010 -0800 @@ -30,7 +30,7 @@ * @compile PermuteBound.java */ -package test.tools.javac.generics.PermuteBound; +package PermuteBound; class C<X, Y> {}
--- a/test/tools/javac/generics/PrimitiveVariant.java Thu Mar 04 13:50:33 2010 -0800 +++ b/test/tools/javac/generics/PrimitiveVariant.java Tue Mar 09 15:29:45 2010 -0800 @@ -30,7 +30,7 @@ * @compile/fail PrimitiveVariant.java */ -package test.tools.javac.generics.PrimitiveVariant; +package PrimitiveVariant; interface I { double m();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/processing/6511613/DummyProcessor.java Tue Mar 09 15:29:45 2010 -0800 @@ -0,0 +1,40 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import java.util.Set; + +@SupportedAnnotationTypes("*") +public class DummyProcessor extends AbstractProcessor { + public boolean process(Set<? extends TypeElement> annotations, + RoundEnvironment roundEnv) { + return true; + } + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/processing/6511613/clss41701.java Tue Mar 09 15:29:45 2010 -0800 @@ -0,0 +1,43 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6511613 + * @summary javac unexpectedly doesn't fail in some cases if an annotation processor specified + * + * @build DummyProcessor + * @compile/fail clss41701.java + * @compile/fail -processor DummyProcessor clss41701.java + */ + +import java.io.PrintStream; + +interface clss41701i { + void run(); +} + +class clss41701a<A extends clss41701i, + B extends clss41701i, + C extends A&B> { +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/processing/model/element/TestAnonClassNames.java Tue Mar 09 15:29:45 2010 -0800 @@ -0,0 +1,186 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6449781 + * @summary Test that reported names of anonymous classes are non-null. + * @author Joseph D. Darcy + * @build TestAnonSourceNames + * @compile/fail -processor TestAnonSourceNames TestAnonClassNames.java + * @build TestAnonClassNames + * @run main TestAnonClassNames + */ + +/* + * This test operates in phases to test retrieving the qualified name + * of anonymous classes from type elements modeling the anonymous + * class. The type elements are generated using both source files and + * class files as the basis of constructing the elements. + * + * Source files will be tested by the @compile line which runs + * TestAnonSourceNames as an annotation processor over this file. + * This compile line is expected to fail until 6930507 is fixed. Once + * bug 6930507 is fixed, the "@compile/fail -processor ..." and + * following "@build..." steps can be replaced with a single "@compile + * -processor ..." directive. + * + * Class files are tested by the @run command on this type. This + * class gets the names of classes with different nesting kinds, + * including anonymous classes, and then invokes the compiler with an + * annotation processor having the class files names as inputs. The + * compiler is invoked via the javax.tools mechanism. + */ + +import java.lang.annotation.*; +import javax.lang.model.element.*; +import javax.annotation.processing.*; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.*; +import javax.lang.model.util.*; +import javax.tools.*; +import java.util.*; + +import static java.lang.annotation.RetentionPolicy.*; +import static javax.lang.model.element.NestingKind.*; +import static javax.lang.model.util.ElementFilter.*; +import static javax.tools.Diagnostic.Kind.*; +import static javax.tools.StandardLocation.*; + +@Nesting(TOP_LEVEL) +public class TestAnonClassNames { + @Nesting(MEMBER) + static class MemberClass1{} + + @Nesting(MEMBER) + class MemberClass2{} + + @Nesting(MEMBER) + class Win$$AtVegas { } // Class with funny name. + + public static void main(String... argv) { + @Nesting(LOCAL) + class LocalClass{}; + + Object o = new @Nesting(ANONYMOUS) Object() { // An anonymous annotated class + public String toString() { + return "I have no name!"; + } + }; + + Class<?>[] classes = { + MemberClass1.class, + MemberClass2.class, + LocalClass.class, + Win$$AtVegas.class, + o.getClass(), + TestAnonClassNames.class, + }; + + for(Class<?> clazz : classes) { + String name = clazz.getName(); + System.out.format("%s is %s%n", + clazz.getName(), + clazz.getAnnotation(Nesting.class).value()); + testClassName(name); + } + } + + /** + * Perform annotation processing on the class file name and verify + * the existence of different flavors of class names when the + * input classes are modeled as elements. + */ + static void testClassName(String className) { + JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); + List<String> classNames = new ArrayList<>(); + classNames.add(className); + + List<String> options = new ArrayList<>(); + options.add("-proc:only"); + options.add("-classpath"); + options.add(System.getProperty("test.classes")); + + JavaCompiler.CompilationTask compileTask = + javaCompiler.getTask(null, // Output + null, // File manager + null, // Diagnostics + options, + classNames, + null); // Sources + List<Processor> processors = new ArrayList<>(); + processors.add(new ClassNameProber()); + compileTask.setProcessors(processors); + Boolean goodResult = compileTask.call(); + if (!goodResult) { + throw new RuntimeException("Errors found during compile."); + } + } +} + +@Retention(RUNTIME) +@interface Nesting { + NestingKind value(); +} + +/** + * Probe at the various kinds of names of a type element. + */ +@SupportedAnnotationTypes("*") +class ClassNameProber extends AbstractProcessor { + public ClassNameProber(){super();} + + private boolean classesFound=false; + + public boolean process(Set<? extends TypeElement> annotations, + RoundEnvironment roundEnv) { + if (!roundEnv.processingOver()) { + for(TypeElement typeElt : typesIn(roundEnv.getRootElements())) { + classesFound = true; + + // Verify different names are non-null; an NPE will + // result in failed compile status being reported. + NestingKind nestingKind = typeElt.getNestingKind(); + System.out.printf("\tSimple name: ''%s''\tQualified Name: ''%s''\tKind ''%s''\tNesting ''%s''%n", + typeElt.getSimpleName().toString(), + typeElt.getQualifiedName().toString(), + typeElt.getKind().toString(), + nestingKind.toString()); + + if (typeElt.getAnnotation(Nesting.class).value() != nestingKind) { + throw new RuntimeException("Mismatch of expected and reported nesting kind."); + } + } + + } + + if (!classesFound) { + throw new RuntimeException("Error: no classes processed."); + } + return true; + } + + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/processing/model/element/TestAnonSourceNames.java Tue Mar 09 15:29:45 2010 -0800 @@ -0,0 +1,92 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.io.*; +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; +import java.util.*; +import com.sun.source.tree.*; +import com.sun.source.util.*; +import static javax.tools.Diagnostic.Kind.*; + +/** + * Using the tree API, retrieve element representations of anonymous + * classes and verify their names are as specified. + */ +@SupportedAnnotationTypes("*") +public class TestAnonSourceNames extends AbstractProcessor { + + public boolean process(Set<? extends TypeElement> annotations, + RoundEnvironment roundEnv) { + if (!roundEnv.processingOver()) { + Trees trees = Trees.instance(processingEnv); + + for(Element rootElement : roundEnv.getRootElements()) { + TreePath treePath = trees.getPath(rootElement); + + (new ClassTreeScanner(trees)). + scan(trees.getTree(rootElement), + treePath.getCompilationUnit()); + } + } + return true; + } + + class ClassTreeScanner extends TreeScanner<Void, CompilationUnitTree> { + private Trees trees; + + public ClassTreeScanner(Trees trees) { + super(); + this.trees = trees; + } + @Override + public Void visitClass(ClassTree node, CompilationUnitTree cu) { + Element element = trees.getElement(trees.getPath(cu, node)); + if (element == null) { + processingEnv.getMessager().printMessage(ERROR, + "No element retreived for node named ''" + + node.getSimpleName() + "''."); + } else { + + System.out.println("\nVisiting class ``" + element.getSimpleName() + + "'' of kind " + element.getKind()); + if (element instanceof TypeElement) { + TypeElement typeElement = (TypeElement) element; + String s = typeElement.getQualifiedName().toString(); + System.out.println("\tqualified name:" + s); + } else { + throw new RuntimeException("TypeElement not gotten from ClassTree."); + } + } + return super.visitClass(node, cu); + } + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/tree/TestAnnotatedAnonClass.java Tue Mar 09 15:29:45 2010 -0800 @@ -0,0 +1,37 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* + * This file is not a regular test, but is processed by ./TreePosTest.java, + * which verifies the position info in the javac tree. + * To run the test standalone, compile TreePosTest, then run TreePosTest + * on this file. + * @bug 6931927 + * @summary position issues with synthesized anonymous class + */ +class TestAnnotatedAnonClass { + void m() { + Object o = new @Deprecated Object() { }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/tree/TreePosTest.java Tue Mar 09 15:29:45 2010 -0800 @@ -0,0 +1,762 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.event.CaretEvent; +import javax.swing.event.CaretListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.DefaultHighlighter; +import javax.swing.text.Highlighter; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticListener; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; + +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCNewClass; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.tree.TreeScanner; + +import static com.sun.tools.javac.util.Position.NOPOS; + +/** + * Utility and test program to check validity of tree positions for tree nodes. + * The program can be run standalone, or as a jtreg test. In standalone mode, + * errors can be displayed in a gui viewer. For info on command line args, + * run program with no args. + * + * <p> + * jtreg: Note that by using the -r switch in the test description below, this test + * will process all java files in the langtools/test directory, thus implicitly + * covering any new language features that may be tested in this test suite. + */ + +/* + * @test + * @bug 6919889 + * @summary assorted position errors in compiler syntax trees + * @run main TreePosTest -q -r -ef ./tools/javac/typeAnnotations -ef ./tools/javap/typeAnnotations -et ANNOTATED_TYPE . + */ +public class TreePosTest { + /** + * Main entry point. + * If test.src is set, program runs in jtreg mode, and will throw an Error + * if any errors arise, otherwise System.exit will be used, unless the gui + * viewer is being used. In jtreg mode, the default base directory for file + * args is the value of ${test.src}. In jtreg mode, the -r option can be + * given to change the default base directory to the root test directory. + */ + public static void main(String... args) { + String testSrc = System.getProperty("test.src"); + File baseDir = (testSrc == null) ? null : new File(testSrc); + boolean ok = new TreePosTest().run(baseDir, args); + if (!ok) { + if (testSrc != null) // jtreg mode + throw new Error("failed"); + else + System.exit(1); + } + } + + /** + * Run the program. A base directory can be provided for file arguments. + * In jtreg mode, the -r option can be given to change the default base + * directory to the test root directory. For other options, see usage(). + * @param baseDir base directory for any file arguments. + * @param args command line args + * @return true if successful or in gui mode + */ + boolean run(File baseDir, String... args) { + if (args.length == 0) { + usage(System.out); + return true; + } + + List<File> files = new ArrayList<File>(); + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if (arg.equals("-encoding") && i + 1 < args.length) + encoding = args[++i]; + else if (arg.equals("-gui")) + gui = true; + else if (arg.equals("-q")) + quiet = true; + else if (arg.equals("-v")) + verbose = true; + else if (arg.equals("-t") && i + 1 < args.length) + tags.add(args[++i]); + else if (arg.equals("-ef") && i + 1 < args.length) + excludeFiles.add(new File(baseDir, args[++i])); + else if (arg.equals("-et") && i + 1 < args.length) + excludeTags.add(args[++i]); + else if (arg.equals("-r")) { + if (excludeFiles.size() > 0) + throw new Error("-r must be used before -ef"); + File d = baseDir; + while (!new File(d, "TEST.ROOT").exists()) { + d = d.getParentFile(); + if (d == null) + throw new Error("cannot find TEST.ROOT"); + } + baseDir = d; + } + else if (arg.startsWith("-")) + throw new Error("unknown option: " + arg); + else { + while (i < args.length) + files.add(new File(baseDir, args[i++])); + } + } + + for (File file: files) { + if (file.exists()) + test(file); + else + error("File not found: " + file); + } + + if (fileCount != 1) + System.err.println(fileCount + " files read"); + if (errors > 0) + System.err.println(errors + " errors"); + + return (gui || errors == 0); + } + + /** + * Print command line help. + * @param out output stream + */ + void usage(PrintStream out) { + out.println("Usage:"); + out.println(" java TreePosTest options... files..."); + out.println(""); + out.println("where options include:"); + out.println("-gui Display returns in a GUI viewer"); + out.println("-q Quiet: don't report on inapplicable files"); + out.println("-v Verbose: report on files as they are being read"); + out.println("-t tag Limit checks to tree nodes with this tag"); + out.println(" Can be repeated if desired"); + out.println("-ef file Exclude file or directory"); + out.println("-et tag Exclude tree nodes with given tag name"); + out.println(""); + out.println("files may be directories or files"); + out.println("directories will be scanned recursively"); + out.println("non java files, or java files which cannot be parsed, will be ignored"); + out.println(""); + } + + /** + * Test a file. If the file is a directory, it will be recursively scanned + * for java files. + * @param file the file or directory to test + */ + void test(File file) { + if (excludeFiles.contains(file)) { + if (!quiet) + error("File " + file + " excluded"); + return; + } + + if (file.isDirectory()) { + for (File f: file.listFiles()) { + test(f); + } + return; + } + + if (file.isFile() && file.getName().endsWith(".java")) { + try { + if (verbose) + System.err.println(file); + fileCount++; + PosTester p = new PosTester(); + p.test(read(file)); + } catch (ParseException e) { + if (!quiet) { + error("Error parsing " + file + "\n" + e.getMessage()); + } + } catch (IOException e) { + error("Error reading " + file + ": " + e); + } + return; + } + + if (!quiet) + error("File " + file + " ignored"); + } + + /** + * Read a file. + * @param file the file to be read + * @return the tree for the content of the file + * @throws IOException if any IO errors occur + * @throws TreePosTest.ParseException if any errors occur while parsing the file + */ + JCCompilationUnit read(File file) throws IOException, ParseException { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + Reporter r = new Reporter(pw); + JavacTool tool = JavacTool.create(); + Charset cs = (encoding == null ? null : Charset.forName(encoding)); + StandardJavaFileManager fm = tool.getStandardFileManager(r, null, null); + Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(file); + JavacTask task = tool.getTask(pw, fm, r, Collections.<String>emptyList(), null, files); + Iterable<? extends CompilationUnitTree> trees = task.parse(); + pw.flush(); + if (r.errors > 0) + throw new ParseException(sw.toString()); + Iterator<? extends CompilationUnitTree> iter = trees.iterator(); + if (!iter.hasNext()) + throw new Error("no trees found"); + JCCompilationUnit t = (JCCompilationUnit) iter.next(); + if (iter.hasNext()) + throw new Error("too many trees found"); + return t; + } + + /** + * Report an error. When the program is complete, the program will either + * exit or throw an Error if any errors have been reported. + * @param msg the error message + */ + void error(String msg) { + System.err.println(msg); + errors++; + } + + /** Number of files that have been analyzed. */ + int fileCount; + /** Number of errors reported. */ + int errors; + /** Flag: don't report irrelevant files. */ + boolean quiet; + /** Flag: report files as they are processed. */ + boolean verbose; + /** Flag: show errors in GUI viewer. */ + boolean gui; + /** Option: encoding for test files. */ + String encoding; + /** The GUI viewer for errors. */ + Viewer viewer; + /** The set of tags for tree nodes to be analyzed; if empty, all tree nodes + * are analyzed. */ + Set<String> tags = new HashSet<String>(); + /** Set of files and directories to be excluded from analysis. */ + Set<File> excludeFiles = new HashSet<File>(); + /** Set of tag names to be excluded from analysis. */ + Set<String> excludeTags = new HashSet<String>(); + /** Table of printable names for tree tag values. */ + TagNames tagNames = new TagNames(); + + /** + * Main class for testing assertions concerning tree positions for tree nodes. + */ + private class PosTester extends TreeScanner { + void test(JCCompilationUnit tree) { + sourcefile = tree.sourcefile; + endPosTable = tree.endPositions; + encl = new Info(); + tree.accept(this); + } + + @Override + public void scan(JCTree tree) { + if (tree == null) + return; + + Info self = new Info(tree, endPosTable); + if (check(encl, self)) { + // Modifiers nodes are present throughout the tree even where + // there is no corresponding source text. + // Redundant semicolons in a class definition can cause empty + // initializer blocks with no positions. + if ((self.tag == JCTree.MODIFIERS || self.tag == JCTree.BLOCK) + && self.pos == NOPOS) { + // If pos is NOPOS, so should be the start and end positions + check("start == NOPOS", encl, self, self.start == NOPOS); + check("end == NOPOS", encl, self, self.end == NOPOS); + } else { + // For this node, start , pos, and endpos should be all defined + check("start != NOPOS", encl, self, self.start != NOPOS); + check("pos != NOPOS", encl, self, self.pos != NOPOS); + check("end != NOPOS", encl, self, self.end != NOPOS); + // The following should normally be ordered + // encl.start <= start <= pos <= end <= encl.end + // In addition, the position of the enclosing node should be + // within this node. + // The primary exceptions are for array type nodes, because of the + // need to support legacy syntax: + // e.g. int a[]; int[] b[]; int f()[] { return null; } + // and because of inconsistent nesting of left and right of + // array declarations: + // e.g. int[][] a = new int[2][]; + check("encl.start <= start", encl, self, encl.start <= self.start); + check("start <= pos", encl, self, self.start <= self.pos); + if (!(self.tag == JCTree.TYPEARRAY + && (encl.tag == JCTree.VARDEF || encl.tag == JCTree.TYPEARRAY))) { + check("encl.pos <= start || end <= encl.pos", + encl, self, encl.pos <= self.start || self.end <= encl.pos); + } + check("pos <= end", encl, self, self.pos <= self.end); + if (!(self.tag == JCTree.TYPEARRAY && encl.tag == JCTree.TYPEARRAY)) { + check("end <= encl.end", encl, self, self.end <= encl.end); + } + } + } + + Info prevEncl = encl; + encl = self; + tree.accept(this); + encl = prevEncl; + } + + @Override + public void visitVarDef(JCVariableDecl tree) { + // enum member declarations are desugared in the parser and have + // ill-defined semantics for tree positions, so for now, we + // skip the synthesized bits and just check parts which came from + // the original source text + if ((tree.mods.flags & Flags.ENUM) != 0) { + scan(tree.mods); + if (tree.init != null) { + if (tree.init.getTag() == JCTree.NEWCLASS) { + JCNewClass init = (JCNewClass) tree.init; + if (init.args != null && init.args.nonEmpty()) { + scan(init.args); + } + if (init.def != null && init.def.defs != null) { + scan(init.def.defs); + } + } + } + } else + super.visitVarDef(tree); + } + + boolean check(Info encl, Info self) { + if (excludeTags.size() > 0) { + if (encl != null && excludeTags.contains(tagNames.get(encl.tag)) + || excludeTags.contains(tagNames.get(self.tag))) + return false; + } + return tags.size() == 0 || tags.contains(tagNames.get(self.tag)); + } + + void check(String label, Info encl, Info self, boolean ok) { + if (!ok) { + if (gui) { + if (viewer == null) + viewer = new Viewer(); + viewer.addEntry(sourcefile, label, encl, self); + } + + String s = self.tree.toString(); + String msg = sourcefile.getName() + ": " + label + ": " + + "encl:" + encl + " this:" + self + "\n" + + s.substring(0, Math.min(80, s.length())).replaceAll("[\r\n]+", " "); + error(msg); + } + } + + JavaFileObject sourcefile; + Map<JCTree, Integer> endPosTable; + Info encl; + + } + + /** + * Utility class providing easy access to position and other info for a tree node. + */ + private class Info { + Info() { + tree = null; + tag = JCTree.ERRONEOUS; + start = 0; + pos = 0; + end = Integer.MAX_VALUE; + } + + Info(JCTree tree, Map<JCTree, Integer> endPosTable) { + this.tree = tree; + tag = tree.getTag(); + start = TreeInfo.getStartPos(tree); + pos = tree.pos; + end = TreeInfo.getEndPos(tree, endPosTable); + } + + @Override + public String toString() { + return tagNames.get(tree.getTag()) + "[start:" + start + ",pos:" + pos + ",end:" + end + "]"; + } + + final JCTree tree; + final int tag; + final int start; + final int pos; + final int end; + } + + /** + * Names for tree tags. + * javac does not provide an API to convert tag values to strings, so this class uses + * reflection to determine names of public static final int values in JCTree. + */ + private static class TagNames { + String get(int tag) { + if (map == null) { + map = new HashMap<Integer, String>(); + Class c = JCTree.class; + for (Field f : c.getDeclaredFields()) { + if (f.getType().equals(int.class)) { + int mods = f.getModifiers(); + if (Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods)) { + try { + map.put(f.getInt(null), f.getName()); + } catch (IllegalAccessException e) { + } + } + } + } + } + String name = map.get(tag); + return (name == null) ? "??" : name; + } + + private Map<Integer, String> map; + } + + /** + * Thrown when errors are found parsing a java file. + */ + private static class ParseException extends Exception { + ParseException(String msg) { + super(msg); + } + } + + /** + * DiagnosticListener to report diagnostics and count any errors that occur. + */ + private static class Reporter implements DiagnosticListener<JavaFileObject> { + Reporter(PrintWriter out) { + this.out = out; + } + + public void report(Diagnostic<? extends JavaFileObject> diagnostic) { + out.println(diagnostic); + switch (diagnostic.getKind()) { + case ERROR: + errors++; + } + } + int errors; + PrintWriter out; + } + + /** + * GUI viewer for issues found by TreePosTester. The viewer provides a drop + * down list for selecting error conditions, a header area providing details + * about an error, and a text area with the ranges of text highlighted as + * appropriate. + */ + private class Viewer extends JFrame { + /** + * Create a viewer. + */ + Viewer() { + initGUI(); + } + + /** + * Add another entry to the list of errors. + * @param file The file containing the error + * @param check The condition that was being tested, and which failed + * @param encl the enclosing tree node + * @param self the tree node containing the error + */ + void addEntry(JavaFileObject file, String check, Info encl, Info self) { + Entry e = new Entry(file, check, encl, self); + DefaultComboBoxModel m = (DefaultComboBoxModel) entries.getModel(); + m.addElement(e); + if (m.getSize() == 1) + entries.setSelectedItem(e); + } + + /** + * Initialize the GUI window. + */ + private void initGUI() { + JPanel head = new JPanel(new GridBagLayout()); + GridBagConstraints lc = new GridBagConstraints(); + GridBagConstraints fc = new GridBagConstraints(); + fc.anchor = GridBagConstraints.WEST; + fc.fill = GridBagConstraints.HORIZONTAL; + fc.gridwidth = GridBagConstraints.REMAINDER; + + entries = new JComboBox(); + entries.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + showEntry((Entry) entries.getSelectedItem()); + } + }); + fc.insets.bottom = 10; + head.add(entries, fc); + fc.insets.bottom = 0; + head.add(new JLabel("check:"), lc); + head.add(checkField = createTextField(80), fc); + fc.fill = GridBagConstraints.NONE; + head.add(setBackground(new JLabel("encl:"), enclColor), lc); + head.add(enclPanel = new InfoPanel(), fc); + head.add(setBackground(new JLabel("self:"), selfColor), lc); + head.add(selfPanel = new InfoPanel(), fc); + add(head, BorderLayout.NORTH); + + body = new JTextArea(); + body.setFont(Font.decode(Font.MONOSPACED)); + body.addCaretListener(new CaretListener() { + public void caretUpdate(CaretEvent e) { + int dot = e.getDot(); + int mark = e.getMark(); + if (dot == mark) + statusText.setText("dot: " + dot); + else + statusText.setText("dot: " + dot + ", mark:" + mark); + } + }); + JScrollPane p = new JScrollPane(body, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + p.setPreferredSize(new Dimension(640, 480)); + add(p, BorderLayout.CENTER); + + statusText = createTextField(80); + add(statusText, BorderLayout.SOUTH); + + pack(); + setLocationRelativeTo(null); // centered on screen + setVisible(true); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + + /** Show an entry that has been selected. */ + private void showEntry(Entry e) { + try { + // update simple fields + setTitle(e.file.getName()); + checkField.setText(e.check); + enclPanel.setInfo(e.encl); + selfPanel.setInfo(e.self); + // show file text with highlights + body.setText(e.file.getCharContent(true).toString()); + Highlighter highlighter = body.getHighlighter(); + highlighter.removeAllHighlights(); + addHighlight(highlighter, e.encl, enclColor); + addHighlight(highlighter, e.self, selfColor); + scroll(body, getMinPos(enclPanel.info, selfPanel.info)); + } catch (IOException ex) { + body.setText("Cannot read " + e.file.getName() + ": " + e); + } + } + + /** Create a test field. */ + private JTextField createTextField(int width) { + JTextField f = new JTextField(width); + f.setEditable(false); + f.setBorder(null); + return f; + } + + /** Add a highlighted region based on the positions in an Info object. */ + private void addHighlight(Highlighter h, Info info, Color c) { + int start = info.start; + int end = info.end; + if (start == -1 && end == -1) + return; + if (start == -1) + start = end; + if (end == -1) + end = start; + try { + h.addHighlight(info.start, info.end, + new DefaultHighlighter.DefaultHighlightPainter(c)); + if (info.pos != -1) { + Color c2 = new Color(c.getRed(), c.getGreen(), c.getBlue(), (int)(.4f * 255)); // 40% + h.addHighlight(info.pos, info.pos + 1, + new DefaultHighlighter.DefaultHighlightPainter(c2)); + } + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + + /** Get the minimum valid position in a set of info objects. */ + private int getMinPos(Info... values) { + int i = Integer.MAX_VALUE; + for (Info info: values) { + if (info.start >= 0) i = Math.min(i, info.start); + if (info.pos >= 0) i = Math.min(i, info.pos); + if (info.end >= 0) i = Math.min(i, info.end); + } + return (i == Integer.MAX_VALUE) ? 0 : i; + } + + /** Set the background on a component. */ + private JComponent setBackground(JComponent comp, Color c) { + comp.setOpaque(true); + comp.setBackground(c); + return comp; + } + + /** Scroll a text area to display a given position near the middle of the visible area. */ + private void scroll(final JTextArea t, final int pos) { + // Using invokeLater appears to give text a chance to sort itself out + // before the scroll happens; otherwise scrollRectToVisible doesn't work. + // Maybe there's a better way to sync with the text... + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + Rectangle r = t.modelToView(pos); + JScrollPane p = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, t); + r.y = Math.max(0, r.y - p.getHeight() * 2 / 5); + r.height += p.getHeight() * 4 / 5; + t.scrollRectToVisible(r); + } catch (BadLocationException ignore) { + } + } + }); + } + + private JComboBox entries; + private JTextField checkField; + private InfoPanel enclPanel; + private InfoPanel selfPanel; + private JTextArea body; + private JTextField statusText; + + private Color selfColor = new Color(0.f, 1.f, 0.f, 0.2f); // 20% green + private Color enclColor = new Color(1.f, 0.f, 0.f, 0.2f); // 20% red + + /** Panel to display an Info object. */ + private class InfoPanel extends JPanel { + InfoPanel() { + add(tagName = createTextField(20)); + add(new JLabel("start:")); + add(addListener(start = createTextField(6))); + add(new JLabel("pos:")); + add(addListener(pos = createTextField(6))); + add(new JLabel("end:")); + add(addListener(end = createTextField(6))); + } + + void setInfo(Info info) { + this.info = info; + tagName.setText(tagNames.get(info.tag)); + start.setText(String.valueOf(info.start)); + pos.setText(String.valueOf(info.pos)); + end.setText(String.valueOf(info.end)); + } + + JTextField addListener(final JTextField f) { + f.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + body.setCaretPosition(Integer.valueOf(f.getText())); + body.getCaret().setVisible(true); + } + }); + return f; + } + + Info info; + JTextField tagName; + JTextField start; + JTextField pos; + JTextField end; + } + + /** Object to record information about an error to be displayed. */ + private class Entry { + Entry(JavaFileObject file, String check, Info encl, Info self) { + this.file = file; + this.check = check; + this.encl = encl; + this.self= self; + } + + @Override + public String toString() { + return file.getName() + " " + check + " " + getMinPos(encl, self); + } + + final JavaFileObject file; + final String check; + final Info encl; + final Info self; + } + } +} +
--- a/test/tools/javac/treepostests/TreePosTest.java Thu Mar 04 13:50:33 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,762 +0,0 @@ -/* - * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.EventQueue; -import java.awt.Font; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.io.File; -import java.io.IOException; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.swing.DefaultComboBoxModel; -import javax.swing.JComboBox; -import javax.swing.JComponent; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.JTextField; -import javax.swing.SwingUtilities; -import javax.swing.event.CaretEvent; -import javax.swing.event.CaretListener; -import javax.swing.text.BadLocationException; -import javax.swing.text.DefaultHighlighter; -import javax.swing.text.Highlighter; -import javax.tools.Diagnostic; -import javax.tools.DiagnosticListener; -import javax.tools.JavaFileObject; -import javax.tools.StandardJavaFileManager; - -import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.util.JavacTask; -import com.sun.tools.javac.api.JavacTool; -import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; -import com.sun.tools.javac.tree.JCTree.JCNewClass; -import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.tree.TreeInfo; -import com.sun.tools.javac.tree.TreeScanner; - -import static com.sun.tools.javac.util.Position.NOPOS; - -/** - * Utility and test program to check validity of tree positions for tree nodes. - * The program can be run standalone, or as a jtreg test. In standalone mode, - * errors can be displayed in a gui viewer. For info on command line args, - * run program with no args. - * - * <p> - * jtreg: Note that by using the -r switch in the test description below, this test - * will process all java files in the langtools/test directory, thus implicitly - * covering any new language features that may be tested in this test suite. - */ - -/* - * @test - * @bug 6919889 - * @summary assorted position errors in compiler syntax trees - * @run main TreePosTest -q -r -ef ./tools/javac/typeAnnotations -ef ./tools/javap/typeAnnotations -et ANNOTATED_TYPE . - */ -public class TreePosTest { - /** - * Main entry point. - * If test.src is set, program runs in jtreg mode, and will throw an Error - * if any errors arise, otherwise System.exit will be used, unless the gui - * viewer is being used. In jtreg mode, the default base directory for file - * args is the value of ${test.src}. In jtreg mode, the -r option can be - * given to change the default base directory to the root test directory. - */ - public static void main(String... args) { - String testSrc = System.getProperty("test.src"); - File baseDir = (testSrc == null) ? null : new File(testSrc); - boolean ok = new TreePosTest().run(baseDir, args); - if (!ok) { - if (testSrc != null) // jtreg mode - throw new Error("failed"); - else - System.exit(1); - } - } - - /** - * Run the program. A base directory can be provided for file arguments. - * In jtreg mode, the -r option can be given to change the default base - * directory to the test root directory. For other options, see usage(). - * @param baseDir base directory for any file arguments. - * @param args command line args - * @return true if successful or in gui mode - */ - boolean run(File baseDir, String... args) { - if (args.length == 0) { - usage(System.out); - return true; - } - - List<File> files = new ArrayList<File>(); - for (int i = 0; i < args.length; i++) { - String arg = args[i]; - if (arg.equals("-encoding") && i + 1 < args.length) - encoding = args[++i]; - else if (arg.equals("-gui")) - gui = true; - else if (arg.equals("-q")) - quiet = true; - else if (arg.equals("-v")) - verbose = true; - else if (arg.equals("-t") && i + 1 < args.length) - tags.add(args[++i]); - else if (arg.equals("-ef") && i + 1 < args.length) - excludeFiles.add(new File(baseDir, args[++i])); - else if (arg.equals("-et") && i + 1 < args.length) - excludeTags.add(args[++i]); - else if (arg.equals("-r")) { - if (excludeFiles.size() > 0) - throw new Error("-r must be used before -ef"); - File d = baseDir; - while (!new File(d, "TEST.ROOT").exists()) { - d = d.getParentFile(); - if (d == null) - throw new Error("cannot find TEST.ROOT"); - } - baseDir = d; - } - else if (arg.startsWith("-")) - throw new Error("unknown option: " + arg); - else { - while (i < args.length) - files.add(new File(baseDir, args[i++])); - } - } - - for (File file: files) { - if (file.exists()) - test(file); - else - error("File not found: " + file); - } - - if (fileCount != 1) - System.err.println(fileCount + " files read"); - if (errors > 0) - System.err.println(errors + " errors"); - - return (gui || errors == 0); - } - - /** - * Print command line help. - * @param out output stream - */ - void usage(PrintStream out) { - out.println("Usage:"); - out.println(" java TreePosTest options... files..."); - out.println(""); - out.println("where options include:"); - out.println("-gui Display returns in a GUI viewer"); - out.println("-q Quiet: don't report on inapplicable files"); - out.println("-v Verbose: report on files as they are being read"); - out.println("-t tag Limit checks to tree nodes with this tag"); - out.println(" Can be repeated if desired"); - out.println("-ef file Exclude file or directory"); - out.println("-et tag Exclude tree nodes with given tag name"); - out.println(""); - out.println("files may be directories or files"); - out.println("directories will be scanned recursively"); - out.println("non java files, or java files which cannot be parsed, will be ignored"); - out.println(""); - } - - /** - * Test a file. If the file is a directory, it will be recursively scanned - * for java files. - * @param file the file or directory to test - */ - void test(File file) { - if (excludeFiles.contains(file)) { - if (!quiet) - error("File " + file + " excluded"); - return; - } - - if (file.isDirectory()) { - for (File f: file.listFiles()) { - test(f); - } - return; - } - - if (file.isFile() && file.getName().endsWith(".java")) { - try { - if (verbose) - System.err.println(file); - fileCount++; - PosTester p = new PosTester(); - p.test(read(file)); - } catch (ParseException e) { - if (!quiet) { - error("Error parsing " + file + "\n" + e.getMessage()); - } - } catch (IOException e) { - error("Error reading " + file + ": " + e); - } - return; - } - - if (!quiet) - error("File " + file + " ignored"); - } - - /** - * Read a file. - * @param file the file to be read - * @return the tree for the content of the file - * @throws IOException if any IO errors occur - * @throws TreePosTest.ParseException if any errors occur while parsing the file - */ - JCCompilationUnit read(File file) throws IOException, ParseException { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - Reporter r = new Reporter(pw); - JavacTool tool = JavacTool.create(); - Charset cs = (encoding == null ? null : Charset.forName(encoding)); - StandardJavaFileManager fm = tool.getStandardFileManager(r, null, null); - Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(file); - JavacTask task = tool.getTask(pw, fm, r, Collections.<String>emptyList(), null, files); - Iterable<? extends CompilationUnitTree> trees = task.parse(); - pw.flush(); - if (r.errors > 0) - throw new ParseException(sw.toString()); - Iterator<? extends CompilationUnitTree> iter = trees.iterator(); - if (!iter.hasNext()) - throw new Error("no trees found"); - JCCompilationUnit t = (JCCompilationUnit) iter.next(); - if (iter.hasNext()) - throw new Error("too many trees found"); - return t; - } - - /** - * Report an error. When the program is complete, the program will either - * exit or throw an Error if any errors have been reported. - * @param msg the error message - */ - void error(String msg) { - System.err.println(msg); - errors++; - } - - /** Number of files that have been analyzed. */ - int fileCount; - /** Number of errors reported. */ - int errors; - /** Flag: don't report irrelevant files. */ - boolean quiet; - /** Flag: report files as they are processed. */ - boolean verbose; - /** Flag: show errors in GUI viewer. */ - boolean gui; - /** Option: encoding for test files. */ - String encoding; - /** The GUI viewer for errors. */ - Viewer viewer; - /** The set of tags for tree nodes to be analyzed; if empty, all tree nodes - * are analyzed. */ - Set<String> tags = new HashSet<String>(); - /** Set of files and directories to be excluded from analysis. */ - Set<File> excludeFiles = new HashSet<File>(); - /** Set of tag names to be excluded from analysis. */ - Set<String> excludeTags = new HashSet<String>(); - /** Table of printable names for tree tag values. */ - TagNames tagNames = new TagNames(); - - /** - * Main class for testing assertions concerning tree positions for tree nodes. - */ - private class PosTester extends TreeScanner { - void test(JCCompilationUnit tree) { - sourcefile = tree.sourcefile; - endPosTable = tree.endPositions; - encl = new Info(); - tree.accept(this); - } - - @Override - public void scan(JCTree tree) { - if (tree == null) - return; - - Info self = new Info(tree, endPosTable); - if (check(encl, self)) { - // Modifiers nodes are present throughout the tree even where - // there is no corresponding source text. - // Redundant semicolons in a class definition can cause empty - // initializer blocks with no positions. - if ((self.tag == JCTree.MODIFIERS || self.tag == JCTree.BLOCK) - && self.pos == NOPOS) { - // If pos is NOPOS, so should be the start and end positions - check("start == NOPOS", encl, self, self.start == NOPOS); - check("end == NOPOS", encl, self, self.end == NOPOS); - } else { - // For this node, start , pos, and endpos should be all defined - check("start != NOPOS", encl, self, self.start != NOPOS); - check("pos != NOPOS", encl, self, self.pos != NOPOS); - check("end != NOPOS", encl, self, self.end != NOPOS); - // The following should normally be ordered - // encl.start <= start <= pos <= end <= encl.end - // In addition, the position of the enclosing node should be - // within this node. - // The primary exceptions are for array type nodes, because of the - // need to support legacy syntax: - // e.g. int a[]; int[] b[]; int f()[] { return null; } - // and because of inconsistent nesting of left and right of - // array declarations: - // e.g. int[][] a = new int[2][]; - check("encl.start <= start", encl, self, encl.start <= self.start); - check("start <= pos", encl, self, self.start <= self.pos); - if (!(self.tag == JCTree.TYPEARRAY - && (encl.tag == JCTree.VARDEF || encl.tag == JCTree.TYPEARRAY))) { - check("encl.pos <= start || end <= encl.pos", - encl, self, encl.pos <= self.start || self.end <= encl.pos); - } - check("pos <= end", encl, self, self.pos <= self.end); - if (!(self.tag == JCTree.TYPEARRAY && encl.tag == JCTree.TYPEARRAY)) { - check("end <= encl.end", encl, self, self.end <= encl.end); - } - } - } - - Info prevEncl = encl; - encl = self; - tree.accept(this); - encl = prevEncl; - } - - @Override - public void visitVarDef(JCVariableDecl tree) { - // enum member declarations are desugared in the parser and have - // ill-defined semantics for tree positions, so for now, we - // skip the synthesized bits and just check parts which came from - // the original source text - if ((tree.mods.flags & Flags.ENUM) != 0) { - scan(tree.mods); - if (tree.init != null) { - if (tree.init.getTag() == JCTree.NEWCLASS) { - JCNewClass init = (JCNewClass) tree.init; - if (init.args != null && init.args.nonEmpty()) { - scan(init.args); - } - if (init.def != null && init.def.defs != null) { - scan(init.def.defs); - } - } - } - } else - super.visitVarDef(tree); - } - - boolean check(Info encl, Info self) { - if (excludeTags.size() > 0) { - if (encl != null && excludeTags.contains(tagNames.get(encl.tag)) - || excludeTags.contains(tagNames.get(self.tag))) - return false; - } - return tags.size() == 0 || tags.contains(tagNames.get(self.tag)); - } - - void check(String label, Info encl, Info self, boolean ok) { - if (!ok) { - if (gui) { - if (viewer == null) - viewer = new Viewer(); - viewer.addEntry(sourcefile, label, encl, self); - } - - String s = self.tree.toString(); - String msg = sourcefile.getName() + ": " + label + ": " + - "encl:" + encl + " this:" + self + "\n" + - s.substring(0, Math.min(80, s.length())).replaceAll("[\r\n]+", " "); - error(msg); - } - } - - JavaFileObject sourcefile; - Map<JCTree, Integer> endPosTable; - Info encl; - - } - - /** - * Utility class providing easy access to position and other info for a tree node. - */ - private class Info { - Info() { - tree = null; - tag = JCTree.ERRONEOUS; - start = 0; - pos = 0; - end = Integer.MAX_VALUE; - } - - Info(JCTree tree, Map<JCTree, Integer> endPosTable) { - this.tree = tree; - tag = tree.getTag(); - start = TreeInfo.getStartPos(tree); - pos = tree.pos; - end = TreeInfo.getEndPos(tree, endPosTable); - } - - @Override - public String toString() { - return tagNames.get(tree.getTag()) + "[start:" + start + ",pos:" + pos + ",end:" + end + "]"; - } - - final JCTree tree; - final int tag; - final int start; - final int pos; - final int end; - } - - /** - * Names for tree tags. - * javac does not provide an API to convert tag values to strings, so this class uses - * reflection to determine names of public static final int values in JCTree. - */ - private static class TagNames { - String get(int tag) { - if (map == null) { - map = new HashMap<Integer, String>(); - Class c = JCTree.class; - for (Field f : c.getDeclaredFields()) { - if (f.getType().equals(int.class)) { - int mods = f.getModifiers(); - if (Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods)) { - try { - map.put(f.getInt(null), f.getName()); - } catch (IllegalAccessException e) { - } - } - } - } - } - String name = map.get(tag); - return (name == null) ? "??" : name; - } - - private Map<Integer, String> map; - } - - /** - * Thrown when errors are found parsing a java file. - */ - private static class ParseException extends Exception { - ParseException(String msg) { - super(msg); - } - } - - /** - * DiagnosticListener to report diagnostics and count any errors that occur. - */ - private static class Reporter implements DiagnosticListener<JavaFileObject> { - Reporter(PrintWriter out) { - this.out = out; - } - - public void report(Diagnostic<? extends JavaFileObject> diagnostic) { - out.println(diagnostic); - switch (diagnostic.getKind()) { - case ERROR: - errors++; - } - } - int errors; - PrintWriter out; - } - - /** - * GUI viewer for issues found by TreePosTester. The viewer provides a drop - * down list for selecting error conditions, a header area providing details - * about an error, and a text area with the ranges of text highlighted as - * appropriate. - */ - private class Viewer extends JFrame { - /** - * Create a viewer. - */ - Viewer() { - initGUI(); - } - - /** - * Add another entry to the list of errors. - * @param file The file containing the error - * @param check The condition that was being tested, and which failed - * @param encl the enclosing tree node - * @param self the tree node containing the error - */ - void addEntry(JavaFileObject file, String check, Info encl, Info self) { - Entry e = new Entry(file, check, encl, self); - DefaultComboBoxModel m = (DefaultComboBoxModel) entries.getModel(); - m.addElement(e); - if (m.getSize() == 1) - entries.setSelectedItem(e); - } - - /** - * Initialize the GUI window. - */ - private void initGUI() { - JPanel head = new JPanel(new GridBagLayout()); - GridBagConstraints lc = new GridBagConstraints(); - GridBagConstraints fc = new GridBagConstraints(); - fc.anchor = GridBagConstraints.WEST; - fc.fill = GridBagConstraints.HORIZONTAL; - fc.gridwidth = GridBagConstraints.REMAINDER; - - entries = new JComboBox(); - entries.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - showEntry((Entry) entries.getSelectedItem()); - } - }); - fc.insets.bottom = 10; - head.add(entries, fc); - fc.insets.bottom = 0; - head.add(new JLabel("check:"), lc); - head.add(checkField = createTextField(80), fc); - fc.fill = GridBagConstraints.NONE; - head.add(setBackground(new JLabel("encl:"), enclColor), lc); - head.add(enclPanel = new InfoPanel(), fc); - head.add(setBackground(new JLabel("self:"), selfColor), lc); - head.add(selfPanel = new InfoPanel(), fc); - add(head, BorderLayout.NORTH); - - body = new JTextArea(); - body.setFont(Font.decode(Font.MONOSPACED)); - body.addCaretListener(new CaretListener() { - public void caretUpdate(CaretEvent e) { - int dot = e.getDot(); - int mark = e.getMark(); - if (dot == mark) - statusText.setText("dot: " + dot); - else - statusText.setText("dot: " + dot + ", mark:" + mark); - } - }); - JScrollPane p = new JScrollPane(body, - JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, - JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - p.setPreferredSize(new Dimension(640, 480)); - add(p, BorderLayout.CENTER); - - statusText = createTextField(80); - add(statusText, BorderLayout.SOUTH); - - pack(); - setLocationRelativeTo(null); // centered on screen - setVisible(true); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - } - - /** Show an entry that has been selected. */ - private void showEntry(Entry e) { - try { - // update simple fields - setTitle(e.file.getName()); - checkField.setText(e.check); - enclPanel.setInfo(e.encl); - selfPanel.setInfo(e.self); - // show file text with highlights - body.setText(e.file.getCharContent(true).toString()); - Highlighter highlighter = body.getHighlighter(); - highlighter.removeAllHighlights(); - addHighlight(highlighter, e.encl, enclColor); - addHighlight(highlighter, e.self, selfColor); - scroll(body, getMinPos(enclPanel.info, selfPanel.info)); - } catch (IOException ex) { - body.setText("Cannot read " + e.file.getName() + ": " + e); - } - } - - /** Create a test field. */ - private JTextField createTextField(int width) { - JTextField f = new JTextField(width); - f.setEditable(false); - f.setBorder(null); - return f; - } - - /** Add a highlighted region based on the positions in an Info object. */ - private void addHighlight(Highlighter h, Info info, Color c) { - int start = info.start; - int end = info.end; - if (start == -1 && end == -1) - return; - if (start == -1) - start = end; - if (end == -1) - end = start; - try { - h.addHighlight(info.start, info.end, - new DefaultHighlighter.DefaultHighlightPainter(c)); - if (info.pos != -1) { - Color c2 = new Color(c.getRed(), c.getGreen(), c.getBlue(), (int)(.4f * 255)); // 40% - h.addHighlight(info.pos, info.pos + 1, - new DefaultHighlighter.DefaultHighlightPainter(c2)); - } - } catch (BadLocationException e) { - e.printStackTrace(); - } - } - - /** Get the minimum valid position in a set of info objects. */ - private int getMinPos(Info... values) { - int i = Integer.MAX_VALUE; - for (Info info: values) { - if (info.start >= 0) i = Math.min(i, info.start); - if (info.pos >= 0) i = Math.min(i, info.pos); - if (info.end >= 0) i = Math.min(i, info.end); - } - return (i == Integer.MAX_VALUE) ? 0 : i; - } - - /** Set the background on a component. */ - private JComponent setBackground(JComponent comp, Color c) { - comp.setOpaque(true); - comp.setBackground(c); - return comp; - } - - /** Scroll a text area to display a given position near the middle of the visible area. */ - private void scroll(final JTextArea t, final int pos) { - // Using invokeLater appears to give text a chance to sort itself out - // before the scroll happens; otherwise scrollRectToVisible doesn't work. - // Maybe there's a better way to sync with the text... - EventQueue.invokeLater(new Runnable() { - public void run() { - try { - Rectangle r = t.modelToView(pos); - JScrollPane p = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, t); - r.y = Math.max(0, r.y - p.getHeight() * 2 / 5); - r.height += p.getHeight() * 4 / 5; - t.scrollRectToVisible(r); - } catch (BadLocationException ignore) { - } - } - }); - } - - private JComboBox entries; - private JTextField checkField; - private InfoPanel enclPanel; - private InfoPanel selfPanel; - private JTextArea body; - private JTextField statusText; - - private Color selfColor = new Color(0.f, 1.f, 0.f, 0.2f); // 20% green - private Color enclColor = new Color(1.f, 0.f, 0.f, 0.2f); // 20% red - - /** Panel to display an Info object. */ - private class InfoPanel extends JPanel { - InfoPanel() { - add(tagName = createTextField(20)); - add(new JLabel("start:")); - add(addListener(start = createTextField(6))); - add(new JLabel("pos:")); - add(addListener(pos = createTextField(6))); - add(new JLabel("end:")); - add(addListener(end = createTextField(6))); - } - - void setInfo(Info info) { - this.info = info; - tagName.setText(tagNames.get(info.tag)); - start.setText(String.valueOf(info.start)); - pos.setText(String.valueOf(info.pos)); - end.setText(String.valueOf(info.end)); - } - - JTextField addListener(final JTextField f) { - f.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - body.setCaretPosition(Integer.valueOf(f.getText())); - body.getCaret().setVisible(true); - } - }); - return f; - } - - Info info; - JTextField tagName; - JTextField start; - JTextField pos; - JTextField end; - } - - /** Object to record information about an error to be displayed. */ - private class Entry { - Entry(JavaFileObject file, String check, Info encl, Info self) { - this.file = file; - this.check = check; - this.encl = encl; - this.self= self; - } - - @Override - public String toString() { - return file.getName() + " " + check + " " + getMinPos(encl, self); - } - - final JavaFileObject file; - final String check; - final Info encl; - final Info self; - } - } -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javah/T6893943.java Tue Mar 09 15:29:45 2010 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6893943 + * @summary exit code from javah with no args is 0 + */ + +import java.io.*; +import java.util.*; + +public class T6893943 { + public static void main(String... args) throws Exception { + new T6893943().run(); + } + + void run() throws Exception { + testSimpleAPI(); + testCommand(); + } + + void testSimpleAPI() throws Exception { + PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.err)); + int rc = com.sun.tools.javah.Main.run(new String[] { }, pw); + expect("testSimpleAPI", rc, 1); + } + + void testCommand() throws Exception { + File javaHome = new File(System.getProperty("java.home")); + if (javaHome.getName().equals("jre")) + javaHome = javaHome.getParentFile(); + + List<String> command = new ArrayList<String>(); + command.add(new File(new File(javaHome, "bin"), "javah").getPath()); + command.add("-J-Xbootclasspath:" + System.getProperty("sun.boot.class.path")); + //System.err.println("command: " + command); + + ProcessBuilder pb = new ProcessBuilder(command); + pb.redirectErrorStream(true); + Process p = pb.start(); + p.getOutputStream().close(); + String line; + BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream())); + while ((line = in.readLine()) != null) + System.err.println("javah: " + line); + int rc = p.waitFor(); + expect("testCommand", rc, 1); + } + + void expect(String name, int actual, int expect) throws Exception { + if (actual != expect) + throw new Exception(name + ": unexpected exit: " + actual + ", expected: " + expect); + } +}