diff --git a/java/java-tests/testSrc/com/intellij/java/psi/JavaStubsTest.groovy b/java/java-tests/testSrc/com/intellij/java/psi/JavaStubsTest.groovy index 2712ef24c24a..3b0e4a1a9dcd 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/JavaStubsTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/psi/JavaStubsTest.groovy @@ -347,6 +347,15 @@ class A { PsiTestUtil.checkStubsMatchText(file) } + void "test remove type argument list after space"() { + def file = myFixture.addFileToProject('a.java', 'class A { A a; }') + WriteCommandAction.runWriteCommandAction(project) { + myFixture.findClass("A").fields[0].typeElement.innermostComponentReferenceElement.parameterList.delete() + } + PsiTestUtil.checkStubsMatchText(file) + PsiTestUtil.checkFileStructure(file) + } + void "test add reference into broken extends list"() { def file = myFixture.addFileToProject('a.java', 'class A extends.ends Foo { int a; }') WriteCommandAction.runWriteCommandAction(project) { diff --git a/platform/core-impl/src/com/intellij/pom/tree/events/impl/ChangeInfoImpl.java b/platform/core-impl/src/com/intellij/pom/tree/events/impl/ChangeInfoImpl.java index 8141291a0382..3c7ff916d57b 100644 --- a/platform/core-impl/src/com/intellij/pom/tree/events/impl/ChangeInfoImpl.java +++ b/platform/core-impl/src/com/intellij/pom/tree/events/impl/ChangeInfoImpl.java @@ -40,10 +40,16 @@ public class ChangeInfoImpl implements ChangeInfo { myNewLength = newChild != null ? newChild.getNotCachedLength() : 0; } + @Nullable public TreeElement getOldChild() { return myOldChild; } + @Nullable + public TreeElement getNewChild() { + return myNewChild; + } + @Override public int getChangeType(){ if (myOldChild == myNewChild) return CONTENTS_CHANGED; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java b/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java index f7d8467e8d02..847d1a929b6a 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java @@ -24,6 +24,7 @@ import com.intellij.pom.tree.TreeAspect; import com.intellij.pom.tree.events.ChangeInfo; import com.intellij.pom.tree.events.TreeChange; import com.intellij.pom.tree.events.TreeChangeEvent; +import com.intellij.pom.tree.events.impl.ChangeInfoImpl; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleSettings; @@ -164,7 +165,9 @@ public class PostprocessReformattingAspect implements PomModelAspect { for (final ASTNode node : changeSet.getChangedElements()) { final TreeChange treeChange = changeSet.getChangesByElement(node); for (final ASTNode affectedChild : treeChange.getAffectedChildren()) { - scheduleReparseIfNeeded(containingFile, affectedChild); + if (changeMightBreakPsiTextConsistency(treeChange, affectedChild)) { + containingFile.putUserData(REPARSE_PENDING, true); + } final ChangeInfo childChange = treeChange.getChangeByChild(affectedChild); switch (childChange.getChangeType()) { @@ -191,14 +194,22 @@ public class PostprocessReformattingAspect implements PomModelAspect { } } - private void scheduleReparseIfNeeded(PsiFile containingFile, ASTNode affectedChild) { - if (changeMightBreakPsiTextConsistency(affectedChild)) { - containingFile.putUserData(REPARSE_PENDING, true); - } + private boolean changeMightBreakPsiTextConsistency(TreeChange treeChange, ASTNode child) { + return TreeUtil.containsOuterLanguageElements(child) || + isRightAfterErrorElement(child) || + isBetweenWhitespaceAndEdge(child) && leavesEmptyRange(treeChange, child); } - private boolean changeMightBreakPsiTextConsistency(ASTNode node) { - return TreeUtil.containsOuterLanguageElements(node) || isRightAfterErrorElement(node); + private boolean leavesEmptyRange(TreeChange treeChange, ASTNode child) { + TreeElement newChild = ((ChangeInfoImpl)treeChange.getChangeByChild(child)).getNewChild(); + return newChild == null || newChild.getTextLength() == 0; + } + + private boolean isBetweenWhitespaceAndEdge(ASTNode deleted) { + ASTNode prev = deleted.getTreePrev(); + ASTNode next = deleted.getTreeNext(); + return next == null && prev instanceof PsiWhiteSpace || + prev == null && next instanceof PsiWhiteSpace; } private boolean isRightAfterErrorElement(ASTNode _node) {