# HG changeset patch # User lana # Date 1441322029 25200 # Node ID ead8b7192f00417185f0e64d0cb332f0f8ad4ae1 # Parent f0e149d3e375f96921b85426397e6a82415c8878# Parent 176472b94f2e59d1c23f652613d28d0ac1b0e8ee Merge diff -r f0e149d3e375 -r ead8b7192f00 src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Thu Sep 03 14:24:46 2015 -0700 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Thu Sep 03 16:13:49 2015 -0700 @@ -76,7 +76,7 @@ private final AtomicBoolean used = new AtomicBoolean(); private Iterable processors; - JavacTaskImpl(Context context) { + protected JavacTaskImpl(Context context) { super(context, true); args = Arguments.instance(context); fileManager = context.get(JavaFileManager.class); diff -r f0e149d3e375 -r ead8b7192f00 src/jdk.compiler/share/classes/com/sun/tools/javac/api/MultiTaskListener.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/MultiTaskListener.java Thu Sep 03 14:24:46 2015 -0700 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/MultiTaskListener.java Thu Sep 03 16:13:49 2015 -0700 @@ -47,6 +47,9 @@ /** The context key for the MultiTaskListener. */ public static final Context.Key taskListenerKey = new Context.Key<>(); + /** Empty array of task listeners */ + private static final TaskListener[] EMPTY_LISTENERS = new TaskListener[0]; + /** Get the MultiTaskListener instance for this context. */ public static MultiTaskListener instance(Context context) { MultiTaskListener instance = context.get(taskListenerKey); @@ -64,7 +67,7 @@ * The current set of registered listeners. * This is a mutable reference to an immutable array. */ - TaskListener[] listeners = { }; + TaskListener[] listeners = EMPTY_LISTENERS; ClientCodeWrapper ccw; @@ -73,7 +76,7 @@ } public boolean isEmpty() { - return (listeners.length == 0); + return listeners == EMPTY_LISTENERS; } public void add(TaskListener listener) { @@ -88,10 +91,14 @@ public void remove(TaskListener listener) { for (int i = 0; i < listeners.length; i++) { if (ccw.unwrap(listeners[i]) == listener) { - TaskListener[] newListeners = new TaskListener[listeners.length - 1]; - System.arraycopy(listeners, 0, newListeners, 0, i); - System.arraycopy(listeners, i + 1, newListeners, i, newListeners.length - i); - listeners = newListeners; + if (listeners.length == 1) { + listeners = EMPTY_LISTENERS; + } else { + TaskListener[] newListeners = new TaskListener[listeners.length - 1]; + System.arraycopy(listeners, 0, newListeners, 0, i); + System.arraycopy(listeners, i + 1, newListeners, i, newListeners.length - i); + listeners = newListeners; + } break; } } @@ -117,4 +124,8 @@ public String toString() { return Arrays.toString(listeners); } + + public void clear() { + listeners = EMPTY_LISTENERS; + } } diff -r f0e149d3e375 -r ead8b7192f00 src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java Thu Sep 03 14:24:46 2015 -0700 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java Thu Sep 03 16:13:49 2015 -0700 @@ -26,6 +26,7 @@ package com.sun.tools.javac.code; import com.sun.tools.javac.code.Kinds.Kind; +import java.lang.ref.WeakReference; import java.util.*; import java.util.function.BiConsumer; import java.util.stream.Stream; @@ -162,15 +163,49 @@ /** A list of scopes to be notified if items are to be removed from this scope. */ - List listeners = List.nil(); + ScopeListenerList listeners = new ScopeListenerList(); - public void addScopeListener(ScopeListener sl) { - listeners = listeners.prepend(sl); + public interface ScopeListener { + void symbolAdded(Symbol sym, Scope s); + void symbolRemoved(Symbol sym, Scope s); } - public interface ScopeListener { - public void symbolAdded(Symbol sym, Scope s); - public void symbolRemoved(Symbol sym, Scope s); + /** + * A list of scope listeners; listeners are stored in weak references, to avoid memory leaks. + * When the listener list is scanned (upon notification), elements corresponding to GC-ed + * listeners are removed so that the listener list size is kept in check. + */ + public static class ScopeListenerList { + + List> listeners = List.nil(); + + void add(ScopeListener sl) { + listeners = listeners.prepend(new WeakReference<>(sl)); + } + + void symbolAdded(Symbol sym, Scope scope) { + walkReferences(sym, scope, false); + } + + void symbolRemoved(Symbol sym, Scope scope) { + walkReferences(sym, scope, true); + } + + private void walkReferences(Symbol sym, Scope scope, boolean isRemove) { + ListBuffer> newListeners = new ListBuffer<>(); + for (WeakReference wsl : listeners) { + ScopeListener sl = wsl.get(); + if (sl != null) { + if (isRemove) { + sl.symbolRemoved(sym, scope); + } else { + sl.symbolAdded(sym, scope); + } + newListeners.add(wsl); + } + } + listeners = newListeners.toList(); + } } public enum LookupKind { @@ -404,9 +439,7 @@ elems = e; //notify listeners - for (List l = listeners; l.nonEmpty(); l = l.tail) { - l.head.symbolAdded(sym, this); - } + listeners.symbolAdded(sym, this); } /** Remove symbol from this scope. @@ -442,9 +475,7 @@ } //notify listeners - for (List l = listeners; l.nonEmpty(); l = l.tail) { - l.head.symbolRemoved(sym, this); - } + listeners.symbolRemoved(sym, this); } /** Enter symbol sym in this scope if not already there. @@ -698,11 +729,12 @@ finalized.enter(sym); } - finalized.addScopeListener(new ScopeListener() { + finalized.listeners.add(new ScopeListener() { @Override public void symbolAdded(Symbol sym, Scope s) { Assert.error("The scope is sealed."); } + @Override public void symbolRemoved(Symbol sym, Scope s) { Assert.error("The scope is sealed."); @@ -929,26 +961,20 @@ public void prependSubScope(Scope that) { if (that != null) { subScopes = subScopes.prepend(that); - that.addScopeListener(this); + that.listeners.add(this); mark++; - for (ScopeListener sl : listeners) { - sl.symbolAdded(null, this); //propagate upwards in case of nested CompoundScopes - } + listeners.symbolAdded(null, this); } } public void symbolAdded(Symbol sym, Scope s) { mark++; - for (ScopeListener sl : listeners) { - sl.symbolAdded(sym, s); - } + listeners.symbolAdded(sym, s); } public void symbolRemoved(Symbol sym, Scope s) { mark++; - for (ScopeListener sl : listeners) { - sl.symbolRemoved(sym, s); - } + listeners.symbolRemoved(sym, s); } public int getMark() { diff -r f0e149d3e375 -r ead8b7192f00 src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java Thu Sep 03 14:24:46 2015 -0700 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java Thu Sep 03 16:13:49 2015 -0700 @@ -68,7 +68,7 @@ /** * The context key for the arguments. */ - protected static final Context.Key argsKey = new Context.Key<>(); + public static final Context.Key argsKey = new Context.Key<>(); private String ownName; private Set classNames; diff -r f0e149d3e375 -r ead8b7192f00 src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Thu Sep 03 14:24:46 2015 -0700 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Thu Sep 03 16:13:49 2015 -0700 @@ -87,7 +87,7 @@ */ public class JavaCompiler { /** The context key for the compiler. */ - protected static final Context.Key compilerKey = new Context.Key<>(); + public static final Context.Key compilerKey = new Context.Key<>(); /** Get the JavaCompiler instance for this context. */ public static JavaCompiler instance(Context context) { @@ -821,7 +821,7 @@ // as a JavaCompiler can only be used once, throw an exception if // it has been used before. if (hasBeenUsed) - throw new AssertionError("attempt to reuse JavaCompiler"); + checkReusable(); hasBeenUsed = true; // forcibly set the equivalent of -Xlint:-options, so that no further @@ -898,6 +898,10 @@ } } + protected void checkReusable() { + throw new AssertionError("attempt to reuse JavaCompiler"); + } + /** * Set needRootClasses to true, in JavaCompiler subclass constructor * that want to collect public apis of classes supplied on the command line. diff -r f0e149d3e375 -r ead8b7192f00 src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu Sep 03 14:24:46 2015 -0700 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu Sep 03 16:13:49 2015 -0700 @@ -26,6 +26,7 @@ package com.sun.tools.javac.parser; import java.util.*; +import java.util.stream.Collectors; import com.sun.source.tree.MemberReferenceTree.ReferenceMode; @@ -510,7 +511,7 @@ if (mods != 0) { long lowestMod = mods & -mods; error(token.pos, "mod.not.allowed.here", - Flags.asFlagSet(lowestMod)); + Flags.asFlagSet(lowestMod)); } } @@ -946,10 +947,7 @@ t = odStack[0]; if (t.hasTag(JCTree.Tag.PLUS)) { - StringBuilder buf = foldStrings(t); - if (buf != null) { - t = toP(F.at(startPos).Literal(TypeTag.CLASS, buf.toString())); - } + t = foldStrings(t); } odStackSupply.add(odStack); @@ -973,37 +971,76 @@ /** If tree is a concatenation of string literals, replace it * by a single literal representing the concatenated string. */ - protected StringBuilder foldStrings(JCTree tree) { + protected JCExpression foldStrings(JCExpression tree) { if (!allowStringFolding) return null; - List buf = List.nil(); + ListBuffer opStack = new ListBuffer<>(); + ListBuffer litBuf = new ListBuffer<>(); + boolean needsFolding = false; + JCExpression curr = tree; while (true) { - if (tree.hasTag(LITERAL)) { - JCLiteral lit = (JCLiteral) tree; - if (lit.typetag == TypeTag.CLASS) { - StringBuilder sbuf = - new StringBuilder((String)lit.value); - while (buf.nonEmpty()) { - sbuf.append(buf.head); - buf = buf.tail; - } - return sbuf; - } - } else if (tree.hasTag(JCTree.Tag.PLUS)) { - JCBinary op = (JCBinary)tree; - if (op.rhs.hasTag(LITERAL)) { - JCLiteral lit = (JCLiteral) op.rhs; - if (lit.typetag == TypeTag.CLASS) { - buf = buf.prepend((String) lit.value); - tree = op.lhs; - continue; - } - } + if (curr.hasTag(JCTree.Tag.PLUS)) { + JCBinary op = (JCBinary)curr; + needsFolding |= foldIfNeeded(op.rhs, litBuf, opStack, false); + curr = op.lhs; + } else { + needsFolding |= foldIfNeeded(curr, litBuf, opStack, true); + break; //last one! } - return null; + } + if (needsFolding) { + List ops = opStack.toList(); + JCExpression res = ops.head; + for (JCExpression op : ops.tail) { + res = F.at(op.getStartPosition()).Binary(optag(TokenKind.PLUS), res, op); + storeEnd(res, getEndPos(op)); + } + return res; + } else { + return tree; } } + private boolean foldIfNeeded(JCExpression tree, ListBuffer litBuf, + ListBuffer opStack, boolean last) { + JCLiteral str = stringLiteral(tree); + if (str != null) { + litBuf.prepend(str); + return last && merge(litBuf, opStack); + } else { + boolean res = merge(litBuf, opStack); + litBuf.clear(); + opStack.prepend(tree); + return res; + } + } + + boolean merge(ListBuffer litBuf, ListBuffer opStack) { + if (litBuf.isEmpty()) { + return false; + } else if (litBuf.size() == 1) { + opStack.prepend(litBuf.first()); + return false; + } else { + JCExpression t = F.at(litBuf.first().getStartPosition()).Literal(TypeTag.CLASS, + litBuf.stream().map(lit -> (String)lit.getValue()).collect(Collectors.joining())); + storeEnd(t, litBuf.last().getEndPosition(endPosTable)); + opStack.prepend(t); + return true; + } + } + + private JCLiteral stringLiteral(JCTree tree) { + if (tree.hasTag(LITERAL)) { + JCLiteral lit = (JCLiteral)tree; + if (lit.typetag == TypeTag.CLASS) { + return lit; + } + } + return null; + } + + /** optimization: To save allocating a new operand/operator stack * for every binary operation, we use supplys. */ diff -r f0e149d3e375 -r ead8b7192f00 src/jdk.compiler/share/classes/com/sun/tools/javac/util/Context.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Context.java Thu Sep 03 14:24:46 2015 -0700 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Context.java Thu Sep 03 16:13:49 2015 -0700 @@ -119,7 +119,7 @@ * or * {@literal Key -> Factory } */ - private final Map,Object> ht = new HashMap<>(); + protected final Map,Object> ht = new HashMap<>(); /** Set the factory for the key in this context. */ public void put(Key key, Factory fac) { @@ -173,7 +173,7 @@ */ private final Map, Key> kt = new HashMap<>(); - private Key key(Class clss) { + protected Key key(Class clss) { checkState(kt); Key k = uncheckedCast(kt.get(clss)); if (k == null) { diff -r f0e149d3e375 -r ead8b7192f00 src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java Thu Sep 03 14:24:46 2015 -0700 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java Thu Sep 03 16:13:49 2015 -0700 @@ -334,7 +334,7 @@ * error message more than once. For each error, a pair consisting of the * source file name and source code position of the error is added to the set. */ - private Set> recorded = new HashSet<>(); + protected Set> recorded = new HashSet<>(); public boolean hasDiagnosticListener() { return diagListener != null; diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/Diagnostics/6769027/T6769027.java --- a/test/tools/javac/Diagnostics/6769027/T6769027.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/Diagnostics/6769027/T6769027.java Thu Sep 03 16:13:49 2015 -0700 @@ -25,26 +25,19 @@ * @test * @bug 6769027 8006694 * @summary Source line should be displayed immediately after the first diagnostic line - * temporarily workaround combo tests are causing time out in several platforms - * @author Maurizio Cimadamore - * @library ../../lib * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.util - * @build JavacTestingAbstractThreadedTest * @run main/othervm T6769027 */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 +// use /othervm to avoid locale issues import java.net.URI; import java.util.regex.Matcher; import javax.tools.*; import com.sun.tools.javac.util.*; -public class T6769027 - extends JavacTestingAbstractThreadedTest - implements Runnable { +public class T6769027 { enum OutputKind { RAW("rawDiagnostics","rawDiagnostics"), @@ -324,11 +317,6 @@ } @Override - protected java.io.PrintWriter getWriterForDiagnosticType(JCDiagnostic.DiagnosticType dt) { - return outWriter; - } - - @Override protected boolean shouldReport(JavaFileObject jfo, int pos) { return true; } @@ -368,7 +356,6 @@ this.subdiagsIndent = subdiagsIndent; } - @Override public void run() { Context ctx = new Context(); Options options = Options.instance(ctx); @@ -419,7 +406,7 @@ for (IndentKind detailsIndent : IndentKind.values()) { for (IndentKind sourceIndent : IndentKind.values()) { for (IndentKind subdiagsIndent : IndentKind.values()) { - pool.execute(new T6769027(outputKind, + new T6769027(outputKind, errKind, multiKind, multiPolicy, @@ -431,7 +418,7 @@ summaryIndent, detailsIndent, sourceIndent, - subdiagsIndent)); + subdiagsIndent).run(); } } } @@ -445,8 +432,6 @@ } } } - - checkAfterExec(false); } void printInfo(String msg, String errorLine) { @@ -457,11 +442,11 @@ " caret=" + caretKind + " sourcePosition=" + sourceLineKind + " summaryIndent=" + summaryIndent + " detailsIndent=" + detailsIndent + " sourceIndent=" + sourceIndent + " subdiagsIndent=" + subdiagsIndent; - errWriter.println(sep); - errWriter.println(desc); - errWriter.println(sep); - errWriter.println(msg); - errWriter.println("Diagnostic formatting problem - expected diagnostic...\n" + errorLine); + System.err.println(sep); + System.err.println(desc); + System.err.println(sep); + System.err.println(msg); + System.err.println("Diagnostic formatting problem - expected diagnostic...\n" + errorLine); } void checkOutput(String msg) { @@ -494,8 +479,8 @@ } if (!msg.equals(errorLine)) { -// printInfo(msg, errorLine); - errCount.incrementAndGet(); + printInfo(msg, errorLine); + throw new AssertionError("errors were found"); } } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/T7093325.java --- a/test/tools/javac/T7093325.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/T7093325.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,38 +23,41 @@ /* * @test - * @bug 7093325 8006694 + * @bug 7093325 8006694 8129962 * @summary Redundant entry in bytecode exception table * temporarily workaround combo tests are causing time out in several platforms - * @library lib + * @library /tools/javac/lib * @modules jdk.jdeps/com.sun.tools.classfile - * @build JavacTestingAbstractThreadedTest - * @run main/othervm T7093325 + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + * @run main T7093325 */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 +import java.io.IOException; +import java.io.InputStream; -import java.io.File; -import java.net.URI; -import java.util.Arrays; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import javax.tools.ToolProvider; - -import com.sun.source.util.JavacTask; import com.sun.tools.classfile.Attribute; import com.sun.tools.classfile.ClassFile; import com.sun.tools.classfile.Code_attribute; -import com.sun.tools.classfile.ConstantPool.*; +import com.sun.tools.classfile.ConstantPoolException; import com.sun.tools.classfile.Method; -public class T7093325 - extends JavacTestingAbstractThreadedTest - implements Runnable { +import javax.tools.JavaFileObject; - enum StatementKind { +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; + +public class T7093325 extends ComboInstance { + + enum StatementKind implements ComboParameter { + NONE(null, false, false), THROW("throw new RuntimeException();", false, false), RETURN_NONEMPTY("System.out.println(); return;", true, false), RETURN_EMPTY("return;", true, true), @@ -64,107 +67,79 @@ boolean canInline; boolean empty; - private StatementKind(String stmt, boolean canInline, boolean empty) { + StatementKind(String stmt, boolean canInline, boolean empty) { this.stmt = stmt; this.canInline = canInline; this.empty = empty; } + + @Override + public String expand(String optParameter) { + return stmt; + } } - enum CatchArity { + enum CatchArity implements ComboParameter { NONE(""), - ONE("catch (A a) { #S1 }"), - TWO("catch (B b) { #S2 }"), - THREE("catch (C c) { #S3 }"), - FOUR("catch (D d) { #S4 }"); + ONE("catch (A a) { #{STMT[1]} }"), + TWO("catch (B b) { #{STMT[2]} }"), + THREE("catch (C c) { #{STMT[3]} }"), + FOUR("catch (D d) { #{STMT[4]} }"); String catchStr; - private CatchArity(String catchStr) { + CatchArity(String catchStr) { this.catchStr = catchStr; } - String catchers() { + @Override + public String expand(String optParameter) { if (this.ordinal() == 0) { return catchStr; } else { - return CatchArity.values()[this.ordinal() - 1].catchers() + + return CatchArity.values()[this.ordinal() - 1].expand(optParameter) + catchStr; } } } public static void main(String... args) throws Exception { - for (CatchArity ca : CatchArity.values()) { - for (StatementKind stmt0 : StatementKind.values()) { - if (ca.ordinal() == 0) { - pool.execute(new T7093325(ca, stmt0)); - continue; - } - for (StatementKind stmt1 : StatementKind.values()) { - if (ca.ordinal() == 1) { - pool.execute(new T7093325(ca, stmt0, stmt1)); - continue; - } - for (StatementKind stmt2 : StatementKind.values()) { - if (ca.ordinal() == 2) { - pool.execute(new T7093325(ca, stmt0, stmt1, stmt2)); - continue; - } - for (StatementKind stmt3 : StatementKind.values()) { - if (ca.ordinal() == 3) { - pool.execute( - new T7093325(ca, stmt0, stmt1, stmt2, stmt3)); - continue; - } - for (StatementKind stmt4 : StatementKind.values()) { - if (ca.ordinal() == 4) { - pool.execute( - new T7093325(ca, stmt0, stmt1, - stmt2, stmt3, stmt4)); - continue; - } - for (StatementKind stmt5 : StatementKind.values()) { - pool.execute( - new T7093325(ca, stmt0, stmt1, stmt2, - stmt3, stmt4, stmt5)); - } - } - } - } - } - } - } - - checkAfterExec(); + new ComboTestHelper() + .withFilter(T7093325::testFilter) + .withDimension("CATCH", (x, ca) -> x.ca = ca, CatchArity.values()) + .withArrayDimension("STMT", (x, stmt, idx) -> x.stmts[idx] = stmt, 5, StatementKind.values()) + .run(T7093325::new); } /** instance decls **/ CatchArity ca; - StatementKind[] stmts; + StatementKind[] stmts = new StatementKind[5]; - public T7093325(CatchArity ca, StatementKind... stmts) { - this.ca = ca; - this.stmts = stmts; + boolean testFilter() { + int lastPos = ca.ordinal() + 1; + for (int i = 0; i < stmts.length ; i++) { + boolean shouldBeSet = i < lastPos; + boolean isSet = stmts[i] != StatementKind.NONE; + if (shouldBeSet != isSet) { + return false; + } + } + return true; } @Override - public void run() { - int id = checkCount.incrementAndGet(); - final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); - JavaSource source = new JavaSource(id); - JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), null, - null, null, Arrays.asList(source)); - ct.call(); - verifyBytecode(source, id); + public void doWork() throws IOException { + verifyBytecode(newCompilationTask() + .withSourceFromTemplate(source_template) + .generate()); } - void verifyBytecode(JavaSource source, int id) { + void verifyBytecode(Result> result) { boolean lastInlined = false; boolean hasCode = false; int gapsCount = 0; - for (int i = 0; i < stmts.length ; i++) { + for (int i = 0; i < ca.ordinal() + 1 ; i++) { lastInlined = stmts[i].canInline; hasCode = hasCode || !stmts[i].empty; if (lastInlined && hasCode) { @@ -176,12 +151,11 @@ gapsCount++; } - File compiledTest = new File(String.format("Test%s.class", id)); - try { - ClassFile cf = ClassFile.read(compiledTest); + try (InputStream is = result.get().iterator().next().openInputStream()) { + ClassFile cf = ClassFile.read(is); if (cf == null) { - throw new Error("Classfile not found: " + - compiledTest.getName()); + fail("Classfile not found: " + result.compilationInfo()); + return; } Method test_method = null; @@ -193,7 +167,8 @@ } if (test_method == null) { - throw new Error("Method test() not found in class Test"); + fail("Method test() not found in class Test" + result.compilationInfo()); + return; } Code_attribute code = null; @@ -205,7 +180,8 @@ } if (code == null) { - throw new Error("Code attribute not found in method test()"); + fail("Code attribute not found in method test()"); + return; } int actualGapsCount = 0; @@ -217,54 +193,28 @@ } if (actualGapsCount != gapsCount) { - throw new Error("Bad exception table for test()\n" + + fail("Bad exception table for test()\n" + "expected gaps: " + gapsCount + "\n" + "found gaps: " + actualGapsCount + "\n" + - source); + result.compilationInfo()); + return; } - } catch (Exception e) { + } catch (IOException | ConstantPoolException e) { e.printStackTrace(); - throw new Error("error reading " + compiledTest +": " + e); + fail("error reading classfile: " + e); } } - class JavaSource extends SimpleJavaFileObject { - - static final String source_template = + static final String source_template = + "class Test {\n" + + " void test() {\n" + + " try { #{STMT[0]} } #{CATCH} finally { System.out.println(); }\n" + + " }\n" + + "}\n" + "class A extends RuntimeException {} \n" + "class B extends RuntimeException {} \n" + "class C extends RuntimeException {} \n" + "class D extends RuntimeException {} \n" + - "class E extends RuntimeException {} \n" + - "class Test#ID {\n" + - " void test() {\n" + - " try { #S0 } #C finally { System.out.println(); }\n" + - " }\n" + - "}"; - - String source; - - public JavaSource(int id) { - super(URI.create(String.format("myfo:/Test%s.java", id)), - JavaFileObject.Kind.SOURCE); - source = source_template.replace("#C", ca.catchers()); - source = source.replace("#S0", stmts[0].stmt); - source = source.replace("#ID", String.valueOf(id)); - for (int i = 1; i < ca.ordinal() + 1; i++) { - source = source.replace("#S" + i, stmts[i].stmt); - } - } - - @Override - public String toString() { - return source; - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; - } - } - + "class E extends RuntimeException {}"; } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/TestBootstrapMethodsCount.java --- a/test/tools/javac/TestBootstrapMethodsCount.java Thu Sep 03 14:24:46 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,236 +0,0 @@ -/* - * Copyright (c) 2012, 2015, 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 8129547 - * @summary Excess entries in BootstrapMethods with the same (bsm, bsmKind, bsmStaticArgs), but different dynamicArgs - * @library lib - * @modules jdk.jdeps/com.sun.tools.classfile - * jdk.compiler/com.sun.tools.javac.api - * jdk.compiler/com.sun.tools.javac.code - * jdk.compiler/com.sun.tools.javac.jvm - * jdk.compiler/com.sun.tools.javac.tree - * jdk.compiler/com.sun.tools.javac.util - * @build JavacTestingAbstractThreadedTest - * @run main/othervm TestBootstrapMethodsCount - */ - -import java.io.File; -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Locale; - -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; - -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.util.TaskEvent; -import com.sun.source.util.TaskListener; -import com.sun.source.util.TreeScanner; - -import com.sun.tools.classfile.Attribute; -import com.sun.tools.classfile.BootstrapMethods_attribute; -import com.sun.tools.classfile.ClassFile; - -import com.sun.tools.javac.api.JavacTaskImpl; -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.Symbol.MethodSymbol; -import com.sun.tools.javac.code.Symtab; -import com.sun.tools.javac.code.Types; -import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; -import com.sun.tools.javac.tree.JCTree.JCMethodDecl; -import com.sun.tools.javac.tree.JCTree.JCIdent; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.Names; - -import static com.sun.tools.javac.jvm.ClassFile.*; - -public class TestBootstrapMethodsCount - extends JavacTestingAbstractThreadedTest - implements Runnable { - - - public static void main(String... args) throws Exception { - pool.execute(new TestBootstrapMethodsCount()); - checkAfterExec(); - } - - DiagChecker dc; - - TestBootstrapMethodsCount() { - dc = new DiagChecker(); - } - - public void run() { - int id = checkCount.incrementAndGet(); - JavaSource source = new JavaSource(id); - JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, fm.get(), dc, - Arrays.asList("-g"), null, Arrays.asList(source)); - Context context = ct.getContext(); - Symtab syms = Symtab.instance(context); - Names names = Names.instance(context); - Types types = Types.instance(context); - ct.addTaskListener(new Indifier(syms, names, types)); - try { - ct.generate(); - } catch (Throwable t) { - t.printStackTrace(); - throw new AssertionError( - String.format("Error thrown when compiling following code\n%s", - source.source)); - } - if (dc.diagFound) { - throw new AssertionError( - String.format("Diags found when compiling following code\n%s\n\n%s", - source.source, dc.printDiags())); - } - verifyBytecode(id); - } - - void verifyBytecode(int id) { - File compiledTest = new File(String.format("Test%d.class", id)); - try { - ClassFile cf = ClassFile.read(compiledTest); - BootstrapMethods_attribute bsm_attr = - (BootstrapMethods_attribute)cf - .getAttribute(Attribute.BootstrapMethods); - int length = bsm_attr.bootstrap_method_specifiers.length; - if (length != 1) { - throw new Error("Bad number of method specifiers " + - "in BootstrapMethods attribute: " + length); - } - } catch (Exception e) { - e.printStackTrace(); - throw new Error("error reading " + compiledTest +": " + e); - } - } - - class JavaSource extends SimpleJavaFileObject { - - static final String source_template = "import java.lang.invoke.*;\n" + - "class Bootstrap {\n" + - " public static CallSite bsm(MethodHandles.Lookup lookup, " + - "String name, MethodType methodType) {\n" + - " return null;\n" + - " }\n" + - "}\n" + - "class Test#ID {\n" + - " void m1() { }\n" + - " void m2(Object arg1) { }\n" + - " void test1() {\n" + - " Object o = this; // marker statement \n" + - " m1();\n" + - " }\n" + - " void test2(Object arg1) {\n" + - " Object o = this; // marker statement \n" + - " m2(arg1);\n" + - " }\n" + - "}"; - - String source; - - JavaSource(int id) { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - source = source_template.replace("#ID", String.valueOf(id)); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; - } - } - - class Indifier extends TreeScanner implements TaskListener { - - MethodSymbol bsm; - Symtab syms; - Names names; - Types types; - - Indifier(Symtab syms, Names names, Types types) { - this.syms = syms; - this.names = names; - this.types = types; - } - - @Override - public void started(TaskEvent e) { - //do nothing - } - - @Override - public void finished(TaskEvent e) { - if (e.getKind() == TaskEvent.Kind.ANALYZE) { - scan(e.getCompilationUnit(), null); - } - } - - @Override - public Void visitMethodInvocation(MethodInvocationTree node, Void p) { - super.visitMethodInvocation(node, p); - JCMethodInvocation apply = (JCMethodInvocation)node; - JCIdent ident = (JCIdent)apply.meth; - Symbol oldSym = ident.sym; - if (!oldSym.isConstructor()) { - ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name, - oldSym.owner, REF_invokeStatic, bsm, oldSym.type, new Object[0]); - } - return null; - } - - @Override - public Void visitMethod(MethodTree node, Void p) { - super.visitMethod(node, p); - if (node.getName().toString().equals("bsm")) { - bsm = ((JCMethodDecl)node).sym; - } - return null; - } - } - - static class DiagChecker - implements javax.tools.DiagnosticListener { - - boolean diagFound; - ArrayList diags = new ArrayList<>(); - - public void report(Diagnostic diagnostic) { - diags.add(diagnostic.getMessage(Locale.getDefault())); - diagFound = true; - } - - String printDiags() { - StringBuilder buf = new StringBuilder(); - for (String s : diags) { - buf.append(s); - buf.append("\n"); - } - return buf.toString(); - } - } - -} diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/cast/intersection/IntersectionTypeCastTest.java --- a/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,53 +23,47 @@ /* * @test - * @bug 8002099 8006694 + * @bug 8002099 8006694 8129962 * @summary Add support for intersection types in cast expression * temporarily workaround combo tests are causing time out in several platforms - * @library ../../lib - * @modules jdk.compiler/com.sun.tools.javac.util - * @build JavacTestingAbstractThreadedTest - * @run main/othervm/timeout=360 IntersectionTypeCastTest + * @library /tools/javac/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + + * @run main IntersectionTypeCastTest */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 +import com.sun.tools.javac.util.List; -import java.net.URI; -import java.util.Arrays; -import javax.tools.Diagnostic; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import javax.tools.ToolProvider; +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; -import com.sun.source.util.JavacTask; -import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.ListBuffer; +import java.io.IOException; -public class IntersectionTypeCastTest - extends JavacTestingAbstractThreadedTest - implements Runnable { +public class IntersectionTypeCastTest extends ComboInstance { - interface Type { + interface Type extends ComboParameter { boolean subtypeOf(Type that); - String asString(); boolean isClass(); boolean isInterface(); } enum InterfaceKind implements Type { - A("interface A { }\n", "A", null), - B("interface B { }\n", "B", null), - C("interface C extends A { }\n", "C", A); + A("A", null), + B("B", null), + C("C", A); - String declStr; String typeStr; InterfaceKind superInterface; - InterfaceKind(String declStr, String typeStr, - InterfaceKind superInterface) { - this.declStr = declStr; + InterfaceKind(String typeStr, InterfaceKind superInterface) { this.typeStr = typeStr; this.superInterface = superInterface; } @@ -81,11 +75,6 @@ } @Override - public String asString() { - return typeStr; - } - - @Override public boolean isClass() { return false; } @@ -94,42 +83,31 @@ public boolean isInterface() { return true; } + + @Override + public String expand(String optParameter) { + return typeStr; + } } enum ClassKind implements Type { - OBJECT(null, "Object"), - CA("#M class CA implements A { }\n", "CA", - InterfaceKind.A), - CB("#M class CB implements B { }\n", "CB", - InterfaceKind.B), - CAB("#M class CAB implements A, B { }\n", "CAB", - InterfaceKind.A, InterfaceKind.B), - CC("#M class CC implements C { }\n", "CC", - InterfaceKind.C, InterfaceKind.A), - CCA("#M class CCA implements C, A { }\n", "CCA", - InterfaceKind.C, InterfaceKind.A), - CCB("#M class CCB implements C, B { }\n", "CCB", - InterfaceKind.C, InterfaceKind.A, InterfaceKind.B), - CCAB("#M class CCAB implements C, A, B { }\n", "CCAB", - InterfaceKind.C, InterfaceKind.A, InterfaceKind.B); + OBJECT("Object"), + CA("CA", InterfaceKind.A), + CB("CB", InterfaceKind.B), + CAB("CAB", InterfaceKind.A, InterfaceKind.B), + CC("CC", InterfaceKind.C, InterfaceKind.A), + CCA("CCA", InterfaceKind.C, InterfaceKind.A), + CCB("CCB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B), + CCAB("CCAB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B); - String declTemplate; String typeStr; List superInterfaces; - ClassKind(String declTemplate, String typeStr, - InterfaceKind... superInterfaces) { - this.declTemplate = declTemplate; + ClassKind(String typeStr, InterfaceKind... superInterfaces) { this.typeStr = typeStr; this.superInterfaces = List.from(superInterfaces); } - String getDecl(ModifierKind mod) { - return declTemplate != null ? - declTemplate.replaceAll("#M", mod.modStr) : - ""; - } - @Override public boolean subtypeOf(Type that) { return this == that || superInterfaces.contains(that) || @@ -137,11 +115,6 @@ } @Override - public String asString() { - return typeStr; - } - - @Override public boolean isClass() { return true; } @@ -150,9 +123,14 @@ public boolean isInterface() { return false; } + + @Override + public String expand(String optParameter) { + return typeStr; + } } - enum ModifierKind { + enum ModifierKind implements ComboParameter { NONE(""), FINAL("final"); @@ -161,14 +139,18 @@ ModifierKind(String modStr) { this.modStr = modStr; } + + @Override + public String expand(String optParameter) { + return modStr; + } } - enum CastKind { - CLASS("(#C)", 0), - INTERFACE("(#I0)", 1), - INTERSECTION2("(#C & #I0)", 1), - INTERSECTION3("(#C & #I0 & #I1)", 2); - //INTERSECTION4("(#C & #I0 & #I1 & #I2)", 3); + enum CastKind implements ComboParameter { + CLASS("(#{CLAZZ#IDX})", 0), + INTERFACE("(#{INTF1#IDX})", 1), + INTERSECTION2("(#{CLAZZ#IDX} & #{INTF1#IDX})", 1), + INTERSECTION3("(#{CLAZZ#IDX} & #{INTF1#IDX} & #{INTF2#IDX})", 2); String castTemplate; int interfaceBounds; @@ -177,6 +159,11 @@ this.castTemplate = castTemplate; this.interfaceBounds = interfaceBounds; } + + @Override + public String expand(String optParameter) { + return castTemplate.replaceAll("#IDX", optParameter); + } } static class CastInfo { @@ -188,19 +175,9 @@ this.types = types; } - String getCast() { - String temp = kind.castTemplate.replaceAll("#C", - types[0].asString()); - for (int i = 0; i < kind.interfaceBounds ; i++) { - temp = temp.replace(String.format("#I%d", i), - types[i + 1].asString()); - } - return temp; - } - boolean hasDuplicateTypes() { - for (int i = 0 ; i < types.length ; i++) { - for (int j = 0 ; j < types.length ; j++) { + for (int i = 0 ; i < arity() ; i++) { + for (int j = 0 ; j < arity() ; j++) { if (i != j && types[i] == types[j]) { return true; } @@ -210,8 +187,10 @@ } boolean compatibleWith(ModifierKind mod, CastInfo that) { - for (Type t1 : types) { - for (Type t2 : that.types) { + for (int i = 0 ; i < arity() ; i++) { + Type t1 = types[i]; + for (int j = 0 ; j < that.arity() ; j++) { + Type t2 = that.types[j]; boolean compat = t1.subtypeOf(t2) || t2.subtypeOf(t1) || @@ -223,138 +202,92 @@ } return true; } + + private int arity() { + return kind.interfaceBounds + 1; + } } public static void main(String... args) throws Exception { - for (ModifierKind mod : ModifierKind.values()) { - for (CastInfo cast1 : allCastInfo()) { - for (CastInfo cast2 : allCastInfo()) { - pool.execute( - new IntersectionTypeCastTest(mod, cast1, cast2)); + new ComboTestHelper() + .withFilter(IntersectionTypeCastTest::isRedundantCast) + .withFilter(IntersectionTypeCastTest::arityFilter) + .withArrayDimension("CAST", (x, ck, idx) -> x.castKinds[idx] = ck, 2, CastKind.values()) + .withDimension("CLAZZ1", (x, ty) -> x.types1[0] = ty, ClassKind.values()) + .withDimension("INTF11", (x, ty) -> x.types1[1] = ty, InterfaceKind.values()) + .withDimension("INTF21", (x, ty) -> x.types1[2] = ty, InterfaceKind.values()) + .withDimension("CLAZZ2", (x, ty) -> x.types2[0] = ty, ClassKind.values()) + .withDimension("INTF12", (x, ty) -> x.types2[1] = ty, InterfaceKind.values()) + .withDimension("INTF22", (x, ty) -> x.types2[2] = ty, InterfaceKind.values()) + .withDimension("MOD", (x, mod) -> x.mod = mod, ModifierKind.values()) + .run(IntersectionTypeCastTest::new); + } + + boolean isRedundantCast() { + for (int i = 0 ; i < 2 ; i++) { + Type[] types = i == 0 ? types1 : types2; + if (castKinds[i] == CastKind.INTERFACE && types[0] != ClassKind.OBJECT) { + return false; + } + } + return true; + } + + boolean arityFilter() { + for (int i = 0 ; i < 2 ; i++) { + int lastPos = castKinds[i].interfaceBounds + 1; + Type[] types = i == 0 ? types1 : types2; + for (int j = 1; j < types.length; j++) { + boolean shouldBeSet = j < lastPos; + if (!shouldBeSet && (types[j] != InterfaceKind.A)) { + return false; } } } - checkAfterExec(); - } - - static List allCastInfo() { - ListBuffer buf = new ListBuffer<>(); - for (CastKind kind : CastKind.values()) { - for (ClassKind clazz : ClassKind.values()) { - if (kind == CastKind.INTERFACE && clazz != ClassKind.OBJECT) { - continue; - } else if (kind.interfaceBounds == 0) { - buf.append(new CastInfo(kind, clazz)); - continue; - } else { - for (InterfaceKind intf1 : InterfaceKind.values()) { - if (kind.interfaceBounds == 1) { - buf.append(new CastInfo(kind, clazz, intf1)); - continue; - } else { - for (InterfaceKind intf2 : InterfaceKind.values()) { - if (kind.interfaceBounds == 2) { - buf.append( - new CastInfo(kind, clazz, intf1, intf2)); - continue; - } else { - for (InterfaceKind intf3 : InterfaceKind.values()) { - buf.append( - new CastInfo(kind, clazz, intf1, - intf2, intf3)); - continue; - } - } - } - } - } - } - } - } - return buf.toList(); + return true; } ModifierKind mod; - CastInfo cast1, cast2; - JavaSource source; - DiagnosticChecker diagChecker; - - IntersectionTypeCastTest(ModifierKind mod, CastInfo cast1, CastInfo cast2) { - this.mod = mod; - this.cast1 = cast1; - this.cast2 = cast2; - this.source = new JavaSource(); - this.diagChecker = new DiagnosticChecker(); - } + CastKind[] castKinds = new CastKind[2]; + Type[] types1 = new Type[3]; + Type[] types2 = new Type[3]; @Override - public void run() { - final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); - - JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker, - null, null, Arrays.asList(source)); - try { - ct.analyze(); - } catch (Throwable ex) { - throw new AssertionError("Error thrown when compiling the following code:\n" + - source.getCharContent(true)); - } - check(); + public void doWork() throws IOException { + check(newCompilationTask() + .withSourceFromTemplate(bodyTemplate) + .analyze()); } - class JavaSource extends SimpleJavaFileObject { - - String bodyTemplate = "class Test {\n" + - " void test() {\n" + - " Object o = #C1#C2null;\n" + - " } }"; - - String source = ""; + String bodyTemplate = "class Test {\n" + + " void test() {\n" + + " Object o = #{CAST[0].1}#{CAST[1].2}null;\n" + + " } }\n" + + "interface A { }\n" + + "interface B { }\n" + + "interface C extends A { }\n" + + "#{MOD} class CA implements A { }\n" + + "#{MOD} class CB implements B { }\n" + + "#{MOD} class CAB implements A, B { }\n" + + "#{MOD} class CC implements C { }\n" + + "#{MOD} class CCA implements C, A { }\n" + + "#{MOD} class CCB implements C, B { }\n" + + "#{MOD} class CCAB implements C, A, B { }"; - public JavaSource() { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - for (ClassKind ck : ClassKind.values()) { - source += ck.getDecl(mod); - } - for (InterfaceKind ik : InterfaceKind.values()) { - source += ik.declStr; - } - source += bodyTemplate.replaceAll("#C1", cast1.getCast()). - replaceAll("#C2", cast2.getCast()); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; - } - } - - void check() { - checkCount.incrementAndGet(); - + void check(Result res) { + CastInfo cast1 = new CastInfo(castKinds[0], types1); + CastInfo cast2 = new CastInfo(castKinds[1], types2); boolean errorExpected = cast1.hasDuplicateTypes() || cast2.hasDuplicateTypes(); errorExpected |= !cast2.compatibleWith(mod, cast1); - if (errorExpected != diagChecker.errorFound) { - throw new Error("invalid diagnostics for source:\n" + - source.getCharContent(true) + - "\nFound error: " + diagChecker.errorFound + + boolean errorsFound = res.hasErrors(); + if (errorExpected != errorsFound) { + fail("invalid diagnostics for source:\n" + + res.compilationInfo() + + "\nFound error: " + errorsFound + "\nExpected error: " + errorExpected); } } - - static class DiagnosticChecker - implements javax.tools.DiagnosticListener { - - boolean errorFound; - - public void report(Diagnostic diagnostic) { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { - errorFound = true; - } - } - } - } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java --- a/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,40 +23,41 @@ /* * @test - * @bug 8005166 + * @bug 8005166 8129962 * @summary Add support for static interface methods * Smoke test for static interface method hiding - * @modules jdk.compiler - * @run main/timeout=600 InterfaceMethodHidingTest + * @library /tools/javac/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + * @run main InterfaceMethodHidingTest */ -import com.sun.source.util.JavacTask; -import java.net.URI; -import java.util.Arrays; -import javax.tools.Diagnostic; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import javax.tools.StandardJavaFileManager; -import javax.tools.ToolProvider; +import java.io.IOException; + +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; - -public class InterfaceMethodHidingTest { - - static int checkCount = 0; +public class InterfaceMethodHidingTest extends ComboInstance { - enum SignatureKind { - VOID_INTEGER("void m(Integer s)", "return;"), - STRING_INTEGER("String m(Integer s)", "return null;"), - VOID_STRING("void m(String s)", "return;"), - STRING_STRING("String m(String s)", "return null;"); + enum SignatureKind implements ComboParameter { + VOID_INTEGER("void m(Integer s)", false), + STRING_INTEGER("String m(Integer s)", true), + VOID_STRING("void m(String s)", false), + STRING_STRING("String m(String s)", true); String sigStr; - String retStr; + boolean needsReturn; - SignatureKind(String sigStr, String retStr) { + SignatureKind(String sigStr, boolean needsReturn) { this.sigStr = sigStr; - this.retStr = retStr; + this.needsReturn = needsReturn; } boolean overrideEquivalentWith(SignatureKind s2) { @@ -71,18 +72,21 @@ throw new AssertionError("bad signature kind"); } } + + @Override + public String expand(String optParameter) { + return sigStr; + } } - enum MethodKind { - VIRTUAL("", "#M #S;"), - STATIC("static", "#M #S { #BE; #R }"), - DEFAULT("default", "#M #S { #BE; #R }"); + enum MethodKind implements ComboParameter { + VIRTUAL("#{SIG[#IDX]};"), + STATIC("static #{SIG[#IDX]} { #{BODY[#IDX]}; #{RET.#IDX} }"), + DEFAULT("default #{SIG[#IDX]} { #{BODY[#IDX]}; #{RET.#IDX} }"); - String modStr; String methTemplate; - MethodKind(String modStr, String methTemplate) { - this.modStr = modStr; + MethodKind(String methTemplate) { this.methTemplate = methTemplate; } @@ -96,15 +100,13 @@ mk1 != STATIC; } - String getBody(BodyExpr be, SignatureKind sk) { - return methTemplate.replaceAll("#BE", be.bodyExprStr) - .replaceAll("#R", sk.retStr) - .replaceAll("#M", modStr) - .replaceAll("#S", sk.sigStr); + @Override + public String expand(String optParameter) { + return methTemplate.replaceAll("#IDX", optParameter); } } - enum BodyExpr { + enum BodyExpr implements ComboParameter { NONE(""), THIS("Object o = this"); @@ -118,129 +120,78 @@ return this == NONE || mk != MethodKind.STATIC; } + + @Override + public String expand(String optParameter) { + return bodyExprStr; + } } public static void main(String... args) throws Exception { - - //create default shared JavaCompiler - reused across multiple compilations - JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); - try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) { - - for (MethodKind mk1 : MethodKind.values()) { - for (SignatureKind sk1 : SignatureKind.values()) { - for (BodyExpr be1 : BodyExpr.values()) { - for (MethodKind mk2 : MethodKind.values()) { - for (SignatureKind sk2 : SignatureKind.values()) { - for (BodyExpr be2 : BodyExpr.values()) { - for (MethodKind mk3 : MethodKind.values()) { - for (SignatureKind sk3 : SignatureKind.values()) { - for (BodyExpr be3 : BodyExpr.values()) { - new InterfaceMethodHidingTest(mk1, mk2, mk3, sk1, sk2, sk3, be1, be2, be3).run(comp, fm); - } - } - } - } - } - } - } - } - } - System.out.println("Total check executed: " + checkCount); - } + new ComboTestHelper() + .withArrayDimension("SIG", (x, sig, idx) -> x.signatureKinds[idx] = sig, 3, SignatureKind.values()) + .withArrayDimension("BODY", (x, body, idx) -> x.bodyExprs[idx] = body, 3, BodyExpr.values()) + .withArrayDimension("MET", (x, meth, idx) -> x.methodKinds[idx] = meth, 3, MethodKind.values()) + .run(InterfaceMethodHidingTest::new); } - MethodKind mk1, mk2, mk3; - SignatureKind sk1, sk2, sk3; - BodyExpr be1, be2, be3; - JavaSource source; - DiagnosticChecker diagChecker; + MethodKind[] methodKinds = new MethodKind[3]; + SignatureKind[] signatureKinds = new SignatureKind[3]; + BodyExpr[] bodyExprs = new BodyExpr[3]; - InterfaceMethodHidingTest(MethodKind mk1, MethodKind mk2, MethodKind mk3, - SignatureKind sk1, SignatureKind sk2, SignatureKind sk3, BodyExpr be1, BodyExpr be2, BodyExpr be3) { - this.mk1 = mk1; - this.mk2 = mk2; - this.mk3 = mk3; - this.sk1 = sk1; - this.sk2 = sk2; - this.sk3 = sk3; - this.be1 = be1; - this.be2 = be2; - this.be3 = be3; - this.source = new JavaSource(); - this.diagChecker = new DiagnosticChecker(); - } - - class JavaSource extends SimpleJavaFileObject { - - String template = "interface Sup {\n" + + String template = "interface Sup {\n" + " default void sup() { }\n" + "}\n" + "interface A extends Sup {\n" + - " #M1\n" + + " #{MET[0].0}\n" + "}\n" + "interface B extends A, Sup {\n" + - " #M2\n" + + " #{MET[1].1}\n" + "}\n" + "interface C extends B, Sup {\n" + - " #M3\n" + + " #{MET[2].2}\n" + "}\n"; - String source; + @Override + public void doWork() throws IOException { + check(newCompilationTask() + .withOption("-XDallowStaticInterfaceMethods") + .withSourceFromTemplate(template, this::returnExpr) + .analyze()); + } - public JavaSource() { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - source = template.replaceAll("#M1", mk1.getBody(be1, sk1)) - .replaceAll("#M2", mk2.getBody(be2, sk2)) - .replaceAll("#M3", mk3.getBody(be3, sk3)); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; + ComboParameter returnExpr(String name) { + switch (name) { + case "RET": + return optParameter -> { + int idx = new Integer(optParameter); + return signatureKinds[idx].needsReturn ? "return null;" : "return;"; + }; + default: + return null; } } - void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { - JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, - Arrays.asList("-XDallowStaticInterfaceMethods"), null, Arrays.asList(source)); - try { - ct.analyze(); - } catch (Throwable ex) { - throw new AssertionError("Error thrown when analyzing the following source:\n" + source.getCharContent(true)); - } - check(); - } + void check(Result res) { + boolean errorExpected = !bodyExprs[0].allowed(methodKinds[0]) || + !bodyExprs[1].allowed(methodKinds[1]) || + !bodyExprs[2].allowed(methodKinds[2]); - void check() { - boolean errorExpected = - !be1.allowed(mk1) || !be2.allowed(mk2) || !be3.allowed(mk3); - - if (mk1.inherithed()) { - errorExpected |= - sk2.overrideEquivalentWith(sk1) && !MethodKind.overrides(mk2, sk2, mk1, sk1) || - sk3.overrideEquivalentWith(sk1) && !MethodKind.overrides(mk3, sk3, mk1, sk1); + if (methodKinds[0].inherithed()) { + errorExpected |= signatureKinds[1].overrideEquivalentWith(signatureKinds[0]) && + !MethodKind.overrides(methodKinds[1], signatureKinds[1], methodKinds[0], signatureKinds[0]) || + signatureKinds[2].overrideEquivalentWith(signatureKinds[0]) && + !MethodKind.overrides(methodKinds[2], signatureKinds[2], methodKinds[0], signatureKinds[0]); } - if (mk2.inherithed()) { - errorExpected |= - sk3.overrideEquivalentWith(sk2) && !MethodKind.overrides(mk3, sk3, mk2, sk2); + if (methodKinds[1].inherithed()) { + errorExpected |= signatureKinds[2].overrideEquivalentWith(signatureKinds[1]) && + !MethodKind.overrides(methodKinds[2], signatureKinds[2], methodKinds[1], signatureKinds[1]); } - checkCount++; - if (diagChecker.errorFound != errorExpected) { - throw new AssertionError("Problem when compiling source:\n" + source.getCharContent(true) + - "\nfound error: " + diagChecker.errorFound); - } - } - - static class DiagnosticChecker implements javax.tools.DiagnosticListener { - - boolean errorFound; - - public void report(Diagnostic diagnostic) { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { - errorFound = true; - } + if (res.hasErrors() != errorExpected) { + fail("Problem when compiling source:\n" + res.compilationInfo() + + "\nfound error: " + res.hasErrors()); } } } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/defaultMethods/super/TestDefaultSuperCall.java --- a/test/tools/javac/defaultMethods/super/TestDefaultSuperCall.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/defaultMethods/super/TestDefaultSuperCall.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,33 +23,32 @@ /* * @test - * @bug 7192246 8006694 + * @bug 7192246 8006694 8129962 * @summary Automatic test for checking correctness of default super/this resolution * temporarily workaround combo tests are causing time out in several platforms - * @library ../../lib - * @modules jdk.compiler - * @build JavacTestingAbstractThreadedTest - * @run main/othervm TestDefaultSuperCall + * @library /tools/javac/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + * @run main TestDefaultSuperCall */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 - -import java.net.URI; -import java.util.Arrays; +import java.io.IOException; import java.util.ArrayList; import java.util.List; -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; - -import com.sun.source.util.JavacTask; -public class TestDefaultSuperCall - extends JavacTestingAbstractThreadedTest - implements Runnable { +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; - enum InterfaceKind { +public class TestDefaultSuperCall extends ComboInstance { + + enum InterfaceKind implements ComboParameter { DEFAULT("interface A extends B { default void m() { } }"), ABSTRACT("interface A extends B { void m(); }"), NONE("interface A extends B { }"); @@ -63,9 +62,14 @@ boolean methodDefined() { return this == DEFAULT; } + + @Override + public String expand(String optParameter) { + return interfaceStr; + } } - enum PruneKind { + enum PruneKind implements ComboParameter { NO_PRUNE("interface C { }"), PRUNE("interface C extends A { }"); @@ -79,15 +83,20 @@ PruneKind(String interfaceStr) { this.interfaceStr = interfaceStr; } + + @Override + public String expand(String optParameter) { + return interfaceStr; + } } - enum QualifierKind { + enum QualifierKind implements ComboParameter { DIRECT_1("C"), DIRECT_2("A"), INDIRECT("B"), UNRELATED("E"), - ENCLOSING_1(null), - ENCLOSING_2(null); + ENCLOSING_1("name0"), + ENCLOSING_2("name1"); String qualifierStr; @@ -95,15 +104,6 @@ this.qualifierStr = qualifierStr; } - String getQualifier(Shape sh) { - switch (this) { - case ENCLOSING_1: return sh.enclosingAt(0); - case ENCLOSING_2: return sh.enclosingAt(1); - default: - return qualifierStr; - } - } - boolean isEnclosing() { return this == ENCLOSING_1 || this == ENCLOSING_2; @@ -119,9 +119,14 @@ return false; } } + + @Override + public String expand(String optParameter) { + return qualifierStr; + } } - enum ExprKind { + enum ExprKind implements ComboParameter { THIS("this"), SUPER("super"); @@ -130,19 +135,24 @@ ExprKind(String exprStr) { this.exprStr = exprStr; } + + @Override + public String expand(String optParameter) { + return exprStr; + } } - enum ElementKind { - INTERFACE("interface #N { #B }", true), - INTERFACE_EXTENDS("interface #N extends A, C { #B }", true), - CLASS("class #N { #B }", false), - CLASS_EXTENDS("abstract class #N implements A, C { #B }", false), - STATIC_CLASS("static class #N { #B }", true), - STATIC_CLASS_EXTENDS("abstract static class #N implements A, C { #B }", true), - ANON_CLASS("new Object() { #B };", false), - METHOD("void test() { #B }", false), - STATIC_METHOD("static void test() { #B }", true), - DEFAULT_METHOD("default void test() { #B }", false); + enum ElementKind implements ComboParameter { + INTERFACE("interface name#CURR { #BODY }", true), + INTERFACE_EXTENDS("interface name#CURR extends A, C { #BODY }", true), + CLASS("class name#CURR { #BODY }", false), + CLASS_EXTENDS("abstract class name#CURR implements A, C { #BODY }", false), + STATIC_CLASS("static class name#CURR { #BODY }", true), + STATIC_CLASS_EXTENDS("abstract static class name#CURR implements A, C { #BODY }", true), + ANON_CLASS("new Object() { #BODY };", false), + METHOD("void test() { #BODY }", false), + STATIC_METHOD("static void test() { #BODY }", true), + DEFAULT_METHOD("default void test() { #BODY }", false); String templateDecl; boolean isStatic; @@ -207,11 +217,21 @@ this == STATIC_CLASS_EXTENDS || this == CLASS_EXTENDS; } + + @Override + public String expand(String optParameter) { + int nextDepth = new Integer(optParameter) + 1; + String replStr = (nextDepth <= 4) ? + String.format("#{ELEM[%d].%d}", nextDepth, nextDepth) : + "#{QUAL}.#{EXPR}.#{METH}();"; + return templateDecl + .replaceAll("#CURR", optParameter) + .replaceAll("#BODY", replStr); + } } static class Shape { - String shapeStr; List enclosingElements; List enclosingNames; List elementsWithMethod; @@ -234,114 +254,73 @@ } else { elementsWithMethod.add(prevName); } - String element = ek.templateDecl.replaceAll("#N", name); - shapeStr = shapeStr == - null ? element : shapeStr.replaceAll("#B", element); prevName = name; } } - - String getShape(QualifierKind qk, ExprKind ek) { - String methName = ek == ExprKind.THIS ? "test" : "m"; - String call = qk.getQualifier(this) + "." + - ek.exprStr + "." + methName + "();"; - return shapeStr.replaceAll("#B", call); - } - - String enclosingAt(int index) { - return index < enclosingNames.size() ? - enclosingNames.get(index) : "BAD"; - } } public static void main(String... args) throws Exception { - for (InterfaceKind ik : InterfaceKind.values()) { - for (PruneKind pk : PruneKind.values()) { - for (ElementKind ek1 : ElementKind.values()) { - if (!ek1.isAllowedTop()) continue; - for (ElementKind ek2 : ElementKind.values()) { - if (!ek2.isAllowedEnclosing(ek1, true)) continue; - for (ElementKind ek3 : ElementKind.values()) { - if (!ek3.isAllowedEnclosing(ek2, false)) continue; - for (ElementKind ek4 : ElementKind.values()) { - if (!ek4.isAllowedEnclosing(ek3, false)) continue; - for (ElementKind ek5 : ElementKind.values()) { - if (!ek5.isAllowedEnclosing(ek4, false) || - ek5.isClassDecl()) continue; - for (QualifierKind qk : QualifierKind.values()) { - for (ExprKind ek : ExprKind.values()) { - pool.execute( - new TestDefaultSuperCall(ik, pk, - new Shape(ek1, ek2, ek3, - ek4, ek5), qk, ek)); - } - } - } - } - } - } - } - } - } - - checkAfterExec(); + new ComboTestHelper() + .withFilter(TestDefaultSuperCall::filterBadTopElement) + .withFilter(TestDefaultSuperCall::filterBadIntermediateElement) + .withFilter(TestDefaultSuperCall::filterBadTerminalElement) + .withDimension("INTF1", (x, ik) -> x.ik = ik, InterfaceKind.values()) + .withDimension("INTF2", (x, pk) -> x.pk = pk, PruneKind.values()) + .withArrayDimension("ELEM", (x, elem, idx) -> x.elements[idx] = elem, 5, ElementKind.values()) + .withDimension("QUAL", (x, qk) -> x.qk = qk, QualifierKind.values()) + .withDimension("EXPR", (x, ek) -> x.ek = ek, ExprKind.values()) + .run(TestDefaultSuperCall::new); } InterfaceKind ik; PruneKind pk; - Shape sh; + ElementKind[] elements = new ElementKind[5]; QualifierKind qk; ExprKind ek; - JavaSource source; - DiagnosticChecker diagChecker; + + boolean filterBadTopElement() { + return elements[0].isAllowedTop(); + } - TestDefaultSuperCall(InterfaceKind ik, PruneKind pk, Shape sh, - QualifierKind qk, ExprKind ek) { - this.ik = ik; - this.pk = pk; - this.sh = sh; - this.qk = qk; - this.ek = ek; - this.source = new JavaSource(); - this.diagChecker = new DiagnosticChecker(); + boolean filterBadIntermediateElement() { + for (int i = 1 ; i < 4 ; i++) { + if (!elements[i].isAllowedEnclosing(elements[i - 1], i == 1)) { + return false; + } + } + return true; + } + + boolean filterBadTerminalElement() { + return elements[4].isAllowedEnclosing(elements[3], false) && !elements[4].isClassDecl(); } - class JavaSource extends SimpleJavaFileObject { - - String template = "interface E {}\n" + - "interface B { }\n" + - "#I\n" + - "#P\n" + - "#C"; - - String source; + String template = "interface E {}\n" + + "interface B { }\n" + + "#{INTF1}\n" + + "#{INTF2}\n" + + "#{ELEM[0].0}"; - public JavaSource() { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - source = template.replaceAll("#I", ik.interfaceStr) - .replaceAll("#P", pk.interfaceStr) - .replaceAll("#C", sh.getShape(qk, ek)); - } + @Override + public void doWork() throws IOException { + check(newCompilationTask() + .withSourceFromTemplate(template, this::methodName) + .analyze()); + } - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; + ComboParameter methodName(String parameterName) { + switch (parameterName) { + case "METH": + String methodName = ek == ExprKind.THIS ? "test" : "m"; + return new ComboParameter.Constant(methodName); + default: + return null; } } - public void run() { - JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker, - null, null, Arrays.asList(source)); - try { - ct.analyze(); - } catch (Throwable ex) { - processException(ex); - return; - } - check(); - } + void check(Result res) { + Shape sh = new Shape(elements); - void check() { boolean errorExpected = false; boolean badEnclosing = false; @@ -364,7 +343,7 @@ boolean found = false; for (int i = 0; i < sh.enclosingElements.size(); i++) { if (sh.enclosingElements.get(i) == ElementKind.ANON_CLASS) continue; - if (sh.enclosingNames.get(i).equals(qk.getQualifier(sh))) { + if (sh.enclosingNames.get(i).equals(qk.qualifierStr)) { found = sh.elementsWithMethod.contains(sh.enclosingNames.get(i)); break; } @@ -388,10 +367,9 @@ } } - checkCount.incrementAndGet(); - if (diagChecker.errorFound != errorExpected) { - throw new AssertionError("Problem when compiling source:\n" + - source.getCharContent(true) + + if (res.hasErrors() != errorExpected) { + fail("Problem when compiling source:\n" + + res.compilationInfo() + "\nenclosingElems: " + sh.enclosingElements + "\nenclosingNames: " + sh.enclosingNames + "\nelementsWithMethod: " + sh.elementsWithMethod + @@ -399,20 +377,7 @@ "\nbad this: " + badThis + "\nbad super: " + badSuper + "\nqual kind: " + qk + - "\nfound error: " + diagChecker.errorFound); + "\nfound error: " + res.hasErrors()); } } - - static class DiagnosticChecker - implements javax.tools.DiagnosticListener { - - boolean errorFound; - - public void report(Diagnostic diagnostic) { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { - errorFound = true; - } - } - } - } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/failover/CheckAttributedTree.java --- a/test/tools/javac/failover/CheckAttributedTree.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/failover/CheckAttributedTree.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,7 +23,7 @@ /* * @test - * @bug 6970584 8006694 8062373 + * @bug 6970584 8006694 8062373 8129962 * @summary assorted position errors in compiler syntax trees * temporarily workaround combo tests are causing time out in several platforms * @library ../lib @@ -31,13 +31,10 @@ * jdk.compiler/com.sun.tools.javac.code * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util - * @build JavacTestingAbstractThreadedTest - * @run main/othervm CheckAttributedTree -q -r -et ERRONEOUS . + * @build combo.ComboTestHelper + * @run main CheckAttributedTree -q -r -et ERRONEOUS . */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 - import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; @@ -56,6 +53,11 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Field; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; @@ -79,18 +81,14 @@ import javax.swing.text.BadLocationException; import javax.swing.text.DefaultHighlighter; import javax.swing.text.Highlighter; -import javax.tools.Diagnostic; -import javax.tools.DiagnosticListener; import javax.tools.JavaFileObject; import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.util.JavacTask; import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskEvent.Kind; import com.sun.source.util.TaskListener; -import com.sun.tools.javac.api.JavacTaskImpl; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; @@ -101,6 +99,10 @@ import static com.sun.tools.javac.tree.JCTree.Tag.*; +import combo.ComboTestHelper; +import combo.ComboInstance; +import combo.ComboTestHelper.IgnoreMode; + /** * Utility and test program to check validity of tree positions for tree nodes. * The program can be run standalone, or as a jtreg test. In standalone mode, @@ -113,7 +115,7 @@ * covering any new language features that may be tested in this test suite. */ -public class CheckAttributedTree extends JavacTestingAbstractThreadedTest { +public class CheckAttributedTree { /** * Main entry point. * If test.src is set, program runs in jtreg mode, and will throw an Error @@ -125,7 +127,6 @@ public static void main(String... args) throws Exception { String testSrc = System.getProperty("test.src"); File baseDir = (testSrc == null) ? null : new File(testSrc); - throwAssertionOnError = false; boolean ok = new CheckAttributedTree().run(baseDir, args); if (!ok) { if (testSrc != null) // jtreg mode @@ -160,7 +161,6 @@ quiet = true; else if (arg.equals("-v")) { verbose = true; - printAll = true; } else if (arg.equals("-t") && i + 1 < args.length) tags.add(args[++i]); @@ -187,18 +187,37 @@ } } - for (File file: files) { - if (file.exists()) - test(file); - else - error("File not found: " + file); - } + ComboTestHelper cth = new ComboTestHelper<>(); + cth.withIgnoreMode(IgnoreMode.IGNORE_ALL) + .withFilter(FileChecker::checkFile) + .withDimension("FILE", (x, file) -> x.file = file, getAllFiles(files)) + .run(FileChecker::new); if (fileCount.get() != 1) errWriter.println(fileCount + " files read"); - checkAfterExec(false); + + if (verbose) { + System.out.println(errSWriter.toString()); + } + + return (gui || !cth.info().hasFailures()); + } - return (gui || errCount.get() == 0); + File[] getAllFiles(List roots) throws IOException { + long now = System.currentTimeMillis(); + ArrayList buf = new ArrayList<>(); + for (File file : roots) { + Files.walkFileTree(file.toPath(), new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + buf.add(file.toFile()); + return FileVisitResult.CONTINUE; + } + }); + } + long delta = System.currentTimeMillis() - now; + System.err.println("All files = " + buf.size() + " " + delta); + return buf.toArray(new File[buf.size()]); } /** @@ -224,116 +243,217 @@ out.println(""); } - /** - * Test a file. If the file is a directory, it will be recursively scanned - * for java files. - * @param file the file or directory to test - */ - void test(final File file) { - if (excludeFiles.contains(file)) { - if (!quiet) - error("File " + file + " excluded"); - return; + class FileChecker extends ComboInstance { + + File file; + + boolean checkFile() { + if (!file.exists()) { + error("File not found: " + file); + return false; + } + if (excludeFiles.contains(file)) { + if (!quiet) + error("File " + file + " excluded"); + return false; + } + if (!file.getName().endsWith(".java")) { + if (!quiet) + error("File " + file + " ignored"); + return false; + } + + return true; } - if (file.isDirectory()) { - for (File f: file.listFiles()) { - test(f); + public void doWork() { + if (!file.exists()) { + error("File not found: " + file); + } + if (excludeFiles.contains(file)) { + if (!quiet) + error("File " + file + " excluded"); + return; + } + if (!file.getName().endsWith(".java")) { + if (!quiet) + error("File " + file + " ignored"); + } + try { + if (verbose) + errWriter.println(file); + fileCount.incrementAndGet(); + NPETester p = new NPETester(); + p.test(read(file)); + } catch (AttributionException e) { + if (!quiet) { + error("Error attributing " + file + "\n" + e.getMessage()); + } + } catch (IOException e) { + error("Error reading " + file + ": " + e); } - return; + } + + /** + * Read a file. + * @param file the file to be read + * @return the tree for the content of the file + * @throws IOException if any IO errors occur + * @throws AttributionException if any errors occur while analyzing the file + */ + List> read(File file) throws IOException, AttributionException { + try { + Iterable files = fileManager().getJavaFileObjects(file); + final List analyzedElems = new ArrayList<>(); + final List trees = new ArrayList<>(); + Iterable elems = newCompilationTask() + .withWriter(pw) + .withOption("-XDshouldStopPolicy=ATTR") + .withOption("-XDverboseCompilePolicy") + .withSource(files.iterator().next()) + .withListener(new TaskListener() { + public void started(TaskEvent e) { + if (e.getKind() == TaskEvent.Kind.ANALYZE) + analyzedElems.add(e.getTypeElement()); + } + + public void finished(TaskEvent e) { + if (e.getKind() == Kind.PARSE) + trees.add(e.getCompilationUnit()); + } + }).analyze().get(); + if (!elems.iterator().hasNext()) + throw new AttributionException("No results from analyze"); + List> res = new ArrayList<>(); + for (CompilationUnitTree t : trees) { + JCCompilationUnit cu = (JCCompilationUnit)t; + for (JCTree def : cu.defs) { + if (def.hasTag(CLASSDEF) && + analyzedElems.contains(((JCTree.JCClassDecl)def).sym)) { + res.add(new Pair<>(cu, def)); + } + } + } + return res; + } + catch (Throwable t) { + throw new AttributionException("Exception while attributing file: " + file); + } } - if (file.isFile() && file.getName().endsWith(".java")) { - pool.execute(new Runnable() { - @Override - public void run() { + /** + * Report an error. When the program is complete, the program will either + * exit or throw an Error if any errors have been reported. + * @param msg the error message + */ + void error(String msg) { + System.err.println(); + System.err.println(msg); + System.err.println(); + fail(msg); + } + + /** + * Main class for testing assertions concerning types/symbol + * left uninitialized after attribution + */ + private class NPETester extends TreeScanner { + void test(List> trees) { + for (Pair p : trees) { + sourcefile = p.fst.sourcefile; + endPosTable = p.fst.endPositions; + encl = new Info(p.snd, endPosTable); + p.snd.accept(this); + } + } + + @Override + public void scan(JCTree tree) { + if (tree == null || + excludeTags.contains(treeUtil.nameFromTag(tree.getTag()))) { + return; + } + + Info self = new Info(tree, endPosTable); + if (mandatoryType(tree)) { + check(tree.type != null, + "'null' field 'type' found in tree ", self); + if (tree.type==null) + Thread.dumpStack(); + } + + Field errField = checkFields(tree); + if (errField!=null) { + check(false, + "'null' field '" + errField.getName() + "' found in tree ", self); + } + + Info prevEncl = encl; + encl = self; + tree.accept(this); + encl = prevEncl; + } + + private boolean mandatoryType(JCTree that) { + return that instanceof JCTree.JCExpression || + that.hasTag(VARDEF) || + that.hasTag(METHODDEF) || + that.hasTag(CLASSDEF); + } + + private final List excludedFields = Arrays.asList("varargsElement", "targetType"); + + void check(boolean ok, String label, Info self) { + if (!ok) { + if (gui) { + if (viewer == null) + viewer = new Viewer(); + viewer.addEntry(sourcefile, label, encl, self); + } + error(label + self.toString() + " encl: " + encl.toString() + + " in file: " + sourcefile + " " + self.tree); + } + } + + Field checkFields(JCTree t) { + List fieldsToCheck = treeUtil.getFieldsOfType(t, + excludedFields, + Symbol.class, + Type.class); + for (Field f : fieldsToCheck) { try { - if (verbose) - errWriter.println(file); - fileCount.incrementAndGet(); - NPETester p = new NPETester(); - p.test(read(file)); - } catch (AttributionException e) { - if (!quiet) { - error("Error attributing " + file + "\n" + e.getMessage()); + if (f.get(t) == null) { + return f; } - } catch (IOException e) { - error("Error reading " + file + ": " + e); + } + catch (IllegalAccessException e) { + System.err.println("Cannot read field: " + f); + //swallow it } } - }); - return; + return null; + } + + @Override + public void visitImport(JCImport tree) { } + + @Override + public void visitTopLevel(JCCompilationUnit tree) { + scan(tree.defs); + } + + JavaFileObject sourcefile; + EndPosTable endPosTable; + Info encl; } - - if (!quiet) - error("File " + file + " ignored"); } // See CR: 6982992 Tests CheckAttributedTree.java, JavacTreeScannerTest.java, and SourceTreeeScannerTest.java timeout StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); - Reporter r = new Reporter(pw); - /** - * Read a file. - * @param file the file to be read - * @return the tree for the content of the file - * @throws IOException if any IO errors occur - * @throws AttributionException if any errors occur while analyzing the file - */ - List> read(File file) throws IOException, AttributionException { - r.errors = 0; - Iterable files = fm.get().getJavaFileObjects(file); - String[] opts = { "-XDshouldStopPolicy=ATTR", "-XDverboseCompilePolicy" }; - JavacTask task = (JavacTask)comp.getTask(pw, fm.get(), r, Arrays.asList(opts), null, files); - final List analyzedElems = new ArrayList<>(); - task.setTaskListener(new TaskListener() { - public void started(TaskEvent e) { - if (e.getKind() == TaskEvent.Kind.ANALYZE) - analyzedElems.add(e.getTypeElement()); - } - public void finished(TaskEvent e) { } - }); - int i = 0; - try { - Iterable trees = task.parse(); -// JavaCompiler c = JavaCompiler.instance(((JavacTaskImpl) task).getContext()); -// System.err.println("verboseCompilePolicy: " + c.verboseCompilePolicy); -// System.err.println("shouldStopIfError: " + c.shouldStopPolicyIfError); -// System.err.println("shouldStopIfNoError: " + c.shouldStopPolicyIfNoError); - Iterable elems = task.analyze(); - if (!elems.iterator().hasNext()) - throw new AttributionException("No results from analyze"); - List> res = new ArrayList<>(); - //System.err.println("Try to add pairs. Elems are " + analyzedElems); - for (CompilationUnitTree t : trees) { - JCCompilationUnit cu = (JCCompilationUnit)t; - for (JCTree def : cu.defs) { - if (def.hasTag(CLASSDEF) && - analyzedElems.contains(((JCTree.JCClassDecl)def).sym)) { - //System.err.println("Adding pair..." + cu.sourcefile + " " + ((JCTree.JCClassDecl) def).name); - res.add((i++ % 2) == 0 ? new Pair<>(cu, def) {} : new Pair<>(cu, def)); - } - } - } - return res; - } - catch (Throwable t) { - throw new AttributionException("Exception while attributing file: " + file); - } - } - - /** - * Report an error. When the program is complete, the program will either - * exit or throw an Error if any errors have been reported. - * @param msg the error message - */ - void error(String msg) { - System.err.println(); - System.err.println(msg); - System.err.println(); - errCount.incrementAndGet(); - } + StringWriter errSWriter = new StringWriter(); + PrintWriter errWriter = new PrintWriter(errSWriter); /** Flag: don't report irrelevant files. */ boolean quiet; @@ -356,101 +476,6 @@ TreeUtil treeUtil = new TreeUtil(); /** - * Main class for testing assertions concerning types/symbol - * left uninitialized after attribution - */ - private class NPETester extends TreeScanner { - void test(List> trees) { - for (Pair p : trees) { -// System.err.println("checking " + p.fst.sourcefile); - sourcefile = p.fst.sourcefile; - endPosTable = p.fst.endPositions; - encl = new Info(p.snd, endPosTable); - p.snd.accept(this); - } - } - - @Override - public void scan(JCTree tree) { - if (tree == null || - excludeTags.contains(treeUtil.nameFromTag(tree.getTag()))) { - return; - } - - Info self = new Info(tree, endPosTable); - if (mandatoryType(tree)) { - check(tree.type != null, - "'null' field 'type' found in tree ", self); - if (tree.type==null) - Thread.dumpStack(); - } - - Field errField = checkFields(tree); - if (errField!=null) { - check(false, - "'null' field '" + errField.getName() + "' found in tree ", self); - } - - Info prevEncl = encl; - encl = self; - tree.accept(this); - encl = prevEncl; - } - - private boolean mandatoryType(JCTree that) { - return that instanceof JCTree.JCExpression || - that.hasTag(VARDEF) || - that.hasTag(METHODDEF) || - that.hasTag(CLASSDEF); - } - - private final List excludedFields = Arrays.asList("varargsElement", "targetType"); - - void check(boolean ok, String label, Info self) { - if (!ok) { - if (gui) { - if (viewer == null) - viewer = new Viewer(); - viewer.addEntry(sourcefile, label, encl, self); - } - error(label + self.toString() + " encl: " + encl.toString() + - " in file: " + sourcefile + " " + self.tree); - } - } - - Field checkFields(JCTree t) { - List fieldsToCheck = treeUtil.getFieldsOfType(t, - excludedFields, - Symbol.class, - Type.class); - for (Field f : fieldsToCheck) { - try { - if (f.get(t) == null) { - return f; - } - } - catch (IllegalAccessException e) { - System.err.println("Cannot read field: " + f); - //swallow it - } - } - return null; - } - - @Override - public void visitImport(JCImport tree) { } - - @Override - public void visitTopLevel(JCCompilationUnit tree) { - scan(tree.defs); - } - - JavaFileObject sourcefile; - EndPosTable endPosTable; - Info encl; - } - - /** * Utility class providing easy access to position and other info for a tree node. */ private class Info { @@ -524,25 +549,6 @@ } /** - * DiagnosticListener to report diagnostics and count any errors that occur. - */ - private static class Reporter implements DiagnosticListener { - Reporter(PrintWriter out) { - this.out = out; - } - - public void report(Diagnostic diagnostic) { - //out.println(diagnostic); - switch (diagnostic.getKind()) { - case ERROR: - errors++; - } - } - int errors; - PrintWriter out; - } - - /** * GUI viewer for issues found by TreePosTester. The viewer provides a drop * down list for selecting error conditions, a header area providing details * about an error, and a text area with the ranges of text highlighted as diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/generics/diamond/7046778/DiamondAndInnerClassTest.java --- a/test/tools/javac/generics/diamond/7046778/DiamondAndInnerClassTest.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/generics/diamond/7046778/DiamondAndInnerClassTest.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,30 +23,32 @@ /* * @test - * @bug 7046778 8006694 + * @bug 7046778 8006694 8129962 * @summary Project Coin: problem with diamond and member inner classes * temporarily workaround combo tests are causing time out in several platforms - * @library ../../../lib - * @modules jdk.compiler - * @build JavacTestingAbstractThreadedTest - * @run main/othervm DiamondAndInnerClassTest + * @library /tools/javac/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + * @compile -Xlint:all DiamondAndInnerClassTest.java + * @run main DiamondAndInnerClassTest */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 - -import com.sun.source.util.JavacTask; -import java.net.URI; +import java.io.IOException; import java.util.Arrays; -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -public class DiamondAndInnerClassTest - extends JavacTestingAbstractThreadedTest - implements Runnable { +import combo.ComboTestHelper; +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; - enum TypeArgumentKind { +public class DiamondAndInnerClassTest extends ComboInstance { + + enum TypeArgumentKind implements ComboParameter { NONE(""), STRING(""), INTEGER(""), @@ -54,7 +56,7 @@ String typeargStr; - private TypeArgumentKind(String typeargStr) { + TypeArgumentKind(String typeargStr) { this.typeargStr = typeargStr; } @@ -75,252 +77,173 @@ default: throw new AssertionError("Unexpected decl kind: " + this); } } + + @Override + public String expand(String optParameter) { + return typeargStr; + } } - enum ArgumentKind { + enum ArgumentKind implements ComboParameter { OBJECT("(Object)null"), STRING("(String)null"), INTEGER("(Integer)null"); String argStr; - private ArgumentKind(String argStr) { + ArgumentKind(String argStr) { this.argStr = argStr; } + + @Override + public String expand(String optParameter) { + return argStr; + } } - enum TypeQualifierArity { - ONE(1, "A1#TA1"), - TWO(2, "A1#TA1.A2#TA2"), - THREE(3, "A1#TA1.A2#TA2.A3#TA3"); + enum TypeQualifierArity implements ComboParameter { + ONE(1, "A1#{TA#IDX[0]}"), + TWO(2, "A1#{TA#IDX[0]}.A2#{TA#IDX[1]}"), + THREE(3, "A1#{TA#IDX[0]}.A2#{TA#IDX[1]}.A3#{TA#IDX[2]}"); int n; String qualifierStr; - private TypeQualifierArity(int n, String qualifierStr) { + TypeQualifierArity(int n, String qualifierStr) { this.n = n; this.qualifierStr = qualifierStr; } - String getType(TypeArgumentKind... typeArgumentKinds) { - String res = qualifierStr; - for (int i = 1 ; i <= typeArgumentKinds.length ; i++) { - res = res.replace("#TA" + i, typeArgumentKinds[i-1].typeargStr); - } - return res; - } - - boolean matches(InnerClassDeclArity innerClassDeclArity) { - return n ==innerClassDeclArity.n; + @Override + public String expand(String optParameter) { + return qualifierStr.replaceAll("#IDX", optParameter); } } - enum InnerClassDeclArity { - ONE(1, "class A1 { A1(X x1) { } #B }"), - TWO(2, "class A1 { class A2 { A2(X1 x1, X2 x2) { } #B } }"), - THREE(3, "class A1 { class A2 { class A3 { A3(X1 x1, X2 x2, X3 x3) { } #B } } }"); + enum InnerClassDeclArity implements ComboParameter { + ONE(1, "class A1 { A1(X x1) { } #{BODY} }"), + TWO(2, "class A1 { class A2 { A2(X1 x1, X2 x2) { } #{BODY} } }"), + THREE(3, "class A1 { class A2 { class A3 { A3(X1 x1, X2 x2, X3 x3) { } #{BODY} } } }"); int n; String classDeclStr; - private InnerClassDeclArity(int n, String classDeclStr) { + InnerClassDeclArity(int n, String classDeclStr) { this.n = n; this.classDeclStr = classDeclStr; } + + @Override + public String expand(String optParameter) { + return classDeclStr; + } } - enum ArgumentListArity { - ONE(1, "(#A1)"), - TWO(2, "(#A1,#A2)"), - THREE(3, "(#A1,#A2,#A3)"); + enum ArgumentListArity implements ComboParameter { + ONE(1, "(#{A[0]})"), + TWO(2, "(#{A[0]},#{A[1]})"), + THREE(3, "(#{A[0]},#{A[1]},#{A[2]})"); int n; String argListStr; - private ArgumentListArity(int n, String argListStr) { + ArgumentListArity(int n, String argListStr) { this.n = n; this.argListStr = argListStr; } - String getArgs(ArgumentKind... argumentKinds) { - String res = argListStr; - for (int i = 1 ; i <= argumentKinds.length ; i++) { - res = res.replace("#A" + i, argumentKinds[i-1].argStr); - } - return res; - } - - boolean matches(InnerClassDeclArity innerClassDeclArity) { - return n ==innerClassDeclArity.n; + @Override + public String expand(String optParameter) { + return argListStr.replaceAll("#IDX", optParameter); } } public static void main(String... args) throws Exception { - for (InnerClassDeclArity innerClassDeclArity : InnerClassDeclArity.values()) { - for (TypeQualifierArity declType : TypeQualifierArity.values()) { - if (!declType.matches(innerClassDeclArity)) continue; - for (TypeQualifierArity newClassType : TypeQualifierArity.values()) { - if (!newClassType.matches(innerClassDeclArity)) continue; - for (ArgumentListArity argList : ArgumentListArity.values()) { - if (!argList.matches(innerClassDeclArity)) continue; - for (TypeArgumentKind taDecl1 : TypeArgumentKind.values()) { - boolean isDeclRaw = taDecl1 == TypeArgumentKind.NONE; - //no diamond on decl site - if (taDecl1 == TypeArgumentKind.DIAMOND) continue; - for (TypeArgumentKind taSite1 : TypeArgumentKind.values()) { - boolean isSiteRaw = - taSite1 == TypeArgumentKind.NONE; - //diamond only allowed on the last type qualifier - if (taSite1 == TypeArgumentKind.DIAMOND && - innerClassDeclArity != - InnerClassDeclArity.ONE) - continue; - for (ArgumentKind arg1 : ArgumentKind.values()) { - if (innerClassDeclArity == innerClassDeclArity.ONE) { - pool.execute( - new DiamondAndInnerClassTest( - innerClassDeclArity, declType, - newClassType, argList, - new TypeArgumentKind[] {taDecl1}, - new TypeArgumentKind[] {taSite1}, - new ArgumentKind[] {arg1})); - continue; - } - for (TypeArgumentKind taDecl2 : TypeArgumentKind.values()) { - //no rare types - if (isDeclRaw != (taDecl2 == TypeArgumentKind.NONE)) - continue; - //no diamond on decl site - if (taDecl2 == TypeArgumentKind.DIAMOND) - continue; - for (TypeArgumentKind taSite2 : TypeArgumentKind.values()) { - //no rare types - if (isSiteRaw != (taSite2 == TypeArgumentKind.NONE)) - continue; - //diamond only allowed on the last type qualifier - if (taSite2 == TypeArgumentKind.DIAMOND && - innerClassDeclArity != InnerClassDeclArity.TWO) - continue; - for (ArgumentKind arg2 : ArgumentKind.values()) { - if (innerClassDeclArity == innerClassDeclArity.TWO) { - pool.execute( - new DiamondAndInnerClassTest( - innerClassDeclArity, - declType, - newClassType, - argList, - new TypeArgumentKind[] {taDecl1, taDecl2}, - new TypeArgumentKind[] {taSite1, taSite2}, - new ArgumentKind[] {arg1, arg2})); - continue; - } - for (TypeArgumentKind taDecl3 : TypeArgumentKind.values()) { - //no rare types - if (isDeclRaw != (taDecl3 == TypeArgumentKind.NONE)) - continue; - //no diamond on decl site - if (taDecl3 == TypeArgumentKind.DIAMOND) - continue; - for (TypeArgumentKind taSite3 : TypeArgumentKind.values()) { - //no rare types - if (isSiteRaw != (taSite3 == TypeArgumentKind.NONE)) - continue; - //diamond only allowed on the last type qualifier - if (taSite3 == TypeArgumentKind.DIAMOND && - innerClassDeclArity != InnerClassDeclArity.THREE) - continue; - for (ArgumentKind arg3 : ArgumentKind.values()) { - if (innerClassDeclArity == - innerClassDeclArity.THREE) { - pool.execute( - new DiamondAndInnerClassTest( - innerClassDeclArity, - declType, - newClassType, - argList, - new TypeArgumentKind[] {taDecl1, taDecl2, taDecl3}, - new TypeArgumentKind[] {taSite1, taSite2, taSite3}, - new ArgumentKind[] {arg1, arg2, arg3})); - continue; - } - } - } - } - } - } - } - } - } - } - } + new ComboTestHelper() + .withFilter(DiamondAndInnerClassTest::rareTypesFilter) + .withFilter(DiamondAndInnerClassTest::noDiamondOnDecl) + .withFilter(DiamondAndInnerClassTest::noDiamondOnIntermediateTypes) + .withFilter(DiamondAndInnerClassTest::arityMismatch) + .withFilter(DiamondAndInnerClassTest::redundantFilter) + .withDimension("BODY", new ComboParameter.Constant<>("#{D.1} res = new #{S.2}#{AL};")) + .withDimension("DECL", (x, arity) -> x.innerClassDeclArity = arity, InnerClassDeclArity.values()) + .withDimension("D", (x, arity) -> x.declArity = arity, TypeQualifierArity.values()) + .withDimension("S", (x, arity) -> x.siteArity = arity, TypeQualifierArity.values()) + .withDimension("AL", (x, alist) -> x.argumentListArity = alist, ArgumentListArity.values()) + .withArrayDimension("TA1", (x, targs, idx) -> x.declTypeArgumentKinds[idx] = targs, 3, TypeArgumentKind.values()) + .withArrayDimension("TA2", (x, targs, idx) -> x.siteTypeArgumentKinds[idx] = targs, 3, TypeArgumentKind.values()) + .withArrayDimension("A", (x, argsk, idx) -> x.argumentKinds[idx] = argsk, 3, ArgumentKind.values()) + .run(DiamondAndInnerClassTest::new); + } + + InnerClassDeclArity innerClassDeclArity; + TypeQualifierArity declArity; + TypeQualifierArity siteArity; + TypeArgumentKind[] declTypeArgumentKinds = new TypeArgumentKind[3]; + TypeArgumentKind[] siteTypeArgumentKinds = new TypeArgumentKind[3]; + ArgumentKind[] argumentKinds = new ArgumentKind[3]; + ArgumentListArity argumentListArity; + + boolean rareTypesFilter() { + for (TypeArgumentKind[] types : Arrays.asList(declTypeArgumentKinds, siteTypeArgumentKinds)) { + boolean isRaw = types[0] == TypeArgumentKind.NONE; + for (int i = 1; i < innerClassDeclArity.n; i++) { + if (isRaw != (types[i] == TypeArgumentKind.NONE)) { + return false; } } } + return true; + } - checkAfterExec(); + boolean noDiamondOnDecl() { + for (int i = 0; i < innerClassDeclArity.n; i++) { + if (declTypeArgumentKinds[i] == TypeArgumentKind.DIAMOND) { + return false; + } + } + return true; + } + + boolean noDiamondOnIntermediateTypes() { + for (int i = 0; i < (innerClassDeclArity.n - 1); i++) { + if (siteTypeArgumentKinds[i] == TypeArgumentKind.DIAMOND) { + return false; + } + } + return true; } - InnerClassDeclArity innerClassDeclArity; - TypeQualifierArity declType; - TypeQualifierArity siteType; - ArgumentListArity argList; - TypeArgumentKind[] declTypeArgumentKinds; - TypeArgumentKind[] siteTypeArgumentKinds; - ArgumentKind[] argumentKinds; - JavaSource source; - DiagnosticChecker diagChecker; - - DiamondAndInnerClassTest(InnerClassDeclArity innerClassDeclArity, - TypeQualifierArity declType, TypeQualifierArity siteType, - ArgumentListArity argList, TypeArgumentKind[] declTypeArgumentKinds, - TypeArgumentKind[] siteTypeArgumentKinds, ArgumentKind[] argumentKinds) { - this.innerClassDeclArity = innerClassDeclArity; - this.declType = declType; - this.siteType = siteType; - this.argList = argList; - this.declTypeArgumentKinds = declTypeArgumentKinds; - this.siteTypeArgumentKinds = siteTypeArgumentKinds; - this.argumentKinds = argumentKinds; - this.source = new JavaSource(); - this.diagChecker = new DiagnosticChecker(); + boolean redundantFilter() { + for (TypeArgumentKind[] types : Arrays.asList(declTypeArgumentKinds, siteTypeArgumentKinds)) { + for (int i = innerClassDeclArity.n; i < types.length; i++) { + if (types[i].ordinal() != 0) { + return false; + } + } + } + for (int i = innerClassDeclArity.n; i < argumentKinds.length; i++) { + if (argumentKinds[i].ordinal() != 0) { + return false; + } + } + return true; } - class JavaSource extends SimpleJavaFileObject { - - String bodyTemplate = "#D res = new #S#AL;"; - - String source; - - public JavaSource() { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - source = innerClassDeclArity.classDeclStr.replace("#B", bodyTemplate) - .replace("#D", declType.getType(declTypeArgumentKinds)) - .replace("#S", siteType.getType(siteTypeArgumentKinds)) - .replace("#AL", argList.getArgs(argumentKinds)); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; - } + boolean arityMismatch() { + return argumentListArity.n == innerClassDeclArity.n && + siteArity.n == innerClassDeclArity.n && + declArity.n == innerClassDeclArity.n; } @Override - public void run() { - JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker, - null, null, Arrays.asList(source)); - try { - ct.analyze(); - } catch (Throwable ex) { - throw new AssertionError("Error thrown when compiling the following code:\n" + - source.getCharContent(true)); - } - check(); + public void doWork() throws IOException { + check(newCompilationTask() + .withSourceFromTemplate("#{DECL}") + .analyze()); } - void check() { - checkCount.incrementAndGet(); - + void check(Result res) { boolean errorExpected = false; TypeArgumentKind[] expectedArgKinds = @@ -345,24 +268,11 @@ } } - if (errorExpected != diagChecker.errorFound) { - throw new Error("invalid diagnostics for source:\n" + - source.getCharContent(true) + - "\nFound error: " + diagChecker.errorFound + + if (errorExpected != res.hasErrors()) { + fail("invalid diagnostics for source:\n" + + res.compilationInfo() + + "\nFound error: " + res.hasErrors() + "\nExpected error: " + errorExpected); } } - - static class DiagnosticChecker - implements javax.tools.DiagnosticListener { - - boolean errorFound; - - public void report(Diagnostic diagnostic) { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { - errorFound = true; - } - } - } - } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java --- a/test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,29 +23,29 @@ /* * @test - * @bug 7062745 8006694 + * @bug 7062745 8006694 8129962 * @summary Regression: difference in overload resolution when two methods * are maximally specific * temporarily workaround combo tests are causing time out in several platforms - * @library ../../../lib - * @modules jdk.compiler - * @build JavacTestingAbstractThreadedTest - * @run main/othervm GenericOverrideTest + * @library /tools/javac/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + * @run main GenericOverrideTest */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 +import java.io.IOException; -import java.net.URI; -import java.util.Arrays; -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import com.sun.source.util.JavacTask; +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; -public class GenericOverrideTest - extends JavacTestingAbstractThreadedTest - implements Runnable { +public class GenericOverrideTest extends ComboInstance { enum SourceLevel { SOURCE_7("-source", "7"), @@ -58,24 +58,29 @@ } } - enum SignatureKind { + enum SignatureKind implements ComboParameter { NON_GENERIC(""), GENERIC(""); String paramStr; - private SignatureKind(String paramStr) { + SignatureKind(String paramStr) { this.paramStr = paramStr; } + + @Override + public String expand(String optParameter) { + return paramStr; + } } - enum ReturnTypeKind { + enum ReturnTypeKind implements ComboParameter { LIST("List"), ARRAYLIST("ArrayList"); String retStr; - private ReturnTypeKind(String retStr) { + ReturnTypeKind(String retStr) { this.retStr = retStr; } @@ -88,9 +93,14 @@ default: throw new AssertionError("Unexpected ret kind: " + this); } } + + @Override + public String expand(String optParameter) { + return retStr; + } } - enum TypeArgumentKind { + enum TypeArgumentKind implements ComboParameter { NONE(""), UNBOUND(""), INTEGER(""), @@ -99,7 +109,7 @@ String typeargStr; - private TypeArgumentKind(String typeargStr) { + TypeArgumentKind(String typeargStr) { this.typeargStr = typeargStr; } @@ -141,136 +151,79 @@ default: throw new AssertionError("Unexpected typearg kind: " + this); } } + + @Override + public String expand(String optParameter) { + return typeargStr; + } } public static void main(String... args) throws Exception { - for (SignatureKind sig1 : SignatureKind.values()) { - for (ReturnTypeKind rt1 : ReturnTypeKind.values()) { - for (TypeArgumentKind ta1 : TypeArgumentKind.values()) { - if (!ta1.compatibleWith(sig1)) continue; - for (SignatureKind sig2 : SignatureKind.values()) { - for (ReturnTypeKind rt2 : ReturnTypeKind.values()) { - for (TypeArgumentKind ta2 : TypeArgumentKind.values()) { - if (!ta2.compatibleWith(sig2)) continue; - for (ReturnTypeKind rt3 : ReturnTypeKind.values()) { - for (TypeArgumentKind ta3 : TypeArgumentKind.values()) { - if (!ta3.compatibleWith(SignatureKind.NON_GENERIC)) - continue; - for (SourceLevel level : SourceLevel.values()) { - pool.execute( - new GenericOverrideTest(sig1, - rt1, ta1, sig2, rt2, - ta2, rt3, ta3, level)); - } - } - } - } - } - } - } - } - } - - checkAfterExec(); + new ComboTestHelper() + .withFilter(GenericOverrideTest::argMismatchFilter) + .withDimension("SOURCE", (x, level) -> x.level = level, SourceLevel.values()) + .withArrayDimension("SIG", (x, sig, idx) -> x.sigs[idx] = sig, 2, SignatureKind.values()) + .withArrayDimension("TARG", (x, targ, idx) -> x.targs[idx] = targ, 3, TypeArgumentKind.values()) + .withArrayDimension("RET", (x, ret, idx) -> x.rets[idx] = ret, 3, ReturnTypeKind.values()) + .run(GenericOverrideTest::new); } - SignatureKind sig1, sig2; - ReturnTypeKind rt1, rt2, rt3; - TypeArgumentKind ta1, ta2, ta3; + SignatureKind[] sigs = new SignatureKind[2]; + ReturnTypeKind[] rets = new ReturnTypeKind[3]; + TypeArgumentKind[] targs = new TypeArgumentKind[3]; SourceLevel level; - JavaSource source; - DiagnosticChecker diagChecker; - GenericOverrideTest(SignatureKind sig1, ReturnTypeKind rt1, TypeArgumentKind ta1, - SignatureKind sig2, ReturnTypeKind rt2, TypeArgumentKind ta2, - ReturnTypeKind rt3, TypeArgumentKind ta3, SourceLevel level) { - this.sig1 = sig1; - this.sig2 = sig2; - this.rt1 = rt1; - this.rt2 = rt2; - this.rt3 = rt3; - this.ta1 = ta1; - this.ta2 = ta2; - this.ta3 = ta3; - this.level = level; - this.source = new JavaSource(); - this.diagChecker = new DiagnosticChecker(); + boolean argMismatchFilter() { + return targs[0].compatibleWith(sigs[0]) && + targs[1].compatibleWith(sigs[1]) && + targs[2].compatibleWith(SignatureKind.NON_GENERIC); } - class JavaSource extends SimpleJavaFileObject { - - String template = "import java.util.*;\n" + - "interface A { #S1 #R1#TA1 m(); }\n" + - "interface B { #S2 #R2#TA2 m(); }\n" + - "interface AB extends A, B {}\n" + - "class Test {\n" + - " void test(AB ab) { #R3#TA3 n = ab.m(); }\n" + - "}"; - - String source; + String template = "import java.util.*;\n" + + "interface A { #{SIG[0]} #{RET[0]}#{TARG[0]} m(); }\n" + + "interface B { #{SIG[1]} #{RET[1]}#{TARG[1]} m(); }\n" + + "interface AB extends A, B {}\n" + + "class Test {\n" + + " void test(AB ab) { #{RET[2]}#{TARG[2]} n = ab.m(); }\n" + + "}"; - public JavaSource() { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - source = template.replace("#S1", sig1.paramStr). - replace("#S2", sig2.paramStr). - replace("#R1", rt1.retStr). - replace("#R2", rt2.retStr). - replace("#R3", rt3.retStr). - replace("#TA1", ta1.typeargStr). - replace("#TA2", ta2.typeargStr). - replace("#TA3", ta3.typeargStr); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; - } + @Override + public void doWork() throws IOException { + check(newCompilationTask() + .withOption("-XDuseUnsharedTable") //this test relies on predictable name indexes! + .withOptions(level.opts) + .withSourceFromTemplate(template) + .analyze()); } - @Override - public void run() { - JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker, - level.opts != null ? Arrays.asList(level.opts) : null, - null, Arrays.asList(source)); - try { - ct.analyze(); - } catch (Throwable ex) { - throw new AssertionError("Error thrown when compiling the following code:\n" + - source.getCharContent(true)); - } - check(); - } - - void check() { - checkCount.incrementAndGet(); - + void check(Result res) { boolean errorExpected = false; int mostSpecific = 0; //first check that either |R1| <: |R2| or |R2| <: |R1| - if (rt1 != rt2) { - if (!rt1.moreSpecificThan(rt2) && - !rt2.moreSpecificThan(rt1)) { + if (rets[0] != rets[1]) { + if (!rets[0].moreSpecificThan(rets[1]) && + !rets[1].moreSpecificThan(rets[0])) { errorExpected = true; } else { - mostSpecific = rt1.moreSpecificThan(rt2) ? 1 : 2; + mostSpecific = rets[0].moreSpecificThan(rets[1]) ? 1 : 2; } } //check that either TA1 <= TA2 or TA2 <= TA1 (unless most specific return found above is raw) if (!errorExpected) { - if (ta1 != ta2) { - boolean useStrictCheck = ta1.moreSpecificThan(ta2, true) || - ta2.moreSpecificThan(ta1, true); - if (!ta1.moreSpecificThan(ta2, useStrictCheck) && - !ta2.moreSpecificThan(ta1, useStrictCheck)) { + if (targs[0] != targs[1]) { + boolean useStrictCheck = targs[0].moreSpecificThan(targs[1], true) || + targs[1].moreSpecificThan(targs[0], true); + if (!targs[0].moreSpecificThan(targs[1], useStrictCheck) && + !targs[1].moreSpecificThan(targs[0], useStrictCheck)) { errorExpected = true; } else { - int mostSpecific2 = ta1.moreSpecificThan(ta2, useStrictCheck) ? 1 : 2; + int mostSpecific2 = targs[0].moreSpecificThan(targs[1], useStrictCheck) ? 1 : 2; if (mostSpecific != 0 && mostSpecific2 != mostSpecific) { errorExpected = mostSpecific == 1 ? - ta1 != TypeArgumentKind.NONE : - ta2 != TypeArgumentKind.NONE; + targs[0] != TypeArgumentKind.NONE : + targs[1] != TypeArgumentKind.NONE; } else { mostSpecific = mostSpecific2; } @@ -284,34 +237,21 @@ //finally, check that most specific return type is compatible with expected type if (!errorExpected) { - ReturnTypeKind msrt = mostSpecific == 1 ? rt1 : rt2; - TypeArgumentKind msta = mostSpecific == 1 ? ta1 : ta2; - SignatureKind mssig = mostSpecific == 1 ? sig1 : sig2; + ReturnTypeKind msrt = mostSpecific == 1 ? rets[0] : rets[1]; + TypeArgumentKind msta = mostSpecific == 1 ? targs[0] : targs[1]; + SignatureKind mssig = mostSpecific == 1 ? sigs[0] : sigs[1]; - if (!msrt.moreSpecificThan(rt3) || - !msta.assignableTo(ta3, mssig, level)) { + if (!msrt.moreSpecificThan(rets[2]) || + !msta.assignableTo(targs[2], mssig, level)) { errorExpected = true; } } - if (errorExpected != diagChecker.errorFound) { - throw new Error("invalid diagnostics for source:\n" + - source.getCharContent(true) + - "\nFound error: " + diagChecker.errorFound + + if (errorExpected != res.hasErrors()) { + fail("invalid diagnostics for source:\n" + + res.compilationInfo() + + "\nFound error: " + res.hasErrors() + "\nExpected error: " + errorExpected); } } - - static class DiagnosticChecker - implements javax.tools.DiagnosticListener { - - boolean errorFound; - - public void report(Diagnostic diagnostic) { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { - errorFound = true; - } - } - } - } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lambda/FunctionalInterfaceConversionTest.java --- a/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,35 +23,32 @@ /** * @test - * @bug 8003280 8004102 8006694 + * @bug 8003280 8004102 8006694 8129962 * @summary Add lambda tests * perform several automated checks in lambda conversion, esp. around accessibility * temporarily workaround combo tests are causing time out in several platforms - * @author Maurizio Cimadamore - * @library ../lib - * @modules jdk.compiler - * @build JavacTestingAbstractThreadedTest - * @run main/timeout=600/othervm FunctionalInterfaceConversionTest + * @library /tools/javac/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + * @run main FunctionalInterfaceConversionTest */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 - import java.io.IOException; -import java.net.URI; -import java.util.Arrays; -import javax.tools.Diagnostic; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import javax.tools.ToolProvider; -import com.sun.source.util.JavacTask; -public class FunctionalInterfaceConversionTest - extends JavacTestingAbstractThreadedTest - implements Runnable { +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; - enum PackageKind { + +public class FunctionalInterfaceConversionTest extends ComboInstance { + + enum PackageKind implements ComboParameter { NO_PKG(""), PKG_A("a"); @@ -61,7 +58,8 @@ this.pkg = pkg; } - String getPkgDecl() { + @Override + public String expand(String optParameter) { return this == NO_PKG ? "" : "package " + pkg + ";"; @@ -74,12 +72,12 @@ } } - enum SamKind { + enum SamKind implements ComboParameter { CLASS("public class Sam { }"), ABSTACT_CLASS("public abstract class Sam { }"), ANNOTATION("public @interface Sam { }"), ENUM("public enum Sam { }"), - INTERFACE("public interface Sam { \n #METH; \n }"); + INTERFACE("public interface Sam { \n #{METH1}; \n }"); String sam_str; @@ -87,12 +85,13 @@ this.sam_str = sam_str; } - String getSam(String methStr) { - return sam_str.replaceAll("#METH", methStr); + @Override + public String expand(String optParameter) { + return sam_str; } } - enum ModifierKind { + enum ModifierKind implements ComboParameter { PUBLIC("public"), PACKAGE(""); @@ -102,77 +101,73 @@ this.modifier_str = modifier_str; } - boolean stricterThan(ModifierKind that) { - return this.ordinal() > that.ordinal(); + @Override + public String expand(String optParameter) { + return modifier_str; } } - enum TypeKind { + enum TypeKind implements ComboParameter { EXCEPTION("Exception"), PKG_CLASS("PackageClass"); String typeStr; - private TypeKind(String typeStr) { + TypeKind(String typeStr) { this.typeStr = typeStr; } + + @Override + public String expand(String optParameter) { + return typeStr; + } } - enum ExprKind { + enum ExprKind implements ComboParameter { LAMBDA("x -> null"), MREF("this::m"); String exprStr; - private ExprKind(String exprStr) { + ExprKind(String exprStr) { this.exprStr = exprStr; } + + @Override + public String expand(String optParameter) { + return exprStr; + } } - enum MethodKind { + enum MethodKind implements ComboParameter { NONE(""), - NON_GENERIC("public abstract #R m(#ARG s) throws #T;"), - GENERIC("public abstract #R m(#ARG s) throws #T;"); + NON_GENERIC("public abstract #{RET} m(#{ARG} s) throws #{THROWN};"), + GENERIC("public abstract #{RET} m(#{ARG} s) throws #{THROWN};"); String methodTemplate; - private MethodKind(String methodTemplate) { + MethodKind(String methodTemplate) { this.methodTemplate = methodTemplate; } - String getMethod(TypeKind retType, TypeKind argType, TypeKind thrownType) { - return methodTemplate.replaceAll("#R", retType.typeStr). - replaceAll("#ARG", argType.typeStr). - replaceAll("#T", thrownType.typeStr); + @Override + public String expand(String optParameter) { + return methodTemplate; } } public static void main(String[] args) throws Exception { - for (PackageKind samPkg : PackageKind.values()) { - for (ModifierKind modKind : ModifierKind.values()) { - for (SamKind samKind : SamKind.values()) { - for (MethodKind samMeth : MethodKind.values()) { - for (MethodKind clientMeth : MethodKind.values()) { - for (TypeKind retType : TypeKind.values()) { - for (TypeKind argType : TypeKind.values()) { - for (TypeKind thrownType : TypeKind.values()) { - for (ExprKind exprKind : ExprKind.values()) { - pool.execute( - new FunctionalInterfaceConversionTest( - samPkg, modKind, samKind, - samMeth, clientMeth, retType, - argType, thrownType, exprKind)); - } - } - } - } - } - } - } - } - } - - checkAfterExec(false); + new ComboTestHelper() + .withDimension("PKG", (x, pkg) -> x.samPkg = pkg, PackageKind.values()) + .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values()) + .withDimension("CLAZZ", (x, sam) -> x.samKind = sam, SamKind.values()) + .withDimension("METH1", (x, meth) -> x.samMeth = meth, MethodKind.values()) + .withDimension("METH2", (x, meth) -> x.clientMeth = meth, MethodKind.values()) + .withDimension("RET", (x, ret) -> x.retType = ret, TypeKind.values()) + .withDimension("ARG", (x, arg) -> x.argType = arg, TypeKind.values()) + .withDimension("THROWN", (x, thrown) -> x.thrownType = thrown, TypeKind.values()) + .withDimension("EXPR", (x, expr) -> x.exprKind = expr, ExprKind.values()) + .run(FunctionalInterfaceConversionTest::new); } PackageKind samPkg; @@ -184,70 +179,32 @@ TypeKind argType; TypeKind thrownType; ExprKind exprKind; - DiagnosticChecker dc; - SourceFile samSourceFile = new SourceFile("Sam.java", "#P \n #C") { - @Override - public String toString() { - return template.replaceAll("#P", samPkg.getPkgDecl()). - replaceAll("#C", samKind.getSam( - samMeth.getMethod(retType, argType, thrownType))); - } - }; - - SourceFile pkgClassSourceFile = - new SourceFile("PackageClass.java", - "#P\n #M class PackageClass extends Exception { }") { - @Override - public String toString() { - return template.replaceAll("#P", samPkg.getPkgDecl()). - replaceAll("#M", modKind.modifier_str); - } - }; + String samSource = "#{PKG} \n #{CLAZZ}"; + String pkgClassSource = "#{PKG}\n #{MOD} class PackageClass extends Exception { }"; + String clientSource = "#{IMP}\n abstract class Client { \n" + + " Sam s = #{EXPR};\n" + + " #{METH2} \n }"; - SourceFile clientSourceFile = - new SourceFile("Client.java", - "#I\n abstract class Client { \n" + - " Sam s = #E;\n" + - " #M \n }") { - @Override - public String toString() { - return template.replaceAll("#I", samPkg.getImportStat()) - .replaceAll("#E", exprKind.exprStr) - .replaceAll("#M", clientMeth.getMethod(retType, argType, thrownType)); - } - }; - - FunctionalInterfaceConversionTest(PackageKind samPkg, ModifierKind modKind, - SamKind samKind, MethodKind samMeth, MethodKind clientMeth, - TypeKind retType, TypeKind argType, TypeKind thrownType, - ExprKind exprKind) { - this.samPkg = samPkg; - this.modKind = modKind; - this.samKind = samKind; - this.samMeth = samMeth; - this.clientMeth = clientMeth; - this.retType = retType; - this.argType = argType; - this.thrownType = thrownType; - this.exprKind = exprKind; - this.dc = new DiagnosticChecker(); + @Override + public void doWork() throws IOException { + check(newCompilationTask() + .withSourceFromTemplate("Sam", samSource) + .withSourceFromTemplate("PackageClass", pkgClassSource) + .withSourceFromTemplate("Client", clientSource, this::importStmt) + .analyze()); } - @Override - public void run() { - final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); + ComboParameter importStmt(String name) { + switch (name) { + case "IMP": return new ComboParameter.Constant<>(samPkg.getImportStat()); + default: return null; + } + } - JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), dc, null, null, - Arrays.asList(samSourceFile, pkgClassSourceFile, clientSourceFile)); - try { - ct.analyze(); - } catch (IOException ex) { - throw new AssertionError("Test failing with cause", ex.getCause()); - } - if (dc.errorFound == checkSamConversion()) { - throw new AssertionError(samSourceFile + "\n\n" + - pkgClassSourceFile + "\n\n" + clientSourceFile); + void check(Result res) { + if (res.hasErrors() == checkSamConversion()) { + fail("Unexpected compilation result; " + res.compilationInfo()); } } @@ -276,35 +233,4 @@ return true; } } - - abstract class SourceFile extends SimpleJavaFileObject { - - protected String template; - - public SourceFile(String filename, String template) { - super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE); - this.template = template; - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return toString(); - } - - @Override - public abstract String toString(); - } - - static class DiagnosticChecker - implements javax.tools.DiagnosticListener { - - boolean errorFound = false; - - @Override - public void report(Diagnostic diagnostic) { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { - errorFound = true; - } - } - } } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lambda/LambdaParserTest.java --- a/test/tools/javac/lambda/LambdaParserTest.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/lambda/LambdaParserTest.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,39 +23,40 @@ /* * @test - * @bug 7115050 8003280 8005852 8006694 + * @bug 7115050 8003280 8005852 8006694 8129962 * @summary Add lambda tests * Add parser support for lambda expressions * temporarily workaround combo tests are causing time out in several platforms - * @library ../lib - * @modules jdk.compiler - * @build JavacTestingAbstractThreadedTest - * @run main/othervm LambdaParserTest + * @library /tools/javac/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + + * @run main LambdaParserTest */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 +import java.io.IOException; -import java.net.URI; -import java.util.Arrays; -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import com.sun.source.util.JavacTask; +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; -public class LambdaParserTest - extends JavacTestingAbstractThreadedTest - implements Runnable { +public class LambdaParserTest extends ComboInstance { - enum LambdaKind { + enum LambdaKind implements ComboParameter { NILARY_EXPR("()->x"), NILARY_STMT("()->{ return x; }"), - ONEARY_SHORT_EXPR("#PN->x"), - ONEARY_SHORT_STMT("#PN->{ return x; }"), - ONEARY_EXPR("(#M1 #T1 #PN)->x"), - ONEARY_STMT("(#M1 #T1 #PN)->{ return x; }"), - TWOARY_EXPR("(#M1 #T1 #PN, #M2 #T2 y)->x"), - TWOARY_STMT("(#M1 #T1 #PN, #M2 #T2 y)->{ return x; }"); + ONEARY_SHORT_EXPR("#{NAME}->x"), + ONEARY_SHORT_STMT("#{NAME}->{ return x; }"), + ONEARY_EXPR("(#{MOD[0]} #{TYPE[0]} #{NAME})->x"), + ONEARY_STMT("(#{MOD[0]} #{TYPE[0]} #{NAME})->{ return x; }"), + TWOARY_EXPR("(#{MOD[0]} #{TYPE[0]} #{NAME}, #{MOD[1]} #{TYPE[1]} y)->x"), + TWOARY_STMT("(#{MOD[0]} #{TYPE[0]} #{NAME}, #{MOD[1]} #{TYPE[1]} y)->{ return x; }"); String lambdaTemplate; @@ -63,13 +64,9 @@ this.lambdaTemplate = lambdaTemplate; } - String getLambdaString(LambdaParameterKind pk1, LambdaParameterKind pk2, - ModifierKind mk1, ModifierKind mk2, LambdaParameterName pn) { - return lambdaTemplate.replaceAll("#M1", mk1.modifier) - .replaceAll("#M2", mk2.modifier) - .replaceAll("#T1", pk1.parameterType) - .replaceAll("#T2", pk2.parameterType) - .replaceAll("#PN", pn.nameStr); + @Override + public String expand(String optParameter) { + return lambdaTemplate; } int arity() { @@ -92,7 +89,7 @@ } } - enum LambdaParameterName { + enum LambdaParameterName implements ComboParameter { IDENT("x"), UNDERSCORE("_"); @@ -101,9 +98,14 @@ LambdaParameterName(String nameStr) { this.nameStr = nameStr; } + + @Override + public String expand(String optParameter) { + return nameStr; + } } - enum LambdaParameterKind { + enum LambdaParameterKind implements ComboParameter { IMPLICIT(""), EXPLIICT_SIMPLE("A"), EXPLIICT_SIMPLE_ARR1("A[]"), @@ -129,9 +131,14 @@ return this == EXPLICIT_VARARGS || this == EXPLICIT_GENERIC2_VARARGS; } + + @Override + public String expand(String optParameter) { + return parameterType; + } } - enum ModifierKind { + enum ModifierKind implements ComboParameter { NONE(""), FINAL("final"), PUBLIC("public"); @@ -150,15 +157,20 @@ default: throw new AssertionError("Invalid modifier kind " + this); } } + + @Override + public String expand(String optParameter) { + return modifier; + } } - enum ExprKind { - NONE("#L#S"), - SINGLE_PAREN1("(#L#S)"), - SINGLE_PAREN2("(#L)#S"), - DOUBLE_PAREN1("((#L#S))"), - DOUBLE_PAREN2("((#L)#S)"), - DOUBLE_PAREN3("((#L))#S"); + enum ExprKind implements ComboParameter { + NONE("#{LAMBDA}#{SUBEXPR}"), + SINGLE_PAREN1("(#{LAMBDA}#{SUBEXPR})"), + SINGLE_PAREN2("(#{LAMBDA})#{SUBEXPR}"), + DOUBLE_PAREN1("((#{LAMBDA}#{SUBEXPR}))"), + DOUBLE_PAREN2("((#{LAMBDA})#{SUBEXPR})"), + DOUBLE_PAREN3("((#{LAMBDA}))#{SUBEXPR}"); String expressionTemplate; @@ -166,14 +178,13 @@ this.expressionTemplate = expressionTemplate; } - String expressionString(LambdaParameterKind pk1, LambdaParameterKind pk2, - ModifierKind mk1, ModifierKind mk2, LambdaKind lk, LambdaParameterName pn, SubExprKind sk) { - return expressionTemplate.replaceAll("#L", lk.getLambdaString(pk1, pk2, mk1, mk2, pn)) - .replaceAll("#S", sk.subExpression); + @Override + public String expand(String optParameter) { + return expressionTemplate; } } - enum SubExprKind { + enum SubExprKind implements ComboParameter { NONE(""), SELECT_FIELD(".f"), SELECT_METHOD(".f()"), @@ -186,133 +197,78 @@ SubExprKind(String subExpression) { this.subExpression = subExpression; } + + @Override + public String expand(String optParameter) { + return subExpression; + } } public static void main(String... args) throws Exception { - for (LambdaKind lk : LambdaKind.values()) { - for (LambdaParameterName pn : LambdaParameterName.values()) { - for (LambdaParameterKind pk1 : LambdaParameterKind.values()) { - if (lk.arity() < 1 && pk1 != LambdaParameterKind.IMPLICIT) - continue; - for (LambdaParameterKind pk2 : LambdaParameterKind.values()) { - if (lk.arity() < 2 && pk2 != LambdaParameterKind.IMPLICIT) - continue; - for (ModifierKind mk1 : ModifierKind.values()) { - if (mk1 != ModifierKind.NONE && lk.isShort()) - continue; - if (lk.arity() < 1 && mk1 != ModifierKind.NONE) - continue; - for (ModifierKind mk2 : ModifierKind.values()) { - if (lk.arity() < 2 && mk2 != ModifierKind.NONE) - continue; - for (SubExprKind sk : SubExprKind.values()) { - for (ExprKind ek : ExprKind.values()) { - pool.execute( - new LambdaParserTest(pk1, pk2, mk1, - mk2, lk, sk, ek, pn)); - } - } - } - } - } - } - } - } - - checkAfterExec(); + new ComboTestHelper() + .withFilter(LambdaParserTest::redundantTestFilter) + .withFilter(LambdaParserTest::badImplicitFilter) + .withDimension("LAMBDA", (x, lk) -> x.lk = lk, LambdaKind.values()) + .withDimension("NAME", (x, name) -> x.pn = name, LambdaParameterName.values()) + .withArrayDimension("TYPE", (x, type, idx) -> x.pks[idx] = type, 2, LambdaParameterKind.values()) + .withArrayDimension("MOD", (x, mod, idx) -> x.mks[idx] = mod, 2, ModifierKind.values()) + .withDimension("EXPR", ExprKind.values()) + .withDimension("SUBEXPR", SubExprKind.values()) + .run(LambdaParserTest::new); } - LambdaParameterKind pk1; - LambdaParameterKind pk2; - ModifierKind mk1; - ModifierKind mk2; + LambdaParameterKind[] pks = new LambdaParameterKind[2]; + ModifierKind[] mks = new ModifierKind[2]; LambdaKind lk; LambdaParameterName pn; - SubExprKind sk; - ExprKind ek; - JavaSource source; - DiagnosticChecker diagChecker; + + boolean badImplicitFilter() { + return !(mks[0] != ModifierKind.NONE && lk.isShort()); + } - LambdaParserTest(LambdaParameterKind pk1, LambdaParameterKind pk2, - ModifierKind mk1, ModifierKind mk2, LambdaKind lk, - SubExprKind sk, ExprKind ek, LambdaParameterName pn) { - this.pk1 = pk1; - this.pk2 = pk2; - this.mk1 = mk1; - this.mk2 = mk2; - this.lk = lk; - this.pn = pn; - this.sk = sk; - this.ek = ek; - this.source = new JavaSource(); - this.diagChecker = new DiagnosticChecker(); + boolean redundantTestFilter() { + for (int i = lk.arity(); i < mks.length ; i++) { + if (mks[i].ordinal() != 0) { + return false; + } + } + for (int i = lk.arity(); i < pks.length ; i++) { + if (pks[i].ordinal() != 0) { + return false; + } + } + return true; } - class JavaSource extends SimpleJavaFileObject { - - String template = "class Test {\n" + - " SAM s = #E;\n" + - "}"; - - String source; + String template = "class Test {\n" + + " SAM s = #{EXPR};\n" + + "}"; - public JavaSource() { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - source = template.replaceAll("#E", - ek.expressionString(pk1, pk2, mk1, mk2, lk, pn, sk)); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; - } + @Override + public void doWork() throws IOException { + check(newCompilationTask() + .withSourceFromTemplate(template) + .parse()); } - public void run() { - JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker, - null, null, Arrays.asList(source)); - try { - ct.parse(); - } catch (Throwable ex) { - processException(ex); - return; - } - check(); - } - - void check() { - checkCount.incrementAndGet(); - - boolean errorExpected = (lk.arity() > 0 && !mk1.compatibleWith(pk1)) || - (lk.arity() > 1 && !mk2.compatibleWith(pk2)); + void check(Result res) { + boolean errorExpected = (lk.arity() > 0 && !mks[0].compatibleWith(pks[0])) || + (lk.arity() > 1 && !mks[1].compatibleWith(pks[1])); if (lk.arity() == 2 && - (pk1.explicit() != pk2.explicit() || - pk1.isVarargs())) { + (pks[0].explicit() != pks[1].explicit() || + pks[0].isVarargs())) { errorExpected = true; } errorExpected |= pn == LambdaParameterName.UNDERSCORE && lk.arity() > 0; - if (errorExpected != diagChecker.errorFound) { - throw new Error("invalid diagnostics for source:\n" + - source.getCharContent(true) + - "\nFound error: " + diagChecker.errorFound + + if (errorExpected != res.hasErrors()) { + fail("invalid diagnostics for source:\n" + + res.compilationInfo() + + "\nFound error: " + res.hasErrors() + "\nExpected error: " + errorExpected); } } - - static class DiagnosticChecker - implements javax.tools.DiagnosticListener { - - boolean errorFound; - - public void report(Diagnostic diagnostic) { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { - errorFound = true; - } - } - } - } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lambda/MethodReferenceParserTest.java --- a/test/tools/javac/lambda/MethodReferenceParserTest.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/lambda/MethodReferenceParserTest.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,39 +23,39 @@ /* * @test - * @bug 7115052 8003280 8006694 + * @bug 7115052 8003280 8006694 8129962 * @summary Add lambda tests * Add parser support for method references * temporarily workaround combo tests are causing time out in several platforms - * @library ../lib - * @modules jdk.compiler - * @build JavacTestingAbstractThreadedTest - * @run main/othervm MethodReferenceParserTest + * @library /tools/javac/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + * @run main MethodReferenceParserTest */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 +import java.io.IOException; -import java.net.URI; -import java.util.Arrays; -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import com.sun.source.util.JavacTask; +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; + +public class MethodReferenceParserTest extends ComboInstance { -public class MethodReferenceParserTest - extends JavacTestingAbstractThreadedTest - implements Runnable { - - enum ReferenceKind { - METHOD_REF("#Q::#Gm"), - CONSTRUCTOR_REF("#Q::#Gnew"), + enum ReferenceKind implements ComboParameter { + METHOD_REF("#{QUAL}::#{TARGS}m"), + CONSTRUCTOR_REF("#{QUAL}::#{TARGS}new"), FALSE_REF("min < max"), - ERR_SUPER("#Q::#Gsuper"), - ERR_METH0("#Q::#Gm()"), - ERR_METH1("#Q::#Gm(X)"), - ERR_CONSTR0("#Q::#Gnew()"), - ERR_CONSTR1("#Q::#Gnew(X)"); + ERR_SUPER("#{QUAL}::#{TARGS}super"), + ERR_METH0("#{QUAL}::#{TARGS}m()"), + ERR_METH1("#{QUAL}::#{TARGS}m(X)"), + ERR_CONSTR0("#{QUAL}::#{TARGS}new()"), + ERR_CONSTR1("#{QUAL}::#{TARGS}new(X)"); String referenceTemplate; @@ -63,12 +63,6 @@ this.referenceTemplate = referenceTemplate; } - String getReferenceString(QualifierKind qk, GenericKind gk) { - return referenceTemplate - .replaceAll("#Q", qk.qualifier) - .replaceAll("#G", gk.typeParameters); - } - boolean erroneous() { switch (this) { case ERR_SUPER: @@ -80,11 +74,16 @@ default: return false; } } + + @Override + public String expand(String optParameter) { + return referenceTemplate; + } } - enum ContextKind { - ASSIGN("SAM s = #E;"), - METHOD("m(#E, i);"); + enum ContextKind implements ComboParameter { + ASSIGN("SAM s = #{EXPR};"), + METHOD("m(#{EXPR}, i);"); String contextTemplate; @@ -92,13 +91,13 @@ this.contextTemplate = contextTemplate; } - String contextString(ExprKind ek, ReferenceKind rk, QualifierKind qk, - GenericKind gk, SubExprKind sk) { - return contextTemplate.replaceAll("#E", ek.expressionString(rk, qk, gk, sk)); + @Override + public String expand(String optParameter) { + return contextTemplate; } } - enum GenericKind { + enum GenericKind implements ComboParameter { NONE(""), ONE(""), TWO(""); @@ -108,9 +107,14 @@ GenericKind(String typeParameters) { this.typeParameters = typeParameters; } + + @Override + public String expand(String optParameter) { + return typeParameters; + } } - enum QualifierKind { + enum QualifierKind implements ComboParameter { THIS("this"), SUPER("super"), NEW("new Foo()"), @@ -131,15 +135,20 @@ QualifierKind(String qualifier) { this.qualifier = qualifier; } + + @Override + public String expand(String optParameter) { + return qualifier; + } } - enum ExprKind { - NONE("#R::S"), - SINGLE_PAREN1("(#R#S)"), - SINGLE_PAREN2("(#R)#S"), - DOUBLE_PAREN1("((#R#S))"), - DOUBLE_PAREN2("((#R)#S)"), - DOUBLE_PAREN3("((#R))#S"); + enum ExprKind implements ComboParameter { + NONE("#{MREF}"), + SINGLE_PAREN1("(#{MREF}#{SUBEXPR})"), + SINGLE_PAREN2("(#{MREF})#{SUBEXPR}"), + DOUBLE_PAREN1("((#{MREF}#{SUBEXPR}))"), + DOUBLE_PAREN2("((#{MREF})#{SUBEXPR})"), + DOUBLE_PAREN3("((#{MREF}))#{SUBEXPR}"); String expressionTemplate; @@ -147,14 +156,13 @@ this.expressionTemplate = expressionTemplate; } - String expressionString(ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk) { - return expressionTemplate - .replaceAll("#R", rk.getReferenceString(qk, gk)) - .replaceAll("#S", sk.subExpression); + @Override + public String expand(String optParameter) { + return expressionTemplate; } } - enum SubExprKind { + enum SubExprKind implements ComboParameter { NONE(""), SELECT_FIELD(".f"), SELECT_METHOD(".f()"), @@ -167,100 +175,45 @@ SubExprKind(String subExpression) { this.subExpression = subExpression; } + + @Override + public String expand(String optParameter) { + return subExpression; + } } public static void main(String... args) throws Exception { - for (ReferenceKind rk : ReferenceKind.values()) { - for (QualifierKind qk : QualifierKind.values()) { - for (GenericKind gk : GenericKind.values()) { - for (SubExprKind sk : SubExprKind.values()) { - for (ExprKind ek : ExprKind.values()) { - for (ContextKind ck : ContextKind.values()) { - pool.execute(new MethodReferenceParserTest(rk, qk, gk, sk, ek, ck)); - } - } - } - } - } - } - - checkAfterExec(); + new ComboTestHelper() + .withDimension("MREF", (x, ref) -> x.rk = ref, ReferenceKind.values()) + .withDimension("QUAL", QualifierKind.values()) + .withDimension("TARGS", GenericKind.values()) + .withDimension("EXPR", ExprKind.values()) + .withDimension("SUBEXPR", SubExprKind.values()) + .withDimension("CTX", ContextKind.values()) + .run(MethodReferenceParserTest::new); } ReferenceKind rk; - QualifierKind qk; - GenericKind gk; - SubExprKind sk; - ExprKind ek; - ContextKind ck; - JavaSource source; - DiagnosticChecker diagChecker; - MethodReferenceParserTest(ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk, ExprKind ek, ContextKind ck) { - this.rk = rk; - this.qk = qk; - this.gk = gk; - this.sk = sk; - this.ek = ek; - this.ck = ck; - this.source = new JavaSource(); - this.diagChecker = new DiagnosticChecker(); + String template = "class Test {\n" + + " void test() {\n" + + " #{CTX}\n" + + " }" + + "}"; + + @Override + public void doWork() throws IOException { + check(newCompilationTask() + .withSourceFromTemplate(template) + .parse()); } - class JavaSource extends SimpleJavaFileObject { - - String template = "class Test {\n" + - " void test() {\n" + - " #C\n" + - " }" + - "}"; - - String source; - - public JavaSource() { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - source = template.replaceAll("#C", ck.contextString(ek, rk, qk, gk, sk)); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; - } - } - - @Override - public void run() { - JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker, - null, null, Arrays.asList(source)); - try { - ct.parse(); - } catch (Throwable ex) { - processException(ex); - return; - } - check(); - } - - void check() { - checkCount.incrementAndGet(); - - if (diagChecker.errorFound != rk.erroneous()) { - throw new Error("invalid diagnostics for source:\n" + - source.getCharContent(true) + - "\nFound error: " + diagChecker.errorFound + + void check(Result res) { + if (res.hasErrors() != rk.erroneous()) { + fail("invalid diagnostics for source:\n" + + res.compilationInfo() + + "\nFound error: " + res.hasErrors() + "\nExpected error: " + rk.erroneous()); } } - - static class DiagnosticChecker implements javax.tools.DiagnosticListener { - - boolean errorFound; - - public void report(Diagnostic diagnostic) { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { - errorFound = true; - } - } - } - } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lambda/TestBootstrapMethodsCount.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/lambda/TestBootstrapMethodsCount.java Thu Sep 03 16:13:49 2015 -0700 @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2012, 2015, 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 8129547 + * @summary Excess entries in BootstrapMethods with the same (bsm, bsmKind, bsmStaticArgs), but different dynamicArgs + * @library /tools/javac/lib + * @modules jdk.jdeps/com.sun.tools.classfile + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + */ + +import java.io.File; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Locale; + +import javax.tools.Diagnostic; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.MethodTree; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; +import com.sun.source.util.TreeScanner; + +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.BootstrapMethods_attribute; +import com.sun.tools.classfile.ClassFile; + +import com.sun.tools.javac.api.JavacTaskImpl; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symbol.MethodSymbol; +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCIdent; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Names; + +import static com.sun.tools.javac.jvm.ClassFile.*; + +public class TestBootstrapMethodsCount { + + public static void main(String... args) throws Exception { + JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); + new TestBootstrapMethodsCount().run(comp); + } + + DiagChecker dc; + + TestBootstrapMethodsCount() { + dc = new DiagChecker(); + } + + public void run(JavaCompiler comp) { + JavaSource source = new JavaSource(); + JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, null, dc, + Arrays.asList("-g"), null, Arrays.asList(source)); + Context context = ct.getContext(); + Symtab syms = Symtab.instance(context); + Names names = Names.instance(context); + Types types = Types.instance(context); + ct.addTaskListener(new Indifier(syms, names, types)); + try { + ct.generate(); + } catch (Throwable t) { + t.printStackTrace(); + throw new AssertionError( + String.format("Error thrown when compiling following code\n%s", + source.source)); + } + if (dc.diagFound) { + throw new AssertionError( + String.format("Diags found when compiling following code\n%s\n\n%s", + source.source, dc.printDiags())); + } + verifyBytecode(); + } + + void verifyBytecode() { + File compiledTest = new File("Test.class"); + try { + ClassFile cf = ClassFile.read(compiledTest); + BootstrapMethods_attribute bsm_attr = + (BootstrapMethods_attribute)cf + .getAttribute(Attribute.BootstrapMethods); + int length = bsm_attr.bootstrap_method_specifiers.length; + if (length != 1) { + throw new Error("Bad number of method specifiers " + + "in BootstrapMethods attribute: " + length); + } + } catch (Exception e) { + e.printStackTrace(); + throw new Error("error reading " + compiledTest +": " + e); + } + } + + class JavaSource extends SimpleJavaFileObject { + + static final String source = "import java.lang.invoke.*;\n" + + "class Bootstrap {\n" + + " public static CallSite bsm(MethodHandles.Lookup lookup, " + + "String name, MethodType methodType) {\n" + + " return null;\n" + + " }\n" + + "}\n" + + "class Test {\n" + + " void m1() { }\n" + + " void m2(Object arg1) { }\n" + + " void test1() {\n" + + " Object o = this; // marker statement \n" + + " m1();\n" + + " }\n" + + " void test2(Object arg1) {\n" + + " Object o = this; // marker statement \n" + + " m2(arg1);\n" + + " }\n" + + "}"; + + JavaSource() { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + } + + class Indifier extends TreeScanner implements TaskListener { + + MethodSymbol bsm; + Symtab syms; + Names names; + Types types; + + Indifier(Symtab syms, Names names, Types types) { + this.syms = syms; + this.names = names; + this.types = types; + } + + @Override + public void started(TaskEvent e) { + //do nothing + } + + @Override + public void finished(TaskEvent e) { + if (e.getKind() == TaskEvent.Kind.ANALYZE) { + scan(e.getCompilationUnit(), null); + } + } + + @Override + public Void visitMethodInvocation(MethodInvocationTree node, Void p) { + super.visitMethodInvocation(node, p); + JCMethodInvocation apply = (JCMethodInvocation)node; + JCIdent ident = (JCIdent)apply.meth; + Symbol oldSym = ident.sym; + if (!oldSym.isConstructor()) { + ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name, + oldSym.owner, REF_invokeStatic, bsm, oldSym.type, new Object[0]); + } + return null; + } + + @Override + public Void visitMethod(MethodTree node, Void p) { + super.visitMethod(node, p); + if (node.getName().toString().equals("bsm")) { + bsm = ((JCMethodDecl)node).sym; + } + return null; + } + } + + static class DiagChecker + implements javax.tools.DiagnosticListener { + + boolean diagFound; + ArrayList diags = new ArrayList<>(); + + public void report(Diagnostic diagnostic) { + diags.add(diagnostic.getMessage(Locale.getDefault())); + diagFound = true; + } + + String printDiags() { + StringBuilder buf = new StringBuilder(); + for (String s : diags) { + buf.append(s); + buf.append("\n"); + } + return buf.toString(); + } + } + +} diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lambda/TestInvokeDynamic.java --- a/test/tools/javac/lambda/TestInvokeDynamic.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/lambda/TestInvokeDynamic.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,33 +23,27 @@ /* * @test - * @bug 7194586 8003280 8006694 8010404 + * @bug 7194586 8003280 8006694 8010404 8129962 * @summary Add lambda tests * Add back-end support for invokedynamic * temporarily workaround combo tests are causing time out in several platforms - * @library ../lib + * @library /tools/javac/lib * @modules jdk.jdeps/com.sun.tools.classfile * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main * jdk.compiler/com.sun.tools.javac.jvm * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util - * @build JavacTestingAbstractThreadedTest - * @run main/othervm TestInvokeDynamic + * @build combo.ComboTestHelper + * @run main TestInvokeDynamic */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 +import java.io.IOException; +import java.io.InputStream; -import java.io.File; -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Locale; - -import javax.tools.Diagnostic; import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.MethodTree; @@ -78,13 +72,17 @@ import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Names; +import combo.ComboParameter; +import combo.ComboTask; +import combo.ComboTestHelper; +import combo.ComboInstance; +import combo.ComboTask.Result; + import static com.sun.tools.javac.jvm.ClassFile.*; -public class TestInvokeDynamic - extends JavacTestingAbstractThreadedTest - implements Runnable { +public class TestInvokeDynamic extends ComboInstance { - enum StaticArgumentKind { + enum StaticArgumentKind implements ComboParameter { STRING("Hello!", "String", "Ljava/lang/String;") { @Override boolean check(CPInfo cpInfo) throws Exception { @@ -189,88 +187,91 @@ throw new AssertionError(); } } + + @Override + public String expand(String optParameter) { + return sourceTypeStr; + } } - enum StaticArgumentsArity { - ZERO(0), - ONE(1), - TWO(2), - THREE(3); + enum StaticArgumentsArity implements ComboParameter { + ZERO(0, ""), + ONE(1, ",#{SARG[0]} s1"), + TWO(2, ",#{SARG[0]} s1, #{SARG[1]} s2"), + THREE(3, ",#{SARG[0]} s1, #{SARG[1]} s2, #{SARG[2]} s3"); int arity; + String argsTemplate; - StaticArgumentsArity(int arity) { + StaticArgumentsArity(int arity, String argsTemplate) { this.arity = arity; + this.argsTemplate = argsTemplate; + } + + @Override + public String expand(String optParameter) { + return argsTemplate; } } public static void main(String... args) throws Exception { - for (StaticArgumentsArity arity : StaticArgumentsArity.values()) { - if (arity.arity == 0) { - pool.execute(new TestInvokeDynamic(arity)); - } else { - for (StaticArgumentKind sak1 : StaticArgumentKind.values()) { - if (arity.arity == 1) { - pool.execute(new TestInvokeDynamic(arity, sak1)); - } else { - for (StaticArgumentKind sak2 : StaticArgumentKind.values()) { - if (arity.arity == 2) { - pool.execute(new TestInvokeDynamic(arity, sak1, sak2)); - } else { - for (StaticArgumentKind sak3 : StaticArgumentKind.values()) { - pool.execute( - new TestInvokeDynamic(arity, sak1, sak2, sak3)); - } - } - } - } - } - } - } - - checkAfterExec(); + new ComboTestHelper() + .withFilter(TestInvokeDynamic::redundantTestFilter) + .withDimension("SARGS", (x, arity) -> x.arity = arity, StaticArgumentsArity.values()) + .withArrayDimension("SARG", (x, arg, idx) -> x.saks[idx] = arg, 3, StaticArgumentKind.values()) + .run(TestInvokeDynamic::new); } StaticArgumentsArity arity; - StaticArgumentKind[] saks; - DiagChecker dc; + StaticArgumentKind[] saks = new StaticArgumentKind[3]; - TestInvokeDynamic(StaticArgumentsArity arity, StaticArgumentKind... saks) { - this.arity = arity; - this.saks = saks; - dc = new DiagChecker(); + boolean redundantTestFilter() { + for (int i = arity.arity ; i < saks.length ; i++) { + if (saks[i].ordinal() != 0) { + return false; + } + } + return true; } - public void run() { - int id = checkCount.incrementAndGet(); - JavaSource source = new JavaSource(id); - JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, fm.get(), dc, - Arrays.asList("-g"), null, Arrays.asList(source)); + final String source_template = + "import java.lang.invoke.*;\n" + + "class Test {\n" + + " void m() { }\n" + + " void test() {\n" + + " Object o = this; // marker statement \n" + + " m();\n" + + " }\n" + + "}\n" + + "class Bootstrap {\n" + + " public static CallSite bsm(MethodHandles.Lookup lookup, " + + "String name, MethodType methodType #{SARGS}) {\n" + + " return null;\n" + + " }\n" + + "}"; + + @Override + public void doWork() throws IOException { + ComboTask comboTask = newCompilationTask() + .withOption("-g") + .withSourceFromTemplate(source_template); + + JavacTaskImpl ct = (JavacTaskImpl)comboTask.getTask(); Context context = ct.getContext(); Symtab syms = Symtab.instance(context); Names names = Names.instance(context); Types types = Types.instance(context); ct.addTaskListener(new Indifier(syms, names, types)); - try { - ct.generate(); - } catch (Throwable t) { - t.printStackTrace(); - throw new AssertionError( - String.format("Error thrown when compiling following code\n%s", - source.source)); - } - if (dc.diagFound) { - throw new AssertionError( - String.format("Diags found when compiling following code\n%s\n\n%s", - source.source, dc.printDiags())); - } - verifyBytecode(id); + verifyBytecode(comboTask.generate()); } - void verifyBytecode(int id) { - File compiledTest = new File(String.format("Test%d.class", id)); - try { - ClassFile cf = ClassFile.read(compiledTest); + void verifyBytecode(Result> res) { + if (res.hasErrors()) { + fail("Diags found when compiling instance: " + res.compilationInfo()); + return; + } + try (InputStream is = res.get().iterator().next().openInputStream()){ + ClassFile cf = ClassFile.read(is); Method testMethod = null; for (Method m : cf.methods) { if (m.getName(cf.constant_pool).equals("test")) { @@ -279,12 +280,14 @@ } } if (testMethod == null) { - throw new Error("Test method not found"); + fail("Test method not found"); + return; } Code_attribute ea = (Code_attribute)testMethod.attributes.get(Attribute.Code); if (testMethod == null) { - throw new Error("Code attribute for test() method not found"); + fail("Code attribute for test() method not found"); + return; } int bsmIdx = -1; @@ -296,37 +299,39 @@ .constant_pool.get(i.getShort(1)); bsmIdx = indyInfo.bootstrap_method_attr_index; if (!indyInfo.getNameAndTypeInfo().getType().equals("()V")) { - throw new - AssertionError("type mismatch for CONSTANT_InvokeDynamic_info"); + fail("type mismatch for CONSTANT_InvokeDynamic_info"); + return; } } } if (bsmIdx == -1) { - throw new Error("Missing invokedynamic in generated code"); + fail("Missing invokedynamic in generated code"); + return; } BootstrapMethods_attribute bsm_attr = (BootstrapMethods_attribute)cf .getAttribute(Attribute.BootstrapMethods); if (bsm_attr.bootstrap_method_specifiers.length != 1) { - throw new Error("Bad number of method specifiers " + + fail("Bad number of method specifiers " + "in BootstrapMethods attribute"); + return; } BootstrapMethods_attribute.BootstrapMethodSpecifier bsm_spec = bsm_attr.bootstrap_method_specifiers[0]; if (bsm_spec.bootstrap_arguments.length != arity.arity) { - throw new Error("Bad number of static invokedynamic args " + + fail("Bad number of static invokedynamic args " + "in BootstrapMethod attribute"); + return; } - int count = 0; - for (StaticArgumentKind sak : saks) { - if (!sak.check(cf.constant_pool - .get(bsm_spec.bootstrap_arguments[count]))) { - throw new Error("Bad static argument value " + sak); + for (int i = 0 ; i < arity.arity ; i++) { + if (!saks[i].check(cf.constant_pool + .get(bsm_spec.bootstrap_arguments[i]))) { + fail("Bad static argument value " + saks[i]); + return; } - count++; } CONSTANT_MethodHandle_info bsm_handle = @@ -334,7 +339,8 @@ .get(bsm_spec.bootstrap_method_ref); if (bsm_handle.reference_kind != RefKind.REF_invokeStatic) { - throw new Error("Bad kind on boostrap method handle"); + fail("Bad kind on boostrap method handle"); + return; } CONSTANT_Methodref_info bsm_ref = @@ -342,88 +348,51 @@ .get(bsm_handle.reference_index); if (!bsm_ref.getClassInfo().getName().equals("Bootstrap")) { - throw new Error("Bad owner of boostrap method"); + fail("Bad owner of boostrap method"); + return; } if (!bsm_ref.getNameAndTypeInfo().getName().equals("bsm")) { - throw new Error("Bad boostrap method name"); + fail("Bad boostrap method name"); + return; } if (!bsm_ref.getNameAndTypeInfo() .getType().equals(asBSMSignatureString())) { - throw new Error("Bad boostrap method type" + + fail("Bad boostrap method type" + bsm_ref.getNameAndTypeInfo().getType() + " " + asBSMSignatureString()); + return; } LineNumberTable_attribute lnt = (LineNumberTable_attribute)ea.attributes.get(Attribute.LineNumberTable); if (lnt == null) { - throw new Error("No LineNumberTable attribute"); + fail("No LineNumberTable attribute"); + return; } if (lnt.line_number_table_length != 3) { - throw new Error("Wrong number of entries in LineNumberTable"); + fail("Wrong number of entries in LineNumberTable"); + return; } } catch (Exception e) { e.printStackTrace(); - throw new Error("error reading " + compiledTest +": " + e); + fail("error reading classfile: " + res.compilationInfo()); + return; } } String asBSMSignatureString() { StringBuilder buf = new StringBuilder(); buf.append("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;"); - for (StaticArgumentKind sak : saks) { - buf.append(sak.bytecodeTypeStr); + for (int i = 0 ; i < arity.arity ; i++) { + buf.append(saks[i].bytecodeTypeStr); } buf.append(")Ljava/lang/invoke/CallSite;"); return buf.toString(); } - class JavaSource extends SimpleJavaFileObject { - - static final String source_template = "import java.lang.invoke.*;\n" + - "class Bootstrap {\n" + - " public static CallSite bsm(MethodHandles.Lookup lookup, " + - "String name, MethodType methodType #SARGS) {\n" + - " return null;\n" + - " }\n" + - "}\n" + - "class Test#ID {\n" + - " void m() { }\n" + - " void test() {\n" + - " Object o = this; // marker statement \n" + - " m();\n" + - " }\n" + - "}"; - - String source; - - JavaSource(int id) { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - source = source_template.replace("#SARGS", asSignatureString()) - .replace("#ID", String.valueOf(id)); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; - } - - String asSignatureString() { - int count = 0; - StringBuilder buf = new StringBuilder(); - for (StaticArgumentKind sak : saks) { - buf.append(","); - buf.append(sak.sourceTypeStr); - buf.append(' '); - buf.append(String.format("x%d", count++)); - } - return buf.toString(); - } - } - class Indifier extends TreeScanner implements TaskListener { MethodSymbol bsm; @@ -475,26 +444,4 @@ return null; } } - - static class DiagChecker - implements javax.tools.DiagnosticListener { - - boolean diagFound; - ArrayList diags = new ArrayList<>(); - - public void report(Diagnostic diagnostic) { - diags.add(diagnostic.getMessage(Locale.getDefault())); - diagFound = true; - } - - String printDiags() { - StringBuilder buf = new StringBuilder(); - for (String s : diags) { - buf.append(s); - buf.append("\n"); - } - return buf.toString(); - } - } - } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lambda/TestLambdaToMethodStats.java --- a/test/tools/javac/lambda/TestLambdaToMethodStats.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/lambda/TestLambdaToMethodStats.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,34 +23,35 @@ /* * @test - * @bug 8013576 + * @bug 8013576 8129962 * @summary Add stat support to LambdaToMethod - * @library ../lib + * @library /tools/javac/lib * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util - * @build JavacTestingAbstractThreadedTest - * @run main/othervm TestLambdaToMethodStats + * @build combo.ComboTestHelper + * @run main TestLambdaToMethodStats */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 - -import java.net.URI; -import java.util.Arrays; +import java.io.IOException; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import com.sun.source.util.JavacTask; import com.sun.tools.javac.api.ClientCodeWrapper; -import com.sun.tools.javac.util.JCDiagnostic; -public class TestLambdaToMethodStats - extends JavacTestingAbstractThreadedTest - implements Runnable { +import com.sun.tools.javac.util.List; +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; - enum ExprKind { +public class TestLambdaToMethodStats extends ComboInstance { + + enum ExprKind implements ComboParameter { LAMBDA("()->null"), MREF1("this::g"), MREF2("this::h"); @@ -60,9 +61,14 @@ ExprKind(String exprStr) { this.exprStr = exprStr; } + + @Override + public String expand(String optParameter) { + return exprStr; + } } - enum TargetKind { + enum TargetKind implements ComboParameter { IMPLICIT(""), SERIALIZABLE("(A & java.io.Serializable)"); @@ -71,124 +77,89 @@ TargetKind(String targetStr) { this.targetStr = targetStr; } + + @Override + public String expand(String optParameter) { + return targetStr; + } + } + + enum DiagnosticKind { + LAMBDA_STAT("compiler.note.lambda.stat", true, false), + MREF_STAT("compiler.note.mref.stat", false, false), + MREF_STAT1("compiler.note.mref.stat.1", false, true); + + String code; + boolean lambda; + boolean bridge; + + DiagnosticKind(String code, boolean lambda, boolean bridge) { + this.code = code; + this.lambda = lambda; + this.bridge = bridge; + } } public static void main(String... args) throws Exception { - for (ExprKind ek : ExprKind.values()) { - for (TargetKind tk : TargetKind.values()) { - pool.execute(new TestLambdaToMethodStats(ek, tk)); - } - } - - checkAfterExec(true); + new ComboTestHelper() + .withDimension("EXPR", (x, expr) -> x.ek = expr, ExprKind.values()) + .withDimension("CAST", (x, target) -> x.tk = target, TargetKind.values()) + .run(TestLambdaToMethodStats::new); } ExprKind ek; TargetKind tk; - JavaSource source; - DiagnosticChecker diagChecker; - - TestLambdaToMethodStats(ExprKind ek, TargetKind tk) { - this.ek = ek; - this.tk = tk; - this.source = new JavaSource(); - this.diagChecker = new DiagnosticChecker(); + String template = "interface A {\n" + + " Object o();\n" + + "}\n" + + "class Test {\n" + + " A a = #{CAST}#{EXPR};\n" + + " Object g() { return null; }\n" + + " Object h(Object... o) { return null; }\n" + + "}"; + + @Override + public void doWork() throws IOException { + check(newCompilationTask() + .withOption("-XDdumpLambdaToMethodStats") + .withSourceFromTemplate(template) + .generate()); } - class JavaSource extends SimpleJavaFileObject { - - String template = "interface A {\n" + - " Object o();\n" + - "}\n" + - "class Test {\n" + - " A a = #C#E;\n" + - " Object g() { return null; }\n" + - " Object h(Object... o) { return null; }\n" + - "}"; - - String source; - - public JavaSource() { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - source = template.replaceAll("#E", ek.exprStr) - .replaceAll("#C", tk.targetStr); + void check(Result res) { + DiagnosticKind diag = null; + boolean altMetafactory = false; + for (DiagnosticKind dk : DiagnosticKind.values()) { + List> jcDiag = res.diagnosticsForKey(dk.code); + if (jcDiag.nonEmpty()) { + diag = dk; + ClientCodeWrapper.DiagnosticSourceUnwrapper dsu = + (ClientCodeWrapper.DiagnosticSourceUnwrapper)jcDiag.head; + altMetafactory = (Boolean)dsu.d.getArgs()[0]; + break; + } } - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; + if (diag == null) { + fail("No diagnostic found; " + res.compilationInfo()); } - } - public void run() { - JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker, - Arrays.asList("-XDdumpLambdaToMethodStats"), - null, Arrays.asList(source)); - try { - ct.generate(); - } catch (Throwable ex) { - throw new - AssertionError("Error thron when analyzing the following source:\n" + - source.getCharContent(true)); - } - check(); - } - - void check() { - checkCount.incrementAndGet(); - - boolean error = diagChecker.lambda != + boolean error = diag.lambda != (ek == ExprKind.LAMBDA); - error |= diagChecker.bridge != + error |= diag.bridge != (ek == ExprKind.MREF2); - error |= diagChecker.altMetafactory != + error |= altMetafactory != (tk == TargetKind.SERIALIZABLE); if (error) { - throw new AssertionError("Bad stat diagnostic found for source\n" + - "lambda = " + diagChecker.lambda + "\n" + - "bridge = " + diagChecker.bridge + "\n" + - "altMF = " + diagChecker.altMetafactory + "\n" + - source.source); - } - } - - static class DiagnosticChecker - implements javax.tools.DiagnosticListener { - - boolean altMetafactory; - boolean bridge; - boolean lambda; - - public void report(Diagnostic diagnostic) { - try { - if (diagnostic.getKind() == Diagnostic.Kind.NOTE) { - switch (diagnostic.getCode()) { - case "compiler.note.lambda.stat": - lambda = true; - break; - case "compiler.note.mref.stat": - lambda = false; - bridge = false; - break; - case "compiler.note.mref.stat.1": - lambda = false; - bridge = true; - break; - default: - throw new AssertionError("unexpected note: " + diagnostic.getCode()); - } - ClientCodeWrapper.DiagnosticSourceUnwrapper dsu = - (ClientCodeWrapper.DiagnosticSourceUnwrapper)diagnostic; - altMetafactory = (Boolean)dsu.d.getArgs()[0]; - } - } catch (RuntimeException t) { - t.printStackTrace(); - throw t; - } + fail("Bad stat diagnostic found for source\n" + + "lambda = " + diag.lambda + "\n" + + "bridge = " + diag.bridge + "\n" + + "altMF = " + altMetafactory + "\n" + + res.compilationInfo()); } } } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lambda/bytecode/TestLambdaBytecode.java --- a/test/tools/javac/lambda/bytecode/TestLambdaBytecode.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/lambda/bytecode/TestLambdaBytecode.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,18 +23,20 @@ /* * @test - * @bug 8009649 + * @bug 8009649 8129962 * @summary Lambda back-end should generate invokespecial for method handles referring to private instance methods - * @library ../../lib + * @library /tools/javac/lib * @modules jdk.jdeps/com.sun.tools.classfile * jdk.compiler/com.sun.tools.javac.api - * @build JavacTestingAbstractThreadedTest - * @run main/othervm TestLambdaBytecode + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + * @run main TestLambdaBytecode */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 - import com.sun.tools.classfile.Attribute; import com.sun.tools.classfile.BootstrapMethods_attribute; import com.sun.tools.classfile.ClassFile; @@ -43,26 +45,22 @@ import com.sun.tools.classfile.Instruction; import com.sun.tools.classfile.Method; -import com.sun.tools.javac.api.JavacTaskImpl; - +import java.io.IOException; +import java.io.InputStream; -import java.io.File; -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Locale; +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; -import javax.tools.Diagnostic; import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import static com.sun.tools.javac.jvm.ClassFile.*; +public class TestLambdaBytecode extends ComboInstance { -public class TestLambdaBytecode - extends JavacTestingAbstractThreadedTest - implements Runnable { + static final int MF_ARITY = 3; + static final String MH_SIG = "()V"; - enum ClassKind { + enum ClassKind implements ComboParameter { CLASS("class"), INTERFACE("interface"); @@ -71,9 +69,14 @@ ClassKind(String classStr) { this.classStr = classStr; } + + @Override + public String expand(String optParameter) { + return classStr; + } } - enum AccessKind { + enum AccessKind implements ComboParameter { PUBLIC("public"), PRIVATE("private"); @@ -82,9 +85,14 @@ AccessKind(String accessStr) { this.accessStr = accessStr; } + + @Override + public String expand(String optParameter) { + return accessStr; + } } - enum StaticKind { + enum StaticKind implements ComboParameter { STATIC("static"), INSTANCE(""); @@ -93,9 +101,14 @@ StaticKind(String staticStr) { this.staticStr = staticStr; } + + @Override + public String expand(String optParameter) { + return staticStr; + } } - enum DefaultKind { + enum DefaultKind implements ComboParameter { DEFAULT("default"), NO_DEFAULT(""); @@ -104,15 +117,10 @@ DefaultKind(String defaultStr) { this.defaultStr = defaultStr; } - } - enum ExprKind { - LAMBDA("Runnable r = ()->{ target(); };"); - - String exprString; - - ExprKind(String exprString) { - this.exprString = exprString; + @Override + public String expand(String optParameter) { + return defaultStr; } } @@ -155,83 +163,53 @@ return true; } } - - String mods() { - StringBuilder buf = new StringBuilder(); - buf.append(ak.accessStr); - buf.append(' '); - buf.append(sk.staticStr); - buf.append(' '); - buf.append(dk.defaultStr); - return buf.toString(); - } } public static void main(String... args) throws Exception { - for (ClassKind ck : ClassKind.values()) { - for (AccessKind ak1 : AccessKind.values()) { - for (StaticKind sk1 : StaticKind.values()) { - for (DefaultKind dk1 : DefaultKind.values()) { - for (AccessKind ak2 : AccessKind.values()) { - for (StaticKind sk2 : StaticKind.values()) { - for (DefaultKind dk2 : DefaultKind.values()) { - for (ExprKind ek : ExprKind.values()) { - pool.execute(new TestLambdaBytecode(ck, ak1, ak2, sk1, sk2, dk1, dk2, ek)); - } - } - } - } - } - } - } - } - - checkAfterExec(); + new ComboTestHelper() + .withDimension("CLASSKIND", (x, ck) -> x.ck = ck, ClassKind.values()) + .withArrayDimension("ACCESS", (x, acc, idx) -> x.accessKinds[idx] = acc, 2, AccessKind.values()) + .withArrayDimension("STATIC", (x, sk, idx) -> x.staticKinds[idx] = sk, 2, StaticKind.values()) + .withArrayDimension("DEFAULT", (x, dk, idx) -> x.defaultKinds[idx] = dk, 2, DefaultKind.values()) + .run(TestLambdaBytecode::new, TestLambdaBytecode::init); } + ClassKind ck; + AccessKind[] accessKinds = new AccessKind[2]; + StaticKind[] staticKinds = new StaticKind[2]; + DefaultKind[] defaultKinds = new DefaultKind[2]; MethodKind mk1, mk2; - ExprKind ek; - DiagChecker dc; - TestLambdaBytecode(ClassKind ck, AccessKind ak1, AccessKind ak2, StaticKind sk1, - StaticKind sk2, DefaultKind dk1, DefaultKind dk2, ExprKind ek) { - mk1 = new MethodKind(ck, ak1, sk1, dk1); - mk2 = new MethodKind(ck, ak2, sk2, dk2); - this.ek = ek; - dc = new DiagChecker(); + void init() { + mk1 = new MethodKind(ck, accessKinds[0], staticKinds[0], defaultKinds[0]); + mk2 = new MethodKind(ck, accessKinds[1], staticKinds[1], defaultKinds[1]); } - public void run() { - int id = checkCount.incrementAndGet(); - JavaSource source = new JavaSource(id); - JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, fm.get(), dc, - null, null, Arrays.asList(source)); - try { - ct.generate(); - } catch (Throwable t) { - t.printStackTrace(); - throw new AssertionError( - String.format("Error thrown when compiling following code\n%s", - source.source)); - } - if (dc.diagFound) { + String source_template = + "#{CLASSKIND} Test {\n" + + " #{ACCESS[0]} #{STATIC[0]} #{DEFAULT[0]} void test() { Runnable r = ()->{ target(); }; }\n" + + " #{ACCESS[1]} #{STATIC[1]} #{DEFAULT[1]} void target() { }\n" + + "}\n"; + + @Override + public void doWork() throws IOException { + verifyBytecode(newCompilationTask() + .withSourceFromTemplate(source_template) + .generate()); + } + + void verifyBytecode(Result> res) { + if (res.hasErrors()) { boolean errorExpected = !mk1.isOK() || !mk2.isOK(); errorExpected |= mk1.isStatic() && !mk2.isStatic(); if (!errorExpected) { - throw new AssertionError( - String.format("Diags found when compiling following code\n%s\n\n%s", - source.source, dc.printDiags())); + fail("Diags found when compiling instance; " + res.compilationInfo()); } return; } - verifyBytecode(id, source); - } - - void verifyBytecode(int id, JavaSource source) { - File compiledTest = new File(String.format("Test%d.class", id)); - try { - ClassFile cf = ClassFile.read(compiledTest); + try (InputStream is = res.get().iterator().next().openInputStream()) { + ClassFile cf = ClassFile.read(is); Method testMethod = null; for (Method m : cf.methods) { if (m.getName(cf.constant_pool).equals("test")) { @@ -240,12 +218,14 @@ } } if (testMethod == null) { - throw new Error("Test method not found"); + fail("Test method not found"); + return; } Code_attribute ea = (Code_attribute)testMethod.attributes.get(Attribute.Code); if (testMethod == null) { - throw new Error("Code attribute for test() method not found"); + fail("Code attribute for test() method not found"); + return; } int bsmIdx = -1; @@ -256,29 +236,34 @@ (CONSTANT_InvokeDynamic_info)cf .constant_pool.get(i.getShort(1)); bsmIdx = indyInfo.bootstrap_method_attr_index; - if (!indyInfo.getNameAndTypeInfo().getType().equals(makeIndyType(id))) { - throw new - AssertionError("type mismatch for CONSTANT_InvokeDynamic_info " + source.source + "\n" + indyInfo.getNameAndTypeInfo().getType() + "\n" + makeIndyType(id)); + if (!indyInfo.getNameAndTypeInfo().getType().equals(makeIndyType())) { + fail("type mismatch for CONSTANT_InvokeDynamic_info " + + res.compilationInfo() + "\n" + indyInfo.getNameAndTypeInfo().getType() + + "\n" + makeIndyType()); + return; } } } if (bsmIdx == -1) { - throw new Error("Missing invokedynamic in generated code"); + fail("Missing invokedynamic in generated code"); + return; } BootstrapMethods_attribute bsm_attr = (BootstrapMethods_attribute)cf .getAttribute(Attribute.BootstrapMethods); if (bsm_attr.bootstrap_method_specifiers.length != 1) { - throw new Error("Bad number of method specifiers " + + fail("Bad number of method specifiers " + "in BootstrapMethods attribute"); + return; } BootstrapMethods_attribute.BootstrapMethodSpecifier bsm_spec = bsm_attr.bootstrap_method_specifiers[0]; if (bsm_spec.bootstrap_arguments.length != MF_ARITY) { - throw new Error("Bad number of static invokedynamic args " + + fail("Bad number of static invokedynamic args " + "in BootstrapMethod attribute"); + return; } CONSTANT_MethodHandle_info mh = @@ -294,74 +279,27 @@ } if (!kindOK) { - throw new Error("Bad invoke kind in implementation method handle"); + fail("Bad invoke kind in implementation method handle"); + return; } if (!mh.getCPRefInfo().getNameAndTypeInfo().getType().toString().equals(MH_SIG)) { - throw new Error("Type mismatch in implementation method handle"); + fail("Type mismatch in implementation method handle"); + return; } } catch (Exception e) { e.printStackTrace(); - throw new Error("error reading " + compiledTest +": " + e); + fail("error reading " + res.compilationInfo() + ": " + e); } } - String makeIndyType(int id) { + + String makeIndyType() { StringBuilder buf = new StringBuilder(); buf.append("("); if (!mk2.isStatic()) { - buf.append(String.format("LTest%d;", id)); + buf.append("LTest;"); } buf.append(")Ljava/lang/Runnable;"); return buf.toString(); } - - static final int MF_ARITY = 3; - static final String MH_SIG = "()V"; - - class JavaSource extends SimpleJavaFileObject { - - static final String source_template = - "#CK Test#ID {\n" + - " #MOD1 void test() { #EK }\n" + - " #MOD2 void target() { }\n" + - "}\n"; - - String source; - - JavaSource(int id) { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - source = source_template.replace("#CK", mk1.ck.classStr) - .replace("#MOD1", mk1.mods()) - .replace("#MOD2", mk2.mods()) - .replace("#EK", ek.exprString) - .replace("#ID", String.valueOf(id)); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; - } - } - - static class DiagChecker - implements javax.tools.DiagnosticListener { - - boolean diagFound; - ArrayList diags = new ArrayList<>(); - - public void report(Diagnostic diagnostic) { - diags.add(diagnostic.getMessage(Locale.getDefault())); - diagFound = true; - } - - String printDiags() { - StringBuilder buf = new StringBuilder(); - for (String s : diags) { - buf.append(s); - buf.append("\n"); - } - return buf.toString(); - } - } - } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lambda/mostSpecific/StructuralMostSpecificTest.java --- a/test/tools/javac/lambda/mostSpecific/StructuralMostSpecificTest.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/lambda/mostSpecific/StructuralMostSpecificTest.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,34 +23,36 @@ /* * @test - * @bug 8003280 8006694 + * @bug 8003280 8006694 8129962 * @summary Add lambda tests * Automatic test for checking correctness of structural most specific test routine * temporarily workaround combo tests are causing time out in several platforms - * @library ../../lib + * @library /tools/javac/lib * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util - * @build JavacTestingAbstractThreadedTest - * @run main/othervm/timeout=600 StructuralMostSpecificTest + * @build combo.ComboTestHelper + + * @run main StructuralMostSpecificTest */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 - -import java.net.URI; -import java.util.Arrays; +import javax.lang.model.element.Element; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import com.sun.source.util.JavacTask; import com.sun.tools.javac.api.ClientCodeWrapper; import com.sun.tools.javac.util.JCDiagnostic; +import com.sun.tools.javac.util.List; +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; -public class StructuralMostSpecificTest - extends JavacTestingAbstractThreadedTest - implements Runnable { +public class StructuralMostSpecificTest extends ComboInstance { - enum RetTypeKind { + enum RetTypeKind implements ComboParameter { SHORT("short"), INT("int"), OBJECT("Object"), @@ -76,9 +78,13 @@ /* INTEGER */ { false , false , true , true , false , false }, /* VOID */ { false , false , false , false , true , true }, /* J_L_VOID */{ false , false , true , false , false , true } }; + + public String expand(String optParameter) { + return retTypeStr; + } } - enum ArgTypeKind { + enum ArgTypeKind implements ComboParameter { SHORT("short"), INT("int"), BOOLEAN("boolean"), @@ -91,9 +97,13 @@ ArgTypeKind(String typeStr) { this.argTypeStr = typeStr; } + + public String expand(String optParameter) { + return argTypeStr; + } } - enum ExceptionKind { + enum ExceptionKind implements ComboParameter { NONE(""), EXCEPTION("throws Exception"), SQL_EXCEPTION("throws java.sql.SQLException"), @@ -104,9 +114,13 @@ ExceptionKind(String exceptionStr) { this.exceptionStr = exceptionStr; } + + public String expand(String optParameter) { + return exceptionStr; + } } - enum LambdaReturnKind { + enum LambdaReturnKind implements ComboParameter { VOID("return;"), SHORT("return (short)0;"), INT("return 0;"), @@ -144,118 +158,72 @@ /* INTEGER */ { false , false , true , false , false }, /* VOID */ { false , false , false , false , false }, /* J_L_VOID */{ true , false , false , false , false } }; - } - public static void main(String... args) throws Exception { - for (LambdaReturnKind lrk : LambdaReturnKind.values()) { - for (RetTypeKind rk1 : RetTypeKind.values()) { - for (RetTypeKind rk2 : RetTypeKind.values()) { - for (ExceptionKind ek1 : ExceptionKind.values()) { - for (ExceptionKind ek2 : ExceptionKind.values()) { - for (ArgTypeKind ak11 : ArgTypeKind.values()) { - for (ArgTypeKind ak12 : ArgTypeKind.values()) { - pool.execute( - new StructuralMostSpecificTest(lrk, rk1, - rk2, ek1, ek2, ak11, ak12)); - } - } - } - } - } - } - } - - checkAfterExec(); - } - - LambdaReturnKind lrk; - RetTypeKind rt1, rt2; - ArgTypeKind ak1, ak2; - ExceptionKind ek1, ek2; - JavaSource source; - DiagnosticChecker diagChecker; - - StructuralMostSpecificTest(LambdaReturnKind lrk, RetTypeKind rt1, RetTypeKind rt2, - ExceptionKind ek1, ExceptionKind ek2, ArgTypeKind ak1, ArgTypeKind ak2) { - this.lrk = lrk; - this.rt1 = rt1; - this.rt2 = rt2; - this.ek1 = ek1; - this.ek2 = ek2; - this.ak1 = ak1; - this.ak2 = ak2; - this.source = new JavaSource(); - this.diagChecker = new DiagnosticChecker(); - } - - class JavaSource extends SimpleJavaFileObject { - - String template = "interface SAM1 {\n" + - " #R1 m(#A1 a1) #E1;\n" + - "}\n" + - "interface SAM2 {\n" + - " #R2 m(#A2 a1) #E2;\n" + - "}\n" + - "class Test {\n" + - " void m(SAM1 s) { }\n" + - " void m(SAM2 s) { }\n" + - " { m((#A1 x)->{ #LR }); }\n" + - "}\n"; - - String source; - - public JavaSource() { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - source = template.replaceAll("#LR", lrk.retStr) - .replaceAll("#R1", rt1.retTypeStr) - .replaceAll("#R2", rt2.retTypeStr) - .replaceAll("#A1", ak1.argTypeStr) - .replaceAll("#A2", ak2.argTypeStr) - .replaceAll("#E1", ek1.exceptionStr) - .replaceAll("#E2", ek2.exceptionStr); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; + public String expand(String optParameter) { + return retStr; } } - public void run() { - JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker, - Arrays.asList("-XDverboseResolution=all,-predef,-internal,-object-init"), - null, Arrays.asList(source)); - try { - ct.analyze(); - } catch (Throwable ex) { - throw new - AssertionError("Error thron when analyzing the following source:\n" + - source.getCharContent(true)); - } - check(); + static final String sourceTemplate = + "interface SAM1 {\n" + + " #{RET[0]} m(#{ARG[0]} a1) #{EX[0]};\n" + + "}\n" + + "interface SAM2 {\n" + + " #{RET[1]} m(#{ARG[1]} a1) #{EX[1]};\n" + + "}\n" + + "class Test {\n" + + " void m(SAM1 s) { }\n" + + " void m(SAM2 s) { }\n" + + " { m((#{ARG[0]} x)->{ #{EXPR} }); }\n" + + "}\n"; + + public static void main(String... args) throws Exception { + new ComboTestHelper() + .withFilter(StructuralMostSpecificTest::hasSameArguments) + .withFilter(StructuralMostSpecificTest::hasCompatibleReturns) + .withFilter(StructuralMostSpecificTest::hasSameOverloadPhase) + .withDimension("EXPR", (x, expr) -> x.lambdaReturnKind = expr, LambdaReturnKind.values()) + .withArrayDimension("RET", (x, ret, idx) -> x.returnType[idx] = ret, 2, RetTypeKind.values()) + .withArrayDimension("EX", 2, ExceptionKind.values()) + .withArrayDimension("ARG", (x, arg, idx) -> x.argumentKind[idx] = arg, 2, ArgTypeKind.values()) + .run(StructuralMostSpecificTest::new); } - void check() { - checkCount.incrementAndGet(); + LambdaReturnKind lambdaReturnKind; + RetTypeKind[] returnType = new RetTypeKind[2]; + ArgTypeKind[] argumentKind = new ArgTypeKind[2]; - if (ak1 != ak2) - return; + boolean hasSameArguments() { + return argumentKind[0] == argumentKind[1]; + } + + boolean hasCompatibleReturns() { + return lambdaReturnKind.compatibleWith(returnType[0]) && + lambdaReturnKind.compatibleWith(returnType[1]); + } - if (!lrk.compatibleWith(rt1) || !lrk.compatibleWith(rt2)) - return; + boolean hasSameOverloadPhase() { + return lambdaReturnKind.needsConversion(returnType[0]) == lambdaReturnKind.needsConversion(returnType[1]); + } - if (lrk.needsConversion(rt1) != lrk.needsConversion(rt2)) - return; + @Override + public void doWork() throws Throwable { + check(newCompilationTask() + .withSourceFromTemplate(sourceTemplate) + .withOption("-XDverboseResolution=all,-predef,-internal,-object-init") + .analyze()); + } - boolean m1MoreSpecific = rt1.moreSpecificThan(rt2); - boolean m2MoreSpecific = rt2.moreSpecificThan(rt1); + void check(Result> result) { + boolean m1MoreSpecific = returnType[0].moreSpecificThan(returnType[1]); + boolean m2MoreSpecific = returnType[1].moreSpecificThan(returnType[0]); boolean ambiguous = (m1MoreSpecific == m2MoreSpecific); - if (ambiguous != diagChecker.ambiguityFound) { - throw new Error("invalid diagnostics for source:\n" + - source.getCharContent(true) + - "\nAmbiguity found: " + diagChecker.ambiguityFound + + if (ambiguous != ambiguityFound(result)) { + fail("invalid diagnostics for combo:\n" + + result.compilationInfo() + "\n" + + "\nAmbiguity found: " + ambiguityFound(result) + "\nm1 more specific: " + m1MoreSpecific + "\nm2 more specific: " + m2MoreSpecific + "\nexpected ambiguity: " + ambiguous); @@ -263,44 +231,32 @@ if (!ambiguous) { String sigToCheck = m1MoreSpecific ? "m(SAM1)" : "m(SAM2)"; - if (!sigToCheck.equals(diagChecker.mostSpecificSig)) { - throw new Error("invalid most specific method selected:\n" + - source.getCharContent(true) + - "\nMost specific found: " + diagChecker.mostSpecificSig + - "\nm1 more specific: " + m1MoreSpecific + - "\nm2 more specific: " + m2MoreSpecific); + if (!sigToCheck.equals(mostSpecificSignature(result))) { + fail("invalid most specific method selected:\n" + + result.compilationInfo() + "\n" + + "\nMost specific found: " + mostSpecificSignature(result) + + "\nm1 more specific: " + m1MoreSpecific + + "\nm2 more specific: " + m2MoreSpecific); } } } - static class DiagnosticChecker - implements javax.tools.DiagnosticListener { - - boolean ambiguityFound; - String mostSpecificSig; + boolean ambiguityFound(Result> result) { + return result.containsKey("compiler.err.ref.ambiguous"); + } - public void report(Diagnostic diagnostic) { - try { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR && - diagnostic.getCode().equals("compiler.err.ref.ambiguous")) { - ambiguityFound = true; - } else if (diagnostic.getKind() == Diagnostic.Kind.NOTE && - diagnostic.getCode() - .equals("compiler.note.verbose.resolve.multi")) { - ClientCodeWrapper.DiagnosticSourceUnwrapper dsu = - (ClientCodeWrapper.DiagnosticSourceUnwrapper)diagnostic; - JCDiagnostic.MultilineDiagnostic mdiag = - (JCDiagnostic.MultilineDiagnostic)dsu.d; - int mostSpecificIndex = (Integer)mdiag.getArgs()[2]; - mostSpecificSig = - ((JCDiagnostic)mdiag.getSubdiagnostics() - .get(mostSpecificIndex)).getArgs()[1].toString(); - } - } catch (RuntimeException t) { - t.printStackTrace(); - throw t; - } + String mostSpecificSignature(Result> result) { + List> rsDiag = + result.diagnosticsForKey("compiler.note.verbose.resolve.multi"); + if (rsDiag.nonEmpty()) { + ClientCodeWrapper.DiagnosticSourceUnwrapper dsu = + (ClientCodeWrapper.DiagnosticSourceUnwrapper)rsDiag.head; + JCDiagnostic.MultilineDiagnostic mdiag = + (JCDiagnostic.MultilineDiagnostic)dsu.d; + int mostSpecificIndex = (Integer)mdiag.getArgs()[2]; + return mdiag.getSubdiagnostics().get(mostSpecificIndex).getArgs()[1].toString(); + } else { + return null; } } - } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lambda/typeInference/combo/TypeInferenceComboTest.java --- a/test/tools/javac/lambda/typeInference/combo/TypeInferenceComboTest.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/lambda/typeInference/combo/TypeInferenceComboTest.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,31 +23,31 @@ /** * @test - * @bug 8003280 8006694 + * @bug 8003280 8006694 8129962 * @summary Add lambda tests * perform automated checks in type inference in lambda expressions * in different contexts * temporarily workaround combo tests are causing time out in several platforms - * @library ../../../lib - * @modules jdk.compiler - * @build JavacTestingAbstractThreadedTest + * @library /tools/javac/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper * @compile TypeInferenceComboTest.java - * @run main/othervm/timeout=360 TypeInferenceComboTest + * @run main TypeInferenceComboTest */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 +import java.io.IOException; -import java.net.URI; -import java.util.Arrays; -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import com.sun.source.util.JavacTask; +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; -public class TypeInferenceComboTest - extends JavacTestingAbstractThreadedTest - implements Runnable { +public class TypeInferenceComboTest extends ComboInstance { enum Context { ASSIGNMENT("SAM#Type s = #LBody;"), METHOD_CALL("#GenericDeclKind void method1(SAM#Type s) { }\n" + @@ -221,82 +221,21 @@ } } - boolean checkTypeInference() { - if (parameterType == TypeKind.VOID) { - if (lambdaBodyType != LambdaBody.RETURN_VOID) - return false; - } - else if (lambdaBodyType != LambdaBody.RETURN_ARG) - return false; - - return true; - } - - String templateStr = "#C\n" + - "interface SAM2 {\n" + - " SAM m();\n" + - "}\n"; - SourceFile samSourceFile = new SourceFile("Sam.java", templateStr) { - public String toString() { - return template.replaceAll("#C", - samKind.getSam(parameterType, returnType)); - } - }; - - SourceFile clientSourceFile = new SourceFile("Client.java", - "class Client { \n" + - " #Context\n" + - "}") { - public String toString() { - return template.replaceAll("#Context", - context.getContext(samKind, samTargetType, keyword, - parameterType, returnType, lambdaKind, parameterKind, - genericDeclKind, lambdaBodyType)); - } - }; - - public void run() { - DiagnosticChecker dc = new DiagnosticChecker(); - JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), dc, - null, null, Arrays.asList(samSourceFile, clientSourceFile)); - try { - ct.analyze(); - } catch (Throwable t) { - processException(t); - } - if (dc.errorFound == checkTypeInference()) { - throw new AssertionError(samSourceFile + "\n\n" + - clientSourceFile + "\n" + parameterType + " " + returnType); - } - } - - abstract class SourceFile extends SimpleJavaFileObject { - - protected String template; - - public SourceFile(String filename, String template) { - super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE); - this.template = template; - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return toString(); - } - - public abstract String toString(); - } - - static class DiagnosticChecker - implements javax.tools.DiagnosticListener { - - boolean errorFound = false; - - public void report(Diagnostic diagnostic) { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { - errorFound = true; - } - } + public static void main(String[] args) { + new ComboTestHelper() + .withFilter(TypeInferenceComboTest::badTestFilter) + .withFilter(TypeInferenceComboTest::redundantTestFilter) + .withDimension("SAM", (x, sam) -> x.samKind = sam, SamKind.values()) + .withDimension("SAMTARGET", (x, target) -> x.samTargetType = target, TypeKind.values()) + .withDimension("PARAMTYPE", (x, param) -> x.parameterType = param, TypeKind.values()) + .withDimension("RETTYPE", (x, ret) -> x.returnType = ret, TypeKind.values()) + .withDimension("CTX", (x, ctx) -> x.context = ctx, Context.values()) + .withDimension("LAMBDABODY", (x, body) -> x.lambdaBodyType = body, LambdaBody.values()) + .withDimension("LAMBDAKIND", (x, lambda) -> x.lambdaKind = lambda, LambdaKind.values()) + .withDimension("PARAMKIND", (x, param) -> x.parameterKind = param, ParameterKind.values()) + .withDimension("KEYWORD", (x, kw) -> x.keyword = kw, Keyword.values()) + .withDimension("GENDECL", (x, gk) -> x.genericDeclKind = gk, GenericDeclKind.values()) + .run(TypeInferenceComboTest::new); } SamKind samKind; @@ -310,84 +249,75 @@ Keyword keyword; GenericDeclKind genericDeclKind; - TypeInferenceComboTest(SamKind sk, TypeKind samTargetT, TypeKind parameterT, - TypeKind returnT, LambdaBody lb, Context c, LambdaKind lk, - ParameterKind pk, Keyword kw, GenericDeclKind gdk) { - samKind = sk; - samTargetType = samTargetT; - parameterType = parameterT; - returnType = returnT; - context = c; - lambdaKind = lk; - parameterKind = pk; - keyword = kw; - lambdaBodyType = lb; - genericDeclKind = gdk; + boolean badTestFilter() { + if (samKind == SamKind.NON_GENERIC) { + return (parameterType != TypeKind.GENERIC && returnType != TypeKind.GENERIC); + } else { + return (samTargetType != TypeKind.VOID && + samTargetType != TypeKind.INT && + samTargetType != TypeKind.GENERIC && + (parameterType == TypeKind.GENERIC || + returnType == TypeKind.GENERIC)); + } } - public static void main(String[] args) throws Exception { - for(Context ct : Context.values()) { - for (TypeKind returnT : TypeKind.values()) { - for (TypeKind parameterT : TypeKind.values()) { - for(LambdaBody lb : LambdaBody.values()) { - for (ParameterKind parameterK : ParameterKind.values()) { - for(LambdaKind lambdaK : LambdaKind.values()) { - for (SamKind sk : SamKind.values()) { - if (sk == SamKind.NON_GENERIC) { - generateNonGenericSAM(ct, returnT, - parameterT, lb, parameterK, - lambdaK, sk); - } - else if (sk == SamKind.GENERIC) { - generateGenericSAM(ct, returnT, - parameterT, lb, parameterK, - lambdaK, sk); - } - } - } - } - } - } - } - } - - checkAfterExec(false); - } - - static void generateNonGenericSAM(Context ct, TypeKind returnT, - TypeKind parameterT, LambdaBody lb, ParameterKind parameterK, - LambdaKind lambdaK, SamKind sk) { - if(parameterT != TypeKind.GENERIC && returnT != TypeKind.GENERIC ) { - pool.execute(new TypeInferenceComboTest(sk, null, parameterT, - returnT, lb, ct, lambdaK, parameterK, null, null)); + boolean redundantTestFilter() { + if (samKind == SamKind.NON_GENERIC) { + return keyword.ordinal() == 0 && samTargetType.ordinal() == 0 && genericDeclKind.ordinal() == 0; + } else { + return context == Context.METHOD_CALL || genericDeclKind.ordinal() == 0; } } - static void generateGenericSAM(Context ct, TypeKind returnT, - TypeKind parameterT, LambdaBody lb, ParameterKind parameterK, - LambdaKind lambdaK, SamKind sk) { - for (Keyword kw : Keyword.values()) { - for (TypeKind samTargetT : TypeKind.values()) { - if(samTargetT != TypeKind.VOID && - samTargetT != TypeKind.INT && - samTargetT != TypeKind.GENERIC && - (parameterT == TypeKind.GENERIC || - returnT == TypeKind.GENERIC)) { - if(ct != Context.METHOD_CALL) { - pool.execute( - new TypeInferenceComboTest(sk, samTargetT, parameterT, - returnT, lb, ct, lambdaK, parameterK, kw, null)); - } else {//Context.METHOD_CALL - for (GenericDeclKind gdk : - GenericDeclKind.values()) - pool.execute( - new TypeInferenceComboTest(sk, samTargetT, - parameterT, returnT, lb, ct, lambdaK, - parameterK, kw, gdk)); - } - } - } - } + String sam_template = "#{SAM}\n" + + "interface SAM2 {\n" + + " SAM m();\n" + + "}\n"; + + + String client_template = "class Client { \n" + + " #{CONTEXT}\n" + + "}"; + + @Override + public void doWork() throws IOException { + Result res = newCompilationTask() + .withSourceFromTemplate("Sam", sam_template, this::samClass) + .withSourceFromTemplate("Client", client_template, this::clientContext) + .analyze(); + + if (res.hasErrors() == checkTypeInference()) { + fail("Unexpected compilation output when compiling instance: " + res.compilationInfo()); + } } + ComboParameter samClass(String parameterName) { + switch (parameterName) { + case "SAM": + return new ComboParameter.Constant<>(samKind.getSam(parameterType, returnType)); + default: + return null; + } + } + + ComboParameter clientContext(String parameterName) { + switch (parameterName) { + case "CONTEXT": + return new ComboParameter.Constant<>(context.getContext(samKind, samTargetType, + keyword, parameterType, returnType, lambdaKind, parameterKind, genericDeclKind, lambdaBodyType)); + default: + return null; + } + } + + boolean checkTypeInference() { + if (parameterType == TypeKind.VOID) { + if (lambdaBodyType != LambdaBody.RETURN_VOID) + return false; + } + else if (lambdaBodyType != LambdaBody.RETURN_ARG) + return false; + + return true; + } } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lib/JavacTestingAbstractThreadedTest.java --- a/test/tools/javac/lib/JavacTestingAbstractThreadedTest.java Thu Sep 03 14:24:46 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2010, 2013, 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. - */ - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import javax.tools.JavaCompiler; -import javax.tools.StandardJavaFileManager; -import javax.tools.ToolProvider; - -/** - * An abstract superclass for threaded tests. - * - * This class will try to read a property named test.concurrency. - * The property can be provided by passing this option to jtreg: - * -javaoption:-Dtest.concurrency=# - * - * If the property is not set the class will use a heuristic to determine the - * maximum number of threads that can be fired to execute a given test. - * - * This code will have to be revisited if jprt starts using concurrency for - * for running jtreg tests. - */ -public abstract class JavacTestingAbstractThreadedTest { - - protected static AtomicInteger numberOfThreads = new AtomicInteger(); - - protected static int getThreadPoolSize() { - Integer testConc = Integer.getInteger("test.concurrency"); - if (testConc != null) return testConc; - int cores = Runtime.getRuntime().availableProcessors(); - numberOfThreads.set(Math.max(2, Math.min(8, cores / 2))); - return numberOfThreads.get(); - } - - protected static void checkAfterExec() throws InterruptedException { - checkAfterExec(true); - }; - - protected static boolean throwAssertionOnError = true; - - protected static boolean printAll = false; - - protected static StringWriter errSWriter = new StringWriter(); - protected static PrintWriter errWriter = new PrintWriter(errSWriter); - - protected static StringWriter outSWriter = new StringWriter(); - protected static PrintWriter outWriter = new PrintWriter(outSWriter); - - protected static void checkAfterExec(boolean printCheckCount) - throws InterruptedException { - pool.shutdown(); - pool.awaitTermination(15, TimeUnit.MINUTES); - if (errCount.get() > 0) { - if (throwAssertionOnError) { - closePrinters(); - System.err.println(errSWriter.toString()); - throw new AssertionError( - String.format("%d errors found", errCount.get())); - } else { - System.err.println( - String.format("%d errors found", errCount.get())); - } - } else if (printCheckCount) { - outWriter.println("Total check executed: " + checkCount.get()); - } - /* - * This output is for supporting debugging. It does not mean that a given - * test had executed that number of threads concurrently. The value printed - * here is the maximum possible amount. - */ - closePrinters(); - if (printAll) { - System.out.println(errSWriter.toString()); - System.out.println(outSWriter.toString()); - } - System.out.println("Total number of threads in thread pool: " + - numberOfThreads.get()); - } - - protected static void closePrinters() { - errWriter.close(); - outWriter.close(); - } - - protected static void processException(Throwable t) { - errCount.incrementAndGet(); - t.printStackTrace(errWriter); - pool.shutdown(); - } - - //number of checks executed - protected static AtomicInteger checkCount = new AtomicInteger(); - - //number of errors found while running combo tests - protected static AtomicInteger errCount = new AtomicInteger(); - - //create default shared JavaCompiler - reused across multiple compilations - protected static JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); - - protected static ExecutorService pool = Executors.newFixedThreadPool( - getThreadPoolSize(), new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - pool.shutdown(); - errCount.incrementAndGet(); - e.printStackTrace(System.err); - } - }); - return t; - } - }); - - /* - * File manager is not thread-safe so it cannot be re-used across multiple - * threads. However we cache per-thread FileManager to avoid excessive - * object creation - */ - protected static final ThreadLocal fm = - new ThreadLocal() { - @Override protected StandardJavaFileManager initialValue() { - return comp.getStandardFileManager(null, null, null); - } - }; - -} diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lib/combo/ComboInstance.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/lib/combo/ComboInstance.java Thu Sep 03 16:13:49 2015 -0700 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2015, 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. + */ + +package combo; + +import javax.tools.StandardJavaFileManager; +import java.util.Optional; + +/** + * This class is the common superclass of all combo test instances. It defines few helper methods + * to build compilation tasks using the shared context object, as well as entry points for + * signalling test failures. + */ +public abstract class ComboInstance> { + + /** The test instance result status. */ + private ResultStatus resultStatus = ResultStatus.PASSED; + + /** The test instance execution environment. */ + private ComboTestHelper.Env env; + + /** + * Entry point for executing a combo test instance; first, the test environment is saved + * in the corresponding field, then the instance is run (see {@link ComboInstance#doWork()}. + * During execution, the result status will be updated to match the test outcome. + */ + final void run(ComboTestHelper.Env env) { + try { + this.env = env; + doWork(); + if (resultStatus.isSuccess()) { + env.info().passCount++; + } + } catch (Throwable ex) { + resultStatus = ResultStatus.ERROR; + env.info().errCount++; + env.info().lastError = Optional.of(ex); + } finally { + this.env = null; + } + } + + /** + * Retrieve a unique ID associated with this test instance. + */ + public int id() { + return env.info().comboCount; + } + + /** + * Retrieve shared file manager. + */ + public StandardJavaFileManager fileManager() { + return env.fileManager(); + } + + /** + * Create a new compilation task using shared compilation context. + */ + protected ComboTask newCompilationTask() { + return new ComboTask(env); + } + + /** + * Main test execution entry point; subclasses must implement this method to define the test + * logic. + */ + protected abstract void doWork() throws Throwable; + + /** + * Report a test failure. + */ + protected void fail() { + //dump some default info (such as dimension bindings) + fail("Combo instance failed; " + env.bindings); + } + + /** + * Report a test failure with corresponding failure message. + */ + protected void fail(String msg) { + resultStatus = ResultStatus.FAILED; + env.info().failCount++; + env.info().lastFailure = Optional.of(msg); + } + + /** + * The status associated with this test instance execution. + */ + enum ResultStatus { + /** Test passed. */ + PASSED(true), + /** Test failed. */ + FAILED(false), + /** Test thrown unexpected error/exception. */ + ERROR(false); + + boolean success; + + ResultStatus(boolean success) { + this.success = success; + } + + boolean isSuccess() { + return success; + } + } +} \ No newline at end of file diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lib/combo/ComboParameter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/lib/combo/ComboParameter.java Thu Sep 03 16:13:49 2015 -0700 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015, 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. + */ + +package combo; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A combo parameter represents an 'hole' in a template that can be replaced with a given string. + * The schema of such holes is defined in {@link ComboParameter#pattern}; the main routine for + * replacing holes in a template scheme is {@link ComboParameter#expandTemplate(String, Resolver)}. + */ +public interface ComboParameter { + + /** + * A combo parameter can take the form: + *

+ * #{MAJOR} + * #{MAJOR.} + * #{MAJOR.MINOR} + *

+ * where MAJOR can be IDENTIFIER or IDENTIFIER[NUMERIC_INDEX] + * and MINOR can be an identifier. + */ + Pattern pattern = Pattern.compile("#\\{([A-Z_][A-Z0-9_]*(?:\\[\\d+\\])?)(?:\\.([A-Z0-9_]*))?\\}"); + + /** + * Entry point for the customizable replacement logic. Subclasses must implement this method to + * specify how a given template hole should be expanded. An optional contextual argument is passed + * in as parameter, to make expansion more flexible. + */ + String expand(String optParameter); + + /** + * Helper class for defining 'constant' combo parameters - i.e. parameters that always expand + * as a given string value - regardless of the context. + */ + class Constant implements ComboParameter { + + D data; + + public Constant(D data) { + this.data = data; + } + + @Override + public String expand(String _unused) { + return String.valueOf(data); + } + } + + /** + * Helper interface used to lookup parameters given a parameter name. + */ + interface Resolver { + ComboParameter lookup(String name); + } + + /** + * Main routine for replacing holes in a template string. Holes are repeatedly searches, their + * corresponding parameters retrieved, and replaced through expansion; since an expansion can + * lead to more holes, the process has to be applied until a fixed point is reached. + */ + static String expandTemplate(String template, Resolver resolver) { + CharSequence in = template; + StringBuffer out = new StringBuffer(); + while (true) { + boolean more = false; + Matcher m = pattern.matcher(in); + while (m.find()) { + String parameterName = m.group(1); + String minor = m.group(2); + ComboParameter parameter = resolver.lookup(parameterName); + if (parameter == null) { + throw new IllegalStateException("Unhandled parameter name " + parameterName); + } + + String replacement = parameter.expand(minor); + more |= pattern.matcher(replacement).find(); + m.appendReplacement(out, replacement); + } + m.appendTail(out); + if (!more) + return out.toString(); + else { + in = out; + out = new StringBuffer(); + } + } + } +} diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lib/combo/ComboTask.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/lib/combo/ComboTask.java Thu Sep 03 16:13:49 2015 -0700 @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2015, 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. + */ + +package combo; + +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.util.JavacTask; +import com.sun.source.util.TaskEvent.Kind; +import com.sun.source.util.TaskListener; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.util.List; +import combo.ComboParameter.Resolver; + +import javax.lang.model.element.Element; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticListener; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import java.io.IOException; +import java.io.Writer; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +/** + * This class represents a compilation task associated with a combo test instance. This is a small + * wrapper around {@link JavacTask} which allows for fluent setup style and which makes use of + * the shared compilation context to speedup performances. + */ +public class ComboTask { + + /** Sources to be compiled in this task. */ + private List sources = List.nil(); + + /** Options associated with this task. */ + private List options = List.nil(); + + /** Diagnostic collector. */ + private DiagnosticCollector diagsCollector = new DiagnosticCollector(); + + /** Output writer. */ + private Writer out; + + /** Listeners associated with this task. */ + private List listeners = List.nil(); + + /** Underlying javac task object. */ + private JavacTask task; + + /** Combo execution environment. */ + private ComboTestHelper.Env env; + + ComboTask(ComboTestHelper.Env env) { + this.env = env; + } + + /** + * Add a new source to this task. + */ + public ComboTask withSource(JavaFileObject comboSource) { + sources = sources.prepend(comboSource); + return this; + } + + /** + * Add a new template source with given name to this task; the template is replaced with + * corresponding combo parameters (as defined in the combo test environment). + */ + public ComboTask withSourceFromTemplate(String name, String template) { + return withSource(new ComboTemplateSource(name, template)); + } + + /** + * Add a new template source with default name ("Test") to this task; the template is replaced with + * corresponding combo parameters (as defined in the combo test environment). + */ + public ComboTask withSourceFromTemplate(String template) { + return withSource(new ComboTemplateSource("Test", template)); + } + + /** + * Add a new template source with given name to this task; the template is replaced with + * corresponding combo parameters (as defined in the combo test environment). A custom resolver + * is used to add combo parameter mappings to the current combo test environment. + */ + public ComboTask withSourceFromTemplate(String name, String template, Resolver resolver) { + return withSource(new ComboTemplateSource(name, template, resolver)); + } + + /** + * Add a new template source with default name ("Test") to this task; the template is replaced with + * corresponding combo parameters (as defined in the combo test environment). A custom resolver + * is used to add combo parameter mappings to the current combo test environment. + */ + public ComboTask withSourceFromTemplate(String template, Resolver resolver) { + return withSource(new ComboTemplateSource("Test", template, resolver)); + } + + /** + * Add a new option to this task. + */ + public ComboTask withOption(String opt) { + options = options.append(opt); + return this; + } + + /** + * Add a set of options to this task. + */ + public ComboTask withOptions(String[] opts) { + for (String opt : opts) { + options = options.append(opt); + } + return this; + } + + /** + * Add a set of options to this task. + */ + public ComboTask withOptions(Iterable opts) { + for (String opt : opts) { + options = options.append(opt); + } + return this; + } + + /** + * Set the output writer associated with this task. + */ + public ComboTask withWriter(Writer out) { + this.out = out; + return this; + } + + /** + * Add a task listener to this task. + */ + public ComboTask withListener(TaskListener listener) { + listeners = listeners.prepend(listener); + return this; + } + + /** + * Parse the sources associated with this task. + */ + public Result> parse() throws IOException { + return new Result<>(getTask().parse()); + } + + /** + * Parse and analyzes the sources associated with this task. + */ + public Result> analyze() throws IOException { + return new Result<>(getTask().analyze()); + } + + /** + * Parse, analyze and perform code generation for the sources associated with this task. + */ + public Result> generate() throws IOException { + return new Result<>(getTask().generate()); + } + + /** + * Fork a new compilation task; if possible the compilation context from previous executions is + * retained (see comments in ReusableContext as to when it's safe to do so); otherwise a brand + * new context is created. + */ + public JavacTask getTask() { + if (task == null) { + ReusableContext context = env.context(); + String opts = options == null ? "" : + StreamSupport.stream(options.spliterator(), false).collect(Collectors.joining()); + context.clear(); + if (!context.polluted && (context.opts == null || context.opts.equals(opts))) { + //we can reuse former context + env.info().ctxReusedCount++; + } else { + env.info().ctxDroppedCount++; + //it's not safe to reuse context - create a new one + context = env.setContext(new ReusableContext()); + } + context.opts = opts; + JavacTask javacTask = ((JavacTool)env.javaCompiler()).getTask(out, env.fileManager(), + diagsCollector, options, null, sources, context); + javacTask.setTaskListener(context); + for (TaskListener l : listeners) { + javacTask.addTaskListener(l); + } + task = javacTask; + } + return task; + } + + /** + * This class is used to help clients accessing the results of a given compilation task. + * Contains several helper methods to inspect diagnostics generated during the task execution. + */ + public class Result { + + /** The underlying compilation results. */ + private final D data; + + public Result(D data) { + this.data = data; + } + + public D get() { + return data; + } + + /** + * Did this task generate any error diagnostics? + */ + public boolean hasErrors() { + return diagsCollector.diagsByKind.containsKey(Diagnostic.Kind.ERROR); + } + + /** + * Did this task generate any warning diagnostics? + */ + public boolean hasWarnings() { + return diagsCollector.diagsByKind.containsKey(Diagnostic.Kind.WARNING); + } + + /** + * Did this task generate any note diagnostics? + */ + public boolean hasNotes() { + return diagsCollector.diagsByKind.containsKey(Diagnostic.Kind.NOTE); + } + + /** + * Did this task generate any diagnostic with given key? + */ + public boolean containsKey(String key) { + return diagsCollector.diagsByKeys.containsKey(key); + } + + /** + * Retrieve the list of diagnostics of a given kind. + */ + public List> diagnosticsForKind(Diagnostic.Kind kind) { + List> diags = diagsCollector.diagsByKind.get(kind); + return diags != null ? diags : List.nil(); + } + + /** + * Retrieve the list of diagnostics with given key. + */ + public List> diagnosticsForKey(String key) { + List> diags = diagsCollector.diagsByKeys.get(key); + return diags != null ? diags : List.nil(); + } + + /** + * Dump useful info associated with this task. + */ + public String compilationInfo() { + return "instance#" + env.info().comboCount + ":[ options = " + options + + ", diagnostics = " + diagsCollector.diagsByKeys.keySet() + + ", dimensions = " + env.bindings + + ", sources = \n" + sources.stream().map(s -> { + try { + return s.getCharContent(true); + } catch (IOException ex) { + return ""; + } + }).collect(Collectors.joining(",")) + "]"; + } + } + + /** + * This class represents a Java source file whose contents are defined in terms of a template + * string. The holes in such template are expanded using corresponding combo parameter + * instances which can be retrieved using a resolver object. + */ + class ComboTemplateSource extends SimpleJavaFileObject { + + String source; + Map localParametersCache = new HashMap<>(); + + protected ComboTemplateSource(String name, String template) { + this(name, template, null); + } + + protected ComboTemplateSource(String name, String template, Resolver resolver) { + super(URI.create("myfo:/" + env.info().comboCount + "/" + name + ".java"), Kind.SOURCE); + source = ComboParameter.expandTemplate(template, pname -> resolveParameter(pname, resolver)); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + + /** + * Combo parameter resolver function. First parameters are looked up in the global environment, + * then the local environment is looked up as a fallback. + */ + ComboParameter resolveParameter(String pname, Resolver resolver) { + //first search the env + ComboParameter parameter = env.parametersCache.get(pname); + if (parameter == null) { + //then lookup local cache + parameter = localParametersCache.get(pname); + if (parameter == null && resolver != null) { + //if still null and we have a custom resolution function, try that + parameter = resolver.lookup(pname); + if (parameter != null) { + //if a match was found, store it in the local cache to aviod redundant recomputation + localParametersCache.put(pname, parameter); + } + } + } + return parameter; + } + } + + /** + * Helper class to collect all diagnostic generated during the execution of a given compilation task. + */ + class DiagnosticCollector implements DiagnosticListener { + + Map>> diagsByKind = new HashMap<>(); + Map>> diagsByKeys = new HashMap<>(); + + public void report(Diagnostic diagnostic) { + List> diags = + diagsByKeys.getOrDefault(diagnostic.getCode(), List.nil()); + diagsByKeys.put(diagnostic.getCode(), diags.prepend(diagnostic)); + Diagnostic.Kind kind = diagnostic.getKind(); + diags = diagsByKind.getOrDefault(kind, List.nil()); + diagsByKind.put(kind, diags.prepend(diagnostic)); + } + } +} diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lib/combo/ComboTestHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/lib/combo/ComboTestHelper.java Thu Sep 03 16:13:49 2015 -0700 @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2015, 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. + */ + +package combo; + +import javax.tools.JavaCompiler; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Stack; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; + + +/** + * An helper class for defining combinatorial (aka "combo" tests). A combo test is made up of one + * or more 'dimensions' - each of which represent a different axis of the test space. For instance, + * if we wanted to test class/interface declaration, one dimension could be the keyword used for + * the declaration (i.e. 'class' vs. 'interface') while another dimension could be the class/interface + * modifiers (i.e. 'public', 'pachake-private' etc.). A combo test consists in running a test instance + * for each point in the test space; that is, for any combination of the combo test dimension: + *

+ * 'public' 'class' + * 'public' interface' + * 'package-private' 'class' + * 'package-private' 'interface' + * ... + *

+ * A new test instance {@link ComboInstance} is created, and executed, after its dimensions have been + * initialized accordingly. Each instance can either pass, fail or throw an unexpected error; this helper + * class defines several policies for how failures should be handled during a combo test execution + * (i.e. should errors be ignored? Do we want the first failure to result in a failure of the whole + * combo test?). + *

+ * Additionally, this helper class allows to specify filter methods that can be used to throw out + * illegal combinations of dimensions - for instance, in the example above, we might want to exclude + * all combinations involving 'protected' and 'private' modifiers, which are disallowed for toplevel + * declarations. + *

+ * While combo tests can be used for a variety of workloads, typically their main task will consist + * in performing some kind of javac compilation. For this purpose, this framework defines an optimized + * javac context {@link ReusableContext} which can be shared across multiple combo instances, + * when the framework detects it's safe to do so. This allows to reduce the overhead associated with + * compiler initialization when the test space is big. + */ +public class ComboTestHelper> { + + /** Failure mode. */ + FailMode failMode = FailMode.FAIL_FAST; + + /** Ignore mode. */ + IgnoreMode ignoreMode = IgnoreMode.IGNORE_NONE; + + /** Combo test instance filter. */ + Optional> optFilter = Optional.empty(); + + /** Combo test dimensions. */ + List> dimensionInfos = new ArrayList<>(); + + /** Combo test stats. */ + Info info = new Info(); + + /** Shared JavaCompiler used across all combo test instances. */ + JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); + + /** Shared file manager used across all combo test instances. */ + StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); + + /** Shared context used across all combo instances. */ + ReusableContext context = new ReusableContext(); + + /** + * Set failure mode for this combo test. + */ + public ComboTestHelper withFailMode(FailMode failMode) { + this.failMode = failMode; + return this; + } + + /** + * Set ignore mode for this combo test. + */ + public ComboTestHelper withIgnoreMode(IgnoreMode ignoreMode) { + this.ignoreMode = ignoreMode; + return this; + } + + /** + * Set a filter for combo test instances to be ignored. + */ + public ComboTestHelper withFilter(Predicate filter) { + optFilter = Optional.of(optFilter.map(filter::and).orElse(filter)); + return this; + } + + /** + * Adds a new dimension to this combo test, with a given name an array of values. + */ + @SafeVarargs + public final ComboTestHelper withDimension(String name, D... dims) { + return withDimension(name, null, dims); + } + + /** + * Adds a new dimension to this combo test, with a given name, an array of values and a + * coresponding setter to be called in order to set the dimension value on the combo test instance + * (before test execution). + */ + @SuppressWarnings("unchecked") + @SafeVarargs + public final ComboTestHelper withDimension(String name, DimensionSetter setter, D... dims) { + dimensionInfos.add(new DimensionInfo<>(name, dims, setter)); + return this; + } + + /** + * Adds a new array dimension to this combo test, with a given base name. This allows to specify + * multiple dimensions at once; the names of the underlying dimensions will be generated from the + * base name, using standard array bracket notation - i.e. "DIM[0]", "DIM[1]", etc. + */ + @SafeVarargs + public final ComboTestHelper withArrayDimension(String name, int size, D... dims) { + return withArrayDimension(name, null, size, dims); + } + + /** + * Adds a new array dimension to this combo test, with a given base name, an array of values and a + * coresponding array setter to be called in order to set the dimension value on the combo test + * instance (before test execution). This allows to specify multiple dimensions at once; the names + * of the underlying dimensions will be generated from the base name, using standard array bracket + * notation - i.e. "DIM[0]", "DIM[1]", etc. + */ + @SafeVarargs + public final ComboTestHelper withArrayDimension(String name, ArrayDimensionSetter setter, int size, D... dims) { + for (int i = 0 ; i < size ; i++) { + dimensionInfos.add(new ArrayDimensionInfo<>(name, dims, i, setter)); + } + return this; + } + + /** + * Returns the stat object associated with this combo test. + */ + public Info info() { + return info; + } + + /** + * Runs this combo test. This will generate the combinatorial explosion of all dimensions, and + * execute a new test instance (built using given supplier) for each such combination. + */ + public void run(Supplier instanceBuilder) { + run(instanceBuilder, null); + } + + /** + * Runs this combo test. This will generate the combinatorial explosion of all dimensions, and + * execute a new test instance (built using given supplier) for each such combination. Before + * executing the test instance entry point, the supplied initialization method is called on + * the test instance; this is useful for ad-hoc test instance initialization once all the dimension + * values have been set. + */ + public void run(Supplier instanceBuilder, Consumer initAction) { + runInternal(0, new Stack<>(), instanceBuilder, Optional.ofNullable(initAction)); + end(); + } + + /** + * Generate combinatorial explosion of all dimension values and create a new test instance + * for each combination. + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + private void runInternal(int index, Stack> bindings, Supplier instanceBuilder, Optional> initAction) { + if (index == dimensionInfos.size()) { + runCombo(instanceBuilder, initAction, bindings); + } else { + DimensionInfo dinfo = dimensionInfos.get(index); + for (Object d : dinfo.dims) { + bindings.push(new DimensionBinding(d, dinfo)); + runInternal(index + 1, bindings, instanceBuilder, initAction); + bindings.pop(); + } + } + } + + /** + * Run a new test instance using supplied dimension bindings. All required setters and initialization + * method are executed before calling the instance main entry point. Also checks if the instance + * is compatible with the specified test filters; if not, the test is simply skipped. + */ + @SuppressWarnings("unchecked") + private void runCombo(Supplier instanceBuilder, Optional> initAction, List> bindings) { + X x = instanceBuilder.get(); + for (DimensionBinding binding : bindings) { + binding.init(x); + } + initAction.ifPresent(action -> action.accept(x)); + info.comboCount++; + if (!optFilter.isPresent() || optFilter.get().test(x)) { + x.run(new Env(bindings)); + if (failMode.shouldStop(ignoreMode, info)) { + end(); + } + } else { + info.skippedCount++; + } + } + + /** + * This method is executed upon combo test completion (either normal or erroneous). Closes down + * all pending resources and dumps useful stats info. + */ + private void end() { + try { + fm.close(); + if (info.hasFailures()) { + throw new AssertionError("Failure when executing combo:" + info.lastFailure.orElse("")); + } else if (info.hasErrors()) { + throw new AssertionError("Unexpected exception while executing combo", info.lastError.get()); + } + } catch (IOException ex) { + throw new AssertionError("Failure when closing down shared file manager; ", ex); + } finally { + info.dump(); + } + } + + /** + * Functional interface for specifying combo test instance setters. + */ + public interface DimensionSetter, D> { + void set(X x, D d); + } + + /** + * Functional interface for specifying combo test instance array setters. The setter method + * receives an extra argument for the index of the array element to be set. + */ + public interface ArrayDimensionSetter, D> { + void set(X x, D d, int index); + } + + /** + * Dimension descriptor; each dimension has a name, an array of value and an optional setter + * to be called on the associated combo test instance. + */ + class DimensionInfo { + String name; + D[] dims; + boolean isParameter; + Optional> optSetter; + + DimensionInfo(String name, D[] dims, DimensionSetter setter) { + this.name = name; + this.dims = dims; + this.optSetter = Optional.ofNullable(setter); + this.isParameter = dims[0] instanceof ComboParameter; + } + } + + /** + * Array dimension descriptor. The dimension name is derived from a base name and an index using + * standard bracket notation; ; the setter accepts an additional 'index' argument to point + * to the array element to be initialized. + */ + class ArrayDimensionInfo extends DimensionInfo { + public ArrayDimensionInfo(String name, D[] dims, int index, ArrayDimensionSetter setter) { + super(String.format("%s[%d]", name, index), dims, + setter != null ? (x, d) -> setter.set(x, d, index) : null); + } + } + + /** + * Failure policies for a combo test run. + */ + public enum FailMode { + /** Combo test fails when first failure is detected. */ + FAIL_FAST, + /** Combo test fails after all instances have been executed. */ + FAIL_AFTER; + + boolean shouldStop(IgnoreMode ignoreMode, Info info) { + switch (this) { + case FAIL_FAST: + return !ignoreMode.canIgnore(info); + default: + return false; + } + } + } + + /** + * Ignore policies for a combo test run. + */ + public enum IgnoreMode { + /** No error or failure is ignored. */ + IGNORE_NONE, + /** Only errors are ignored. */ + IGNORE_ERRORS, + /** Only failures are ignored. */ + IGNORE_FAILURES, + /** Both errors and failures are ignored. */ + IGNORE_ALL; + + boolean canIgnore(Info info) { + switch (this) { + case IGNORE_ERRORS: + return info.failCount == 0; + case IGNORE_FAILURES: + return info.errCount == 0; + case IGNORE_ALL: + return true; + default: + return info.failCount == 0 && info.errCount == 0; + } + } + } + + /** + * A dimension binding. This is essentially a pair of a dimension value and its corresponding + * dimension info. + */ + class DimensionBinding { + D d; + DimensionInfo info; + + DimensionBinding(D d, DimensionInfo info) { + this.d = d; + this.info = info; + } + + void init(X x) { + info.optSetter.ifPresent(setter -> setter.set(x, d)); + } + + public String toString() { + return String.format("(%s -> %s)", info.name, d); + } + } + + /** + * This class is used to keep track of combo tests stats; info such as numbero of failures/errors, + * number of times a context has been shared/dropped are all recorder here. + */ + public static class Info { + int failCount; + int errCount; + int passCount; + int comboCount; + int skippedCount; + int ctxReusedCount; + int ctxDroppedCount; + Optional lastFailure = Optional.empty(); + Optional lastError = Optional.empty(); + + void dump() { + System.err.println(String.format("%d total checks executed", comboCount)); + System.err.println(String.format("%d successes found", passCount)); + System.err.println(String.format("%d failures found", failCount)); + System.err.println(String.format("%d errors found", errCount)); + System.err.println(String.format("%d skips found", skippedCount)); + System.err.println(String.format("%d contexts shared", ctxReusedCount)); + System.err.println(String.format("%d contexts dropped", ctxDroppedCount)); + } + + public boolean hasFailures() { + return failCount != 0; + } + + public boolean hasErrors() { + return errCount != 0; + } + } + + /** + * THe execution environment for a given combo test instance. An environment contains the + * bindings for all the dimensions, along with the combo parameter cache (this is non-empty + * only if one or more dimensions are subclasses of the {@code ComboParameter} interface). + */ + class Env { + List> bindings; + Map parametersCache = new HashMap<>(); + + @SuppressWarnings({"Unchecked", "rawtypes"}) + Env(List> bindings) { + this.bindings = bindings; + for (DimensionBinding binding : bindings) { + if (binding.info.isParameter) { + parametersCache.put(binding.info.name, (ComboParameter)binding.d); + }; + } + } + + Info info() { + return ComboTestHelper.this.info(); + } + + StandardJavaFileManager fileManager() { + return fm; + } + + JavaCompiler javaCompiler() { + return comp; + } + + ReusableContext context() { + return context; + } + + ReusableContext setContext(ReusableContext context) { + return ComboTestHelper.this.context = context; + } + } +} + + + diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/lib/combo/ReusableContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/lib/combo/ReusableContext.java Thu Sep 03 16:13:49 2015 -0700 @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2015, 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. + */ + +package combo; + +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.util.JavacTask; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskEvent.Kind; +import com.sun.source.util.TaskListener; +import com.sun.source.util.TreeScanner; +import com.sun.tools.javac.api.MultiTaskListener; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.comp.Check; +import com.sun.tools.javac.comp.CompileStates; +import com.sun.tools.javac.comp.Enter; +import com.sun.tools.javac.main.Arguments; +import com.sun.tools.javac.main.JavaCompiler; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Log; + +import javax.tools.Diagnostic; +import javax.tools.DiagnosticListener; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import java.util.HashSet; +import java.util.Set; + +/** + * A reusable context is a context that can be used safely across multiple compilation rounds + * arising from execution of a combo test. It achieves reuse by replacing some components + * (most notably JavaCompiler and Log) with reusable counterparts, and by exposing a method + * to cleanup leftovers from previous compilation. + *

+ * There are, however, situations in which reusing the context is not safe: (i) when different + * compilations are using different sets of compiler options (as most option values are cached + * inside components themselves) and (ii) when the compilation unit happens to redefine classes + * in the java.* packages. + */ +class ReusableContext extends Context implements TaskListener { + + Set roots = new HashSet<>(); + + String opts; + boolean polluted = false; + + ReusableContext() { + super(); + put(Log.logKey, ReusableLog.factory); + put(JavaCompiler.compilerKey, ReusableJavaCompiler.factory); + } + + void clear() { + drop(Arguments.argsKey); + drop(DiagnosticListener.class); + drop(Log.outKey); + drop(JavaFileManager.class); + drop(JavacTask.class); + + if (ht.get(Log.logKey) instanceof ReusableLog) { + //log already inited - not first round + ((ReusableLog)Log.instance(this)).clear(); + Enter.instance(this).newRound(); + ((ReusableJavaCompiler)ReusableJavaCompiler.instance(this)).clear(); + Types.instance(this).newRound(); + Check.instance(this).newRound(); + CompileStates.instance(this).clear(); + MultiTaskListener.instance(this).clear(); + + //find if any of the roots have redefined java.* classes + Symtab syms = Symtab.instance(this); + new TreeScanner() { + @Override + public Void visitClass(ClassTree node, Void aVoid) { + Symbol sym = ((JCClassDecl)node).sym; + if (sym != null) { + syms.classes.remove(sym.flatName()); + if (sym.flatName().toString().startsWith("java.")) { + polluted = true; + } + } + return super.visitClass(node, aVoid); + } + }.scan(roots, null); + roots.clear(); + } + } + + @Override + public void finished(TaskEvent e) { + if (e.getKind() == Kind.PARSE) { + roots.add(e.getCompilationUnit()); + } + } + + @Override + public void started(TaskEvent e) { + //do nothing + } + + void drop(Key k) { + ht.remove(k); + } + + void drop(Class c) { + ht.remove(key(c)); + } + + /** + * Reusable JavaCompiler; exposes a method to clean up the component from leftovers associated with + * previous compilations. + */ + static class ReusableJavaCompiler extends JavaCompiler { + + static Factory factory = ReusableJavaCompiler::new; + + ReusableJavaCompiler(Context context) { + super(context); + } + + @Override + public void close() { + //do nothing + } + + void clear() { + newRound(); + } + + @Override + protected void checkReusable() { + //do nothing - it's ok to reuse the compiler + } + } + + /** + * Reusable Log; exposes a method to clean up the component from leftovers associated with + * previous compilations. + */ + static class ReusableLog extends Log { + + static Factory factory = ReusableLog::new; + + Context context; + + ReusableLog(Context context) { + super(context); + this.context = context; + } + + void clear() { + recorded.clear(); + sourceMap.clear(); + nerrors = 0; + nwarnings = 0; + //Set a fake listener that will lazily lookup the context for the 'real' listener. Since + //this field is never updated when a new task is created, we cannot simply reset the field + //or keep old value. This is a hack to workaround the limitations in the current infrastructure. + diagListener = new DiagnosticListener() { + DiagnosticListener cachedListener; + + @Override + @SuppressWarnings("unchecked") + public void report(Diagnostic diagnostic) { + if (cachedListener == null) { + cachedListener = context.get(DiagnosticListener.class); + } + cachedListener.report(diagnostic); + } + }; + } + } +} diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/multicatch/7030606/DisjunctiveTypeWellFormednessTest.java --- a/test/tools/javac/multicatch/7030606/DisjunctiveTypeWellFormednessTest.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/multicatch/7030606/DisjunctiveTypeWellFormednessTest.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,30 +23,31 @@ /* * @test - * @bug 7030606 8006694 + * @bug 7030606 8006694 8129962 * @summary Project-coin: multi-catch types should be pairwise disjoint * temporarily workaround combo tests are causing time out in several platforms - * @library ../../lib - * @modules jdk.compiler - * @build JavacTestingAbstractThreadedTest - * @run main/othervm DisjunctiveTypeWellFormednessTest + * @library /tools/javac/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + * @run main DisjunctiveTypeWellFormednessTest */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 +import java.io.IOException; -import java.net.URI; -import java.util.Arrays; -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import com.sun.source.util.JavacTask; +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; -public class DisjunctiveTypeWellFormednessTest - extends JavacTestingAbstractThreadedTest - implements Runnable { - enum Alternative { +public class DisjunctiveTypeWellFormednessTest extends ComboInstance { + + enum Alternative implements ComboParameter { EXCEPTION("Exception"), RUNTIME_EXCEPTION("RuntimeException"), IO_EXCEPTION("java.io.IOException"), @@ -55,21 +56,10 @@ String exceptionStr; - private Alternative(String exceptionStr) { + Alternative(String exceptionStr) { this.exceptionStr = exceptionStr; } - static String makeDisjunctiveType(Alternative... alternatives) { - StringBuilder buf = new StringBuilder(); - String sep = ""; - for (Alternative alternative : alternatives) { - buf.append(sep); - buf.append(alternative.exceptionStr); - sep = "|"; - } - return buf.toString(); - } - boolean disjoint(Alternative that) { return disjoint[this.ordinal()][that.ordinal()]; } @@ -82,135 +72,85 @@ /*FileNotFoundException*/ { false, true, false, false, true }, /*IllegalArgumentException*/ { false, false, true, true, false } }; + + @Override + public String expand(String optParameter) { + return exceptionStr; + } } - enum Arity { - ONE(1), - TWO(2), - THREE(3), - FOUR(4), - FIVE(5); + enum Arity implements ComboParameter { + ONE(1, "#{TYPE[0]}"), + TWO(2, "#{TYPE[0]} | #{TYPE[1]}"), + THREE(3, "#{TYPE[0]} | #{TYPE[1]} | #{TYPE[2]}"), + FOUR(4, "#{TYPE[0]} | #{TYPE[1]} | #{TYPE[2]} | #{TYPE[3]}"), + FIVE(5, "#{TYPE[0]} | #{TYPE[1]} | #{TYPE[2]} | #{TYPE[3]} | #{TYPE[4]}"); int n; + String arityTemplate; - private Arity(int n) { + Arity(int n, String arityTemplate) { this.n = n; + this.arityTemplate = arityTemplate; + } + + @Override + public String expand(String optParameter) { + return arityTemplate; } } public static void main(String... args) throws Exception { - for (Arity arity : Arity.values()) { - for (Alternative a1 : Alternative.values()) { - if (arity == Arity.ONE) { - pool.execute(new DisjunctiveTypeWellFormednessTest(a1)); - continue; - } - for (Alternative a2 : Alternative.values()) { - if (arity == Arity.TWO) { - pool.execute(new DisjunctiveTypeWellFormednessTest(a1, a2)); - continue; - } - for (Alternative a3 : Alternative.values()) { - if (arity == Arity.THREE) { - pool.execute(new DisjunctiveTypeWellFormednessTest(a1, a2, a3)); - continue; - } - for (Alternative a4 : Alternative.values()) { - if (arity == Arity.FOUR) { - pool.execute(new DisjunctiveTypeWellFormednessTest(a1, a2, a3, a4)); - continue; - } - for (Alternative a5 : Alternative.values()) { - pool.execute(new DisjunctiveTypeWellFormednessTest(a1, a2, a3, a4, a5)); - } - } - } + new ComboTestHelper() + .withFilter(DisjunctiveTypeWellFormednessTest::arityFilter) + .withDimension("CTYPE", (x, arity) -> x.arity = arity, Arity.values()) + .withArrayDimension("TYPE", (x, type, idx) -> x.alternatives[idx] = type, 5, Alternative.values()) + .run(DisjunctiveTypeWellFormednessTest::new); + } + + Arity arity; + Alternative[] alternatives = new Alternative[5]; + + boolean arityFilter() { + for (int i = arity.n; i < alternatives.length ; i++) { + if (alternatives[i].ordinal() != 0) { + return false; + } + } + return true; + } + + String template = "class Test {\n" + + "void test() {\n" + + "try {} catch (#{CTYPE} e) {}\n" + + "}\n" + + "}\n"; + + @Override + public void doWork() throws IOException { + check(newCompilationTask() + .withSourceFromTemplate(template) + .analyze()); + } + + void check(Result res) { + + int non_disjoint = 0; + for (int i = 0 ; i < arity.n ; i++) { + for (int j = 0 ; j < i ; j++) { + if (!alternatives[i].disjoint(alternatives[j])) { + non_disjoint++; + break; } } } - checkAfterExec(false); - } - - Alternative[] alternatives; - JavaSource source; - DiagnosticChecker diagChecker; - - DisjunctiveTypeWellFormednessTest(Alternative... alternatives) { - this.alternatives = alternatives; - this.source = new JavaSource(); - this.diagChecker = new DiagnosticChecker(); - } - - class JavaSource extends SimpleJavaFileObject { - - String template = "class Test {\n" + - "void test() {\n" + - "try {} catch (#T e) {}\n" + - "}\n" + - "}\n"; - - String source; - - public JavaSource() { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - source = template.replace("#T", Alternative.makeDisjunctiveType(alternatives)); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; + int foundErrs = res.diagnosticsForKey("compiler.err.multicatch.types.must.be.disjoint").size(); + if (non_disjoint != foundErrs) { + fail("invalid diagnostics for source:\n" + + res.compilationInfo() + + "\nFound errors: " + foundErrs + + "\nExpected errors: " + non_disjoint); } } - - @Override - public void run() { - JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker, - null, null, Arrays.asList(source)); - try { - ct.analyze(); - } catch (Throwable t) { - processException(t); - return; - } - check(); - } - - void check() { - - int non_disjoint = 0; - int i = 0; - for (Alternative a1 : alternatives) { - int j = 0; - for (Alternative a2 : alternatives) { - if (i == j) continue; - if (!a1.disjoint(a2)) { - non_disjoint++; - break; - } - j++; - } - i++; - } - - if (non_disjoint != diagChecker.errorsFound) { - throw new Error("invalid diagnostics for source:\n" + - source.getCharContent(true) + - "\nFound errors: " + diagChecker.errorsFound + - "\nExpected errors: " + non_disjoint); - } - } - - static class DiagnosticChecker implements javax.tools.DiagnosticListener { - - int errorsFound; - - public void report(Diagnostic diagnostic) { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR && - diagnostic.getCode().startsWith("compiler.err.multicatch.types.must.be.disjoint")) { - errorsFound++; - } - } - } - } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/parser/8134007/T8134007.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/parser/8134007/T8134007.java Thu Sep 03 16:13:49 2015 -0700 @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2015, 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 8134007 + * @summary Improve string folding + * @compile T8134007.java + */ +class T8134007 { + String v = ""; + + //interleaved non-literals + String s1 = "Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v; + + //heading non-literal + String s2 = v + "Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"; + + //trailing non-literal + String s3 = "Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v; +} diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/resolve/BitWiseOperators.java --- a/test/tools/javac/resolve/BitWiseOperators.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/resolve/BitWiseOperators.java Thu Sep 03 16:13:49 2015 -0700 @@ -21,47 +21,30 @@ * questions. */ -/**@test - * @bug 8082311 +/* + * @test + * @bug 8082311 8129962 * @summary Verify that bitwise operators don't allow to mix numeric and boolean operands. * @library ../lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + * @run main BitWiseOperators */ import com.sun.tools.javac.util.StringUtils; -import java.net.URI; -import java.util.Arrays; -import java.util.List; -import javax.tools.DiagnosticCollector; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -public class BitWiseOperators extends JavacTestingAbstractThreadedTest { - public static void main(String... args) { - new BitWiseOperators().run(); - } +import java.io.IOException; - void run() { - for (TYPE type1 : TYPE.values()) { - for (OPERATION op : OPERATION.values()) { - for (TYPE type2 : TYPE.values()) { - runTest(type1, op, type2); - } - } - } - } +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; - void runTest(TYPE type1, OPERATION op, TYPE type2) { - DiagnosticCollector dc = new DiagnosticCollector<>(); - List files = Arrays.asList(new JavaSource(type1, op, type2)); - comp.getTask(null, null, dc, null, null, files).call(); - if (dc.getDiagnostics().isEmpty() ^ TYPE.compatible(type1, type2)) { - throw new AssertionError("Unexpected behavior. Type1: " + type1 + - "; type2: " + type2 + - "; diagnostics: " + dc.getDiagnostics()); - } - } - enum TYPE { +public class BitWiseOperators extends ComboInstance { + + enum OperandType implements ComboParameter { BYTE, CHAR, SHORT, @@ -69,45 +52,57 @@ LONG, BOOLEAN; - public static boolean compatible(TYPE op1, TYPE op2) { + public static boolean compatible(OperandType op1, OperandType op2) { return !(op1 == BOOLEAN ^ op2 == BOOLEAN); } + + @Override + public String expand(String optParameter) { + return StringUtils.toLowerCase(name()); + } } - enum OPERATION { + enum OperatorKind implements ComboParameter { BITAND("&"), BITOR("|"), BITXOR("^"); String op; - private OPERATION(String op) { + OperatorKind(String op) { this.op = op; } - } - - class JavaSource extends SimpleJavaFileObject { - - String template = "class Test {\n" + - " public Object test(#TYPE1 var1, #TYPE2 var2) {\n" + - " return var1 #OP var2;\n" + - " }\n" + - "}"; - - String source; - - public JavaSource(TYPE type1, OPERATION op, TYPE type2) { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - source = template.replaceAll("#TYPE1", StringUtils.toLowerCase(type1.name())) - .replaceAll("#OP", StringUtils.toLowerCase(op.op)) - .replaceAll("#TYPE2", StringUtils.toLowerCase(type2.name())); - } - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; + public String expand(String optParameter) { + return op; } } + public static void main(String... args) { + new ComboTestHelper() + .withArrayDimension("TYPE", (x, type, idx) -> x.opTypes[idx] = type, 2, OperandType.values()) + .withDimension("OP", OperatorKind.values()) + .run(BitWiseOperators::new); + } + + OperandType[] opTypes = new OperandType[2]; + + String template = "class Test {\n" + + " public Object test(#{TYPE[0]} var1, #{TYPE[1]} var2) {\n" + + " return var1 #{OP} var2;\n" + + " }\n" + + "}"; + + @Override + public void doWork() throws IOException { + Result res = newCompilationTask() + .withSourceFromTemplate(template) + .analyze(); + if (res.hasErrors() == OperandType.compatible(opTypes[0], opTypes[1])) { + fail("Unexpected behavior. Type1: " + opTypes[0] + + "; type2: " + opTypes[1] + + "; " + res.compilationInfo()); + } + } } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/types/ScopeListenerTest.java --- a/test/tools/javac/types/ScopeListenerTest.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/types/ScopeListenerTest.java Thu Sep 03 16:13:49 2015 -0700 @@ -29,6 +29,7 @@ */ import com.sun.tools.javac.code.Scope; +import com.sun.tools.javac.code.Scope.ScopeListenerList; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.code.Types; @@ -53,20 +54,14 @@ types.membersClosure(syms.stringType, true); types.membersClosure(syms.stringType, false); - Field listenersField = Scope.class.getDeclaredField("listeners"); - - listenersField.setAccessible(true); - - int listenerCount = - ((Collection) listenersField.get(syms.stringType.tsym.members())).size(); + int listenerCount = listenerCount(syms.stringType.tsym.members()); for (int i = 0; i < 100; i++) { types.membersClosure(syms.stringType, true); types.membersClosure(syms.stringType, false); } - int newListenerCount - = ((Collection) listenersField.get(syms.stringType.tsym.members())).size(); + int newListenerCount = listenerCount(syms.stringType.tsym.members()); if (listenerCount != newListenerCount) { throw new AssertionError("Orig listener count: " + listenerCount + @@ -79,4 +74,12 @@ ; } + int listenerCount(Scope s) throws ReflectiveOperationException { + Field listenersListField = Scope.class.getDeclaredField("listeners"); + listenersListField.setAccessible(true); + Field listenersField = ScopeListenerList.class.getDeclaredField("listeners"); + listenersField.setAccessible(true); + return ((Collection)listenersField.get(listenersListField.get(s))).size(); + } + } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/varargs/7042566/T7042566.java --- a/test/tools/javac/varargs/7042566/T7042566.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/varargs/7042566/T7042566.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,31 +23,25 @@ /* * @test - * @bug 7042566 8006694 + * @bug 7042566 8006694 8129962 * @summary Unambiguous varargs method calls flagged as ambiguous * temporarily workaround combo tests are causing time out in several platforms - * @library ../../lib + * @library /tools/javac/lib * @modules jdk.jdeps/com.sun.tools.classfile + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util - * @build JavacTestingAbstractThreadedTest - * @run main/othervm T7042566 + * @build combo.ComboTestHelper + * @run main T7042566 */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 +import java.io.IOException; +import java.io.InputStream; +import javax.tools.JavaFileObject; -import java.io.File; -import java.net.URI; -import java.util.Arrays; -import java.util.Locale; -import java.util.concurrent.atomic.AtomicInteger; -import javax.tools.Diagnostic; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import javax.tools.ToolProvider; - -import com.sun.source.util.JavacTask; import com.sun.tools.classfile.Instruction; import com.sun.tools.classfile.Attribute; import com.sun.tools.classfile.ClassFile; @@ -56,145 +50,12 @@ import com.sun.tools.classfile.Method; import com.sun.tools.javac.util.List; -public class T7042566 - extends JavacTestingAbstractThreadedTest - implements Runnable { - - VarargsMethod m1; - VarargsMethod m2; - TypeConfiguration actuals; - - T7042566(TypeConfiguration m1_conf, TypeConfiguration m2_conf, - TypeConfiguration actuals) { - this.m1 = new VarargsMethod(m1_conf); - this.m2 = new VarargsMethod(m2_conf); - this.actuals = actuals; - } - - @Override - public void run() { - int id = checkCount.incrementAndGet(); - final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); - JavaSource source = new JavaSource(id); - ErrorChecker ec = new ErrorChecker(); - JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), ec, - null, null, Arrays.asList(source)); - ct.call(); - check(source, ec, id); - } - - void check(JavaSource source, ErrorChecker ec, int id) { - boolean resolutionError = false; - VarargsMethod selectedMethod = null; - - boolean m1_applicable = m1.isApplicable(actuals); - boolean m2_applicable = m2.isApplicable(actuals); - - if (!m1_applicable && !m2_applicable) { - resolutionError = true; - } else if (m1_applicable && m2_applicable) { - //most specific - boolean m1_moreSpecific = m1.isMoreSpecificThan(m2); - boolean m2_moreSpecific = m2.isMoreSpecificThan(m1); - - resolutionError = m1_moreSpecific == m2_moreSpecific; - selectedMethod = m1_moreSpecific ? m1 : m2; - } else { - selectedMethod = m1_applicable ? - m1 : m2; - } - - if (ec.errorFound != resolutionError) { - throw new Error("invalid diagnostics for source:\n" + - source.getCharContent(true) + - "\nExpected resolution error: " + resolutionError + - "\nFound error: " + ec.errorFound + - "\nCompiler diagnostics:\n" + ec.printDiags()); - } else if (!resolutionError) { - verifyBytecode(selectedMethod, source, id); - } - } +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; - void verifyBytecode(VarargsMethod selected, JavaSource source, int id) { - bytecodeCheckCount.incrementAndGet(); - File compiledTest = new File(String.format("Test%d.class", id)); - try { - ClassFile cf = ClassFile.read(compiledTest); - Method testMethod = null; - for (Method m : cf.methods) { - if (m.getName(cf.constant_pool).equals("test")) { - testMethod = m; - break; - } - } - if (testMethod == null) { - throw new Error("Test method not found"); - } - Code_attribute ea = - (Code_attribute)testMethod.attributes.get(Attribute.Code); - if (testMethod == null) { - throw new Error("Code attribute for test() method not found"); - } - - for (Instruction i : ea.getInstructions()) { - if (i.getMnemonic().equals("invokevirtual")) { - int cp_entry = i.getUnsignedShort(1); - CONSTANT_Methodref_info methRef = - (CONSTANT_Methodref_info)cf.constant_pool.get(cp_entry); - String type = methRef.getNameAndTypeInfo().getType(); - String sig = selected.parameterTypes.bytecodeSigStr; - if (!type.contains(sig)) { - throw new Error("Unexpected type method call: " + - type + "" + - "\nfound: " + sig + - "\n" + source.getCharContent(true)); - } - break; - } - } - } catch (Exception e) { - e.printStackTrace(); - throw new Error("error reading " + compiledTest +": " + e); - } - } - - class JavaSource extends SimpleJavaFileObject { - - static final String source_template = "class Test#ID {\n" + - " #V1\n" + - " #V2\n" + - " void test() { m(#E); }\n" + - "}"; - - String source; - - public JavaSource(int id) { - super(URI.create(String.format("myfo:/Test%d.java", id)), - JavaFileObject.Kind.SOURCE); - source = source_template.replaceAll("#V1", m1.toString()) - .replaceAll("#V2", m2.toString()) - .replaceAll("#E", actuals.expressionListStr) - .replaceAll("#ID", String.valueOf(id)); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; - } - } - - public static void main(String... args) throws Exception { - for (TypeConfiguration tconf1 : TypeConfiguration.values()) { - for (TypeConfiguration tconf2 : TypeConfiguration.values()) { - for (TypeConfiguration tconf3 : TypeConfiguration.values()) { - pool.execute(new T7042566(tconf1, tconf2, tconf3)); - } - } - } - - outWriter.println("Bytecode checks made: " + bytecodeCheckCount.get()); - checkAfterExec(); - } +public class T7042566 extends ComboInstance { enum TypeKind { OBJECT("Object", "(Object)null", "Ljava/lang/Object;"), @@ -216,7 +77,7 @@ } } - enum TypeConfiguration { + enum TypeConfiguration implements ComboParameter { A(TypeKind.OBJECT), B(TypeKind.STRING), AA(TypeKind.OBJECT, TypeKind.OBJECT), @@ -237,7 +98,7 @@ String parameterListStr; String bytecodeSigStr; - private TypeConfiguration(TypeKind... typeKindList) { + TypeConfiguration(TypeKind... typeKindList) { this.typeKindList = List.from(typeKindList); expressionListStr = asExpressionList(); parameterListStr = asParameterList(); @@ -284,6 +145,11 @@ } return buf.toString(); } + + @Override + public String expand(String optParameter) { + return expressionListStr; + } } static class VarargsMethod { @@ -333,31 +199,119 @@ } } - static class ErrorChecker - implements javax.tools.DiagnosticListener { + public static void main(String[] args) { + new ComboTestHelper() + .withArrayDimension("SIG", (x, sig, idx) -> x.methodSignatures[idx] = sig, 2, TypeConfiguration.values()) + .withDimension("ACTUALS", (x, actuals) -> x.actuals = actuals, TypeConfiguration.values()) + .run(T7042566::new, T7042566::setup); + } - boolean errorFound; - List errDiags = List.nil(); + VarargsMethod m1; + VarargsMethod m2; + TypeConfiguration[] methodSignatures = new TypeConfiguration[2]; + TypeConfiguration actuals; + + void setup() { + this.m1 = new VarargsMethod(methodSignatures[0]); + this.m2 = new VarargsMethod(methodSignatures[1]); + } - public void report(Diagnostic diagnostic) { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { - errDiags = errDiags - .append(diagnostic.getMessage(Locale.getDefault())); - errorFound = true; - } - } + final String source_template = "class Test {\n" + + " #{METH.1}\n" + + " #{METH.2}\n" + + " void test() { m(#{ACTUALS}); }\n" + + "}"; - String printDiags() { - StringBuilder buf = new StringBuilder(); - for (String s : errDiags) { - buf.append(s); - buf.append("\n"); - } - return buf.toString(); + @Override + public void doWork() throws IOException { + check(newCompilationTask() + .withSourceFromTemplate(source_template, this::getMethodDecl) + .generate()); + } + + ComboParameter getMethodDecl(String parameterName) { + switch (parameterName) { + case "METH": return optParameter -> { + return optParameter.equals("1") ? + m1.toString() : m2.toString(); + }; + default: + return null; } } - //number of bytecode checks made while running combo tests - static AtomicInteger bytecodeCheckCount = new AtomicInteger(); + void check(Result> res) { + boolean resolutionError = false; + VarargsMethod selectedMethod = null; + + boolean m1_applicable = m1.isApplicable(actuals); + boolean m2_applicable = m2.isApplicable(actuals); + + if (!m1_applicable && !m2_applicable) { + resolutionError = true; + } else if (m1_applicable && m2_applicable) { + //most specific + boolean m1_moreSpecific = m1.isMoreSpecificThan(m2); + boolean m2_moreSpecific = m2.isMoreSpecificThan(m1); + + resolutionError = m1_moreSpecific == m2_moreSpecific; + selectedMethod = m1_moreSpecific ? m1 : m2; + } else { + selectedMethod = m1_applicable ? + m1 : m2; + } + + if (res.hasErrors() != resolutionError) { + fail("invalid diagnostics for source:\n" + + res.compilationInfo() + + "\nExpected resolution error: " + resolutionError + + "\nFound error: " + res.hasErrors()); + } else if (!resolutionError) { + verifyBytecode(res, selectedMethod); + } + } + void verifyBytecode(Result> res, VarargsMethod selected) { + try (InputStream is = res.get().iterator().next().openInputStream()) { + ClassFile cf = ClassFile.read(is); + Method testMethod = null; + for (Method m : cf.methods) { + if (m.getName(cf.constant_pool).equals("test")) { + testMethod = m; + break; + } + } + if (testMethod == null) { + fail("Test method not found"); + return; + } + Code_attribute ea = + (Code_attribute)testMethod.attributes.get(Attribute.Code); + if (testMethod == null) { + fail("Code attribute for test() method not found"); + return; + } + + for (Instruction i : ea.getInstructions()) { + if (i.getMnemonic().equals("invokevirtual")) { + int cp_entry = i.getUnsignedShort(1); + CONSTANT_Methodref_info methRef = + (CONSTANT_Methodref_info)cf.constant_pool.get(cp_entry); + String type = methRef.getNameAndTypeInfo().getType(); + String sig = selected.parameterTypes.bytecodeSigStr; + if (!type.contains(sig)) { + fail("Unexpected type method call: " + + type + "" + + "\nfound: " + sig + + "\n" + res.compilationInfo()); + return; + } + break; + } + } + } catch (Exception e) { + e.printStackTrace(); + fail("error reading classfile; " + res.compilationInfo() +": " + e); + } + } } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/varargs/warning/Warn4.java --- a/test/tools/javac/varargs/warning/Warn4.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/varargs/warning/Warn4.java Thu Sep 03 16:13:49 2015 -0700 @@ -23,40 +23,39 @@ /** * @test - * @bug 6945418 6993978 8006694 7196160 + * @bug 6945418 6993978 8006694 7196160 8129962 * @summary Project Coin: Simplified Varargs Method Invocation * temporarily workaround combo tests are causing time out in several platforms - * @author mcimadamore - * @library ../../lib - * @modules jdk.compiler - * @build JavacTestingAbstractThreadedTest - * @run main/othervm Warn4 + * @library /tools/javac/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + * @run main Warn4 */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 - -import java.net.URI; -import java.util.Arrays; +import java.io.IOException; import java.util.Set; import java.util.HashSet; import javax.tools.Diagnostic; -import javax.tools.JavaCompiler; +import javax.tools.Diagnostic.Kind; import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import javax.tools.ToolProvider; -import com.sun.source.util.JavacTask; -public class Warn4 - extends JavacTestingAbstractThreadedTest - implements Runnable { +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; + +public class Warn4 extends ComboInstance { final static Warning[] error = null; final static Warning[] none = new Warning[] {}; final static Warning[] vararg = new Warning[] { Warning.VARARGS }; final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED }; - final static Warning[] both = - new Warning[] { Warning.VARARGS, Warning.UNCHECKED }; + final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED }; enum Warning { UNCHECKED("generic.array.creation"), @@ -105,7 +104,7 @@ } } - enum TrustMe { + enum TrustMe implements ComboParameter { DONT_TRUST(""), TRUST("@java.lang.SafeVarargs"); @@ -114,9 +113,14 @@ TrustMe(String anno) { this.anno = anno; } + + @Override + public String expand(String optParameter) { + return anno; + } } - enum ModifierKind { + enum ModifierKind implements ComboParameter { NONE(" "), FINAL("final "), STATIC("static "), @@ -127,9 +131,14 @@ ModifierKind(String mod) { this.mod = mod; } + + @Override + public String expand(String optParameter) { + return mod; + } } - enum SuppressLevel { + enum SuppressLevel implements ComboParameter { NONE(""), UNCHECKED("unchecked"); @@ -139,21 +148,22 @@ this.lint = lint; } - String getSuppressAnno() { + @Override + public String expand(String optParameter) { return "@SuppressWarnings(\"" + lint + "\")"; } } - enum Signature { - UNBOUND("void #name(List#arity arg) { #body }", + enum Signature implements ComboParameter { + UNBOUND("void #NAME(List#ARITY arg) { #BODY }", new Warning[][] {none, none, none, none, error}), - INVARIANT_TVAR(" void #name(List#arity arg) { #body }", + INVARIANT_TVAR(" void #NAME(List#ARITY arg) { #BODY }", new Warning[][] {both, both, error, both, error}), - TVAR(" void #name(Z#arity arg) { #body }", + TVAR(" void #NAME(Z#ARITY arg) { #BODY }", new Warning[][] {both, both, both, both, vararg}), - INVARIANT("void #name(List#arity arg) { #body }", + INVARIANT("void #NAME(List#ARITY arg) { #BODY }", new Warning[][] {error, error, error, both, error}), - UNPARAMETERIZED("void #name(String#arity arg) { #body }", + UNPARAMETERIZED("void #NAME(String#ARITY arg) { #BODY }", new Warning[][] {error, error, error, error, none}); String template; @@ -177,130 +187,85 @@ return warnings[other.ordinal()] == vararg || warnings[other.ordinal()] == both; } + + @Override + public String expand(String optParameter) { + if (optParameter.equals("CLIENT")) { + return template.replaceAll("#ARITY", "") + .replaceAll("#NAME", "test") + .replaceAll("#BODY", "m(arg)"); + } else { + return template.replaceAll("#ARITY", "...") + .replaceAll("#NAME", "m") + .replaceAll("#BODY", ""); + } + } } - public static void main(String... args) throws Exception { - for (SourceLevel sourceLevel : SourceLevel.values()) { - for (TrustMe trustMe : TrustMe.values()) { - for (SuppressLevel suppressLevelClient : SuppressLevel.values()) { - for (SuppressLevel suppressLevelDecl : SuppressLevel.values()) { - for (ModifierKind modKind : ModifierKind.values()) { - for (Signature vararg_meth : Signature.values()) { - for (Signature client_meth : Signature.values()) { - if (vararg_meth.isApplicableTo(client_meth)) { - pool.execute(new Warn4(sourceLevel, - trustMe, - suppressLevelClient, - suppressLevelDecl, - modKind, - vararg_meth, - client_meth)); - } - } - } - } - } - } - } - } - - checkAfterExec(); + public static void main(String... args) { + new ComboTestHelper() + .withFilter(Warn4::badTestFilter) + .withDimension("SOURCE", (x, level) -> x.sourceLevel = level, SourceLevel.values()) + .withDimension("TRUSTME", (x, trustme) -> x.trustMe = trustme, TrustMe.values()) + .withArrayDimension("SUPPRESS", (x, suppress, idx) -> x.suppress[idx] = suppress, 2, SuppressLevel.values()) + .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values()) + .withArrayDimension("MTH", (x, sig, idx) -> x.sigs[idx] = sig, 2, Signature.values()) + .run(Warn4::new); } SourceLevel sourceLevel; TrustMe trustMe; - SuppressLevel suppressLevelClient; - SuppressLevel suppressLevelDecl; + SuppressLevel[] suppress = new SuppressLevel[2]; ModifierKind modKind; - Signature vararg_meth; - Signature client_meth; - DiagnosticChecker diagChecker; + Signature[] sigs = new Signature[2]; - public Warn4(SourceLevel sourceLevel, TrustMe trustMe, - SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl, - ModifierKind modKind, Signature vararg_meth, Signature client_meth) { - this.sourceLevel = sourceLevel; - this.trustMe = trustMe; - this.suppressLevelClient = suppressLevelClient; - this.suppressLevelDecl = suppressLevelDecl; - this.modKind = modKind; - this.vararg_meth = vararg_meth; - this.client_meth = client_meth; - this.diagChecker = new DiagnosticChecker(); + boolean badTestFilter() { + return sigs[0].isApplicableTo(sigs[1]); } + final String template = "import java.util.List;\n" + + "class Test {\n" + + " #{TRUSTME} #{SUPPRESS[0]} #{MOD} #{MTH[0].VARARG}\n" + + " #{SUPPRESS[1]} #{MTH[1].CLIENT}\n" + + "}"; + @Override - public void run() { - int id = checkCount.incrementAndGet(); - final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); - JavaSource source = new JavaSource(id); - JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker, - Arrays.asList("-Xlint:unchecked", "-source", sourceLevel.sourceKey), - null, Arrays.asList(source)); - ct.call(); //to get mandatory notes - check(source, new boolean[] {vararg_meth.giveUnchecked(client_meth), - vararg_meth.giveVarargs(client_meth)}); + public void doWork() throws IOException { + check(newCompilationTask() + .withOption("-Xlint:unchecked") + .withOption("-source") + .withOption(sourceLevel.sourceKey) + .withSourceFromTemplate(template) + .analyze()); } - void check(JavaSource source, boolean[] warnArr) { + void check(Result res) { + boolean[] warnArr = new boolean[] {sigs[0].giveUnchecked(sigs[1]), + sigs[0].giveVarargs(sigs[1])}; + + Set warnings = new HashSet<>(); + for (Diagnostic d : res.diagnosticsForKind(Kind.MANDATORY_WARNING)) { + if (d.getCode().contains(Warning.VARARGS.key)) { + warnings.add(Warning.VARARGS); + } else if(d.getCode().contains(Warning.UNCHECKED.key)) { + warnings.add(Warning.UNCHECKED); + } + } + boolean badOutput = false; for (Warning wkind : Warning.values()) { boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel, - suppressLevelClient, suppressLevelDecl, modKind); + suppress[1], suppress[0], modKind); badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) != - diagChecker.warnings.contains(wkind); + warnings.contains(wkind); } if (badOutput) { - throw new Error("invalid diagnostics for source:\n" + - source.getCharContent(true) + + fail("invalid diagnostics for source:\n" + + res.compilationInfo() + "\nExpected unchecked warning: " + warnArr[0] + "\nExpected unsafe vararg warning: " + warnArr[1] + - "\nWarnings: " + diagChecker.warnings + + "\nWarnings: " + warnings + "\nSource level: " + sourceLevel); } } - - class JavaSource extends SimpleJavaFileObject { - - String source; - - public JavaSource(int id) { - super(URI.create(String.format("myfo:/Test%d.java", id)), - JavaFileObject.Kind.SOURCE); - String meth1 = vararg_meth.template.replace("#arity", "..."); - meth1 = meth1.replace("#name", "m"); - meth1 = meth1.replace("#body", ""); - meth1 = trustMe.anno + "\n" + suppressLevelDecl.getSuppressAnno() + - modKind.mod + meth1; - String meth2 = client_meth.template.replace("#arity", ""); - meth2 = meth2.replace("#name", "test"); - meth2 = meth2.replace("#body", "m(arg);"); - meth2 = suppressLevelClient.getSuppressAnno() + meth2; - source = String.format("import java.util.List;\n" + - "class Test%s {\n %s \n %s \n } \n", id, meth1, meth2); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; - } - } - - static class DiagnosticChecker - implements javax.tools.DiagnosticListener { - - Set warnings = new HashSet<>(); - - public void report(Diagnostic diagnostic) { - if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING || - diagnostic.getKind() == Diagnostic.Kind.WARNING) { - if (diagnostic.getCode().contains(Warning.VARARGS.key)) { - warnings.add(Warning.VARARGS); - } else if(diagnostic.getCode().contains(Warning.UNCHECKED.key)) { - warnings.add(Warning.UNCHECKED); - } - } - } - } - } diff -r f0e149d3e375 -r ead8b7192f00 test/tools/javac/varargs/warning/Warn5.java --- a/test/tools/javac/varargs/warning/Warn5.java Thu Sep 03 14:24:46 2015 -0700 +++ b/test/tools/javac/varargs/warning/Warn5.java Thu Sep 03 16:13:49 2015 -0700 @@ -26,29 +26,30 @@ * @bug 6993978 7097436 8006694 7196160 * @summary Project Coin: Annotation to reduce varargs warnings * temporarily workaround combo tests are causing time out in several platforms - * @author mcimadamore - * @library ../../lib - * @modules jdk.compiler - * @build JavacTestingAbstractThreadedTest + * @library /tools/javac/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper * @run main/othervm Warn5 */ -// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) -// see JDK-8006746 - -import java.net.URI; -import java.util.Arrays; +import java.io.IOException; import java.util.EnumSet; import javax.tools.Diagnostic; -import javax.tools.JavaCompiler; +import javax.tools.Diagnostic.Kind; import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import javax.tools.ToolProvider; -import com.sun.source.util.JavacTask; -public class Warn5 - extends JavacTestingAbstractThreadedTest - implements Runnable { +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; + + +public class Warn5 extends ComboInstance { enum XlintOption { NONE("none"), @@ -65,7 +66,7 @@ } } - enum TrustMe { + enum TrustMe implements ComboParameter { DONT_TRUST(""), TRUST("@java.lang.SafeVarargs"); @@ -74,20 +75,26 @@ TrustMe(String anno) { this.anno = anno; } + + @Override + public String expand(String optParameter) { + return anno; + } } - enum SuppressLevel { + enum SuppressLevel implements ComboParameter { NONE, VARARGS; - String getSuppressAnno() { + @Override + public String expand(String optParameter) { return this == VARARGS ? "@SuppressWarnings(\"varargs\")" : ""; } } - enum ModifierKind { + enum ModifierKind implements ComboParameter { NONE(""), FINAL("final"), STATIC("static"), @@ -98,9 +105,14 @@ ModifierKind(String mod) { this.mod = mod; } + + @Override + public String expand(String optParameter) { + return mod; + } } - enum MethodKind { + enum MethodKind implements ComboParameter { METHOD("void m"), CONSTRUCTOR("Test"); @@ -109,6 +121,11 @@ MethodKind(String name) { this.name = name; } + + @Override + public String expand(String optParameter) { + return name; + } } enum SourceLevel { @@ -123,11 +140,11 @@ } } - enum SignatureKind { - VARARGS_X("#K #N(X... x)", false, true), - VARARGS_STRING("#K #N(String... x)", true, true), - ARRAY_X("#K #N(X[] x)", false, false), - ARRAY_STRING("#K #N(String[] x)", true, false); + enum SignatureKind implements ComboParameter { + VARARGS_X("#{NAME}(X... x)", false, true), + VARARGS_STRING("#{NAME}(String... x)", true, true), + ARRAY_X("#{NAME}(X[] x)", false, false), + ARRAY_STRING("#{NAME}(String[] x)", true, false); String stub; boolean isReifiableArg; @@ -139,14 +156,13 @@ this.isVarargs = isVarargs; } - String getSignature(ModifierKind modKind, MethodKind methKind) { - return methKind != MethodKind.CONSTRUCTOR ? - stub.replace("#K", modKind.mod).replace("#N", methKind.name) : - stub.replace("#K", "").replace("#N", methKind.name); + @Override + public String expand(String optParameter) { + return stub; } } - enum BodyKind { + enum BodyKind implements ComboParameter { ASSIGN("Object o = x;", true), CAST("Object o = (Object)x;", true), METH("test(x);", true), @@ -162,82 +178,84 @@ this.body = body; this.hasAliasing = hasAliasing; } + + @Override + public String expand(String optParameter) { + return body; + } } enum WarningKind { - UNSAFE_BODY, - UNSAFE_DECL, - MALFORMED_SAFEVARARGS, - REDUNDANT_SAFEVARARGS; + UNSAFE_BODY("compiler.warn.varargs.unsafe.use.varargs.param"), + UNSAFE_DECL("compiler.warn.unchecked.varargs.non.reifiable.type"), + MALFORMED_SAFEVARARGS("compiler.err.varargs.invalid.trustme.anno"), + REDUNDANT_SAFEVARARGS("compiler.warn.varargs.redundant.trustme.anno"); + + String code; + + WarningKind(String code) { + this.code = code; + } + } + + public static void main(String[] args) { + new ComboTestHelper() + .withFilter(Warn5::badTestFilter) + .withDimension("SOURCE", (x, level) -> x.sourceLevel = level, SourceLevel.values()) + .withDimension("LINT", (x, lint) -> x.xlint = lint, XlintOption.values()) + .withDimension("TRUSTME", (x, trustme) -> x.trustMe = trustme, TrustMe.values()) + .withDimension("SUPPRESS", (x, suppress) -> x.suppressLevel = suppress, SuppressLevel.values()) + .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values()) + .withDimension("NAME", (x, name) -> x.methKind = name, MethodKind.values()) + .withDimension("SIG", (x, sig) -> x.sig = sig, SignatureKind.values()) + .withDimension("BODY", (x, body) -> x.body = body, BodyKind.values()) + .run(Warn5::new); } - public static void main(String... args) throws Exception { - for (SourceLevel sourceLevel : SourceLevel.values()) { - for (XlintOption xlint : XlintOption.values()) { - for (TrustMe trustMe : TrustMe.values()) { - for (SuppressLevel suppressLevel : SuppressLevel.values()) { - for (ModifierKind modKind : ModifierKind.values()) { - for (MethodKind methKind : MethodKind.values()) { - for (SignatureKind sig : SignatureKind.values()) { - for (BodyKind body : BodyKind.values()) { - pool.execute(new Warn5(sourceLevel, - xlint, trustMe, suppressLevel, - modKind, methKind, sig, body)); - } - } - } - } + SourceLevel sourceLevel; + XlintOption xlint; + TrustMe trustMe; + SuppressLevel suppressLevel; + ModifierKind modKind; + MethodKind methKind; + SignatureKind sig; + BodyKind body; + + boolean badTestFilter() { + return (methKind != MethodKind.CONSTRUCTOR || modKind == ModifierKind.NONE); + } + + String template = "import com.sun.tools.javac.api.*;\n" + + "import java.util.List;\n" + + "class Test {\n" + + " static void test(Object o) {}\n" + + " static void testArr(Object[] o) {}\n" + + " #{TRUSTME} #{SUPPRESS} #{MOD} #{SIG} { #{BODY} }\n" + + "}\n"; + + @Override + public void doWork() throws IOException { + check(newCompilationTask() + .withOption(xlint.getXlintOption()) + .withOption("-source") + .withOption(sourceLevel.sourceKey) + .withSourceFromTemplate(template) + .analyze()); + } + + void check(Result res) { + + EnumSet foundWarnings = EnumSet.noneOf(WarningKind.class); + for (Diagnostic.Kind kind : new Kind[] { Kind.ERROR, Kind.MANDATORY_WARNING, Kind.WARNING}) { + for (Diagnostic diag : res.diagnosticsForKind(kind)) { + for (WarningKind wk : WarningKind.values()) { + if (wk.code.equals(diag.getCode())) { + foundWarnings.add(wk); } } } } - checkAfterExec(false); - } - - final SourceLevel sourceLevel; - final XlintOption xlint; - final TrustMe trustMe; - final SuppressLevel suppressLevel; - final ModifierKind modKind; - final MethodKind methKind; - final SignatureKind sig; - final BodyKind body; - final JavaSource source; - final DiagnosticChecker dc; - - public Warn5(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe, - SuppressLevel suppressLevel, ModifierKind modKind, - MethodKind methKind, SignatureKind sig, BodyKind body) { - this.sourceLevel = sourceLevel; - this.xlint = xlint; - this.trustMe = trustMe; - this.suppressLevel = suppressLevel; - this.modKind = modKind; - this.methKind = methKind; - this.sig = sig; - this.body = body; - this.source = new JavaSource(); - this.dc = new DiagnosticChecker(); - } - - @Override - public void run() { - final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); - JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), dc, - Arrays.asList(xlint.getXlintOption(), - "-source", sourceLevel.sourceKey), - null, Arrays.asList(source)); - try { - ct.analyze(); - } catch (Throwable t) { - processException(t); - } - check(); - } - - void check() { - EnumSet expectedWarnings = EnumSet.noneOf(WarningKind.class); @@ -284,77 +302,14 @@ expectedWarnings.add(WarningKind.REDUNDANT_SAFEVARARGS); } - if (!expectedWarnings.containsAll(dc.warnings) || - !dc.warnings.containsAll(expectedWarnings)) { - throw new Error("invalid diagnostics for source:\n" + - source.getCharContent(true) + + if (!expectedWarnings.containsAll(foundWarnings) || + !foundWarnings.containsAll(expectedWarnings)) { + fail("invalid diagnostics for source:\n" + + res.compilationInfo() + "\nOptions: " + xlint.getXlintOption() + "\nSource Level: " + sourceLevel + "\nExpected warnings: " + expectedWarnings + - "\nFound warnings: " + dc.warnings); - } - } - - class JavaSource extends SimpleJavaFileObject { - - String template = "import com.sun.tools.javac.api.*;\n" + - "import java.util.List;\n" + - "class Test {\n" + - " static void test(Object o) {}\n" + - " static void testArr(Object[] o) {}\n" + - " #T \n #S #M { #B }\n" + - "}\n"; - - String source; - - public JavaSource() { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - source = template.replace("#T", trustMe.anno). - replace("#S", suppressLevel.getSuppressAnno()). - replace("#M", sig.getSignature(modKind, methKind)). - replace("#B", body.body); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; + "\nFound warnings: " + foundWarnings); } } - - class DiagnosticChecker - implements javax.tools.DiagnosticListener { - - EnumSet warnings = EnumSet.noneOf(WarningKind.class); - - public void report(Diagnostic diagnostic) { - if (diagnostic.getKind() == Diagnostic.Kind.WARNING) { - if (diagnostic.getCode(). - contains("unsafe.use.varargs.param")) { - setWarning(WarningKind.UNSAFE_BODY); - } else if (diagnostic.getCode(). - contains("redundant.trustme")) { - setWarning(WarningKind.REDUNDANT_SAFEVARARGS); - } - } else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING && - diagnostic.getCode(). - contains("varargs.non.reifiable.type")) { - setWarning(WarningKind.UNSAFE_DECL); - } else if (diagnostic.getKind() == Diagnostic.Kind.ERROR && - diagnostic.getCode().contains("invalid.trustme")) { - setWarning(WarningKind.MALFORMED_SAFEVARARGS); - } - } - - void setWarning(WarningKind wk) { - if (!warnings.add(wk)) { - throw new AssertionError("Duplicate warning of kind " + - wk + " in source:\n" + source); - } - } - - boolean hasWarning(WarningKind wk) { - return warnings.contains(wk); - } - } - }