SSR: fix replacing of unmatched catch blocks

This commit is contained in:
Bas Leijdekkers
2018-08-04 18:21:17 +02:00
parent 43db7f8204
commit 81aef76919
2 changed files with 60 additions and 9 deletions
@@ -4,6 +4,7 @@ package com.intellij.structuralsearch;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.util.PsiTreeUtil;
@@ -393,11 +394,28 @@ public class JavaReplaceHandler extends StructuralReplaceHandler {
if (unmatchedElements != null) {
final PsiElement firstElement = unmatchedElements.get(0);
if (firstElement instanceof PsiResourceList) addElementAfterAnchor(tryStatement, firstElement, tryStatement.getFirstChild());
final PsiCatchSection[] catches = tryStatement.getCatchSections();
final PsiElement anchor = catches.length == 0 ? tryStatement.getTryBlock() : catches[catches.length - 1];
for (int i = unmatchedElements.size() - 1; i >= 0; i--) {
outer: for (int i = 0, max = unmatchedElements.size(); i < max; i++) {
final PsiElement element = unmatchedElements.get(i);
if ((element instanceof PsiCatchSection)) addElementAfterAnchor(tryStatement, element, anchor);
if (element instanceof PsiCatchSection) {
final PsiCatchSection[] catches = tryStatement.getCatchSections();
final PsiCatchSection catchSection = (PsiCatchSection)element;
if (catches.length == 0) {
addElementAfterAnchor(tryStatement, element, tryStatement.getTryBlock());
}
else {
final PsiType newType = catchSection.getCatchType();
for (PsiCatchSection existingCatch : catches) {
final PsiType existingType = existingCatch.getCatchType();
if (existingType != null && newType != null) {
if (existingType.isAssignableFrom(newType)) {
addElementBeforeAnchor(tryStatement, element, existingCatch);
continue outer;
}
}
}
addElementAfterAnchor(tryStatement, element, catches[catches.length - 1]);
}
}
}
final PsiElement lastElement = unmatchedElements.get(unmatchedElements.size() - 1);
if (lastElement instanceof PsiCodeBlock) {
@@ -413,11 +431,7 @@ public class JavaReplaceHandler extends StructuralReplaceHandler {
try {
final PsiElement inserted = elementParent.addBefore(replacement, elementToReplace);
if (replacement instanceof PsiComment &&
(elementParent instanceof PsiIfStatement ||
elementParent instanceof PsiLoopStatement
)
) {
if (replacement instanceof PsiComment && (elementParent instanceof PsiIfStatement || elementParent instanceof PsiLoopStatement)) {
elementParent.addAfter(createSemicolon(replacement), inserted);
}
}
@@ -545,6 +559,12 @@ public class JavaReplaceHandler extends StructuralReplaceHandler {
if (sibling instanceof PsiWhiteSpace) parentElement.addAfter(sibling, anchor); // recycle whitespace
}
private static void addElementBeforeAnchor(PsiElement parentElement, PsiElement element, PsiElement anchor) {
final PsiElement sibling = element.getPrevSibling().copy();
parentElement.addBefore(element, anchor);
if (sibling instanceof PsiWhiteSpace) parentElement.addBefore(sibling, anchor);
}
@Override
public void postProcess(PsiElement affectedElement, ReplaceOptions options) {
if (!affectedElement.isValid()) {
@@ -1837,6 +1837,37 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase {
assertEquals("Replacing try/finally should also keep unmatched resource lists and finally blocks",
expected2,
replace(in2, what2, by2));
final String in3 = "class Foo {\n" +
" {\n" +
" try {\n" +
" } catch (NullPointerException e) {\n" +
" } catch (IllegalArgumentException e) {\n" +
" } catch (Exception ignored) {\n" +
" }\n" +
" }\n" +
"}";
final String what3 = "try {\n" +
"} catch(Exception ignored) {\n" +
"}";
final String by3 = "try {\n" +
" // 1\n" +
"} catch(Exception ignored) {\n" +
" //2\n" +
"}";
assertEquals("don't break the order of catch blocks",
"class Foo {\n" +
" {\n" +
" try {\n" +
" // 1\n" +
"} catch (NullPointerException e) {\n" +
" } catch (IllegalArgumentException e) {\n" +
" } catch(Exception ignored) {\n" +
" //2\n" +
"}\n" +
" }\n" +
"}",
replace(in3, what3, by3));
}
public void testReplaceExtraSemicolon() {