Improve the error recovery for parameter directives

This commit is contained in:
Ben Gruver 2015-03-05 21:47:12 -08:00
parent bdbb235c6f
commit 87be840208
5 changed files with 145 additions and 15 deletions

View File

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

View File

@ -107,7 +107,7 @@ public class SmaliMethodParameter extends SmaliStubBasedPsiElement<SmaliMethodPa
return null;
}
@Override public String getName() {
@Nullable @Override public String getName() {
SmaliMethodParameterStub stub = getStub();
if (stub != null) {
return stub.getName();

View File

@ -57,6 +57,7 @@ public class ParserTest extends LightCodeInsightParsingTestCase {
public void testSuperClassInvalidSyntax() throws Exception { doTest(true); }
public void testSuperClassInvalidSyntax2() throws Exception { doTest(true); }
public void testInvalidMethodReference() throws Exception { doTest(true); }
public void testInvalidParameter() throws Exception { doTest(true); }
public void testInvalidMethod() throws Exception { doTest(true); }
public void testInvalidMethod2() throws Exception { doTest(true); }
public void testInvalidMethod3() throws Exception { doTest(true); }

View File

@ -0,0 +1,10 @@
.method public blah()V
.param v0, "blah"
.a
.end method
.method public blah()V
.param v0, "blah"
.annotation runtime Lblah; .end annotation
.
.end method

View File

@ -0,0 +1,85 @@
smali.FILE
SmaliClass(CLASS)
SmaliExtendsList(EXTENDS_LIST)
<empty list>
SmaliImplementsList(IMPLEMENTS_LIST)
<empty list>
SmaliMethod(METHOD)
SmaliThrowsList(THROWS_LIST)
<empty 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)
<empty 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)
<empty 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)
<empty 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)
<empty 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')