[java-inspections] IDEA-360279 Unable to convert a class into implicit declaration when package is present

GitOrigin-RevId: 60ea75dd154ad17728ad9732c1819916cbaf5751
This commit is contained in:
Mikhail Pyltsin
2025-05-09 16:55:32 +02:00
committed by intellij-monorepo-bot
parent d2c5e91c62
commit 0acd402d7f
4 changed files with 129 additions and 17 deletions

View File

@@ -6,13 +6,16 @@ import com.intellij.codeInsight.daemon.impl.UnusedSymbolUtil;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.java.JavaBundle;
import com.intellij.java.codeserver.core.JavaPsiModuleUtil;
import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
import com.intellij.modcommand.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PackageScope;
import com.intellij.psi.search.PsiSearchHelper;
import com.intellij.psi.search.searches.ReferencesSearch;
@@ -57,9 +60,7 @@ public final class ExplicitToImplicitClassMigrationInspection extends AbstractBa
return;
}
PsiJavaFile file = (PsiJavaFile)aClass.getContainingFile();
if (file.getPackageStatement() != null) {
return;
}
boolean underRoot = file.getPackageStatement() == null;
if (file.getClasses().length != 1) {
return;
@@ -114,10 +115,6 @@ public final class ExplicitToImplicitClassMigrationInspection extends AbstractBa
}
Project project = holder.getProject();
PsiPackage aPackage = JavaPsiFacade.getInstance(project).findPackage("");
if (aPackage == null) {
return;
}
PsiIdentifier classIdentifier = aClass.getNameIdentifier();
if (classIdentifier == null) {
return;
@@ -128,7 +125,18 @@ public final class ExplicitToImplicitClassMigrationInspection extends AbstractBa
return;
}
PackageScope scope = new PackageScope(aPackage, false, false);
GlobalSearchScope scope;
if (underRoot) {
PsiPackage aPackage = JavaPsiFacade.getInstance(project).findPackage("");
if (aPackage == null) {
return;
}
scope = new PackageScope(aPackage, false, false);
}
else {
scope = aClass.getResolveScope();
}
if (isOnTheFly) {
final PsiSearchHelper searchHelper = PsiSearchHelper.getInstance(project);
final PsiSearchHelper.SearchCostResult cost =
@@ -146,10 +154,18 @@ public final class ExplicitToImplicitClassMigrationInspection extends AbstractBa
if (PsiTreeUtil.hasErrorElements(aClass)) {
return;
}
holder.registerProblem(aClass, new TextRange(0, classIdentifier.getTextRangeInParent().getEndOffset()),
JavaBundle.message("inspection.explicit.to.implicit.class.migration.name"),
new ReplaceWithImplicitClassFix());
if (underRoot) {
holder.registerProblem(aClass, new TextRange(0, classIdentifier.getTextRangeInParent().getEndOffset()),
JavaBundle.message("inspection.explicit.to.implicit.class.migration.name"),
new ReplaceWithImplicitClassFix());
}
else {
holder.registerProblem(aClass,
JavaBundle.message("inspection.explicit.to.implicit.class.migration.name"),
ProblemHighlightType.INFORMATION,
new TextRange(0, classIdentifier.getTextRangeInParent().getEndOffset()),
new ReplaceWithImplicitClassFix());
}
}
private static boolean onlyObjectExtends(PsiClassType[] types) {
@@ -161,7 +177,7 @@ public final class ExplicitToImplicitClassMigrationInspection extends AbstractBa
}
private static class ReplaceWithImplicitClassFix extends PsiUpdateModCommandQuickFix {
private static class ReplaceWithImplicitClassFix extends ModCommandQuickFix {
@Override
public @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull String getFamilyName() {
@@ -169,11 +185,71 @@ public final class ExplicitToImplicitClassMigrationInspection extends AbstractBa
}
@Override
protected void applyFix(@NotNull Project project, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) {
public final @NotNull ModCommand perform(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement element = descriptor.getStartElement();
PsiFile file = element.getContainingFile();
if (!(file instanceof PsiJavaFile javaFile)) return ModCommand.nop();
PsiPackageStatement statement = javaFile.getPackageStatement();
ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
VirtualFile sourceRoot = fileIndex.getSourceRootForFile(javaFile.getVirtualFile());
if (statement == null || sourceRoot == null) {
return ModCommand
.psiUpdate(element, (e, updater) -> applyFix(project, e));
}
return ModCommand.chooseAction(
JavaBundle.message("inspection.explicit.to.implicit.move.to.root.title"),
getCommandActionWithMovingToRoot(project),
ModCommand.psiUpdateStep(element, JavaBundle.message("inspection.explicit.to.implicit.move.to.root.delete.package"),
(e, updater) -> applyFix(project, e))
);
}
private static @NotNull ModCommandAction getCommandActionWithMovingToRoot(@NotNull Project project) {
return new ModCommandAction() {
@Override
public Presentation getPresentation(@NotNull ActionContext context) {
return Presentation.of(getFamilyName());
}
@Override
public @NotNull ModCommand perform(@NotNull ActionContext context) {
int offset = context.offset();
PsiElement element = context.file().findElementAt(offset);
if (element == null) return ModCommand.nop();
PsiClass psiClass = PsiTreeUtil.getParentOfType(element, PsiClass.class, false);
if (psiClass == null) return ModCommand.nop();
PsiFile containingFile = psiClass.getContainingFile();
if (containingFile == null) return ModCommand.nop();
ModCommand modCommand = ModCommand
.psiUpdate(psiClass, (e, updater) -> applyFix(project, e));
VirtualFile from = containingFile.getVirtualFile();
ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
VirtualFile sourceRoot = fileIndex.getSourceRootForFile(from);
if (sourceRoot != null) {
modCommand = modCommand
.andThen(
ModCommand.moveFile(from, sourceRoot)
);
}
return modCommand;
}
@Override
public @NotNull String getFamilyName() {
return JavaBundle.message("inspection.explicit.to.implicit.move.to.root.move");
}
};
}
private static void applyFix(@NotNull Project project, @NotNull PsiElement element) {
PsiFile containingFile = element.getContainingFile();
if (!(containingFile instanceof PsiJavaFile javaFile)) {
return;
}
PsiPackageStatement packageStatement = javaFile.getPackageStatement();
if (packageStatement != null) {
new CommentTracker().deleteAndRestoreComments(packageStatement);
}
PsiImportList list = javaFile.getImportList();
if (list != null) {
List<SmartPsiElementPointer<PsiImportStatementBase>> pointers = new ArrayList<>();