[groovy] parse modifier list until the subsequent modifier if not a qualifier of some path (follow up IDEA-134006)

This commit is contained in:
Daniil Ovchinnikov
2016-09-21 15:26:28 +03:00
parent 10b99e7bbd
commit c07b75ed2f
4 changed files with 54 additions and 33 deletions
@@ -34,7 +34,6 @@ import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.declaration.D
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.AssignmentExpression;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.ConditionalExpression;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.ExpressionStatement;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.arithmetic.PathExpression;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.imports.ImportStatement;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.typeDefinitions.TypeDefinition;
import org.jetbrains.plugins.groovy.lang.parser.parsing.toplevel.CompilationUnit;
@@ -399,13 +398,6 @@ public class GroovyParser implements PsiParser {
PsiBuilder.Marker declMarker = builder.mark();
boolean modifiersParsed = Modifiers.parse(builder, this);
if (modifiersParsed && PathExpression.isQualicationDot(builder)) {
modifiersParsed = false;
declMarker.rollbackTo();
declMarker = builder.mark();
builder.mark().done(GroovyElementTypes.MODIFIERS);
}
if (GroovyTokenTypes.kIMPORT == builder.getTokenType()) {
final PsiBuilder.Marker impMarker = declMarker.precede();
ImportStatement.parseAfterModifiers(builder);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyParser;
import org.jetbrains.plugins.groovy.lang.parser.parsing.auxiliary.annotations.Annotation;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.arithmetic.PathExpression;
import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils;
/**
@@ -30,40 +31,41 @@ import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils;
*/
/*
* Modifiers ::= "def" nls
* | {modifier nls}+
* | {annotation nls}+
* Modifiers ::= {modifier|annotation} (nls? {modifier|annotation})+
*/
public class Modifiers {
public static boolean parse(PsiBuilder builder, GroovyParser parser) {
boolean endsWithNewLine;
PsiBuilder.Marker modifiersMarker = builder.mark();
boolean hasModifiers = false;
if (!Annotation.parse(builder, parser) && !parseModifier(builder)) {
modifiersMarker.done(GroovyElementTypes.MODIFIERS);
return false;
do {
final PsiBuilder.Marker modifierListItem = builder.mark();
if (hasModifiers) ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
final boolean parsed = Annotation.parse(builder, parser) || parseModifier(builder);
if (parsed) {
if (PathExpression.isQualicationDot(builder)) {
modifierListItem.rollbackTo();
break;
}
else {
modifierListItem.drop();
hasModifiers = true;
}
}
else {
modifierListItem.rollbackTo();
break;
}
}
while (true);
PsiBuilder.Marker newLineMarker = builder.mark();
while (true) {
newLineMarker.drop();
newLineMarker = builder.mark();
endsWithNewLine = ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
if (!Annotation.parse(builder, parser) && !parseModifier(builder)) break;
}
// Do not include last newline
if (endsWithNewLine) {
newLineMarker.rollbackTo();
} else {
newLineMarker.drop();
}
modifiersMarker.done(GroovyElementTypes.MODIFIERS);
ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
return true;
return hasModifiers;
}
public static boolean parseModifier(PsiBuilder builder) {
@@ -201,6 +201,8 @@ class StatementsParsingTest extends GroovyParsingTestCase {
void testMethods$method5() throws Throwable { doTest(); }
void testMethods$method6() throws Throwable { doTest(); }
void testMethods$vararg() throws Throwable { doTest(); }
void testMultiple_assign$grvy2086() throws Throwable { doTest("multiple_assign/grvy-2086.test"); }
@@ -0,0 +1,25 @@
public def.MyClass foo() {}
-----
Groovy script
Method
Modifiers
PsiElement(public)('public')
PsiWhiteSpace(' ')
Type element
Reference element
Reference element
PsiElement(def)('def')
PsiElement(.)('.')
PsiElement(identifier)('MyClass')
PsiWhiteSpace(' ')
PsiElement(identifier)('foo')
PsiElement(()('(')
Parameter list
<empty list>
PsiElement())(')')
Throw clause
<empty list>
PsiWhiteSpace(' ')
Open block
PsiElement({)('{')
PsiElement(})('}')