1 /*
2  * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3  * Use of this file is governed by the BSD 3-clause license that
4  * can be found in the LICENSE.txt file in the project root.
5  */
6 
7 package org.antlr.v4.test.tool;
8 
9 import org.antlr.v4.Tool;
10 import org.antlr.v4.tool.ErrorType;
11 import org.junit.Assert;
12 import org.junit.Before;
13 import org.junit.Test;
14 
15 public class TestToolSyntaxErrors extends BaseJavaToolTest {
16     static String[] A = {
17 	    // INPUT
18 		"grammar A;\n" +
19 		"",
20 		// YIELDS
21 		"error(" + ErrorType.NO_RULES.code + "): A.g4::: grammar A has no rules\n",
22 
23 		"lexer grammar A;\n" +
24 		"",
25 		"error(" + ErrorType.NO_RULES.code + "): A.g4::: grammar A has no rules\n",
26 
27 		"A;",
28 		"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:1:0: syntax error: 'A' came as a complete surprise to me\n",
29 
30 		"grammar ;",
31 		"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:1:8: syntax error: ';' came as a complete surprise to me while looking for an identifier\n",
32 
33 		"grammar A\n" +
34 		"a : ID ;\n",
35 		"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:0: syntax error: missing SEMI at 'a'\n",
36 
37 		"grammar A;\n" +
38 		"a : ID ;;\n"+
39 		"b : B ;",
40 		"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:8: syntax error: ';' came as a complete surprise to me\n",
41 
42 		"grammar A;;\n" +
43 		"a : ID ;\n",
44 		"error(" + ErrorType.SYNTAX_ERROR.code + "): A;.g4:1:10: syntax error: ';' came as a complete surprise to me\n",
45 
46 		"grammar A;\n" +
47 		"a @init : ID ;\n",
48 		"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:8: syntax error: mismatched input ':' expecting ACTION while matching rule preamble\n",
49 
50 		"grammar A;\n" +
51 		"a  ( A | B ) D ;\n" +
52 		"b : B ;",
53 		"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:3: syntax error: '(' came as a complete surprise to me while matching rule preamble\n" +
54 		"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:11: syntax error: mismatched input ')' expecting SEMI while matching a rule\n" +
55 		"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:15: syntax error: mismatched input ';' expecting COLON while matching a lexer rule\n",
56     };
57 
58 	@Before
59 	@Override
testSetUp()60 	public void testSetUp() throws Exception {
61 		super.testSetUp();
62 	}
63 
64 	@Test
AllErrorCodesDistinct()65 	public void AllErrorCodesDistinct() {
66 		ErrorType[] errorTypes = ErrorType.class.getEnumConstants();
67 		for (int i = 0; i < errorTypes.length; i++) {
68 			for (int j = i + 1; j < errorTypes.length; j++) {
69 				Assert.assertNotEquals(errorTypes[i].code, errorTypes[j].code);
70 			}
71 		}
72 	}
73 
testA()74 	@Test public void testA() { super.testErrors(A, true); }
75 
testExtraColon()76 	@Test public void testExtraColon() {
77 		String[] pair = new String[] {
78 			"grammar A;\n" +
79 			"a : : A ;\n" +
80 			"b : B ;",
81 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:4: syntax error: ':' came as a complete surprise to me while matching alternative\n",
82 		};
83 		super.testErrors(pair, true);
84 	}
85 
testMissingRuleSemi()86 	@Test public void testMissingRuleSemi() {
87 		String[] pair = new String[] {
88 			"grammar A;\n" +
89 			"a : A \n" +
90 			"b : B ;",
91 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:3:0: syntax error: unterminated rule (missing ';') detected at 'b :' while looking for rule element\n",
92 		};
93 		super.testErrors(pair, true);
94 	}
95 
testMissingRuleSemi2()96 	@Test public void testMissingRuleSemi2() {
97 		String[] pair = new String[] {
98 			"lexer grammar A;\n" +
99 			"A : 'a' \n" +
100 			"B : 'b' ;",
101 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:3:0: syntax error: unterminated rule (missing ';') detected at 'B :' while looking for lexer rule element\n",
102 		};
103 		super.testErrors(pair, true);
104 	}
105 
testMissingRuleSemi3()106 	@Test public void testMissingRuleSemi3() {
107 		String[] pair = new String[] {
108 			"grammar A;\n" +
109 			"a : A \n" +
110 			"b[int i] returns [int y] : B ;",
111 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:3:9: syntax error: unterminated rule (missing ';') detected at 'returns int y' while looking for rule element\n"
112 		};
113 		super.testErrors(pair, true);
114 	}
115 
testMissingRuleSemi4()116 	@Test public void testMissingRuleSemi4() {
117 		String[] pair = new String[] {
118 			"grammar A;\n" +
119 			"a : b \n" +
120 			"  catch [Exception e] {...}\n" +
121 			"b : B ;\n",
122 
123 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:4: syntax error: unterminated rule (missing ';') detected at 'b catch' while looking for rule element\n"
124 		};
125 		super.testErrors(pair, true);
126 	}
127 
testMissingRuleSemi5()128 	@Test public void testMissingRuleSemi5() {
129 		String[] pair = new String[] {
130 			"grammar A;\n" +
131 			"a : A \n" +
132 			"  catch [Exception e] {...}\n",
133 
134 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:4: syntax error: unterminated rule (missing ';') detected at 'A catch' while looking for rule element\n"
135 		};
136 		super.testErrors(pair, true);
137 	}
138 
testBadRulePrequelStart()139 	@Test public void testBadRulePrequelStart() {
140 		String[] pair = new String[] {
141 			"grammar A;\n" +
142 			"a @ options {k=1;} : A ;\n" +
143 			"b : B ;",
144 
145 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:4: syntax error: 'options {' came as a complete surprise to me while looking for an identifier\n"
146 		};
147 		super.testErrors(pair, true);
148 	}
149 
testBadRulePrequelStart2()150 	@Test public void testBadRulePrequelStart2() {
151 		String[] pair = new String[] {
152 			"grammar A;\n" +
153 			"a } : A ;\n" +
154 			"b : B ;",
155 
156 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:2: syntax error: '}' came as a complete surprise to me while matching rule preamble\n"
157 		};
158 		super.testErrors(pair, true);
159 	}
160 
testModeInParser()161 	@Test public void testModeInParser() {
162 		String[] pair = new String[] {
163 			"grammar A;\n" +
164 			"a : A ;\n" +
165 			"mode foo;\n" +
166 			"b : B ;",
167 
168 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:4:0: syntax error: 'b' came as a complete surprise to me\n" +
169 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:4:6: syntax error: mismatched input ';' expecting COLON while matching a lexer rule\n"
170 		};
171 		super.testErrors(pair, true);
172 	}
173 
174 	/**
175 	 * This is a regression test for antlr/antlr4#243
176 	 * "Generate a good message for unterminated strings"
177 	 * https://github.com/antlr/antlr4/issues/243
178 	 */
testUnterminatedStringLiteral()179 	@Test public void testUnterminatedStringLiteral() {
180 		String[] pair = new String[] {
181 			"grammar A;\n" +
182 			"a : 'x\n" +
183 			"  ;\n",
184 
185 			"error(" + ErrorType.UNTERMINATED_STRING_LITERAL.code + "): A.g4:2:4: unterminated string literal\n"
186 		};
187 		super.testErrors(pair, true);
188 	}
189 
190 	/**
191 	 * This is a regression test for antlr/antlr4#262
192 	 * "Parser Rule Name Starting With an Underscore"
193 	 * https://github.com/antlr/antlr4/issues/262
194 	 */
testParserRuleNameStartingWithUnderscore()195 	@Test public void testParserRuleNameStartingWithUnderscore() {
196 		String[] pair = new String[] {
197 			"grammar A;\n" +
198 			"_a : 'x' ;\n",
199 
200 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:0: syntax error: '_' came as a complete surprise to me\n"
201 		};
202 		super.testErrors(pair, true);
203 	}
204 
205 	/**
206 	 * This is a regression test for antlr/antlr4#194
207 	 * "NullPointerException on 'options{}' in grammar file"
208 	 * https://github.com/antlr/antlr4/issues/194
209 	 */
testEmptyGrammarOptions()210 	@Test public void testEmptyGrammarOptions() {
211 		String[] pair = new String[] {
212 			"grammar A;\n" +
213 			"options {}\n" +
214 			"a : 'x' ;\n",
215 
216 			""
217 		};
218 		super.testErrors(pair, true);
219 	}
220 
221 	/**
222 	 * This is a "related" regression test for antlr/antlr4#194
223 	 * "NullPointerException on 'options{}' in grammar file"
224 	 * https://github.com/antlr/antlr4/issues/194
225 	 */
testEmptyRuleOptions()226 	@Test public void testEmptyRuleOptions() {
227 		String[] pair = new String[] {
228 			"grammar A;\n" +
229 			"a options{} : 'x' ;\n",
230 
231 			""
232 		};
233 		super.testErrors(pair, true);
234 	}
235 
236 	/**
237 	 * This is a "related" regression test for antlr/antlr4#194
238 	 * "NullPointerException on 'options{}' in grammar file"
239 	 * https://github.com/antlr/antlr4/issues/194
240 	 */
testEmptyBlockOptions()241 	@Test public void testEmptyBlockOptions() {
242 		String[] pair = new String[] {
243 			"grammar A;\n" +
244 			"a : (options{} : 'x') ;\n",
245 
246 			""
247 		};
248 		super.testErrors(pair, true);
249 	}
250 
testEmptyTokensBlock()251 	@Test public void testEmptyTokensBlock() {
252 		String[] pair = new String[] {
253 			"grammar A;\n" +
254 			"tokens {}\n" +
255 			"a : 'x' ;\n",
256 
257 			""
258 		};
259 		super.testErrors(pair, true);
260 	}
261 
262 	/**
263 	 * This is a regression test for antlr/antlr4#190
264 	 * "NullPointerException building lexer grammar using bogus 'token' action"
265 	 * https://github.com/antlr/antlr4/issues/190
266 	 */
testInvalidLexerCommand()267 	@Test public void testInvalidLexerCommand() {
268 		String[] pair = new String[] {
269 			"grammar A;\n" +
270 			"tokens{Foo}\n" +
271 			"b : Foo ;\n" +
272 			"X : 'foo1' -> popmode;\n" + // "meant" to use -> popMode
273 			"Y : 'foo2' -> token(Foo);", // "meant" to use -> type(Foo)
274 
275 			"error(" + ErrorType.INVALID_LEXER_COMMAND.code + "): A.g4:4:14: lexer command popmode does not exist or is not supported by the current target\n" +
276 			"error(" + ErrorType.INVALID_LEXER_COMMAND.code + "): A.g4:5:14: lexer command token does not exist or is not supported by the current target\n"
277 		};
278 		super.testErrors(pair, true);
279 	}
280 
testLexerCommandArgumentValidation()281 	@Test public void testLexerCommandArgumentValidation() {
282 		String[] pair = new String[] {
283 			"grammar A;\n" +
284 			"tokens{Foo}\n" +
285 			"b : Foo ;\n" +
286 			"X : 'foo1' -> popMode(Foo);\n" + // "meant" to use -> popMode
287 			"Y : 'foo2' -> type;", // "meant" to use -> type(Foo)
288 
289 			"error(" + ErrorType.UNWANTED_LEXER_COMMAND_ARGUMENT.code + "): A.g4:4:14: lexer command popMode does not take any arguments\n" +
290 			"error(" + ErrorType.MISSING_LEXER_COMMAND_ARGUMENT.code + "): A.g4:5:14: missing argument for lexer command type\n"
291 		};
292 		super.testErrors(pair, true);
293 	}
294 
testRuleRedefinition()295 	@Test public void testRuleRedefinition() {
296 		String[] pair = new String[] {
297 			"grammar Oops;\n" +
298 			"\n" +
299 			"ret_ty : A ;\n" +
300 			"ret_ty : B ;\n" +
301 			"\n" +
302 			"A : 'a' ;\n" +
303 			"B : 'b' ;\n",
304 
305 			"error(" + ErrorType.RULE_REDEFINITION.code + "): Oops.g4:4:0: rule ret_ty redefinition; previous at line 3\n"
306 		};
307 		super.testErrors(pair, true);
308 	}
309 
testEpsilonClosureAnalysis()310 	@Test public void testEpsilonClosureAnalysis() {
311 		String grammar =
312 			"grammar A;\n"
313 			+ "x : ;\n"
314 			+ "y1 : x+;\n"
315 			+ "y2 : x*;\n"
316 			+ "z1 : ('foo' | 'bar'? 'bar2'?)*;\n"
317 			+ "z2 : ('foo' | 'bar' 'bar2'? | 'bar2')*;\n";
318 		String expected =
319 			"error(" + ErrorType.EPSILON_CLOSURE.code + "): A.g4:3:0: rule y1 contains a closure with at least one alternative that can match an empty string\n" +
320 			"error(" + ErrorType.EPSILON_CLOSURE.code + "): A.g4:4:0: rule y2 contains a closure with at least one alternative that can match an empty string\n" +
321 			"error(" + ErrorType.EPSILON_CLOSURE.code + "): A.g4:5:0: rule z1 contains a closure with at least one alternative that can match an empty string\n";
322 
323 		String[] pair = new String[] {
324 			grammar,
325 			expected
326 		};
327 
328 		super.testErrors(pair, true);
329 	}
330 
331 	// Test for https://github.com/antlr/antlr4/issues/1203
testEpsilonNestedClosureAnalysis()332 	@Test public void testEpsilonNestedClosureAnalysis() {
333 		String grammar =
334 			"grammar T;\n"+
335 			"s : (a a)* ;\n"+
336 			"a : 'foo'* ;\n";
337 		String expected =
338 			"error(" + ErrorType.EPSILON_CLOSURE.code + "): T.g4:2:0: rule s contains a closure with at least one alternative that can match an empty string\n";
339 
340 		String[] pair = new String[] {
341 			grammar,
342 			expected
343 		};
344 
345 		super.testErrors(pair, true);
346 	}
347 
348 	// Test for https://github.com/antlr/antlr4/issues/1203
testEpsilonOptionalAndClosureAnalysis()349 	@Test public void testEpsilonOptionalAndClosureAnalysis() {
350 		String grammar =
351 			"grammar T;\n"+
352 			"s : (a a)? ;\n"+
353 			"a : 'foo'* ;\n";
354 		String expected =
355 			"warning(" + ErrorType.EPSILON_OPTIONAL.code + "): T.g4:2:0: rule s contains an optional block with at least one alternative that can match an empty string\n";
356 
357 		String[] pair = new String[] {
358 			grammar,
359 			expected
360 		};
361 
362 		super.testErrors(pair, true);
363 	}
364 
testEpsilonOptionalAnalysis()365 	@Test public void testEpsilonOptionalAnalysis() {
366 		String grammar =
367 			"grammar A;\n"
368 			+ "x : ;\n"
369 			+ "y  : x?;\n"
370 			+ "z1 : ('foo' | 'bar'? 'bar2'?)?;\n"
371 			+ "z2 : ('foo' | 'bar' 'bar2'? | 'bar2')?;\n";
372 		String expected =
373 			"warning(" + ErrorType.EPSILON_OPTIONAL.code + "): A.g4:3:0: rule y contains an optional block with at least one alternative that can match an empty string\n" +
374 			"warning(" + ErrorType.EPSILON_OPTIONAL.code + "): A.g4:4:0: rule z1 contains an optional block with at least one alternative that can match an empty string\n";
375 
376 		String[] pair = new String[] {
377 			grammar,
378 			expected
379 		};
380 
381 		super.testErrors(pair, true);
382 	}
383 
384 	/**
385 	 * This is a regression test for antlr/antlr4#315
386 	 * "Inconsistent lexer error msg for actions"
387 	 * https://github.com/antlr/antlr4/issues/315
388 	 */
testActionAtEndOfOneLexerAlternative()389 	@Test public void testActionAtEndOfOneLexerAlternative() {
390 		String grammar =
391 			"grammar A;\n" +
392 			"stat : 'start' CharacterLiteral 'end' EOF;\n" +
393 			"\n" +
394 			"// Lexer\n" +
395 			"\n" +
396 			"CharacterLiteral\n" +
397 			"    :   '\\'' SingleCharacter '\\''\n" +
398 			"    |   '\\'' ~[\\r\\n] {notifyErrorListeners(\"unclosed character literal\");}\n" +
399 			"    ;\n" +
400 			"\n" +
401 			"fragment\n" +
402 			"SingleCharacter\n" +
403 			"    :   ~['\\\\\\r\\n]\n" +
404 			"    ;\n" +
405 			"\n" +
406 			"WS   : [ \\r\\t\\n]+ -> skip ;\n";
407 		String expected =
408 			"";
409 
410 		String[] pair = new String[] { grammar, expected };
411 		super.testErrors(pair, true);
412 	}
413 
414 	/**
415 	 * This is a regression test for antlr/antlr4#308 "NullPointer exception"
416 	 * https://github.com/antlr/antlr4/issues/308
417 	 */
testDoubleQuotedStringLiteral()418 	@Test public void testDoubleQuotedStringLiteral() {
419 		String grammar =
420 			"lexer grammar A;\n"
421 			+ "WHITESPACE : (\" \" | \"\\t\" | \"\\n\" | \"\\r\" | \"\\f\");\n";
422 		String expected =
423 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:14: syntax error: '\"' came as a complete surprise to me\n" +
424 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:16: syntax error: '\"' came as a complete surprise to me\n" +
425 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:20: syntax error: '\"' came as a complete surprise to me\n" +
426 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:21: syntax error: '\\' came as a complete surprise to me\n" +
427 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:23: syntax error: '\"' came as a complete surprise to me\n" +
428 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:27: syntax error: '\"' came as a complete surprise to me\n" +
429 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:28: syntax error: '\\' came as a complete surprise to me\n" +
430 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:30: syntax error: '\"' came as a complete surprise to me\n" +
431 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:34: syntax error: '\"' came as a complete surprise to me\n" +
432 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:35: syntax error: '\\' came as a complete surprise to me\n" +
433 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:37: syntax error: '\"' came as a complete surprise to me\n" +
434 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:41: syntax error: '\"' came as a complete surprise to me\n" +
435 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:42: syntax error: '\\' came as a complete surprise to me\n" +
436 			"error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:2:44: syntax error: '\"' came as a complete surprise to me\n";
437 
438 		String[] pair = new String[] {
439 			grammar,
440 			expected
441 		};
442 
443 		super.testErrors(pair, true);
444 	}
445 
446 	/**
447 	 * This is a regression test for https://github.com/antlr/antlr4/issues/1815
448 	 * "Null ptr exception in SqlBase.g4"
449 	 */
testDoubleQuoteInTwoStringLiterals()450 	@Test public void testDoubleQuoteInTwoStringLiterals() {
451 		String grammar =
452 			"lexer grammar A;\n" +
453 			"STRING : '\\\"' '\\\"' 'x' ;";
454 		String expected =
455 			"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): A.g4:2:10: invalid escape sequence \\\"\n"+
456 			"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): A.g4:2:15: invalid escape sequence \\\"\n";
457 
458 		String[] pair = new String[] {
459 			grammar,
460 			expected
461 		};
462 
463 		super.testErrors(pair, true);
464 	}
465 
466 	/**
467 	 * This test ensures that the {@link ErrorType#INVALID_ESCAPE_SEQUENCE}
468 	 * error is not reported for escape sequences that are known to be valid.
469 	 */
testValidEscapeSequences()470 	@Test public void testValidEscapeSequences() {
471 		String grammar =
472 			"lexer grammar A;\n" +
473 			"NORMAL_ESCAPE : '\\b \\t \\n \\f \\r \\' \\\\';\n" +
474 			"UNICODE_ESCAPE : '\\u0001 \\u00A1 \\u00a1 \\uaaaa \\uAAAA';\n";
475 		String expected =
476 			"";
477 
478 		String[] pair = new String[] {
479 			grammar,
480 			expected
481 		};
482 
483 		super.testErrors(pair, true);
484 	}
485 
486 	/**
487 	 * This is a regression test for antlr/antlr4#507 "NullPointerException When
488 	 * Generating Code from Grammar".
489 	 * https://github.com/antlr/antlr4/issues/507
490 	 */
testInvalidEscapeSequences()491 	@Test public void testInvalidEscapeSequences() {
492 		String grammar =
493 			"lexer grammar A;\n" +
494 			"RULE : 'Foo \\uAABG \\x \\u';\n";
495 		String expected =
496 			"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): A.g4:2:12: invalid escape sequence \\uAABG\n" +
497 			"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): A.g4:2:19: invalid escape sequence \\x\n" +
498 			"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): A.g4:2:22: invalid escape sequence \\u\n" +
499 			"warning("+ErrorType.EPSILON_TOKEN.code+"): A.g4:2:0: non-fragment lexer rule RULE can match the empty string\n";
500 
501 		String[] pair = new String[] {
502 			grammar,
503 			expected
504 		};
505 
506 		super.testErrors(pair, true);
507 	}
508 
509 	/**
510 	 * This is a regression test for antlr/antlr4#959 "NullPointerException".
511 	 * https://github.com/antlr/antlr4/issues/959
512 	 */
testNotAllowedEmptyStrings()513 	@Test public void testNotAllowedEmptyStrings() {
514 		String grammar =
515 			"lexer grammar T;\n" +
516 			"Error0: '''test''';\n" +
517 			"Error1: '' 'test';\n" +
518 			"Error2: 'test' '';\n" +
519 			"Error3: '';\n" +
520 			"NotError: ' ';";
521 		String expected =
522 			"error(" + ErrorType.EMPTY_STRINGS_AND_SETS_NOT_ALLOWED.code + "): T.g4:2:8: string literals and sets cannot be empty: ''\n" +
523 			"error(" + ErrorType.EMPTY_STRINGS_AND_SETS_NOT_ALLOWED.code + "): T.g4:2:16: string literals and sets cannot be empty: ''\n" +
524 			"error(" + ErrorType.EMPTY_STRINGS_AND_SETS_NOT_ALLOWED.code + "): T.g4:3:8: string literals and sets cannot be empty: ''\n" +
525 			"error(" + ErrorType.EMPTY_STRINGS_AND_SETS_NOT_ALLOWED.code + "): T.g4:4:15: string literals and sets cannot be empty: ''\n" +
526 			"error(" + ErrorType.EMPTY_STRINGS_AND_SETS_NOT_ALLOWED.code + "): T.g4:5:8: string literals and sets cannot be empty: ''\n";
527 
528 		String[] pair = new String[] {
529 				grammar,
530 				expected
531 		};
532 
533 		super.testErrors(pair, true);
534 	}
535 
testInvalidCharSetsAndStringLiterals()536 	@Test public void testInvalidCharSetsAndStringLiterals() {
537 		String grammar =
538 				"lexer grammar Test;\n" +
539 				"INVALID_STRING_LITERAL:       '\\\"' | '\\]' | '\\u24';\n" +
540 				"INVALID_STRING_LITERAL_RANGE: 'GH'..'LM';\n" +
541 				"INVALID_CHAR_SET:             [\\u24\\uA2][\\{];\n" +  //https://github.com/antlr/antlr4/issues/1077
542 				"EMPTY_STRING_LITERAL_RANGE:   'F'..'A' | 'Z';\n" +
543 				"EMPTY_CHAR_SET:               [f-az][];\n" +
544 				"START_HYPHEN_IN_CHAR_SET:     [-z];\n" +
545 				"END_HYPHEN_IN_CHAR_SET:       [a-];\n" +
546 				"SINGLE_HYPHEN_IN_CHAR_SET:    [-];\n" +
547 				"VALID_STRING_LITERALS:        '\\u1234' | '\\t' | '\\'';\n" +
548 				"VALID_CHAR_SET:               [`\\-=\\]];";
549 
550 		String expected =
551 				"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): Test.g4:2:31: invalid escape sequence \\\"\n" +
552 				"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): Test.g4:2:38: invalid escape sequence \\]\n" +
553 				"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): Test.g4:2:45: invalid escape sequence \\u24\n" +
554 				"error(" + ErrorType.INVALID_LITERAL_IN_LEXER_SET.code + "): Test.g4:3:30: multi-character literals are not allowed in lexer sets: 'GH'\n" +
555 				"error(" + ErrorType.INVALID_LITERAL_IN_LEXER_SET.code + "): Test.g4:3:36: multi-character literals are not allowed in lexer sets: 'LM'\n" +
556 				"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): Test.g4:4:30: invalid escape sequence \\u24\\u\n" +
557 				"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): Test.g4:4:40: invalid escape sequence \\{\n" +
558 				"error(" + ErrorType.EMPTY_STRINGS_AND_SETS_NOT_ALLOWED.code + "): Test.g4:5:33: string literals and sets cannot be empty: 'F'..'A'\n" +
559 				"error(" + ErrorType.EMPTY_STRINGS_AND_SETS_NOT_ALLOWED.code + "): Test.g4:6:30: string literals and sets cannot be empty: 'f'..'a'\n" +
560 				"error(" + ErrorType.EMPTY_STRINGS_AND_SETS_NOT_ALLOWED.code + "): Test.g4:6:36: string literals and sets cannot be empty: []\n" +
561 				"warning("+ ErrorType.EPSILON_TOKEN.code + "): Test.g4:2:0: non-fragment lexer rule INVALID_STRING_LITERAL can match the empty string\n";
562 
563 		String[] pair = new String[] {
564 				grammar,
565 				expected
566 		};
567 
568 		super.testErrors(pair, true);
569 	}
570 
testInvalidUnicodeEscapesInCharSet()571 	@Test public void testInvalidUnicodeEscapesInCharSet() {
572 		String grammar =
573 				"lexer grammar Test;\n" +
574 				"INVALID_EXTENDED_UNICODE_EMPTY: [\\u{}];\n" +
575 				"INVALID_EXTENDED_UNICODE_NOT_TERMINATED: [\\u{];\n" +
576 				"INVALID_EXTENDED_UNICODE_TOO_LONG: [\\u{110000}];\n" +
577 				"INVALID_UNICODE_PROPERTY_EMPTY: [\\p{}];\n" +
578 				"INVALID_UNICODE_PROPERTY_NOT_TERMINATED: [\\p{];\n" +
579 				"INVALID_INVERTED_UNICODE_PROPERTY_EMPTY: [\\P{}];\n" +
580 				"INVALID_UNICODE_PROPERTY_UNKNOWN: [\\p{NotAProperty}];\n" +
581 				"INVALID_INVERTED_UNICODE_PROPERTY_UNKNOWN: [\\P{NotAProperty}];\n" +
582 				"UNICODE_PROPERTY_NOT_ALLOWED_IN_RANGE: [\\p{Uppercase_Letter}-\\p{Lowercase_Letter}];\n" +
583 				"UNICODE_PROPERTY_NOT_ALLOWED_IN_RANGE_2: [\\p{Letter}-Z];\n" +
584 				"UNICODE_PROPERTY_NOT_ALLOWED_IN_RANGE_3: [A-\\p{Number}];\n" +
585 				"INVERTED_UNICODE_PROPERTY_NOT_ALLOWED_IN_RANGE: [\\P{Uppercase_Letter}-\\P{Number}];\n";
586 
587 		String expected =
588 				"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): Test.g4:2:32: invalid escape sequence \\u{}\n"+
589 				"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): Test.g4:3:41: invalid escape sequence \\u{\n"+
590 				"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): Test.g4:4:35: invalid escape sequence \\u{110\n"+
591 				"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): Test.g4:5:32: invalid escape sequence \\p{}\n"+
592 				"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): Test.g4:6:41: invalid escape sequence \\p{\n"+
593 				"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): Test.g4:7:41: invalid escape sequence \\P{}\n"+
594 				"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): Test.g4:8:34: invalid escape sequence \\p{NotAProperty}\n"+
595 				"warning(" + ErrorType.INVALID_ESCAPE_SEQUENCE.code + "): Test.g4:9:43: invalid escape sequence \\P{NotAProperty}\n"+
596 				"error(" + ErrorType.UNICODE_PROPERTY_NOT_ALLOWED_IN_RANGE.code + "): Test.g4:10:39: unicode property escapes not allowed in lexer charset range: [\\p{Uppercase_Letter}-\\p{Lowercase_Letter}]\n" +
597 				"error(" + ErrorType.UNICODE_PROPERTY_NOT_ALLOWED_IN_RANGE.code + "): Test.g4:11:41: unicode property escapes not allowed in lexer charset range: [\\p{Letter}-Z]\n" +
598 				"error(" + ErrorType.UNICODE_PROPERTY_NOT_ALLOWED_IN_RANGE.code + "): Test.g4:12:41: unicode property escapes not allowed in lexer charset range: [A-\\p{Number}]\n" +
599 				"error(" + ErrorType.UNICODE_PROPERTY_NOT_ALLOWED_IN_RANGE.code + "): Test.g4:13:48: unicode property escapes not allowed in lexer charset range: [\\P{Uppercase_Letter}-\\P{Number}]\n";
600 
601 		String[] pair = new String[] {
602 				grammar,
603 				expected
604 		};
605 
606 		super.testErrors(pair, true);
607 	}
608 
609 	/**
610 	 * This test ensures the {@link ErrorType#UNRECOGNIZED_ASSOC_OPTION} warning
611 	 * is produced as described in the documentation.
612 	 */
testUnrecognizedAssocOption()613 	@Test public void testUnrecognizedAssocOption() {
614 		String grammar =
615 			"grammar A;\n" +
616 			"x : 'x'\n" +
617 			"  | x '+'<assoc=right> x   // warning 157\n" +
618 			"  |<assoc=right> x '*' x   // ok\n" +
619 			"  ;\n";
620 		String expected =
621 			"warning(" + ErrorType.UNRECOGNIZED_ASSOC_OPTION.code + "): A.g4:3:10: rule x contains an assoc terminal option in an unrecognized location\n";
622 
623 		String[] pair = new String[] {
624 			grammar,
625 			expected
626 		};
627 
628 		super.testErrors(pair, true);
629 	}
630 
631 	/**
632 	 * This test ensures the {@link ErrorType#FRAGMENT_ACTION_IGNORED} warning
633 	 * is produced as described in the documentation.
634 	 */
testFragmentActionIgnored()635 	@Test public void testFragmentActionIgnored() {
636 		String grammar =
637 			"lexer grammar A;\n" +
638 			"X1 : 'x' -> more    // ok\n" +
639 			"   ;\n" +
640 			"Y1 : 'x' {more();}  // ok\n" +
641 			"   ;\n" +
642 			"fragment\n" +
643 			"X2 : 'x' -> more    // warning 158\n" +
644 			"   ;\n" +
645 			"fragment\n" +
646 			"Y2 : 'x' {more();}  // warning 158\n" +
647 			"   ;\n";
648 		String expected =
649 			"warning(" + ErrorType.FRAGMENT_ACTION_IGNORED.code + "): A.g4:7:12: fragment rule X2 contains an action or command which can never be executed\n" +
650 			"warning(" + ErrorType.FRAGMENT_ACTION_IGNORED.code + "): A.g4:10:9: fragment rule Y2 contains an action or command which can never be executed\n";
651 
652 		String[] pair = new String[] {
653 			grammar,
654 			expected
655 		};
656 
657 		super.testErrors(pair, true);
658 	}
659 
660 	/**
661 	 * This is a regression test for antlr/antlr4#500 "Array Index Out Of
662 	 * Bounds".
663 	 * https://github.com/antlr/antlr4/issues/500
664 	 */
testTokenNamedEOF()665 	@Test public void testTokenNamedEOF() {
666 		String grammar =
667 			"lexer grammar A;\n" +
668 			"WS : ' ';\n" +
669 			" EOF : 'a';\n";
670 		String expected =
671 			"error(" + ErrorType.RESERVED_RULE_NAME.code + "): A.g4:3:1: cannot declare a rule with reserved name EOF\n";
672 
673 		String[] pair = new String[] {
674 			grammar,
675 			expected
676 		};
677 
678 		super.testErrors(pair, true);
679 	}
680 
681 	/**
682 	 * This is a regression test for antlr/antlr4#649 "unknown target causes
683 	 * null ptr exception.".
684 	 * https://github.com/antlr/antlr4/issues/649
685 	 * Stops before processing the lexer
686 	 */
testInvalidLanguageInGrammarWithLexerCommand()687 	@Test public void testInvalidLanguageInGrammarWithLexerCommand() throws Exception {
688 		String grammar =
689 			"grammar T;\n" +
690 			"options { language=Foo; }\n" +
691 			"start : 'T' EOF;\n" +
692 			"Something : 'something' -> channel(CUSTOM);";
693 		String expected =
694 			"error(" + ErrorType.CANNOT_CREATE_TARGET_GENERATOR.code + "):  ANTLR cannot generate Foo code as of version " + Tool.VERSION + "\n";
695 		String[] pair = new String[] {
696 			grammar,
697 			expected
698 		};
699 
700 		super.testErrors(pair, true);
701 	}
702 
703 	/**
704 	 * This is a regression test for antlr/antlr4#649 "unknown target causes
705 	 * null ptr exception.".
706 	 * https://github.com/antlr/antlr4/issues/649
707 	 */
testInvalidLanguageInGrammar()708 	@Test public void testInvalidLanguageInGrammar() throws Exception {
709 		String grammar =
710 			"grammar T;\n" +
711 			"options { language=Foo; }\n" +
712 			"start : 'T' EOF;\n";
713 		String expected =
714 			"error(" + ErrorType.CANNOT_CREATE_TARGET_GENERATOR.code + "):  ANTLR cannot generate Foo code as of version " + Tool.VERSION + "\n";
715 
716 		String[] pair = new String[] {
717 			grammar,
718 			expected
719 		};
720 
721 		super.testErrors(pair, true);
722 	}
723 
testChannelDefinitionInLexer()724 	@Test public void testChannelDefinitionInLexer() throws Exception {
725 		String grammar =
726 			"lexer grammar T;\n" +
727 			"\n" +
728 			"channels {\n" +
729 			"	WHITESPACE_CHANNEL,\n" +
730 			"	COMMENT_CHANNEL\n" +
731 			"}\n" +
732 			"\n" +
733 			"COMMENT:    '//' ~[\\n]+ -> channel(COMMENT_CHANNEL);\n" +
734 			"WHITESPACE: [ \\t]+      -> channel(WHITESPACE_CHANNEL);\n";
735 
736 		String expected = "";
737 
738 		String[] pair = { grammar, expected };
739 		super.testErrors(pair, true);
740 	}
741 
testChannelDefinitionInParser()742 	@Test public void testChannelDefinitionInParser() throws Exception {
743 		String grammar =
744 			"parser grammar T;\n" +
745 			"\n" +
746 			"channels {\n" +
747 			"	WHITESPACE_CHANNEL,\n" +
748 			"	COMMENT_CHANNEL\n" +
749 			"}\n" +
750 			"\n" +
751 			"start : EOF;\n";
752 
753 		String expected =
754 			"error(" + ErrorType.CHANNELS_BLOCK_IN_PARSER_GRAMMAR.code + "): T.g4:3:0: custom channels are not supported in parser grammars\n";
755 
756 		String[] pair = { grammar, expected };
757 		super.testErrors(pair, true);
758 	}
759 
testChannelDefinitionInCombined()760 	@Test public void testChannelDefinitionInCombined() throws Exception {
761 		String grammar =
762 			"grammar T;\n" +
763 			"\n" +
764 			"channels {\n" +
765 			"	WHITESPACE_CHANNEL,\n" +
766 			"	COMMENT_CHANNEL\n" +
767 			"}\n" +
768 			"\n" +
769 			"start : EOF;\n" +
770 			"\n" +
771 			"COMMENT:    '//' ~[\\n]+ -> channel(COMMENT_CHANNEL);\n" +
772 			"WHITESPACE: [ \\t]+      -> channel(WHITESPACE_CHANNEL);\n";
773 
774 		String expected =
775 			"error(" + ErrorType.CONSTANT_VALUE_IS_NOT_A_RECOGNIZED_CHANNEL_NAME.code + "): T.g4:10:35: COMMENT_CHANNEL is not a recognized channel name\n" +
776 			"error(" + ErrorType.CONSTANT_VALUE_IS_NOT_A_RECOGNIZED_CHANNEL_NAME.code + "): T.g4:11:35: WHITESPACE_CHANNEL is not a recognized channel name\n" +
777 			"error(" + ErrorType.CHANNELS_BLOCK_IN_COMBINED_GRAMMAR.code + "): T.g4:3:0: custom channels are not supported in combined grammars\n";
778 
779 		String[] pair = { grammar, expected };
780 		super.testErrors(pair, true);
781 	}
782 
783 	/**
784 	 * This is a regression test for antlr/antlr4#497 now that antlr/antlr4#309
785 	 * is resolved.
786 	 * https://github.com/antlr/antlr4/issues/497
787 	 * https://github.com/antlr/antlr4/issues/309
788 	 */
testChannelDefinitions()789 	@Test public void testChannelDefinitions() throws Exception {
790 		String grammar =
791 			"lexer grammar T;\n" +
792 			"\n" +
793 			"channels {\n" +
794 			"	WHITESPACE_CHANNEL,\n" +
795 			"	COMMENT_CHANNEL\n" +
796 			"}\n" +
797 			"\n" +
798 			"COMMENT:    '//' ~[\\n]+ -> channel(COMMENT_CHANNEL);\n" +
799 			"WHITESPACE: [ \\t]+      -> channel(WHITESPACE_CHANNEL);\n" +
800 			"NEWLINE:    '\\r'? '\\n' -> channel(NEWLINE_CHANNEL);";
801 
802 		// WHITESPACE_CHANNEL and COMMENT_CHANNEL are defined, but NEWLINE_CHANNEL is not
803 		String expected =
804 			"error(" + ErrorType.CONSTANT_VALUE_IS_NOT_A_RECOGNIZED_CHANNEL_NAME.code + "): T.g4:10:34: NEWLINE_CHANNEL is not a recognized channel name\n";
805 
806 		String[] pair = { grammar, expected };
807 		super.testErrors(pair, true);
808 	}
809 
810 	// Test for https://github.com/antlr/antlr4/issues/1556
testRangeInParserGrammar()811 	@Test public void testRangeInParserGrammar() {
812 		String grammar =
813 			"grammar T;\n"+
814 			"a:  'A'..'Z' ;\n";
815 		String expected =
816 			"error(" + ErrorType.TOKEN_RANGE_IN_PARSER.code + "): T.g4:2:4: token ranges not allowed in parser: 'A'..'Z'\n";
817 
818 		String[] pair = new String[] {
819 			grammar,
820 			expected
821 		};
822 
823 		super.testErrors(pair, true);
824 	}
825 }
826