Greedy unclosed code blocks

This commit is contained in:
Roman Shevchenko
2010-08-12 12:42:34 +04:00
parent 39545b68a5
commit ad3b391f9c
4 changed files with 21 additions and 4 deletions
@@ -17,6 +17,7 @@ package com.intellij.lang.java.parser;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.WhitespacesAndCommentsProcessor;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.impl.source.tree.JavaElementType;
@@ -42,6 +43,12 @@ public class StatementParser {
private static final TokenSet TRY_CLOSERS_SET = TokenSet.create(JavaTokenType.CATCH_KEYWORD, JavaTokenType.FINALLY_KEYWORD);
private static final WhitespacesAndCommentsProcessor GREEDY_CODE_BLOCK_PROCESSOR = new WhitespacesAndCommentsProcessor() {
public int process(final List<IElementType> tokens) {
return tokens.size();
}
};
private StatementParser() { }
@Nullable
@@ -52,10 +59,12 @@ public class StatementParser {
final PsiBuilder.Marker codeBlock = builder.mark();
builder.advanceLexer();
boolean greedyBlock = false;
int braceCount = 1;
while (true) {
final IElementType tokenType = builder.getTokenType();
if (tokenType == null) {
greedyBlock = true;
break;
}
if (tokenType == JavaTokenType.LBRACE) {
@@ -90,6 +99,7 @@ public class StatementParser {
if (last == JavaTokenType.IDENTIFIER &&
(prevLast == JavaTokenType.IDENTIFIER || ElementType.PRIMITIVE_TYPE_BIT_SET.contains(prevLast))) {
position.rollbackTo();
greedyBlock = true;
break;
}
}
@@ -98,6 +108,9 @@ public class StatementParser {
}
codeBlock.collapse(JavaElementType.CODE_BLOCK);
if (greedyBlock) {
codeBlock.setCustomEdgeProcessors(null, GREEDY_CODE_BLOCK_PROCESSOR);
}
return codeBlock;
}
@@ -110,9 +123,12 @@ public class StatementParser {
parseStatements(builder, (parseUntilEof ? BraceMode.TILL_LAST : BraceMode.TILL_FIRST));
expectOrError(builder, JavaTokenType.RBRACE, JavaErrorMessages.message("expected.rbrace"));
final boolean greedyBlock = !expectOrError(builder, JavaTokenType.RBRACE, JavaErrorMessages.message("expected.rbrace"));
codeBlock.done(JavaElementType.CODE_BLOCK);
if (greedyBlock) {
codeBlock.setCustomEdgeProcessors(null, GREEDY_CODE_BLOCK_PROCESSOR);
}
return codeBlock;
}
@@ -3,4 +3,5 @@ PsiJavaFile:BlockIncomplete0.java
PsiJavaToken:LBRACE('{')
PsiErrorElement:'}' expected
<empty list>
PsiWhiteSpace(' ')
PsiWhiteSpace(' ')
PsiComment(C_STYLE_COMMENT)('/*}')
@@ -34,7 +34,7 @@ public class ClassParsingTest extends JavaParsingTestCase {
public void testLongClass() { doTest(false); }
public void testIncompleteAnnotation() { doTest(true); }
public void testExtraOpeningBraceInMethod() { doTestDefaultParser(true); } // todo: fix
public void testExtraOpeningBraceInMethod() { doTest(true); }
public void testExtraClosingBraceInMethod() { doTest(true); }
public void testErrors0() { doTest(true); }
@@ -33,7 +33,7 @@ public class StatementParserTest extends JavaParsingTestCase {
public void testBlockSimple() { doParserTest("{ {} }"); }
public void testBlockEmpty() { doParserTest("{ ; }"); }
public void testAnonymousInSmartCompletion() { doParserTest("{ new Foo(hash\n#) {};\n new Foo(hash\n#, bar) {};\n new Foo(hash\n#x) {}; }"); }
public void testBlockIncomplete0() { doParserTest("{ "); }
public void testBlockIncomplete0() { doParserTest("{ /*}"); }
public void testBlockIncomplete1() { doParserTest("{ { }"); }
public void testBlockIncomplete2() { doParserTest("{ else; catch; finally; }"); }