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:
parent
9c273720d6
commit
985efdc475
@ -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
|
||||
|
@ -49,4 +49,5 @@ public interface TryTree extends StatementTree {
|
||||
BlockTree getBlock();
|
||||
List<? extends CatchTree> getCatches();
|
||||
BlockTree getFinallyBlock();
|
||||
List<? extends Tree> getResources();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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[]>();
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
55
langtools/test/tools/javac/TryWithResources/ArmLint.java
Normal file
55
langtools/test/tools/javac/TryWithResources/ArmLint.java
Normal 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;
|
||||
}
|
||||
}
|
3
langtools/test/tools/javac/TryWithResources/ArmLint.out
Normal file
3
langtools/test/tools/javac/TryWithResources/ArmLint.out
Normal 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
|
36
langtools/test/tools/javac/TryWithResources/BadTwr.java
Normal file
36
langtools/test/tools/javac/TryWithResources/BadTwr.java
Normal 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() {
|
||||
;
|
||||
}
|
||||
}
|
5
langtools/test/tools/javac/TryWithResources/BadTwr.out
Normal file
5
langtools/test/tools/javac/TryWithResources/BadTwr.out
Normal 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
|
@ -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() {
|
||||
;
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
BadTwrSyntax.java:14:43: compiler.err.illegal.start.of.expr
|
||||
1 error
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {}
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
DuplicateResourceDecl.java:12:45: compiler.err.already.defined: c, main(java.lang.String[])
|
||||
1 error
|
@ -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();
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
ImplicitFinal.java:14:13: compiler.err.twr.resource.may.not.be.assigned: r
|
||||
1 error
|
15
langtools/test/tools/javac/TryWithResources/PlainTry.java
Normal file
15
langtools/test/tools/javac/TryWithResources/PlainTry.java
Normal 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 {
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
2
langtools/test/tools/javac/TryWithResources/PlainTry.out
Normal file
2
langtools/test/tools/javac/TryWithResources/PlainTry.out
Normal file
@ -0,0 +1,2 @@
|
||||
PlainTry.java:11:9: compiler.err.try.without.catch.finally.or.resource.decls
|
||||
1 error
|
@ -0,0 +1,2 @@
|
||||
PlainTry.java:11:9: compiler.err.try.without.catch.or.finally
|
||||
1 error
|
@ -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() {}
|
||||
}
|
||||
}
|
@ -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
|
@ -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; }
|
||||
}
|
39
langtools/test/tools/javac/TryWithResources/TwrFlow.java
Normal file
39
langtools/test/tools/javac/TryWithResources/TwrFlow.java
Normal 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 {}
|
5
langtools/test/tools/javac/TryWithResources/TwrFlow.out
Normal file
5
langtools/test/tools/javac/TryWithResources/TwrFlow.out
Normal 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
|
@ -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; }
|
||||
}
|
@ -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; }
|
||||
}
|
@ -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; }
|
||||
}
|
@ -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
|
@ -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 {}
|
@ -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!");
|
||||
}
|
||||
}
|
@ -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
|
742
langtools/test/tools/javac/TryWithResources/TwrTests.java
Normal file
742
langtools/test/tools/javac/TryWithResources/TwrTests.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
48
langtools/test/tools/javac/TryWithResources/WeirdTwr.java
Normal file
48
langtools/test/tools/javac/TryWithResources/WeirdTwr.java
Normal 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++;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user