8173807: JShell: control characters should be escaped in String values
authorrfield
Mon, 06 Feb 2017 09:25:31 -0800
changeset 43587 6103af590758
parent 43586 cc7a4eb79b29
child 43588 6a0e0ea0e93b
8173807: JShell: control characters should be escaped in String values Reviewed-by: jlahoda
langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/DirectExecutionControl.java
langtools/test/jdk/jshell/SimpleRegressionTest.java
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/DirectExecutionControl.java	Mon Feb 06 09:00:02 2017 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/DirectExecutionControl.java	Mon Feb 06 09:25:31 2017 -0800
@@ -28,6 +28,7 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.stream.IntStream;
 import jdk.jshell.spi.ExecutionControl;
 import jdk.jshell.spi.SPIResolutionException;
 
@@ -41,6 +42,23 @@
  */
 public class DirectExecutionControl implements ExecutionControl {
 
+    private static final String[] charRep;
+
+    static {
+        charRep = new String[256];
+        for (int i = 0; i < charRep.length; ++i) {
+            charRep[i] = Character.isISOControl(i)
+                    ? String.format("\\%03o", i)
+                    : "" + (char) i;
+        }
+        charRep['\b'] = "\\b";
+        charRep['\t'] = "\\t";
+        charRep['\n'] = "\\n";
+        charRep['\f'] = "\\f";
+        charRep['\r'] = "\\r";
+        charRep['\\'] = "\\\\";
+    }
+
     private final LoaderDelegate loaderDelegate;
 
     /**
@@ -192,9 +210,26 @@
         if (value == null) {
             return "null";
         } else if (value instanceof String) {
-            return "\"" + (String) value + "\"";
+            return "\"" + ((String) value).codePoints()
+                    .flatMap(cp ->
+                        (cp == '"')
+                            ? "\\\"".codePoints()
+                            : (cp < 256)
+                                ? charRep[cp].codePoints()
+                                : IntStream.of(cp))
+                    .collect(
+                            StringBuilder::new,
+                            StringBuilder::appendCodePoint,
+                            StringBuilder::append)
+                    .toString() + "\"";
         } else if (value instanceof Character) {
-            return "'" + value + "'";
+            char cp = (char) (Character) value;
+            return "'" + (
+                (cp == '\'')
+                    ? "\\\'"
+                    : (cp < 256)
+                            ? charRep[cp]
+                            : String.valueOf(cp)) + "'";
         } else if (value.getClass().isArray()) {
             int dims = 0;
             Class<?> t = value.getClass();
--- a/langtools/test/jdk/jshell/SimpleRegressionTest.java	Mon Feb 06 09:00:02 2017 -0800
+++ b/langtools/test/jdk/jshell/SimpleRegressionTest.java	Mon Feb 06 09:25:31 2017 -0800
@@ -22,7 +22,7 @@
  */
 
 /*
- * @test 8130450 8158906 8154374 8166400 8171892 8173848
+ * @test 8130450 8158906 8154374 8166400 8171892 8173807 8173848
  * @summary simple regression test
  * @build KullaTesting TestingInputStream
  * @run testng SimpleRegressionTest
@@ -191,4 +191,36 @@
         assertEval("new boolean[2][1][3]",
                 "boolean[2][][] { boolean[1][] { boolean[3] { false, false, false } }, boolean[1][] { boolean[3] { false, false, false } } }");
     }
+
+    public void testStringRepresentation() {
+        assertEval("\"A!\\rB!\"",
+                   "\"A!\\rB!\"");
+        assertEval("\"a\\bB\\tc\\nd\\fe\\rf\\\"g'\\\\h\"",
+                   "\"a\\bB\\tc\\nd\\fe\\rf\\\"g'\\\\h\"");
+        assertEval("\"\\141\\10B\\11c\\nd\\fe\\15f\\42g\\'\\134h\"",
+                   "\"a\\bB\\tc\\nd\\fe\\rf\\\"g'\\\\h\"");
+        assertEval("\"1234567890!@#$%^&*()-_=+qwertQWERT,./<>?;:[]{}\"",
+                   "\"1234567890!@#$%^&*()-_=+qwertQWERT,./<>?;:[]{}\"");
+        assertEval("\"AA\\1\\7\\35\\25\"",
+                   "\"AA\\001\\007\\035\\025\"");
+        assertEval("\"\"",
+                   "\"\"");
+        assertEval("(String)null",
+                   "null");
+    }
+
+    public void testCharRepresentation() {
+        for (String s : new String[]{"'A'", "'Z'", "'0'", "'9'",
+            "'a'", "'z'", "'*'", "'%'",
+            "'\\b'", "'\\t'", "'\\n'", "'\\f'", "'\\r'",
+            "'\"'", "'\\\''", "'\\\\'", "'\\007'", "'\\034'",}) {
+            assertEval(s, s);
+        }
+        assertEval("'\\3'",
+                "'\\003'");
+        assertEval("'\\u001D'",
+                "'\\035'");
+        assertEval("\"a\\bb\\tc\\nd\\fe\\rf\\\"g'\\\\h\".charAt(1)",
+                "'\\b'");
+    }
 }