cleanup IDEA-382376: move com.siyeh.ig.memory package from java-impl to java-impl-inspections

GitOrigin-RevId: 24d3ca0a34664e5863a24d9120988b9ac94b7caf
This commit is contained in:
Bartek Pacia
2026-02-12 12:49:55 +00:00
committed by intellij-monorepo-bot
parent 8e973743aa
commit 3c94faef3d
3 changed files with 0 additions and 0 deletions
@@ -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;
}
}
}
}
@@ -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);
}
}
}
}
@@ -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);
}
}
}