mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-167942 Migrate to simplified collection factories (JEP 269): initial implementation (supported scenarios 2, 3, 4 for sets and similar for lists)
This commit is contained in:
+220
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.java19api;
|
||||
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.codeInspection.ex.BaseLocalInspectionTool;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.siyeh.ig.callMatcher.CallMapper;
|
||||
import com.siyeh.ig.callMatcher.CallMatcher;
|
||||
import com.siyeh.ig.psiutils.ClassUtils;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import com.siyeh.ig.psiutils.MethodCallUtils;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.util.ObjectUtils.tryCast;
|
||||
|
||||
/**
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
public class Java9CollectionFactoryInspection extends BaseLocalInspectionTool {
|
||||
private static final CallMatcher UNMODIFIABLE_SET =
|
||||
CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "unmodifiableSet").parameterCount(1);
|
||||
private static final CallMatcher UNMODIFIABLE_LIST =
|
||||
CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "unmodifiableList").parameterCount(1);
|
||||
private static final CallMatcher ARRAYS_AS_LIST =
|
||||
CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_ARRAYS, "asList");
|
||||
private static final CallMatcher COLLECTION_ADD =
|
||||
CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_COLLECTION, "add").parameterCount(1);
|
||||
private static final CallMatcher STREAM_COLLECT =
|
||||
CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_STREAM_STREAM, "collect").parameterCount(1);
|
||||
private static final CallMatcher STREAM_OF =
|
||||
CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_STREAM_STREAM, "of");
|
||||
private static final CallMatcher COLLECTORS_TO_SET =
|
||||
CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, "toSet").parameterCount(0);
|
||||
private static final CallMatcher COLLECTORS_TO_LIST =
|
||||
CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, "toList").parameterCount(0);
|
||||
|
||||
private static final CallMapper<PrepopulatedCollectionModel> MAPPER = new CallMapper<PrepopulatedCollectionModel>()
|
||||
.register(UNMODIFIABLE_SET, call -> PrepopulatedCollectionModel.fromSet(call.getArgumentList().getExpressions()[0]))
|
||||
.register(UNMODIFIABLE_LIST, call -> PrepopulatedCollectionModel.fromList(call.getArgumentList().getExpressions()[0]));
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||
if (!PsiUtil.isLanguageLevel9OrHigher(holder.getFile())) {
|
||||
return PsiElementVisitor.EMPTY_VISITOR;
|
||||
}
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression call) {
|
||||
PrepopulatedCollectionModel model = MAPPER.mapFirst(call);
|
||||
if(model != null) {
|
||||
PsiElement element = call.getMethodExpression().getReferenceNameElement();
|
||||
if(element != null) {
|
||||
holder.registerProblem(element, "Can be replaced with '"+model.myType+".of' call",
|
||||
new ReplaceWithCollectionFactoryFix(model.myType));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static class PrepopulatedCollectionModel {
|
||||
final List<PsiExpression> myContent;
|
||||
final List<PsiStatement> myStatementsToDelete;
|
||||
final String myType;
|
||||
|
||||
PrepopulatedCollectionModel(List<PsiExpression> content, List<PsiStatement> delete, String type) {
|
||||
myContent = content;
|
||||
myStatementsToDelete = delete;
|
||||
myType = type;
|
||||
}
|
||||
|
||||
public static PrepopulatedCollectionModel fromList(PsiExpression listDefinition) {
|
||||
listDefinition = PsiUtil.skipParenthesizedExprDown(listDefinition);
|
||||
if(listDefinition instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression call = (PsiMethodCallExpression)listDefinition;
|
||||
if (ARRAYS_AS_LIST.test(call)) {
|
||||
return new PrepopulatedCollectionModel(Arrays.asList(call.getArgumentList().getExpressions()), Collections.emptyList(), "List");
|
||||
}
|
||||
if(STREAM_COLLECT.test(call) && COLLECTORS_TO_LIST.matches(call.getArgumentList().getExpressions()[0])) {
|
||||
PsiMethodCallExpression qualifier = MethodCallUtils.getQualifierMethodCall(call);
|
||||
if(STREAM_OF.matches(qualifier)) {
|
||||
return new PrepopulatedCollectionModel(Arrays.asList(qualifier.getArgumentList().getExpressions()), Collections.emptyList(),
|
||||
"List");
|
||||
}
|
||||
}
|
||||
}
|
||||
if(listDefinition instanceof PsiNewExpression) {
|
||||
return fromNewExpression((PsiNewExpression)listDefinition, "List", CommonClassNames.JAVA_UTIL_ARRAY_LIST);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PrepopulatedCollectionModel fromSet(PsiExpression setDefinition) {
|
||||
setDefinition = PsiUtil.skipParenthesizedExprDown(setDefinition);
|
||||
if(setDefinition instanceof PsiNewExpression) {
|
||||
return fromNewExpression((PsiNewExpression)setDefinition, "Set", CommonClassNames.JAVA_UTIL_HASH_SET);
|
||||
}
|
||||
if(setDefinition instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression call = (PsiMethodCallExpression)setDefinition;
|
||||
if(STREAM_COLLECT.test(call) && COLLECTORS_TO_SET.matches(call.getArgumentList().getExpressions()[0])) {
|
||||
PsiMethodCallExpression qualifier = MethodCallUtils.getQualifierMethodCall(call);
|
||||
if(STREAM_OF.matches(qualifier)) {
|
||||
return new PrepopulatedCollectionModel(Arrays.asList(qualifier.getArgumentList().getExpressions()), Collections.emptyList(),
|
||||
"Set");
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PrepopulatedCollectionModel fromNewExpression(PsiNewExpression newExpression, String type, String className) {
|
||||
PsiExpressionList argumentList = newExpression.getArgumentList();
|
||||
if (argumentList != null) {
|
||||
PsiExpression[] args = argumentList.getExpressions();
|
||||
PsiJavaCodeReferenceElement classReference = newExpression.getClassReference();
|
||||
if (classReference != null && className.equals(classReference.getQualifiedName())) {
|
||||
return fromArraysAsList(args, type);
|
||||
}
|
||||
PsiAnonymousClass anonymousClass = newExpression.getAnonymousClass();
|
||||
if (anonymousClass != null && args.length == 0) {
|
||||
PsiJavaCodeReferenceElement baseClassReference = anonymousClass.getBaseClassReference();
|
||||
if (className.equals(baseClassReference.getQualifiedName())) {
|
||||
return fromInitializer(anonymousClass, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PrepopulatedCollectionModel fromArraysAsList(PsiExpression[] args, String type) {
|
||||
if (args.length == 1) {
|
||||
PsiMethodCallExpression arg = tryCast(PsiUtil.skipParenthesizedExprDown(args[0]), PsiMethodCallExpression.class);
|
||||
if (ARRAYS_AS_LIST.test(arg)) {
|
||||
return new PrepopulatedCollectionModel(Arrays.asList(arg.getArgumentList().getExpressions()), Collections.emptyList(), type);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PrepopulatedCollectionModel fromInitializer(PsiAnonymousClass anonymousClass, String type) {
|
||||
PsiClassInitializer initializer = ClassUtils.getDoubleBraceInitializer(anonymousClass);
|
||||
if(initializer != null) {
|
||||
List<PsiExpression> contents = new ArrayList<>();
|
||||
for(PsiStatement statement : initializer.getBody().getStatements()) {
|
||||
if(!(statement instanceof PsiExpressionStatement)) return null;
|
||||
PsiMethodCallExpression call = tryCast(((PsiExpressionStatement)statement).getExpression(), PsiMethodCallExpression.class);
|
||||
if(!COLLECTION_ADD.test(call)) return null;
|
||||
PsiExpression qualifier = call.getMethodExpression().getQualifierExpression();
|
||||
if(qualifier != null && !qualifier.getText().equals("this")) return null;
|
||||
contents.add(call.getArgumentList().getExpressions()[0]);
|
||||
}
|
||||
return new PrepopulatedCollectionModel(contents, Collections.emptyList(), type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReplaceWithCollectionFactoryFix implements LocalQuickFix {
|
||||
private String myType;
|
||||
|
||||
public ReplaceWithCollectionFactoryFix(String type) {myType = type;}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Replace with '"+myType+".of' call";
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return "Replace with collection factory call";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiMethodCallExpression call = PsiTreeUtil.getParentOfType(descriptor.getStartElement(), PsiMethodCallExpression.class);
|
||||
if(call == null) return;
|
||||
PrepopulatedCollectionModel model = MAPPER.mapFirst(call);
|
||||
if(model == null) return;
|
||||
CommentTracker ct = new CommentTracker();
|
||||
model.myStatementsToDelete.forEach(ct::delete);
|
||||
ct.replaceAndRestoreComments(call, StreamEx.of(model.myContent).map(ct::text)
|
||||
.joining(",", "java.util." + model.myType + ".of(", ")"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Replace with 'List.of' call" "true"
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Test {
|
||||
public static final List<Number> EVEN = List.of(2, 4, 6, 8, 10);
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Replace with 'List.of' call" "true"
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Test {
|
||||
public static final List<Number> EVEN = List.of(0, 2, 4, 6, 8);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Replace with 'List.of' call" "true"
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Test {
|
||||
public static final List<Number> EVEN = List.of(2, 4, 6, 8, 10);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Replace with 'Set.of' call" "true"
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Test {
|
||||
public static final Set<String> MY_SET = Set.of("a", "b", "c");
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Replace with 'Set.of' call" "true"
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Test {
|
||||
public static final Set<String> MY_SET = Set.of("a", "b", "c".toUpperCase());
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Replace with 'List.of' call" "true"
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Test {
|
||||
public static final List<Class<?>> MY_LIST = List.of(String.class, int.class, Object.class);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Replace with 'Set.of' call" "true"
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Test {
|
||||
public static final Set<Class<?>> MY_SET = Set.of(String.class, int.class, Object.class);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Replace with 'List.of' call" "true"
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Test {
|
||||
public static final List<Number> EVEN = Collections.unmo<caret>difiableList(new ArrayList<>(Arrays.asList(2,4,6,8,10)));
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// "Replace with 'List.of' call" "true"
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Test {
|
||||
public static final List<Number> EVEN = Collections.unmodif<caret>iableList(new ArrayList<>() {{
|
||||
this.add(0);
|
||||
this.add(2);
|
||||
this.add(4);
|
||||
this.add(6);
|
||||
this.add(8);
|
||||
}});
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Replace with 'List.of' call" "true"
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Test {
|
||||
public static final List<Number> EVEN = Collections.unmodi<caret>fiableList(Arrays.asList(2,4,6,8,10));
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Replace with 'Set.of' call" "true"
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Test {
|
||||
public static final Set<String> MY_SET = Collections.unm<caret>odifiableSet(new HashSet<>(Arrays.asList("a", "b", "c")));
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Replace with 'Set.of' call" "true"
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Test {
|
||||
public static final Set<String> MY_SET = Collections.unmodi<caret>fiableSet(new HashSet<String>() {{
|
||||
add("a");
|
||||
add("b");
|
||||
add("c".toUpperCase());
|
||||
}});
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// "Replace with 'Set.of' call" "false"
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Test {
|
||||
static Set<String> WRONG_SET = new HashSet<>();
|
||||
|
||||
public static final Set<String> MY_SET = Collections.unmod<caret>ifiableSet(new HashSet<String>() {{
|
||||
add("a");
|
||||
add("b");
|
||||
WRONG_SET.add("c".toUpperCase());
|
||||
}});
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace with 'List.of' call" "true"
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Test {
|
||||
public static final List<Class<?>> MY_LIST = Collections
|
||||
.unmo<caret>difiableList(Stream.of(String.class, int.class, Object.class).collect(Collectors.toList()));
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace with 'Set.of' call" "true"
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Test {
|
||||
public static final Set<Class<?>> MY_SET = Collections
|
||||
.un<caret>modifiableSet(Stream.of(String.class, int.class, Object.class).collect(Collectors.toSet()));
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.java19api;
|
||||
|
||||
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
public class Java9CollectionFactoryInspectionTest extends LightQuickFixParameterizedTestCase {
|
||||
@Override
|
||||
protected LanguageLevel getLanguageLevel() {
|
||||
return LanguageLevel.JDK_1_9;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected LocalInspectionTool[] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[]{new Java9CollectionFactoryInspection()};
|
||||
}
|
||||
|
||||
public void test() throws Exception {
|
||||
doAllTests();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/inspection/java9CollectionFactory";
|
||||
}
|
||||
}
|
||||
+13
@@ -17,6 +17,7 @@ package com.siyeh.ig.callMatcher;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.psiutils.MethodCallUtils;
|
||||
@@ -44,6 +45,18 @@ public interface CallMatcher extends Predicate<PsiMethodCallExpression> {
|
||||
@Contract("null -> false")
|
||||
boolean test(@Nullable PsiMethodCallExpression call);
|
||||
|
||||
/**
|
||||
* Returns true if the supplied expression is (possibly parenthesized) method call which matches this matcher
|
||||
*
|
||||
* @param expression expression to test
|
||||
* @return true if the supplied expression matches this matcher
|
||||
*/
|
||||
@Contract("null -> false")
|
||||
default boolean matches(@Nullable PsiExpression expression) {
|
||||
expression = PsiUtil.skipParenthesizedExprDown(expression);
|
||||
return expression instanceof PsiMethodCallExpression && test((PsiMethodCallExpression)expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new matcher which will return true if any of supplied matchers return true
|
||||
*
|
||||
|
||||
+3
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.psiutils.ClassUtils;
|
||||
import com.siyeh.ig.psiutils.ParenthesesUtils;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -180,31 +181,7 @@ public class DoubleBraceInitializationInspection extends BaseInspection {
|
||||
@Override
|
||||
public void visitAnonymousClass(PsiAnonymousClass aClass) {
|
||||
super.visitAnonymousClass(aClass);
|
||||
final PsiClassInitializer[] initializers = aClass.getInitializers();
|
||||
if (initializers.length != 1) {
|
||||
return;
|
||||
}
|
||||
final PsiClassInitializer initializer = initializers[0];
|
||||
if (initializer.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
// don't warn on broken code
|
||||
return;
|
||||
}
|
||||
final PsiField[] fields = aClass.getFields();
|
||||
if (fields.length != 0) {
|
||||
return;
|
||||
}
|
||||
final PsiMethod[] methods = aClass.getMethods();
|
||||
if (methods.length != 0) {
|
||||
return;
|
||||
}
|
||||
final PsiClass[] innerClasses = aClass.getInnerClasses();
|
||||
if (innerClasses.length != 0) {
|
||||
return;
|
||||
}
|
||||
final PsiJavaCodeReferenceElement reference = aClass.getBaseClassReference();
|
||||
if (reference.resolve() == null) {
|
||||
return;
|
||||
}
|
||||
if (ClassUtils.getDoubleBraceInitializer(aClass) == null) return;
|
||||
registerClassError(aClass, aClass);
|
||||
}
|
||||
}
|
||||
|
||||
+23
@@ -223,4 +223,27 @@ public class ClassUtils {
|
||||
final PsiClass parentClass = (PsiClass)parent;
|
||||
return !parentClass.isInterface();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns "double brace" initialization for given anonymous class.
|
||||
*
|
||||
* @param aClass anonymous class to extract the "double brace" initializer from
|
||||
* @return "double brace" initializer or null if the class does not follow double brace initialization anti-pattern
|
||||
*/
|
||||
@Nullable
|
||||
public static PsiClassInitializer getDoubleBraceInitializer(PsiAnonymousClass aClass) {
|
||||
final PsiClassInitializer[] initializers = aClass.getInitializers();
|
||||
if (initializers.length != 1) return null;
|
||||
final PsiClassInitializer initializer = initializers[0];
|
||||
if (initializer.hasModifierProperty(PsiModifier.STATIC)) return null;
|
||||
final PsiField[] fields = aClass.getFields();
|
||||
if (fields.length != 0) return null;
|
||||
final PsiMethod[] methods = aClass.getMethods();
|
||||
if (methods.length != 0) return null;
|
||||
final PsiClass[] innerClasses = aClass.getInnerClasses();
|
||||
if (innerClasses.length != 0) return null;
|
||||
final PsiJavaCodeReferenceElement reference = aClass.getBaseClassReference();
|
||||
if (reference.resolve() == null) return null;
|
||||
return initializer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection helps to convert unmodifiable collections created before Java 9 to new collection factory methods
|
||||
like <code>List.of</code> or <code>Set.of</code>.
|
||||
<!-- tooltip end -->
|
||||
<p>This inspection is available since Java 9 only.</p>
|
||||
<small>New in 2017.2</small>
|
||||
</body>
|
||||
</html>
|
||||
@@ -857,6 +857,11 @@
|
||||
groupKey="group.names.language.level.specific.issues.and.migration.aids8" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="com.intellij.codeInspection.java18api.Java8MapForEachInspection"
|
||||
displayName="Replace with Map.forEach"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="Java9CollectionFactory"
|
||||
groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.code.style.issues" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="com.intellij.codeInspection.java19api.Java9CollectionFactoryInspection"
|
||||
displayName="Immutable collection creation can be replaced with collection factory call"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="ExcessiveLambdaUsage"
|
||||
groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.verbose.or.redundant.code.constructs" enabledByDefault="true" level="WARNING"
|
||||
|
||||
Reference in New Issue
Block a user