1 /* 2 * Copyright (c) 2015, 2019, 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 8223782 8235474 8246774 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 import java.util.function.Consumer; 35 import javax.lang.model.SourceVersion; 36 import jdk.jshell.JShell; 37 38 import org.testng.annotations.Test; 39 import jdk.jshell.SourceCodeAnalysis.Completeness; 40 41 import static jdk.jshell.SourceCodeAnalysis.Completeness.*; 42 import org.testng.annotations.BeforeMethod; 43 44 @Test 45 public class CompletenessTest extends KullaTesting { 46 47 // Add complete units that end with semicolon to complete_with_semi (without 48 // the semicolon). Both cases will be tested. 49 static final String[] complete = new String[] { 50 "{ x= 4; }", 51 "int mm(int x) {kll}", 52 "if (t) { ddd; }", 53 "for (int i = 0; i < lines.length(); ++i) { foo }", 54 "while (ct == null) { switch (current.kind) { case EOF: { } } }", 55 "if (match.kind == BRACES && (prevCT.kind == ARROW || prevCT.kind == NEW_MIDDLE)) { new CT(UNMATCHED, current, \"Unmatched \" + unmatched); }", 56 "enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM); }", 57 "List<T> f() { return null; }", 58 "List<?> f() { return null; }", 59 "List<? extends Object> f() { return null; }", 60 "Map<? extends Object, ? super Object> f() { return null; }", 61 "class C { int z; }", 62 "synchronized (r) { f(); }", 63 "try { } catch (Exception ex) { }", 64 "try { } catch (Exception ex) { } finally { }", 65 "try { } finally { }", 66 "try (java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName)) { }", 67 "foo: while (true) { printf(\"Innn\"); break foo; }", 68 "class Case<E1 extends Enum<E1>, E2 extends Enum<E2>, E3 extends Enum<E3>> {}", 69 ";", 70 "enum Tt { FOO, BAR, BAZ,; }", 71 "record D(int i) {}", 72 "static record D(int i) {}", 73 }; 74 75 static final String[] expression = new String[] { 76 "test", 77 "x + y", 78 "x + y ++", 79 "p = 9", 80 "match(BRACKETS, TokenKind.LBRACKET)", 81 "new C()", getSourceFile(String fileName)82 "new C() { public String toString() { return \"Hi\"; } }", 83 "new int[]", 84 "new int[] {1, 2,3}", 85 "new Foo() {}", 86 "i >= 0 && Character.isWhitespace(s.charAt(i))", 87 "int.class", 88 "String.class", 89 "record.any", 90 "record()", 91 "record(1)", 92 "record.length()" 93 }; 94 95 static final String[] complete_with_semi = new String[] { 96 "int mm", 97 "if (t) ddd", 98 "int p = 9", 99 "int p", 100 "Deque<Token> stack = new ArrayDeque<>()", 101 "final Deque<Token> stack = new ArrayDeque<>()", 102 "java.util.Scanner input = new java.util.Scanner(System.in)", dataProvider()103 "java.util.Scanner input = new java.util.Scanner(System.in) { }", 104 "int j = -i", 105 "String[] a = { \"AAA\" }", 106 "assert true", 107 "int path[]", 108 "int path[][]", 109 "int path[][] = new int[22][]", 110 "int path[] = new int[22]", 111 "int path[] = new int[] {1, 2, 3}", 112 "int[] path", 113 "int path[] = new int[22]", 114 "int path[][] = new int[22][]", 115 "for (Object o : a) System.out.println(\"Yep\")", 116 "while (os == null) System.out.println(\"Yep\")", 117 "do f(); while (t)", 118 "if (os == null) System.out.println(\"Yep\")", 119 "if (t) if (!t) System.out.println(123)", 120 "for (int i = 0; i < 10; ++i) if (i < 5) System.out.println(i); else break", 121 "for (int i = 0; i < 10; ++i) if (i < 5) System.out.println(i); else continue", 122 "for (int i = 0; i < 10; ++i) if (i < 5) System.out.println(i); else return", 123 "throw ex", 124 "C c = new C()", 125 "java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName)", 126 "BufferedReader br = new BufferedReader(new FileReader(path))", 127 "bar: g()", 128 "baz: while (true) if (t()) printf('-'); else break baz", 129 "java.util.function.IntFunction<int[]> ggg = int[]::new", 130 "List<? extends Object> l", 131 "int[] m = {1, 2}", 132 "int[] m = {1, 2}, n = null", 133 "int[] m = {1, 2}, n", 134 "int[] m = {1, 2}, n = {3, 4}", 135 }; 136 137 static final String[] considered_incomplete = new String[] { 138 "if (t)", 139 "if (t) { } else", 140 "if (t) if (!t)", 141 "if (match.kind == BRACES && (prevCT.kind == ARROW || prevCT.kind == NEW_MIDDLE))", 142 "for (int i = 0; i < 10; ++i)", 143 "while (os == null)", 144 }; 145 146 static final String[] definitely_incomplete = new String[] { 147 "int mm(", 148 "int mm(int x", 149 "int mm(int x)", 150 "int mm(int x) {", 151 "int mm(int x) {kll", 152 "if", 153 "if (", 154 "if (t", 155 "if (t) {", 156 "if (t) { ddd", 157 "if (t) { ddd;", 158 "if (t) if (", 159 "if (stack.isEmpty()) {", 160 "if (match.kind == BRACES && (prevCT.kind == ARROW || prevCT.kind == NEW_MIDDLE)) {", 161 "if (match.kind == BRACES && (prevCT.kind == ARROW || prevCT.kind == NEW_MIDDLE)) { new CT(UNMATCHED, current, \"Unmatched \" + unmatched);", 162 "x +", 163 "x *", 164 "3 *", 165 "int", 166 "for (int i = 0; i < lines.length(); ++i) {", 167 "new", 168 "new C(", 169 "new int[", 170 "new int[] {1, 2,3", 171 "new int[] {", 172 "while (ct == null) {", 173 "while (ct == null) { switch (current.kind) {", isLegal(StatementTree st)174 "while (ct == null) { switch (current.kind) { case EOF: {", 175 "while (ct == null) { switch (current.kind) { case EOF: { } }", 176 "enum TK {", 177 "enum TK { EOF(TokenKind.EOF, 0),", 178 "enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM)", 179 "enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM); ", 180 "enum Tt { FOO, BAR, BAZ,;", 181 "class C", 182 "class C extends D", 183 "class C implements D", 184 "class C implements D, E", 185 "interface I extends D", 186 "interface I extends D, E", 187 "enum E", 188 "enum E implements I1", 189 "enum E implements I1, I2", 190 "@interface Anno", 191 "void f()", 192 "void f() throws E", 193 "@A(", 194 "int n = 4,", 195 "int n,", 196 "int[] m = {1, 2},", 197 "int[] m = {1, 2}, n = {3, 4},", 198 "Map<String,", 199 "switch (x) {", 200 "var v = switch (x) {", 201 "var v = switch (x) { case ", 202 "var v = switch (x) { case 0:", 203 "var v = switch (x) { case 0: break 12; ", 204 "record D", 205 "record D(", 206 "record D(String", 207 "record D(String i", 208 "record D(String i,", 209 "record D(String i, String", 210 "record D(String i, String j", 211 "record D(String i)", 212 "record D(String i, String j)", 213 "record D(String i) {", 214 "record D(String i, String j) {", 215 "static record D", 216 "static record D(", 217 "static record D(String", 218 "static record D(String i", 219 "static record D(String i,", 220 "static record D(String i, String", 221 "static record D(String i, String j", 222 "static record D(String i)", 223 "static record D(String i, String j)", 224 "static record D(String i) {", 225 "static record D(String i, String j) {", 226 }; 227 228 static final String[] unknown = new String[] { 229 "new ;" 230 }; 231 232 static final Map<Completeness, String[]> statusToCases = new HashMap<>(); 233 static { 234 statusToCases.put(COMPLETE, complete); 235 statusToCases.put(COMPLETE_WITH_SEMI, complete_with_semi); 236 statusToCases.put(CONSIDERED_INCOMPLETE, considered_incomplete); 237 statusToCases.put(DEFINITELY_INCOMPLETE, definitely_incomplete); 238 } 239 240 private void assertStatus(String input, Completeness status, String source) { 241 String augSrc; 242 switch (status) { 243 case COMPLETE_WITH_SEMI: 244 augSrc = source + ";"; 245 break; 246 247 case DEFINITELY_INCOMPLETE: 248 augSrc = null; 249 break; 250 251 case CONSIDERED_INCOMPLETE: 252 augSrc = source + ";"; 253 break; 254 255 case EMPTY: 256 case COMPLETE: 257 case UNKNOWN: 258 augSrc = source; 259 break; 260 261 default: 262 throw new AssertionError(); 263 } 264 assertAnalyze(input, status, augSrc); 265 } 266 267 private void assertStatus(String[] ins, Completeness status) { 268 for (String input : ins) { 269 assertStatus(input, status, input); 270 } 271 } 272 273 public void test_complete() { 274 assertStatus(complete, COMPLETE); 275 } 276 277 public void test_expression() { 278 assertStatus(expression, COMPLETE); 279 } 280 281 public void test_complete_with_semi() { 282 assertStatus(complete_with_semi, COMPLETE_WITH_SEMI); 283 } 284 285 public void test_considered_incomplete() { 286 assertStatus(considered_incomplete, CONSIDERED_INCOMPLETE); 287 } 288 289 public void test_definitely_incomplete() { 290 assertStatus(definitely_incomplete, DEFINITELY_INCOMPLETE); 291 } 292 293 public void test_unknown() { 294 assertStatus(definitely_incomplete, DEFINITELY_INCOMPLETE); 295 } 296 297 public void testCompleted_complete_with_semi() { 298 for (String in : complete_with_semi) { 299 String input = in + ";"; 300 assertStatus(input, COMPLETE, input); 301 } 302 } 303 304 public void testCompleted_expression_with_semi() { 305 for (String in : expression) { 306 String input = in + ";"; 307 assertStatus(input, COMPLETE, input); 308 } 309 } 310 311 public void testCompleted_considered_incomplete() { 312 for (String in : considered_incomplete) { 313 String input = in + ";"; 314 assertStatus(input, COMPLETE, input); 315 } 316 } 317 318 private void assertSourceByStatus(String first) { 319 for (Map.Entry<Completeness, String[]> e : statusToCases.entrySet()) { 320 for (String in : e.getValue()) { 321 String input = first + in; 322 assertAnalyze(input, COMPLETE, first, in, true); 323 } 324 } 325 } 326 327 public void testCompleteSource_complete() { 328 for (String input : complete) { 329 assertSourceByStatus(input); 330 } 331 } 332 333 public void testCompleteSource_complete_with_semi() { 334 for (String in : complete_with_semi) { 335 String input = in + ";"; 336 assertSourceByStatus(input); 337 } 338 } 339 340 public void testCompleteSource_expression() { 341 for (String in : expression) { 342 String input = in + ";"; 343 assertSourceByStatus(input); 344 } 345 } 346 347 public void testCompleteSource_considered_incomplete() { 348 for (String in : considered_incomplete) { 349 String input = in + ";"; 350 assertSourceByStatus(input); 351 } 352 } 353 354 public void testTrailingSlash() { 355 assertStatus("\"abc\\", UNKNOWN, "\"abc\\"); 356 } 357 358 public void testOpenComment() { 359 assertStatus("int xx; /* hello", DEFINITELY_INCOMPLETE, null); 360 assertStatus("/** test", DEFINITELY_INCOMPLETE, null); 361 } 362 363 public void testTextBlocks() { 364 assertStatus("\"\"\"", DEFINITELY_INCOMPLETE, null); 365 assertStatus("\"\"\"broken", DEFINITELY_INCOMPLETE, null); 366 assertStatus("\"\"\"\ntext", DEFINITELY_INCOMPLETE, null); 367 assertStatus("\"\"\"\ntext\"\"", DEFINITELY_INCOMPLETE, "\"\"\"\ntext\"\"\""); 368 assertStatus("\"\"\"\ntext\"\"\"", COMPLETE, "\"\"\"\ntext\"\"\""); 369 assertStatus("\"\"\"\ntext\\\"\"\"\"", COMPLETE, "\"\"\"\ntext\\\"\"\"\""); 370 assertStatus("\"\"\"\ntext\\\"\"\"", DEFINITELY_INCOMPLETE, null); 371 assertStatus("\"\"\"\ntext\\\"\"\"\\\"\"\"", DEFINITELY_INCOMPLETE, null); 372 assertStatus("\"\"\"\ntext\\\"\"\"\\\"\"\"\"\"\"", COMPLETE, "\"\"\"\ntext\\\"\"\"\\\"\"\"\"\"\""); 373 } 374 375 public void testMiscSource() { 376 assertStatus("if (t) if ", DEFINITELY_INCOMPLETE, "if (t) if"); //Bug 377 assertStatus("int m() {} dfd", COMPLETE, "int m() {}"); 378 assertStatus("int p = ", DEFINITELY_INCOMPLETE, "int p ="); //Bug 379 assertStatus("int[] m = {1, 2}, n = new int[0]; int i;", COMPLETE, 380 "int[] m = {1, 2}, n = new int[0];"); 381 } 382 } 383