mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 22:51:17 +07:00
[java-intentions] IDEA-370071 Convert Java 'Optimize imports' action to ModCommand
GitOrigin-RevId: 5d6b55225f3b87f9a2b10599c6a6a3deeec3200f
This commit is contained in:
committed by
intellij-monorepo-bot
parent
360ae51ffe
commit
7ddc26cb54
@@ -282,7 +282,7 @@ public abstract class QuickFixFactory {
|
||||
|
||||
public abstract @NotNull IntentionAction createCreateAnnotationMethodFromUsageFix(@NotNull PsiNameValuePair pair);
|
||||
|
||||
public abstract @NotNull IntentionAction createOptimizeImportsFix(boolean fixOnTheFly, @NotNull PsiFile file);
|
||||
public abstract @NotNull ModCommandAction createOptimizeImportsFix(boolean fixOnTheFly, @NotNull PsiFile file);
|
||||
|
||||
public abstract @NotNull IntentionAction createSafeDeleteUnusedParameterInHierarchyFix(@NotNull PsiParameter parameter, boolean excludingHierarchy);
|
||||
|
||||
|
||||
@@ -1,17 +1,24 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.daemon.impl.analysis;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
|
||||
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerEx;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.modcommand.ActionContext;
|
||||
import com.intellij.modcommand.ModCommand;
|
||||
import com.intellij.modcommand.ModCommandAction;
|
||||
import com.intellij.modcommand.ModCommandExecutor;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.AppUIExecutor;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.components.Service;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.PsiTreeAnyChangeAbstractAdapter;
|
||||
import com.intellij.util.concurrency.AppExecutorUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -27,7 +34,9 @@ import java.util.List;
|
||||
final class OptimizeImportRestarter implements Disposable {
|
||||
private final Project myProject;
|
||||
private final List<OptimizeRequest> queue = new ArrayList<>(); // guarded by queue
|
||||
private record OptimizeRequest(@NotNull PsiFile psiFile, long modificationStampBefore, @NotNull IntentionAction optimizeFix) {}
|
||||
|
||||
private record OptimizeRequest(@NotNull PsiFile psiFile, long modificationStampBefore, @NotNull ModCommandAction optimizeFix) {
|
||||
}
|
||||
|
||||
static OptimizeImportRestarter getInstance(Project project) {
|
||||
return project.getService(OptimizeImportRestarter.class);
|
||||
@@ -74,26 +83,25 @@ final class OptimizeImportRestarter implements Disposable {
|
||||
if (!psiFile.isWritable()) {
|
||||
continue;
|
||||
}
|
||||
ModCommandAction optimizeFix = request.optimizeFix();
|
||||
if (!DaemonCodeAnalyzerEx.getInstanceEx(myProject).isErrorAnalyzingFinished(psiFile)) {
|
||||
// re-fire when daemon is really finished
|
||||
scheduleOnDaemonFinish(psiFile, request.optimizeFix());
|
||||
scheduleOnDaemonFinish(psiFile, optimizeFix);
|
||||
continue;
|
||||
}
|
||||
// later because should invoke when highlighting is finished (OptimizeImportsFix relies on that)
|
||||
AppUIExecutor.onUiThread().later().withDocumentsCommitted(myProject).execute(() -> {
|
||||
if (myProject.isDisposed()) return;
|
||||
long stampAfter = psiFile.getModificationStamp();
|
||||
if (stampAfter != request.modificationStampBefore()) {
|
||||
return;
|
||||
}
|
||||
if (request.optimizeFix().isAvailable(myProject, null, psiFile)) {
|
||||
request.optimizeFix().invoke(myProject, null, psiFile);
|
||||
}
|
||||
});
|
||||
ActionContext context = ActionContext.from(null, psiFile);
|
||||
if (optimizeFix.getPresentation(context) == null) continue;
|
||||
ReadAction.nonBlocking(() -> optimizeFix.getPresentation(context) != null ? optimizeFix.perform(context) : ModCommand.nop())
|
||||
.expireWhen(() -> myProject.isDisposed() || psiFile.getModificationStamp() != request.modificationStampBefore())
|
||||
.finishOnUiThread(ModalityState.defaultModalityState(),
|
||||
command -> CommandProcessor.getInstance().executeCommand(
|
||||
myProject, () -> ModCommandExecutor.getInstance().executeInBatch(context, command),
|
||||
CodeInsightBundle.message("process.optimize.imports"), null))
|
||||
.submit(AppExecutorUtil.getAppExecutorService());
|
||||
}
|
||||
}
|
||||
|
||||
void scheduleOnDaemonFinish(@NotNull PsiFile psiFile, @NotNull IntentionAction optimizeFix) {
|
||||
void scheduleOnDaemonFinish(@NotNull PsiFile psiFile, @NotNull ModCommandAction optimizeFix) {
|
||||
long modificationStampBefore = psiFile.getModificationStamp();
|
||||
synchronized (queue) {
|
||||
queue.add(new OptimizeRequest(psiFile, modificationStampBefore, optimizeFix));
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.intellij.codeInspection.unusedImport.UnusedImportInspection;
|
||||
import com.intellij.java.analysis.JavaAnalysisBundle;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.lang.annotation.ProblemGroup;
|
||||
import com.intellij.modcommand.ModCommandAction;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.colors.TextAttributesKey;
|
||||
@@ -75,9 +76,9 @@ class UnusedImportsVisitor extends JavaElementVisitor {
|
||||
FileStatusMap fileStatusMap = daemonCodeAnalyzer.getFileStatusMap();
|
||||
fileStatusMap.setErrorFoundFlag(myDocument, myContext, true);
|
||||
}
|
||||
IntentionAction fixNotOnFly = null;
|
||||
ModCommandAction fixNotOnFly = null;
|
||||
if (requiresFix) {
|
||||
IntentionAction fix = QuickFixFactory.getInstance().createOptimizeImportsFix(true, myFile);
|
||||
ModCommandAction fix = QuickFixFactory.getInstance().createOptimizeImportsFix(true, myFile);
|
||||
OptimizeImportRestarter.getInstance(myProject).scheduleOnDaemonFinish(myFile, fix);
|
||||
fixNotOnFly = QuickFixFactory.getInstance().createOptimizeImportsFix(false, myFile);
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
package com.intellij.codeInspection.unusedImport;
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInsight.intention.QuickFixFactory;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.java.analysis.JavaAnalysisBundle;
|
||||
import com.intellij.modcommand.ModCommandAction;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiImportList;
|
||||
@@ -41,7 +41,8 @@ public final class MissortedImportsInspection extends GlobalSimpleInspectionTool
|
||||
@NotNull ProblemDescriptionsProcessor problemDescriptionsProcessor) {
|
||||
if (!(file instanceof PsiJavaFile javaFile) || FileTypeUtils.isInServerPageFile(file)) return;
|
||||
PsiImportList importList = javaFile.getImportList();
|
||||
PsiImportStatementBase[] imports = importList == null ? PsiImportStatementBase.EMPTY_ARRAY : importList.getAllImportStatements();
|
||||
if (importList == null) return;
|
||||
PsiImportStatementBase[] imports = importList.getAllImportStatements();
|
||||
int currentEntryIndex = 0;
|
||||
for (PsiImportStatementBase importStatement : imports) {
|
||||
ProgressManager.checkCanceled();
|
||||
@@ -52,8 +53,8 @@ public final class MissortedImportsInspection extends GlobalSimpleInspectionTool
|
||||
int entryIndex = JavaCodeStyleManager.getInstance(javaFile.getProject()).findEntryIndex(importStatement);
|
||||
if (entryIndex < currentEntryIndex) {
|
||||
// mis-sorted import found
|
||||
IntentionAction fix = QuickFixFactory.getInstance().createOptimizeImportsFix(false, javaFile);
|
||||
problemsHolder.registerProblem(importList, getDisplayNameText(), new IntentionWrapper(fix));
|
||||
ModCommandAction fix = QuickFixFactory.getInstance().createOptimizeImportsFix(false, javaFile);
|
||||
problemsHolder.problem(importList, getDisplayNameText()).fix(fix).register();
|
||||
return;
|
||||
}
|
||||
currentEntryIndex = entryIndex;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
package com.intellij.codeInsight.intention.impl.config;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightWorkspaceSettings;
|
||||
import com.intellij.codeInsight.actions.OptimizeImportsProcessor;
|
||||
import com.intellij.codeInsight.daemon.JavaErrorBundle;
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle;
|
||||
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerEx;
|
||||
@@ -29,17 +28,16 @@ import com.intellij.diagnostic.CoreAttachmentFactory;
|
||||
import com.intellij.ide.scratch.ScratchUtil;
|
||||
import com.intellij.java.JavaBundle;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.lang.java.JavaImportOptimizer;
|
||||
import com.intellij.lang.java.request.CreateConstructorFromUsage;
|
||||
import com.intellij.lang.java.request.CreateMethodFromUsage;
|
||||
import com.intellij.modcommand.*;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
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.util.Comparing;
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.NonPhysicalFileSystem;
|
||||
@@ -53,8 +51,6 @@ import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PropertyMemberType;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.refactoring.JavaRefactoringActionHandlerFactory;
|
||||
import com.intellij.util.DocumentUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.ThreeState;
|
||||
import com.intellij.util.concurrency.ThreadingAssertions;
|
||||
@@ -596,57 +592,58 @@ public final class QuickFixFactoryImpl extends QuickFixFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull IntentionAction createOptimizeImportsFix(final boolean fixOnTheFly, @NotNull PsiFile file) {
|
||||
public @NotNull ModCommandAction createOptimizeImportsFix(final boolean fixOnTheFly, @NotNull PsiFile file) {
|
||||
ApplicationManager.getApplication().assertIsNonDispatchThread();
|
||||
VirtualFile virtualFile = file.getVirtualFile();
|
||||
boolean isInContent = virtualFile != null && (ModuleUtilCore.projectContainsFile(file.getProject(), virtualFile, false) || ScratchUtil.isScratch(virtualFile));
|
||||
return new OptimizeImportsFix(fixOnTheFly, isInContent, virtualFile == null ? ThreeState.UNSURE : SilentChangeVetoer.extensionsAllowToChangeFileSilently(file.getProject(), virtualFile));
|
||||
}
|
||||
|
||||
private static final class OptimizeImportsFix implements IntentionAction {
|
||||
private static final class OptimizeImportsFix implements ModCommandAction {
|
||||
private final boolean myOnTheFly;
|
||||
private final boolean myInContent;
|
||||
private final ThreeState extensionsAllowToChangeFileSilently;
|
||||
|
||||
private OptimizeImportsFix(boolean onTheFly, boolean isInContent, @NotNull ThreeState extensionsAllowToChangeFileSilently) {
|
||||
this.extensionsAllowToChangeFileSilently = extensionsAllowToChangeFileSilently;
|
||||
ApplicationManager.getApplication().assertIsNonDispatchThread();
|
||||
myOnTheFly = onTheFly;
|
||||
myInContent = isInContent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getText() {
|
||||
return QuickFixBundle.message("optimize.imports.fix");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getFamilyName() {
|
||||
return QuickFixBundle.message("optimize.imports.fix");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
public @Nullable Presentation getPresentation(@NotNull ActionContext context) {
|
||||
PsiFile file = context.file();
|
||||
if (!(file instanceof PsiJavaFile)) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
if (ApplicationManager.getApplication().isDispatchThread() && myOnTheFly && !timeToOptimizeImports(file, myInContent, extensionsAllowToChangeFileSilently)) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
VirtualFile virtualFile = file.getViewProvider().getVirtualFile();
|
||||
return myInContent ||
|
||||
ScratchUtil.isScratch(virtualFile) ||
|
||||
virtualFile.getFileSystem() instanceof NonPhysicalFileSystem;
|
||||
boolean available = myInContent ||
|
||||
ScratchUtil.isScratch(virtualFile) ||
|
||||
virtualFile.getFileSystem() instanceof NonPhysicalFileSystem;
|
||||
return available ? Presentation.of(getFamilyName()) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(final @NotNull Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {
|
||||
invokeOnTheFlyImportOptimizer(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startInWriteAction() {
|
||||
return true;
|
||||
public @NotNull ModCommand perform(@NotNull ActionContext context) {
|
||||
PsiFile file = context.file();
|
||||
ModCommand command = ModCommand.psiUpdate(file, f -> {
|
||||
new JavaImportOptimizer().processFile(f).run();
|
||||
});
|
||||
if (command.isEmpty()) {
|
||||
VirtualFile vFile = file.getViewProvider().getVirtualFile();
|
||||
LOG.error("Import optimizer hasn't optimized any imports",
|
||||
new Throwable(vFile.getPath()),
|
||||
CoreAttachmentFactory.createAttachment(vFile));
|
||||
}
|
||||
return command;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,24 +727,6 @@ public final class QuickFixFactoryImpl extends QuickFixFactory {
|
||||
return OrderEntryFix.registerFixes(reference, registrar);
|
||||
}
|
||||
|
||||
private static void invokeOnTheFlyImportOptimizer(@NotNull PsiFile file) {
|
||||
final Project project = file.getProject();
|
||||
final Document document = PsiDocumentManager.getInstance(project).getDocument(file);
|
||||
if (document == null) return;
|
||||
|
||||
String beforeText = file.getText();
|
||||
long oldStamp = document.getModificationStamp();
|
||||
DocumentUtil.writeInRunUndoTransparentAction(() -> new OptimizeImportsProcessor(project, file).run());
|
||||
if (oldStamp != document.getModificationStamp()) {
|
||||
String afterText = file.getText();
|
||||
if (Comparing.strEqual(beforeText, afterText)) {
|
||||
LOG.error("Import optimizer hasn't optimized any imports",
|
||||
new Throwable(file.getViewProvider().getVirtualFile().getPath()),
|
||||
CoreAttachmentFactory.createAttachment(file.getViewProvider().getVirtualFile()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull IntentionAction createAddMissingRequiredAnnotationParametersFix(final @NotNull PsiAnnotation annotation,
|
||||
final PsiMethod @NotNull [] annotationMethods,
|
||||
|
||||
@@ -41,10 +41,8 @@ public final class JavaImportOptimizer implements ImportOptimizer {
|
||||
public void run() {
|
||||
try {
|
||||
final PsiDocumentManager manager = PsiDocumentManager.getInstance(file.getProject());
|
||||
final Document document = manager.getDocument(file);
|
||||
if (document != null) {
|
||||
manager.commitDocument(document);
|
||||
}
|
||||
final Document document = file.getFileDocument();
|
||||
manager.commitDocument(document);
|
||||
final PsiImportList oldImportList = ((PsiJavaFile)file).getImportList();
|
||||
assert oldImportList != null;
|
||||
final List<String> oldImports = new ArrayList<>();
|
||||
|
||||
@@ -400,7 +400,7 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase {
|
||||
myFixture.type('A'); // make file dirty
|
||||
myFixture.type('\b');
|
||||
IntentionAction fix = ReadAction.nonBlocking(() -> QuickFixFactory.getInstance().createOptimizeImportsFix(true, myFixture.getFile())).submit(
|
||||
AppExecutorUtil.getAppExecutorService()).get();
|
||||
AppExecutorUtil.getAppExecutorService()).get().asIntention();
|
||||
myFixture.doHighlighting(); // wait until highlighting is finished to .isAvailable() return true
|
||||
boolean old = CodeInsightWorkspaceSettings.getInstance(myFixture.getProject()).isOptimizeImportsOnTheFly();
|
||||
CodeInsightWorkspaceSettings.getInstance(myFixture.getProject()).setOptimizeImportsOnTheFly(true);
|
||||
|
||||
Reference in New Issue
Block a user