author | coleenp |
Wed, 15 Nov 2017 08:14:31 -0500 | |
changeset 47894 | 352b17f62ff7 |
parent 47216 | 71c04702a3d5 |
child 51563 | de411d537aae |
permissions | -rw-r--r-- |
33362 | 1 |
/* |
36494 | 2 |
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. |
33362 | 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 |
|
45748
0202b55d8e08
8182268: JShell: CompletionInfo.source() for CONSIDERED_INCOMPLETE missing semicolon
rfield
parents:
42267
diff
changeset
|
26 |
* @bug 8149524 8131024 8165211 8080071 8130454 8167343 8129559 8114842 8182268 |
33362 | 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; }", |
|
36494 | 64 |
"class Case<E1 extends Enum<E1>, E2 extends Enum<E2>, E3 extends Enum<E3>> {}", |
33362 | 65 |
";", |
40771 | 66 |
"enum Tt { FOO, BAR, BAZ,; }" |
33362 | 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))", |
|
40771 | 81 |
"int.class", |
82 |
"String.class", |
|
33362 | 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", |
|
40771 | 119 |
"java.util.function.IntFunction<int[]> ggg = int[]::new", |
41450
83877f4dd010
8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style
shinyafox
parents:
40771
diff
changeset
|
120 |
"List<? extends Object> l", |
42267
a0c712fc6575
8114842: JShell: SourceCodeAnalysis splits code with array initialiazer incorrectly
rfield
parents:
41940
diff
changeset
|
121 |
"int[] m = {1, 2}", |
a0c712fc6575
8114842: JShell: SourceCodeAnalysis splits code with array initialiazer incorrectly
rfield
parents:
41940
diff
changeset
|
122 |
"int[] m = {1, 2}, n = null", |
a0c712fc6575
8114842: JShell: SourceCodeAnalysis splits code with array initialiazer incorrectly
rfield
parents:
41940
diff
changeset
|
123 |
"int[] m = {1, 2}, n", |
a0c712fc6575
8114842: JShell: SourceCodeAnalysis splits code with array initialiazer incorrectly
rfield
parents:
41940
diff
changeset
|
124 |
"int[] m = {1, 2}, n = {3, 4}", |
33362 | 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 +", |
|
40771 | 153 |
"x *", |
154 |
"3 *", |
|
33362 | 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); ", |
|
41450
83877f4dd010
8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style
shinyafox
parents:
40771
diff
changeset
|
170 |
"enum Tt { FOO, BAR, BAZ,;", |
83877f4dd010
8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style
shinyafox
parents:
40771
diff
changeset
|
171 |
"class C", |
83877f4dd010
8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style
shinyafox
parents:
40771
diff
changeset
|
172 |
"class C extends D", |
83877f4dd010
8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style
shinyafox
parents:
40771
diff
changeset
|
173 |
"class C implements D", |
83877f4dd010
8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style
shinyafox
parents:
40771
diff
changeset
|
174 |
"class C implements D, E", |
83877f4dd010
8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style
shinyafox
parents:
40771
diff
changeset
|
175 |
"interface I extends D", |
83877f4dd010
8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style
shinyafox
parents:
40771
diff
changeset
|
176 |
"interface I extends D, E", |
83877f4dd010
8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style
shinyafox
parents:
40771
diff
changeset
|
177 |
"enum E", |
83877f4dd010
8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style
shinyafox
parents:
40771
diff
changeset
|
178 |
"enum E implements I1", |
83877f4dd010
8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style
shinyafox
parents:
40771
diff
changeset
|
179 |
"enum E implements I1, I2", |
83877f4dd010
8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style
shinyafox
parents:
40771
diff
changeset
|
180 |
"@interface Anno", |
83877f4dd010
8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style
shinyafox
parents:
40771
diff
changeset
|
181 |
"void f()", |
83877f4dd010
8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style
shinyafox
parents:
40771
diff
changeset
|
182 |
"void f() throws E", |
41940
048d559e9da7
8129559: JShell: compilation fails if class, method or field is annotated and has modifiers
rfield
parents:
41450
diff
changeset
|
183 |
"@A(", |
42267
a0c712fc6575
8114842: JShell: SourceCodeAnalysis splits code with array initialiazer incorrectly
rfield
parents:
41940
diff
changeset
|
184 |
"int n = 4,", |
a0c712fc6575
8114842: JShell: SourceCodeAnalysis splits code with array initialiazer incorrectly
rfield
parents:
41940
diff
changeset
|
185 |
"int n,", |
a0c712fc6575
8114842: JShell: SourceCodeAnalysis splits code with array initialiazer incorrectly
rfield
parents:
41940
diff
changeset
|
186 |
"int[] m = {1, 2},", |
a0c712fc6575
8114842: JShell: SourceCodeAnalysis splits code with array initialiazer incorrectly
rfield
parents:
41940
diff
changeset
|
187 |
"int[] m = {1, 2}, n = {3, 4},", |
a0c712fc6575
8114842: JShell: SourceCodeAnalysis splits code with array initialiazer incorrectly
rfield
parents:
41940
diff
changeset
|
188 |
"Map<String," |
33362 | 189 |
}; |
190 |
||
191 |
static final String[] unknown = new String[] { |
|
192 |
"new ;" |
|
193 |
}; |
|
194 |
||
195 |
static final Map<Completeness, String[]> statusToCases = new HashMap<>(); |
|
196 |
static { |
|
197 |
statusToCases.put(COMPLETE, complete); |
|
198 |
statusToCases.put(COMPLETE_WITH_SEMI, complete_with_semi); |
|
199 |
statusToCases.put(CONSIDERED_INCOMPLETE, considered_incomplete); |
|
200 |
statusToCases.put(DEFINITELY_INCOMPLETE, definitely_incomplete); |
|
201 |
} |
|
202 |
||
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: |
|
45748
0202b55d8e08
8182268: JShell: CompletionInfo.source() for CONSIDERED_INCOMPLETE missing semicolon
rfield
parents:
42267
diff
changeset
|
211 |
augSrc = null; |
0202b55d8e08
8182268: JShell: CompletionInfo.source() for CONSIDERED_INCOMPLETE missing semicolon
rfield
parents:
42267
diff
changeset
|
212 |
break; |
0202b55d8e08
8182268: JShell: CompletionInfo.source() for CONSIDERED_INCOMPLETE missing semicolon
rfield
parents:
42267
diff
changeset
|
213 |
|
33362 | 214 |
case CONSIDERED_INCOMPLETE: |
45748
0202b55d8e08
8182268: JShell: CompletionInfo.source() for CONSIDERED_INCOMPLETE missing semicolon
rfield
parents:
42267
diff
changeset
|
215 |
augSrc = source + ";"; |
33362 | 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 |
||
230 |
private void assertStatus(String[] ins, Completeness status) { |
|
231 |
for (String input : ins) { |
|
232 |
assertStatus(input, status, input); |
|
233 |
} |
|
234 |
} |
|
235 |
||
236 |
public void test_complete() { |
|
237 |
assertStatus(complete, COMPLETE); |
|
238 |
} |
|
239 |
||
240 |
public void test_expression() { |
|
241 |
assertStatus(expression, COMPLETE); |
|
242 |
} |
|
243 |
||
244 |
public void test_complete_with_semi() { |
|
245 |
assertStatus(complete_with_semi, COMPLETE_WITH_SEMI); |
|
246 |
} |
|
247 |
||
248 |
public void test_considered_incomplete() { |
|
249 |
assertStatus(considered_incomplete, CONSIDERED_INCOMPLETE); |
|
250 |
} |
|
251 |
||
252 |
public void test_definitely_incomplete() { |
|
253 |
assertStatus(definitely_incomplete, DEFINITELY_INCOMPLETE); |
|
254 |
} |
|
255 |
||
256 |
public void test_unknown() { |
|
257 |
assertStatus(definitely_incomplete, DEFINITELY_INCOMPLETE); |
|
258 |
} |
|
259 |
||
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 |
||
267 |
public void testCompleted_expression_with_semi() { |
|
268 |
for (String in : expression) { |
|
269 |
String input = in + ";"; |
|
270 |
assertStatus(input, COMPLETE, input); |
|
271 |
} |
|
272 |
} |
|
273 |
||
274 |
public void testCompleted_considered_incomplete() { |
|
275 |
for (String in : considered_incomplete) { |
|
276 |
String input = in + ";"; |
|
277 |
assertStatus(input, COMPLETE, input); |
|
278 |
} |
|
279 |
} |
|
280 |
||
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 |
||
290 |
public void testCompleteSource_complete() { |
|
291 |
for (String input : complete) { |
|
292 |
assertSourceByStatus(input); |
|
293 |
} |
|
294 |
} |
|
295 |
||
296 |
public void testCompleteSource_complete_with_semi() { |
|
297 |
for (String in : complete_with_semi) { |
|
298 |
String input = in + ";"; |
|
299 |
assertSourceByStatus(input); |
|
300 |
} |
|
301 |
} |
|
302 |
||
303 |
public void testCompleteSource_expression() { |
|
304 |
for (String in : expression) { |
|
305 |
String input = in + ";"; |
|
306 |
assertSourceByStatus(input); |
|
307 |
} |
|
308 |
} |
|
309 |
||
310 |
public void testCompleteSource_considered_incomplete() { |
|
311 |
for (String in : considered_incomplete) { |
|
312 |
String input = in + ";"; |
|
313 |
assertSourceByStatus(input); |
|
314 |
} |
|
315 |
} |
|
316 |
||
317 |
public void testTrailingSlash() { |
|
318 |
assertStatus("\"abc\\", UNKNOWN, "\"abc\\"); |
|
319 |
} |
|
320 |
||
38835
37280d52d723
8131024: JShell: multi-line comment not detected as incomplete
rfield
parents:
36494
diff
changeset
|
321 |
public void testOpenComment() { |
37280d52d723
8131024: JShell: multi-line comment not detected as incomplete
rfield
parents:
36494
diff
changeset
|
322 |
assertStatus("int xx; /* hello", DEFINITELY_INCOMPLETE, null); |
37280d52d723
8131024: JShell: multi-line comment not detected as incomplete
rfield
parents:
36494
diff
changeset
|
323 |
assertStatus("/** test", DEFINITELY_INCOMPLETE, null); |
37280d52d723
8131024: JShell: multi-line comment not detected as incomplete
rfield
parents:
36494
diff
changeset
|
324 |
} |
37280d52d723
8131024: JShell: multi-line comment not detected as incomplete
rfield
parents:
36494
diff
changeset
|
325 |
|
33362 | 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 |
|
42267
a0c712fc6575
8114842: JShell: SourceCodeAnalysis splits code with array initialiazer incorrectly
rfield
parents:
41940
diff
changeset
|
330 |
assertStatus("int[] m = {1, 2}, n = new int[0]; int i;", COMPLETE, |
a0c712fc6575
8114842: JShell: SourceCodeAnalysis splits code with array initialiazer incorrectly
rfield
parents:
41940
diff
changeset
|
331 |
"int[] m = {1, 2}, n = new int[0];"); |
33362 | 332 |
} |
333 |
} |