8152925: JShell: enable corralling of any type declaration, including enum
Reviewed-by: jlahoda
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java
index 349e393..ce9ee86 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java
@@ -25,124 +25,125 @@
package jdk.jshell;
-import java.util.List;
-import com.sun.source.tree.ArrayTypeTree;
+import java.io.IOException;
+import java.io.StringWriter;
import com.sun.source.tree.ClassTree;
-import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
-import com.sun.source.tree.VariableTree;
-import jdk.jshell.Wrap.Range;
-import static java.util.stream.Collectors.toList;
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCBlock;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCNewClass;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.tree.Pretty;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Names;
+import static com.sun.tools.javac.code.Flags.STATIC;
+import static com.sun.tools.javac.code.Flags.INTERFACE;
+import static com.sun.tools.javac.code.Flags.ENUM;
+import static com.sun.tools.javac.code.Flags.PUBLIC;
/**
* Produce a corralled version of the Wrap for a snippet.
+ * Incoming tree is mutated.
*
* @author Robert Field
*/
-class Corraller {
+class Corraller extends Pretty {
- private final int index;
- private final String compileSource;
- private final TreeDissector dis;
+ private final StringWriter out;
+ private final int keyIndex;
+ private final TreeMaker make;
+ private final Names names;
+ private JCBlock resolutionExceptionBlock;
- Corraller(int index, String compileSource, TreeDissector dis) {
- this.index = index;
- this.compileSource = compileSource;
- this.dis = dis;
+ public Corraller(int keyIndex, Context context) {
+ this(new StringWriter(), keyIndex, context);
}
- Wrap corralTree(Tree tree, String enclosingType, int indent) {
- switch (tree.getKind()) {
- case VARIABLE:
- return corralVariable((VariableTree) tree, indent);
- case CLASS:
- case ENUM:
- case ANNOTATION_TYPE:
- case INTERFACE:
- return corralType((ClassTree) tree, indent);
- case METHOD:
- return corralMethod((MethodTree) tree, enclosingType, indent);
- default:
- return null;
- }
+ private Corraller(StringWriter out, int keyIndex, Context context) {
+ super(out, false);
+ this.out = out;
+ this.keyIndex = keyIndex;
+ this.make = TreeMaker.instance(context);
+ this.names = Names.instance(context);
}
- Wrap corralMethod(MethodTree mt) {
- return corralMethod(mt, null, 1);
+ public Wrap corralType(ClassTree ct) {
+ ((JCClassDecl) ct).mods.flags |= Flags.STATIC | Flags.PUBLIC;
+ return corral(ct);
}
- Wrap corralMethod(MethodTree mt, String enclosingType, int indent) {
- Range modRange = dis.treeToRange(mt.getModifiers());
- Range tpRange = dis.treeListToRange(mt.getTypeParameters());
- Range typeRange = dis.treeToRange(mt.getReturnType());
- String name = mt.getName().toString();
- if ("<init>".equals(name)) {
- name = enclosingType;
- }
- Range paramRange = dis.treeListToRange(mt.getParameters());
- Range throwsRange = dis.treeListToRange(mt.getThrows());
- return Wrap.corralledMethod(compileSource,
- modRange, tpRange, typeRange, name, paramRange, throwsRange, index, indent);
+ public Wrap corralMethod(MethodTree mt) {
+ ((JCMethodDecl) mt).mods.flags |= Flags.STATIC | Flags.PUBLIC;
+ return corral(mt);
}
- Wrap corralVariable(VariableTree vt, int indent) {
- String name = vt.getName().toString();
- Range modRange = dis.treeToRange(vt.getModifiers());
- Tree baseType = vt.getType();
- StringBuilder sbBrackets = new StringBuilder();
- while (baseType instanceof ArrayTypeTree) {
- //TODO handle annotations too
- baseType = ((ArrayTypeTree) baseType).getType();
- sbBrackets.append("[]");
+ private Wrap corral(Tree tree) {
+ try {
+ printStat((JCTree) tree);
+ } catch (IOException e) {
+ throw new AssertionError(e);
}
- Range rtype = dis.treeToRange(baseType);
- Range runit = dis.treeToRange(vt);
- runit = new Range(runit.begin, runit.end - 1);
- ExpressionTree it = vt.getInitializer();
- int nameMax;
- if (it != null) {
- Range rinit = dis.treeToRange(it);
- nameMax = rinit.begin - 1;
- } else {
- nameMax = runit.end - 1;
- }
- int nameStart = compileSource.lastIndexOf(name, nameMax);
- if (nameStart < 0) {
- throw new AssertionError("Name '" + name + "' not found");
- }
- int nameEnd = nameStart + name.length();
- Range rname = new Range(nameStart, nameEnd);
- return Wrap.corralledVar(compileSource, modRange, rtype, sbBrackets.toString(), rname, indent);
+ return Wrap.simpleWrap(out.toString());
}
- Wrap corralType(ClassTree ct, int indent) {
- boolean isClass;
- switch (ct.getKind()) {
- case CLASS:
- isClass = true;
- break;
- case INTERFACE:
- isClass = false;
- break;
- default:
- return null;
+ @Override
+ public void visitBlock(JCBlock tree) {
+ // Top-level executable blocks (usually method bodies) are corralled
+ super.visitBlock((tree.flags & STATIC) != 0
+ ? tree
+ : resolutionExceptionBlock());
+ }
+
+ @Override
+ public void visitVarDef(JCVariableDecl tree) {
+ // No field inits in corralled classes
+ tree.init = null;
+ super.visitVarDef(tree);
+ }
+
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ if ((tree.mods.flags & (INTERFACE | ENUM)) == 0 &&
+ !tree.getMembers().stream()
+ .anyMatch(t -> t.getKind() == Tree.Kind.METHOD &&
+ ((MethodTree) t).getName() == tree.name.table.names.init)) {
+ // Generate a default constructor, since
+ // this is a regular class and there are no constructors
+ ListBuffer<JCTree> ndefs = new ListBuffer<>();
+ ndefs.addAll(tree.defs);
+ ndefs.add(make.MethodDef(make.Modifiers(PUBLIC),
+ tree.name.table.names.init,
+ null, List.nil(), List.nil(), List.nil(),
+ resolutionExceptionBlock(), null));
+ tree.defs = ndefs.toList();
}
- Range modRange = dis.treeToRange(ct.getModifiers());
- String name = ct.getSimpleName().toString();
- Range tpRange = dis.treeListToRange(ct.getTypeParameters());
- Range extendsRange = dis.treeToRange(ct.getExtendsClause());
- List<Range> implementsRanges = ct.getImplementsClause().stream()
- .map(ic -> dis.treeToRange(ic))
- .collect(toList());
- List<Wrap> members = ct.getMembers().stream()
- .map(t -> corralTree(t, name, indent + 1))
- .filter(w -> w != null)
- .collect(toList());
- boolean hasConstructor = ct.getMembers().stream()
- .anyMatch(t -> t.getKind() == Tree.Kind.METHOD && ((MethodTree) t).getName().toString().equals("<init>"));
- Wrap wrap = Wrap.corralledType(compileSource, modRange, ct.getKind(), name, tpRange,
- extendsRange, implementsRanges, members, isClass && !hasConstructor, index, indent);
- return wrap;
+ super.visitClassDef(tree);
+ }
+
+ private JCBlock resolutionExceptionBlock() {
+ if (resolutionExceptionBlock == null) {
+ JCExpression expClass
+ = make.Select(make.Select(make.Select(make.Select(
+ make.Ident(names.fromString("jdk")),
+ names.fromString("internal")),
+ names.fromString("jshell")),
+ names.fromString("remote")),
+ names.fromString("RemoteResolutionException")
+ );
+ JCNewClass exp = make.NewClass(null,
+ null, expClass, List.of(make.Literal(keyIndex)), null);
+ resolutionExceptionBlock = make.Block(0L, List.<JCStatement>of(
+ make.Throw(exp)));
+ }
+ return resolutionExceptionBlock;
}
}
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
index 6108403..64b4d98 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
@@ -50,6 +50,7 @@
import java.io.Writer;
import java.util.LinkedHashSet;
import java.util.Set;
+import com.sun.tools.javac.util.Context;
import jdk.jshell.ClassTracker.ClassInfo;
import jdk.jshell.Key.ErroneousKey;
import jdk.jshell.Key.MethodKey;
@@ -133,7 +134,7 @@
}
private List<SnippetEvent> processImport(String userSource, String compileSource) {
- Wrap guts = Wrap.importWrap(compileSource);
+ Wrap guts = Wrap.simpleWrap(compileSource);
Matcher mat = IMPORT_PATTERN.matcher(compileSource);
String fullname;
String name;
@@ -300,13 +301,15 @@
ClassTree klassTree = (ClassTree) unitTree;
String name = klassTree.getSimpleName().toString();
- Wrap guts = Wrap.classMemberWrap(compileSource);
+ DiagList modDiag = modifierDiagnostics(klassTree.getModifiers(), dis, false);
TypeDeclKey key = state.keyMap.keyForClass(name);
- Wrap corralled = new Corraller(key.index(), compileSource, dis).corralType(klassTree, 1);
- Snippet snip = new TypeDeclSnippet(state.keyMap.keyForClass(name), userSource, guts,
+ // Corralling mutates. Must be last use of pt, unitTree, klassTree
+ Wrap corralled = new Corraller(key.index(), pt.getContext()).corralType(klassTree);
+
+ Wrap guts = Wrap.classMemberWrap(compileSource);
+ Snippet snip = new TypeDeclSnippet(key, userSource, guts,
name, snippetKind,
corralled, tds.declareReferences(), tds.bodyReferences());
- DiagList modDiag = modifierDiagnostics(klassTree.getModifiers(), dis, false);
return declare(snip, modDiag);
}
@@ -354,31 +357,30 @@
private List<SnippetEvent> processMethod(String userSource, Tree unitTree, String compileSource, ParseTask pt) {
TreeDependencyScanner tds = new TreeDependencyScanner();
tds.scan(unitTree);
+ TreeDissector dis = TreeDissector.createByFirstClass(pt);
MethodTree mt = (MethodTree) unitTree;
- TreeDissector dis = TreeDissector.createByFirstClass(pt);
- DiagList modDiag = modifierDiagnostics(mt.getModifiers(), dis, true);
- if (modDiag.hasErrors()) {
- return compileFailResult(modDiag, userSource);
- }
- String unitName = mt.getName().toString();
- Wrap guts = Wrap.classMemberWrap(compileSource);
-
- Range typeRange = dis.treeToRange(mt.getReturnType());
String name = mt.getName().toString();
-
String parameterTypes
= mt.getParameters()
.stream()
.map(param -> dis.treeToRange(param.getType()).part(compileSource))
.collect(Collectors.joining(","));
+ Tree returnType = mt.getReturnType();
+ DiagList modDiag = modifierDiagnostics(mt.getModifiers(), dis, true);
+ MethodKey key = state.keyMap.keyForMethod(name, parameterTypes);
+ // Corralling mutates. Must be last use of pt, unitTree, mt
+ Wrap corralled = new Corraller(key.index(), pt.getContext()).corralMethod(mt);
+
+ if (modDiag.hasErrors()) {
+ return compileFailResult(modDiag, userSource);
+ }
+ Wrap guts = Wrap.classMemberWrap(compileSource);
+ Range typeRange = dis.treeToRange(returnType);
String signature = "(" + parameterTypes + ")" + typeRange.part(compileSource);
- MethodKey key = state.keyMap.keyForMethod(name, parameterTypes);
- // rewrap with correct Key index
- Wrap corralled = new Corraller(key.index(), compileSource, dis).corralMethod(mt);
Snippet snip = new MethodSnippet(key, userSource, guts,
- unitName, signature,
+ name, signature,
corralled, tds.declareReferences(), tds.bodyReferences());
return declare(snip, modDiag);
}
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
index c7be108..45f9661 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
@@ -258,7 +258,7 @@
OuterWrap codeWrap;
switch (guessKind(code)) {
case IMPORT:
- codeWrap = OuterWrap.wrapImport(null, Wrap.importWrap(code + "any.any"));
+ codeWrap = OuterWrap.wrapImport(null, Wrap.simpleWrap(code + "any.any"));
break;
case METHOD:
codeWrap = wrapInClass(Wrap.classMemberWrap(code));
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java
index 6275931..3dd3975 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java
@@ -25,9 +25,6 @@
package jdk.jshell;
-import java.util.ArrayList;
-import java.util.List;
-import com.sun.source.tree.Tree;
import static jdk.internal.jshell.remote.RemoteCodes.DOIT_METHOD_NAME;
/**
@@ -67,97 +64,6 @@
return "\n" + indent(n);
}
- public static Wrap corralledMethod(String source, Range modRange, Range tpRange,
- Range typeRange, String name, Range paramRange, Range throwsRange, int id, int indent) {
- List<Object> l = new ArrayList<>();
- l.add(indent(indent) + ((indent == 1) ? "public static" + nlindent(indent) : ""));
- if (!modRange.isEmpty()) {
- l.add(new RangeWrap(source, modRange));
- l.add(" ");
- }
- if (tpRange != null) {
- l.add("<");
- l.add(new RangeWrap(source, tpRange));
- l.add("> ");
- }
- if (!typeRange.isEmpty()) {
- l.add(new RangeWrap(source, typeRange));
- l.add(" ");
- }
- l.add(name + "(");
- if (paramRange != null && !paramRange.isEmpty()) {
- l.add(nlindent(indent + 1));
- l.add(new RangeWrap(source, paramRange));
- }
- l.add(")");
- if (throwsRange != null) {
- l.add(" throws ");
- l.add(new RangeWrap(source, throwsRange));
- }
- l.add(" {"
- + nlindent(indent+1)
- + "throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");"
- + nlindent(indent)
- + "}\n");
- return new CompoundWrap(l.toArray());
- }
-
- public static Wrap corralledType(String source, Range modRange, Tree.Kind kind, String name, Range tpRange,
- Range extendsRange, List<Range> implementsRanges, List<Wrap> members,
- boolean defaultConstructor, int id, int indent) {
- boolean isInterface = kind == Tree.Kind.INTERFACE;
- List<Object> l = new ArrayList<>();
- l.add(indent(indent) + ((indent == 1) ? "public static" + nlindent(indent) : ""));
- if (!modRange.isEmpty()) {
- l.add(new RangeWrap(source, modRange));
- l.add(" ");
- }
- l.add((isInterface ? "interface " : "class ") + name);
- if (tpRange != null) {
- l.add("<");
- l.add(new RangeWrap(source, tpRange));
- l.add("> ");
- }
- if (extendsRange != null && !extendsRange.isEmpty()) {
- l.add(" extends ");
- l.add(new RangeWrap(source, extendsRange));
- }
- for (int i = 0; i < implementsRanges.size(); ++i) {
- Range ir = implementsRanges.get(i);
- l.add(i == 0 ? " implements " : ", ");
- l.add(new RangeWrap(source, ir));
- }
- if (defaultConstructor) {
- l.add(" {"
- + nlindent(indent+1)
- + ((indent == 1)? "public " : "") + name + "() {"
- + nlindent(indent+2)
- + "throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");"
- + nlindent(indent+1)
- + "}\n");
- } else {
- l.add(" {\n");
- }
- l.addAll(members);
- l.add(indent(indent) + "}\n");
- return new CompoundWrap(l.toArray());
- }
-
- public static Wrap corralledVar(String source, Range modRange, Range typeRange, String brackets, Range nameRange, int indent) {
- RangeWrap wname = new RangeWrap(source, nameRange);
- List<Object> l = new ArrayList<>();
- l.add(indent(indent) + ((indent == 1) ? "public static" + nlindent(indent) : ""));
- if (!modRange.isEmpty()) {
- l.add(new RangeWrap(source, modRange));
- l.add(" ");
- }
- l.add(new RangeWrap(source, typeRange));
- l.add(" ");
- l.add(wname);
- l.add(semi(wname));
- return new CompoundWrap(l.toArray());
- }
-
/**
*
* @param in
@@ -200,7 +106,7 @@
return new CompoundWrap(varDecl, wInitMeth);
}
- public static Wrap importWrap(String source) {
+ public static Wrap simpleWrap(String source) {
return new NoWrap(source);
}
diff --git a/langtools/test/jdk/jshell/ReplaceTest.java b/langtools/test/jdk/jshell/ReplaceTest.java
index 36b1c50..60807c0 100644
--- a/langtools/test/jdk/jshell/ReplaceTest.java
+++ b/langtools/test/jdk/jshell/ReplaceTest.java
@@ -22,7 +22,7 @@
*/
/*
- * @test 8080069
+ * @test 8080069 8152925
* @summary Test of Snippet redefinition and replacement.
* @build KullaTesting TestingInputStream
* @run testng ReplaceTest
@@ -374,18 +374,18 @@
}
public void testForwardVarToEnum() {
- DeclarationSnippet a = classKey(assertEval("enum E { Q, W, E; float ff() { return fff; } }", added(RECOVERABLE_NOT_DEFINED)));
- assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "variable fff");
+ DeclarationSnippet a = classKey(assertEval("enum E { Q, W, E; float ff() { return fff; } }", added(RECOVERABLE_DEFINED)));
+ assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable fff");
Snippet g = varKey(assertEval("float fff = 4.5f;", "4.5",
added(VALID),
- ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)));
+ ste(a, RECOVERABLE_DEFINED, VALID, false, null)));
assertEval("E.Q.ff();", "4.5");
assertEval("double fff = 3.3;", "3.3", null,
DiagCheck.DIAG_OK,
DiagCheck.DIAG_ERROR,
ste(MAIN_SNIPPET, VALID, VALID, true, null),
ste(g, VALID, OVERWRITTEN, false, MAIN_SNIPPET),
- ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET));
+ ste(a, VALID, RECOVERABLE_DEFINED, false, MAIN_SNIPPET));
assertUnresolvedDependencies(a, 0);
assertActiveKeys();
}