6911256: Project Coin: Support Automatic Resource Management (ARM) blocks in the compiler

6964740: Project Coin: More tests for ARM compiler changes
6965277: Project Coin: Correctness issues in ARM implementation
6967065: add -Xlint warning category for Automatic Resource Management (ARM)

Reviewed-by: jjb, darcy, mcimadamore, jjg, briangoetz
This commit is contained in:
Tom Ball 2010-07-16 19:35:24 -07:00 committed by Joe Darcy
parent 9c273720d6
commit 985efdc475
51 changed files with 1950 additions and 18 deletions

View File

@ -107,7 +107,8 @@ javac.includes = \
javax/annotation/processing/ \
javax/lang/model/ \
javax/tools/ \
com/sun/source/ com/sun/tools/javac/
com/sun/source/ \
com/sun/tools/javac/
javac.tests = \
tools/javac

View File

@ -49,4 +49,5 @@ public interface TryTree extends StatementTree {
BlockTree getBlock();
List<? extends CatchTree> getCatches();
BlockTree getFinallyBlock();
List<? extends Tree> getResources();
}

View File

@ -209,7 +209,8 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
}
public R visitTry(TryTree node, P p) {
R r = scan(node.getBlock(), p);
R r = scan(node.getResources(), p);
r = scanAndReduce(node.getBlock(), p, r);
r = scanAndReduce(node.getCatches(), p, r);
r = scanAndReduce(node.getFinallyBlock(), p, r);
return r;

View File

@ -208,7 +208,12 @@ public class Lint
/**
* Warn about potentially unsafe vararg methods
*/
VARARGS("varargs");
VARARGS("varargs"),
/**
* Warn about arm resources
*/
ARM("arm");
LintCategory(String option) {
this(option, false);

View File

@ -159,6 +159,9 @@ public enum Source {
public boolean enforceMandatoryWarnings() {
return compareTo(JDK1_5) >= 0;
}
public boolean allowTryWithResources() {
return compareTo(JDK1_7) >= 0;
}
public boolean allowTypeAnnotations() {
return compareTo(JDK1_7) >= 0;
}

View File

@ -993,12 +993,17 @@ public abstract class Symbol implements Element {
return data == ElementKind.EXCEPTION_PARAMETER;
}
public boolean isResourceVariable() {
return data == ElementKind.RESOURCE_VARIABLE;
}
public Object getConstValue() {
// TODO: Consider if getConstValue and getConstantValue can be collapsed
if (data == ElementKind.EXCEPTION_PARAMETER) {
if (data == ElementKind.EXCEPTION_PARAMETER ||
data == ElementKind.RESOURCE_VARIABLE) {
return null;
} else if (data instanceof Callable<?>) {
// In this case, this is final a variable, with an as
// In this case, this is a final variable, with an as
// yet unevaluated initializer.
Callable<?> eval = (Callable<?>)data;
data = null; // to make sure we don't evaluate this twice.

View File

@ -148,6 +148,7 @@ public class Symtab {
public final Type inheritedType;
public final Type proprietaryType;
public final Type systemType;
public final Type autoCloseableType;
/** The symbol representing the length field of an array.
*/
@ -159,6 +160,9 @@ public class Symtab {
/** The symbol representing the final finalize method on enums */
public final MethodSymbol enumFinalFinalize;
/** The symbol representing the close method on TWR AutoCloseable type */
public final MethodSymbol autoCloseableClose;
/** The predefined type that belongs to a tag.
*/
public final Type[] typeOfTag = new Type[TypeTags.TypeTagCount];
@ -444,6 +448,12 @@ public class Symtab {
suppressWarningsType = enterClass("java.lang.SuppressWarnings");
inheritedType = enterClass("java.lang.annotation.Inherited");
systemType = enterClass("java.lang.System");
autoCloseableType = enterClass("java.lang.AutoCloseable");
autoCloseableClose = new MethodSymbol(PUBLIC,
names.close,
new MethodType(List.<Type>nil(), voidType,
List.of(exceptionType), methodClass),
autoCloseableType.tsym);
synthesizeEmptyInterfaceIfMissing(cloneableType);
synthesizeEmptyInterfaceIfMissing(serializableType);

View File

@ -192,7 +192,7 @@ public class Attr extends JCTree.Visitor {
Type check(JCTree tree, Type owntype, int ownkind, int pkind, Type pt) {
if (owntype.tag != ERROR && pt.tag != METHOD && pt.tag != FORALL) {
if ((ownkind & ~pkind) == 0) {
owntype = chk.checkType(tree.pos(), owntype, pt);
owntype = chk.checkType(tree.pos(), owntype, pt, errKey);
} else {
log.error(tree.pos(), "unexpected.type",
kindNames(pkind),
@ -239,7 +239,11 @@ public class Attr extends JCTree.Visitor {
!((base == null ||
(base.getTag() == JCTree.IDENT && TreeInfo.name(base) == names._this)) &&
isAssignableAsBlankFinal(v, env)))) {
log.error(pos, "cant.assign.val.to.final.var", v);
if (v.isResourceVariable()) { //TWR resource
log.error(pos, "twr.resource.may.not.be.assigned", v);
} else {
log.error(pos, "cant.assign.val.to.final.var", v);
}
}
}
@ -372,6 +376,10 @@ public class Attr extends JCTree.Visitor {
*/
Type pt;
/** Visitor argument: the error key to be generated when a type error occurs
*/
String errKey;
/** Visitor result: the computed type.
*/
Type result;
@ -385,13 +393,19 @@ public class Attr extends JCTree.Visitor {
* @param pt The prototype visitor argument.
*/
Type attribTree(JCTree tree, Env<AttrContext> env, int pkind, Type pt) {
return attribTree(tree, env, pkind, pt, "incompatible.types");
}
Type attribTree(JCTree tree, Env<AttrContext> env, int pkind, Type pt, String errKey) {
Env<AttrContext> prevEnv = this.env;
int prevPkind = this.pkind;
Type prevPt = this.pt;
String prevErrKey = this.errKey;
try {
this.env = env;
this.pkind = pkind;
this.pt = pt;
this.errKey = errKey;
tree.accept(this);
if (tree == breakTree)
throw new BreakAttr(env);
@ -403,6 +417,7 @@ public class Attr extends JCTree.Visitor {
this.env = prevEnv;
this.pkind = prevPkind;
this.pt = prevPt;
this.errKey = prevErrKey;
}
}
@ -412,6 +427,10 @@ public class Attr extends JCTree.Visitor {
return attribTree(tree, env, VAL, pt.tag != ERROR ? pt : Type.noType);
}
public Type attribExpr(JCTree tree, Env<AttrContext> env, Type pt, String key) {
return attribTree(tree, env, VAL, pt.tag != ERROR ? pt : Type.noType, key);
}
/** Derived visitor method: attribute an expression tree with
* no constraints on the computed type.
*/
@ -976,14 +995,34 @@ public class Attr extends JCTree.Visitor {
}
public void visitTry(JCTry tree) {
// Create a new local environment with a local
Env<AttrContext> localEnv = env.dup(tree, env.info.dup(env.info.scope.dup()));
boolean isTryWithResource = tree.resources.nonEmpty();
// Create a nested environment for attributing the try block if needed
Env<AttrContext> tryEnv = isTryWithResource ?
env.dup(tree, localEnv.info.dup(localEnv.info.scope.dup())) :
localEnv;
// Attribute resource declarations
for (JCTree resource : tree.resources) {
if (resource.getTag() == JCTree.VARDEF) {
attribStat(resource, tryEnv);
chk.checkType(resource, resource.type, syms.autoCloseableType, "twr.not.applicable.to.type");
VarSymbol var = (VarSymbol)TreeInfo.symbolFor(resource);
var.setData(ElementKind.RESOURCE_VARIABLE);
} else {
attribExpr(resource, tryEnv, syms.autoCloseableType, "twr.not.applicable.to.type");
}
}
// Attribute body
attribStat(tree.body, env.dup(tree, env.info.dup()));
attribStat(tree.body, tryEnv);
if (isTryWithResource)
tryEnv.info.scope.leave();
// Attribute catch clauses
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
JCCatch c = l.head;
Env<AttrContext> catchEnv =
env.dup(c, env.info.dup(env.info.scope.dup()));
localEnv.dup(c, localEnv.info.dup(localEnv.info.scope.dup()));
Type ctype = attribStat(c.param, catchEnv);
if (TreeInfo.isMultiCatch(c)) {
//check that multi-catch parameter is marked as final
@ -1003,7 +1042,9 @@ public class Attr extends JCTree.Visitor {
}
// Attribute finalizer
if (tree.finalizer != null) attribStat(tree.finalizer, env);
if (tree.finalizer != null) attribStat(tree.finalizer, localEnv);
localEnv.info.scope.leave();
result = null;
}
@ -2139,6 +2180,15 @@ public class Attr extends JCTree.Visitor {
checkAssignable(tree.pos(), v, tree.selected, env);
}
if (sitesym != null &&
sitesym.kind == VAR &&
((VarSymbol)sitesym).isResourceVariable() &&
sym.kind == MTH &&
sym.overrides(syms.autoCloseableClose, sitesym.type.tsym, types, true) &&
env.info.lint.isEnabled(Lint.LintCategory.ARM)) {
log.warning(tree, "twr.explicit.close.call");
}
// Disallow selecting a type from an expression
if (isType(sym) && (sitesym==null || (sitesym.kind&(TYP|PCK)) == 0)) {
tree.type = check(tree.selected, pt,

View File

@ -393,6 +393,10 @@ public class Check {
* @param req The type that was required.
*/
Type checkType(DiagnosticPosition pos, Type found, Type req) {
return checkType(pos, found, req, "incompatible.types");
}
Type checkType(DiagnosticPosition pos, Type found, Type req, String errKey) {
if (req.tag == ERROR)
return req;
if (found.tag == FORALL)
@ -411,7 +415,7 @@ public class Check {
log.error(pos, "assignment.to.extends-bound", req);
return types.createErrorType(found);
}
return typeError(pos, diags.fragment("incompatible.types"), found, req);
return typeError(pos, diags.fragment(errKey), found, req);
}
/** Instantiate polymorphic type to some prototype, unless

View File

@ -28,6 +28,8 @@
package com.sun.tools.javac.comp;
import java.util.HashMap;
import java.util.Map;
import java.util.LinkedHashMap;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.tree.*;
@ -265,6 +267,10 @@ public class Flow extends TreeScanner {
*/
List<Type> caught;
/** The list of unreferenced automatic resources.
*/
Map<VarSymbol, JCVariableDecl> unrefdResources;
/** Set when processing a loop body the second time for DU analysis. */
boolean loopPassTwo = false;
@ -963,6 +969,7 @@ public class Flow extends TreeScanner {
public void visitTry(JCTry tree) {
List<Type> caughtPrev = caught;
List<Type> thrownPrev = thrown;
Map<VarSymbol, JCVariableDecl> unrefdResourcesPrev = unrefdResources;
thrown = List.nil();
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
@ -977,6 +984,32 @@ public class Flow extends TreeScanner {
pendingExits = new ListBuffer<PendingExit>();
Bits initsTry = inits.dup();
uninitsTry = uninits.dup();
unrefdResources = new LinkedHashMap<VarSymbol, JCVariableDecl>();
for (JCTree resource : tree.resources) {
if (resource instanceof JCVariableDecl) {
JCVariableDecl vdecl = (JCVariableDecl) resource;
visitVarDef(vdecl);
unrefdResources.put(vdecl.sym, vdecl);
} else if (resource instanceof JCExpression) {
scanExpr((JCExpression) resource);
} else {
throw new AssertionError(tree); // parser error
}
}
for (JCTree resource : tree.resources) {
MethodSymbol topCloseMethod = (MethodSymbol)syms.autoCloseableType.tsym.members().lookup(names.close).sym;
List<Type> closeableSupertypes = resource.type.isCompound() ?
types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
List.of(resource.type);
for (Type sup : closeableSupertypes) {
if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
MethodSymbol closeMethod = types.implementation(topCloseMethod, sup.tsym, types, true);
for (Type t : closeMethod.getThrownTypes()) {
markThrown(tree.body, t);
}
}
}
}
scanStat(tree.body);
List<Type> thrownInTry = thrown;
thrown = thrownPrev;
@ -987,6 +1020,14 @@ public class Flow extends TreeScanner {
Bits uninitsEnd = uninits;
int nextadrCatch = nextadr;
if (!unrefdResources.isEmpty() &&
lint.isEnabled(Lint.LintCategory.ARM)) {
for (Map.Entry<VarSymbol, JCVariableDecl> e : unrefdResources.entrySet()) {
log.warning(e.getValue().pos(),
"automatic.resource.not.referenced", e.getKey());
}
}
List<Type> caughtInTry = List.nil();
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
alive = true;
@ -1070,6 +1111,7 @@ public class Flow extends TreeScanner {
while (exits.nonEmpty()) pendingExits.append(exits.next());
}
uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
unrefdResources = unrefdResourcesPrev;
}
public void visitConditional(JCConditional tree) {
@ -1293,8 +1335,16 @@ public class Flow extends TreeScanner {
}
public void visitIdent(JCIdent tree) {
if (tree.sym.kind == VAR)
if (tree.sym.kind == VAR) {
checkInit(tree.pos(), (VarSymbol)tree.sym);
referenced(tree.sym);
}
}
void referenced(Symbol sym) {
if (unrefdResources != null && unrefdResources.containsKey(sym)) {
unrefdResources.remove(sym);
}
}
public void visitTypeCast(JCTypeCast tree) {

View File

@ -605,6 +605,23 @@ public class Lower extends TreeTranslator {
s.enter(sym);
}
/** Create a fresh synthetic name within a given scope - the unique name is
* obtained by appending '$' chars at the end of the name until no match
* is found.
*
* @param name base name
* @param s scope in which the name has to be unique
* @return fresh synthetic name
*/
private Name makeSyntheticName(Name name, Scope s) {
do {
name = name.append(
target.syntheticNameChar(),
names.empty);
} while (lookupSynthetic(name, s) != null);
return name;
}
/** Check whether synthetic symbols generated during lowering conflict
* with user-defined symbols.
*
@ -1299,6 +1316,11 @@ public class Lower extends TreeTranslator {
*/
Scope proxies;
/** A scope containing all unnamed resource variables/saved
* exception variables for translated TWR blocks
*/
Scope twrVars;
/** A stack containing the this$n field of the currently translated
* classes (if needed) in innermost first order.
* Inside a constructor, proxies and any this$n symbol are duplicated
@ -1400,6 +1422,122 @@ public class Lower extends TreeTranslator {
}
}
/** Optionally replace a try statement with an automatic resource
* management (ARM) block.
* @param tree The try statement to inspect.
* @return An ARM block, or the original try block if there are no
* resources to manage.
*/
JCTree makeArmTry(JCTry tree) {
make_at(tree.pos());
twrVars = twrVars.dup();
JCBlock armBlock = makeArmBlock(tree.resources, tree.body, 0);
if (tree.catchers.isEmpty() && tree.finalizer == null)
result = translate(armBlock);
else
result = translate(make.Try(armBlock, tree.catchers, tree.finalizer));
twrVars = twrVars.leave();
return result;
}
private JCBlock makeArmBlock(List<JCTree> resources, JCBlock block, int depth) {
if (resources.isEmpty())
return block;
// Add resource declaration or expression to block statements
ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>();
JCTree resource = resources.head;
JCExpression expr = null;
if (resource instanceof JCVariableDecl) {
JCVariableDecl var = (JCVariableDecl) resource;
expr = make.Ident(var.sym).setType(resource.type);
stats.add(var);
} else {
assert resource instanceof JCExpression;
VarSymbol syntheticTwrVar =
new VarSymbol(SYNTHETIC | FINAL,
makeSyntheticName(names.fromString("twrVar" +
depth), twrVars),
(resource.type.tag == TypeTags.BOT) ?
syms.autoCloseableType : resource.type,
currentMethodSym);
twrVars.enter(syntheticTwrVar);
JCVariableDecl syntheticTwrVarDecl =
make.VarDef(syntheticTwrVar, (JCExpression)resource);
expr = (JCExpression)make.Ident(syntheticTwrVar);
stats.add(syntheticTwrVarDecl);
}
// Add primaryException declaration
VarSymbol primaryException =
new VarSymbol(SYNTHETIC,
makeSyntheticName(names.fromString("primaryException" +
depth), twrVars),
syms.throwableType,
currentMethodSym);
twrVars.enter(primaryException);
JCVariableDecl primaryExceptionTreeDecl = make.VarDef(primaryException, makeNull());
stats.add(primaryExceptionTreeDecl);
// Create catch clause that saves exception and then rethrows it
VarSymbol param =
new VarSymbol(FINAL|SYNTHETIC,
names.fromString("t" +
target.syntheticNameChar()),
syms.throwableType,
currentMethodSym);
JCVariableDecl paramTree = make.VarDef(param, null);
JCStatement assign = make.Assignment(primaryException, make.Ident(param));
JCStatement rethrowStat = make.Throw(make.Ident(param));
JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(assign, rethrowStat));
JCCatch catchClause = make.Catch(paramTree, catchBlock);
int oldPos = make.pos;
make.at(TreeInfo.endPos(block));
JCBlock finallyClause = makeArmFinallyClause(primaryException, expr);
make.at(oldPos);
JCTry outerTry = make.Try(makeArmBlock(resources.tail, block, depth + 1),
List.<JCCatch>of(catchClause),
finallyClause);
stats.add(outerTry);
return make.Block(0L, stats.toList());
}
private JCBlock makeArmFinallyClause(Symbol primaryException, JCExpression resource) {
// primaryException.addSuppressedException(catchException);
VarSymbol catchException =
new VarSymbol(0, make.paramName(2),
syms.throwableType,
currentMethodSym);
JCStatement addSuppressionStatement =
make.Exec(makeCall(make.Ident(primaryException),
names.fromString("addSuppressedException"),
List.<JCExpression>of(make.Ident(catchException))));
// try { resource.close(); } catch (e) { primaryException.addSuppressedException(e); }
JCBlock tryBlock =
make.Block(0L, List.<JCStatement>of(makeResourceCloseInvocation(resource)));
JCVariableDecl catchExceptionDecl = make.VarDef(catchException, null);
JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(addSuppressionStatement));
List<JCCatch> catchClauses = List.<JCCatch>of(make.Catch(catchExceptionDecl, catchBlock));
JCTry tryTree = make.Try(tryBlock, catchClauses, null);
// if (resource != null) resourceClose;
JCExpression nullCheck = makeBinary(JCTree.NE,
make.Ident(primaryException),
makeNull());
JCIf closeIfStatement = make.If(nullCheck,
tryTree,
makeResourceCloseInvocation(resource));
return make.Block(0L, List.<JCStatement>of(closeIfStatement));
}
private JCStatement makeResourceCloseInvocation(JCExpression resource) {
// create resource.close() method invocation
JCExpression resourceClose = makeCall(resource, names.close, List.<JCExpression>nil());
return make.Exec(resourceClose);
}
/** Construct a tree that represents the outer instance
* <C.this>. Never pick the current `this'.
* @param pos The source code position to be used for the tree.
@ -3405,6 +3543,15 @@ public class Lower extends TreeTranslator {
result = tree;
}
@Override
public void visitTry(JCTry tree) {
if (tree.resources.isEmpty()) {
super.visitTry(tree);
} else {
result = makeArmTry(tree);
}
}
/**************************************************************************
* main method
*************************************************************************/
@ -3430,6 +3577,7 @@ public class Lower extends TreeTranslator {
actualSymbols = new HashMap<Symbol,Symbol>();
freevarCache = new HashMap<ClassSymbol,List<VarSymbol>>();
proxies = new Scope(syms.noSymbol);
twrVars = new Scope(syms.noSymbol);
outerThisStack = List.nil();
accessNums = new HashMap<Symbol,Integer>();
accessSyms = new HashMap<Symbol,MethodSymbol[]>();

View File

@ -535,6 +535,14 @@ public class TransTypes extends TreeTranslator {
result = tree;
}
public void visitTry(JCTry tree) {
tree.resources = translate(tree.resources, syms.autoCloseableType);
tree.body = translate(tree.body);
tree.catchers = translateCatchers(tree.catchers);
tree.finalizer = translate(tree.finalizer);
result = tree;
}
public void visitConditional(JCConditional tree) {
tree.cond = translate(tree.cond, syms.booleanType);
tree.truepart = translate(tree.truepart, erasure(tree.type));

View File

@ -325,6 +325,7 @@ implements CRTFlags {
public void visitTry(JCTry tree) {
SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
sr.mergeWith(csp(tree.resources));
sr.mergeWith(csp(tree.body));
sr.mergeWith(cspCatchers(tree.catchers));
sr.mergeWith(csp(tree.finalizer));

View File

@ -131,6 +131,7 @@ public class JavacParser implements Parser {
this.allowForeach = source.allowForeach();
this.allowStaticImport = source.allowStaticImport();
this.allowAnnotations = source.allowAnnotations();
this.allowTWR = source.allowTryWithResources();
this.allowDiamond = source.allowDiamond();
this.allowMulticatch = source.allowMulticatch();
this.allowTypeAnnotations = source.allowTypeAnnotations();
@ -186,6 +187,10 @@ public class JavacParser implements Parser {
*/
boolean allowTypeAnnotations;
/** Switch: should we recognize automatic resource management?
*/
boolean allowTWR;
/** Switch: should we keep docComments?
*/
boolean keepDocComments;
@ -1846,6 +1851,7 @@ public class JavacParser implements Parser {
* | WHILE ParExpression Statement
* | DO Statement WHILE ParExpression ";"
* | TRY Block ( Catches | [Catches] FinallyPart )
* | TRY "(" ResourceSpecification ")" Block [Catches] [FinallyPart]
* | SWITCH ParExpression "{" SwitchBlockStatementGroups "}"
* | SYNCHRONIZED ParExpression Block
* | RETURN [Expression] ";"
@ -1916,6 +1922,13 @@ public class JavacParser implements Parser {
}
case TRY: {
S.nextToken();
List<JCTree> resources = List.<JCTree>nil();
if (S.token() == LPAREN) {
checkAutomaticResourceManagement();
S.nextToken();
resources = resources();
accept(RPAREN);
}
JCBlock body = block();
ListBuffer<JCCatch> catchers = new ListBuffer<JCCatch>();
JCBlock finalizer = null;
@ -1926,9 +1939,13 @@ public class JavacParser implements Parser {
finalizer = block();
}
} else {
log.error(pos, "try.without.catch.or.finally");
if (allowTWR) {
if (resources.isEmpty())
log.error(pos, "try.without.catch.finally.or.resource.decls");
} else
log.error(pos, "try.without.catch.or.finally");
}
return F.at(pos).Try(body, catchers.toList(), finalizer);
return F.at(pos).Try(resources, body, catchers.toList(), finalizer);
}
case SWITCH: {
S.nextToken();
@ -2389,6 +2406,39 @@ public class JavacParser implements Parser {
return toP(F.at(pos).VarDef(mods, name, type, null));
}
/** Resources = Resource { ";" Resources }
*/
List<JCTree> resources() {
ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
defs.append(resource());
while (S.token() == SEMI) {
// All but last of multiple declarators subsume a semicolon
storeEnd(defs.elems.last(), S.endPos());
S.nextToken();
defs.append(resource());
}
return defs.toList();
}
/** Resource =
* VariableModifiers Type VariableDeclaratorId = Expression
* | Expression
*/
JCTree resource() {
int pos = S.pos();
if (S.token() == FINAL || S.token() == MONKEYS_AT) {
return variableDeclaratorRest(pos, optFinal(0), parseType(),
ident(), true, null);
} else {
JCExpression t = term(EXPR | TYPE);
if ((lastmode & TYPE) != 0 && S.token() == IDENTIFIER)
return variableDeclaratorRest(pos, toP(F.at(pos).Modifiers(Flags.FINAL)), t,
ident(), true, null);
else
return t;
}
}
/** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration}
*/
public JCTree.JCCompilationUnit parseCompilationUnit() {
@ -3220,6 +3270,12 @@ public class JavacParser implements Parser {
if (!allowMulticatch) {
log.error(S.pos(), "multicatch.not.supported.in.source", source.name);
allowMulticatch = true;
}
}
}
void checkAutomaticResourceManagement() {
if (!allowTWR) {
log.error(S.pos(), "automatic.resource.management.not.supported.in.source", source.name);
allowTWR = true;
}
}
}

View File

@ -61,6 +61,8 @@ compiler.err.anon.class.impl.intf.no.typeargs=\
anonymous class implements interface; cannot have type arguments
compiler.err.anon.class.impl.intf.no.qual.for.new=\
anonymous class implements interface; cannot have qualifier for new
compiler.misc.twr.not.applicable.to.type=\
automatic resource management not applicable to variable type
compiler.err.array.and.varargs=\
cannot declare both {0} and {1} in {2}
compiler.err.array.dimension.missing=\
@ -172,6 +174,8 @@ compiler.err.except.never.thrown.in.try=\
compiler.err.final.parameter.may.not.be.assigned=\
final parameter {0} may not be assigned
compiler.err.twr.resource.may.not.be.assigned=\
automatic resource {0} may not be assigned
compiler.err.multicatch.parameter.may.not.be.assigned=\
multi-catch parameter {0} may not be assigned
compiler.err.multicatch.param.must.be.final=\
@ -448,6 +452,8 @@ compiler.err.throws.not.allowed.in.intf.annotation=\
throws clause not allowed in @interface members
compiler.err.try.without.catch.or.finally=\
''try'' without ''catch'' or ''finally''
compiler.err.try.without.catch.finally.or.resource.decls=\
''try'' without ''catch'', ''finally'' or resource declarations
compiler.err.type.doesnt.take.params=\
type {0} does not take parameters
compiler.err.type.var.cant.be.deref=\
@ -797,6 +803,10 @@ compiler.warn.proc.unclosed.type.files=\
compiler.warn.proc.unmatched.processor.options=\
The following options were not recognized by any processor: ''{0}''
compiler.warn.twr.explicit.close.call=\
[arm] explicit call to close() on an automatic resource
compiler.warn.automatic.resource.not.referenced=\
[arm] automatic resource {0} is never referenced in body of corresponding try statement
compiler.warn.unchecked.assign=\
[unchecked] unchecked assignment: {0} to {1}
compiler.warn.unchecked.assign.to.var=\
@ -1217,6 +1227,10 @@ compiler.err.unsupported.underscore.lit=\
underscores in literals are not supported in -source {0}\n\
(use -source 7 or higher to enable underscores in literals)
compiler.err.automatic.resource.management.not.supported.in.source=\
automatic resource management is not supported in -source {0}\n\
(use -source 7 or higher to enable automatic resource management)
compiler.warn.enum.as.identifier=\
as of release 5, ''enum'' is a keyword, and may not be used as an identifier\n\
(use -source 5 or higher to use ''enum'' as a keyword)

View File

@ -1021,10 +1021,15 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public JCBlock body;
public List<JCCatch> catchers;
public JCBlock finalizer;
protected JCTry(JCBlock body, List<JCCatch> catchers, JCBlock finalizer) {
public List<JCTree> resources;
protected JCTry(List<JCTree> resources,
JCBlock body,
List<JCCatch> catchers,
JCBlock finalizer) {
this.body = body;
this.catchers = catchers;
this.finalizer = finalizer;
this.resources = resources;
}
@Override
public void accept(Visitor v) { v.visitTry(this); }
@ -1040,6 +1045,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
return v.visitTry(this, d);
}
@Override
public List<? extends JCTree> getResources() {
return resources;
}
@Override
public int getTag() {
return TRY;
}
@ -2162,6 +2171,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
JCCase Case(JCExpression pat, List<JCStatement> stats);
JCSynchronized Synchronized(JCExpression lock, JCBlock body);
JCTry Try(JCBlock body, List<JCCatch> catchers, JCBlock finalizer);
JCTry Try(List<JCTree> resources,
JCBlock body,
List<JCCatch> catchers,
JCBlock finalizer);
JCCatch Catch(JCVariableDecl param, JCBlock body);
JCConditional Conditional(JCExpression cond,
JCExpression thenpart,

View File

@ -691,6 +691,19 @@ public class Pretty extends JCTree.Visitor {
public void visitTry(JCTry tree) {
try {
print("try ");
if (tree.resources.nonEmpty()) {
print("(");
boolean first = true;
for (JCTree var : tree.resources) {
if (!first) {
println();
indent();
}
printStat(var);
first = false;
}
print(") ");
}
printStat(tree.body);
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
printStat(l.head);

View File

@ -332,10 +332,11 @@ public class TreeCopier<P> implements TreeVisitor<JCTree,P> {
public JCTree visitTry(TryTree node, P p) {
JCTry t = (JCTry) node;
List<JCTree> resources = copy(t.resources, p);
JCBlock body = copy(t.body, p);
List<JCCatch> catchers = copy(t.catchers, p);
JCBlock finalizer = copy(t.finalizer, p);
return M.at(t.pos).Try(body, catchers, finalizer);
return M.at(t.pos).Try(resources, body, catchers, finalizer);
}
public JCTree visitParameterizedType(ParameterizedTypeTree node, P p) {

View File

@ -269,7 +269,14 @@ public class TreeMaker implements JCTree.Factory {
}
public JCTry Try(JCBlock body, List<JCCatch> catchers, JCBlock finalizer) {
JCTry tree = new JCTry(body, catchers, finalizer);
return Try(List.<JCTree>nil(), body, catchers, finalizer);
}
public JCTry Try(List<JCTree> resources,
JCBlock body,
List<JCCatch> catchers,
JCBlock finalizer) {
JCTry tree = new JCTry(resources, body, catchers, finalizer);
tree.pos = pos;
return tree;
}

View File

@ -147,6 +147,7 @@ public class TreeScanner extends Visitor {
}
public void visitTry(JCTry tree) {
scan(tree.resources);
scan(tree.body);
scan(tree.catchers);
scan(tree.finalizer);

View File

@ -212,6 +212,7 @@ public class TreeTranslator extends JCTree.Visitor {
}
public void visitTry(JCTry tree) {
tree.resources = translate(tree.resources);
tree.body = translate(tree.body);
tree.catchers = translateCatchers(tree.catchers);
tree.finalizer = translate(tree.finalizer);

View File

@ -148,6 +148,8 @@ public class Names {
public final Name getDeclaringClass;
public final Name ex;
public final Name finalize;
public final Name java_lang_AutoCloseable;
public final Name close;
public final Name.Table table;
@ -263,6 +265,9 @@ public class Names {
getDeclaringClass = fromString("getDeclaringClass");
ex = fromString("ex");
finalize = fromString("finalize");
java_lang_AutoCloseable = fromString("java.lang.AutoCloseable");
close = fromString("close");
}
protected Name.Table createTable(Options options) {

View File

@ -0,0 +1,55 @@
/*
* @test /nodynamiccopyright/
* @bug 6911256 6964740 6965277 6967065
* @author Joseph D. Darcy
* @summary Check that -Xlint:arm warnings are generated as expected
* @compile/ref=ArmLint.out -Xlint:arm,deprecation -XDrawDiagnostics ArmLint.java
*/
class ArmLint implements AutoCloseable {
private static void test1() {
try(ArmLint r1 = new ArmLint();
ArmLint r2 = new ArmLint();
ArmLint r3 = new ArmLint()) {
r1.close(); // The resource's close
r2.close(42); // *Not* the resource's close
// r3 not referenced
}
}
@SuppressWarnings("arm")
private static void test2() {
try(@SuppressWarnings("deprecation") AutoCloseable r4 =
new DeprecatedAutoCloseable()) {
// r4 not referenced
} catch(Exception e) {
;
}
}
/**
* The AutoCloseable method of a resource.
*/
@Override
public void close () {
return;
}
/**
* <em>Not</em> the AutoCloseable method of a resource.
*/
public void close (int arg) {
return;
}
}
@Deprecated
class DeprecatedAutoCloseable implements AutoCloseable {
public DeprecatedAutoCloseable(){super();}
@Override
public void close () {
return;
}
}

View File

@ -0,0 +1,3 @@
ArmLint.java:14:15: compiler.warn.twr.explicit.close.call
ArmLint.java:13:13: compiler.warn.automatic.resource.not.referenced: r3
2 warnings

View File

@ -0,0 +1,36 @@
/*
* @test /nodynamiccopyright/
* @bug 6911256 6964740
* @author Joseph D. Darcy
* @summary Verify bad TWRs don't compile
* @compile/fail -source 6 TwrFlow.java
* @compile/fail/ref=BadTwr.out -XDrawDiagnostics BadTwr.java
*/
public class BadTwr implements AutoCloseable {
public static void main(String... args) {
// illegal repeated name
try(BadTwr r1 = new BadTwr(); BadTwr r1 = new BadTwr()) {
System.out.println(r1.toString());
}
// illegal duplicate name of method argument
try(BadTwr args = new BadTwr()) {
System.out.println(args.toString());
final BadTwr thatsIt = new BadTwr();
thatsIt = null;
}
try(BadTwr name = new BadTwr()) {
// illegal duplicate name of enclosing try
try(BadTwr name = new BadTwr()) {
System.out.println(name.toString());
}
}
}
public void close() {
;
}
}

View File

@ -0,0 +1,5 @@
BadTwr.java:13:39: compiler.err.already.defined: r1, main(java.lang.String...)
BadTwr.java:18:13: compiler.err.already.defined: args, main(java.lang.String...)
BadTwr.java:21:13: compiler.err.cant.assign.val.to.final.var: thatsIt
BadTwr.java:26:17: compiler.err.already.defined: name, main(java.lang.String...)
4 errors

View File

@ -0,0 +1,22 @@
/*
* @test /nodynamiccopyright/
* @bug 6911256 6964740
* @author Joseph D. Darcy
* @summary Verify bad TWRs don't compile
* @compile/fail -source 6 BadTwrSyntax.java
* @compile/fail/ref=BadTwrSyntax.out -XDrawDiagnostics BadTwrSyntax.java
*/
import java.io.IOException;
public class BadTwrSyntax implements AutoCloseable {
public static void main(String... args) throws Exception {
// illegal semicolon ending resources
try(BadTwr twrflow = new BadTwr();) {
System.out.println(twrflow.toString());
}
}
public void close() {
;
}
}

View File

@ -0,0 +1,2 @@
BadTwrSyntax.java:14:43: compiler.err.illegal.start.of.expr
1 error

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6911256 6964740 6965277
* @author Maurizio Cimadamore
* @summary Check that lowered arm block does not end up creating resource twice
*/
import java.util.ArrayList;
public class DuplicateResource {
static class TestResource implements AutoCloseable {
TestResource() {
resources.add(this);
}
boolean isClosed = false;
public void close() throws Exception {
isClosed = true;
}
}
static ArrayList<TestResource> resources = new ArrayList<TestResource>();
public static void main(String[] args) {
try(new TestResource()) {
//do something
} catch (Exception e) {
throw new AssertionError("Shouldn't reach here", e);
}
check();
}
public static void check() {
if (resources.size() != 1) {
throw new AssertionError("Expected one resource, found: " + resources.size());
}
TestResource resource = resources.get(0);
if (!resource.isClosed) {
throw new AssertionError("Resource used in ARM block has not been automatically closed");
}
}
}

View File

@ -0,0 +1,20 @@
/*
* @test /nodynamiccopyright/
* @bug 6911256 6964740 6965277
* @author Maurizio Cimadamore
* @summary Check that resource variable is not accessible from catch/finally clause
* @compile/fail/ref=DuplicateResourceDecl.out -XDrawDiagnostics DuplicateResourceDecl.java
*/
class DuplicateResourceDecl {
public static void main(String[] args) {
try(MyResource c = new MyResource();MyResource c = new MyResource()) {
//do something
} catch (Exception e) { }
}
static class MyResource implements AutoCloseable {
public void close() throws Exception {}
}
}

View File

@ -0,0 +1,2 @@
DuplicateResourceDecl.java:12:45: compiler.err.already.defined: c, main(java.lang.String[])
1 error

View File

@ -0,0 +1,27 @@
/*
* @test /nodynamiccopyright/
* @bug 6911256 6964740 6965277
* @author Maurizio Cimadamore
* @summary Test that resource variables are implicitly final
* @compile/fail/ref=ImplicitFinal.out -XDrawDiagnostics ImplicitFinal.java
*/
import java.io.IOException;
class ImplicitFinal implements AutoCloseable {
public static void main(String... args) {
try(ImplicitFinal r = new ImplicitFinal()) {
r = null; //disallowed
} catch (IOException ioe) { // Not reachable
throw new AssertionError("Shouldn't reach here", ioe);
}
}
// A close method, but the class is <em>not</em> Closeable or
// AutoCloseable.
public void close() throws IOException {
throw new IOException();
}
}

View File

@ -0,0 +1,2 @@
ImplicitFinal.java:14:13: compiler.err.twr.resource.may.not.be.assigned: r
1 error

View File

@ -0,0 +1,15 @@
/*
* @test /nodynamiccopyright/
* @bug 6911256 6964740
* @author Joseph D. Darcy
* @summary Test error messages for an unadorned try
* @compile/fail/ref=PlainTry6.out -XDrawDiagnostics -source 6 PlainTry.java
* @compile/fail/ref=PlainTry.out -XDrawDiagnostics PlainTry.java
*/
public class PlainTry {
public static void main(String... args) {
try {
;
}
}
}

View File

@ -0,0 +1,2 @@
PlainTry.java:11:9: compiler.err.try.without.catch.finally.or.resource.decls
1 error

View File

@ -0,0 +1,2 @@
PlainTry.java:11:9: compiler.err.try.without.catch.or.finally
1 error

View File

@ -0,0 +1,23 @@
/*
* @test /nodynamiccopyright/
* @bug 6911256 6964740 6965277
* @author Maurizio Cimadamore
* @summary Check that resource variable is not accessible from catch/finally clause
* @compile/fail/ref=ResourceOutsideTry.out -XDrawDiagnostics ResourceOutsideTry.java
*/
class ResourceOutsideTry {
void test() {
try(MyResource c = new MyResource()) {
//do something
} catch (Exception e) {
c.test();
} finally {
c.test();
}
}
static class MyResource implements AutoCloseable {
public void close() throws Exception {}
void test() {}
}
}

View File

@ -0,0 +1,3 @@
ResourceOutsideTry.java:14:13: compiler.err.cant.resolve.location: kindname.variable, c, , , kindname.class, ResourceOutsideTry
ResourceOutsideTry.java:16:13: compiler.err.cant.resolve.location: kindname.variable, c, , , kindname.class, ResourceOutsideTry
2 errors

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6911256 6964740 6965277
* @author Maurizio Cimadamore
* @summary Resource of a type-variable type crashes Flow
* @compile ResourceTypeVar.java
*/
class ResourceTypeVar<X extends AutoCloseable> {
public void test() {
try(X armflow = getX()) {
//do something
} catch (Exception e) { // Not reachable
throw new AssertionError("Shouldn't reach here", e);
}
}
X getX() { return null; }
}

View File

@ -0,0 +1,39 @@
/*
* @test /nodynamiccopyright/
* @bug 6911256 6964740
* @author Joseph D. Darcy
* @summary Test exception analysis of ARM blocks
* @compile/fail/ref=TwrFlow.out -XDrawDiagnostics TwrFlow.java
*/
import java.io.IOException;
public class TwrFlow implements AutoCloseable {
public static void main(String... args) {
try(TwrFlow armflow = new TwrFlow()) {
System.out.println(armflow.toString());
} catch (IOException ioe) { // Not reachable
throw new AssertionError("Shouldn't reach here", ioe);
}
// CustomCloseException should be caught or added to throws clause
// Also check behavior on a resource expression rather than a
// declaration.
TwrFlow armflowexpr = new TwrFlow();
try(armflowexpr) {
System.out.println(armflowexpr.toString());
} catch (IOException ioe) { // Not reachable
throw new AssertionError("Shouldn't reach here", ioe);
}
// CustomCloseException should be caught or added to throws clause
}
/*
* A close method, but the class is <em>not</em> Closeable or
* AutoCloseable.
*/
public void close() throws CustomCloseException {
throw new CustomCloseException();
}
}
class CustomCloseException extends Exception {}

View File

@ -0,0 +1,5 @@
TwrFlow.java:14:11: compiler.err.except.never.thrown.in.try: java.io.IOException
TwrFlow.java:24:11: compiler.err.except.never.thrown.in.try: java.io.IOException
TwrFlow.java:12:46: compiler.err.unreported.exception.need.to.catch.or.throw: CustomCloseException
TwrFlow.java:22:26: compiler.err.unreported.exception.need.to.catch.or.throw: CustomCloseException
4 errors

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6911256 6964740 6965277
* @author Maurizio Cimadamore
* @summary Verify that method type-inference works as expected in TWR context
* @compile TwrInference.java
*/
class TwrInference {
public void test() {
try(getX()) {
//do something
} catch (Exception e) { // Not reachable
throw new AssertionError("Shouldn't reach here", e);
}
}
<X> X getX() { return null; }
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6911256 6964740 6965277
* @author Maurizio Cimadamore
* @summary Resource of an intersection type crashes Flow
* @compile TwrIntersection.java
*/
interface MyCloseable extends AutoCloseable {
void close() throws java.io.IOException;
}
class ResourceTypeVar {
public void test() {
try(getX()) {
//do something
} catch (java.io.IOException e) { // Not reachable
throw new AssertionError("Shouldn't reach here", e);
}
}
<X extends Number & MyCloseable> X getX() { return null; }
}

View File

@ -0,0 +1,37 @@
/*
* @test /nodynamiccopyright/
* @bug 6911256 6964740 6965277
* @author Maurizio Cimadamore
* @summary Check that resources of an intersection type forces union of exception types
* to be caught outside twr block
* @compile/fail/ref=TwrIntersection02.out -XDrawDiagnostics TwrIntersection02.java
*/
class TwrIntersection02 {
static class Exception1 extends Exception {}
static class Exception2 extends Exception {}
interface MyResource1 extends AutoCloseable {
void close() throws Exception1;
}
interface MyResource2 extends AutoCloseable {
void close() throws Exception2;
}
public void test1() throws Exception1 {
try(getX()) {
//do something
}
}
public void test2() throws Exception2 {
try(getX()) {
//do something
}
}
<X extends MyResource1 & MyResource2> X getX() { return null; }
}

View File

@ -0,0 +1,3 @@
TwrIntersection02.java:25:21: compiler.err.unreported.exception.need.to.catch.or.throw: TwrIntersection02.Exception2
TwrIntersection02.java:31:21: compiler.err.unreported.exception.need.to.catch.or.throw: TwrIntersection02.Exception1
2 errors

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6911256 6964740
* @author Joseph D. Darcy
* @summary Test that TWR and multi-catch play well together
* @compile TwrMultiCatch.java
* @run main TwrMultiCatch
*/
import java.io.IOException;
public class TwrMultiCatch implements AutoCloseable {
private final Class<? extends Exception> exceptionClass;
private TwrMultiCatch(Class<? extends Exception> exceptionClass) {
this.exceptionClass = exceptionClass;
}
public static void main(String... args) {
test(new TwrMultiCatch(CustomCloseException1.class),
CustomCloseException1.class);
test(new TwrMultiCatch(CustomCloseException2.class),
CustomCloseException2.class);
}
private static void test(TwrMultiCatch twrMultiCatch,
Class<? extends Exception> expected) {
try(twrMultiCatch) {
System.out.println(twrMultiCatch.toString());
} catch (final CustomCloseException1 |
CustomCloseException2 exception) {
if (!exception.getClass().equals(expected) ) {
throw new RuntimeException("Unexpected catch!");
}
}
}
public void close() throws CustomCloseException1, CustomCloseException2 {
Throwable t;
try {
t = exceptionClass.newInstance();
} catch(ReflectiveOperationException rfe) {
throw new RuntimeException(rfe);
}
try {
throw t;
} catch (final CustomCloseException1 |
CustomCloseException2 exception) {
throw exception;
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}
}
class CustomCloseException1 extends Exception {}
class CustomCloseException2 extends Exception {}

View File

@ -0,0 +1,42 @@
/*
* @test /nodynamiccopyright/
* @bug 6911256 6964740
* @author Joseph D. Darcy
* @summary Verify invalid TWR block is not accepted.
* @compile/fail -source 6 TwrOnNonResource.java
* @compile/fail/ref=TwrOnNonResource.out -XDrawDiagnostics TwrOnNonResource.java
*/
class TwrOnNonResource {
public static void main(String... args) {
try(TwrOnNonResource aonr = new TwrOnNonResource()) {
System.out.println(aonr.toString());
}
try(TwrOnNonResource aonr = new TwrOnNonResource()) {
System.out.println(aonr.toString());
} finally {;}
try(TwrOnNonResource aonr = new TwrOnNonResource()) {
System.out.println(aonr.toString());
} catch (Exception e) {;}
// Also check expression form
TwrOnNonResource aonr = new TwrOnNonResource();
try(aonr) {
System.out.println(aonr.toString());
}
try(aonr) {
System.out.println(aonr.toString());
} finally {;}
try(aonr) {
System.out.println(aonr.toString());
} catch (Exception e) {;}
}
/*
* A close method, but the class is <em>not</em> Closeable or
* AutoCloseable.
*/
public void close() {
throw new AssertionError("I'm not Closable!");
}
}

View File

@ -0,0 +1,7 @@
TwrOnNonResource.java:12:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable
TwrOnNonResource.java:15:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable
TwrOnNonResource.java:18:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable
TwrOnNonResource.java:24:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable
TwrOnNonResource.java:27:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable
TwrOnNonResource.java:30:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable
6 errors

View File

@ -0,0 +1,742 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6911256 6964740
* @summary Tests of generated TWR code.
*/
import java.util.List;
import java.util.ArrayList;
public class TwrTests {
public static void main(String[] args) {
testCreateFailure1();
testCreateFailure2();
testCreateFailure2Nested();
testCreateFailure3();
testCreateFailure3Nested();
testCreateFailure4();
testCreateFailure4Nested();
testCreateFailure5();
testCreateFailure5Nested();
testCreateSuccess1();
testCreateSuccess2();
testCreateSuccess2Nested();
testCreateSuccess3();
testCreateSuccess3Nested();
testCreateSuccess4();
testCreateSuccess4Nested();
testCreateSuccess5();
testCreateSuccess5Nested();
}
/*
* The following tests simulate a creation failure of every possible
* resource in an TWR block, and check to make sure that the failure
* prevents creation of subsequent resources, and that all created
* resources are properly closed, even if one or more of the close
* attempts fails.
*/
public static void testCreateFailure1() {
int creationFailuresDetected = 0;
List<Integer> closedList = new ArrayList<Integer>(0);
try (Resource r0 = createResource(0, 0, 0, closedList)) {
throw new AssertionError("Resource creation succeeded");
} catch (Resource.CreateFailException e) {
creationFailuresDetected++;
if (e.resourceId() != 0) {
throw new AssertionError("Wrong resource creation "
+ e.resourceId() + " failed");
}
} catch (Resource.CloseFailException e) {
throw new AssertionError("Unexpected CloseFailException: " + e.resourceId());
}
checkForSingleCreationFailure(creationFailuresDetected);
checkClosedList(closedList, 0);
}
public static void testCreateFailure2() {
for (int createFailureId = 0; createFailureId < 2; createFailureId++) {
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
int creationFailuresDetected = 0;
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList);
Resource r1 = createResource(1, createFailureId, bitMap, closedList)) {
throw new AssertionError("Entire resource creation succeeded");
} catch (Resource.CreateFailException e) {
creationFailuresDetected++;
checkCreateFailureId(e.resourceId(), createFailureId);
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
throw new AssertionError("Secondary exception suppression failed");
}
checkForSingleCreationFailure(creationFailuresDetected);
checkClosedList(closedList, createFailureId);
}
}
}
public static void testCreateFailure2Nested() {
for (int createFailureId = 0; createFailureId < 2; createFailureId++) {
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
int creationFailuresDetected = 0;
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList)) {
try(Resource r1 = createResource(1, createFailureId, bitMap, closedList)) {
throw new AssertionError("Entire resource creation succeeded");
}
} catch (Resource.CreateFailException e) {
creationFailuresDetected++;
checkCreateFailureId(e.resourceId(), createFailureId);
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
throw new AssertionError("Secondary exception suppression failed");
}
checkForSingleCreationFailure(creationFailuresDetected);
checkClosedList(closedList, createFailureId);
}
}
}
public static void testCreateFailure3() {
for (int createFailureId = 0; createFailureId < 3; createFailureId++) {
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
int creationFailuresDetected = 0;
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList);
Resource r1 = createResource(1, createFailureId, bitMap, closedList);
Resource r2 = createResource(2, createFailureId, bitMap, closedList)) {
throw new AssertionError("Entire resource creation succeeded");
} catch (Resource.CreateFailException e) {
creationFailuresDetected++;
checkCreateFailureId(e.resourceId(), createFailureId);
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
throw new AssertionError("Secondary exception suppression failed:" + e);
}
checkForSingleCreationFailure(creationFailuresDetected);
checkClosedList(closedList, createFailureId);
}
}
}
public static void testCreateFailure3Nested() {
for (int createFailureId = 0; createFailureId < 3; createFailureId++) {
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
int creationFailuresDetected = 0;
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList)) {
try (Resource r1 = createResource(1, createFailureId, bitMap, closedList)) {
try (Resource r2 = createResource(2, createFailureId, bitMap, closedList)) {
throw new AssertionError("Entire resource creation succeeded");
}
}
} catch (Resource.CreateFailException e) {
creationFailuresDetected++;
checkCreateFailureId(e.resourceId(), createFailureId);
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
throw new AssertionError("Secondary exception suppression failed:" + e);
}
checkForSingleCreationFailure(creationFailuresDetected);
checkClosedList(closedList, createFailureId);
}
}
}
public static void testCreateFailure4() {
for (int createFailureId = 0; createFailureId < 4; createFailureId++) {
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
int creationFailuresDetected = 0;
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList);
Resource r1 = createResource(1, createFailureId, bitMap, closedList);
Resource r2 = createResource(2, createFailureId, bitMap, closedList);
Resource r3 = createResource(3, createFailureId, bitMap, closedList)) {
throw new AssertionError("Entire resource creation succeeded");
} catch (Resource.CreateFailException e) {
creationFailuresDetected++;
checkCreateFailureId(e.resourceId(), createFailureId);
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
throw new AssertionError("Secondary exception suppression failed:" + e);
}
checkForSingleCreationFailure(creationFailuresDetected);
checkClosedList(closedList, createFailureId);
}
}
}
public static void testCreateFailure4Nested() {
for (int createFailureId = 0; createFailureId < 4; createFailureId++) {
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
int creationFailuresDetected = 0;
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList)) {
try (Resource r1 = createResource(1, createFailureId, bitMap, closedList)) {
try (Resource r2 = createResource(2, createFailureId, bitMap, closedList)) {
try (Resource r3 = createResource(3, createFailureId, bitMap, closedList)) {
throw new AssertionError("Entire resource creation succeeded");
}
}
}
} catch (Resource.CreateFailException e) {
creationFailuresDetected++;
checkCreateFailureId(e.resourceId(), createFailureId);
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
throw new AssertionError("Secondary exception suppression failed:" + e);
}
checkForSingleCreationFailure(creationFailuresDetected);
checkClosedList(closedList, createFailureId);
}
}
}
public static void testCreateFailure5() {
for (int createFailureId = 0; createFailureId < 5; createFailureId++) {
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
int creationFailuresDetected = 0;
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList);
Resource r1 = createResource(1, createFailureId, bitMap, closedList);
Resource r2 = createResource(2, createFailureId, bitMap, closedList);
Resource r3 = createResource(3, createFailureId, bitMap, closedList);
Resource r4 = createResource(4, createFailureId, bitMap, closedList)) {
throw new AssertionError("Entire resource creation succeeded");
} catch (Resource.CreateFailException e) {
creationFailuresDetected++;
checkCreateFailureId(e.resourceId(), createFailureId);
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
throw new AssertionError("Secondary exception suppression failed:" + e);
}
checkForSingleCreationFailure(creationFailuresDetected);
checkClosedList(closedList, createFailureId);
}
}
}
public static void testCreateFailure5Nested() {
for (int createFailureId = 0; createFailureId < 5; createFailureId++) {
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
int creationFailuresDetected = 0;
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList)) {
try (Resource r1 = createResource(1, createFailureId, bitMap, closedList)) {
try (Resource r2 = createResource(2, createFailureId, bitMap, closedList)) {
try (Resource r3 = createResource(3, createFailureId, bitMap, closedList)) {
try (Resource r4 = createResource(4, createFailureId, bitMap, closedList)) {
throw new AssertionError("Entire resource creation succeeded");
}
}
}
}
} catch (Resource.CreateFailException e) {
creationFailuresDetected++;
checkCreateFailureId(e.resourceId(), createFailureId);
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
throw new AssertionError("Secondary exception suppression failed:" + e);
}
checkForSingleCreationFailure(creationFailuresDetected);
checkClosedList(closedList, createFailureId);
}
}
}
/**
* Create a resource with the specified ID. The ID must be less than createFailureId.
* A subsequent attempt to close the resource will fail iff the corresponding bit
* is set in closeFailureBitMap. When an attempt is made to close this resource,
* its ID will be added to closedList, regardless of whether the attempt succeeds.
*
* @param id the ID of this resource
* @param createFailureId the ID of the resource whose creation will fail
* @param closeFailureBitMap a bit vector describing which resources should throw an
* exception when close is attempted
* @param closedList a list on which to record resource close attempts
* @throws AssertionError if no attempt should be made to create this resource
*/
private static Resource createResource(int id,
int createFailureId,
int closeFailureBitMap,
List<Integer> closedList) throws Resource.CreateFailException {
if (id > createFailureId)
throw new AssertionError("Resource " + id + " shouldn't be created");
boolean createSucceeds = id != createFailureId;
boolean closeSucceeds = (closeFailureBitMap & (1 << id)) == 0;
return new Resource(id, createSucceeds, closeSucceeds, closedList);
}
/**
* Check that an observed creation failure has the expected resource ID.
*
* @param foundId the ID of the resource whose creation failed
* @param expectedId the ID of the resource whose creation should have failed
*/
private static void checkCreateFailureId(int foundId, int expectedId) {
if (foundId != expectedId)
throw new AssertionError("Wrong resource creation failed. Found ID "
+ foundId + " expected " + expectedId);
}
/**
* Check for proper suppressed exceptions in proper order.
*
* @param suppressedExceptions the suppressed exceptions array returned by
* getSuppressedExceptions()
* @bitmap a bitmap indicating which suppressed exceptions are expected.
* Bit i is set iff id should throw a CloseFailException.
*/
private static void checkSuppressedExceptions(Throwable[] suppressedExceptions, int bitMap) {
if (suppressedExceptions.length != Integer.bitCount(bitMap))
throw new AssertionError("Expected " + Integer.bitCount(bitMap)
+ " suppressed exceptions, got " + suppressedExceptions.length);
int prevCloseFailExceptionId = Integer.MAX_VALUE;
for (Throwable t : suppressedExceptions) {
int id = ((Resource.CloseFailException) t).resourceId();
if ((1 << id & bitMap) == 0)
throw new AssertionError("Unexpected suppressed CloseFailException: " + id);
if (id > prevCloseFailExceptionId)
throw new AssertionError("Suppressed CloseFailException" + id
+ " followed " + prevCloseFailExceptionId);
}
}
/**
* Check that exactly one resource creation failed.
*
* @param numCreationFailuresDetected the number of creation failures detected
*/
private static void checkForSingleCreationFailure(int numCreationFailuresDetected) {
if (numCreationFailuresDetected != 1)
throw new AssertionError("Wrong number of creation failures: "
+ numCreationFailuresDetected);
}
/**
* Check that a close was attempted on every resourced that was successfully opened,
* and that the close attempts occurred in the proper order.
*
* @param closedList the resource IDs of the close attempts, in the order they occurred
* @param the ID of the resource whose creation failed. Close attempts should occur
* for all previous resources, in reverse order.
*/
private static void checkClosedList(List<Integer> closedList, int createFailureId) {
List<Integer> expectedList = new ArrayList<Integer>(createFailureId);
for (int i = createFailureId - 1; i >= 0; i--)
expectedList.add(i);
if (!closedList.equals(expectedList))
throw new AssertionError("Closing sequence " + closedList + " != " + expectedList);
}
/*
* The following tests simulate the creation of several resources, followed
* by success or failure of forward processing. They test that all resources
* are properly closed, even if one or more of the close attempts fails.
*/
public static void testCreateSuccess1() {
for (int bitMap = 0, n = 1 << 1; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
} catch (Resource.CreateFailException e) {
throw new AssertionError(
"Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 1);
}
}
}
public static void testCreateSuccess2() {
for (int bitMap = 0, n = 1 << 2; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList);
Resource r1 = createResource(1, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
} catch (Resource.CreateFailException e) {
throw new AssertionError(
"Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 2);
}
}
}
public static void testCreateSuccess2Nested() {
for (int bitMap = 0, n = 1 << 2; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList)) {
try (Resource r1 = createResource(1, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
}
} catch (Resource.CreateFailException e) {
throw new AssertionError(
"Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 2);
}
}
}
public static void testCreateSuccess3() {
for (int bitMap = 0, n = 1 << 3; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList);
Resource r1 = createResource(1, bitMap, closedList);
Resource r2 = createResource(2, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
} catch (Resource.CreateFailException e) {
throw new AssertionError(
"Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 3);
}
}
}
public static void testCreateSuccess3Nested() {
for (int bitMap = 0, n = 1 << 3; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList)) {
try (Resource r1 = createResource(1, bitMap, closedList)) {
try (Resource r2 = createResource(2, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
}
}
} catch (Resource.CreateFailException e) {
throw new AssertionError(
"Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 3);
}
}
}
public static void testCreateSuccess4() {
for (int bitMap = 0, n = 1 << 4; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList);
Resource r1 = createResource(1, bitMap, closedList);
Resource r2 = createResource(2, bitMap, closedList);
Resource r3 = createResource(3, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
} catch (Resource.CreateFailException e) {
throw new AssertionError(
"Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 4);
}
}
}
public static void testCreateSuccess4Nested() {
for (int bitMap = 0, n = 1 << 4; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList)) {
try (Resource r1 = createResource(1, bitMap, closedList)) {
try (Resource r2 = createResource(2, bitMap, closedList)) {
try (Resource r3 = createResource(3, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
}
}
}
} catch (Resource.CreateFailException e) {
throw new AssertionError(
"Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 4);
}
}
}
public static void testCreateSuccess5() {
for (int bitMap = 0, n = 1 << 5; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList);
Resource r1 = createResource(1, bitMap, closedList);
Resource r2 = createResource(2, bitMap, closedList);
Resource r3 = createResource(3, bitMap, closedList);
Resource r4 = createResource(4, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
} catch (Resource.CreateFailException e) {
throw new AssertionError("Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 5);
}
}
}
public static void testCreateSuccess5Nested() {
for (int bitMap = 0, n = 1 << 5; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList)) {
try (Resource r1 = createResource(1, bitMap, closedList)) {
try (Resource r2 = createResource(2, bitMap, closedList)) {
try (Resource r3 = createResource(3, bitMap, closedList)) {
try (Resource r4 = createResource(4, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
}
}
}
}
} catch (Resource.CreateFailException e) {
throw new AssertionError("Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 5);
}
}
}
private static Resource createResource(int id,
int closeFailureBitMap,
List<Integer> closedList) throws Resource.CreateFailException {
boolean closeSucceeds = (closeFailureBitMap & (1 << id)) == 0;
return new Resource(id, true, closeSucceeds, closedList);
}
private static class MyKindOfException extends Exception {
}
}
class Resource implements AutoCloseable {
/** A number identifying this resource */
private final int resourceId;
/** Whether the close call on this resource should succeed or fail */
private final boolean closeSucceeds;
/** When resource is closed, it records its ID in this list */
private final List<Integer> closedList;
Resource(int resourceId, boolean createSucceeds, boolean closeSucceeds,
List<Integer> closedList) throws CreateFailException {
if (!createSucceeds)
throw new CreateFailException(resourceId);
this.resourceId = resourceId;
this.closeSucceeds = closeSucceeds;
this.closedList = closedList;
}
public void close() throws CloseFailException {
closedList.add(resourceId);
if (!closeSucceeds)
throw new CloseFailException(resourceId);
}
public static class ResourceException extends RuntimeException {
private final int resourceId;
public ResourceException(int resourceId) {
super("Resource ID = " + resourceId);
this.resourceId = resourceId;
}
public int resourceId() {
return resourceId;
}
}
public static class CreateFailException extends ResourceException {
public CreateFailException(int resourceId) {
super(resourceId);
}
}
public static class CloseFailException extends ResourceException {
public CloseFailException(int resourceId) {
super(resourceId);
}
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6911256 6964740
* @author Joseph D. Darcy
* @summary Strange TWRs
* @compile/fail -source 6 WeirdTwr.java
* @compile WeirdTwr.java
* @run main WeirdTwr
*/
public class WeirdTwr implements AutoCloseable {
private static int closeCount = 0;
public static void main(String... args) {
try(WeirdTwr r1 = new WeirdTwr(); WeirdTwr r2 = r1) {
if (r1 != r2)
throw new RuntimeException("Unexpected inequality.");
}
if (closeCount != 2)
throw new RuntimeException("bad closeCount" + closeCount);
}
public void close() {
closeCount++;
}
}

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6911256 6964740
* @summary Test that the resource variable kind is appropriately set
* @author Joseph D. Darcy
* @build TestResourceVariable
* @compile/fail -processor TestResourceVariable -proc:only TestResourceVariable.java
*/
// Bug should be filed for this misbehavior
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 the
* resource of an ARM block and verify their kind tags are set
* appropriately.
*/
@SupportedAnnotationTypes("*")
public class TestResourceVariable extends AbstractProcessor implements AutoCloseable {
int resourceVariableCount = 0;
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 ResourceVariableScanner(trees)).
scan(trees.getTree(rootElement),
treePath.getCompilationUnit());
}
if (resourceVariableCount != 3)
throw new RuntimeException("Bad resource variable count " +
resourceVariableCount);
}
return true;
}
@Override
public void close() {}
private void test1() {
try(TestResourceVariable trv = this) {}
}
private void test2() {
try(TestResourceVariable trv1 = this; TestResourceVariable trv2 = trv1) {}
}
class ResourceVariableScanner extends TreeScanner<Void, CompilationUnitTree> {
private Trees trees;
public ResourceVariableScanner(Trees trees) {
super();
this.trees = trees;
}
@Override
public Void visitVariable(VariableTree node, CompilationUnitTree cu) {
Element element = trees.getElement(trees.getPath(cu, node));
if (element == null) {
System.out.println("Null variable element: " + node);
} else {
System.out.println("Name: " + element.getSimpleName() +
"\tKind: " + element.getKind());
}
if (element != null &&
element.getKind() == ElementKind.RESOURCE_VARIABLE) {
resourceVariableCount++;
}
return super.visitVariable(node, cu);
}
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
}