From 81aef76919275226f6fdc15d727cdce5ef57cfd1 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Sat, 4 Aug 2018 18:18:19 +0200 Subject: [PATCH] SSR: fix replacing of unmatched catch blocks --- .../structuralsearch/JavaReplaceHandler.java | 38 ++++++++++++++----- .../StructuralReplaceTest.java | 31 +++++++++++++++ 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java index 427200d01625..06ea1f6ad398 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java @@ -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()) { diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java index c8a6e4efd968..fdda70fec75a 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java @@ -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() {