From cd1bfec129a83edd267e474bd5725f49ce0a21bc Mon Sep 17 00:00:00 2001 From: Artemiy Sartakov Date: Thu, 18 Apr 2019 12:41:46 +0700 Subject: [PATCH] ReplaceWithMutableCollectionIntention: added intention to convert immutable collections to mutable ones (IDEA-196755) --- .../src/META-INF/IntentionPowerPack.xml | 5 + .../siyeh/IntentionPowerPackBundle.properties | 1 + .../ImmutableCollectionModelUtils.java | 276 ++++++++++++++++++ ...ReplaceWithMutableCollectionIntention.java | 50 ++++ .../after.java.template | 13 + .../before.java.template | 11 + .../description.html | 5 + .../to_mutable_collection/Assigned.java | 13 + .../to_mutable_collection/Assigned_after.java | 16 + .../to_mutable_collection/Empty.java | 12 + .../to_mutable_collection/Empty_after.java | 13 + .../to_mutable_collection/LambdaExpr.java | 8 + .../LambdaExpr_after.java | 12 + .../to_mutable_collection/ListOf.java | 12 + .../to_mutable_collection/ListOf_after.java | 16 + .../to_mutable_collection/MapOf.java | 12 + .../to_mutable_collection/MapOf_after.java | 17 ++ .../to_mutable_collection/SingletonList.java | 11 + .../SingletonList_after.java | 13 + .../to_mutable_collection/SingletonMap.java | 11 + .../SingletonMap_after.java | 13 + ...aceWithMutableCollectionIntentionTest.java | 57 ++++ 22 files changed, 597 insertions(+) create mode 100644 plugins/IntentionPowerPak/src/com/siyeh/ipp/collections/ImmutableCollectionModelUtils.java create mode 100644 plugins/IntentionPowerPak/src/com/siyeh/ipp/collections/ReplaceWithMutableCollectionIntention.java create mode 100644 plugins/IntentionPowerPak/src/intentionDescriptions/ReplaceWithMutableCollectionIntention/after.java.template create mode 100644 plugins/IntentionPowerPak/src/intentionDescriptions/ReplaceWithMutableCollectionIntention/before.java.template create mode 100644 plugins/IntentionPowerPak/src/intentionDescriptions/ReplaceWithMutableCollectionIntention/description.html create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Assigned.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Assigned_after.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Empty.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Empty_after.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/LambdaExpr.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/LambdaExpr_after.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/ListOf.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/ListOf_after.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/MapOf.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/MapOf_after.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonList.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonList_after.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonMap.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonMap_after.java create mode 100644 plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/collections/ReplaceWithMutableCollectionIntentionTest.java diff --git a/plugins/IntentionPowerPak/src/META-INF/IntentionPowerPack.xml b/plugins/IntentionPowerPak/src/META-INF/IntentionPowerPack.xml index 24f894ea84b2..cfe9aa8cb068 100644 --- a/plugins/IntentionPowerPak/src/META-INF/IntentionPowerPack.xml +++ b/plugins/IntentionPowerPak/src/META-INF/IntentionPowerPack.xml @@ -434,5 +434,10 @@ com.siyeh.IntentionPowerPackBundle intention.category.other + + com.siyeh.ipp.collections.ReplaceWithMutableCollectionIntention + com.siyeh.IntentionPowerPackBundle + intention.category.other + diff --git a/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties b/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties index e5dee8da0492..3bb91afa2703 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties +++ b/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties @@ -144,6 +144,7 @@ postfix.prefix.intention.family.name=Flip prefix/postfix expression replace.conditional.with.boolean.expression.intention.family.name=Replace conditional expression with boolean expression replace.conditional.with.boolean.expression.intention.name=Replace '?:' with boolean expression replace.with.arrays.as.list.intention.family.name=Replace with 'Arrays.asList()' +replace.with.mutable.collection.intention.family.name=Replace with mutable collection #hand made flip.smth.intention.name=Flip ''{0}'' diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/collections/ImmutableCollectionModelUtils.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/collections/ImmutableCollectionModelUtils.java new file mode 100644 index 000000000000..4892b32f797d --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/collections/ImmutableCollectionModelUtils.java @@ -0,0 +1,276 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.siyeh.ipp.collections; + +import com.intellij.codeInsight.BlockUtils; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.SuggestedNameInfo; +import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; +import com.intellij.refactoring.util.RefactoringUtil; +import com.intellij.util.ObjectUtils; +import com.siyeh.ig.PsiReplacementUtil; +import com.siyeh.ig.callMatcher.CallMatcher; +import com.siyeh.ig.psiutils.CommentTracker; +import com.siyeh.ig.psiutils.ControlFlowUtils; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +import static com.siyeh.ipp.collections.ImmutableCollectionModelUtils.ImmutableCollectionModel.CollectionType; + +class ImmutableCollectionModelUtils { + + private static final Map INITIALIZERS = new EnumMap<>(CollectionType.class); + + static { + INITIALIZERS.put(CollectionType.SET, "new " + CommonClassNames.JAVA_UTIL_HASH_SET + "<>()"); + INITIALIZERS.put(CollectionType.MAP, "new " + CommonClassNames.JAVA_UTIL_HASH_MAP + "<>()"); + INITIALIZERS.put(CollectionType.LIST, "new " + CommonClassNames.JAVA_UTIL_ARRAY_LIST + "<>()"); + } + + @Nullable + static ImmutableCollectionModel createModel(@NotNull PsiMethodCallExpression call) { + CollectionType type = CollectionType.create(call); + if (type == null) return null; + PsiExpression[] args = call.getArgumentList().getExpressions(); + if (type == CollectionType.MAP && args.length % 2 != 0) return null; + PsiVariable assignedVariable = getAssignedVariable(call); + return new ImmutableCollectionModel(call, type, args, assignedVariable); + } + + static void replaceWithMutable(@NotNull ImmutableCollectionModel model, @Nullable Editor editor) { + PsiMethodCallExpression call = model.getCall(); + Project project = call.getProject(); + PsiElementFactory factory = PsiElementFactory.getInstance(project); + String initializerText = INITIALIZERS.get(model.getType()); + if (initializerText == null) return; + + PsiVariable assignedVariable = model.getAssignedVariable(); + if (assignedVariable != null) { + String name = assignedVariable.getName(); + if (name == null) return; + PsiElement initializer = PsiReplacementUtil.replaceExpressionAndShorten(call, initializerText, new CommentTracker()); + PsiStatement statement = getOuterStatement(initializer); + if (statement == null) return; + PsiElement anchor = addUpdates(name, model, statement, factory); + if (editor != null) editor.getCaretModel().moveToOffset(anchor.getTextRange().getEndOffset()); + } + else { + JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); + PsiType type = call.getType(); + if (type == null) return; + String[] nameSuggestions = getNameSuggestions(call, type, codeStyleManager); + if (nameSuggestions.length == 0) return; + String name = nameSuggestions[0]; + PsiElement anchor = new CommentTracker().replaceAndRestoreComments(call, name); + PsiStatement statement = getOuterStatement(anchor); + if (statement == null) return; + PsiDeclarationStatement declaration = addDeclaration(name, initializerText, type, statement, factory, codeStyleManager); + if (declaration == null) return; + if (anchor.getParent() instanceof PsiExpressionStatement) new CommentTracker().deleteAndRestoreComments(anchor); + anchor = addUpdates(name, model, declaration, factory); + if (editor != null) { + PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); + PsiVariable variable = PsiTreeUtil.getChildOfType(declaration, PsiVariable.class); + if (variable == null) return; + new VariableRenamer(variable, editor, anchor).performInplaceRefactoring(new LinkedHashSet<>(Arrays.asList(nameSuggestions))); + } + } + } + + @Nullable + private static PsiStatement getOuterStatement(PsiElement element) { + PsiElement parent = PsiTreeUtil.getParentOfType(element, PsiStatement.class, PsiLambdaExpression.class); + if (!(parent instanceof PsiLambdaExpression)) return (PsiStatement)parent; + PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)parent; + PsiCodeBlock codeBlock = RefactoringUtil.expandExpressionLambdaToCodeBlock(lambdaExpression); + return ControlFlowUtils.getFirstStatementInBlock(codeBlock); + } + + @Nullable + private static PsiVariable getAssignedVariable(@NotNull PsiMethodCallExpression call) { + PsiElement parent = PsiTreeUtil.getParentOfType(call, PsiVariable.class, PsiAssignmentExpression.class); + if (parent == null) return null; + if (parent instanceof PsiVariable) { + PsiExpression initializer = PsiUtil.skipParenthesizedExprDown(((PsiVariable)parent).getInitializer()); + return initializer == call ? (PsiVariable)parent : null; + } + PsiAssignmentExpression assignment = (PsiAssignmentExpression)parent; + PsiExpression rhs = PsiUtil.skipParenthesizedExprDown(assignment.getRExpression()); + if (rhs != call) return null; + PsiExpression lhs = PsiUtil.skipParenthesizedExprDown(assignment.getLExpression()); + PsiReferenceExpression ref = ObjectUtils.tryCast(lhs, PsiReferenceExpression.class); + if (ref == null) return null; + return ObjectUtils.tryCast(ref.resolve(), PsiVariable.class); + } + + @NotNull + private static PsiElement addUpdates(@NotNull String name, + @NotNull ImmutableCollectionModel model, + @NotNull PsiStatement anchor, + @NotNull PsiElementFactory factory) { + PsiExpression[] args = model.getArgs(); + for (int i = 0; i < args.length; i++) { + if (model.getType() != CollectionType.MAP) { + anchor = addUpdate(name + ".add(" + args[i].getText() + ");", anchor, factory); + continue; + } + if (i % 2 != 0) { + anchor = addUpdate(name + ".put(" + args[i - 1].getText() + ", " + args[i].getText() + ");", anchor, factory); + } + } + return anchor; + } + + @NotNull + private static PsiStatement addUpdate(@NotNull String updateText, @NotNull PsiStatement anchor, @NotNull PsiElementFactory factory) { + PsiStatement statement = factory.createStatementFromText(updateText, null); + return BlockUtils.addAfter(anchor, statement); + } + + @Nullable + private static PsiDeclarationStatement addDeclaration(@NotNull String name, + @NotNull String initializerText, + @NotNull PsiType type, + @NotNull PsiStatement statement, + @NotNull PsiElementFactory factory, + @NotNull JavaCodeStyleManager codeStyleManager) { + PsiExpression initializer = factory.createExpressionFromText(initializerText, null); + PsiDeclarationStatement declaration = factory.createVariableDeclarationStatement(name, type, initializer); + declaration = ObjectUtils.tryCast(codeStyleManager.shortenClassReferences(declaration), PsiDeclarationStatement.class); + if (declaration == null) return null; + return ObjectUtils.tryCast(BlockUtils.addBefore(statement, declaration), PsiDeclarationStatement.class); + } + + @NotNull + private static String[] getNameSuggestions(@NotNull PsiMethodCallExpression call, + @NotNull PsiType type, + @NotNull JavaCodeStyleManager codeStyleManager) { + String propertyName = getPropertyName(call, type, codeStyleManager); + SuggestedNameInfo nameInfo = codeStyleManager.suggestVariableName(VariableKind.LOCAL_VARIABLE, propertyName, call, type); + return codeStyleManager.suggestUniqueVariableName(nameInfo, call, true).names; + } + + @NotNull + private static String getPropertyName(PsiMethodCallExpression call, PsiType type, JavaCodeStyleManager codeStyleManager) { + String propertyName = getPropertyNameByCall(call); + if (propertyName != null) return propertyName; + return codeStyleManager.suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, type).names[0]; + } + + @Nullable + private static String getPropertyNameByCall(@NotNull PsiMethodCallExpression call) { + PsiMethodCallExpression outerCall = PsiTreeUtil.getParentOfType(call, PsiMethodCallExpression.class); + if (outerCall == null) return null; + PsiMethod method = outerCall.resolveMethod(); + if (method == null) return null; + PsiExpression[] arguments = outerCall.getArgumentList().getExpressions(); + PsiParameter[] parameters = method.getParameterList().getParameters(); + if (parameters.length == 0) return null; + for (int i = 0; i < arguments.length; i++) { + if (arguments[i] == call) { + int idx = i >= parameters.length ? parameters.length - 1 : i; + return parameters[idx].getName(); + } + } + return null; + } + + private static class VariableRenamer extends VariableInplaceRenamer { + + private final PsiElement myAnchor; + + private VariableRenamer(@NotNull PsiNamedElement elementToRename, @NotNull Editor editor, @NotNull PsiElement anchor) { + super(elementToRename, editor); + this.myAnchor = anchor; + editor.getCaretModel().moveToOffset(elementToRename.getTextOffset()); + } + + @Override + public void finish(boolean success) { + super.finish(success); + myEditor.getCaretModel().moveToOffset(myAnchor.getTextRange().getEndOffset()); + } + } + + /** + * Represents immutable collection creation call (e.g. {@link Collections#singleton(Object)}). + */ + static class ImmutableCollectionModel { + + private static final CallMatcher LIST_CALL_MATCHER = CallMatcher.anyOf( + CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "emptyList").parameterCount(0), + CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "singletonList").parameterCount(1), + CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_LIST, "of").withLanguageLevelAtLeast(LanguageLevel.JDK_1_9) + ); + private static final CallMatcher MAP_CALL_MATCHER = CallMatcher.anyOf( + CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "emptyMap").parameterCount(0), + CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "singletonMap").parameterCount(2), + CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_MAP, "of").withLanguageLevelAtLeast(LanguageLevel.JDK_1_9) + ); + private static final CallMatcher SET_CALL_MATCHER = CallMatcher.anyOf( + CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "emptySet").parameterCount(0), + CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "singleton").parameterCount(1), + CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_SET, "of").withLanguageLevelAtLeast(LanguageLevel.JDK_1_9) + ); + + private final PsiMethodCallExpression myCall; + private final CollectionType myType; + private final PsiExpression[] myArgs; + private final PsiVariable myAssignedVariable; + + @Contract(pure = true) + ImmutableCollectionModel(@NotNull PsiMethodCallExpression call, + @NotNull CollectionType type, + @NotNull PsiExpression[] args, + @Nullable PsiVariable assignedVariable) { + myCall = call; + myType = type; + myArgs = args; + myAssignedVariable = assignedVariable; + } + + PsiMethodCallExpression getCall() { + return myCall; + } + + CollectionType getType() { + return myType; + } + + PsiExpression[] getArgs() { + return myArgs; + } + + PsiVariable getAssignedVariable() { + return myAssignedVariable; + } + + enum CollectionType { + + MAP(MAP_CALL_MATCHER), + LIST(LIST_CALL_MATCHER), + SET(SET_CALL_MATCHER); + + private final CallMatcher myMatcher; + + @Contract(pure = true) + CollectionType(@NotNull CallMatcher matcher) { + myMatcher = matcher; + } + + @Nullable + static CollectionType create(@NotNull PsiMethodCallExpression call) { + return Arrays.stream(CollectionType.values()).filter(type -> type.myMatcher.test(call)).findFirst().orElse(null); + } + } + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/collections/ReplaceWithMutableCollectionIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/collections/ReplaceWithMutableCollectionIntention.java new file mode 100644 index 000000000000..af5500bd2bf7 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/collections/ReplaceWithMutableCollectionIntention.java @@ -0,0 +1,50 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.siyeh.ipp.collections; + +import com.intellij.openapi.editor.Editor; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.ObjectUtils; +import com.siyeh.IntentionPowerPackBundle; +import com.siyeh.ipp.base.Intention; +import com.siyeh.ipp.base.PsiElementPredicate; +import com.siyeh.ipp.collections.ImmutableCollectionModelUtils.ImmutableCollectionModel; +import org.jetbrains.annotations.NotNull; + +public class ReplaceWithMutableCollectionIntention extends Intention { + + @Override + protected void processIntention(Editor editor, @NotNull PsiElement element) { + PsiMethodCallExpression call = ObjectUtils.tryCast(element, PsiMethodCallExpression.class); + if (call == null) return; + ImmutableCollectionModel model = ImmutableCollectionModelUtils.createModel(call); + if (model == null) return; + ImmutableCollectionModelUtils.replaceWithMutable(model, editor); + } + + @Override + protected void processIntention(@NotNull PsiElement element) { + processIntention(null, element); + } + + @NotNull + @Override + public String getText() { + return IntentionPowerPackBundle.defaultableMessage("replace.with.mutable.collection.intention.family.name"); + } + + @NotNull + @Override + protected PsiElementPredicate getElementPredicate() { + return new PsiElementPredicate() { + @Override + public boolean satisfiedBy(PsiElement element) { + PsiMethodCallExpression call = ObjectUtils.tryCast(element, PsiMethodCallExpression.class); + PsiElement parent = + PsiTreeUtil.getParentOfType(call, PsiLambdaExpression.class, PsiConditionalExpression.class, PsiStatement.class); + if (parent == null || parent instanceof PsiConditionalExpression) return false; + return ImmutableCollectionModelUtils.createModel(call) != null; + } + }; + } +} diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/ReplaceWithMutableCollectionIntention/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/ReplaceWithMutableCollectionIntention/after.java.template new file mode 100644 index 000000000000..7d83680403ed --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/ReplaceWithMutableCollectionIntention/after.java.template @@ -0,0 +1,13 @@ +import java.util.*; + +public class X { + + void foo() { + List list = new ArrayList<>(); + list.add("foo"); + process(list); + } + + void process(List list) { + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/ReplaceWithMutableCollectionIntention/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/ReplaceWithMutableCollectionIntention/before.java.template new file mode 100644 index 000000000000..8eccc1a921df --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/ReplaceWithMutableCollectionIntention/before.java.template @@ -0,0 +1,11 @@ +import java.util.*; + +public class X { + + void foo() { + process(Collections.singletonList("foo")); + } + + void process(List list) { + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/ReplaceWithMutableCollectionIntention/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/ReplaceWithMutableCollectionIntention/description.html new file mode 100644 index 000000000000..433546f4d067 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/ReplaceWithMutableCollectionIntention/description.html @@ -0,0 +1,5 @@ + + +Replaces creation of an immutable collection with creation of a mutable. + + \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Assigned.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Assigned.java new file mode 100644 index 000000000000..d7326b6720f4 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Assigned.java @@ -0,0 +1,13 @@ +import java.util.*; + +class Test { + + void foo() { + Map map = /*1*/(Collections.singletonMap/*2*/(/*3*/"foo", "bar"))/*4*/; + process(map); + } + + void process(Map model) { + + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Assigned_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Assigned_after.java new file mode 100644 index 000000000000..a7968ec9736a --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Assigned_after.java @@ -0,0 +1,16 @@ +import java.util.*; + +class Test { + + void foo() { + /*2*/ + /*3*/ + Map map = /*1*/(new HashMap<>())/*4*/; + map.put("foo", "bar"); + process(map); + } + + void process(Map model) { + + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Empty.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Empty.java new file mode 100644 index 000000000000..15f4c4c3b69c --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Empty.java @@ -0,0 +1,12 @@ +import java.util.*; + +class Test { + + void foo() { + process(Collections.emptyList()); + } + + void process(List model) { + + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Empty_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Empty_after.java new file mode 100644 index 000000000000..1c5996e727c7 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/Empty_after.java @@ -0,0 +1,13 @@ +import java.util.*; + +class Test { + + void foo() { + List model = new ArrayList<>(); + process(model); + } + + void process(List model) { + + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/LambdaExpr.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/LambdaExpr.java new file mode 100644 index 000000000000..fdb0bc064a2a --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/LambdaExpr.java @@ -0,0 +1,8 @@ +import java.util.*; +import java.util.concurrent.Callable; + +class Test { + void test() { + Callable> c = () -> Collections.singletonMap("foo", "bar"); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/LambdaExpr_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/LambdaExpr_after.java new file mode 100644 index 000000000000..a440fe121479 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/LambdaExpr_after.java @@ -0,0 +1,12 @@ +import java.util.*; +import java.util.concurrent.Callable; + +class Test { + void test() { + Callable> c = () -> { + Map stringStringMap = new HashMap<>(); + stringStringMap.put("foo", "bar"); + return stringStringMap; + }; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/ListOf.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/ListOf.java new file mode 100644 index 000000000000..c0fdcceaf935 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/ListOf.java @@ -0,0 +1,12 @@ +import java.util.*; + +class Test { + + void foo() { + process(List.of("foo", "bar", "baz")); + } + + void process(List model) { + + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/ListOf_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/ListOf_after.java new file mode 100644 index 000000000000..bf840d5ca87e --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/ListOf_after.java @@ -0,0 +1,16 @@ +import java.util.*; + +class Test { + + void foo() { + List model = new ArrayList<>(); + model.add("foo"); + model.add("bar"); + model.add("baz"); + process(model); + } + + void process(List model) { + + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/MapOf.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/MapOf.java new file mode 100644 index 000000000000..a717c5dc03ac --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/MapOf.java @@ -0,0 +1,12 @@ +import java.util.*; + +class Test { + + void foo() { + process(/*1*/Map.of/*2*/("foo"/*3*/, "bar", "goo", "baz")/*4*/); + } + + void process(Map model) { + + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/MapOf_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/MapOf_after.java new file mode 100644 index 000000000000..00931fe6024d --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/MapOf_after.java @@ -0,0 +1,17 @@ +import java.util.*; + +class Test { + + void foo() { + /*2*/ + /*3*/ + Map model = new HashMap<>(); + model.put("foo", "bar"); + model.put("goo", "baz"); + process(/*1*/model/*4*/); + } + + void process(Map model) { + + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonList.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonList.java new file mode 100644 index 000000000000..1a83bad9f58e --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonList.java @@ -0,0 +1,11 @@ +import java.util.*; + +public class Test { + + void foo() { + process(Collections.singletonList("foo")); + } + + void process(List model) { + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonList_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonList_after.java new file mode 100644 index 000000000000..5b40feef247b --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonList_after.java @@ -0,0 +1,13 @@ +import java.util.*; + +public class Test { + + void foo() { + List model = new ArrayList<>(); + model.add("foo"); + process(model); + } + + void process(List model) { + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonMap.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonMap.java new file mode 100644 index 000000000000..cbbb9e74b466 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonMap.java @@ -0,0 +1,11 @@ +import java.util.*; + +class Test { + + void foo() { + process(Collections.singletonMap("bar", "baz")); + } + + void process(Map model) { + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonMap_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonMap_after.java new file mode 100644 index 000000000000..5baa1c4a56b7 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/collections/to_mutable_collection/SingletonMap_after.java @@ -0,0 +1,13 @@ +import java.util.*; + +class Test { + + void foo() { + Map model = new HashMap<>(); + model.put("bar", "baz"); + process(model); + } + + void process(Map model) { + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/collections/ReplaceWithMutableCollectionIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/collections/ReplaceWithMutableCollectionIntentionTest.java new file mode 100644 index 000000000000..c075eabd4dee --- /dev/null +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/collections/ReplaceWithMutableCollectionIntentionTest.java @@ -0,0 +1,57 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.siyeh.ipp.collections; + +import com.intellij.testFramework.LightProjectDescriptor; +import com.siyeh.IntentionPowerPackBundle; +import com.siyeh.ipp.IPPTestCase; +import org.jetbrains.annotations.NotNull; + +/** + * @see ReplaceWithMutableCollectionIntention + */ +public class ReplaceWithMutableCollectionIntentionTest extends IPPTestCase { + + public void testMapOf() { + doTest(); + } + + public void testListOf() { + doTest(); + } + + public void testLambdaExpr() { + doTest(); + } + + public void testSingletonMap() { + doTest(); + } + + public void testSingletonList() { + doTest(); + } + + public void testEmpty() { + doTest(); + } + + public void testAssigned() { + doTest(); + } + + @Override + protected String getIntentionName() { + return IntentionPowerPackBundle.message("replace.with.mutable.collection.intention.family.name"); + } + + @Override + protected String getRelativePath() { + return "collections/to_mutable_collection"; + } + + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return JAVA_9_ANNOTATED; + } +}