[java, import-module] Replace 'import module' with class imports in module-info.java (IDEA-367505)

GitOrigin-RevId: 8a0ba58ca14698f553fdd6baf132d00d7ba0e504
This commit is contained in:
Aleksey Dobrynin
2025-02-14 01:09:59 +00:00
committed by intellij-monorepo-bot
parent d208f217ca
commit d41422ac8f
5 changed files with 54 additions and 9 deletions
@@ -1,4 +1,4 @@
// 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.intellij.codeInsight.intention;
import com.intellij.codeInspection.LocalQuickFix;
@@ -516,4 +516,6 @@ public abstract class QuickFixFactory {
@ApiStatus.Experimental
public abstract @NotNull IntentionAction createAddMainMethodFix(@NotNull PsiImplicitClass implicitClass);
public abstract @NotNull ModCommandAction createReplaceOnDemandImport(@NotNull PsiImportModuleStatement importModuleStatement, @NotNull @Nls String text);
}
@@ -415,6 +415,7 @@ add.annotation.attribute.name=Add ''{0}=''
replace.with.getter.setter=Replace with getter/setter
replace.with.getter=Replace with getter
replace.with.setter=Replace with setter
replace.import.module.fix.text=Replace 'import module' with single class imports
wrap.with.block=Wrap with block
create.block=Create block
@@ -152,6 +152,7 @@ final class JavaErrorFixProvider {
error -> myFactory.createDeleteFix(error.psi(), QuickFixBundle.message("delete.reference.fix.text")));
fix(MODULE_DUPLICATE_OPENS_TARGET,
error -> myFactory.createDeleteFix(error.psi(), QuickFixBundle.message("delete.reference.fix.text")));
fix(MODULE_IMPORT_STATEMENT_NOT_ALLOWED, error -> myFactory.createReplaceOnDemandImport(error.psi(), QuickFixBundle.message("replace.import.module.fix.text")));
fix(MODULE_DUPLICATE_IMPLEMENTATION,
error -> myFactory.createDeleteFix(error.psi(), QuickFixBundle.message("delete.reference.fix.text")));
multi(MODULE_NOT_ON_PATH, error -> {
@@ -683,9 +684,9 @@ final class JavaErrorFixProvider {
private void createTypeFixes() {
fixes(TYPE_INCOMPATIBLE, (error, sink) ->
HighlightFixUtil.registerIncompatibleTypeFixes(sink, error.psi(), error.context().lType(), error.context().rType()));
fixes(SWITCH_EXPRESSION_INCOMPATIBLE_TYPE, (error, sink) ->
fixes(SWITCH_EXPRESSION_INCOMPATIBLE_TYPE, (error, sink) ->
HighlightFixUtil.registerIncompatibleTypeFixes(sink,
requireNonNull(PsiTreeUtil.getParentOfType(error.psi(), PsiSwitchExpression.class)),
requireNonNull(PsiTreeUtil.getParentOfType(error.psi(), PsiSwitchExpression.class)),
error.context().lType(), error.context().rType()));
fixes(CALL_TYPE_INFERENCE_ERROR, (error, sink) -> {
if (error.psi() instanceof PsiMethodCallExpression callExpression) {
@@ -1,4 +1,4 @@
// 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.intellij.codeInsight.intention.impl.config;
import com.intellij.codeInsight.CodeInsightWorkspaceSettings;
@@ -31,10 +31,7 @@ import com.intellij.java.JavaBundle;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.lang.java.request.CreateConstructorFromUsage;
import com.intellij.lang.java.request.CreateMethodFromUsage;
import com.intellij.modcommand.ActionContext;
import com.intellij.modcommand.ModCommandAction;
import com.intellij.modcommand.Presentation;
import com.intellij.modcommand.PsiBasedModCommandAction;
import com.intellij.modcommand.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
@@ -43,6 +40,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.NonPhysicalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
@@ -62,6 +60,7 @@ import com.intellij.util.ThreeState;
import com.intellij.util.concurrency.ThreadingAssertions;
import com.siyeh.ig.controlflow.UnnecessaryDefaultInspection;
import com.siyeh.ig.fixes.*;
import com.siyeh.ipp.imports.ReplaceOnDemandImportIntention;
import com.siyeh.ipp.modifiers.ChangeModifierIntention;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -1150,4 +1149,29 @@ public final class QuickFixFactoryImpl extends QuickFixFactory {
public @NotNull IntentionAction createAddMainMethodFix(@NotNull PsiImplicitClass implicitClass) {
return new AddMainMethodFix(implicitClass).asIntention();
}
@Override
public @NotNull ModCommandAction createReplaceOnDemandImport(@NotNull PsiImportModuleStatement importModuleStatement, @NotNull @Nls String text) {
return new ReplaceOnDemandImportAction(importModuleStatement, text);
}
private static class ReplaceOnDemandImportAction extends PsiUpdateModCommandAction<PsiImportModuleStatement> {
@NlsSafe private final String text;
private ReplaceOnDemandImportAction(PsiImportModuleStatement element, @NlsSafe String text) {
super(element);
this.text = text;
}
@Override
public @NotNull String getFamilyName() {
return text;
}
@Override
protected void invoke(@NotNull ActionContext context, @NotNull PsiImportModuleStatement element, @NotNull ModPsiUpdater updater) {
element = updater.getWritable(element);
ReplaceOnDemandImportIntention.replaceOnDemand(element);
}
}
}
@@ -84,7 +84,24 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
}
}
fun testModuleImportDeclarationUnresolvedModule() {
fun testModuleImportDeclarationInModuleInfoFileFix() {
IdeaTestUtil.withLevel(module, LanguageLevel.JDK_23_PREVIEW) {
myFixture.configureFromExistingVirtualFile(addFile("module-info.java", """
<error descr="Import module is not allowed">import module <caret>M2;</error>
module my.module {
requires M2;
}
""".trimIndent()))
val availableIntentions = myFixture.availableIntentions
val available = availableIntentions
.map { (it.asModCommandAction() ?: IntentionActionDelegate.unwrap(it))::class.java }
.map { it.simpleName }
assertThat(available).describedAs(availableIntentions.toString()).contains("ReplaceOnDemandImportAction")
}
}
fun testModuleImportDeclarationUnresolvedModule() {
IdeaTestUtil.withLevel(module, LanguageLevel.JDK_23_PREVIEW) {
addFile("moodule-info.java", "module current.module.name {}")
highlight("Test.java", """