mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
cleanup IDEA-382376: move com.siyeh.ig.memory package from java-impl to java-impl-inspections
GitOrigin-RevId: 24d3ca0a34664e5863a24d9120988b9ac94b7caf
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8e973743aa
commit
3c94faef3d
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2003-2025 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* 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.siyeh.ig.memory;
|
||||
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.pom.java.JavaFeature;
|
||||
import com.intellij.psi.CommonClassNames;
|
||||
import com.intellij.psi.JavaRecursiveElementWalkingVisitor;
|
||||
import com.intellij.psi.PsiAnonymousClass;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiEnumConstantInitializer;
|
||||
import com.intellij.psi.PsiJavaCodeReferenceElement;
|
||||
import com.intellij.psi.PsiMember;
|
||||
import com.intellij.psi.PsiModifier;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.fixes.MoveAnonymousToInnerClassFix;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class AnonymousInnerClassMayBeStaticInspection extends BaseInspection {
|
||||
|
||||
@Override
|
||||
protected LocalQuickFix buildFix(Object... infos) {
|
||||
return new MoveAnonymousToInnerClassFix(InspectionGadgetsBundle.message("anonymous.inner.may.be.named.static.inner.class.quickfix"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message("anonymous.inner.may.be.named.static.inner.class.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull BaseInspectionVisitor buildVisitor() {
|
||||
return new AnonymousInnerClassMayBeStaticVisitor();
|
||||
}
|
||||
|
||||
private static class AnonymousInnerClassMayBeStaticVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitAnonymousClass(@NotNull PsiAnonymousClass anonymousClass) {
|
||||
if (anonymousClass instanceof PsiEnumConstantInitializer) {
|
||||
return;
|
||||
}
|
||||
if (PsiUtil.isAvailable(JavaFeature.INNER_NOT_CAPTURE_THIS, anonymousClass) &&
|
||||
!InheritanceUtil.isInheritor(anonymousClass, CommonClassNames.JAVA_IO_SERIALIZABLE)) {
|
||||
// Since Java 18, non-serializable anonymous classes don't capture 'this' reference
|
||||
return;
|
||||
}
|
||||
final PsiMember containingMember = PsiTreeUtil.getParentOfType(anonymousClass, PsiMember.class);
|
||||
if (containingMember == null || containingMember.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
return;
|
||||
}
|
||||
final PsiJavaCodeReferenceElement reference = anonymousClass.getBaseClassReference();
|
||||
if (reference.resolve() == null) {
|
||||
// don't warn on broken code
|
||||
return;
|
||||
}
|
||||
final PsiClass containingClass = PsiTreeUtil.getParentOfType(anonymousClass, PsiClass.class);
|
||||
if (containingClass == null) {
|
||||
return;
|
||||
}
|
||||
if (containingClass.getContainingClass() != null && !containingClass.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
// strictly speaking can be named static inner class but not when part of the current containing class
|
||||
return;
|
||||
}
|
||||
final InnerClassReferenceVisitor visitor = new InnerClassReferenceVisitor(anonymousClass, true);
|
||||
anonymousClass.accept(visitor);
|
||||
if (!visitor.canInnerClassBeStatic()) {
|
||||
return;
|
||||
}
|
||||
if (hasReferenceToLocalClass(anonymousClass)) {
|
||||
return;
|
||||
}
|
||||
registerClassError(anonymousClass);
|
||||
}
|
||||
|
||||
private static boolean hasReferenceToLocalClass(PsiAnonymousClass anonymousClass) {
|
||||
final LocalClassReferenceVisitor visitor = new LocalClassReferenceVisitor();
|
||||
anonymousClass.accept(visitor);
|
||||
return visitor.hasReferenceToLocalClass();
|
||||
}
|
||||
|
||||
private static class LocalClassReferenceVisitor extends JavaRecursiveElementWalkingVisitor {
|
||||
|
||||
private boolean referenceToLocalClass;
|
||||
|
||||
@Override
|
||||
public void visitReferenceElement(@NotNull PsiJavaCodeReferenceElement reference) {
|
||||
super.visitReferenceElement(reference);
|
||||
if (reference.getQualifier() != null) {
|
||||
return;
|
||||
}
|
||||
final PsiElement target = reference.resolve();
|
||||
if (!(target instanceof PsiClass aClass) || !PsiUtil.isLocalClass(aClass)) {
|
||||
return;
|
||||
}
|
||||
referenceToLocalClass = true;
|
||||
}
|
||||
|
||||
private boolean hasReferenceToLocalClass() {
|
||||
return referenceToLocalClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2003-2023 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* 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.siyeh.ig.memory;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.options.JavaClassValidator;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.options.OptPane;
|
||||
import com.intellij.codeInspection.util.SpecialAnnotationsUtilBase;
|
||||
import com.intellij.modcommand.ActionContext;
|
||||
import com.intellij.modcommand.ModCommand;
|
||||
import com.intellij.modcommand.ModCommandBatchQuickFix;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.pom.java.JavaFeature;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementFactory;
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import com.intellij.psi.PsiExpressionList;
|
||||
import com.intellij.psi.PsiJavaCodeReferenceElement;
|
||||
import com.intellij.psi.PsiModifier;
|
||||
import com.intellij.psi.PsiModifierList;
|
||||
import com.intellij.psi.PsiNewExpression;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.PsiReferenceParameterList;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.OrderedSet;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.junit.JUnitCommonClassNames;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.codeInspection.options.OptPane.pane;
|
||||
import static com.intellij.codeInspection.options.OptPane.stringList;
|
||||
|
||||
public final class InnerClassMayBeStaticInspection extends BaseInspection {
|
||||
|
||||
@SuppressWarnings("PublicField")
|
||||
public OrderedSet<String> ignorableAnnotations =
|
||||
new OrderedSet<>(Collections.singletonList(JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_NESTED));
|
||||
|
||||
@Override
|
||||
protected @NotNull String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message("inner.class.may.be.static.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull OptPane getOptionsPane() {
|
||||
return pane(
|
||||
stringList("ignorableAnnotations", InspectionGadgetsBundle.message("ignore.if.annotated.by"),
|
||||
new JavaClassValidator().annotationsOnly()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean runForWholeFile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalQuickFix @NotNull [] buildFixes(Object... infos) {
|
||||
final List<LocalQuickFix> fixes = new ArrayList<>();
|
||||
fixes.add(new InnerClassMayBeStaticFix());
|
||||
final PsiClass aClass = (PsiClass)infos[0];
|
||||
fixes.addAll(SpecialAnnotationsUtilBase.createAddAnnotationToListFixes(aClass, this, insp -> insp.ignorableAnnotations));
|
||||
return fixes.toArray(LocalQuickFix.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
private static class InnerClassMayBeStaticFix extends ModCommandBatchQuickFix {
|
||||
|
||||
@Override
|
||||
public @NotNull String getFamilyName() {
|
||||
return InspectionGadgetsBundle.message("make.static.quickfix");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ModCommand perform(@NotNull Project project, @NotNull List<ProblemDescriptor> descriptors) {
|
||||
final List<Handler> handlers = StreamEx.of(descriptors).map(descriptor -> descriptor.getPsiElement().getParent())
|
||||
.select(PsiClass.class).map(Handler::new).toList();
|
||||
return ModCommand.psiUpdate(ActionContext.from(descriptors.get(0)), updater -> {
|
||||
ContainerUtil.map(handlers, h -> h.getWritable(updater))
|
||||
.forEach(Handler::makeStatic);
|
||||
});
|
||||
}
|
||||
|
||||
private static class Handler {
|
||||
private final @NotNull PsiClass innerClass;
|
||||
private final @NotNull List<@NotNull PsiElement> references;
|
||||
|
||||
Handler(@NotNull PsiClass innerClass) {
|
||||
this.innerClass = innerClass;
|
||||
final Collection<PsiReference> references = ReferencesSearch.search(innerClass, innerClass.getUseScope()).findAll();
|
||||
this.references = ContainerUtil.map(references, PsiReference::getElement);
|
||||
}
|
||||
|
||||
private Handler(@NotNull PsiClass innerClass, @NotNull List<@NotNull PsiElement> references) {
|
||||
this.innerClass = innerClass;
|
||||
this.references = references;
|
||||
}
|
||||
|
||||
void makeStatic() {
|
||||
final PsiModifierList modifiers = innerClass.getModifierList();
|
||||
if (modifiers == null) {
|
||||
return;
|
||||
}
|
||||
modifiers.setModifierProperty(PsiModifier.STATIC, true);
|
||||
final Project project = innerClass.getProject();
|
||||
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
references.stream()
|
||||
.sorted((r1, r2) -> PsiUtilCore.compareElementsByPosition(r2, r1))
|
||||
.forEach(reference -> {
|
||||
final PsiElement parent = reference.getParent();
|
||||
if (parent instanceof PsiNewExpression newExpression) {
|
||||
final PsiJavaCodeReferenceElement classReference = newExpression.getClassReference();
|
||||
if (classReference == null) {
|
||||
return;
|
||||
}
|
||||
final PsiExpressionList argumentList = newExpression.getArgumentList();
|
||||
if (argumentList == null) {
|
||||
return;
|
||||
}
|
||||
final PsiReferenceParameterList parameterList = classReference.getParameterList();
|
||||
final String genericParameters = parameterList != null ? parameterList.getText() : "";
|
||||
final String text = "new " + classReference.getQualifiedName() + genericParameters + argumentList.getText();
|
||||
final PsiExpression expression = factory.createExpressionFromText(text, innerClass);
|
||||
codeStyleManager.shortenClassReferences(newExpression.replace(expression));
|
||||
}
|
||||
else if (reference instanceof PsiJavaCodeReferenceElement ref) {
|
||||
removeTypeArguments(ref);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Handler getWritable(@NotNull ModPsiUpdater updater) {
|
||||
return new Handler(updater.getWritable(innerClass),
|
||||
ContainerUtil.map(references, updater::getWritable));
|
||||
}
|
||||
|
||||
private static void removeTypeArguments(PsiJavaCodeReferenceElement ref) {
|
||||
if (ref == null || !(ref.getQualifier() instanceof PsiJavaCodeReferenceElement qualifier)) {
|
||||
return;
|
||||
}
|
||||
removeTypeArguments(qualifier);
|
||||
PsiReferenceParameterList parameterList = qualifier.getParameterList();
|
||||
if (parameterList != null && parameterList.getFirstChild() != null) {
|
||||
parameterList.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull BaseInspectionVisitor buildVisitor() {
|
||||
return new InnerClassMayBeStaticVisitor();
|
||||
}
|
||||
|
||||
private class InnerClassMayBeStaticVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
if (aClass.getContainingClass() != null && !aClass.hasModifierProperty(PsiModifier.STATIC) ||
|
||||
PsiUtil.isLocalOrAnonymousClass(aClass)) {
|
||||
if (!PsiUtil.isAvailable(JavaFeature.INNER_STATICS, aClass)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (PsiClass innerClass : aClass.getInnerClasses()) {
|
||||
if (innerClass.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
continue;
|
||||
}
|
||||
if (AnnotationUtil.isAnnotated(innerClass, ignorableAnnotations, 0)) {
|
||||
continue;
|
||||
}
|
||||
final InnerClassReferenceVisitor visitor = new InnerClassReferenceVisitor(innerClass);
|
||||
innerClass.accept(visitor);
|
||||
if (!visitor.canInnerClassBeStatic()) {
|
||||
continue;
|
||||
}
|
||||
registerClassError(innerClass, innerClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2003-2025 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* 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.siyeh.ig.memory;
|
||||
|
||||
import com.intellij.psi.PsiArrayInitializerExpression;
|
||||
import com.intellij.psi.PsiNewExpression;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.fixes.IntroduceConstantFix;
|
||||
import com.siyeh.ig.psiutils.ConstructionUtils;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import org.intellij.lang.annotations.Pattern;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class ZeroLengthArrayInitializationInspection extends BaseInspection {
|
||||
|
||||
@Override
|
||||
protected InspectionGadgetsFix buildFix(Object... infos) {
|
||||
return new IntroduceConstantFix();
|
||||
}
|
||||
|
||||
@Pattern(VALID_ID_PATTERN)
|
||||
@Override
|
||||
public @NotNull String getID() {
|
||||
return "ZeroLengthArrayAllocation";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message("array.allocation.zero.length.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull BaseInspectionVisitor buildVisitor() {
|
||||
return new ZeroLengthArrayInitializationVisitor();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class ZeroLengthArrayInitializationVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitNewExpression(@NotNull PsiNewExpression expression) {
|
||||
super.visitNewExpression(expression);
|
||||
if (!ConstructionUtils.isEmptyArrayInitializer(expression)) {
|
||||
return;
|
||||
}
|
||||
if (ExpressionUtils.isDeclaredConstant(expression)) {
|
||||
return;
|
||||
}
|
||||
registerError(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitArrayInitializerExpression(@NotNull PsiArrayInitializerExpression expression) {
|
||||
super.visitArrayInitializerExpression(expression);
|
||||
if (!expression.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (expression.getParent() instanceof PsiNewExpression) {
|
||||
return;
|
||||
}
|
||||
if (ExpressionUtils.isDeclaredConstant(expression)) {
|
||||
return;
|
||||
}
|
||||
registerError(expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user