From fd22f8c50ce31ff7fd4be3c020c9bf901b9c0fa7 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Wed, 30 Aug 2017 15:57:12 +0700 Subject: [PATCH] ExtractSetFromComparisonChainAction: use smart pointers Review ID: IDEA-CR-24175 --- .../ExtractSetFromComparisonChainAction.java | 123 +++++++++++------- 1 file changed, 76 insertions(+), 47 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ExtractSetFromComparisonChainAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ExtractSetFromComparisonChainAction.java index 5a97845bb76b..569a63448d0c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ExtractSetFromComparisonChainAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ExtractSetFromComparisonChainAction.java @@ -95,37 +95,43 @@ public class ExtractSetFromComparisonChainAction extends PsiElementBaseIntention if (comparisons.size() < 2) return; PsiClass containingClass = ClassUtils.getContainingStaticClass(element); if (containingClass == null) return; - List> copies = findCopies(comparisons, containingClass); + ExpressionToConstantReplacementContext context = new ExpressionToConstantReplacementContext(comparisons); + List copies = findCopies(comparisons, containingClass); JavaCodeStyleManager manager = JavaCodeStyleManager.getInstance(project); PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); LinkedHashSet suggestions = getSuggestions(comparisons); class Extractor implements ThrowableRunnable { - PsiElement result; - PsiField field; + SmartPsiElementPointer resultPtr; + SmartPsiElementPointer fieldPtr; @Override public void run() { if (!containingClass.isValid()) return; String name = manager.suggestUniqueVariableName(suggestions.iterator().next(), containingClass, false); - String fieldInitializer = StreamEx.of(comparisons).map(cmp -> cmp.myConstant.getText()).joining(","); - String pattern = ExtractSetFromComparisonChainAction.this.getInitializer(comparisons.get(0).myType, containingClass); - String elementType = comparisons.get(0).myType.getCanonicalText(); - String initializer = MessageFormat.format(pattern, fieldInitializer, elementType); + String fieldInitializer = context.myInitializer; + PsiType elementType = context.myTypePtr.getType(); + if (elementType == null) return; + String pattern = getInitializer(elementType, containingClass); + String initializer = MessageFormat.format(pattern, fieldInitializer, elementType.getCanonicalText()); String modifiers = containingClass.isInterface() ? "" : "private static final "; - String type = CommonClassNames.JAVA_UTIL_SET + (PsiUtil.isLanguageLevel5OrHigher(containingClass) ? "<" + elementType + ">" : ""); - field = factory.createFieldFromText(modifiers + type + " " + name + "=" + initializer + ";", containingClass); + String type = CommonClassNames.JAVA_UTIL_SET + + (PsiUtil.isLanguageLevel5OrHigher(containingClass) ? "<" + elementType.getCanonicalText() + ">" : ""); + PsiField field = factory.createFieldFromText(modifiers + type + " " + name + "=" + initializer + ";", containingClass); field = (PsiField)containingClass.add(field); PsiDiamondTypeUtil.removeRedundantTypeArguments(field); CodeStyleManager.getInstance(project).reformat(manager.shortenClassReferences(field)); - result = replace(comparisons, field); + SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(project); + PsiElement result = context.replace(field); + resultPtr = result == null ? null : smartPointerManager.createSmartPsiElementPointer(result); + fieldPtr = smartPointerManager.createSmartPsiElementPointer(field); } } Extractor extractor = new Extractor(); WriteAction.run(extractor); - PsiField field = extractor.field; - if (field == null || !field.isValid()) return; + PsiElement result = extractor.resultPtr == null ? null : extractor.resultPtr.getElement(); + if (result == null || !result.isValid()) return; if (!copies.isEmpty()) { int answer = ApplicationManager.getApplication().isUnitTestMode() ? Messages.YES : @@ -136,15 +142,18 @@ public class ExtractSetFromComparisonChainAction extends PsiElementBaseIntention Messages.getQuestionIcon()); if (answer == Messages.YES) { WriteAction.run(() -> { - for (List copy : copies) { - replace(copy, field); + PsiField field = extractor.fieldPtr.getElement(); + if (field == null) return; + for (ExpressionToConstantReplacementContext copy : copies) { + copy.replace(field); } }); } } - PsiElement result = extractor.result; - if (result == null || !result.isValid()) return; + PsiField field = extractor.fieldPtr.getElement(); + result = extractor.resultPtr.getElement(); + if (result == null || field == null) return; PsiReferenceExpression fieldRef = tryCast(ReferencesSearch.search(field, new LocalSearchScope(result)).findFirst(), PsiReferenceExpression.class); if (fieldRef == null) return; @@ -155,37 +164,10 @@ public class ExtractSetFromComparisonChainAction extends PsiElementBaseIntention new MemberInplaceRenamer(field, field, editor).performInplaceRefactoring(suggestions); } - private static PsiElement replace(List comparisons, PsiField field) { - if (comparisons.isEmpty()) return null; - Project project = field.getProject(); - PsiClass containingClass = field.getContainingClass(); - if (containingClass == null) return null; - String name = field.getName(); - if (name == null) return null; - PsiExpression stringExpression = comparisons.get(0).myExpression; - PsiExpression firstComparison = comparisons.get(0).myComparison; - PsiExpression lastComparison = comparisons.get(comparisons.size() - 1).myComparison; - PsiExpression disjunction = tryCast(firstComparison.getParent(), PsiPolyadicExpression.class); - if (disjunction == null) return null; - int startOffset = firstComparison.getStartOffsetInParent(); - int endOffset = lastComparison.getStartOffsetInParent() + lastComparison.getTextLength(); - String origText = disjunction.getText(); - String fieldReference = PsiResolveHelper.SERVICE.getInstance(project).resolveReferencedVariable(name, disjunction) == field ? - name : containingClass.getQualifiedName() + "." + name; - String replacementText = origText.substring(0, startOffset) + - fieldReference + ".contains(" + stringExpression.getText() + ")" + - origText.substring(endOffset); - PsiExpression replacement = JavaPsiFacade.getElementFactory(project).createExpressionFromText(replacementText, disjunction); - if (replacement instanceof PsiMethodCallExpression && disjunction.getParent() instanceof PsiParenthesizedExpression) { - disjunction = (PsiExpression)disjunction.getParent(); - } - return disjunction.replace(replacement); - } - - private static List> findCopies(@NotNull List comparisons, - @NotNull PsiClass aClass) { + private static List findCopies(@NotNull List comparisons, + @NotNull PsiClass aClass) { Set orig = StreamEx.of(comparisons).map(c -> c.myConstantRepresentation).toSet(); - List> copies = new ArrayList<>(); + List copies = new ArrayList<>(); Set processedOperands = new HashSet<>(); aClass.accept(new JavaRecursiveElementWalkingVisitor() { @Override @@ -200,7 +182,7 @@ public class ExtractSetFromComparisonChainAction extends PsiElementBaseIntention otherComparisons.get(0).myExpression != comparisons.get(0).myExpression && otherComparisons.get(0).myType.equals(comparisons.get(0).myType) && StreamEx.of(otherComparisons).map(c -> c.myConstantRepresentation).toSet().equals(orig)) { - copies.add(otherComparisons); + copies.add(new ExpressionToConstantReplacementContext(otherComparisons)); } } } @@ -292,6 +274,53 @@ public class ExtractSetFromComparisonChainAction extends PsiElementBaseIntention return StreamEx.ofReversed(prefix).append(anchorComparison).append(suffix); } + static final class ExpressionToConstantReplacementContext { + final SmartPsiElementPointer myExpressionPtr; + final SmartPsiElementPointer myFirstComparisonPtr; + final SmartPsiElementPointer myLastComparisonPtr; + final SmartTypePointer myTypePtr; + final String myInitializer; + + ExpressionToConstantReplacementContext(List comparisons) { + assert !comparisons.isEmpty(); + Project project = comparisons.get(0).myComparison.getProject(); + SmartPointerManager manager = SmartPointerManager.getInstance(project); + myExpressionPtr = manager.createSmartPsiElementPointer(comparisons.get(0).myExpression); + myFirstComparisonPtr = manager.createSmartPsiElementPointer(comparisons.get(0).myComparison); + myLastComparisonPtr = manager.createSmartPsiElementPointer(comparisons.get(comparisons.size() - 1).myComparison); + myTypePtr = SmartTypePointerManager.getInstance(project).createSmartTypePointer(comparisons.get(0).myType); + myInitializer = StreamEx.of(comparisons).map(cmp -> cmp.myConstant.getText()).joining(","); + } + + @Nullable + private PsiElement replace(@NotNull PsiField field) { + Project project = field.getProject(); + PsiClass containingClass = field.getContainingClass(); + if (containingClass == null) return null; + String name = field.getName(); + if (name == null) return null; + PsiExpression expression = myExpressionPtr.getElement(); + PsiExpression firstComparison = myFirstComparisonPtr.getElement(); + PsiExpression lastComparison = myLastComparisonPtr.getElement(); + if (expression == null || firstComparison == null || lastComparison == null) return null; + PsiExpression disjunction = tryCast(firstComparison.getParent(), PsiPolyadicExpression.class); + if (disjunction == null) return null; + int startOffset = firstComparison.getStartOffsetInParent(); + int endOffset = lastComparison.getStartOffsetInParent() + lastComparison.getTextLength(); + String origText = disjunction.getText(); + String fieldReference = PsiResolveHelper.SERVICE.getInstance(project).resolveReferencedVariable(name, disjunction) == field ? + name : containingClass.getQualifiedName() + "." + name; + String replacementText = origText.substring(0, startOffset) + + fieldReference + ".contains(" + expression.getText() + ")" + + origText.substring(endOffset); + PsiExpression replacement = JavaPsiFacade.getElementFactory(project).createExpressionFromText(replacementText, disjunction); + if (replacement instanceof PsiMethodCallExpression && disjunction.getParent() instanceof PsiParenthesizedExpression) { + disjunction = (PsiExpression)disjunction.getParent(); + } + return disjunction.replace(replacement); + } + } + static final class ExpressionToConstantComparison { @NotNull final PsiExpression myComparison; @NotNull final PsiExpression myExpression;