This commit is contained in:
Lana Steuck 2010-03-09 15:29:45 -08:00
commit a5884c7b3d
61 changed files with 912 additions and 156 deletions

View File

@ -457,8 +457,10 @@ public class Apt extends ListBuffer<Env<AttrContext>> {
throw new UsageMessageNeededException(); throw new UsageMessageNeededException();
try { try {
for(AnnotationProcessorFactory apFactory: factoryToAnnotation.keySet()) { for(Map.Entry<AnnotationProcessorFactory, Set<AnnotationTypeDeclaration>> entry :
AnnotationProcessor processor = apFactory.getProcessorFor(factoryToAnnotation.get(apFactory), factoryToAnnotation.entrySet()) {
AnnotationProcessorFactory apFactory = entry.getKey();
AnnotationProcessor processor = apFactory.getProcessorFor(entry.getValue(),
trivAPE); trivAPE);
if (processor != null) if (processor != null)
processors.add(processor); processors.add(processor);

View File

@ -82,7 +82,7 @@ public class CommandLine {
st.commentChar('#'); st.commentChar('#');
st.quoteChar('"'); st.quoteChar('"');
st.quoteChar('\''); st.quoteChar('\'');
while (st.nextToken() != st.TT_EOF) { while (st.nextToken() != StreamTokenizer.TT_EOF) {
args.append(st.sval); args.append(st.sval);
} }
r.close(); r.close();

View File

@ -270,7 +270,7 @@ class AnnotationProxyMaker {
* The toString, hashCode, and equals methods foward to the underlying * The toString, hashCode, and equals methods foward to the underlying
* type. * type.
*/ */
private static class MirroredTypeExceptionProxy extends ExceptionProxy { private static final class MirroredTypeExceptionProxy extends ExceptionProxy {
private static final long serialVersionUID = 6662035281599933545L; private static final long serialVersionUID = 6662035281599933545L;
private MirroredTypeException ex; private MirroredTypeException ex;
@ -312,7 +312,7 @@ class AnnotationProxyMaker {
* The toString, hashCode, and equals methods foward to the underlying * The toString, hashCode, and equals methods foward to the underlying
* types. * types.
*/ */
private static class MirroredTypesExceptionProxy extends ExceptionProxy { private static final class MirroredTypesExceptionProxy extends ExceptionProxy {
private static final long serialVersionUID = -6670822532616693951L; private static final long serialVersionUID = -6670822532616693951L;
private MirroredTypesException ex; private MirroredTypesException ex;

View File

@ -58,7 +58,7 @@ public abstract class DeclarationImpl implements Declaration {
protected final AptEnv env; protected final AptEnv env;
public final Symbol sym; public final Symbol sym;
protected static DeclarationFilter identityFilter = protected static final DeclarationFilter identityFilter =
new DeclarationFilter(); new DeclarationFilter();

View File

@ -71,6 +71,6 @@ public abstract class TypeMirrorImpl implements TypeMirror {
* {@inheritDoc} * {@inheritDoc}
*/ */
public int hashCode() { public int hashCode() {
return env.jctypes.hashCode(type); return Types.hashCode(type);
} }
} }

View File

@ -40,7 +40,7 @@ import java.util.Iterator;
*/ */
public class ConstantPool { public class ConstantPool {
public class InvalidIndex extends ConstantPoolException { public static class InvalidIndex extends ConstantPoolException {
private static final long serialVersionUID = -4350294289300939730L; private static final long serialVersionUID = -4350294289300939730L;
InvalidIndex(int index) { InvalidIndex(int index) {
super(index); super(index);
@ -53,7 +53,7 @@ public class ConstantPool {
} }
} }
public class UnexpectedEntry extends ConstantPoolException { public static class UnexpectedEntry extends ConstantPoolException {
private static final long serialVersionUID = 6986335935377933211L; private static final long serialVersionUID = 6986335935377933211L;
UnexpectedEntry(int index, int expected_tag, int found_tag) { UnexpectedEntry(int index, int expected_tag, int found_tag) {
super(index); super(index);
@ -71,7 +71,7 @@ public class ConstantPool {
public final int found_tag; public final int found_tag;
} }
public class InvalidEntry extends ConstantPoolException { public static class InvalidEntry extends ConstantPoolException {
private static final long serialVersionUID = 1000087545585204447L; private static final long serialVersionUID = 1000087545585204447L;
InvalidEntry(int index, int tag) { InvalidEntry(int index, int tag) {
super(index); super(index);
@ -87,7 +87,7 @@ public class ConstantPool {
public final int tag; public final int tag;
} }
public class EntryNotFound extends ConstantPoolException { public static class EntryNotFound extends ConstantPoolException {
private static final long serialVersionUID = 2885537606468581850L; private static final long serialVersionUID = 2885537606468581850L;
EntryNotFound(Object value) { EntryNotFound(Object value) {
super(-1); super(-1);
@ -694,7 +694,7 @@ public class ConstantPool {
public int byteLength() { public int byteLength() {
class SizeOutputStream extends OutputStream { class SizeOutputStream extends OutputStream {
@Override @Override
public void write(int b) throws IOException { public void write(int b) {
size++; size++;
} }
int size; int size;

View File

@ -31,23 +31,21 @@ import com.sun.tools.doclets.formats.html.*;
public class Standard { public class Standard {
public static final HtmlDoclet htmlDoclet = new HtmlDoclet();
public static int optionLength(String option) { public static int optionLength(String option) {
return htmlDoclet.optionLength(option); return HtmlDoclet.optionLength(option);
} }
public static boolean start(RootDoc root) { public static boolean start(RootDoc root) {
return htmlDoclet.start(root); return HtmlDoclet.start(root);
} }
public static boolean validOptions(String[][] options, public static boolean validOptions(String[][] options,
DocErrorReporter reporter) { DocErrorReporter reporter) {
return htmlDoclet.validOptions(options, reporter); return HtmlDoclet.validOptions(options, reporter);
} }
public static LanguageVersion languageVersion() { public static LanguageVersion languageVersion() {
return htmlDoclet.languageVersion(); return HtmlDoclet.languageVersion();
} }
} }

View File

@ -64,7 +64,7 @@ class Launcher {
fileChooser.setSelectedFile(new File(fileName)); fileChooser.setSelectedFile(new File(fileName));
} }
} }
if (fileChooser.showOpenDialog(null) == fileChooser.APPROVE_OPTION) { if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
String fileName = fileChooser.getSelectedFile().getPath(); String fileName = fileChooser.getSelectedFile().getPath();
prefs.put("recent.file", fileName); prefs.put("recent.file", fileName);
javac.run(System.in, null, null, "-d", "/tmp", fileName); javac.run(System.in, null, null, "-d", "/tmp", fileName);

View File

@ -137,7 +137,7 @@ public final class JavacTool implements JavaCompiler {
} }
private static boolean match(OptionKind clientKind, OptionKind optionKind) { 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( public JavacFileManager getStandardFileManager(

View File

@ -198,7 +198,12 @@ public class Lint
/** /**
* Warn about Sun proprietary API that may be removed in a future release. * 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) { LintCategory(String option) {
this(option, false); this(option, false);

View File

@ -162,7 +162,7 @@ public abstract class Symbol implements Element {
* the default package; otherwise, the owner symbol is returned * the default package; otherwise, the owner symbol is returned
*/ */
public Symbol location() { 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 null;
} }
return owner; return owner;

View File

@ -2504,7 +2504,7 @@ public class Types {
} }
@Override @Override
public int hashCode() { public int hashCode() {
return 127 * Types.this.hashCode(t1) + Types.this.hashCode(t2); return 127 * Types.hashCode(t1) + Types.hashCode(t2);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
@ -3375,7 +3375,7 @@ public class Types {
this.t = t; this.t = t;
} }
public int hashCode() { public int hashCode() {
return Types.this.hashCode(t); return Types.hashCode(t);
} }
public boolean equals(Object obj) { public boolean equals(Object obj) {
return (obj instanceof SingletonType) && return (obj instanceof SingletonType) &&

View File

@ -2020,6 +2020,10 @@ public class Attr extends JCTree.Visitor {
tree.pos(), site, sym.name, true); 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', ... // If we are selecting an instance member via a `super', ...
@ -2636,6 +2640,7 @@ public class Attr extends JCTree.Visitor {
if (tree.bounds.tail.nonEmpty()) { if (tree.bounds.tail.nonEmpty()) {
log.error(tree.bounds.tail.head.pos(), log.error(tree.bounds.tail.head.pos(),
"type.var.may.not.be.followed.by.other.bounds"); "type.var.may.not.be.followed.by.other.bounds");
log.unrecoverableError = true;
tree.bounds = List.of(tree.bounds.head); tree.bounds = List.of(tree.bounds.head);
a.bound = bs.head; a.bound = bs.head;
} }

View File

@ -189,6 +189,11 @@ public class Check {
sunApiHandler.report(pos, msg, args); 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. * Report any deferred diagnostics.
*/ */

View File

@ -270,6 +270,7 @@ public class Enter extends JCTree.Visitor {
return ts.toList(); return ts.toList();
} }
@Override
public void visitTopLevel(JCCompilationUnit tree) { public void visitTopLevel(JCCompilationUnit tree) {
JavaFileObject prev = log.useSource(tree.sourcefile); JavaFileObject prev = log.useSource(tree.sourcefile);
boolean addEnv = false; boolean addEnv = false;
@ -289,13 +290,13 @@ public class Enter extends JCTree.Visitor {
tree.packge = syms.unnamedPackage; tree.packge = syms.unnamedPackage;
} }
tree.packge.complete(); // Find all classes in package. 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. // Save environment of package-info.java file.
if (isPkgInfo) { if (isPkgInfo) {
Env<AttrContext> env0 = typeEnvs.get(tree.packge); Env<AttrContext> env0 = typeEnvs.get(tree.packge);
if (env0 == null) { if (env0 == null) {
typeEnvs.put(tree.packge, env); typeEnvs.put(tree.packge, topEnv);
} else { } else {
JCCompilationUnit tree0 = env0.toplevel; JCCompilationUnit tree0 = env0.toplevel;
if (!fileManager.isSameFile(tree.sourcefile, tree0.sourcefile)) { if (!fileManager.isSameFile(tree.sourcefile, tree0.sourcefile)) {
@ -306,7 +307,7 @@ public class Enter extends JCTree.Visitor {
if (addEnv || (tree0.packageAnnotations.isEmpty() && if (addEnv || (tree0.packageAnnotations.isEmpty() &&
tree.docComments != null && tree.docComments != null &&
tree.docComments.get(tree) != null)) { tree.docComments.get(tree) != null)) {
typeEnvs.put(tree.packge, env); typeEnvs.put(tree.packge, topEnv);
} }
} }
} }
@ -322,14 +323,15 @@ public class Enter extends JCTree.Visitor {
c.members_field = new Scope(c); c.members_field = new Scope(c);
tree.packge.package_info = c; tree.packge.package_info = c;
} }
classEnter(tree.defs, env); classEnter(tree.defs, topEnv);
if (addEnv) { if (addEnv) {
todo.append(env); todo.append(topEnv);
} }
log.useSource(prev); log.useSource(prev);
result = null; result = null;
} }
@Override
public void visitClassDef(JCClassDecl tree) { public void visitClassDef(JCClassDecl tree) {
Symbol owner = env.info.scope.owner; Symbol owner = env.info.scope.owner;
Scope enclScope = enterScope(env); Scope enclScope = enterScope(env);
@ -435,6 +437,7 @@ public class Enter extends JCTree.Visitor {
* Enter a symbol for type parameter in local scope, after checking that it * Enter a symbol for type parameter in local scope, after checking that it
* is unique. * is unique.
*/ */
@Override
public void visitTypeParameter(JCTypeParameter tree) { public void visitTypeParameter(JCTypeParameter tree) {
TypeVar a = (tree.type != null) TypeVar a = (tree.type != null)
? (TypeVar)tree.type ? (TypeVar)tree.type
@ -448,6 +451,7 @@ public class Enter extends JCTree.Visitor {
/** Default class enter visitor method: do nothing. /** Default class enter visitor method: do nothing.
*/ */
@Override
public void visitTree(JCTree tree) { public void visitTree(JCTree tree) {
result = null; result = null;
} }
@ -489,10 +493,8 @@ public class Enter extends JCTree.Visitor {
for (JCCompilationUnit tree : trees) { for (JCCompilationUnit tree : trees) {
if (tree.starImportScope.elems == null) { if (tree.starImportScope.elems == null) {
JavaFileObject prev = log.useSource(tree.sourcefile); JavaFileObject prev = log.useSource(tree.sourcefile);
Env<AttrContext> env = typeEnvs.get(tree); Env<AttrContext> topEnv = topLevelEnv(tree);
if (env == null) memberEnter.memberEnter(tree, topEnv);
env = topLevelEnv(tree);
memberEnter.memberEnter(tree, env);
log.useSource(prev); log.useSource(prev);
} }
} }

View File

@ -607,10 +607,12 @@ public class TransTypes extends TreeTranslator {
public void visitNewArray(JCNewArray tree) { public void visitNewArray(JCNewArray tree) {
tree.elemtype = translate(tree.elemtype, null); tree.elemtype = translate(tree.elemtype, null);
translate(tree.dims, syms.intType); translate(tree.dims, syms.intType);
tree.elems = translate(tree.elems, if (tree.type != null) {
(tree.type == null) ? null tree.elems = translate(tree.elems, erasure(types.elemtype(tree.type)));
: erasure(types.elemtype(tree.type))); tree.type = erasure(tree.type);
tree.type = erasure(tree.type); } else {
tree.elems = translate(tree.elems, null);
}
result = tree; result = tree;
} }

View File

@ -260,7 +260,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
archive = openArchive(directory); archive = openArchive(directory);
} catch (IOException ex) { } catch (IOException ex) {
log.error("error.reading.file", log.error("error.reading.file",
directory, ex.getLocalizedMessage()); directory, getMessage(ex));
return; return;
} }
} }
@ -489,7 +489,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
archive = new MissingArchive(zipFileName); archive = new MissingArchive(zipFileName);
} catch (IOException ex) { } catch (IOException ex) {
if (zipFileName.exists()) if (zipFileName.exists())
log.error("error.reading.file", zipFileName, ex.getLocalizedMessage()); log.error("error.reading.file", zipFileName, getMessage(ex));
archive = new MissingArchive(zipFileName); archive = new MissingArchive(zipFileName);
} }
@ -838,4 +838,23 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
} }
throw new IllegalArgumentException("Invalid relative path: " + file); 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();
}
} }

View File

@ -320,7 +320,7 @@ public class Paths {
addFile(f, warn); addFile(f, warn);
} }
} catch (IOException e) { } catch (IOException e) {
log.error("error.reading.file", jarFile, e.getLocalizedMessage()); log.error("error.reading.file", jarFile, JavacFileManager.getMessage(e));
} }
} }
} }

View File

@ -1135,7 +1135,7 @@ public class ClassReader implements Completer {
self.name = simpleBinaryName(self.flatname, c.flatname) ; self.name = simpleBinaryName(self.flatname, c.flatname) ;
self.owner = m != null ? m : c; self.owner = m != null ? m : c;
if (self.name.isEmpty()) if (self.name.isEmpty())
self.fullname = null; self.fullname = names.empty;
else else
self.fullname = ClassSymbol.formFullName(self.name, self.owner); self.fullname = ClassSymbol.formFullName(self.name, self.owner);

View File

@ -808,8 +808,8 @@ public class Gen extends JCTree.Visitor {
code.resolve(secondJumps); code.resolve(secondJumps);
CondItem second = genCond(tree.falsepart, CRT_FLOW_TARGET); CondItem second = genCond(tree.falsepart, CRT_FLOW_TARGET);
CondItem result = items.makeCondItem(second.opcode, CondItem result = items.makeCondItem(second.opcode,
code.mergeChains(trueJumps, second.trueJumps), Code.mergeChains(trueJumps, second.trueJumps),
code.mergeChains(falseJumps, second.falseJumps)); Code.mergeChains(falseJumps, second.falseJumps));
if (markBranches) result.tree = tree.falsepart; if (markBranches) result.tree = tree.falsepart;
return result; return result;
} else { } else {
@ -1322,7 +1322,7 @@ public class Gen extends JCTree.Visitor {
if (useJsrLocally) { if (useJsrLocally) {
if (tree.finalizer != null) { if (tree.finalizer != null) {
Code.State jsrState = code.state.dup(); Code.State jsrState = code.state.dup();
jsrState.push(code.jsrReturnValue); jsrState.push(Code.jsrReturnValue);
tryEnv.info.cont = tryEnv.info.cont =
new Chain(code.emitJump(jsr), new Chain(code.emitJump(jsr),
tryEnv.info.cont, tryEnv.info.cont,
@ -1375,7 +1375,7 @@ public class Gen extends JCTree.Visitor {
genFinalizer(env); genFinalizer(env);
if (hasFinalizer || l.tail.nonEmpty()) { if (hasFinalizer || l.tail.nonEmpty()) {
code.statBegin(TreeInfo.endPos(env.tree)); code.statBegin(TreeInfo.endPos(env.tree));
exitChain = code.mergeChains(exitChain, exitChain = Code.mergeChains(exitChain,
code.branch(goto_)); code.branch(goto_));
} }
endFinalizerGap(env); endFinalizerGap(env);
@ -1963,7 +1963,7 @@ public class Gen extends JCTree.Visitor {
result = items. result = items.
makeCondItem(rcond.opcode, makeCondItem(rcond.opcode,
rcond.trueJumps, rcond.trueJumps,
code.mergeChains(falseJumps, Code.mergeChains(falseJumps,
rcond.falseJumps)); rcond.falseJumps));
} else { } else {
result = lcond; result = lcond;
@ -1976,7 +1976,7 @@ public class Gen extends JCTree.Visitor {
CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET); CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
result = items. result = items.
makeCondItem(rcond.opcode, makeCondItem(rcond.opcode,
code.mergeChains(trueJumps, rcond.trueJumps), Code.mergeChains(trueJumps, rcond.trueJumps),
rcond.falseJumps); rcond.falseJumps);
} else { } else {
result = lcond; result = lcond;

View File

@ -792,25 +792,25 @@ public class Items {
} }
Chain jumpTrue() { 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 // we should proceed further in -Xjcov mode only
int startpc = code.curPc(); 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()); code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
return c; return c;
} }
Chain jumpFalse() { 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 // we should proceed further in -Xjcov mode only
int startpc = code.curPc(); 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()); code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
return c; return c;
} }
CondItem negate() { CondItem negate() {
CondItem c = new CondItem(code.negate(opcode), falseJumps, trueJumps); CondItem c = new CondItem(Code.negate(opcode), falseJumps, trueJumps);
c.tree = tree; c.tree = tree;
return c; return c;
} }

View File

@ -82,7 +82,7 @@ public class CommandLine {
st.commentChar('#'); st.commentChar('#');
st.quoteChar('"'); st.quoteChar('"');
st.quoteChar('\''); st.quoteChar('\'');
while (st.nextToken() != st.TT_EOF) { while (st.nextToken() != StreamTokenizer.TT_EOF) {
args.append(st.sval); args.append(st.sval);
} }
r.close(); r.close();

View File

@ -549,12 +549,6 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
return log.nwarnings; return log.nwarnings;
} }
/** Whether or not any parse errors have occurred.
*/
public boolean parseErrors() {
return parseErrors;
}
/** Try to open input stream with given name. /** Try to open input stream with given name.
* Report an error if this fails. * Report an error if this fails.
* @param filename The file name of the input stream to be opened. * @param filename The file name of the input stream to be opened.
@ -564,7 +558,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
inputFiles.add(filename); inputFiles.add(filename);
return filename.getCharContent(false); return filename.getCharContent(false);
} catch (IOException e) { } catch (IOException e) {
log.error("error.reading.file", filename, e.getLocalizedMessage()); log.error("error.reading.file", filename, JavacFileManager.getMessage(e));
return null; return null;
} }
} }
@ -588,7 +582,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
int initialErrorCount = log.nerrors; int initialErrorCount = log.nerrors;
Parser parser = parserFactory.newParser(content, keepComments(), genEndPos, lineDebugInfo); Parser parser = parserFactory.newParser(content, keepComments(), genEndPos, lineDebugInfo);
tree = parser.parseCompilationUnit(); tree = parser.parseCompilationUnit();
parseErrors |= (log.nerrors > initialErrorCount); log.unrecoverableError |= (log.nerrors > initialErrorCount);
if (verbose) { if (verbose) {
printVerbose("parsing.done", Long.toString(elapsed(msec))); printVerbose("parsing.done", Long.toString(elapsed(msec)));
} }
@ -723,7 +717,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
try { try {
tree = parse(filename, filename.getCharContent(false)); tree = parse(filename, filename.getCharContent(false));
} catch (IOException e) { } 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()); tree = make.TopLevel(List.<JCTree.JCAnnotation>nil(), null, List.<JCTree>nil());
} finally { } finally {
log.useSource(prev); log.useSource(prev);
@ -768,9 +762,6 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
private long start_msec = 0; private long start_msec = 0;
public long elapsed_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) public void compile(List<JavaFileObject> sourceFileObject)
throws Throwable { throws Throwable {
compile(sourceFileObject, List.<String>nil(), null); compile(sourceFileObject, List.<String>nil(), null);
@ -1114,7 +1105,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
return env; return env;
if (verboseCompilePolicy) if (verboseCompilePolicy)
log.printLines(log.noticeWriter, "[attribute " + env.enclClass.sym + "]"); Log.printLines(log.noticeWriter, "[attribute " + env.enclClass.sym + "]");
if (verbose) if (verbose)
printVerbose("checking.attribution", env.enclClass.sym); printVerbose("checking.attribution", env.enclClass.sym);

View File

@ -26,6 +26,8 @@
package com.sun.tools.javac.model; package com.sun.tools.javac.model;
import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.*;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.lang.annotation.*; import java.lang.annotation.*;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -268,10 +270,10 @@ public class AnnotationProxyMaker {
* The toString, hashCode, and equals methods foward to the underlying * The toString, hashCode, and equals methods foward to the underlying
* type. * type.
*/ */
private static class MirroredTypeExceptionProxy extends ExceptionProxy { private static final class MirroredTypeExceptionProxy extends ExceptionProxy {
static final long serialVersionUID = 269; static final long serialVersionUID = 269;
private transient final TypeMirror type; private transient TypeMirror type;
private final String typeString; private final String typeString;
MirroredTypeExceptionProxy(TypeMirror t) { MirroredTypeExceptionProxy(TypeMirror t) {
@ -296,6 +298,13 @@ public class AnnotationProxyMaker {
protected RuntimeException generateException() { protected RuntimeException generateException() {
return new MirroredTypeException(type); 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 @@ public class AnnotationProxyMaker {
* The toString, hashCode, and equals methods foward to the underlying * The toString, hashCode, and equals methods foward to the underlying
* types. * types.
*/ */
private static class MirroredTypesExceptionProxy extends ExceptionProxy { private static final class MirroredTypesExceptionProxy extends ExceptionProxy {
static final long serialVersionUID = 269; static final long serialVersionUID = 269;
private transient final List<TypeMirror> types; private transient List<TypeMirror> types;
private final String typeStrings; private final String typeStrings;
MirroredTypesExceptionProxy(List<TypeMirror> ts) { MirroredTypesExceptionProxy(List<TypeMirror> ts) {
@ -333,5 +342,12 @@ public class AnnotationProxyMaker {
protected RuntimeException generateException() { protected RuntimeException generateException() {
return new MirroredTypesException(types); return new MirroredTypesException(types);
} }
// Explicitly set all transient fields.
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
types = null;
}
} }
} }

View File

@ -1561,7 +1561,10 @@ public class JavacParser implements Parser {
JCNewClass newClass = classCreatorRest(newpos, null, typeArgs, t); JCNewClass newClass = classCreatorRest(newpos, null, typeArgs, t);
if (newClass.def != null) { if (newClass.def != null) {
assert newClass.def.mods.annotations.isEmpty(); 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; return newClass;
} else { } else {
@ -3016,6 +3019,18 @@ public class JavacParser implements Parser {
return (oc >= 0) ? TreeInfo.opPrec(oc) : -1; 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, /** Return operation tag of binary operator represented by token,
* -1 if token is not a binary operator. * -1 if token is not a binary operator.
*/ */

View File

@ -690,10 +690,12 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
ProcessorState ps = psi.next(); ProcessorState ps = psi.next();
Set<String> matchedNames = new HashSet<String>(); Set<String> matchedNames = new HashSet<String>();
Set<TypeElement> typeElements = new LinkedHashSet<TypeElement>(); 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) ) { if (ps.annotationSupported(unmatchedAnnotationName) ) {
matchedNames.add(unmatchedAnnotationName); matchedNames.add(unmatchedAnnotationName);
TypeElement te = unmatchedAnnotations.get(unmatchedAnnotationName); TypeElement te = entry.getValue();
if (te != null) if (te != null)
typeElements.add(te); typeElements.add(te);
} }
@ -790,16 +792,13 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
List<JCCompilationUnit> roots, List<JCCompilationUnit> roots,
List<ClassSymbol> classSymbols, List<ClassSymbol> classSymbols,
Iterable<? extends PackageSymbol> pckSymbols) Iterable<? extends PackageSymbol> pckSymbols)
throws IOException { throws IOException {
log = Log.instance(context); log = Log.instance(context);
// Writer for -XprintRounds and -XprintProcessorInfo data // Writer for -XprintRounds and -XprintProcessorInfo data
PrintWriter xout = context.get(Log.outKey); PrintWriter xout = context.get(Log.outKey);
TaskListener taskListener = context.get(TaskListener.class); TaskListener taskListener = context.get(TaskListener.class);
AnnotationCollector collector = new AnnotationCollector();
JavaCompiler compiler = JavaCompiler.instance(context); JavaCompiler compiler = JavaCompiler.instance(context);
compiler.todo.clear(); // free the compiler's resources compiler.todo.clear(); // free the compiler's resources
@ -878,7 +877,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
roots = cleanTrees(roots).appendList(parsedFiles); roots = cleanTrees(roots).appendList(parsedFiles);
// Check for errors after parsing // Check for errors after parsing
if (compiler.parseErrors()) { if (log.unrecoverableError) {
errorStatus = true; errorStatus = true;
break runAround; break runAround;
} else { } else {
@ -912,7 +911,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
roots = runLastRound(xout, roundNumber, errorStatus, compiler, roots, taskListener); roots = runLastRound(xout, roundNumber, errorStatus, compiler, roots, taskListener);
// Set error status for any files compiled and generated in // Set error status for any files compiled and generated in
// the last round // the last round
if (compiler.parseErrors()) if (log.unrecoverableError)
errorStatus = true; errorStatus = true;
compiler.close(false); compiler.close(false);
@ -1218,45 +1217,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
return false; 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) { private static <T extends JCTree> List<T> cleanTrees(List<T> nodes) {
for (T node : nodes) for (T node : nodes)
treeCleaner.scan(node); treeCleaner.scan(node);

View File

@ -720,6 +720,9 @@ compiler.warn.big.major.version=\
{0}: major version {1} is newer than {2}, the highest major version supported by this compiler.\n\ {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. 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 # Warnings related to annotation processing
compiler.warn.proc.package.does.not.exist=\ compiler.warn.proc.package.does.not.exist=\
package {0} does not exist package {0} does not exist

View File

@ -201,7 +201,7 @@ public class BasicDiagnosticFormatter extends AbstractDiagnosticFormatter {
private String selectFormat(JCDiagnostic d) { private String selectFormat(JCDiagnostic d) {
DiagnosticSource source = d.getDiagnosticSource(); DiagnosticSource source = d.getDiagnosticSource();
String format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT); String format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT);
if (source != null) { if (source != null && source != DiagnosticSource.NO_SOURCE) {
if (d.getIntPosition() != Position.NOPOS) { if (d.getIntPosition() != Position.NOPOS) {
format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_POS_FORMAT); format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_POS_FORMAT);
} else if (source.getFile() != null && } else if (source.getFile() != null &&

View File

@ -192,6 +192,12 @@ public class Log extends AbstractLog {
*/ */
public int nwarnings = 0; 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 /** 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 * 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. * source file name and source code position of the error is added to the set.

View File

@ -34,7 +34,6 @@ import com.sun.javadoc.*;
import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.ClassType; 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.comp.Check;
import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Context;
@ -73,10 +72,6 @@ public class DocEnv {
/** Referenced directly in RootDocImpl. */ /** Referenced directly in RootDocImpl. */
JavadocClassReader reader; JavadocClassReader reader;
/** The compiler's attribution phase (needed to evaluate
* constant initializers). */
Attr attr;
/** Javadoc's own version of the compiler's enter phase. */ /** Javadoc's own version of the compiler's enter phase. */
JavadocEnter enter; JavadocEnter enter;
@ -91,8 +86,6 @@ public class DocEnv {
/** Access filter (public, protected, ...). */ /** Access filter (public, protected, ...). */
ModifierFilter showAccess; ModifierFilter showAccess;
private ClassDocImpl runtimeException;
/** True if we are using a sentence BreakIterator. */ /** True if we are using a sentence BreakIterator. */
boolean breakiterator; boolean breakiterator;
@ -129,7 +122,6 @@ public class DocEnv {
syms = Symtab.instance(context); syms = Symtab.instance(context);
reader = JavadocClassReader.instance0(context); reader = JavadocClassReader.instance0(context);
enter = JavadocEnter.instance0(context); enter = JavadocEnter.instance0(context);
attr = Attr.instance(context);
names = Names.instance(context); names = Names.instance(context);
externalizableSym = reader.enterClass(names.fromString("java.io.Externalizable")); externalizableSym = reader.enterClass(names.fromString("java.io.Externalizable"));
chk = Check.instance(context); chk = Check.instance(context);

View File

@ -349,12 +349,12 @@ class SeeTagImpl extends TagImpl implements SeeTag, LayoutCharacters {
// (int i, String s) ==> [0] = "int", [1] = String // (int i, String s) ==> [0] = "int", [1] = String
// (int[][], String[]) ==> [0] = "int[][]" // [1] = "String[]" // (int[][], String[]) ==> [0] = "int[][]" // [1] = "String[]"
class ParameterParseMachine { class ParameterParseMachine {
final int START = 0; static final int START = 0;
final int TYPE = 1; static final int TYPE = 1;
final int NAME = 2; static final int NAME = 2;
final int TNSPACE = 3; // space between type and name static final int TNSPACE = 3; // space between type and name
final int ARRAYDECORATION = 4; static final int ARRAYDECORATION = 4;
final int ARRAYSPACE = 5; static final int ARRAYSPACE = 5;
String parameters; String parameters;

View File

@ -255,9 +255,11 @@ public class JavahTask implements NativeHeaderTool.NativeHeaderTask {
} }
this.classes = new ArrayList<String>(); this.classes = new ArrayList<String>();
for (String classname: classes) { if (classes != null) {
classname.getClass(); // null-check for (String classname: classes) {
this.classes.add(classname); classname.getClass(); // null-check
this.classes.add(classname);
}
} }
} }
@ -316,6 +318,12 @@ public class JavahTask implements NativeHeaderTool.NativeHeaderTask {
int run(String[] args) { int run(String[] args) {
try { try {
handleOptions(args); handleOptions(args);
if (classes == null || classes.size() == 0) {
if (help || version || fullVersion)
return 0;
else
return 1;
}
boolean ok = run(); boolean ok = run();
return ok ? 0 : 1; return ok ? 0 : 1;
} catch (BadArgs e) { } catch (BadArgs e) {
@ -347,8 +355,7 @@ public class JavahTask implements NativeHeaderTool.NativeHeaderTask {
fileManager = getDefaultFileManager(diagnosticListener, log); fileManager = getDefaultFileManager(diagnosticListener, log);
Iterator<String> iter = args.iterator(); Iterator<String> iter = args.iterator();
if (!iter.hasNext()) boolean noArgs = !iter.hasNext();
help = true;
while (iter.hasNext()) { while (iter.hasNext()) {
String arg = iter.next(); String arg = iter.next();
@ -365,7 +372,7 @@ public class JavahTask implements NativeHeaderTool.NativeHeaderTask {
} }
if ((classes == null || classes.size() == 0) && if ((classes == null || classes.size() == 0) &&
!(help || version || fullVersion)) { !(noArgs || help || version || fullVersion)) {
throw new BadArgs("err.no.classes.specified"); throw new BadArgs("err.no.classes.specified");
} }

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);
}
};
}

View File

@ -30,6 +30,8 @@
* @compile ThrowsIntersection_1.java * @compile ThrowsIntersection_1.java
*/ */
package ThrowsIntersection_1;
class Ex1 extends Exception {} class Ex1 extends Exception {}
class Ex2 extends Exception {} class Ex2 extends Exception {}

View File

@ -30,6 +30,8 @@
* @compile ThrowsIntersection_2.java * @compile ThrowsIntersection_2.java
*/ */
package ThrowsIntersection_2;
class Ex1 extends Exception {} class Ex1 extends Exception {}
class Ex2 extends Exception {} class Ex2 extends Exception {}
class Ex3 extends Exception {} class Ex3 extends Exception {}

View File

@ -30,6 +30,8 @@
* @run compile/fail ThrowsIntersection_3.java * @run compile/fail ThrowsIntersection_3.java
*/ */
package ThrowsIntersection_3;
class Ex1 extends Exception {} class Ex1 extends Exception {}
class Ex2 extends Exception {} class Ex2 extends Exception {}

View File

@ -30,6 +30,8 @@
* @run compile/fail ThrowsIntersection_4.java * @run compile/fail ThrowsIntersection_4.java
*/ */
package ThrowsIntersection_4;
// Note: This is the test that actually failed for 4042259. The others are for completeness. // Note: This is the test that actually failed for 4042259. The others are for completeness.
class Ex1 extends Exception {} class Ex1 extends Exception {}

View File

@ -30,7 +30,7 @@
* @compile/fail Constant.java * @compile/fail Constant.java
*/ */
package test.tools.javac.annotation.Constant; package Constant;
@T(a = X.x) @T(a = X.x)
@interface T { @interface T {

View File

@ -34,7 +34,10 @@ import com.sun.tools.javac.api.JavacTaskImpl;
import com.sun.tools.javac.parser.*; // XXX import com.sun.tools.javac.parser.*; // XXX
import com.sun.tools.javac.util.*; // XXX import com.sun.tools.javac.util.*; // XXX
import java.io.*; import java.io.*;
import java.net.*;
import java.nio.*; import java.nio.*;
import java.nio.charset.Charset;
import java.util.Arrays;
import javax.lang.model.element.Element; import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType; import javax.lang.model.type.DeclaredType;
@ -43,6 +46,10 @@ import javax.lang.model.util.Elements;
import javax.lang.model.util.Types; import javax.lang.model.util.Types;
import javax.tools.*; 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 { public class TestJavacTaskScanner extends ToolTester {
final JavacTaskImpl task; final JavacTaskImpl task;
@ -56,6 +63,7 @@ public class TestJavacTaskScanner extends ToolTester {
TestJavacTaskScanner(File file) { TestJavacTaskScanner(File file) {
final Iterable<? extends JavaFileObject> compilationUnits = final Iterable<? extends JavaFileObject> compilationUnits =
fm.getJavaFileObjects(new File[] {file}); fm.getJavaFileObjects(new File[] {file});
StandardJavaFileManager fm = getLocalFileManager(tool, null, null);
task = (JavacTaskImpl)tool.getTask(null, fm, null, null, null, compilationUnits); task = (JavacTaskImpl)tool.getTask(null, fm, null, null, null, compilationUnits);
task.getContext().put(Scanner.Factory.scannerFactoryKey, task.getContext().put(Scanner.Factory.scannerFactoryKey,
new MyScanner.Factory(task.getContext(), this)); new MyScanner.Factory(task.getContext(), this));
@ -83,7 +91,7 @@ public class TestJavacTaskScanner extends ToolTester {
System.out.println("#parseTypeElements: " + numParseTypeElements); System.out.println("#parseTypeElements: " + numParseTypeElements);
System.out.println("#allMembers: " + numAllMembers); System.out.println("#allMembers: " + numAllMembers);
check(numTokens, "#Tokens", 891); check(numTokens, "#Tokens", 1222);
check(numParseTypeElements, "#parseTypeElements", 136); check(numParseTypeElements, "#parseTypeElements", 136);
check(numAllMembers, "#allMembers", 67); check(numAllMembers, "#allMembers", 67);
} }
@ -117,6 +125,47 @@ public class TestJavacTaskScanner extends ToolTester {
numAllMembers++; 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 { class MyScanner extends Scanner {

View File

@ -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;
}

View File

@ -30,7 +30,7 @@
* @compile Casting.java * @compile Casting.java
*/ */
package test.tools.javac.generics.Casting; package Casting;
class Test {} class Test {}

View File

@ -30,7 +30,7 @@
* @compile Casting3.java * @compile Casting3.java
*/ */
package test.tools.javac.generics.Casting3; package Casting3;
class A<T extends A<T>> { class A<T extends A<T>> {
<U extends A<U>> void f() { <U extends A<U>> void f() {

View File

@ -30,7 +30,7 @@
* @compile -Werror -Xlint:unchecked Casting4.java * @compile -Werror -Xlint:unchecked Casting4.java
*/ */
package test.tools.javac.generics.Casting4; package Casting4;
class Casting4 { class Casting4 {
<M> Integer f(Comparable<M> c) { <M> Integer f(Comparable<M> c) {

View File

@ -30,7 +30,7 @@
* @compile InnerInterface1.java * @compile InnerInterface1.java
*/ */
package test.tools.javac.generics.InnerInterface1; package InnerInterface1;
interface Iterator<E> { interface Iterator<E> {
} }

View File

@ -30,7 +30,7 @@
* @compile InnerInterface2.java * @compile InnerInterface2.java
*/ */
package test.tools.javac.generics.InnerInterface2; package InnerInterface2;
class Builder<Community> { class Builder<Community> {

View File

@ -30,7 +30,7 @@
* @compile/fail Multibound1.java * @compile/fail Multibound1.java
*/ */
package test.tools.javac.generics.Multibound1; package Multibound1;
interface A {} interface A {}
interface B {} interface B {}

View File

@ -30,7 +30,7 @@
* @compile MultipleInheritance.java * @compile MultipleInheritance.java
*/ */
package test.tools.javac.generics.MultipleInheritance; package MultipleInheritance;
import java.util.*; import java.util.*;

View File

@ -27,22 +27,22 @@
* @summary generics: type inference failure due to a bug in ClassSymbol.isLess * @summary generics: type inference failure due to a bug in ClassSymbol.isLess
* @author gafter * @author gafter
* *
* @compile NameOrder.java * @compile NameOrder.java
*/ */
package test.tools.javac.generics.NameOrder; package NameOrder;
interface a {} interface a {}
interface b {} interface b {}
interface c {} interface c {}
class A implements a, b {} class AB implements a, b {}
class B implements c, a {} class CA implements c, a {}
// this is how to trigger a symptom: // this is how to trigger a symptom:
abstract class C { abstract class X {
<T> T f(T t1, T t2) { return null; } <T> T f(T t1, T t2) { return null; }
void g() { void g() {
a x = f( new A(), new B() ); a x = f( new AB(), new CA() );
} }
} }

View File

@ -30,7 +30,7 @@
* @compile PermuteBound.java * @compile PermuteBound.java
*/ */
package test.tools.javac.generics.PermuteBound; package PermuteBound;
class C<X, Y> {} class C<X, Y> {}

View File

@ -30,7 +30,7 @@
* @compile/fail PrimitiveVariant.java * @compile/fail PrimitiveVariant.java
*/ */
package test.tools.javac.generics.PrimitiveVariant; package PrimitiveVariant;
interface I { interface I {
double m(); double m();

View File

@ -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();
}
}

View File

@ -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> {
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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() { };
}
}

View File

@ -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);
}
}