8142384: JShell tool: New command: /imports, /i which show the list of imported packages or classes, etc...
authorshinyafox
Thu, 12 Nov 2015 08:48:42 +0100
changeset 33714 8064f484590e
parent 33713 dc1d2632935c
child 33715 74b1bed86932
8142384: JShell tool: New command: /imports, /i which show the list of imported packages or classes, etc... Reviewed-by: rfield, jlahoda
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/ImportSnippet.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java
langtools/test/jdk/jshell/ReplToolTesting.java
langtools/test/jdk/jshell/ToolBasicTest.java
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Thu Nov 12 08:39:23 2015 +0530
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Thu Nov 12 08:48:42 2015 +0100
@@ -675,6 +675,9 @@
         registerCommand(new Command("/classes", "/c", null, "list the declared classes",
                                     arg -> cmdClasses(),
                                     EMPTY_COMPLETION_PROVIDER));
+        registerCommand(new Command("/imports", "/i", null, "list the imported items",
+                                    arg -> cmdImports(),
+                                    EMPTY_COMPLETION_PROVIDER));
         registerCommand(new Command("/exit", "/x", null, "exit the REPL",
                                     arg -> cmdExit(),
                                     EMPTY_COMPLETION_PROVIDER));
@@ -1256,6 +1259,12 @@
         }
     }
 
+    private void cmdImports() {
+        state.imports().forEach(ik -> {
+            hard("  import %s%s", ik.isStatic() ? "static " : "", ik.fullname());
+        });
+    }
+
     private void cmdUseHistoryEntry(int index) {
         List<Snippet> keys = state.snippets();
         if (index < 0)
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ImportSnippet.java	Thu Nov 12 08:39:23 2015 +0530
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ImportSnippet.java	Thu Nov 12 08:48:42 2015 +0100
@@ -68,6 +68,29 @@
         return key().name();
     }
 
+    /**
+     *
+     * The qualified name of the import. For any imports
+     * ({@link jdk.jshell.Snippet.SubKind#TYPE_IMPORT_ON_DEMAND_SUBKIND},
+     * ({@link jdk.jshell.Snippet.SubKind#STATIC_IMPORT_ON_DEMAND_SUBKIND}),
+     * ({@link jdk.jshell.Snippet.SubKind#SINGLE_TYPE_IMPORT_SUBKIND} or
+     * ({@link jdk.jshell.Snippet.SubKind#SINGLE_STATIC_IMPORT_SUBKIND})
+     * that is the full specifier including any
+     * qualifiers and the asterisks.
+     * @return the fullname of the import
+     */
+    public String fullname() {
+        return fullname;
+    }
+
+    /**
+     * When this snippet represent static import, this method returns true.
+     * @return true when this snippet represent static import, otherwise false
+     */
+    public boolean isStatic() {
+        return isStatic;
+    }
+
     /**** internal access ****/
 
     @Override
@@ -75,10 +98,6 @@
         return (ImportKey) super.key();
     }
 
-    boolean isStatic() {
-        return isStatic;
-    }
-
     @Override
     String importLine(JShell state) {
         return source();
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java	Thu Nov 12 08:39:23 2015 +0530
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java	Thu Nov 12 08:48:42 2015 +0100
@@ -469,6 +469,22 @@
     }
 
     /**
+     * Returns the active import snippets.
+     * This convenience method is equivalent to <code>snippets()</code> filtered for
+     * {@link jdk.jshell.Snippet.Status#isActive status(snippet).isActive}
+     * <code>&amp;&amp; snippet.kind() == Kind.IMPORT</code>
+     * and cast to ImportSnippet.
+     * @return the active declared import declarations.
+     * @throws IllegalStateException if this JShell instance is closed.
+     */
+    public List<ImportSnippet> imports() throws IllegalStateException {
+        return snippets().stream()
+                .filter(sn -> status(sn).isActive && sn.kind() == Snippet.Kind.IMPORT)
+                .map(sn -> (ImportSnippet) sn)
+                .collect(collectingAndThen(toList(), Collections::unmodifiableList));
+    }
+
+    /**
      * Return the status of the snippet.
      * This is updated either because of an explicit <code>eval()</code> call or
      * an automatic update triggered by a dependency.
--- a/langtools/test/jdk/jshell/ReplToolTesting.java	Thu Nov 12 08:39:23 2015 +0530
+++ b/langtools/test/jdk/jshell/ReplToolTesting.java	Thu Nov 12 08:48:42 2015 +0100
@@ -27,11 +27,10 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -62,6 +61,7 @@
     private Map<String, VariableInfo> variables;
     private Map<String, MethodInfo> methods;
     private Map<String, ClassInfo> classes;
+    private Map<String, ImportInfo> imports;
     private boolean isDefaultStartUp = true;
 
     public JShellTool repl = null;
@@ -127,6 +127,10 @@
         return assertMembers("Classes", classes);
     }
 
+    public Consumer<String> assertImports() {
+        return assertMembers("Imports", imports);
+    }
+
     public String getCommandOutput() {
         String s = cmdout.toString();
         cmdout.reset();
@@ -184,9 +188,21 @@
         variables = new HashMap<>();
         methods = new HashMap<>();
         classes = new HashMap<>();
+        imports = new HashMap<>();
         if (isDefaultStartUp) {
             methods.put("printf (String,Object...)void",
                     new MethodInfo("", "(String,Object...)void", "printf"));
+            imports.putAll(
+                Stream.of(
+                    "java.util.*",
+                    "java.io.*",
+                    "java.math.*",
+                    "java.net.*",
+                    "java.util.concurrent.*",
+                    "java.util.prefs.*",
+                    "java.util.regex.*")
+                    .map(s -> new ImportInfo("", "", s))
+                    .collect(Collectors.toMap(Object::toString, Function.identity())));
         }
     }
 
@@ -300,6 +316,19 @@
         addKey(after, clazz);
     }
 
+    public void loadImport(boolean after, String src, String type, String name) {
+        ImportInfo i = new ImportInfo(src, type, name);
+        addKey(after, i, imports);
+        addKey(after, i);
+    }
+
+    public void assertImport(boolean after, String src, String type, String name) {
+        ImportInfo i = new ImportInfo(src, type, name);
+        assertCommandCheckOutput(after, src, i.checkOutput());
+        addKey(after, i, imports);
+        addKey(after, i);
+    }
+
     private <T extends MemberInfo> void addKey(boolean after, T memberInfo, Map<String, T> map) {
         if (after) {
             map.entrySet().removeIf(e -> e.getValue().equals(memberInfo));
@@ -347,6 +376,10 @@
         dropKey(after, cmd, name, classes);
     }
 
+    public void dropImport(boolean after, String cmd, String name) {
+        dropKey(after, cmd, name, imports);
+    }
+
     public void assertCommand(boolean after, String cmd, String out) {
         assertCommand(after, cmd, out, "", null, "", "");
     }
@@ -580,6 +613,31 @@
         }
     }
 
+    public static class ImportInfo extends MemberInfo {
+        public ImportInfo(String source, String type, String fullname) {
+            super(source, type, fullname);
+        }
+
+        @Override
+        public Consumer<String> checkOutput() {
+            return s -> assertTrue("".equals(s), "Expected: '', actual: " + s);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o instanceof ImportInfo) {
+                ImportInfo i = (ImportInfo) o;
+                return name.equals(i.name) && type.equals(i.type);
+            }
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("import %s%s", type.equals("static") ? "static " : "", name);
+        }
+    }
+
     class WaitingTestingInputStream extends TestingInputStream {
 
         @Override
--- a/langtools/test/jdk/jshell/ToolBasicTest.java	Thu Nov 12 08:39:23 2015 +0530
+++ b/langtools/test/jdk/jshell/ToolBasicTest.java	Thu Nov 12 08:48:42 2015 +0100
@@ -24,7 +24,6 @@
 /*
  * @test
  * @summary Tests for Basic tests for REPL tool
- * @ignore 8139873
  * @library /tools/lib
  * @build KullaTesting TestingInputStream ToolBox Compiler
  * @run testng ToolBasicTest
@@ -139,7 +138,13 @@
                     (a) -> assertCommand(a, "class A {}\u0003", ""),
                     (a) -> assertCommandCheckOutput(a, "/c", assertClasses()),
                     (a) -> assertClass(a, "interface A {}", "interface", "A"),
-                    (a) -> assertCommandCheckOutput(a, "/c", assertClasses())
+                    (a) -> assertCommandCheckOutput(a, "/c", assertClasses()),
+                    (a) -> assertCommand(a, "import java.util.stream." + s, ""),
+                    interrupt,
+                    (a) -> assertCommand(a, "import java.util.stream.\u0003", ""),
+                    (a) -> assertCommandCheckOutput(a, "/i", assertImports()),
+                    (a) -> assertImport(a, "import java.util.stream.Stream", "", "java.util.stream.Stream"),
+                    (a) -> assertCommandCheckOutput(a, "/i", assertImports())
             );
         }
     }
@@ -364,6 +369,35 @@
         );
     }
 
+    public void defineImports() {
+        test(
+                (a) -> assertCommandCheckOutput(a, "/l", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/i", assertImports()),
+                (a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
+                (a) -> assertImport(a, "import java.util.stream.Stream;", "", "java.util.stream.Stream"),
+                (a) -> assertCommandCheckOutput(a, "/l", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/i", assertImports()),
+                (a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
+                (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
+                (a) -> assertCommandCheckOutput(a, "/l", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/i", assertImports()),
+                (a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
+                (a) -> assertImport(a, "import static java.lang.Math.PI;", "static", "java.lang.Math.PI"),
+                (a) -> assertCommandCheckOutput(a, "/l", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/i", assertImports()),
+                (a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
+                (a) -> assertImport(a, "import static java.lang.Math.*;", "static", "java.lang.Math.*"),
+                (a) -> assertCommandCheckOutput(a, "/l", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/i", assertImports()),
+                (a) -> assertCommandCheckOutput(a, "/imports", assertImports())
+        );
+    }
+
     public void testClasspathDirectory() {
         Compiler compiler = new Compiler();
         Path outDir = Paths.get("testClasspathDirectory");
@@ -443,10 +477,13 @@
                 (a) -> assertCommandCheckOutput(a, "/m", assertMethods()),
                 (a) -> assertClass(a, "class A { }", "class", "A"),
                 (a) -> assertCommandCheckOutput(a, "/c", assertClasses()),
+                (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
+                (a) -> assertCommandCheckOutput(a, "/i", assertImports()),
                 (a) -> assertReset(a, "/reset"),
                 (a) -> assertCommandCheckOutput(a, "/v", assertVariables()),
                 (a) -> assertCommandCheckOutput(a, "/m", assertMethods()),
-                (a) -> assertCommandCheckOutput(a, "/c", assertClasses())
+                (a) -> assertCommandCheckOutput(a, "/c", assertClasses()),
+                (a) -> assertCommandCheckOutput(a, "/i", assertImports())
         );
     }
 
@@ -455,22 +492,26 @@
         Path path = compiler.getPath("testOpen.repl");
         compiler.writeToFile(path,
                 "int a = 10;\ndouble x = 20;\ndouble a = 10;\n" +
-                        "class A { public String toString() { return \"A\"; } }");
+                        "class A { public String toString() { return \"A\"; } }\nimport java.util.stream.*;");
         for (String s : new String[]{"/o", "/open"}) {
             test(
                     (a) -> assertCommand(a, s + " " + path.toString(), ""),
                     (a) -> assertCommand(a, "a", "|  Variable a of type double has value 10.0\n"),
                     (a) -> evaluateExpression(a, "A", "new A();", "\"A\""),
+                    (a) -> evaluateExpression(a, "long", "Stream.of(\"A\").count();", "1"),
                     (a) -> {
                         loadVariable(a, "double", "x", "20.0", "20.0");
                         loadVariable(a, "double", "a", "10.0", "10.0");
-                        loadVariable(a, "A", "$6", "new A();", "A");
+                        loadVariable(a, "A", "$7", "new A();", "A");
+                        loadVariable(a, "long", "$8", "Stream.of(\"A\").count();", "1");
                         loadClass(a, "class A { public String toString() { return \"A\"; } }",
                                 "class", "A");
+                        loadImport(a, "import java.util.stream.*;", "", "java.util.stream.*");
                         assertCommandCheckOutput(a, "/c", assertClasses());
                     },
                     (a) -> assertCommandCheckOutput(a, "/m", assertMethods()),
-                    (a) -> assertCommandCheckOutput(a, "/v", assertVariables())
+                    (a) -> assertCommandCheckOutput(a, "/v", assertVariables()),
+                    (a) -> assertCommandCheckOutput(a, "/i", assertImports())
             );
             Path unknown = compiler.getPath("UNKNOWN.repl");
             test(
@@ -536,6 +577,7 @@
                     (a) -> assertVariable(a, "int", "a"),
                     (a) -> assertVariable(a, "double", "b", "10", "10.0"),
                     (a) -> assertMethod(a, "void f() {}", "()V", "f"),
+                    (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
                     (a) -> assertCommand(a, "/s " + startUpFile.toString(), null),
                     (a) -> assertCommand(a, "/setstart " + startUpFile.toString(), null)
             );
@@ -549,10 +591,12 @@
                         loadVariable(a, "int", "a");
                         loadVariable(a, "double", "b", "10.0", "10.0");
                         loadMethod(a, "void f() {}", "()void", "f");
+                        loadImport(a, "import java.util.stream.*;", "", "java.util.stream.*");
                         assertCommandCheckOutput(a, "/c", assertClasses());
                     },
                     (a) -> assertCommandCheckOutput(a, "/v", assertVariables()),
-                    (a) -> assertCommandCheckOutput(a, "/m", assertMethods())
+                    (a) -> assertCommandCheckOutput(a, "/m", assertMethods()),
+                    (a) -> assertCommandCheckOutput(a, "/i", assertImports())
             );
         } finally {
             removeStartup();
@@ -768,9 +812,12 @@
                     a -> dropMethod(a, drop + " 2", "b ()I"),
                     a -> assertClass(a, "class A {}", "class", "A"),
                     a -> dropClass(a, drop + " 3", "class A"),
+                    a -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
+                    a -> dropImport(a, drop + " 4", "import java.util.stream.*"),
                     a -> assertCommandCheckOutput(a, "/v", assertVariables()),
                     a -> assertCommandCheckOutput(a, "/m", assertMethods()),
-                    a -> assertCommandCheckOutput(a, "/c", assertClasses())
+                    a -> assertCommandCheckOutput(a, "/c", assertClasses()),
+                    a -> assertCommandCheckOutput(a, "/i", assertImports())
             );
             test(false, new String[]{"-nostartup"},
                     a -> assertVariable(a, "int", "a"),
@@ -781,7 +828,8 @@
                     a -> dropClass(a, drop + " A", "class A"),
                     a -> assertCommandCheckOutput(a, "/v", assertVariables()),
                     a -> assertCommandCheckOutput(a, "/m", assertMethods()),
-                    a -> assertCommandCheckOutput(a, "/c", assertClasses())
+                    a -> assertCommandCheckOutput(a, "/c", assertClasses()),
+                    a -> assertCommandCheckOutput(a, "/i", assertImports())
             );
         }
     }
@@ -814,7 +862,8 @@
                     a -> assertCommandCheckOutput(a, drop + " a", check),
                     a -> assertCommandCheckOutput(a, "/v", assertVariables()),
                     a -> assertCommandCheckOutput(a, "/m", assertMethods()),
-                    a -> assertCommandCheckOutput(a, "/c", assertClasses())
+                    a -> assertCommandCheckOutput(a, "/c", assertClasses()),
+                    a -> assertCommandCheckOutput(a, "/i", assertImports())
             );
             test(
                     a -> assertMethod(a, "int a() { return 0; }", "()int", "a"),