8159027: JShell API: SourceCodeAnalysis.Suggestion has constructor, ...
authorrfield
Mon, 15 Aug 2016 11:39:53 -0700
changeset 40498 f54048be4a57
parent 40320 2e83d21d78cd
child 40499 ac4c100be583
8159027: JShell API: SourceCodeAnalysis.Suggestion has constructor, ... Reviewed-by: jlahoda
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
langtools/test/jdk/jshell/CompletenessStressTest.java
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Wed Jul 05 22:05:29 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Mon Aug 15 11:39:53 2016 -0700
@@ -923,7 +923,7 @@
 
             for (String alternative : alternatives) {
                 if (alternative.startsWith(input)) {
-                    result.add(new Suggestion(alternative, false));
+                    result.add(new ArgSuggestion(alternative));
                 }
             }
 
@@ -951,7 +951,7 @@
             List<Suggestion> result = new ArrayList<>();
             try (Stream<Path> dir = Files.list(current)) {
                 dir.filter(f -> accept.test(f) && f.getFileName().toString().startsWith(prefix))
-                   .map(f -> new Suggestion(f.getFileName() + (Files.isDirectory(f) ? "/" : ""), false))
+                   .map(f -> new ArgSuggestion(f.getFileName() + (Files.isDirectory(f) ? "/" : "")))
                    .forEach(result::add);
             } catch (IOException ex) {
                 //ignore...
@@ -959,7 +959,7 @@
             if (path.isEmpty()) {
                 StreamSupport.stream(FileSystems.getDefault().getRootDirectories().spliterator(), false)
                              .filter(root -> accept.test(root) && root.toString().startsWith(prefix))
-                             .map(root -> new Suggestion(root.toString(), false))
+                             .map(root -> new ArgSuggestion(root.toString()))
                              .forEach(result::add);
             }
             anchor[0] = path.length();
@@ -981,7 +981,7 @@
                                 ? Stream.of(String.valueOf(k.id()), ((DeclarationSnippet) k).name())
                                 : Stream.of(String.valueOf(k.id())))
                         .filter(k -> k.startsWith(prefix))
-                        .map(k -> new Suggestion(k, false))
+                        .map(k -> new ArgSuggestion(k))
                         .collect(Collectors.toList());
         };
     }
@@ -1146,7 +1146,7 @@
                              .filter(cmd -> cmd.kind.shouldSuggestCompletions)
                              .map(cmd -> cmd.command)
                              .filter(key -> key.startsWith(prefix))
-                             .map(key -> new Suggestion(key + " ", false));
+                             .map(key -> new ArgSuggestion(key + " "));
             anchor[0] = 0;
         } else {
             String arg = prefix.substring(space + 1);
@@ -2457,6 +2457,42 @@
             this.tid = tid;
         }
     }
+
+    private static class ArgSuggestion implements Suggestion {
+
+        private final String continuation;
+
+        /**
+         * Create a {@code Suggestion} instance.
+         *
+         * @param continuation a candidate continuation of the user's input
+         */
+        public ArgSuggestion(String continuation) {
+            this.continuation = continuation;
+        }
+
+        /**
+         * The candidate continuation of the given user's input.
+         *
+         * @return the continuation string
+         */
+        @Override
+        public String continuation() {
+            return continuation;
+        }
+
+        /**
+         * Indicates whether input continuation matches the target type and is thus
+         * more likely to be the desired continuation. A matching continuation is
+         * preferred.
+         *
+         * @return {@code false}, non-types analysis
+         */
+        @Override
+        public boolean matchesType() {
+            return false;
+        }
+    }
 }
 
 abstract class NonInteractiveIOContext extends IOContext {
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java	Wed Jul 05 22:05:29 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java	Mon Aug 15 11:39:53 2016 -0700
@@ -144,30 +144,16 @@
 
     /**
      * The result of {@code analyzeCompletion(String input)}.
-     * Describes the completeness and position of the first snippet in the given input.
+     * Describes the completeness of the first snippet in the given input.
      */
-    public static class CompletionInfo {
-
-        private final Completeness completeness;
-        private final int unitEndPos;
-        private final String source;
-        private final String remaining;
-
-        CompletionInfo(Completeness completeness, int unitEndPos, String source, String remaining) {
-            this.completeness = completeness;
-            this.unitEndPos = unitEndPos;
-            this.source = source;
-            this.remaining = remaining;
-        }
+    public interface CompletionInfo {
 
         /**
          * The analyzed completeness of the input.
          *
          * @return an enum describing the completeness of the input string.
          */
-        public Completeness completeness() {
-            return completeness;
-        }
+        Completeness completeness();
 
         /**
          * Input remaining after the complete part of the source.
@@ -175,9 +161,7 @@
          * @return the portion of the input string that remains after the
          * complete Snippet
          */
-        public String remaining() {
-            return remaining;
-        }
+        String remaining();
 
         /**
          * Source code for the first Snippet of code input. For example, first
@@ -186,18 +170,7 @@
          *
          * @return the source of the first encountered Snippet
          */
-        public String source() {
-            return source;
-        }
-
-        /**
-         * The end of the first Snippet of source.
-         *
-         * @return the position of the end of the first Snippet in the input.
-         */
-        public int unitEndPos() {
-            return unitEndPos;
-        }
+        String source();
     }
 
     /**
@@ -272,30 +245,14 @@
     /**
      * A candidate for continuation of the given user's input.
      */
-    public static class Suggestion {
-
-        private final String continuation;
-        private final boolean matchesType;
-
-        /**
-         * Create a {@code Suggestion} instance.
-         *
-         * @param continuation a candidate continuation of the user's input
-         * @param matchesType does the candidate match the target type
-         */
-        public Suggestion(String continuation, boolean matchesType) {
-            this.continuation = continuation;
-            this.matchesType = matchesType;
-        }
+    public interface Suggestion {
 
         /**
          * The candidate continuation of the given user's input.
          *
          * @return the continuation string
          */
-        public String continuation() {
-            return continuation;
-        }
+        String continuation();
 
         /**
          * Indicates whether input continuation matches the target type and is thus
@@ -305,9 +262,7 @@
          * @return {@code true} if this suggested continuation matches the
          * target type; otherwise {@code false}
          */
-        public boolean matchesType() {
-            return matchesType;
-        }
+        boolean matchesType();
     }
 
     /**
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Wed Jul 05 22:05:29 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Mon Aug 15 11:39:53 2016 -0700
@@ -171,13 +171,13 @@
         MaskCommentsAndModifiers mcm = new MaskCommentsAndModifiers(srcInput, false);
         if (mcm.endsWithOpenComment()) {
             proc.debug(DBG_COMPA, "Incomplete (open comment): %s\n", srcInput);
-            return new CompletionInfo(DEFINITELY_INCOMPLETE, srcInput.length(), null, srcInput + '\n');
+            return new CompletionInfoImpl(DEFINITELY_INCOMPLETE, null, srcInput + '\n');
         }
         String cleared = mcm.cleared();
         String trimmedInput = Util.trimEnd(cleared);
         if (trimmedInput.isEmpty()) {
             // Just comment or empty
-            return new CompletionInfo(Completeness.EMPTY, srcInput.length(), srcInput, "");
+            return new CompletionInfoImpl(Completeness.EMPTY, srcInput, "");
         }
         CaInfo info = ca.scan(trimmedInput);
         Completeness status = info.status;
@@ -195,12 +195,12 @@
                             + mcm.mask().substring(nonCommentNonWhiteLength);
                     proc.debug(DBG_COMPA, "Complete: %s\n", compileSource);
                     proc.debug(DBG_COMPA, "   nothing remains.\n");
-                    return new CompletionInfo(status, unitEndPos, compileSource, "");
+                    return new CompletionInfoImpl(status, compileSource, "");
                 } else {
                     String remain = srcInput.substring(unitEndPos);
                     proc.debug(DBG_COMPA, "Complete: %s\n", src);
                     proc.debug(DBG_COMPA, "          remaining: %s\n", remain);
-                    return new CompletionInfo(status, unitEndPos, src, remain);
+                    return new CompletionInfoImpl(status, src, remain);
                 }
             case COMPLETE_WITH_SEMI:
                 // The unit is the whole non-coment/white input plus semicolon
@@ -209,19 +209,19 @@
                         + mcm.mask().substring(nonCommentNonWhiteLength);
                 proc.debug(DBG_COMPA, "Complete with semi: %s\n", compileSource);
                 proc.debug(DBG_COMPA, "   nothing remains.\n");
-                return new CompletionInfo(status, unitEndPos, compileSource, "");
+                return new CompletionInfoImpl(status, compileSource, "");
             case DEFINITELY_INCOMPLETE:
                 proc.debug(DBG_COMPA, "Incomplete: %s\n", srcInput);
-                return new CompletionInfo(status, unitEndPos, null, srcInput + '\n');
+                return new CompletionInfoImpl(status, null, srcInput + '\n');
             case CONSIDERED_INCOMPLETE:
                 proc.debug(DBG_COMPA, "Considered incomplete: %s\n", srcInput);
-                return new CompletionInfo(status, unitEndPos, null, srcInput + '\n');
+                return new CompletionInfoImpl(status, null, srcInput + '\n');
             case EMPTY:
                 proc.debug(DBG_COMPA, "Detected empty: %s\n", srcInput);
-                return new CompletionInfo(status, unitEndPos, srcInput, "");
+                return new CompletionInfoImpl(status, srcInput, "");
             case UNKNOWN:
                 proc.debug(DBG_COMPA, "Detected error: %s\n", srcInput);
-                return new CompletionInfo(status, unitEndPos, srcInput, "");
+                return new CompletionInfoImpl(status, srcInput, "");
         }
         throw new InternalError();
     }
@@ -665,7 +665,7 @@
             if (c.getKind() == ElementKind.CONSTRUCTOR || c.getKind() == ElementKind.METHOD) {
                 simpleName += paren.apply(hasParams.contains(simpleName));
             }
-            result.add(new Suggestion(simpleName, smart.test(c)));
+            result.add(new SuggestionImpl(simpleName, smart.test(c)));
         }
     }
 
@@ -1700,4 +1700,98 @@
             }
         }
     }
+
+    /**
+     * A candidate for continuation of the given user's input.
+     */
+    private static class SuggestionImpl implements Suggestion {
+
+        private final String continuation;
+        private final boolean matchesType;
+
+        /**
+         * Create a {@code Suggestion} instance.
+         *
+         * @param continuation a candidate continuation of the user's input
+         * @param matchesType does the candidate match the target type
+         */
+        public SuggestionImpl(String continuation, boolean matchesType) {
+            this.continuation = continuation;
+            this.matchesType = matchesType;
+        }
+
+        /**
+         * The candidate continuation of the given user's input.
+         *
+         * @return the continuation string
+         */
+        @Override
+        public String continuation() {
+            return continuation;
+        }
+
+        /**
+         * Indicates whether input continuation matches the target type and is thus
+         * more likely to be the desired continuation. A matching continuation is
+         * preferred.
+         *
+         * @return {@code true} if this suggested continuation matches the
+         * target type; otherwise {@code false}
+         */
+        @Override
+        public boolean matchesType() {
+            return matchesType;
+        }
+    }
+
+    /**
+     * The result of {@code analyzeCompletion(String input)}.
+     * Describes the completeness and position of the first snippet in the given input.
+     */
+    private static class CompletionInfoImpl implements CompletionInfo {
+
+        private final Completeness completeness;
+        private final String source;
+        private final String remaining;
+
+        CompletionInfoImpl(Completeness completeness, String source, String remaining) {
+            this.completeness = completeness;
+            this.source = source;
+            this.remaining = remaining;
+        }
+
+        /**
+         * The analyzed completeness of the input.
+         *
+         * @return an enum describing the completeness of the input string.
+         */
+        @Override
+        public Completeness completeness() {
+            return completeness;
+        }
+
+        /**
+         * Input remaining after the complete part of the source.
+         *
+         * @return the portion of the input string that remains after the
+         * complete Snippet
+         */
+        @Override
+        public String remaining() {
+            return remaining;
+        }
+
+        /**
+         * Source code for the first Snippet of code input. For example, first
+         * statement, or first method declaration. Trailing semicolons will be
+         * added, as needed.
+         *
+         * @return the source of the first encountered Snippet
+         */
+        @Override
+        public String source() {
+            return source;
+        }
+    }
+
 }
--- a/langtools/test/jdk/jshell/CompletenessStressTest.java	Wed Jul 05 22:05:29 2017 +0200
+++ b/langtools/test/jdk/jshell/CompletenessStressTest.java	Mon Aug 15 11:39:53 2016 -0700
@@ -253,10 +253,8 @@
                 writer.write(String.format("Empty statement: row %d, column %d: -- %s\n",
                         start, end, unit));
             } else {
-                String oops = unit.substring(max(0, ci.unitEndPos() - 10), ci.unitEndPos()) + "|||" +
-                        unit.substring(ci.unitEndPos(), min(unit.length(), ci.unitEndPos() + 10));
                 writer.write(String.format("Expected %s got %s: '%s'  row %d, column %d: -- %s\n",
-                        expected, ci.completeness(), oops, row, column, unit));
+                        expected, ci.completeness(), unit, row, column, unit));
                 return false;
             }
         }