diff --git a/java/java-analysis-impl/src/com/siyeh/ig/classlayout/UtilityClassWithPublicConstructorInspection.java b/java/java-analysis-impl/src/com/siyeh/ig/classlayout/UtilityClassWithPublicConstructorInspection.java index 616c15a97280..d7109b50abe1 100644 --- a/java/java-analysis-impl/src/com/siyeh/ig/classlayout/UtilityClassWithPublicConstructorInspection.java +++ b/java/java-analysis-impl/src/com/siyeh/ig/classlayout/UtilityClassWithPublicConstructorInspection.java @@ -1,51 +1,55 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +/* + * 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.classlayout; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.modcommand.ModPsiUpdater; import com.intellij.modcommand.PsiUpdateModCommandQuickFix; import com.intellij.openapi.project.Project; -import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.SearchScope; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; import com.intellij.psi.search.searches.ClassInheritorsSearch; -import com.intellij.util.Query; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.psiutils.UtilityClassUtil; import org.jetbrains.annotations.NotNull; -public final class UtilityClassWithPublicConstructorInspection - extends BaseInspection { - +public final class UtilityClassWithPublicConstructorInspection extends BaseInspection { @Override protected @NotNull String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message( - "utility.class.with.public.constructor.problem.descriptor"); + return InspectionGadgetsBundle.message("utility.class.with.public.constructor.problem.descriptor"); } @Override protected LocalQuickFix buildFix(Object... infos) { final PsiClass psiClass = (PsiClass)infos[0]; final boolean hasInheritors = (Boolean)infos[1]; - if (psiClass.getConstructors().length > 1) { - return new UtilityClassWithPublicConstructorFix(true, hasInheritors); - } - else { - return new UtilityClassWithPublicConstructorFix(false, hasInheritors); - } + return new UtilityClassWithPublicConstructorFix(psiClass.getConstructors().length > 1, hasInheritors); } - private static class UtilityClassWithPublicConstructorFix - extends PsiUpdateModCommandQuickFix { + private static class UtilityClassWithPublicConstructorFix extends PsiUpdateModCommandQuickFix { private final boolean m_multipleConstructors; private final boolean m_hasInheritors; UtilityClassWithPublicConstructorFix(boolean multipleConstructors, boolean hasInheritors) { - super(); m_multipleConstructors = multipleConstructors; m_hasInheritors = hasInheritors; } @@ -71,13 +75,9 @@ public final class UtilityClassWithPublicConstructorInspection return; } - String modifier = m_hasInheritors? PsiModifier.PROTECTED : PsiModifier.PRIVATE; - - final PsiMethod[] constructors = psiClass.getConstructors(); - for (PsiMethod constructor : constructors) { - final PsiModifierList modifierList = - constructor.getModifierList(); - modifierList.setModifierProperty(modifier, true); + String modifier = m_hasInheritors ? PsiModifier.PROTECTED : PsiModifier.PRIVATE; + for (PsiMethod constructor : psiClass.getConstructors()) { + constructor.getModifierList().setModifierProperty(modifier, true); } } } @@ -87,30 +87,20 @@ public final class UtilityClassWithPublicConstructorInspection return new StaticClassWithPublicConstructorVisitor(); } - private static class StaticClassWithPublicConstructorVisitor - extends BaseInspectionVisitor { + private static class StaticClassWithPublicConstructorVisitor extends BaseInspectionVisitor { @Override public void visitClass(@NotNull PsiClass aClass) { - // no call to super, so that it doesn't drill down to inner classes - if (!UtilityClassUtil.isUtilityClass(aClass)) { - return; - } - if (!hasPublicConstructor(aClass)) { + if (!UtilityClassUtil.isUtilityClass(aClass) || !hasPublicConstructor(aClass)) { return; } - final SearchScope scope = GlobalSearchScope.projectScope(aClass.getProject()); - final Query query = ClassInheritorsSearch.search(aClass, scope, false); - final PsiClass subclass = query.findFirst(); - Boolean hasInheritors = subclass != null; - + boolean hasInheritors = ClassInheritorsSearch.search(aClass, aClass.getUseScope(), false).findFirst() != null; registerClassError(aClass, aClass, hasInheritors); } private static boolean hasPublicConstructor(PsiClass aClass) { - final PsiMethod[] constructors = aClass.getConstructors(); - for (final PsiMethod constructor : constructors) { + for (PsiMethod constructor : aClass.getConstructors()) { if (constructor.hasModifierProperty(PsiModifier.PUBLIC)) { return true; } diff --git a/java/java-impl/src/com/siyeh/ig/classlayout/PublicConstructorInspection.java b/java/java-impl/src/com/siyeh/ig/classlayout/PublicConstructorInspection.java index 6f985be6350b..dd691efe43f3 100644 --- a/java/java-impl/src/com/siyeh/ig/classlayout/PublicConstructorInspection.java +++ b/java/java-impl/src/com/siyeh/ig/classlayout/PublicConstructorInspection.java @@ -1,19 +1,14 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. - +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ig.classlayout; import com.intellij.codeInsight.intention.ReplaceConstructorWithFactoryAction; import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiModifier; -import com.intellij.psi.PsiParameterList; +import com.intellij.psi.*; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.psiutils.SerializationUtils; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * @author Bas Leijdekkers @@ -21,18 +16,16 @@ import org.jetbrains.annotations.Nullable; public final class PublicConstructorInspection extends BaseInspection { @Override - protected @Nullable LocalQuickFix buildFix(Object... infos) { + protected @NotNull LocalQuickFix buildFix(Object... infos) { return LocalQuickFix.from(new ReplaceConstructorWithFactoryAction()); } @Override protected @NotNull String buildErrorString(Object... infos) { - if (((Boolean)infos[0]).booleanValue()) { - return InspectionGadgetsBundle.message("public.default.constructor.problem.descriptor"); - } - else { - return InspectionGadgetsBundle.message("public.constructor.problem.descriptor"); - } + boolean defaultConstructor = ((Boolean)infos[0]).booleanValue(); + return defaultConstructor + ? InspectionGadgetsBundle.message("public.default.constructor.problem.descriptor") + : InspectionGadgetsBundle.message("public.constructor.problem.descriptor"); } @Override @@ -47,45 +40,28 @@ public final class PublicConstructorInspection extends BaseInspection { private static class PublicConstructorVisitor extends BaseInspectionVisitor { - @Override - public void visitMethod(@NotNull PsiMethod method) { - super.visitMethod(method); - if (!method.isConstructor()) { - return; - } - if (!method.hasModifierProperty(PsiModifier.PUBLIC)) { - return; - } - final PsiClass aClass = method.getContainingClass(); - if (aClass == null || aClass.hasModifierProperty(PsiModifier.ABSTRACT) || aClass.isRecord()) { - return; - } - if (SerializationUtils.isExternalizable(aClass)) { - final PsiParameterList parameterList = method.getParameterList(); - if (parameterList.isEmpty()) { - return; - } - } - registerMethodError(method, Boolean.FALSE); - } - @Override public void visitClass(@NotNull PsiClass aClass) { super.visitClass(aClass); if (aClass.isInterface() || aClass.isEnum() || aClass.isRecord()) { return; } - if (!aClass.hasModifierProperty(PsiModifier.PUBLIC) || aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + if (aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { return; } - final PsiMethod[] constructors = aClass.getConstructors(); - if (constructors.length > 0) { - return; + PsiMethod[] constructors = aClass.getConstructors(); + for (PsiMethod constructor : constructors) { + if (!constructor.hasModifierProperty(PsiModifier.PUBLIC)) { + continue; + } + if (SerializationUtils.isExternalizable(aClass) && constructor.getParameterList().isEmpty()) { + continue; + } + registerMethodError(constructor, Boolean.FALSE); } - if (SerializationUtils.isExternalizable(aClass)) { - return; + if (constructors.length == 0 && aClass.hasModifierProperty(PsiModifier.PUBLIC) && !SerializationUtils.isExternalizable(aClass)) { + registerClassError(aClass, Boolean.TRUE); } - registerClassError(aClass, Boolean.TRUE); } } } diff --git a/java/java-impl/src/com/siyeh/ig/classlayout/UtilityClassWithoutPrivateConstructorInspection.java b/java/java-impl/src/com/siyeh/ig/classlayout/UtilityClassWithoutPrivateConstructorInspection.java index 32ddcbee8108..792ed3b03902 100644 --- a/java/java-impl/src/com/siyeh/ig/classlayout/UtilityClassWithoutPrivateConstructorInspection.java +++ b/java/java-impl/src/com/siyeh/ig/classlayout/UtilityClassWithoutPrivateConstructorInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2021 Dave Griffith, Bas Leijdekkers + * 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. @@ -25,8 +25,6 @@ import com.intellij.modcommand.PsiUpdateModCommandQuickFix; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.util.Query; @@ -65,14 +63,13 @@ public final class UtilityClassWithoutPrivateConstructorInspection extends BaseI protected LocalQuickFix @NotNull [] buildFixes(Object... infos) { final List fixes = new ArrayList<>(); final PsiClass aClass = (PsiClass)infos[0]; - final PsiMethod constructor = getNullArgConstructor(aClass); + final PsiMethod constructor = getNoArgConstructor(aClass); if (constructor == null) { fixes.add(new CreateEmptyPrivateConstructor()); } else { - final Query query = ReferencesSearch.search(constructor, constructor.getUseScope()); - final PsiReference reference = query.findFirst(); - if (reference == null) { + boolean hasInstantiation = ReferencesSearch.search(constructor, constructor.getUseScope()).findFirst() == null; + if (hasInstantiation) { fixes.add(new MakeConstructorPrivateFix()); } } @@ -95,11 +92,9 @@ public final class UtilityClassWithoutPrivateConstructorInspection extends BaseI return query.anyMatch(ref -> ref != null && ref.getElement().getParent() instanceof PsiNewExpression); } - static @Nullable PsiMethod getNullArgConstructor(PsiClass aClass) { - final PsiMethod[] constructors = aClass.getConstructors(); - for (final PsiMethod constructor : constructors) { - final PsiParameterList params = constructor.getParameterList(); - if (params.isEmpty()) { + private static @Nullable PsiMethod getNoArgConstructor(PsiClass aClass) { + for (PsiMethod constructor : aClass.getConstructors()) { + if (constructor.getParameterList().isEmpty()) { return constructor; } } @@ -115,22 +110,19 @@ public final class UtilityClassWithoutPrivateConstructorInspection extends BaseI @Override protected void applyFix(@NotNull Project project, @NotNull PsiElement classNameIdentifier, @NotNull ModPsiUpdater updater) { - final PsiElement parent = classNameIdentifier.getParent(); - if (!(parent instanceof PsiClass aClass)) { + if (!(classNameIdentifier.getParent() instanceof PsiClass aClass)) { return; } if (hasImplicitConstructorUsage(aClass)) { updater.cancel(InspectionGadgetsBundle.message("utility.class.without.private.constructor.cant.generate.constructor.message")); return; } - final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); - final PsiElementFactory factory = psiFacade.getElementFactory(); + final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory(); final PsiMethod constructor = factory.createConstructor(); final PsiModifierList modifierList = constructor.getModifierList(); modifierList.setModifierProperty(PsiModifier.PRIVATE, true); aClass.add(constructor); - final CodeStyleManager styleManager = CodeStyleManager.getInstance(project); - styleManager.reformat(constructor); + CodeStyleManager.getInstance(project).reformat(constructor); } } @@ -147,10 +139,8 @@ public final class UtilityClassWithoutPrivateConstructorInspection extends BaseI if (!(parent instanceof PsiClass aClass)) { return; } - final PsiMethod[] constructors = aClass.getConstructors(); - for (final PsiMethod constructor : constructors) { - final PsiParameterList parameterList = constructor.getParameterList(); - if (parameterList.isEmpty()) { + for (PsiMethod constructor : aClass.getConstructors()) { + if (constructor.getParameterList().isEmpty()) { final PsiModifierList modifiers = constructor.getModifierList(); modifiers.setModifierProperty(PsiModifier.PUBLIC, false); modifiers.setModifierProperty(PsiModifier.PROTECTED, false); @@ -164,7 +154,6 @@ public final class UtilityClassWithoutPrivateConstructorInspection extends BaseI @Override public void visitClass(@NotNull PsiClass aClass) { - // no call to super, so that it doesn't drill down to inner classes if (aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { return; } @@ -183,10 +172,8 @@ public final class UtilityClassWithoutPrivateConstructorInspection extends BaseI if (aClass.hasModifierProperty(PsiModifier.PRIVATE) && aClass.getConstructors().length == 0) { return; } - final SearchScope scope = GlobalSearchScope.projectScope(aClass.getProject()); - final Query query = ClassInheritorsSearch.search(aClass, scope, true); - final PsiClass subclass = query.findFirst(); - if (subclass != null) { + boolean hasInheritor = ClassInheritorsSearch.search(aClass, aClass.getUseScope(), true).findFirst() != null; + if (hasInheritor) { return; } registerClassError(aClass, aClass); @@ -198,33 +185,20 @@ public final class UtilityClassWithoutPrivateConstructorInspection extends BaseI return false; } for (PsiMethod method : methods) { - if (method.isConstructor()) { + if (method.isConstructor() || method.hasModifierProperty(PsiModifier.PRIVATE)) { continue; } - if (!method.hasModifierProperty(PsiModifier.STATIC)) { + if (!method.hasModifierProperty(PsiModifier.STATIC) || !method.hasModifierProperty(PsiModifier.PUBLIC)) { return false; } - if (method.hasModifierProperty(PsiModifier.PRIVATE)) { - continue; - } - if (!method.hasModifierProperty(PsiModifier.PUBLIC)) { - return false; - } - final String name = method.getName(); - if (!name.equals(HardcodedMethodConstants.MAIN)) { - return false; - } - final PsiType returnType = method.getReturnType(); - if (!PsiTypes.voidType().equals(returnType)) { + if (!HardcodedMethodConstants.MAIN.equals(method.getName()) || !PsiTypes.voidType().equals(method.getReturnType())) { return false; } final PsiParameterList parameterList = method.getParameterList(); if (parameterList.getParametersCount() != 1) { return false; } - final PsiParameter[] parameters = parameterList.getParameters(); - final PsiParameter parameter = parameters[0]; - final PsiType type = parameter.getType(); + final PsiType type = parameterList.getParameters()[0].getType(); final @NonNls String stringArray = "java.lang.String[]"; if (!type.equalsToText(stringArray)) { return false; @@ -234,8 +208,7 @@ public final class UtilityClassWithoutPrivateConstructorInspection extends BaseI } boolean hasPrivateConstructor(PsiClass aClass) { - final PsiMethod[] constructors = aClass.getConstructors(); - for (final PsiMethod constructor : constructors) { + for (PsiMethod constructor : aClass.getConstructors()) { if (constructor.hasModifierProperty(PsiModifier.PRIVATE)) { return true; }