From 87be8402085578f1a6ff52adf98175a6ebb8fb8f Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Thu, 5 Mar 2015 21:47:12 -0800 Subject: [PATCH] Improve the error recovery for parameter directives --- smalidea/src/main/antlr3/smalideaParser.g | 62 +++++++++++--- .../psi/impl/SmaliMethodParameter.java | 2 +- .../test/java/org/jf/smalidea/ParserTest.java | 1 + smalidea/testData/InvalidParameter.smalidea | 10 +++ smalidea/testData/InvalidParameter.txt | 85 +++++++++++++++++++ 5 files changed, 145 insertions(+), 15 deletions(-) create mode 100644 smalidea/testData/InvalidParameter.smalidea create mode 100644 smalidea/testData/InvalidParameter.txt diff --git a/smalidea/src/main/antlr3/smalideaParser.g b/smalidea/src/main/antlr3/smalideaParser.g index e1290854..9b1e555c 100644 --- a/smalidea/src/main/antlr3/smalideaParser.g +++ b/smalidea/src/main/antlr3/smalideaParser.g @@ -923,22 +923,56 @@ add them to the $statements_and_directives::methodAnnotations list*/ parameter_directive @init { Marker marker = mark(); - Marker preAnnotationMarker = null; - Marker nameMarker = null; + Marker annotationsMarker = null; + boolean gotEndParam = false; } : PARAMETER_DIRECTIVE register - (comma { nameMarker = mark(); } string_literal { nameMarker.done(SmaliElementTypes.LOCAL_NAME); })? - { preAnnotationMarker = mark(); } - ({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation)* - ( END_PARAMETER_DIRECTIVE { - preAnnotationMarker.drop(); - marker.done(SmaliElementTypes.PARAMETER_STATEMENT); - } - | /*epsilon*/ { - marker.doneBefore(SmaliElementTypes.PARAMETER_STATEMENT, preAnnotationMarker); - preAnnotationMarker.drop(); - } - ); + (comma local_name)? + { annotationsMarker = mark(); } parameter_annotations + ( end_parameter_directive { gotEndParam = true; } )? + { + if (gotEndParam) { + annotationsMarker.drop(); + marker.done(SmaliElementTypes.PARAMETER_STATEMENT); + } else { + marker.doneBefore(SmaliElementTypes.PARAMETER_STATEMENT, annotationsMarker); + annotationsMarker.drop(); + } + }; + catch [RecognitionException re] { + if (annotationsMarker != null) { + annotationsMarker.drop(); + } + recover(input, re); + reportError(marker, re, false); + } + +parameter_annotations + : ((ANNOTATION_DIRECTIVE)=> annotation)*; + catch [RecognitionException re] { + Marker errorMarker = mark(); + recover(input, re); + reportError(errorMarker, re, false); + } + +end_parameter_directive + : END_PARAMETER_DIRECTIVE; + +local_name + @init { + Marker localNameMarker = mark(); + Marker stringMarker = mark(); + } + : STRING_LITERAL + { + finishToken(stringMarker, SmaliElementTypes.LITERAL); + finishToken(localNameMarker, SmaliElementTypes.LOCAL_NAME); + }; + catch [RecognitionException re] { + stringMarker.drop(); + recover(input, re); + reportError(localNameMarker, re, false); + } register @init { Marker marker = mark(); } diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodParameter.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodParameter.java index fcfcd91b..61683a5d 100644 --- a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodParameter.java +++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodParameter.java @@ -107,7 +107,7 @@ public class SmaliMethodParameter extends SmaliStubBasedPsiElement + SmaliImplementsList(IMPLEMENTS_LIST) + + SmaliMethod(METHOD) + SmaliThrowsList(THROWS_LIST) + + PsiElement(METHOD_DIRECTIVE)('.method') + PsiWhiteSpace(' ') + SmaliModifierList(MODIFIER_LIST) + PsiElement(ACCESS_SPEC)('public') + PsiWhiteSpace(' ') + PsiElement(MEMBER_NAME) + PsiElement(SIMPLE_NAME)('blah') + SmaliMethodPrototype(METHOD_PROTOTYPE) + PsiElement(OPEN_PAREN)('(') + SmaliMethodParamList(METHOD_PARAM_LIST) + + PsiElement(CLOSE_PAREN)(')') + PsiElement(VOID_TYPE) + PsiElement(VOID_TYPE)('V') + PsiWhiteSpace('\n ') + PsiElement(PARAMETER_STATEMENT) + PsiElement(PARAMETER_DIRECTIVE)('.param') + PsiWhiteSpace(' ') + PsiElement(REGISTER_REFERENCE) + PsiElement(REGISTER)('v0') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + PsiElement(LOCAL_NAME) + PsiElement(LITERAL) + PsiElement(STRING_LITERAL)('"blah"') + PsiWhiteSpace('\n ') + PsiErrorElement:no viable alternative at input '.a' + PsiElement(BAD_CHARACTER)('.a') + PsiWhiteSpace('\n') + PsiElement(END_METHOD_DIRECTIVE)('.end method') + PsiWhiteSpace('\n\n') + SmaliMethod(METHOD) + SmaliThrowsList(THROWS_LIST) + + PsiElement(METHOD_DIRECTIVE)('.method') + PsiWhiteSpace(' ') + SmaliModifierList(MODIFIER_LIST) + PsiElement(ACCESS_SPEC)('public') + PsiWhiteSpace(' ') + PsiElement(MEMBER_NAME) + PsiElement(SIMPLE_NAME)('blah') + SmaliMethodPrototype(METHOD_PROTOTYPE) + PsiElement(OPEN_PAREN)('(') + SmaliMethodParamList(METHOD_PARAM_LIST) + + PsiElement(CLOSE_PAREN)(')') + PsiElement(VOID_TYPE) + PsiElement(VOID_TYPE)('V') + PsiWhiteSpace('\n ') + PsiElement(PARAMETER_STATEMENT) + PsiElement(PARAMETER_DIRECTIVE)('.param') + PsiWhiteSpace(' ') + PsiElement(REGISTER_REFERENCE) + PsiElement(REGISTER)('v0') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + PsiElement(LOCAL_NAME) + PsiElement(LITERAL) + PsiElement(STRING_LITERAL)('"blah"') + PsiWhiteSpace('\n ') + SmaliAnnotation(ANNOTATION) + PsiElement(ANNOTATION_DIRECTIVE)('.annotation') + PsiWhiteSpace(' ') + PsiElement(ANNOTATION_VISIBILITY)('runtime') + PsiWhiteSpace(' ') + PsiElement(CLASS_TYPE) + PsiElement(CLASS_DESCRIPTOR)('Lblah;') + PsiWhiteSpace(' ') + PsiElement(ANNOTATION_PARAMETER_LIST) + + PsiElement(END_ANNOTATION_DIRECTIVE)('.end annotation') + PsiWhiteSpace('\n ') + PsiErrorElement:no viable alternative at input '.' + PsiElement(BAD_CHARACTER)('.') + PsiWhiteSpace('\n') + PsiElement(END_METHOD_DIRECTIVE)('.end method') \ No newline at end of file