MoveToPackageFix: suggest move inheritor to sealed parents' package when parent in unnamed module and in different package (IDEA-243904)

GitOrigin-RevId: 8fd0c7bdcc69b5a664d458acc8ab74b2aa1fe005
This commit is contained in:
Artemiy Sartakov
2020-07-28 05:37:37 +00:00
committed by intellij-monorepo-bot
parent 51d219a9a5
commit cb146f0b02
6 changed files with 75 additions and 18 deletions
@@ -485,4 +485,6 @@ public abstract class QuickFixFactory {
*/
@NotNull
public abstract IntentionAction createAddToPermitsListFix(@NotNull PsiClass subClass, @NotNull PsiClass superClass);
public abstract IntentionAction createMoveClassToPackageFix(@NotNull PsiClass classToMove, @NotNull String packageName);
}
@@ -1094,10 +1094,16 @@ public final class HighlightClassUtil {
}
else {
if (currentModule == null && !psiFacade.arePackagesTheSame(aClass, inheritorClass)) {
holder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
.range(permitted)
.descriptionAndTooltip(JavaErrorBundle.message("class.not.allowed.to.extend.sealed.class.from.another.package"))
.create());
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
.range(permitted)
.descriptionAndTooltip(JavaErrorBundle.message("class.not.allowed.to.extend.sealed.class.from.another.package"))
.create();
PsiFile parentFile = aClass.getContainingFile();
if (parentFile instanceof PsiClassOwner) {
String parentPackage = ((PsiClassOwner)parentFile).getPackageName();
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createMoveClassToPackageFix(inheritorClass, parentPackage));
}
holder.add(info);
}
else if (currentModule != null && currentModule != JavaModuleGraphUtil.findDescriptorByElement(inheritorClass)) {
holder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
@@ -941,4 +941,9 @@ public final class QuickFixFactoryImpl extends QuickFixFactory {
@NotNull PsiClass superClass) {
return new AddToPermitsListFix(subClass, superClass);
}
@Override
public IntentionAction createMoveClassToPackageFix(@NotNull PsiClass classToMove, @NotNull String packageName) {
return new MoveToPackageFix(classToMove.getContainingFile(), packageName);
}
}
@@ -18,7 +18,9 @@ package com.intellij.codeInspection;
import com.intellij.CommonBundle;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInspection.util.IntentionName;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.*;
@@ -29,18 +31,19 @@ import com.intellij.refactoring.move.moveClassesOrPackages.SingleSourceRootMoveD
import com.intellij.refactoring.util.RefactoringMessageUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class MoveToPackageFix implements LocalQuickFix {
public class MoveToPackageFix extends LocalQuickFixAndIntentionActionOnPsiElement {
private static final Logger LOG = Logger.getInstance(MoveToPackageFix.class);
private final String myTargetPackage;
public MoveToPackageFix(String targetPackage) {
public MoveToPackageFix(PsiFile psiFile, String targetPackage) {
super(psiFile);
myTargetPackage = targetPackage;
}
@Override
@NotNull
public String getName() {
public @IntentionName @NotNull String getText() {
return QuickFixBundle.message("move.class.to.package.text", myTargetPackage);
}
@@ -60,15 +63,12 @@ public class MoveToPackageFix implements LocalQuickFix {
}
@Override
public boolean startInWriteAction() {
return false;
}
@Override
public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
PsiElement element = descriptor.getPsiElement();
if (element == null) return;
final PsiFile myFile = element.getContainingFile();
public void invoke(@NotNull Project project,
@NotNull PsiFile file,
@Nullable Editor editor,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
final PsiFile myFile = startElement.getContainingFile();
if (!FileModificationService.getInstance().prepareFileForWrite(myFile)) return;
@@ -103,4 +103,9 @@ public class MoveToPackageFix implements LocalQuickFix {
LOG.error(e);
}
}
@Override
public boolean startInWriteAction() {
return false;
}
}
@@ -33,7 +33,7 @@ import java.util.List;
public class WrongPackageStatementInspection extends AbstractBaseJavaLocalInspectionTool {
protected void addMoveToPackageFix(PsiFile file, String packName, List<? super LocalQuickFix> availableFixes) {
MoveToPackageFix moveToPackageFix = new MoveToPackageFix(packName);
MoveToPackageFix moveToPackageFix = new MoveToPackageFix(file, packName);
if (moveToPackageFix.isAvailable(file)) {
availableFixes.add(moveToPackageFix);
}
@@ -0,0 +1,39 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.codeInsight.daemon.quickFix;
import com.intellij.psi.PsiClass;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull;
public class MoveToPackageTest extends LightJavaCodeInsightFixtureTestCase {
@Override
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
return LightJavaCodeInsightFixtureTestCase.JAVA_15;
}
public void testSimple() {
PsiClass bClass = myFixture.addClass("package foo;\nimport bar.A;\npublic final class B extends A {}");
myFixture.configureByText("A.java", "package bar;\n import foo.B;\npublic sealed class A permits <caret>B {}");
invokeFix("Move to package 'bar'");
assertEquals("package bar;\nimport bar.A;\npublic final class B extends A {}", bClass.getContainingFile().getText());
}
public void testNestedClass() {
PsiClass bClass = myFixture.addClass("package foo;\nimport bar.A;\npublic class B { public static final class C extends A {} }");
myFixture.configureByText("A.java", "package bar;\n import foo.B;\npublic sealed class A permits <caret>B.C {}");
invokeFix("Move to package 'bar'");
assertEquals("package bar;\nimport bar.A;\npublic class B { public static final class C extends A {} }",
bClass.getContainingFile().getText());
}
public void testNonAccessibleClass() {
myFixture.addClass("package foo;\nimport bar.A;\nfinal class B extends A {}");
myFixture.configureByText("A.java", "package bar;\n import foo.B;\npublic sealed class A permits <caret>B {}");
assertEmpty(myFixture.filterAvailableIntentions("Move to package 'bar'"));
}
private void invokeFix(@NotNull String hint) {
myFixture.launchAction(myFixture.findSingleIntention(hint));
}
}