diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyClassNameInsertHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyClassNameInsertHandler.java index 3646278c8912..d7f827909403 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyClassNameInsertHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyClassNameInsertHandler.java @@ -59,7 +59,7 @@ public class GroovyClassNameInsertHandler implements InsertHandler"); } } } - public static boolean isInClosurePropertyParameters(PsiElement position) { //Closure cl={String x, ... + public static boolean isInPossibleClosureParameter(PsiElement position) { //Closure cl={String x, ... if (position == null) return false; - GrVariableDeclaration declaration = PsiTreeUtil.getParentOfType(position, GrVariableDeclaration.class, false, GrStatement.class); - if (declaration == null) { - if (position.getParent() instanceof PsiErrorElement) position = position.getParent(); - PsiElement prev = position.getPrevSibling(); - prev = skipWhitespaces(prev, false); - if (prev instanceof PsiErrorElement) { - prev = prev.getPrevSibling(); - } - prev = skipWhitespaces(prev, false); - if (prev instanceof GrVariableDeclaration) declaration = (GrVariableDeclaration)prev; + if (position instanceof PsiWhiteSpace || position.getNode().getElementType() == GroovyElementTypes.mNLS) { + position = FilterPositionUtil.searchNonSpaceNonCommentBack(position); } - if (declaration != null) { - if (!(declaration.getParent() instanceof GrClosableBlock)) return false; - PsiElement prevSibling = skipWhitespaces(declaration.getPrevSibling(), false); - return prevSibling instanceof GrParameterList; + + boolean hasCommas = false; + while (position != null) { + PsiElement parent = position.getParent(); + if (parent instanceof GrVariable) { + PsiElement prev = FilterPositionUtil.searchNonSpaceNonCommentBack(parent); + hasCommas = prev != null && prev.getNode().getElementType() == GroovyElementTypes.mCOMMA; + } + + if (parent instanceof GrClosableBlock) { + PsiElement sibling = position.getPrevSibling(); + while (sibling != null) { + if (sibling instanceof GrParameterList) { + return hasCommas; + } + + boolean isComma = sibling instanceof LeafPsiElement && GroovyElementTypes.mCOMMA == ((LeafPsiElement)sibling).getElementType(); + hasCommas |= isComma; + + if (isComma || + sibling instanceof PsiWhiteSpace || + sibling instanceof PsiErrorElement || + sibling instanceof GrVariableDeclaration || + sibling instanceof GrReferenceExpression && !((GrReferenceExpression)sibling).isQualified() + ) { + sibling = sibling.getPrevSibling(); + } + else { + return false; + } + } + return false; + } + position = parent; } return false; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/filters/exprs/InstanceOfFilter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/filters/exprs/InstanceOfFilter.java index d916ac804178..6368134d11f2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/filters/exprs/InstanceOfFilter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/filters/exprs/InstanceOfFilter.java @@ -30,6 +30,10 @@ import org.jetbrains.annotations.NonNls; */ public class InstanceOfFilter implements ElementFilter { public boolean isAcceptable(Object element, PsiElement context) { + return isInfixOperatorPosition(context); + } + + public static boolean isInfixOperatorPosition(PsiElement context) { if (context.getParent() != null && context.getParent() instanceof GrReferenceExpression && context.getParent().getParent() != null && diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/filters/types/BuiltInTypeFilter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/filters/types/BuiltInTypeFilter.java index bcbf212dc661..10d8d0e9ccde 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/filters/types/BuiltInTypeFilter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/filters/types/BuiltInTypeFilter.java @@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.filters.ElementFilter; import org.jetbrains.annotations.NonNls; import org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionUtil; +import org.jetbrains.plugins.groovy.lang.completion.filters.exprs.InstanceOfFilter; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; @@ -37,8 +38,13 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; */ public class BuiltInTypeFilter implements ElementFilter { public boolean isAcceptable(Object element, PsiElement context) { + if (InstanceOfFilter.isInfixOperatorPosition(context)) { + return false; + } + final PsiElement parent = context.getParent(); if (parent == null) return false; + PsiElement previous = PsiImplUtil.realPrevious(parent.getPrevSibling()); if (previous != null && GroovyTokenTypes.mAT.equals(previous.getNode().getElementType())) { return false; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyParser.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyParser.java index fbd75e3854a5..b05e3248fe3c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyParser.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyParser.java @@ -20,6 +20,7 @@ import com.intellij.lang.ASTNode; import com.intellij.lang.PsiBuilder; import com.intellij.lang.PsiParser; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.GroovyBundle; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; @@ -46,6 +47,9 @@ import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.*; */ public class GroovyParser implements PsiParser { + public static final TokenSet RCURLY_ONLY = TokenSet.create(mRCURLY); + public static final TokenSet CASE_SECTION_END = TokenSet.create(kCASE, kDEFAULT, mRCURLY); + public boolean parseDeep() { return false; } @@ -202,29 +206,8 @@ public class GroovyParser implements PsiParser { } public void parseSwitchCaseList(PsiBuilder builder) { - if (!parseStatement(builder, false) && !parseExtendedStatement(builder)) { - builder.error(GroovyBundle.message("wrong.statement")); - return; - } - - while (true) { - while (ParserUtils.getToken(builder, mSEMI)) {} - PsiBuilder.Marker beforeSeparators = builder.mark(); - ParserUtils.getToken(builder, mNLS); - if (builder.eof() || builder.getTokenType() == kCASE || builder.getTokenType() == kDEFAULT || builder.getTokenType() == mRCURLY) { - beforeSeparators.rollbackTo(); - break; - } - beforeSeparators.drop(); - boolean first = true; - if (!parseStatement(builder, false) && !parseExtendedStatement(builder)) { - if (first) { - builder.error("statement expected"); - first = false; - } - assert builder.getTokenType() != mLCURLY && builder.getTokenType() != mRCURLY; - builder.advanceLexer(); - } + if (parseGenericStatement(builder, CASE_SECTION_END)) { + parseCodeBlock(builder, CASE_SECTION_END); } } @@ -281,76 +264,71 @@ public class GroovyParser implements PsiParser { } } - /** - * Rolls marker forward after possible errors - */ - private void cleanAfterError(PsiBuilder builder, boolean rCurlyNeeded) { - int braceLevel = 1; - int i = 0; - PsiBuilder.Marker em = builder.mark(); + public void parseBlockBody(PsiBuilder builder) { + skipSeparators(builder); + parseCodeBlock(builder, RCURLY_ONLY); + ParserUtils.getToken(builder, mNLS); + } + + private void parseCodeBlock(PsiBuilder builder, TokenSet until) { while (true) { - if (builder.eof()) { - break; - } - final IElementType type = builder.getTokenType(); - if (GroovyTokenTypes.mLCURLY == type) { - braceLevel++; - } - else if (GroovyTokenTypes.mRCURLY == type) { - braceLevel--; - if (braceLevel == 0) { - break; - } - } - else if (braceLevel == 1) { - if (!rCurlyNeeded && (GroovyTokenTypes.mNLS.equals(type) || GroovyTokenTypes.mSEMI.equals(type))) { - break; - } - if (isExtendedSeparator(type)) { - break; - } - } - builder.advanceLexer(); - i++; - } - if (i > 0) { - em.error(GroovyBundle.message("separator.or.rcurly.expected")); - } else { - em.drop(); + if (builder.eof() || until.contains(builder.getTokenType())) break; + if (!parseGenericStatement(builder, until)) break; } } - public void parseBlockBody(PsiBuilder builder) { + private boolean parseGenericStatement(PsiBuilder builder, TokenSet until) { + boolean plainStatement = parseStatement(builder, false); - - parseExtendedStatement(builder); - if (GroovyTokenTypes.mSEMI.equals(builder.getTokenType()) || GroovyTokenTypes.mNLS.equals(builder.getTokenType())) { - Separators.parse(builder); - } - while (parseExtendedStatement(builder)) { - Separators.parse(builder); - } - - boolean result = parseStatement(builder, false); - - while (result && - (GroovyTokenTypes.mSEMI.equals(builder.getTokenType()) || - GroovyTokenTypes.mNLS.equals(builder.getTokenType()) || parseExtendedStatement(builder))) { - Separators.parse(builder); - while (parseExtendedStatement(builder)) { - Separators.parse(builder); + if (plainStatement || parseExtendedStatement(builder)) { + if (parseSeparatorsWithoutLastNls(builder, plainStatement, until)) { + return false; } - result = parseStatement(builder, false); - if (!isExtendedSeparator(builder.getTokenType())) { - cleanAfterError(builder, false); + } else { + builder.error(GroovyBundle.message("wrong.statement")); + assert builder.getTokenType() != mLCURLY && builder.getTokenType() != mRCURLY; + builder.advanceLexer(); + } + return true; + } + + private boolean parseSeparatorsWithoutLastNls(PsiBuilder builder, boolean requireSeparator, TokenSet until) { + boolean hasSeparator = false; + while (true) { + while (builder.getTokenType() == mSEMI || isExtendedSeparator(builder.getTokenType())) { + hasSeparator = true; + builder.advanceLexer(); + } + + if (builder.getTokenType() == mNLS) { + PsiBuilder.Marker beforeNls = builder.mark(); + hasSeparator = true; + builder.advanceLexer(); + if (builder.eof() || until.contains(builder.getTokenType())) { + beforeNls.rollbackTo(); + return true; + } + beforeNls.drop(); + } else { + break; } } - cleanAfterError(builder, true); - Separators.parse(builder); - while (parseExtendedStatement(builder)) { - Separators.parse(builder); + if (builder.eof() || until.contains(builder.getTokenType())) { + return true; } + if (requireSeparator && !hasSeparator) { + builder.error(GroovyBundle.message("separator.or.rcurly.expected")); + } + return false; + } + private boolean skipSeparators(PsiBuilder builder) { + boolean hasSeparators = false; + while (builder.getTokenType() == mSEMI || isExtendedSeparator(builder.getTokenType()) || builder.getTokenType() == mNLS) { + hasSeparators = true; + builder.advanceLexer(); + } + return hasSeparators; } public boolean parseStatement(PsiBuilder builder, boolean isBlockStatementNeeded) { @@ -372,7 +350,8 @@ public class GroovyParser implements PsiParser { return parseIfStatement(builder); } if (GroovyTokenTypes.kSWITCH.equals(builder.getTokenType())) { - return SwitchStatement.parseSwitch(builder, this); + SwitchStatement.parseSwitch(builder, this); + return true; } if (GroovyTokenTypes.kTRY.equals(builder.getTokenType())) { return TryCatchStatement.parse(builder, this); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/SwitchStatement.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/SwitchStatement.java index 2a3d90ab5d88..33656a2a85cc 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/SwitchStatement.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/SwitchStatement.java @@ -31,13 +31,13 @@ import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils; */ public class SwitchStatement implements GroovyElementTypes { - public static boolean parseSwitch(PsiBuilder builder, GroovyParser parser) { + public static void parseSwitch(PsiBuilder builder, GroovyParser parser) { PsiBuilder.Marker marker = builder.mark(); ParserUtils.getToken(builder, kSWITCH); if (!ParserUtils.getToken(builder, mLPAREN, GroovyBundle.message("lparen.expected"))) { marker.done(SWITCH_STATEMENT); - return true; + return; } if (!StrictContextExpression.parse(builder, parser)) { builder.error(GroovyBundle.message("expression.expected")); @@ -45,14 +45,9 @@ public class SwitchStatement implements GroovyElementTypes { ParserUtils.getToken(builder, mNLS); if (!ParserUtils.getToken(builder, mRPAREN, GroovyBundle.message("rparen.expected"))) { - while (!builder.eof() && !mNLS.equals(builder.getTokenType()) && !mRPAREN.equals(builder.getTokenType())) { - builder.error(GroovyBundle.message("rparen.expected")); - builder.advanceLexer(); - } - if (!ParserUtils.getToken(builder, mRPAREN)) { - marker.done(SWITCH_STATEMENT); - return true; - } + builder.error(GroovyBundle.message("rparen.expected")); + marker.done(SWITCH_STATEMENT); + return; } PsiBuilder.Marker warn = builder.mark(); ParserUtils.getToken(builder, mNLS); @@ -61,13 +56,11 @@ public class SwitchStatement implements GroovyElementTypes { warn.rollbackTo(); builder.error(GroovyBundle.message("case.block.expected")); marker.done(SWITCH_STATEMENT); - return true; + return; } warn.drop(); parseCaseBlock(builder, parser); marker.done(SWITCH_STATEMENT); - return true; - } private static void parseCaseBlock(PsiBuilder builder, GroovyParser parser) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy index d05e995af7d5..9488cbb385f9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy @@ -169,9 +169,8 @@ public class GroovyCompletionTest extends GroovyCompletionTestBase { doBasicTest(); } - public void testCompletionInParameterListInClosableBlock() throws Throwable { - doBasicTest(); - } + public void testCompletionInParameterListInClosableBlock() throws Throwable { doBasicTest(); } + public void testCompletionInParameterListInClosableBlock3() throws Throwable { doBasicTest(); } public void testCompletionInParameterListInClosableBlock2() throws Throwable { myFixture.testCompletionVariants(getTestName(false) + ".groovy", "aDouble"); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/KeywordCompletionTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/KeywordCompletionTest.java index 26e6a34c8ece..8cd50478b599 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/KeywordCompletionTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/KeywordCompletionTest.java @@ -81,7 +81,6 @@ public class KeywordCompletionTest extends CompletionTestBase { public void testVar6() throws Throwable { doTest(); } public void testVar7() throws Throwable { doTest(); } public void testVar8() throws Throwable { doTest(); } - public void testVar9() throws Throwable { doTest(); } public void testWhile55() throws Throwable { doTest(); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy index 82ee2f8ab5e6..8c86ade6d638 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy @@ -194,6 +194,7 @@ public class ExpressionsParsingTest extends GroovyParsingTestCase { public void testDollar() throws Throwable { doTest(); } public void testNoArrowClosure() throws Throwable { doTest(); } + public void testNoArrowClosure2() throws Throwable { doTest(); } public void testPropertyAccessError() throws Throwable { checkParsing "a[b{}}", """Groovy script diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/GroovyParsingTestCase.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/GroovyParsingTestCase.java index 6adcde0f82f0..08a53d8c699c 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/GroovyParsingTestCase.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/GroovyParsingTestCase.java @@ -36,6 +36,7 @@ public abstract class GroovyParsingTestCase extends LightCodeInsightFixtureTestC protected void checkParsing(String input, String output) { final PsiFile psiFile = TestUtils.createPseudoPhysicalGroovyFile(getProject(), input); String psiTree = DebugUtil.psiToString(psiFile, false); - assertEquals(output.trim(), psiTree.trim()); + String prefix = input.trim() + "\n-----\n"; + assertEquals(prefix + output.trim(), prefix + psiTree.trim()); } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/GroovyReparseTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/GroovyReparseTest.groovy index 94ae3ead3b8f..56d22cdc60de 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/GroovyReparseTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/GroovyReparseTest.groovy @@ -138,5 +138,16 @@ def foo() { """, "\b" } + public void testSwitchRParen() { + checkReparse """ +def foo() { + switch (word w w) { + case 2: + def x = (y) + } + } +""", "\b" + } + } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/StatementsParsingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/StatementsParsingTest.groovy index 587b2ccb3aad..95806baff56a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/StatementsParsingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/StatementsParsingTest.groovy @@ -187,49 +187,10 @@ public class StatementsParsingTest extends GroovyParsingTestCase { public void testVardef$vardeferrsingle4() throws Throwable { doTest(); } public void testWith$with1() throws Throwable { doTest(); } public void testWith$with2() throws Throwable { doTest(); } + public void testAfterAs() throws Throwable { doTest(); } public void testUnnamedField() throws Throwable { doTest(); } - - public void testIfRecovery() throws Throwable { - checkParsing """def test239() { - if (foo() {} - }""", -"""Groovy script - Method - Modifiers - PsiElement(def)('def') - PsiWhiteSpace(' ') - PsiElement(identifier)('test239') - PsiElement(()('(') - Parameter list - - PsiElement())(')') - PsiWhiteSpace(' ') - Throw clause - - Open block - PsiElement({)('{') - PsiWhiteSpace('\\n ') - IF statement - PsiElement(if)('if') - PsiWhiteSpace(' ') - PsiElement(()('(') - Method call - Reference expression - PsiElement(identifier)('foo') - Arguments - PsiElement(()('(') - PsiElement())(')') - PsiWhiteSpace(' ') - Closable block - PsiElement({)('{') - Parameter list - - PsiElement(})('}') - PsiErrorElement:')' expected - - PsiWhiteSpace('\\n ') - PsiElement(})('}')""" - } + public void testIfRecovery() throws Throwable { doTest(); } + public void testSemicolonsOnDifferentLines() throws Throwable { doTest(); } } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/completion/CompletionInParameterListInClosableBlock3.groovy b/plugins/groovy/testdata/groovy/completion/CompletionInParameterListInClosableBlock3.groovy new file mode 100644 index 000000000000..d8324dc89833 --- /dev/null +++ b/plugins/groovy/testdata/groovy/completion/CompletionInParameterListInClosableBlock3.groovy @@ -0,0 +1,5 @@ +def x = { + def a, Doubl + +} + diff --git a/plugins/groovy/testdata/groovy/completion/CompletionInParameterListInClosableBlock3_after.groovy b/plugins/groovy/testdata/groovy/completion/CompletionInParameterListInClosableBlock3_after.groovy new file mode 100644 index 000000000000..1b96acf81555 --- /dev/null +++ b/plugins/groovy/testdata/groovy/completion/CompletionInParameterListInClosableBlock3_after.groovy @@ -0,0 +1,5 @@ +def x = { + def a, Double + +} + diff --git a/plugins/groovy/testdata/groovy/oldCompletion/keyword/var9.test b/plugins/groovy/testdata/groovy/oldCompletion/keyword/var9.test deleted file mode 100644 index 6e1109270ef4..000000000000 --- a/plugins/groovy/testdata/groovy/oldCompletion/keyword/var9.test +++ /dev/null @@ -1,12 +0,0 @@ -package a.b.c - -import org.* - -class A { - def foo() { - switch (k){ - - } - } -} ------ \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/atHang.test b/plugins/groovy/testdata/parsing/groovy/expressions/atHang.test index 95d1403d149f..0a3dd11c251f 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/atHang.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/atHang.test @@ -15,8 +15,12 @@ Groovy script PsiElement({)('{') Parameter list - PsiErrorElement:';', '}' or new line expected - PsiElement(@)('@') - PsiElement(wrong token)('#') + PsiErrorElement:Wrong statement + + PsiElement(@)('@') + PsiErrorElement:Wrong statement + + PsiElement(wrong token)('#') + Literal PsiElement(Integer)('2') PsiElement(})('}') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/noArrowClosure2.test b/plugins/groovy/testdata/parsing/groovy/expressions/noArrowClosure2.test new file mode 100644 index 000000000000..30b316fdaee6 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/noArrowClosure2.test @@ -0,0 +1,42 @@ +{ a, b, c + println a+b+c +} +----- +Groovy script + Closable block + PsiElement({)('{') + PsiWhiteSpace(' ') + Parameter list + + Reference expression + PsiElement(identifier)('a') + PsiErrorElement:';', '}' or new line expected + + PsiElement(,)(',') + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('b') + PsiErrorElement:';', '}' or new line expected + + PsiElement(,)(',') + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('c') + PsiElement(new line)('\n ') + Call expression + Reference expression + PsiElement(identifier)('println') + PsiWhiteSpace(' ') + Command arguments + Additive expression + Additive expression + Reference expression + PsiElement(identifier)('a') + PsiElement(+)('+') + Reference expression + PsiElement(identifier)('b') + PsiElement(+)('+') + Reference expression + PsiElement(identifier)('c') + PsiElement(new line)('\n') + PsiElement(})('}') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/statements/blocks/clos4.test b/plugins/groovy/testdata/parsing/groovy/statements/blocks/clos4.test index 1bb7922e7ee6..cbb25f49acf1 100644 --- a/plugins/groovy/testdata/parsing/groovy/statements/blocks/clos4.test +++ b/plugins/groovy/testdata/parsing/groovy/statements/blocks/clos4.test @@ -28,8 +28,10 @@ Groovy script Command arguments Literal PsiElement(Gstring)('"bugaga"') - PsiWhiteSpace(' ') PsiErrorElement:';', '}' or new line expected + + PsiWhiteSpace(' ') + Literal PsiElement(Integer)('3') PsiElement(})('}') PsiElement(Gstring content)(' ved') diff --git a/plugins/groovy/testdata/parsing/groovy/statements/ifRecovery.test b/plugins/groovy/testdata/parsing/groovy/statements/ifRecovery.test new file mode 100644 index 000000000000..4214ae16976e --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/statements/ifRecovery.test @@ -0,0 +1,40 @@ +def test239() { + if (foo() {} +} +----- +Groovy script + Method + Modifiers + PsiElement(def)('def') + PsiWhiteSpace(' ') + PsiElement(identifier)('test239') + PsiElement(()('(') + Parameter list + + PsiElement())(')') + PsiWhiteSpace(' ') + Throw clause + + Open block + PsiElement({)('{') + PsiWhiteSpace('\n ') + IF statement + PsiElement(if)('if') + PsiWhiteSpace(' ') + PsiElement(()('(') + Method call + Reference expression + PsiElement(identifier)('foo') + Arguments + PsiElement(()('(') + PsiElement())(')') + PsiWhiteSpace(' ') + Closable block + PsiElement({)('{') + Parameter list + + PsiElement(})('}') + PsiErrorElement:')' expected + + PsiWhiteSpace('\n') + PsiElement(})('}') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/statements/semicolonsOnDifferentLines.test b/plugins/groovy/testdata/parsing/groovy/statements/semicolonsOnDifferentLines.test new file mode 100644 index 000000000000..69e04e6d7f28 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/statements/semicolonsOnDifferentLines.test @@ -0,0 +1,31 @@ +def foo() { + ; + ;; + + ; +} +----- +Groovy script + Method + Modifiers + PsiElement(def)('def') + PsiWhiteSpace(' ') + PsiElement(identifier)('foo') + PsiElement(()('(') + Parameter list + + PsiElement())(')') + PsiWhiteSpace(' ') + Throw clause + + Open block + PsiElement({)('{') + PsiWhiteSpace('\n ') + PsiElement(;)(';') + PsiElement(new line)('\n ') + PsiElement(;)(';') + PsiElement(;)(';') + PsiElement(new line)('\n\n ') + PsiElement(;)(';') + PsiElement(new line)('\n') + PsiElement(})('}') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/statements/try_catch/try2.test b/plugins/groovy/testdata/parsing/groovy/statements/try_catch/try2.test index 76baafcfd0cf..f0e3bead0385 100644 --- a/plugins/groovy/testdata/parsing/groovy/statements/try_catch/try2.test +++ b/plugins/groovy/testdata/parsing/groovy/statements/try_catch/try2.test @@ -28,9 +28,13 @@ Groovy script Reference expression PsiElement(identifier)('e1') PsiErrorElement:';', '}' or new line expected - PsiElement())(')') - PsiWhiteSpace(' ') + + PsiElement())(')') + PsiWhiteSpace(' ') + Closable block PsiElement({)('{') + Parameter list + PsiElement(})('}') PsiElement(new line)('\n') PsiErrorElement:'catch' without 'try' @@ -49,9 +53,13 @@ Groovy script Reference expression PsiElement(identifier)('e2') PsiErrorElement:';', '}' or new line expected - PsiElement())(')') - PsiWhiteSpace(' ') + + PsiElement())(')') + PsiWhiteSpace(' ') + Closable block PsiElement({)('{') + Parameter list + PsiElement(})('}') PsiElement(new line)('\n') PsiErrorElement:'finally' without 'try' diff --git a/plugins/groovy/testdata/reparse/OpeningParenthesisAtBlockStart.txt b/plugins/groovy/testdata/reparse/OpeningParenthesisAtBlockStart.txt index 30a797946ccf..68fc4f47f4c6 100644 --- a/plugins/groovy/testdata/reparse/OpeningParenthesisAtBlockStart.txt +++ b/plugins/groovy/testdata/reparse/OpeningParenthesisAtBlockStart.txt @@ -86,16 +86,28 @@ Groovy script PsiWhiteSpace('\n ') PsiElement(identifier)('simplePlugins') PsiErrorElement:';', '}' or new line expected - PsiElement(.)('.') - PsiElement(identifier)('each') + + PsiElement(.)('.') + Method call + Reference expression + PsiElement(identifier)('each') PsiWhiteSpace(' ') - PsiElement({)('{') - PsiWhiteSpace('\n ') - PsiElement(identifier)('layoutPlugin') - PsiWhiteSpace(' ') - PsiElement(identifier)('it') - PsiElement(new line)('\n ') - PsiElement(})('}') + Arguments + + Closable block + PsiElement({)('{') + PsiWhiteSpace('\n ') + Parameter list + + Call expression + Reference expression + PsiElement(identifier)('layoutPlugin') + PsiWhiteSpace(' ') + Command arguments + Reference expression + PsiElement(identifier)('it') + PsiElement(new line)('\n ') + PsiElement(})('}') PsiWhiteSpace('\n\n') PsiElement(})('}') PsiElement(new line)('\n') diff --git a/plugins/groovy/testdata/reparse/SwitchCaseDo.txt b/plugins/groovy/testdata/reparse/SwitchCaseDo.txt index b52961b3724b..acec5bae7b6e 100644 --- a/plugins/groovy/testdata/reparse/SwitchCaseDo.txt +++ b/plugins/groovy/testdata/reparse/SwitchCaseDo.txt @@ -79,6 +79,8 @@ Groovy script PsiElement(new line)('\n ') Reference expression PsiElement(identifier)('do') + PsiErrorElement:';', '}' or new line expected + PsiWhiteSpace(' ') RETURN statement PsiElement(return)('return') diff --git a/plugins/groovy/testdata/reparse/SwitchCaseDot.txt b/plugins/groovy/testdata/reparse/SwitchCaseDot.txt index 585e72ece8ad..aff0d03726d3 100644 --- a/plugins/groovy/testdata/reparse/SwitchCaseDot.txt +++ b/plugins/groovy/testdata/reparse/SwitchCaseDot.txt @@ -112,12 +112,16 @@ Groovy script PsiElement(.)('.') PsiElement(new line)('\n ') PsiElement(case)('case') + PsiErrorElement:';', '}' or new line expected + PsiWhiteSpace(' ') Literal PsiElement(Integer)('3') - PsiErrorElement:statement expected + PsiErrorElement:';', '}' or new line expected PsiElement(:)(':') + PsiErrorElement:Wrong statement + PsiElement(new line)('\n ') RETURN statement PsiElement(return)('return') diff --git a/plugins/groovy/testdata/reparse/SwitchRParen.txt b/plugins/groovy/testdata/reparse/SwitchRParen.txt new file mode 100644 index 000000000000..7401ddea64b2 --- /dev/null +++ b/plugins/groovy/testdata/reparse/SwitchRParen.txt @@ -0,0 +1,139 @@ +Groovy script + PsiElement(new line)('\n') + Method + Modifiers + PsiElement(def)('def') + PsiWhiteSpace(' ') + PsiElement(identifier)('foo') + PsiElement(()('(') + Parameter list + + PsiElement())(')') + PsiWhiteSpace(' ') + Throw clause + + Open block + PsiElement({)('{') + PsiWhiteSpace('\n ') + Switch statement + PsiElement(switch)('switch') + PsiWhiteSpace(' ') + PsiElement(()('(') + Reference expression + PsiElement(identifier)('word') + PsiErrorElement:')' expected + + PsiWhiteSpace(' ') + Call expression + Reference expression + PsiElement(identifier)('w') + PsiWhiteSpace(' ') + Command arguments + Reference expression + PsiElement(identifier)('w') + PsiErrorElement:';', '}' or new line expected + + PsiElement())(')') + PsiWhiteSpace(' ') + Closable block + PsiElement({)('{') + PsiWhiteSpace('\n ') + Parameter list + + PsiErrorElement:'case' outside 'switch' block + Case label + PsiElement(case)('case') + PsiWhiteSpace(' ') + Literal + PsiElement(Integer)('2') + PsiElement(:)(':') + PsiElement(new line)('\n ') + Variable definitions + Modifiers + PsiElement(def)('def') + PsiWhiteSpace(' ') + Variable + PsiElement(identifier)('x') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Parenthesized expression + PsiElement(()('(') + Reference expression + PsiElement(identifier)('y') + PsiElement())(')') + PsiElement(new line)('\n ') + PsiElement(})('}') + PsiElement(new line)('\n ') + PsiElement(})('}') + PsiElement(new line)('\n') +--- +Groovy script + PsiElement(new line)('\n') + Method + Modifiers + PsiElement(def)('def') + PsiWhiteSpace(' ') + PsiElement(identifier)('foo') + PsiElement(()('(') + Parameter list + + PsiElement())(')') + PsiWhiteSpace(' ') + Throw clause + + Open block + PsiElement({)('{') + PsiWhiteSpace('\n ') + Switch statement + PsiElement(switch)('switch') + PsiWhiteSpace(' ') + PsiElement(()('(') + Reference expression + PsiElement(identifier)('word') + PsiErrorElement:')' expected + + PsiWhiteSpace(' ') + Call expression + Reference expression + PsiElement(identifier)('w') + PsiWhiteSpace(' ') + Command arguments + Method call + Reference expression + PsiElement(identifier)('w') + PsiWhiteSpace(' ') + Arguments + + Closable block + PsiElement({)('{') + PsiWhiteSpace('\n ') + Parameter list + + PsiErrorElement:'case' outside 'switch' block + Case label + PsiElement(case)('case') + PsiWhiteSpace(' ') + Literal + PsiElement(Integer)('2') + PsiElement(:)(':') + PsiElement(new line)('\n ') + Variable definitions + Modifiers + PsiElement(def)('def') + PsiWhiteSpace(' ') + Variable + PsiElement(identifier)('x') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Parenthesized expression + PsiElement(()('(') + Reference expression + PsiElement(identifier)('y') + PsiElement())(')') + PsiElement(new line)('\n ') + PsiElement(})('}') + PsiWhiteSpace('\n ') + PsiElement(})('}') + PsiElement(new line)('\n') \ No newline at end of file