mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java] fix to move a class with unresolved reference on the test library from production to the test root (IDEA-278923)
GitOrigin-RevId: d7c792d91997dd2ab6311783ddefe75ef7d4c913
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b36789d9ee
commit
ad3c351ee5
+36
-7
@@ -6,7 +6,9 @@ import com.intellij.codeInsight.daemon.impl.actions.AddImportAction;
|
||||
import com.intellij.codeInsight.daemon.quickFix.ExternalLibraryResolver;
|
||||
import com.intellij.codeInsight.daemon.quickFix.ExternalLibraryResolver.ExternalClassResolveResult;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInsight.intention.PriorityAction;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.MoveToTestRootFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
@@ -141,6 +143,7 @@ public abstract class OrderEntryFix implements IntentionAction, LocalQuickFix {
|
||||
Map<Library, String> librariesToAdd = new HashMap<>();
|
||||
Set<VirtualFile> jars = new HashSet<>();
|
||||
Set<Library> excluded = new HashSet<>();
|
||||
Set<Library> withTestScope = new HashSet<>();
|
||||
ModuleFileIndex moduleFileIndex = ModuleRootManager.getInstance(currentModule).getFileIndex();
|
||||
for (PsiClass aClass : allowedDependencies) {
|
||||
if (!facade.getResolveHelper().isAccessible(aClass, psiElement, aClass)) continue;
|
||||
@@ -166,11 +169,16 @@ public abstract class OrderEntryFix implements IntentionAction, LocalQuickFix {
|
||||
continue;
|
||||
}
|
||||
OrderEntry entryForFile = moduleFileIndex.getOrderEntryForFile(virtualFile);
|
||||
if (entryForFile != null &&
|
||||
!(entryForFile instanceof ExportableOrderEntry &&
|
||||
((ExportableOrderEntry)entryForFile).getScope() == DependencyScope.TEST &&
|
||||
!moduleFileIndex.isInTestSourceContent(refVFile))) {
|
||||
excluded.add(library);
|
||||
if (entryForFile != null) {
|
||||
boolean testScopeLibraryInProduction = entryForFile instanceof ExportableOrderEntry &&
|
||||
((ExportableOrderEntry)entryForFile).getScope() == DependencyScope.TEST &&
|
||||
!moduleFileIndex.isInTestSourceContent(refVFile);
|
||||
if (testScopeLibraryInProduction) {
|
||||
withTestScope.add(library);
|
||||
}
|
||||
else {
|
||||
excluded.add(library);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,10 +186,30 @@ public abstract class OrderEntryFix implements IntentionAction, LocalQuickFix {
|
||||
excluded.forEach(librariesToAdd::remove);
|
||||
|
||||
if (!librariesToAdd.isEmpty()) {
|
||||
OrderEntryFix fix = new AddLibraryDependencyFix(reference, currentModule, librariesToAdd, scope, false);
|
||||
class AddLibraryFix extends AddLibraryDependencyFix implements PriorityAction {
|
||||
AddLibraryFix(PsiReference reference,
|
||||
Module currentModule,
|
||||
Map<Library, String> libraries, DependencyScope scope, boolean exported) {
|
||||
super(reference, currentModule, libraries, scope, exported);
|
||||
}
|
||||
@Override
|
||||
public @NotNull Priority getPriority() {
|
||||
return withTestScope.isEmpty() ? Priority.NORMAL : Priority.LOW;
|
||||
}
|
||||
}
|
||||
OrderEntryFix fix = new AddLibraryFix(reference, currentModule, librariesToAdd, scope, false);
|
||||
registrar.register(fix);
|
||||
result.add(fix);
|
||||
}
|
||||
|
||||
if (!withTestScope.isEmpty()) {
|
||||
MoveToTestRootFix fix = new MoveToTestRootFix(containingFile);
|
||||
if (fix.isAvailable(containingFile)) {
|
||||
registrar.register(fix);
|
||||
result.add(fix);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -262,7 +290,8 @@ public abstract class OrderEntryFix implements IntentionAction, LocalQuickFix {
|
||||
facade.findClass(resolveResult.getQualifiedClassName(), currentModule.getModuleWithDependenciesAndLibrariesScope(true)) == null) {
|
||||
fix = new AddExtLibraryDependencyFix(reference, currentModule, resolveResult.getLibrary(), scope, resolveResult.getQualifiedClassName());
|
||||
}
|
||||
else if (!fullReferenceText.equals(shortReferenceName)) {
|
||||
else if (!fullReferenceText.equals(shortReferenceName) &&
|
||||
facade.findClass(fullReferenceText, currentModule.getModuleWithDependenciesAndLibrariesScope(true)) == null) {
|
||||
ExternalLibraryDescriptor descriptor = resolver.resolvePackage(fullReferenceText);
|
||||
if (descriptor != null) {
|
||||
fix = new AddExtLibraryDependencyFix(reference, currentModule, descriptor, scope, null);
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInspection;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.codeInspection.util.IntentionName;
|
||||
import com.intellij.ide.util.DirectoryChooser;
|
||||
import com.intellij.java.JavaBundle;
|
||||
import com.intellij.java.refactoring.JavaRefactoringBundle;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtilCore;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ContentFolder;
|
||||
import com.intellij.openapi.roots.ModuleFileIndex;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.roots.SourceFolder;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.refactoring.PackageWrapper;
|
||||
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesProcessor;
|
||||
import com.intellij.refactoring.move.moveClassesOrPackages.SingleSourceRootMoveDestination;
|
||||
import com.intellij.refactoring.util.RefactoringMessageUtil;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class MoveToTestRootFix extends LocalQuickFixAndIntentionActionOnPsiElement {
|
||||
private static final Logger LOG = Logger.getInstance(MoveToTestRootFix.class);
|
||||
|
||||
public MoveToTestRootFix(PsiFile psiFile) {
|
||||
super(psiFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @IntentionName @NotNull String getText() {
|
||||
PsiFile containingFile = getStartElement().getContainingFile();
|
||||
if (containingFile instanceof PsiClassOwner) {
|
||||
PsiClass[] classes = ((PsiClassOwner)containingFile).getClasses();
|
||||
if (classes.length > 0) {
|
||||
return JavaBundle.message("intention.name.move.class.to.test.root", classes[0].getName());
|
||||
}
|
||||
}
|
||||
return getFamilyName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return JavaBundle.message("intention.family.name.move.class.to.test.root");
|
||||
}
|
||||
|
||||
public boolean isAvailable(PsiFile file) {
|
||||
if (file == null || !file.isValid()) return false;
|
||||
VirtualFile virtualFile = PsiUtilCore.getVirtualFile(file);
|
||||
if (virtualFile == null) return false;
|
||||
Module module = ModuleUtilCore.findModuleForFile(virtualFile, file.getProject());
|
||||
if (module == null) return false;
|
||||
ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
|
||||
ModuleFileIndex fileIndex = rootManager.getFileIndex();
|
||||
if (!fileIndex.isInSourceContent(virtualFile)) return false;
|
||||
return getTestRoots(rootManager).findFirst().isPresent();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Stream<SourceFolder> getTestRoots(ModuleRootManager rootManager) {
|
||||
return Arrays.stream(rootManager.getContentEntries())
|
||||
.flatMap(entry -> Arrays.stream(entry.getSourceFolders()))
|
||||
.filter(SourceFolder::isTestSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
Module module = ModuleUtilCore.findModuleForFile(myFile);
|
||||
Stream<SourceFolder> testRoots = getTestRoots(ModuleRootManager.getInstance(Objects.requireNonNull(module)));
|
||||
|
||||
DirectoryChooser chooser = new DirectoryChooser(project);
|
||||
chooser.setTitle(JavaRefactoringBundle.message("select.source.root.chooser.title"));
|
||||
|
||||
PsiManager manager = myFile.getManager();
|
||||
|
||||
PsiDirectory[] directories = testRoots.map(ContentFolder::getFile).filter(Objects::nonNull)
|
||||
.map(vFile -> manager.findDirectory(vFile))
|
||||
.filter(Objects::nonNull).toArray(PsiDirectory[]::new);
|
||||
chooser.fillList(directories, null, project, "");
|
||||
if (!chooser.showAndGet()) {
|
||||
return;
|
||||
}
|
||||
PsiDirectory sourceRoot = chooser.getSelectedDirectory();
|
||||
if (sourceRoot == null) return;
|
||||
|
||||
PsiPackage targetPackage = JavaDirectoryService.getInstance().getPackage(myFile.getContainingDirectory());
|
||||
|
||||
PackageWrapper wrapper = PackageWrapper.create(targetPackage);
|
||||
|
||||
PsiDirectory selectedDirectory = WriteAction.compute(() -> RefactoringUtil.createPackageDirectoryInSourceRoot(wrapper, sourceRoot.getVirtualFile()));
|
||||
|
||||
try {
|
||||
String error;
|
||||
try {
|
||||
error = RefactoringMessageUtil.checkCanCreateFile(selectedDirectory, myFile.getName());
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
error = e.getLocalizedMessage();
|
||||
}
|
||||
|
||||
if (error != null) {
|
||||
Messages.showMessageDialog(project, error, CommonBundle.getErrorTitle(), Messages.getErrorIcon());
|
||||
return;
|
||||
}
|
||||
|
||||
new MoveClassesOrPackagesProcessor(
|
||||
project,
|
||||
((PsiJavaFile) myFile).getClasses(),
|
||||
new SingleSourceRootMoveDestination(wrapper, selectedDirectory), false,
|
||||
false,
|
||||
null).run();
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startInWriteAction() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1687,3 +1687,5 @@ javadoc.documentation.url.checked=The following documentation {0, choice, 1#URL
|
||||
javadoc.edit.api.docs.paths=Edit API docs paths
|
||||
intention.family.name.edit.color.settings=Edit color settings for reassigned variable
|
||||
intention.name.edit.color.settings=Edit ''{0}'' color settings
|
||||
intention.family.name.move.class.to.test.root=Move class to test root
|
||||
intention.name.move.class.to.test.root=Move ''{0}'' to test root
|
||||
|
||||
Reference in New Issue
Block a user