# HG changeset patch # User rfield # Date 1459527633 25200 # Node ID 6bf2bef08a914ef72b3c4f797aa6ebaad3f0eecc # Parent 9a030c4d2591763466978fe5e2226bc375146989 8152925: JShell: enable corralling of any type declaration, including enum Reviewed-by: jlahoda diff -r 9a030c4d2591 -r 6bf2bef08a91 langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java Tue Mar 29 10:24:30 2016 -0700 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java Fri Apr 01 09:20:33 2016 -0700 @@ -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); + } + + public Wrap corralType(ClassTree ct) { + ((JCClassDecl) ct).mods.flags |= Flags.STATIC | Flags.PUBLIC; + return corral(ct); } - Wrap corralMethod(MethodTree mt) { - return corralMethod(mt, null, 1); + public Wrap corralMethod(MethodTree mt) { + ((JCMethodDecl) mt).mods.flags |= Flags.STATIC | Flags.PUBLIC; + return corral(mt); } - 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 ("".equals(name)) { - name = enclosingType; + private Wrap corral(Tree tree) { + try { + printStat((JCTree) tree); + } catch (IOException e) { + throw new AssertionError(e); } - Range paramRange = dis.treeListToRange(mt.getParameters()); - Range throwsRange = dis.treeListToRange(mt.getThrows()); - return Wrap.corralledMethod(compileSource, - modRange, tpRange, typeRange, name, paramRange, throwsRange, index, indent); + return Wrap.simpleWrap(out.toString()); } - 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("[]"); - } - 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); + @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); } - 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 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 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 implementsRanges = ct.getImplementsClause().stream() - .map(ic -> dis.treeToRange(ic)) - .collect(toList()); - List 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("")); - 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.of( + make.Throw(exp))); + } + return resolutionExceptionBlock; } } diff -r 9a030c4d2591 -r 6bf2bef08a91 langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java Tue Mar 29 10:24:30 2016 -0700 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java Fri Apr 01 09:20:33 2016 -0700 @@ -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 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 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 -r 9a030c4d2591 -r 6bf2bef08a91 langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java Tue Mar 29 10:24:30 2016 -0700 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java Fri Apr 01 09:20:33 2016 -0700 @@ -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 -r 9a030c4d2591 -r 6bf2bef08a91 langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java Tue Mar 29 10:24:30 2016 -0700 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java Fri Apr 01 09:20:33 2016 -0700 @@ -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 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 implementsRanges, List members, - boolean defaultConstructor, int id, int indent) { - boolean isInterface = kind == Tree.Kind.INTERFACE; - List 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 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 -r 9a030c4d2591 -r 6bf2bef08a91 langtools/test/jdk/jshell/ReplaceTest.java --- a/langtools/test/jdk/jshell/ReplaceTest.java Tue Mar 29 10:24:30 2016 -0700 +++ b/langtools/test/jdk/jshell/ReplaceTest.java Fri Apr 01 09:20:33 2016 -0700 @@ -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(); }