1 /* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8149524 8131024 8165211 8080071 8130454 8167343 8129559 8114842 8182268 27 * @summary Test SourceCodeAnalysis 28 * @build KullaTesting TestingInputStream 29 * @run testng CompletenessTest 30 */ 31 32 import java.util.Map; 33 import java.util.HashMap; 34 35 import org.testng.annotations.Test; 36 import jdk.jshell.SourceCodeAnalysis.Completeness; 37 38 import static jdk.jshell.SourceCodeAnalysis.Completeness.*; 39 40 @Test 41 public class CompletenessTest extends KullaTesting { 42 43 // Add complete units that end with semicolon to complete_with_semi (without 44 // the semicolon). Both cases will be tested. 45 static final String[] complete = new String[] { 46 "{ x= 4; }", 47 "int mm(int x) {kll}", 48 "if (t) { ddd; }", 49 "for (int i = 0; i < lines.length(); ++i) { foo }", 50 "while (ct == null) { switch (current.kind) { case EOF: { } } }", 51 "if (match.kind == BRACES && (prevCT.kind == ARROW || prevCT.kind == NEW_MIDDLE)) { new CT(UNMATCHED, current, \"Unmatched \" + unmatched); }", 52 "enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM); }", 53 "List<T> f() { return null; }", 54 "List<?> f() { return null; }", 55 "List<? extends Object> f() { return null; }", 56 "Map<? extends Object, ? super Object> f() { return null; }", 57 "class C { int z; }", 58 "synchronized (r) { f(); }", 59 "try { } catch (Exception ex) { }", 60 "try { } catch (Exception ex) { } finally { }", 61 "try { } finally { }", 62 "try (java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName)) { }", 63 "foo: while (true) { printf(\"Innn\"); break foo; }", 64 "class Case<E1 extends Enum<E1>, E2 extends Enum<E2>, E3 extends Enum<E3>> {}", 65 ";", 66 "enum Tt { FOO, BAR, BAZ,; }" 67 }; 68 69 static final String[] expression = new String[] { 70 "test", 71 "x + y", 72 "x + y ++", 73 "p = 9", 74 "match(BRACKETS, TokenKind.LBRACKET)", 75 "new C()", 76 "new C() { public String toString() { return \"Hi\"; } }", 77 "new int[]", 78 "new int[] {1, 2,3}", 79 "new Foo() {}", 80 "i >= 0 && Character.isWhitespace(s.charAt(i))", 81 "int.class", 82 "String.class", 83 }; 84 85 static final String[] complete_with_semi = new String[] { 86 "int mm", 87 "if (t) ddd", 88 "int p = 9", 89 "int p", 90 "Deque<Token> stack = new ArrayDeque<>()", 91 "final Deque<Token> stack = new ArrayDeque<>()", 92 "java.util.Scanner input = new java.util.Scanner(System.in)", 93 "java.util.Scanner input = new java.util.Scanner(System.in) { }", 94 "int j = -i", 95 "String[] a = { \"AAA\" }", 96 "assert true", 97 "int path[]", 98 "int path[][]", 99 "int path[][] = new int[22][]", 100 "int path[] = new int[22]", 101 "int path[] = new int[] {1, 2, 3}", 102 "int[] path", 103 "int path[] = new int[22]", 104 "int path[][] = new int[22][]", 105 "for (Object o : a) System.out.println(\"Yep\")", 106 "while (os == null) System.out.println(\"Yep\")", 107 "do f(); while (t)", 108 "if (os == null) System.out.println(\"Yep\")", 109 "if (t) if (!t) System.out.println(123)", 110 "for (int i = 0; i < 10; ++i) if (i < 5) System.out.println(i); else break", 111 "for (int i = 0; i < 10; ++i) if (i < 5) System.out.println(i); else continue", 112 "for (int i = 0; i < 10; ++i) if (i < 5) System.out.println(i); else return", 113 "throw ex", 114 "C c = new C()", 115 "java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName)", 116 "BufferedReader br = new BufferedReader(new FileReader(path))", 117 "bar: g()", 118 "baz: while (true) if (t()) printf('-'); else break baz", 119 "java.util.function.IntFunction<int[]> ggg = int[]::new", 120 "List<? extends Object> l", 121 "int[] m = {1, 2}", 122 "int[] m = {1, 2}, n = null", 123 "int[] m = {1, 2}, n", 124 "int[] m = {1, 2}, n = {3, 4}", 125 }; 126 127 static final String[] considered_incomplete = new String[] { 128 "if (t)", 129 "if (t) { } else", 130 "if (t) if (!t)", 131 "if (match.kind == BRACES && (prevCT.kind == ARROW || prevCT.kind == NEW_MIDDLE))", 132 "for (int i = 0; i < 10; ++i)", 133 "while (os == null)", 134 }; 135 136 static final String[] definitely_incomplete = new String[] { 137 "int mm(", 138 "int mm(int x", 139 "int mm(int x)", 140 "int mm(int x) {", 141 "int mm(int x) {kll", 142 "if", 143 "if (", 144 "if (t", 145 "if (t) {", 146 "if (t) { ddd", 147 "if (t) { ddd;", 148 "if (t) if (", 149 "if (stack.isEmpty()) {", 150 "if (match.kind == BRACES && (prevCT.kind == ARROW || prevCT.kind == NEW_MIDDLE)) {", 151 "if (match.kind == BRACES && (prevCT.kind == ARROW || prevCT.kind == NEW_MIDDLE)) { new CT(UNMATCHED, current, \"Unmatched \" + unmatched);", 152 "x +", 153 "x *", 154 "3 *", 155 "int", 156 "for (int i = 0; i < lines.length(); ++i) {", 157 "new", 158 "new C(", 159 "new int[", 160 "new int[] {1, 2,3", 161 "new int[] {", 162 "while (ct == null) {", 163 "while (ct == null) { switch (current.kind) {", 164 "while (ct == null) { switch (current.kind) { case EOF: {", 165 "while (ct == null) { switch (current.kind) { case EOF: { } }", 166 "enum TK {", 167 "enum TK { EOF(TokenKind.EOF, 0),", 168 "enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM)", 169 "enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM); ", 170 "enum Tt { FOO, BAR, BAZ,;", 171 "class C", 172 "class C extends D", 173 "class C implements D", 174 "class C implements D, E", 175 "interface I extends D", 176 "interface I extends D, E", 177 "enum E", 178 "enum E implements I1", 179 "enum E implements I1, I2", 180 "@interface Anno", 181 "void f()", 182 "void f() throws E", 183 "@A(", 184 "int n = 4,", 185 "int n,", 186 "int[] m = {1, 2},", 187 "int[] m = {1, 2}, n = {3, 4},", 188 "Map<String," 189 }; 190 191 static final String[] unknown = new String[] { 192 "new ;" 193 }; 194 195 static final Map<Completeness, String[]> statusToCases = new HashMap<>(); 196 static { statusToCases.put(COMPLETE, complete)197 statusToCases.put(COMPLETE, complete); statusToCases.put(COMPLETE_WITH_SEMI, complete_with_semi)198 statusToCases.put(COMPLETE_WITH_SEMI, complete_with_semi); statusToCases.put(CONSIDERED_INCOMPLETE, considered_incomplete)199 statusToCases.put(CONSIDERED_INCOMPLETE, considered_incomplete); statusToCases.put(DEFINITELY_INCOMPLETE, definitely_incomplete)200 statusToCases.put(DEFINITELY_INCOMPLETE, definitely_incomplete); 201 } 202 assertStatus(String input, Completeness status, String source)203 private void assertStatus(String input, Completeness status, String source) { 204 String augSrc; 205 switch (status) { 206 case COMPLETE_WITH_SEMI: 207 augSrc = source + ";"; 208 break; 209 210 case DEFINITELY_INCOMPLETE: 211 augSrc = null; 212 break; 213 214 case CONSIDERED_INCOMPLETE: 215 augSrc = source + ";"; 216 break; 217 218 case EMPTY: 219 case COMPLETE: 220 case UNKNOWN: 221 augSrc = source; 222 break; 223 224 default: 225 throw new AssertionError(); 226 } 227 assertAnalyze(input, status, augSrc); 228 } 229 assertStatus(String[] ins, Completeness status)230 private void assertStatus(String[] ins, Completeness status) { 231 for (String input : ins) { 232 assertStatus(input, status, input); 233 } 234 } 235 test_complete()236 public void test_complete() { 237 assertStatus(complete, COMPLETE); 238 } 239 test_expression()240 public void test_expression() { 241 assertStatus(expression, COMPLETE); 242 } 243 test_complete_with_semi()244 public void test_complete_with_semi() { 245 assertStatus(complete_with_semi, COMPLETE_WITH_SEMI); 246 } 247 test_considered_incomplete()248 public void test_considered_incomplete() { 249 assertStatus(considered_incomplete, CONSIDERED_INCOMPLETE); 250 } 251 test_definitely_incomplete()252 public void test_definitely_incomplete() { 253 assertStatus(definitely_incomplete, DEFINITELY_INCOMPLETE); 254 } 255 test_unknown()256 public void test_unknown() { 257 assertStatus(definitely_incomplete, DEFINITELY_INCOMPLETE); 258 } 259 testCompleted_complete_with_semi()260 public void testCompleted_complete_with_semi() { 261 for (String in : complete_with_semi) { 262 String input = in + ";"; 263 assertStatus(input, COMPLETE, input); 264 } 265 } 266 testCompleted_expression_with_semi()267 public void testCompleted_expression_with_semi() { 268 for (String in : expression) { 269 String input = in + ";"; 270 assertStatus(input, COMPLETE, input); 271 } 272 } 273 testCompleted_considered_incomplete()274 public void testCompleted_considered_incomplete() { 275 for (String in : considered_incomplete) { 276 String input = in + ";"; 277 assertStatus(input, COMPLETE, input); 278 } 279 } 280 assertSourceByStatus(String first)281 private void assertSourceByStatus(String first) { 282 for (Map.Entry<Completeness, String[]> e : statusToCases.entrySet()) { 283 for (String in : e.getValue()) { 284 String input = first + in; 285 assertAnalyze(input, COMPLETE, first, in, true); 286 } 287 } 288 } 289 testCompleteSource_complete()290 public void testCompleteSource_complete() { 291 for (String input : complete) { 292 assertSourceByStatus(input); 293 } 294 } 295 testCompleteSource_complete_with_semi()296 public void testCompleteSource_complete_with_semi() { 297 for (String in : complete_with_semi) { 298 String input = in + ";"; 299 assertSourceByStatus(input); 300 } 301 } 302 testCompleteSource_expression()303 public void testCompleteSource_expression() { 304 for (String in : expression) { 305 String input = in + ";"; 306 assertSourceByStatus(input); 307 } 308 } 309 testCompleteSource_considered_incomplete()310 public void testCompleteSource_considered_incomplete() { 311 for (String in : considered_incomplete) { 312 String input = in + ";"; 313 assertSourceByStatus(input); 314 } 315 } 316 testTrailingSlash()317 public void testTrailingSlash() { 318 assertStatus("\"abc\\", UNKNOWN, "\"abc\\"); 319 } 320 testOpenComment()321 public void testOpenComment() { 322 assertStatus("int xx; /* hello", DEFINITELY_INCOMPLETE, null); 323 assertStatus("/** test", DEFINITELY_INCOMPLETE, null); 324 } 325 testMiscSource()326 public void testMiscSource() { 327 assertStatus("if (t) if ", DEFINITELY_INCOMPLETE, "if (t) if"); //Bug 328 assertStatus("int m() {} dfd", COMPLETE, "int m() {}"); 329 assertStatus("int p = ", DEFINITELY_INCOMPLETE, "int p ="); //Bug 330 assertStatus("int[] m = {1, 2}, n = new int[0]; int i;", COMPLETE, 331 "int[] m = {1, 2}, n = new int[0];"); 332 } 333 } 334