Add compiler warning 158: FRAGMENT_ACTION_IGNORED (fixes #472)
This commit is contained in:
parent
b2af59e73e
commit
0ed651cbc6
|
@ -116,6 +116,13 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
|
|||
*/
|
||||
protected int nonFragmentRuleCount;
|
||||
|
||||
/**
|
||||
* This is {@code true} from the time {@link #discoverLexerRule} is called
|
||||
* for a lexer rule with the {@code fragment} modifier until
|
||||
* {@link #exitLexerRule} is called.
|
||||
*/
|
||||
private boolean inFragmentRule;
|
||||
|
||||
public BasicSemanticChecks(Grammar g, RuleCollector ruleCollector) {
|
||||
this.g = g;
|
||||
this.ruleCollector = ruleCollector;
|
||||
|
@ -200,20 +207,24 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
|
|||
{
|
||||
checkInvalidRuleDef(ID.token);
|
||||
|
||||
boolean fragmentRule = false;
|
||||
if (modifiers != null) {
|
||||
for (GrammarAST tree : modifiers) {
|
||||
if (tree.getType() == ANTLRParser.FRAGMENT) {
|
||||
fragmentRule = true;
|
||||
inFragmentRule = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fragmentRule) {
|
||||
if (!inFragmentRule) {
|
||||
nonFragmentRuleCount++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exitLexerRule(GrammarAST tree) {
|
||||
inFragmentRule = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ruleRef(GrammarAST ref, ActionAST arg) {
|
||||
checkInvalidRuleRef(ref.token);
|
||||
|
@ -381,6 +392,21 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
|
|||
@Override
|
||||
protected void enterLexerCommand(GrammarAST tree) {
|
||||
checkElementIsOuterMostInSingleAlt(tree);
|
||||
|
||||
if (inFragmentRule) {
|
||||
String fileName = tree.token.getInputStream().getSourceName();
|
||||
String ruleName = currentRuleName;
|
||||
g.tool.errMgr.grammarError(ErrorType.FRAGMENT_ACTION_IGNORED, fileName, tree.token, ruleName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionInAlt(ActionAST action) {
|
||||
if (inFragmentRule) {
|
||||
String fileName = action.token.getInputStream().getSourceName();
|
||||
String ruleName = currentRuleName;
|
||||
g.tool.errMgr.grammarError(ErrorType.FRAGMENT_ACTION_IGNORED, fileName, action.token, ruleName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -852,6 +852,37 @@ public enum ErrorType {
|
|||
* @since 4.2.1
|
||||
*/
|
||||
UNRECOGNIZED_ASSOC_OPTION(157, "rule '<arg>' contains an 'assoc' terminal option in an unrecognized location", ErrorSeverity.WARNING),
|
||||
/**
|
||||
* Compiler Warning 158.
|
||||
*
|
||||
* <p>fragment rule '<em>rule</em>' contains an action or command which can
|
||||
* never be executed</p>
|
||||
*
|
||||
* <p>A lexer rule which is marked with the {@code fragment} modifier
|
||||
* contains an embedded action or lexer command. ANTLR lexers only execute
|
||||
* commands and embedded actions located in the top-level matched rule.
|
||||
* Since fragment rules can never be the top-level rule matched by a lexer,
|
||||
* actions or commands placed in these rules can never be executed during
|
||||
* the lexing process.</p>
|
||||
*
|
||||
* <p>The following rule produces this warning.</p>
|
||||
*
|
||||
* <pre>
|
||||
* X1 : 'x' -> more // ok
|
||||
* ;
|
||||
* Y1 : 'x' {more();} // ok
|
||||
* ;
|
||||
* fragment
|
||||
* X2 : 'x' -> more // warning 158
|
||||
* ;
|
||||
* fragment
|
||||
* Y2 : 'x' {more();} // warning 158
|
||||
* ;
|
||||
* </pre>
|
||||
*
|
||||
* @since 4.2.1
|
||||
*/
|
||||
FRAGMENT_ACTION_IGNORED(158, "fragment rule '<arg>' contains an action or command which can never be executed", ErrorSeverity.WARNING),
|
||||
|
||||
/*
|
||||
* Backward incompatibility errors
|
||||
|
|
|
@ -473,4 +473,33 @@ public class TestToolSyntaxErrors extends BaseTest {
|
|||
|
||||
super.testErrors(pair, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test ensures the {@link ErrorType#FRAGMENT_ACTION_IGNORED} warning
|
||||
* is produced as described in the documentation.
|
||||
*/
|
||||
@Test public void testFragmentActionIgnored() {
|
||||
String grammar =
|
||||
"lexer grammar A;\n" +
|
||||
"X1 : 'x' -> more // ok\n" +
|
||||
" ;\n" +
|
||||
"Y1 : 'x' {more();} // ok\n" +
|
||||
" ;\n" +
|
||||
"fragment\n" +
|
||||
"X2 : 'x' -> more // warning 158\n" +
|
||||
" ;\n" +
|
||||
"fragment\n" +
|
||||
"Y2 : 'x' {more();} // warning 158\n" +
|
||||
" ;\n";
|
||||
String expected =
|
||||
"warning(" + ErrorType.FRAGMENT_ACTION_IGNORED.code + "): A.g4:7:12: fragment rule 'X2' contains an action or command which can never be executed\n" +
|
||||
"warning(" + ErrorType.FRAGMENT_ACTION_IGNORED.code + "): A.g4:10:9: fragment rule 'Y2' contains an action or command which can never be executed\n";
|
||||
|
||||
String[] pair = new String[] {
|
||||
grammar,
|
||||
expected
|
||||
};
|
||||
|
||||
super.testErrors(pair, true);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue