Add compiler warning 158: FRAGMENT_ACTION_IGNORED (fixes #472)

This commit is contained in:
Sam Harwell 2014-03-23 17:45:58 -05:00
parent b2af59e73e
commit 0ed651cbc6
3 changed files with 89 additions and 3 deletions

View File

@ -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);
}
}
/**

View File

@ -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

View File

@ -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);
}
}