Merge
This commit is contained in:
commit
e405645f6f
langtools
src/jdk.compiler/share/classes/com/sun/tools/javac
api
code
main
parser
util
test/tools/javac
Diagnostics/6769027
T7093325.javacast/intersection
defaultMethods
failover
generics
lambda
FunctionalInterfaceConversionTest.javaLambdaParserTest.javaMethodReferenceParserTest.javaTestBootstrapMethodsCount.javaTestInvokeDynamic.javaTestLambdaToMethodStats.java
bytecode
mostSpecific
typeInference/combo
lib
multicatch/7030606
parser/8134007
resolve
types
varargs
@ -76,7 +76,7 @@ public class JavacTaskImpl extends BasicJavacTask {
|
||||
private final AtomicBoolean used = new AtomicBoolean();
|
||||
private Iterable<? extends Processor> processors;
|
||||
|
||||
JavacTaskImpl(Context context) {
|
||||
protected JavacTaskImpl(Context context) {
|
||||
super(context, true);
|
||||
args = Arguments.instance(context);
|
||||
fileManager = context.get(JavaFileManager.class);
|
||||
|
@ -47,6 +47,9 @@ public class MultiTaskListener implements TaskListener {
|
||||
/** The context key for the MultiTaskListener. */
|
||||
public static final Context.Key<MultiTaskListener> 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 @@ public class MultiTaskListener implements TaskListener {
|
||||
* 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 class MultiTaskListener implements TaskListener {
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return (listeners.length == 0);
|
||||
return listeners == EMPTY_LISTENERS;
|
||||
}
|
||||
|
||||
public void add(TaskListener listener) {
|
||||
@ -88,10 +91,14 @@ public class MultiTaskListener implements TaskListener {
|
||||
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 class MultiTaskListener implements TaskListener {
|
||||
public String toString() {
|
||||
return Arrays.toString(listeners);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
listeners = EMPTY_LISTENERS;
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ public abstract class Scope {
|
||||
|
||||
/** A list of scopes to be notified if items are to be removed from this scope.
|
||||
*/
|
||||
List<ScopeListener> listeners = List.nil();
|
||||
|
||||
public void addScopeListener(ScopeListener sl) {
|
||||
listeners = listeners.prepend(sl);
|
||||
}
|
||||
ScopeListenerList listeners = new ScopeListenerList();
|
||||
|
||||
public interface ScopeListener {
|
||||
public void symbolAdded(Symbol sym, Scope s);
|
||||
public void symbolRemoved(Symbol sym, Scope s);
|
||||
void symbolAdded(Symbol sym, Scope s);
|
||||
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<WeakReference<ScopeListener>> 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<WeakReference<ScopeListener>> newListeners = new ListBuffer<>();
|
||||
for (WeakReference<ScopeListener> 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 @@ public abstract class Scope {
|
||||
elems = e;
|
||||
|
||||
//notify listeners
|
||||
for (List<ScopeListener> 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 @@ public abstract class Scope {
|
||||
}
|
||||
|
||||
//notify listeners
|
||||
for (List<ScopeListener> 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 @@ public abstract class Scope {
|
||||
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 abstract class Scope {
|
||||
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() {
|
||||
|
@ -68,7 +68,7 @@ public class Arguments {
|
||||
/**
|
||||
* The context key for the arguments.
|
||||
*/
|
||||
protected static final Context.Key<Arguments> argsKey = new Context.Key<>();
|
||||
public static final Context.Key<Arguments> argsKey = new Context.Key<>();
|
||||
|
||||
private String ownName;
|
||||
private Set<String> classNames;
|
||||
|
@ -87,7 +87,7 @@ import static javax.tools.StandardLocation.CLASS_OUTPUT;
|
||||
*/
|
||||
public class JavaCompiler {
|
||||
/** The context key for the compiler. */
|
||||
protected static final Context.Key<JavaCompiler> compilerKey = new Context.Key<>();
|
||||
public static final Context.Key<JavaCompiler> compilerKey = new Context.Key<>();
|
||||
|
||||
/** Get the JavaCompiler instance for this context. */
|
||||
public static JavaCompiler instance(Context context) {
|
||||
@ -821,7 +821,7 @@ public class JavaCompiler {
|
||||
// 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 @@ public class JavaCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -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 @@ public class JavacParser implements Parser {
|
||||
if (mods != 0) {
|
||||
long lowestMod = mods & -mods;
|
||||
error(token.pos, "mod.not.allowed.here",
|
||||
Flags.asFlagSet(lowestMod));
|
||||
Flags.asFlagSet(lowestMod));
|
||||
}
|
||||
}
|
||||
|
||||
@ -946,10 +947,7 @@ public class JavacParser implements Parser {
|
||||
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 @@ public class JavacParser implements Parser {
|
||||
/** 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<String> buf = List.nil();
|
||||
ListBuffer<JCExpression> opStack = new ListBuffer<>();
|
||||
ListBuffer<JCLiteral> 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<JCExpression> 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<JCLiteral> litBuf,
|
||||
ListBuffer<JCExpression> 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<JCLiteral> litBuf, ListBuffer<JCExpression> 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.
|
||||
*/
|
||||
|
@ -119,7 +119,7 @@ public class Context {
|
||||
* or
|
||||
* {@literal Key<T> -> Factory<T> }
|
||||
*/
|
||||
private final Map<Key<?>,Object> ht = new HashMap<>();
|
||||
protected final Map<Key<?>,Object> ht = new HashMap<>();
|
||||
|
||||
/** Set the factory for the key in this context. */
|
||||
public <T> void put(Key<T> key, Factory<T> fac) {
|
||||
@ -173,7 +173,7 @@ public class Context {
|
||||
*/
|
||||
private final Map<Class<?>, Key<?>> kt = new HashMap<>();
|
||||
|
||||
private <T> Key<T> key(Class<T> clss) {
|
||||
protected <T> Key<T> key(Class<T> clss) {
|
||||
checkState(kt);
|
||||
Key<T> k = uncheckedCast(kt.get(clss));
|
||||
if (k == null) {
|
||||
|
@ -334,7 +334,7 @@ public class Log extends AbstractLog {
|
||||
* 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<Pair<JavaFileObject, Integer>> recorded = new HashSet<>();
|
||||
protected Set<Pair<JavaFileObject, Integer>> recorded = new HashSet<>();
|
||||
|
||||
public boolean hasDiagnosticListener() {
|
||||
return diagListener != null;
|
||||
|
@ -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"),
|
||||
@ -323,11 +316,6 @@ public class T6769027
|
||||
super(ctx);
|
||||
}
|
||||
|
||||
@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 @@ public class T6769027
|
||||
this.subdiagsIndent = subdiagsIndent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Context ctx = new Context();
|
||||
Options options = Options.instance(ctx);
|
||||
@ -419,7 +406,7 @@ public class T6769027
|
||||
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 @@ public class T6769027
|
||||
summaryIndent,
|
||||
detailsIndent,
|
||||
sourceIndent,
|
||||
subdiagsIndent));
|
||||
subdiagsIndent).run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -445,8 +432,6 @@ public class T6769027
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkAfterExec(false);
|
||||
}
|
||||
|
||||
void printInfo(String msg, String errorLine) {
|
||||
@ -457,11 +442,11 @@ public class T6769027
|
||||
" 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 @@ public class T6769027
|
||||
}
|
||||
|
||||
if (!msg.equals(errorLine)) {
|
||||
// printInfo(msg, errorLine);
|
||||
errCount.incrementAndGet();
|
||||
printInfo(msg, errorLine);
|
||||
throw new AssertionError("errors were found");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<T7093325> {
|
||||
|
||||
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 @@ public class T7093325
|
||||
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<T7093325>()
|
||||
.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<Iterable<? extends JavaFileObject>> 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 @@ public class T7093325
|
||||
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 @@ public class T7093325
|
||||
}
|
||||
|
||||
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 @@ public class T7093325
|
||||
}
|
||||
|
||||
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 @@ public class T7093325
|
||||
}
|
||||
|
||||
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 {}";
|
||||
}
|
||||
|
@ -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 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;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import com.sun.tools.javac.util.ListBuffer;
|
||||
|
||||
public class IntersectionTypeCastTest
|
||||
extends JavacTestingAbstractThreadedTest
|
||||
implements Runnable {
|
||||
import combo.ComboInstance;
|
||||
import combo.ComboParameter;
|
||||
import combo.ComboTask.Result;
|
||||
import combo.ComboTestHelper;
|
||||
|
||||
interface Type {
|
||||
import java.io.IOException;
|
||||
|
||||
public class IntersectionTypeCastTest extends ComboInstance<IntersectionTypeCastTest> {
|
||||
|
||||
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;
|
||||
}
|
||||
@ -80,11 +74,6 @@ public class IntersectionTypeCastTest
|
||||
that == ClassKind.OBJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString() {
|
||||
return typeStr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClass() {
|
||||
return false;
|
||||
@ -94,53 +83,37 @@ public class IntersectionTypeCastTest
|
||||
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<InterfaceKind> 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) ||
|
||||
that == OBJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString() {
|
||||
return typeStr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClass() {
|
||||
return true;
|
||||
@ -150,9 +123,14 @@ public class IntersectionTypeCastTest
|
||||
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 @@ public class IntersectionTypeCastTest
|
||||
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 @@ public class IntersectionTypeCastTest
|
||||
this.castTemplate = castTemplate;
|
||||
this.interfaceBounds = interfaceBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String expand(String optParameter) {
|
||||
return castTemplate.replaceAll("#IDX", optParameter);
|
||||
}
|
||||
}
|
||||
|
||||
static class CastInfo {
|
||||
@ -188,19 +175,9 @@ public class IntersectionTypeCastTest
|
||||
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 @@ public class IntersectionTypeCastTest
|
||||
}
|
||||
|
||||
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 @@ public class IntersectionTypeCastTest
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
checkAfterExec();
|
||||
new ComboTestHelper<IntersectionTypeCastTest>()
|
||||
.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);
|
||||
}
|
||||
|
||||
static List<CastInfo> allCastInfo() {
|
||||
ListBuffer<CastInfo> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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 = "";
|
||||
|
||||
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();
|
||||
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 { }";
|
||||
|
||||
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<JavaFileObject> {
|
||||
|
||||
boolean errorFound;
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
|
||||
errorFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 {
|
||||
public class InterfaceMethodHidingTest extends ComboInstance<InterfaceMethodHidingTest> {
|
||||
|
||||
static int checkCount = 0;
|
||||
|
||||
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 @@ public class InterfaceMethodHidingTest {
|
||||
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 @@ public class InterfaceMethodHidingTest {
|
||||
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 @@ public class InterfaceMethodHidingTest {
|
||||
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<InterfaceMethodHidingTest>()
|
||||
.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<JavaFileObject> {
|
||||
|
||||
boolean errorFound;
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
import combo.ComboInstance;
|
||||
import combo.ComboParameter;
|
||||
import combo.ComboTask.Result;
|
||||
import combo.ComboTestHelper;
|
||||
|
||||
public class TestDefaultSuperCall
|
||||
extends JavacTestingAbstractThreadedTest
|
||||
implements Runnable {
|
||||
public class TestDefaultSuperCall extends ComboInstance<TestDefaultSuperCall> {
|
||||
|
||||
enum InterfaceKind {
|
||||
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 @@ public class TestDefaultSuperCall
|
||||
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 @@ public class TestDefaultSuperCall
|
||||
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 @@ public class TestDefaultSuperCall
|
||||
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 @@ public class TestDefaultSuperCall
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String expand(String optParameter) {
|
||||
return qualifierStr;
|
||||
}
|
||||
}
|
||||
|
||||
enum ExprKind {
|
||||
enum ExprKind implements ComboParameter {
|
||||
THIS("this"),
|
||||
SUPER("super");
|
||||
|
||||
@ -130,19 +135,24 @@ public class TestDefaultSuperCall
|
||||
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 @@ public class TestDefaultSuperCall
|
||||
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<ElementKind> enclosingElements;
|
||||
List<String> enclosingNames;
|
||||
List<String> elementsWithMethod;
|
||||
@ -234,114 +254,73 @@ public class TestDefaultSuperCall
|
||||
} 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<TestDefaultSuperCall>()
|
||||
.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;
|
||||
|
||||
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 filterBadTopElement() {
|
||||
return elements[0].isAllowedTop();
|
||||
}
|
||||
|
||||
class JavaSource extends SimpleJavaFileObject {
|
||||
|
||||
String template = "interface E {}\n" +
|
||||
"interface B { }\n" +
|
||||
"#I\n" +
|
||||
"#P\n" +
|
||||
"#C";
|
||||
|
||||
String source;
|
||||
|
||||
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));
|
||||
boolean filterBadIntermediateElement() {
|
||||
for (int i = 1 ; i < 4 ; i++) {
|
||||
if (!elements[i].isAllowedEnclosing(elements[i - 1], i == 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
||||
return source;
|
||||
boolean filterBadTerminalElement() {
|
||||
return elements[4].isAllowedEnclosing(elements[3], false) && !elements[4].isClassDecl();
|
||||
}
|
||||
|
||||
String template = "interface E {}\n" +
|
||||
"interface B { }\n" +
|
||||
"#{INTF1}\n" +
|
||||
"#{INTF2}\n" +
|
||||
"#{ELEM[0].0}";
|
||||
|
||||
@Override
|
||||
public void doWork() throws IOException {
|
||||
check(newCompilationTask()
|
||||
.withSourceFromTemplate(template, this::methodName)
|
||||
.analyze());
|
||||
}
|
||||
|
||||
ComboParameter methodName(String parameterName) {
|
||||
switch (parameterName) {
|
||||
case "METH":
|
||||
String methodName = ek == ExprKind.THIS ? "test" : "m";
|
||||
return new ComboParameter.Constant<String>(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 @@ public class TestDefaultSuperCall
|
||||
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 @@ public class TestDefaultSuperCall
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class TestDefaultSuperCall
|
||||
"\nbad this: " + badThis +
|
||||
"\nbad super: " + badSuper +
|
||||
"\nqual kind: " + qk +
|
||||
"\nfound error: " + diagChecker.errorFound);
|
||||
"\nfound error: " + res.hasErrors());
|
||||
}
|
||||
}
|
||||
|
||||
static class DiagnosticChecker
|
||||
implements javax.tools.DiagnosticListener<JavaFileObject> {
|
||||
|
||||
boolean errorFound;
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
|
||||
errorFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.PrintStream;
|
||||
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.event.CaretListener;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.DefaultHighlighter;
|
||||
import javax.swing.text.Highlighter;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.DiagnosticListener;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import 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 com.sun.tools.javac.util.Pair;
|
||||
|
||||
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 @@ import static com.sun.tools.javac.tree.JCTree.Tag.*;
|
||||
* 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 class CheckAttributedTree extends JavacTestingAbstractThreadedTest {
|
||||
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 @@ public class CheckAttributedTree extends JavacTestingAbstractThreadedTest {
|
||||
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 @@ public class CheckAttributedTree extends JavacTestingAbstractThreadedTest {
|
||||
}
|
||||
}
|
||||
|
||||
for (File file: files) {
|
||||
if (file.exists())
|
||||
test(file);
|
||||
else
|
||||
error("File not found: " + file);
|
||||
}
|
||||
ComboTestHelper<FileChecker> 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);
|
||||
|
||||
return (gui || errCount.get() == 0);
|
||||
if (verbose) {
|
||||
System.out.println(errSWriter.toString());
|
||||
}
|
||||
|
||||
return (gui || !cth.info().hasFailures());
|
||||
}
|
||||
|
||||
File[] getAllFiles(List<File> roots) throws IOException {
|
||||
long now = System.currentTimeMillis();
|
||||
ArrayList<File> buf = new ArrayList<>();
|
||||
for (File file : roots) {
|
||||
Files.walkFileTree(file.toPath(), new SimpleFileVisitor<Path>() {
|
||||
@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 @@ public class CheckAttributedTree extends JavacTestingAbstractThreadedTest {
|
||||
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<FileChecker> {
|
||||
|
||||
if (file.isDirectory()) {
|
||||
for (File f: file.listFiles()) {
|
||||
test(f);
|
||||
File file;
|
||||
|
||||
boolean checkFile() {
|
||||
if (!file.exists()) {
|
||||
error("File not found: " + file);
|
||||
return false;
|
||||
}
|
||||
return;
|
||||
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.isFile() && file.getName().endsWith(".java")) {
|
||||
pool.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
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());
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<Pair<JCCompilationUnit, JCTree>> read(File file) throws IOException, AttributionException {
|
||||
try {
|
||||
Iterable<? extends JavaFileObject> files = fileManager().getJavaFileObjects(file);
|
||||
final List<Element> analyzedElems = new ArrayList<>();
|
||||
final List<CompilationUnitTree> trees = new ArrayList<>();
|
||||
Iterable<? extends Element> 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());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
error("Error reading " + file + ": " + e);
|
||||
|
||||
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<Pair<JCCompilationUnit, JCTree>> 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<Pair<JCCompilationUnit, JCTree>> trees) {
|
||||
for (Pair<JCCompilationUnit, JCTree> 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<String> 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<Field> 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;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!quiet)
|
||||
error("File " + file + " ignored");
|
||||
@Override
|
||||
public void visitImport(JCImport tree) { }
|
||||
|
||||
@Override
|
||||
public void visitTopLevel(JCCompilationUnit tree) {
|
||||
scan(tree.defs);
|
||||
}
|
||||
|
||||
JavaFileObject sourcefile;
|
||||
EndPosTable endPosTable;
|
||||
Info encl;
|
||||
}
|
||||
}
|
||||
|
||||
// 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<Pair<JCCompilationUnit, JCTree>> read(File file) throws IOException, AttributionException {
|
||||
r.errors = 0;
|
||||
Iterable<? extends JavaFileObject> 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<Element> 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<? extends CompilationUnitTree> 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<? extends Element> elems = task.analyze();
|
||||
if (!elems.iterator().hasNext())
|
||||
throw new AttributionException("No results from analyze");
|
||||
List<Pair<JCCompilationUnit, JCTree>> 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;
|
||||
@ -355,101 +475,6 @@ public class CheckAttributedTree extends JavacTestingAbstractThreadedTest {
|
||||
/** Utility class for trees */
|
||||
TreeUtil treeUtil = new TreeUtil();
|
||||
|
||||
/**
|
||||
* Main class for testing assertions concerning types/symbol
|
||||
* left uninitialized after attribution
|
||||
*/
|
||||
private class NPETester extends TreeScanner {
|
||||
void test(List<Pair<JCCompilationUnit, JCTree>> trees) {
|
||||
for (Pair<JCCompilationUnit, JCTree> 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<String> 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<Field> 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.
|
||||
*/
|
||||
@ -523,25 +548,6 @@ public class CheckAttributedTree extends JavacTestingAbstractThreadedTest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DiagnosticListener to report diagnostics and count any errors that occur.
|
||||
*/
|
||||
private static class Reporter implements DiagnosticListener<JavaFileObject> {
|
||||
Reporter(PrintWriter out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
//out.println(diagnostic);
|
||||
switch (diagnostic.getKind()) {
|
||||
case ERROR:
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
int errors;
|
||||
PrintWriter out;
|
||||
}
|
||||
|
||||
/**
|
||||
* GUI viewer for issues found by TreePosTester. The viewer provides a drop
|
||||
* down list for selecting error conditions, a header area providing details
|
||||
|
@ -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<DiamondAndInnerClassTest> {
|
||||
|
||||
enum TypeArgumentKind implements ComboParameter {
|
||||
NONE(""),
|
||||
STRING("<String>"),
|
||||
INTEGER("<Integer>"),
|
||||
@ -54,7 +56,7 @@ public class DiamondAndInnerClassTest
|
||||
|
||||
String typeargStr;
|
||||
|
||||
private TypeArgumentKind(String typeargStr) {
|
||||
TypeArgumentKind(String typeargStr) {
|
||||
this.typeargStr = typeargStr;
|
||||
}
|
||||
|
||||
@ -75,252 +77,173 @@ public class DiamondAndInnerClassTest
|
||||
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<X> { A1(X x1) { } #B }"),
|
||||
TWO(2, "class A1<X1> { class A2<X2> { A2(X1 x1, X2 x2) { } #B } }"),
|
||||
THREE(3, "class A1<X1> { class A2<X2> { class A3<X3> { A3(X1 x1, X2 x2, X3 x3) { } #B } } }");
|
||||
enum InnerClassDeclArity implements ComboParameter {
|
||||
ONE(1, "class A1<X> { A1(X x1) { } #{BODY} }"),
|
||||
TWO(2, "class A1<X1> { class A2<X2> { A2(X1 x1, X2 x2) { } #{BODY} } }"),
|
||||
THREE(3, "class A1<X1> { class A2<X2> { class A3<X3> { 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkAfterExec();
|
||||
new ComboTestHelper<DiamondAndInnerClassTest>()
|
||||
.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 declType;
|
||||
TypeQualifierArity siteType;
|
||||
ArgumentListArity argList;
|
||||
TypeArgumentKind[] declTypeArgumentKinds;
|
||||
TypeArgumentKind[] siteTypeArgumentKinds;
|
||||
ArgumentKind[] argumentKinds;
|
||||
JavaSource source;
|
||||
DiagnosticChecker diagChecker;
|
||||
TypeQualifierArity declArity;
|
||||
TypeQualifierArity siteArity;
|
||||
TypeArgumentKind[] declTypeArgumentKinds = new TypeArgumentKind[3];
|
||||
TypeArgumentKind[] siteTypeArgumentKinds = new TypeArgumentKind[3];
|
||||
ArgumentKind[] argumentKinds = new ArgumentKind[3];
|
||||
ArgumentListArity argumentListArity;
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
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));
|
||||
boolean noDiamondOnDecl() {
|
||||
for (int i = 0; i < innerClassDeclArity.n; i++) {
|
||||
if (declTypeArgumentKinds[i] == TypeArgumentKind.DIAMOND) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
||||
return source;
|
||||
boolean noDiamondOnIntermediateTypes() {
|
||||
for (int i = 0; i < (innerClassDeclArity.n - 1); i++) {
|
||||
if (siteTypeArgumentKinds[i] == TypeArgumentKind.DIAMOND) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 @@ public class DiamondAndInnerClassTest
|
||||
}
|
||||
}
|
||||
|
||||
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<JavaFileObject> {
|
||||
|
||||
boolean errorFound;
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
|
||||
errorFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<GenericOverrideTest> {
|
||||
|
||||
enum SourceLevel {
|
||||
SOURCE_7("-source", "7"),
|
||||
@ -58,24 +58,29 @@ public class GenericOverrideTest
|
||||
}
|
||||
}
|
||||
|
||||
enum SignatureKind {
|
||||
enum SignatureKind implements ComboParameter {
|
||||
NON_GENERIC(""),
|
||||
GENERIC("<X>");
|
||||
|
||||
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 @@ public class GenericOverrideTest
|
||||
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("<Number>"),
|
||||
@ -99,7 +109,7 @@ public class GenericOverrideTest
|
||||
|
||||
String typeargStr;
|
||||
|
||||
private TypeArgumentKind(String typeargStr) {
|
||||
TypeArgumentKind(String typeargStr) {
|
||||
this.typeargStr = typeargStr;
|
||||
}
|
||||
|
||||
@ -141,136 +151,79 @@ public class GenericOverrideTest
|
||||
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<GenericOverrideTest>()
|
||||
.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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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" +
|
||||
"}";
|
||||
|
||||
@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();
|
||||
public void doWork() throws IOException {
|
||||
check(newCompilationTask()
|
||||
.withOption("-XDuseUnsharedTable") //this test relies on predictable name indexes!
|
||||
.withOptions(level.opts)
|
||||
.withSourceFromTemplate(template)
|
||||
.analyze());
|
||||
}
|
||||
|
||||
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 @@ public class GenericOverrideTest
|
||||
|
||||
//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<JavaFileObject> {
|
||||
|
||||
boolean errorFound;
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
|
||||
errorFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<FunctionalInterfaceConversionTest> {
|
||||
|
||||
enum PackageKind implements ComboParameter {
|
||||
NO_PKG(""),
|
||||
PKG_A("a");
|
||||
|
||||
@ -61,7 +58,8 @@ public class FunctionalInterfaceConversionTest
|
||||
this.pkg = pkg;
|
||||
}
|
||||
|
||||
String getPkgDecl() {
|
||||
@Override
|
||||
public String expand(String optParameter) {
|
||||
return this == NO_PKG ?
|
||||
"" :
|
||||
"package " + pkg + ";";
|
||||
@ -74,12 +72,12 @@ public class FunctionalInterfaceConversionTest
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class FunctionalInterfaceConversionTest
|
||||
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 @@ public class FunctionalInterfaceConversionTest
|
||||
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 <X> #R m(#ARG s) throws #T;");
|
||||
NON_GENERIC("public abstract #{RET} m(#{ARG} s) throws #{THROWN};"),
|
||||
GENERIC("public abstract <X> #{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<FunctionalInterfaceConversionTest>()
|
||||
.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 @@ public class FunctionalInterfaceConversionTest
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
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();
|
||||
}
|
||||
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 }";
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
|
||||
public void doWork() throws IOException {
|
||||
check(newCompilationTask()
|
||||
.withSourceFromTemplate("Sam", samSource)
|
||||
.withSourceFromTemplate("PackageClass", pkgClassSource)
|
||||
.withSourceFromTemplate("Client", clientSource, this::importStmt)
|
||||
.analyze());
|
||||
}
|
||||
|
||||
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());
|
||||
ComboParameter importStmt(String name) {
|
||||
switch (name) {
|
||||
case "IMP": return new ComboParameter.Constant<>(samPkg.getImportStat());
|
||||
default: return null;
|
||||
}
|
||||
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 @@ public class FunctionalInterfaceConversionTest
|
||||
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<JavaFileObject> {
|
||||
|
||||
boolean errorFound = false;
|
||||
|
||||
@Override
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
|
||||
errorFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<LambdaParserTest> {
|
||||
|
||||
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 @@ public class LambdaParserTest
|
||||
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 @@ public class LambdaParserTest
|
||||
}
|
||||
}
|
||||
|
||||
enum LambdaParameterName {
|
||||
enum LambdaParameterName implements ComboParameter {
|
||||
IDENT("x"),
|
||||
UNDERSCORE("_");
|
||||
|
||||
@ -101,9 +98,14 @@ public class LambdaParserTest
|
||||
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 @@ public class LambdaParserTest
|
||||
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 @@ public class LambdaParserTest
|
||||
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 @@ public class LambdaParserTest
|
||||
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 @@ public class LambdaParserTest
|
||||
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<LambdaParserTest>()
|
||||
.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;
|
||||
|
||||
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 badImplicitFilter() {
|
||||
return !(mks[0] != ModifierKind.NONE && lk.isShort());
|
||||
}
|
||||
|
||||
class JavaSource extends SimpleJavaFileObject {
|
||||
|
||||
String template = "class Test {\n" +
|
||||
" SAM s = #E;\n" +
|
||||
"}";
|
||||
|
||||
String source;
|
||||
|
||||
public JavaSource() {
|
||||
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
|
||||
source = template.replaceAll("#E",
|
||||
ek.expressionString(pk1, pk2, mk1, mk2, lk, pn, sk));
|
||||
boolean redundantTestFilter() {
|
||||
for (int i = lk.arity(); i < mks.length ; i++) {
|
||||
if (mks[i].ordinal() != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
||||
return source;
|
||||
for (int i = lk.arity(); i < pks.length ; i++) {
|
||||
if (pks[i].ordinal() != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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();
|
||||
String template = "class Test {\n" +
|
||||
" SAM s = #{EXPR};\n" +
|
||||
"}";
|
||||
|
||||
@Override
|
||||
public void doWork() throws IOException {
|
||||
check(newCompilationTask()
|
||||
.withSourceFromTemplate(template)
|
||||
.parse());
|
||||
}
|
||||
|
||||
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<JavaFileObject> {
|
||||
|
||||
boolean errorFound;
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
|
||||
errorFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 JavacTestingAbstractThreadedTest
|
||||
implements Runnable {
|
||||
public class MethodReferenceParserTest extends ComboInstance<MethodReferenceParserTest> {
|
||||
|
||||
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 @@ public class MethodReferenceParserTest
|
||||
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 @@ public class MethodReferenceParserTest
|
||||
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 @@ public class MethodReferenceParserTest
|
||||
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("<X>"),
|
||||
TWO("<X,Y>");
|
||||
@ -108,9 +107,14 @@ public class MethodReferenceParserTest
|
||||
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 @@ public class MethodReferenceParserTest
|
||||
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 @@ public class MethodReferenceParserTest
|
||||
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 @@ public class MethodReferenceParserTest
|
||||
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<MethodReferenceParserTest>()
|
||||
.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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
String template = "class Test {\n" +
|
||||
" void test() {\n" +
|
||||
" #{CTX}\n" +
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
@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();
|
||||
public void doWork() throws IOException {
|
||||
check(newCompilationTask()
|
||||
.withSourceFromTemplate(template)
|
||||
.parse());
|
||||
}
|
||||
|
||||
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<JavaFileObject> {
|
||||
|
||||
boolean errorFound;
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
|
||||
errorFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,15 +25,12 @@
|
||||
* @test
|
||||
* @bug 8129547
|
||||
* @summary Excess entries in BootstrapMethods with the same (bsm, bsmKind, bsmStaticArgs), but different dynamicArgs
|
||||
* @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.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;
|
||||
@ -43,8 +40,10 @@ 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;
|
||||
@ -69,14 +68,11 @@ import com.sun.tools.javac.util.Names;
|
||||
|
||||
import static com.sun.tools.javac.jvm.ClassFile.*;
|
||||
|
||||
public class TestBootstrapMethodsCount
|
||||
extends JavacTestingAbstractThreadedTest
|
||||
implements Runnable {
|
||||
|
||||
public class TestBootstrapMethodsCount {
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
pool.execute(new TestBootstrapMethodsCount());
|
||||
checkAfterExec();
|
||||
JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
|
||||
new TestBootstrapMethodsCount().run(comp);
|
||||
}
|
||||
|
||||
DiagChecker dc;
|
||||
@ -85,10 +81,9 @@ public class 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,
|
||||
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);
|
||||
@ -108,11 +103,11 @@ public class TestBootstrapMethodsCount
|
||||
String.format("Diags found when compiling following code\n%s\n\n%s",
|
||||
source.source, dc.printDiags()));
|
||||
}
|
||||
verifyBytecode(id);
|
||||
verifyBytecode();
|
||||
}
|
||||
|
||||
void verifyBytecode(int id) {
|
||||
File compiledTest = new File(String.format("Test%d.class", id));
|
||||
void verifyBytecode() {
|
||||
File compiledTest = new File("Test.class");
|
||||
try {
|
||||
ClassFile cf = ClassFile.read(compiledTest);
|
||||
BootstrapMethods_attribute bsm_attr =
|
||||
@ -131,14 +126,14 @@ public class TestBootstrapMethodsCount
|
||||
|
||||
class JavaSource extends SimpleJavaFileObject {
|
||||
|
||||
static final String source_template = "import java.lang.invoke.*;\n" +
|
||||
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#ID {\n" +
|
||||
"class Test {\n" +
|
||||
" void m1() { }\n" +
|
||||
" void m2(Object arg1) { }\n" +
|
||||
" void test1() {\n" +
|
||||
@ -151,11 +146,8 @@ public class TestBootstrapMethodsCount
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
String source;
|
||||
|
||||
JavaSource(int id) {
|
||||
JavaSource() {
|
||||
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
|
||||
source = source_template.replace("#ID", String.valueOf(id));
|
||||
}
|
||||
|
||||
@Override
|
@ -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.tree.JCTree.JCIdent;
|
||||
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<TestInvokeDynamic> {
|
||||
|
||||
enum StaticArgumentKind {
|
||||
enum StaticArgumentKind implements ComboParameter {
|
||||
STRING("Hello!", "String", "Ljava/lang/String;") {
|
||||
@Override
|
||||
boolean check(CPInfo cpInfo) throws Exception {
|
||||
@ -189,88 +187,91 @@ public class TestInvokeDynamic
|
||||
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<TestInvokeDynamic>()
|
||||
.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<Iterable<? extends JavaFileObject>> 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 @@ public class TestInvokeDynamic
|
||||
}
|
||||
}
|
||||
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 @@ public class TestInvokeDynamic
|
||||
.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 @@ public class TestInvokeDynamic
|
||||
.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 @@ public class TestInvokeDynamic
|
||||
.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<Void, Void> implements TaskListener {
|
||||
|
||||
MethodSymbol bsm;
|
||||
@ -475,26 +444,4 @@ public class TestInvokeDynamic
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class DiagChecker
|
||||
implements javax.tools.DiagnosticListener<JavaFileObject> {
|
||||
|
||||
boolean diagFound;
|
||||
ArrayList<String> diags = new ArrayList<>();
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<TestLambdaToMethodStats> {
|
||||
|
||||
enum ExprKind implements ComboParameter {
|
||||
LAMBDA("()->null"),
|
||||
MREF1("this::g"),
|
||||
MREF2("this::h");
|
||||
@ -60,9 +61,14 @@ public class TestLambdaToMethodStats
|
||||
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 @@ public class TestLambdaToMethodStats
|
||||
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<TestLambdaToMethodStats>()
|
||||
.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;
|
||||
|
||||
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" +
|
||||
"}";
|
||||
|
||||
TestLambdaToMethodStats(ExprKind ek, TargetKind tk) {
|
||||
this.ek = ek;
|
||||
this.tk = tk;
|
||||
this.source = new JavaSource();
|
||||
this.diagChecker = new DiagnosticChecker();
|
||||
@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<Diagnostic<? extends JavaFileObject>> 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<JavaFileObject> {
|
||||
|
||||
boolean altMetafactory;
|
||||
boolean bridge;
|
||||
boolean lambda;
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.ConstantPool.*;
|
||||
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 combo.ComboInstance;
|
||||
import combo.ComboParameter;
|
||||
import combo.ComboTask.Result;
|
||||
import combo.ComboTestHelper;
|
||||
|
||||
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 static com.sun.tools.javac.jvm.ClassFile.*;
|
||||
public class TestLambdaBytecode extends ComboInstance<TestLambdaBytecode> {
|
||||
|
||||
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 @@ public class TestLambdaBytecode
|
||||
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 @@ public class TestLambdaBytecode
|
||||
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 @@ public class TestLambdaBytecode
|
||||
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 @@ public class TestLambdaBytecode
|
||||
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 @@ public class TestLambdaBytecode
|
||||
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<TestLambdaBytecode>()
|
||||
.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<Iterable<? extends JavaFileObject>> 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 @@ public class TestLambdaBytecode
|
||||
}
|
||||
}
|
||||
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 @@ public class TestLambdaBytecode
|
||||
(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 @@ public class TestLambdaBytecode
|
||||
}
|
||||
|
||||
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<JavaFileObject> {
|
||||
|
||||
boolean diagFound;
|
||||
ArrayList<String> diags = new ArrayList<>();
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<StructuralMostSpecificTest> {
|
||||
|
||||
enum RetTypeKind {
|
||||
enum RetTypeKind implements ComboParameter {
|
||||
SHORT("short"),
|
||||
INT("int"),
|
||||
OBJECT("Object"),
|
||||
@ -76,9 +78,13 @@ public class StructuralMostSpecificTest
|
||||
/* 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 @@ public class StructuralMostSpecificTest
|
||||
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 @@ public class StructuralMostSpecificTest
|
||||
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 @@ public class StructuralMostSpecificTest
|
||||
/* INTEGER */ { false , false , true , false , false },
|
||||
/* VOID */ { false , false , false , false , false },
|
||||
/* J_L_VOID */{ true , false , false , false , false } };
|
||||
|
||||
public String expand(String optParameter) {
|
||||
return retStr;
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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();
|
||||
new ComboTestHelper<StructuralMostSpecificTest>()
|
||||
.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);
|
||||
}
|
||||
|
||||
LambdaReturnKind lrk;
|
||||
RetTypeKind rt1, rt2;
|
||||
ArgTypeKind ak1, ak2;
|
||||
ExceptionKind ek1, ek2;
|
||||
JavaSource source;
|
||||
DiagnosticChecker diagChecker;
|
||||
LambdaReturnKind lambdaReturnKind;
|
||||
RetTypeKind[] returnType = new RetTypeKind[2];
|
||||
ArgTypeKind[] argumentKind = new ArgTypeKind[2];
|
||||
|
||||
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();
|
||||
boolean hasSameArguments() {
|
||||
return argumentKind[0] == argumentKind[1];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
boolean hasCompatibleReturns() {
|
||||
return lambdaReturnKind.compatibleWith(returnType[0]) &&
|
||||
lambdaReturnKind.compatibleWith(returnType[1]);
|
||||
}
|
||||
|
||||
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();
|
||||
boolean hasSameOverloadPhase() {
|
||||
return lambdaReturnKind.needsConversion(returnType[0]) == lambdaReturnKind.needsConversion(returnType[1]);
|
||||
}
|
||||
|
||||
void check() {
|
||||
checkCount.incrementAndGet();
|
||||
@Override
|
||||
public void doWork() throws Throwable {
|
||||
check(newCompilationTask()
|
||||
.withSourceFromTemplate(sourceTemplate)
|
||||
.withOption("-XDverboseResolution=all,-predef,-internal,-object-init")
|
||||
.analyze());
|
||||
}
|
||||
|
||||
if (ak1 != ak2)
|
||||
return;
|
||||
|
||||
if (!lrk.compatibleWith(rt1) || !lrk.compatibleWith(rt2))
|
||||
return;
|
||||
|
||||
if (lrk.needsConversion(rt1) != lrk.needsConversion(rt2))
|
||||
return;
|
||||
|
||||
boolean m1MoreSpecific = rt1.moreSpecificThan(rt2);
|
||||
boolean m2MoreSpecific = rt2.moreSpecificThan(rt1);
|
||||
void check(Result<Iterable<? extends Element>> 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 @@ public class StructuralMostSpecificTest
|
||||
|
||||
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<JavaFileObject> {
|
||||
|
||||
boolean ambiguityFound;
|
||||
String mostSpecificSig;
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> 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;
|
||||
}
|
||||
}
|
||||
boolean ambiguityFound(Result<Iterable<? extends Element>> result) {
|
||||
return result.containsKey("compiler.err.ref.ambiguous");
|
||||
}
|
||||
|
||||
String mostSpecificSignature(Result<Iterable<? extends Element>> result) {
|
||||
List<Diagnostic<? extends JavaFileObject>> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<TypeInferenceComboTest> {
|
||||
enum Context {
|
||||
ASSIGNMENT("SAM#Type s = #LBody;"),
|
||||
METHOD_CALL("#GenericDeclKind void method1(SAM#Type s) { }\n" +
|
||||
@ -221,82 +221,21 @@ public class TypeInferenceComboTest
|
||||
}
|
||||
}
|
||||
|
||||
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<JavaFileObject> {
|
||||
|
||||
boolean errorFound = false;
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
|
||||
errorFound = true;
|
||||
}
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
new ComboTestHelper<TypeInferenceComboTest>()
|
||||
.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 @@ public class TypeInferenceComboTest
|
||||
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;
|
||||
}
|
||||
|
||||
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 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));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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<StandardJavaFileManager> fm =
|
||||
new ThreadLocal<StandardJavaFileManager>() {
|
||||
@Override protected StandardJavaFileManager initialValue() {
|
||||
return comp.getStandardFileManager(null, null, null);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
128
langtools/test/tools/javac/lib/combo/ComboInstance.java
Normal file
128
langtools/test/tools/javac/lib/combo/ComboInstance.java
Normal file
@ -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<X extends ComboInstance<X>> {
|
||||
|
||||
/** The test instance result status. */
|
||||
private ResultStatus resultStatus = ResultStatus.PASSED;
|
||||
|
||||
/** The test instance execution environment. */
|
||||
private ComboTestHelper<X>.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<X>.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;
|
||||
}
|
||||
}
|
||||
}
|
112
langtools/test/tools/javac/lib/combo/ComboParameter.java
Normal file
112
langtools/test/tools/javac/lib/combo/ComboParameter.java
Normal file
@ -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:
|
||||
* <p>
|
||||
* #{MAJOR}
|
||||
* #{MAJOR.}
|
||||
* #{MAJOR.MINOR}
|
||||
* <p>
|
||||
* 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<D> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
359
langtools/test/tools/javac/lib/combo/ComboTask.java
Normal file
359
langtools/test/tools/javac/lib/combo/ComboTask.java
Normal file
@ -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<JavaFileObject> sources = List.nil();
|
||||
|
||||
/** Options associated with this task. */
|
||||
private List<String> options = List.nil();
|
||||
|
||||
/** Diagnostic collector. */
|
||||
private DiagnosticCollector diagsCollector = new DiagnosticCollector();
|
||||
|
||||
/** Output writer. */
|
||||
private Writer out;
|
||||
|
||||
/** Listeners associated with this task. */
|
||||
private List<TaskListener> 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<? extends String> 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<Iterable<? extends CompilationUnitTree>> parse() throws IOException {
|
||||
return new Result<>(getTask().parse());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and analyzes the sources associated with this task.
|
||||
*/
|
||||
public Result<Iterable<? extends Element>> analyze() throws IOException {
|
||||
return new Result<>(getTask().analyze());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse, analyze and perform code generation for the sources associated with this task.
|
||||
*/
|
||||
public Result<Iterable<? extends JavaFileObject>> 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<D> {
|
||||
|
||||
/** 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<Diagnostic<? extends JavaFileObject>> diagnosticsForKind(Diagnostic.Kind kind) {
|
||||
List<Diagnostic<? extends JavaFileObject>> diags = diagsCollector.diagsByKind.get(kind);
|
||||
return diags != null ? diags : List.nil();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the list of diagnostics with given key.
|
||||
*/
|
||||
public List<Diagnostic<? extends JavaFileObject>> diagnosticsForKey(String key) {
|
||||
List<Diagnostic<? extends JavaFileObject>> 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<String, ComboParameter> 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<JavaFileObject> {
|
||||
|
||||
Map<Diagnostic.Kind, List<Diagnostic<? extends JavaFileObject>>> diagsByKind = new HashMap<>();
|
||||
Map<String, List<Diagnostic<? extends JavaFileObject>>> diagsByKeys = new HashMap<>();
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
List<Diagnostic<? extends JavaFileObject>> 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));
|
||||
}
|
||||
}
|
||||
}
|
444
langtools/test/tools/javac/lib/combo/ComboTestHelper.java
Normal file
444
langtools/test/tools/javac/lib/combo/ComboTestHelper.java
Normal file
@ -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:
|
||||
* <p>
|
||||
* 'public' 'class'
|
||||
* 'public' interface'
|
||||
* 'package-private' 'class'
|
||||
* 'package-private' 'interface'
|
||||
* ...
|
||||
* <p>
|
||||
* 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?).
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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<X extends ComboInstance<X>> {
|
||||
|
||||
/** Failure mode. */
|
||||
FailMode failMode = FailMode.FAIL_FAST;
|
||||
|
||||
/** Ignore mode. */
|
||||
IgnoreMode ignoreMode = IgnoreMode.IGNORE_NONE;
|
||||
|
||||
/** Combo test instance filter. */
|
||||
Optional<Predicate<X>> optFilter = Optional.empty();
|
||||
|
||||
/** Combo test dimensions. */
|
||||
List<DimensionInfo<?>> 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<X> withFailMode(FailMode failMode) {
|
||||
this.failMode = failMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set ignore mode for this combo test.
|
||||
*/
|
||||
public ComboTestHelper<X> withIgnoreMode(IgnoreMode ignoreMode) {
|
||||
this.ignoreMode = ignoreMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a filter for combo test instances to be ignored.
|
||||
*/
|
||||
public ComboTestHelper<X> withFilter(Predicate<X> 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 <D> ComboTestHelper<X> 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 <D> ComboTestHelper<X> withDimension(String name, DimensionSetter<X, D> 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 <D> ComboTestHelper<X> 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 <D> ComboTestHelper<X> withArrayDimension(String name, ArrayDimensionSetter<X, D> 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<X> 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<X> instanceBuilder, Consumer<X> 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<DimensionBinding<?>> bindings, Supplier<X> instanceBuilder, Optional<Consumer<X>> 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<X> instanceBuilder, Optional<Consumer<X>> initAction, List<DimensionBinding<?>> 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<X extends ComboInstance<X>, 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<X extends ComboInstance<X>, 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<D> {
|
||||
String name;
|
||||
D[] dims;
|
||||
boolean isParameter;
|
||||
Optional<DimensionSetter<X, D>> optSetter;
|
||||
|
||||
DimensionInfo(String name, D[] dims, DimensionSetter<X, D> 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<D> extends DimensionInfo<D> {
|
||||
public ArrayDimensionInfo(String name, D[] dims, int index, ArrayDimensionSetter<X, D> 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 d;
|
||||
DimensionInfo<D> info;
|
||||
|
||||
DimensionBinding(D d, DimensionInfo<D> 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<String> lastFailure = Optional.empty();
|
||||
Optional<Throwable> 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<DimensionBinding<?>> bindings;
|
||||
Map<String, ComboParameter> parametersCache = new HashMap<>();
|
||||
|
||||
@SuppressWarnings({"Unchecked", "rawtypes"})
|
||||
Env(List<DimensionBinding<?>> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
197
langtools/test/tools/javac/lib/combo/ReusableContext.java
Normal file
197
langtools/test/tools/javac/lib/combo/ReusableContext.java
Normal file
@ -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.
|
||||
* <p>
|
||||
* 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<CompilationUnitTree> 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<Void, Void>() {
|
||||
@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
|
||||
}
|
||||
|
||||
<T> void drop(Key<T> k) {
|
||||
ht.remove(k);
|
||||
}
|
||||
|
||||
<T> void drop(Class<T> 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<JavaCompiler> 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<Log> 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<JavaFileObject>() {
|
||||
DiagnosticListener<JavaFileObject> cachedListener;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
if (cachedListener == null) {
|
||||
cachedListener = context.get(DiagnosticListener.class);
|
||||
}
|
||||
cachedListener.report(diagnostic);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -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<DisjunctiveTypeWellFormednessTest> {
|
||||
|
||||
enum Alternative implements ComboParameter {
|
||||
EXCEPTION("Exception"),
|
||||
RUNTIME_EXCEPTION("RuntimeException"),
|
||||
IO_EXCEPTION("java.io.IOException"),
|
||||
@ -55,21 +56,10 @@ public class DisjunctiveTypeWellFormednessTest
|
||||
|
||||
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 @@ public class DisjunctiveTypeWellFormednessTest
|
||||
/*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<DisjunctiveTypeWellFormednessTest>()
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
checkAfterExec(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
String template = "class Test {\n" +
|
||||
"void test() {\n" +
|
||||
"try {} catch (#{CTYPE} e) {}\n" +
|
||||
"}\n" +
|
||||
"}\n";
|
||||
|
||||
@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();
|
||||
public void doWork() throws IOException {
|
||||
check(newCompilationTask()
|
||||
.withSourceFromTemplate(template)
|
||||
.analyze());
|
||||
}
|
||||
|
||||
void check() {
|
||||
void check(Result<?> res) {
|
||||
|
||||
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)) {
|
||||
for (int i = 0 ; i < arity.n ; i++) {
|
||||
for (int j = 0 ; j < i ; j++) {
|
||||
if (!alternatives[i].disjoint(alternatives[j])) {
|
||||
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<JavaFileObject> {
|
||||
|
||||
int errorsFound;
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
|
||||
diagnostic.getCode().startsWith("compiler.err.multicatch.types.must.be.disjoint")) {
|
||||
errorsFound++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
488
langtools/test/tools/javac/parser/8134007/T8134007.java
Normal file
488
langtools/test/tools/javac/parser/8134007/T8134007.java
Normal file
@ -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;
|
||||
}
|
@ -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<JavaFileObject> dc = new DiagnosticCollector<>();
|
||||
List<JavaSource> 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<BitWiseOperators> {
|
||||
|
||||
enum OperandType implements ComboParameter {
|
||||
BYTE,
|
||||
CHAR,
|
||||
SHORT,
|
||||
@ -69,45 +52,57 @@ public class BitWiseOperators extends JavacTestingAbstractThreadedTest {
|
||||
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<BitWiseOperators>()
|
||||
.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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ public class ScopeListenerTest {
|
||||
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 @@ public class ScopeListenerTest {
|
||||
;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.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 java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
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.ConstantPool.*;
|
||||
import com.sun.tools.classfile.Method;
|
||||
import com.sun.tools.javac.util.List;
|
||||
|
||||
public class T7042566
|
||||
extends JavacTestingAbstractThreadedTest
|
||||
implements Runnable {
|
||||
import combo.ComboInstance;
|
||||
import combo.ComboParameter;
|
||||
import combo.ComboTask.Result;
|
||||
import combo.ComboTestHelper;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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<T7042566> {
|
||||
|
||||
enum TypeKind {
|
||||
OBJECT("Object", "(Object)null", "Ljava/lang/Object;"),
|
||||
@ -216,7 +77,7 @@ public class T7042566
|
||||
}
|
||||
}
|
||||
|
||||
enum TypeConfiguration {
|
||||
enum TypeConfiguration implements ComboParameter {
|
||||
A(TypeKind.OBJECT),
|
||||
B(TypeKind.STRING),
|
||||
AA(TypeKind.OBJECT, TypeKind.OBJECT),
|
||||
@ -237,7 +98,7 @@ public class T7042566
|
||||
String parameterListStr;
|
||||
String bytecodeSigStr;
|
||||
|
||||
private TypeConfiguration(TypeKind... typeKindList) {
|
||||
TypeConfiguration(TypeKind... typeKindList) {
|
||||
this.typeKindList = List.from(typeKindList);
|
||||
expressionListStr = asExpressionList();
|
||||
parameterListStr = asParameterList();
|
||||
@ -284,6 +145,11 @@ public class T7042566
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String expand(String optParameter) {
|
||||
return expressionListStr;
|
||||
}
|
||||
}
|
||||
|
||||
static class VarargsMethod {
|
||||
@ -333,31 +199,119 @@ public class T7042566
|
||||
}
|
||||
}
|
||||
|
||||
static class ErrorChecker
|
||||
implements javax.tools.DiagnosticListener<JavaFileObject> {
|
||||
public static void main(String[] args) {
|
||||
new ComboTestHelper<T7042566>()
|
||||
.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<String> errDiags = List.nil();
|
||||
VarargsMethod m1;
|
||||
VarargsMethod m2;
|
||||
TypeConfiguration[] methodSignatures = new TypeConfiguration[2];
|
||||
TypeConfiguration actuals;
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
|
||||
errDiags = errDiags
|
||||
.append(diagnostic.getMessage(Locale.getDefault()));
|
||||
errorFound = true;
|
||||
}
|
||||
}
|
||||
void setup() {
|
||||
this.m1 = new VarargsMethod(methodSignatures[0]);
|
||||
this.m2 = new VarargsMethod(methodSignatures[1]);
|
||||
}
|
||||
|
||||
String printDiags() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (String s : errDiags) {
|
||||
buf.append(s);
|
||||
buf.append("\n");
|
||||
}
|
||||
return buf.toString();
|
||||
final String source_template = "class Test {\n" +
|
||||
" #{METH.1}\n" +
|
||||
" #{METH.2}\n" +
|
||||
" void test() { m(#{ACTUALS}); }\n" +
|
||||
"}";
|
||||
|
||||
@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<Iterable<? extends JavaFileObject>> 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<Iterable<? extends JavaFileObject>> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Warn4> {
|
||||
|
||||
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 @@ public class Warn4
|
||||
}
|
||||
}
|
||||
|
||||
enum TrustMe {
|
||||
enum TrustMe implements ComboParameter {
|
||||
DONT_TRUST(""),
|
||||
TRUST("@java.lang.SafeVarargs");
|
||||
|
||||
@ -114,9 +113,14 @@ public class Warn4
|
||||
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 @@ public class Warn4
|
||||
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 @@ public class Warn4
|
||||
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("<Z> void #name(List<Z>#arity arg) { #body }",
|
||||
INVARIANT_TVAR("<Z> void #NAME(List<Z>#ARITY arg) { #BODY }",
|
||||
new Warning[][] {both, both, error, both, error}),
|
||||
TVAR("<Z> void #name(Z#arity arg) { #body }",
|
||||
TVAR("<Z> void #NAME(Z#ARITY arg) { #BODY }",
|
||||
new Warning[][] {both, both, both, both, vararg}),
|
||||
INVARIANT("void #name(List<String>#arity arg) { #body }",
|
||||
INVARIANT("void #NAME(List<String>#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 @@ public class Warn4
|
||||
return warnings[other.ordinal()] == vararg ||
|
||||
warnings[other.ordinal()] == both;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@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", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkAfterExec();
|
||||
public static void main(String... args) {
|
||||
new ComboTestHelper<Warn4>()
|
||||
.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<Warning> warnings = new HashSet<>();
|
||||
for (Diagnostic<? extends JavaFileObject> 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<JavaFileObject> {
|
||||
|
||||
Set<Warning> warnings = new HashSet<>();
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<Warn5> {
|
||||
|
||||
enum XlintOption {
|
||||
NONE("none"),
|
||||
@ -65,7 +66,7 @@ public class Warn5
|
||||
}
|
||||
}
|
||||
|
||||
enum TrustMe {
|
||||
enum TrustMe implements ComboParameter {
|
||||
DONT_TRUST(""),
|
||||
TRUST("@java.lang.SafeVarargs");
|
||||
|
||||
@ -74,20 +75,26 @@ public class Warn5
|
||||
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 @@ public class Warn5
|
||||
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 @@ public class Warn5
|
||||
MethodKind(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String expand(String optParameter) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
enum SourceLevel {
|
||||
@ -123,11 +140,11 @@ public class Warn5
|
||||
}
|
||||
}
|
||||
|
||||
enum SignatureKind {
|
||||
VARARGS_X("#K <X>#N(X... x)", false, true),
|
||||
VARARGS_STRING("#K #N(String... x)", true, true),
|
||||
ARRAY_X("#K <X>#N(X[] x)", false, false),
|
||||
ARRAY_STRING("#K #N(String[] x)", true, false);
|
||||
enum SignatureKind implements ComboParameter {
|
||||
VARARGS_X("<X>#{NAME}(X... x)", false, true),
|
||||
VARARGS_STRING("#{NAME}(String... x)", true, true),
|
||||
ARRAY_X("<X>#{NAME}(X[] x)", false, false),
|
||||
ARRAY_STRING("#{NAME}(String[] x)", true, false);
|
||||
|
||||
String stub;
|
||||
boolean isReifiableArg;
|
||||
@ -139,14 +156,13 @@ public class Warn5
|
||||
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 @@ public class Warn5
|
||||
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) 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
new ComboTestHelper<Warn5>()
|
||||
.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);
|
||||
}
|
||||
|
||||
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<WarningKind> foundWarnings = EnumSet.noneOf(WarningKind.class);
|
||||
for (Diagnostic.Kind kind : new Kind[] { Kind.ERROR, Kind.MANDATORY_WARNING, Kind.WARNING}) {
|
||||
for (Diagnostic<? extends JavaFileObject> 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<WarningKind> expectedWarnings =
|
||||
EnumSet.noneOf(WarningKind.class);
|
||||
|
||||
@ -284,77 +302,14 @@ public class Warn5
|
||||
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);
|
||||
"\nFound warnings: " + foundWarnings);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
class DiagnosticChecker
|
||||
implements javax.tools.DiagnosticListener<JavaFileObject> {
|
||||
|
||||
EnumSet<WarningKind> warnings = EnumSet.noneOf(WarningKind.class);
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user