mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Java: Intention that wraps list/set/map with Collections.unmodifiableList/Set/Map (IDEA-93154)
This commit is contained in:
@@ -1263,6 +1263,10 @@
|
||||
<className>com.intellij.codeInsight.intention.impl.SplitSwitchBranchWithSeveralCaseValuesAction</className>
|
||||
<category>Java/Control Flow</category>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInsight.intention.impl.WrapWithUnmodifiableAction</className>
|
||||
<category>Java/Other</category>
|
||||
</intentionAction>
|
||||
<externalAnnotationsArtifactsResolver implementation="com.intellij.jarRepository.ExternalAnnotationsRepositoryResolver"/>
|
||||
<errorQuickFixProvider implementation="com.intellij.codeInsight.daemon.impl.analysis.JavaErrorQuickFixProvider"/>
|
||||
<fileTypeDetector implementation="com.intellij.openapi.fileTypes.impl.JavaFileTypeDetector"/>
|
||||
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
// 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.intellij.codeInsight.intention.impl;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.psi.CommonClassNames.*;
|
||||
import static com.intellij.util.ObjectUtils.tryCast;
|
||||
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
public class WrapWithUnmodifiableAction extends PsiElementBaseIntentionAction {
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
|
||||
PsiExpression expression = getParentExpression(element);
|
||||
if (expression != null) {
|
||||
PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(expression.getType());
|
||||
if (InheritanceUtil.isInheritor(psiClass, JAVA_UTIL_LIST)) {
|
||||
wrapWith(expression, "unmodifiableList");
|
||||
}
|
||||
else if (InheritanceUtil.isInheritor(psiClass, "java.util.SortedSet")) {
|
||||
wrapWith(expression, "unmodifiableSortedSet");
|
||||
}
|
||||
else if (InheritanceUtil.isInheritor(psiClass, JAVA_UTIL_SET)) {
|
||||
wrapWith(expression, "unmodifiableSet");
|
||||
}
|
||||
else if (InheritanceUtil.isInheritor(psiClass, "java.util.SortedMap")) {
|
||||
wrapWith(expression, "unmodifiableSortedMap");
|
||||
}
|
||||
else if (InheritanceUtil.isInheritor(psiClass, JAVA_UTIL_MAP)) {
|
||||
wrapWith(expression, "unmodifiableMap");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static PsiExpression getParentExpression(@NotNull PsiElement element) {
|
||||
PsiExpression expression = PsiTreeUtil.getNonStrictParentOfType(element, PsiExpression.class);
|
||||
if (expression != null) {
|
||||
PsiMethodCallExpression methodCall = tryCast(expression.getParent(), PsiMethodCallExpression.class);
|
||||
if (methodCall != null && methodCall.getMethodExpression() == expression) {
|
||||
return methodCall;
|
||||
}
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
private static void wrapWith(PsiExpression expression, String methodName) {
|
||||
CommentTracker tracker = new CommentTracker();
|
||||
String text = JAVA_UTIL_COLLECTIONS + '.' + methodName + '(' + tracker.text(expression) + ')';
|
||||
PsiElement result = tracker.replaceAndRestoreComments(expression, text);
|
||||
JavaCodeStyleManager.getInstance(result.getProject()).shortenClassReferences(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
|
||||
PsiExpression expression = getParentExpression(element);
|
||||
if (expression != null) {
|
||||
if (isUnmodifiable(expression)) {
|
||||
return false;
|
||||
}
|
||||
PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(expression.getType());
|
||||
if (psiClass != null) {
|
||||
if (InheritanceUtil.isInheritor(psiClass, JAVA_UTIL_LIST)) {
|
||||
setText(CodeInsightBundle.message("intention.wrap.with.unmodifiable.list"));
|
||||
return true;
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(psiClass, JAVA_UTIL_SET)) {
|
||||
setText(CodeInsightBundle.message("intention.wrap.with.unmodifiable.set"));
|
||||
return true;
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(psiClass, JAVA_UTIL_MAP)) {
|
||||
setText(CodeInsightBundle.message("intention.wrap.with.unmodifiable.map"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isUnmodifiable(PsiExpression expression) {
|
||||
PsiMethodCallExpression methodCall = tryCast(expression, PsiMethodCallExpression.class);
|
||||
if (isUnmodifiableCall(methodCall)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PsiExpressionList expressionList = tryCast(PsiUtil.skipParenthesizedExprUp(expression.getParent()), PsiExpressionList.class);
|
||||
if (expressionList != null && expressionList.getExpressionCount() == 1) {
|
||||
methodCall = tryCast(expressionList.getParent(), PsiMethodCallExpression.class);
|
||||
if (isUnmodifiableCall(methodCall)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isUnmodifiableCall(@Nullable PsiMethodCallExpression methodCall) {
|
||||
if (methodCall != null) {
|
||||
String name = methodCall.getMethodExpression().getReferenceName();
|
||||
if (name != null && name.startsWith("unmodifiable")) {
|
||||
PsiMethod method = methodCall.resolveMethod();
|
||||
if (method != null && method.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
PsiClass psiClass = method.getContainingClass();
|
||||
if (psiClass != null && JAVA_UTIL_COLLECTIONS.equals(psiClass.getQualifiedName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Nls(capitalization = Nls.Capitalization.Sentence)
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return CodeInsightBundle.message("intention.wrap.with.unmodifiable");
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
List<String> result = new ArrayList<String>();
|
||||
// ...
|
||||
return <spot>Collections.unmodifiableList</spot>(result);
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
List<String> result = new ArrayList<String>();
|
||||
// ...
|
||||
return result;
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention wraps a list, a set, or a map with Collections.unmodifiableList/Set/Map().
|
||||
</body>
|
||||
</html>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Wrap with unmodifiable list" "true"
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
class C {
|
||||
List<String> test() {
|
||||
List<String> result = new ArrayList<>();
|
||||
return Collections.unmodifiableList(result);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Wrap with unmodifiable map" "true"
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
class C {
|
||||
Map<String, Integer> test() {
|
||||
var result = new HashMap<>();
|
||||
return Collections.unmodifiableMap(result);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Wrap with unmodifiable set" "true"
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
class C {
|
||||
Set<String> test() {
|
||||
Set<String> result = new HashSet<>();
|
||||
return Collections.unmodifiableSet(result);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Wrap with unmodifiable map" "true"
|
||||
import java.util.Collections;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
class C {
|
||||
SortedMap<String, Integer> test() {
|
||||
SortedMap<String, Integer> result = new TreeMap<>();
|
||||
return Collections.unmodifiableSortedMap(result);
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Wrap with unmodifiable set" "true"
|
||||
import java.util.*;
|
||||
|
||||
class C {
|
||||
Set<String> test() {
|
||||
SortedSet<String> result = new TreeSet<>();
|
||||
return Collections.unmodifiableSortedSet(result);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Wrap with unmodifiable list" "true"
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
class C {
|
||||
List<String> test() {
|
||||
List<String> result = new ArrayList<>();
|
||||
return <caret>result;
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Wrap with unmodifiable map" "true"
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
class C {
|
||||
Map<String, Integer> test() {
|
||||
var result = new HashMap<>();
|
||||
return <caret>result;
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Wrap with unmodifiable set" "true"
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
class C {
|
||||
Set<String> test() {
|
||||
Set<String> result = new HashSet<>();
|
||||
return <caret>result;
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Wrap with unmodifiable map" "true"
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
class C {
|
||||
SortedMap<String, Integer> test() {
|
||||
SortedMap<String, Integer> result = new TreeMap<>();
|
||||
return <caret>result;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Wrap with unmodifiable set" "true"
|
||||
import java.util.*;
|
||||
|
||||
class C {
|
||||
Set<String> test() {
|
||||
SortedSet<String> result = new TreeSet<>();
|
||||
return <caret>result;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Wrap with unmodifiable list" "false"
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
class C {
|
||||
List<String> test() {
|
||||
List<String> result = new ArrayList<>();
|
||||
return Collections.<caret>unmodifiableList(result);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Wrap with unmodifiable list" "false"
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
class C {
|
||||
List<String> test() {
|
||||
List<String> result = new ArrayList<>();
|
||||
return Collections.unmodifiableList(<caret>result);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Wrap with unmodifiable map" "false"
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
class C {
|
||||
Map<String, Integer> test() {
|
||||
Map<String, Integer> result = new HashMap<>();
|
||||
return Collections.unmodifiab<caret>leMap(result);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Wrap with unmodifiable map" "false"
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
class C {
|
||||
Map<String, Integer> test() {
|
||||
Map<String, Integer> result = new HashMap<>();
|
||||
return Collections.unmodifiableMap((res<caret>ult));
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Wrap with unmodifiable set" "false"
|
||||
import java.util.*;
|
||||
|
||||
class C {
|
||||
Set<String> test() {
|
||||
SortedSet<String> result = new TreeSet<>();
|
||||
return Collections.unmodifiableSor<caret>tedSet(result);
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// 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.intellij.java.codeInsight.intention;
|
||||
|
||||
import com.intellij.codeInsight.daemon.LightIntentionActionTestCase;
|
||||
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
public class WrapWithUnmodifiableTest extends LightIntentionActionTestCase {
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/wrapWithUnmodifiable";
|
||||
}
|
||||
}
|
||||
@@ -260,6 +260,11 @@ intention.create.test.dialog.library.not.found={0} library not found in the modu
|
||||
intention.create.test.dialog.fix.library=Fix
|
||||
intention.create.test.dialog.java=Java
|
||||
|
||||
intention.wrap.with.unmodifiable=Wrap with unmodifiable collection or map
|
||||
intention.wrap.with.unmodifiable.list=Wrap with unmodifiable list
|
||||
intention.wrap.with.unmodifiable.set=Wrap with unmodifiable set
|
||||
intention.wrap.with.unmodifiable.map=Wrap with unmodifiable map
|
||||
|
||||
lightbulb.tooltip=Click or press {0}
|
||||
dialog.intention.settings.intention.list.title=Intention List
|
||||
dialog.intention.settings.description.panel.title=Description
|
||||
|
||||
Reference in New Issue
Block a user