fix stub-ast mismatch caused by broken import list

plus add a test for mismatch in IDEA-169118
This commit is contained in:
peter
2017-06-16 09:23:31 +02:00
parent 911d516e7b
commit 3add884872
4 changed files with 76 additions and 27 deletions
@@ -147,37 +147,41 @@ public class FileParser {
private Pair<PsiBuilder.Marker, Boolean> parseImportList(PsiBuilder builder, Predicate<PsiBuilder> stopper) {
PsiBuilder.Marker list = builder.mark();
IElementType tokenType = builder.getTokenType();
boolean isEmpty = tokenType != JavaTokenType.IMPORT_KEYWORD && tokenType != JavaTokenType.SEMICOLON;
if (!isEmpty) {
PsiBuilder.Marker invalidElements = null;
while (!builder.eof()) {
if (stopper.test(builder)) {
break;
}
else if (builder.getTokenType() == JavaTokenType.SEMICOLON) {
builder.advanceLexer();
continue;
}
final PsiBuilder.Marker statement = parseImportStatement(builder);
if (statement != null) {
if (invalidElements != null) {
invalidElements.errorBefore(JavaErrorMessages.message("unexpected.token"), statement);
invalidElements = null;
}
continue;
}
if (invalidElements == null) {
invalidElements = builder.mark();
}
boolean isEmpty = true;
PsiBuilder.Marker invalidElements = null;
while (!builder.eof()) {
if (stopper.test(builder)) {
break;
}
else if (builder.getTokenType() == JavaTokenType.SEMICOLON) {
builder.advanceLexer();
continue;
}
if (invalidElements != null) {
invalidElements.error(JavaErrorMessages.message("unexpected.token"));
final PsiBuilder.Marker statement = parseImportStatement(builder);
if (statement != null) {
isEmpty = false;
if (invalidElements != null) {
invalidElements.errorBefore(JavaErrorMessages.message("unexpected.token"), statement);
invalidElements = null;
}
continue;
}
if (invalidElements == null) {
invalidElements = builder.mark();
}
builder.advanceLexer();
}
if (invalidElements != null) {
invalidElements.error(JavaErrorMessages.message("unexpected.token"));
}
if (isEmpty) {
PsiBuilder.Marker precede = list.precede();
list.rollbackTo();
list = precede;
}
done(list, JavaElementType.IMPORT_LIST);
@@ -0,0 +1,13 @@
PsiJavaFile:ImportBrokenFromBeginning.java
PsiImportList
PsiErrorElement:Unexpected token
PsiIdentifier:xx('xx')
PsiWhiteSpace(' ')
PsiImportStatement
PsiKeyword:import('import')
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:a
PsiIdentifier:a('a')
PsiReferenceParameterList
<empty list>
PsiJavaToken:SEMICOLON(';')
@@ -38,6 +38,7 @@ public class FileParserTest extends JavaParsingTestCase {
public void testUnclosedImport1() { doParserTest("import java.awt.*"); }
public void testUnclosedImport2() { doParserTest("import java.awt."); }
public void testUnclosedImport3() { doParserTest("import static a"); }
public void testImportBrokenFromBeginning() { doParserTest("xx import a;"); }
public void testExtraSemicolons() {
doParserTest(
@@ -19,15 +19,21 @@ import com.intellij.codeInsight.AnnotationTargetUtil
import com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ReadAction
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.psi.PsiAnnotationMethod
import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiReferenceExpression
import com.intellij.psi.SyntaxTraverser
import com.intellij.psi.impl.source.PsiClassImpl
import com.intellij.psi.impl.source.PsiFileImpl
import com.intellij.psi.impl.source.tree.TreeUtil
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.searches.AnnotatedElementsSearch
import com.intellij.psi.search.searches.ClassInheritorsSearch
import com.intellij.psi.util.PsiUtil
import com.intellij.testFramework.PsiTestUtil
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import java.util.concurrent.Callable
@@ -173,4 +179,29 @@ import java.lang.annotation.*;
assert !((PsiFileImpl) cls.containingFile).contentsLoaded
}
void "test breaking and adding import does not cause stub AST mismatch"() {
def file = myFixture.addFileToProject("a.java", "import foo.*; import bar.*; class Foo {}") as PsiJavaFile
def another = myFixture.addClass("package zoo; public class Another {}")
WriteCommandAction.runWriteCommandAction(project) {
file.viewProvider.document.insertString(file.text.indexOf('import'), 'x')
PsiDocumentManager.getInstance(project).commitAllDocuments()
file.importClass(another)
}
PsiTestUtil.checkStubsMatchText(file)
}
void "test adding type before method call does not cause stub AST mismatch"() {
def file = myFixture.addFileToProject("a.java", """
class Foo {
void foo() {
something();
call();
}
}
""") as PsiJavaFile
WriteCommandAction.runWriteCommandAction(project) {
file.viewProvider.document.insertString(file.text.indexOf('call'), 'char ')
PsiTestUtil.checkStubsMatchText(file)
}
}
}