diff --git a/src/main/java/org/antlr/intellij/adaptor/parser/ANTLRParseTreeToPSIConverter.java b/src/main/java/org/antlr/intellij/adaptor/parser/ANTLRParseTreeToPSIConverter.java index 1155746..b6421ab 100644 --- a/src/main/java/org/antlr/intellij/adaptor/parser/ANTLRParseTreeToPSIConverter.java +++ b/src/main/java/org/antlr/intellij/adaptor/parser/ANTLRParseTreeToPSIConverter.java @@ -6,6 +6,7 @@ import org.antlr.intellij.adaptor.lexer.PSIElementTypeFactory; import org.antlr.intellij.adaptor.lexer.RuleIElementType; import org.antlr.intellij.adaptor.lexer.TokenIElementType; +import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.ANTLRErrorListener; import org.antlr.v4.runtime.Parser; import org.antlr.v4.runtime.ParserRuleContext; @@ -30,7 +31,7 @@ public class ANTLRParseTreeToPSIConverter implements ParseTreeListener { protected final Language language; protected final PsiBuilder builder; - protected List syntaxErrors; + protected Map syntaxErrors; protected final Deque markers = new ArrayDeque<>(); protected final List tokenElementTypes; @@ -48,8 +49,8 @@ public ANTLRParseTreeToPSIConverter(Language language, Parser parser, PsiBuilder for (ANTLRErrorListener listener : parser.getErrorListeners()) { if (listener instanceof SyntaxErrorListener) { - syntaxErrors = ((SyntaxErrorListener)listener).getSyntaxErrors(); - for (SyntaxError error : syntaxErrors) { + syntaxErrors = ((SyntaxErrorListener) listener).getErrorMap(); + for (SyntaxError error : syntaxErrors.values()) { // record first error per token int StartIndex = error.getOffendingSymbol().getStartIndex(); if ( !tokenToErrorMap.containsKey(StartIndex) ) { @@ -115,6 +116,7 @@ public void visitTerminal(TerminalNode node) { * prediction started (which we use to find syntax errors). So, * SyntaxError objects return start not offending token in this case. */ + @Override public void visitErrorNode(ErrorNode node) { ProgressIndicatorProvider.checkCanceled(); @@ -159,6 +161,15 @@ public void enterEveryRule(ParserRuleContext ctx) { public void exitEveryRule(ParserRuleContext ctx) { ProgressIndicatorProvider.checkCanceled(); PsiBuilder.Marker marker = markers.pop(); - marker.done(getRuleElementTypes().get(ctx.getRuleIndex())); + if (ctx.exception != null) { + SyntaxError error = syntaxErrors.get(ctx.exception); + if (error != null) { + marker.error(error.getMessage()); + } else { + marker.done(getRuleElementTypes().get(ctx.getRuleIndex())); + } + } else { + marker.done(getRuleElementTypes().get(ctx.getRuleIndex())); + } } } diff --git a/src/main/java/org/antlr/intellij/adaptor/parser/SyntaxErrorListener.java b/src/main/java/org/antlr/intellij/adaptor/parser/SyntaxErrorListener.java index 0d7c442..02eff81 100644 --- a/src/main/java/org/antlr/intellij/adaptor/parser/SyntaxErrorListener.java +++ b/src/main/java/org/antlr/intellij/adaptor/parser/SyntaxErrorListener.java @@ -7,19 +7,25 @@ import org.antlr.v4.runtime.misc.Utils; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** Traps errors from parsing language of plugin. E.g., for a Java plugin, * this would catch errors when people type invalid Java code into .java file. * This swallows the errors as the PSI tree has error nodes. */ public class SyntaxErrorListener extends BaseErrorListener { - private final List syntaxErrors = new ArrayList<>(); + private final Map syntaxErrors = new HashMap<>(); public SyntaxErrorListener() { } public List getSyntaxErrors() { + return new ArrayList<>(syntaxErrors.values()); + } + + Map getErrorMap() { return syntaxErrors; } @@ -29,11 +35,11 @@ public void syntaxError(Recognizer recognizer, int line, int charPositionInLine, String msg, RecognitionException e) { - syntaxErrors.add(new SyntaxError(recognizer, (Token)offendingSymbol, line, charPositionInLine, msg, e)); + syntaxErrors.put(e, new SyntaxError(recognizer, (Token) offendingSymbol, line, charPositionInLine, msg, e)); } @Override public String toString() { - return Utils.join(syntaxErrors.iterator(), "\n"); + return Utils.join(syntaxErrors.values().iterator(), "\n"); } }