add shouldMakeCurrentFileWritable to intentions and quick fixes

This commit is contained in:
peter
2016-11-18 17:35:50 +01:00
parent 428e6f2799
commit 096640c64e
13 changed files with 118 additions and 40 deletions
@@ -73,6 +73,11 @@ public class IncreaseLanguageLevelFix implements IntentionAction {
JavaProjectModelModificationService.getInstance(project).changeLanguageLevel(module, myLevel);
}
@Override
public boolean shouldMakeCurrentFileWritable() {
return false;
}
@Override
public boolean startInWriteAction() {
return true;
@@ -22,7 +22,6 @@ import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInspection.*;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkModificator;
@@ -209,13 +208,16 @@ public class MagicConstantInspection extends BaseJavaLocalInspectionTool {
return "Attach annotations";
}
@Override
public boolean shouldMakeCurrentFileWritable() {
return false;
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
ApplicationManager.getApplication().runWriteAction(() -> {
SdkModificator modificator = finalJdk.getSdkModificator();
JavaSdkImpl.attachJdkAnnotations(modificator);
modificator.commitChanges();
});
SdkModificator modificator = finalJdk.getSdkModificator();
JavaSdkImpl.attachJdkAnnotations(modificator);
modificator.commitChanges();
}
});
}
@@ -16,7 +16,6 @@
package com.intellij.codeInsight.intention;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.WriteActionAware;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Iconable;
@@ -40,7 +39,7 @@ import org.jetbrains.annotations.NotNull;
*
* @see IntentionManager#registerIntentionAndMetaData(IntentionAction, String...)
*/
public interface IntentionAction extends WriteActionAware {
public interface IntentionAction extends IntentionLike {
IntentionAction[] EMPTY_ARRAY = new IntentionAction[0];
/**
* Returns text to be shown in the list of available actions, if this action
@@ -0,0 +1,42 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.intention;
import com.intellij.openapi.application.WriteActionAware;
/**
* An interface that {@link IntentionAction} and {@link com.intellij.codeInspection.LocalQuickFix} share.
*
* @since 171.*
* @author peter
*/
public interface IntentionLike extends WriteActionAware {
/**
* Controls whether this intention/fix is going to modify the current editor file.
* If {@code true}, and the file is read-only,
* it will be made writable (honoring version control integration) before the intention/fix is invoked.<p/>
*
* By default, as a heuristic, returns the same as {@link #startInWriteAction()}.<p/>
*
* If the action is going to modify multiple files, or the set of the files is unknown in advance, please
* don't bother overriding this method, return {@code false} from {@link #startInWriteAction()}, and call {@link com.intellij.codeInsight.FileModificationService} methods in the implementation, and take write actions yourself as needed.
*/
default boolean shouldMakeCurrentFileWritable() {
return startInWriteAction();
}
}
@@ -61,6 +61,11 @@ public abstract class PriorityActionWrapper extends LocalQuickFixAndIntentionAct
return fix.startInWriteAction();
}
@Override
public boolean shouldMakeCurrentFileWritable() {
return fix.shouldMakeCurrentFileWritable();
}
@NotNull
@Override
public String getText() {
@@ -15,8 +15,10 @@
*/
package com.intellij.codeInspection;
import com.intellij.codeInsight.intention.IntentionLike;
/**
* QuickFix based on {@link com.intellij.codeInspection.ProblemDescriptor ProblemDescriptor}
* QuickFix based on {@link ProblemDescriptor ProblemDescriptor}
* <p/>
* N.B. Please DO NOT store PSI elements inside the LocalQuickFix instance, to avoid holding too much PSI files during inspection.
* Instead, use the {@link ProblemDescriptor#getPsiElement()}
@@ -32,9 +34,9 @@ package com.intellij.codeInspection;
*
* @author max
* @see LocalQuickFixBase
* @see com.intellij.codeInspection.ProblemDescriptor
* @see ProblemDescriptor
* @see com.intellij.openapi.util.Iconable
*/
public interface LocalQuickFix extends QuickFix<ProblemDescriptor> {
public interface LocalQuickFix extends QuickFix<ProblemDescriptor>, IntentionLike {
LocalQuickFix[] EMPTY_ARRAY = new LocalQuickFix[0];
}
@@ -169,6 +169,11 @@ public class ExternalAnnotatorInspectionVisitor extends PsiElementVisitor {
myAction.invoke(project, null, getPsiFile(descriptor));
}
@Override
public boolean shouldMakeCurrentFileWritable() {
return myAction.shouldMakeCurrentFileWritable();
}
@Nullable
private static PsiFile getPsiFile(@NotNull ProblemDescriptor descriptor) {
PsiElement startElement = descriptor.getStartElement();
@@ -95,6 +95,11 @@ public class QuickFixWrapper implements IntentionAction {
return getFix().startInWriteAction();
}
@Override
public boolean shouldMakeCurrentFileWritable() {
return getFix().shouldMakeCurrentFileWritable();
}
public LocalQuickFix getFix() {
return (LocalQuickFix)myDescriptor.getFixes()[myFixNumber];
}
@@ -56,6 +56,11 @@ public abstract class PriorityIntentionActionWrapper implements IntentionAction
action.invoke(project, editor, file);
}
@Override
public boolean shouldMakeCurrentFileWritable() {
return action.shouldMakeCurrentFileWritable();
}
@Override
public boolean startInWriteAction() {
return action.startInWriteAction();
@@ -69,6 +69,11 @@ public class IntentionWrapper implements LocalQuickFix, IntentionAction, ActionC
myAction.invoke(project, editor, file);
}
@Override
public final boolean shouldMakeCurrentFileWritable() {
return myAction.shouldMakeCurrentFileWritable();
}
@Override
public boolean startInWriteAction() {
return myAction.startInWriteAction();
@@ -18,8 +18,6 @@ package com.intellij.codeInsight.daemon.quickFix;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
@@ -96,20 +94,19 @@ public class CreateFileFix extends LocalQuickFixAndIntentionActionOnPsiElement {
return CodeInsightBundle.message("create.file.family");
}
@Override
public boolean shouldMakeCurrentFileWritable() {
return false;
}
@Override
public void invoke(@NotNull final Project project,
@NotNull PsiFile file,
Editor editor,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
final PsiDirectory myDirectory = (PsiDirectory)startElement;
if (isAvailable(project, null, file)) {
new WriteCommandAction(project) {
@Override
protected void run(@NotNull Result result) throws Throwable {
invoke(project, myDirectory);
}
}.execute();
invoke(project, (PsiDirectory)startElement);
}
}
@@ -17,6 +17,7 @@
package com.intellij.codeInsight.intention.impl;
import com.intellij.codeInsight.CodeInsightActionHandler;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl;
import com.intellij.codeInsight.daemon.impl.ShowIntentionsPass;
@@ -35,7 +36,6 @@ import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.application.TransactionGuard;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
@@ -44,7 +44,6 @@ import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.PairProcessor;
import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
@@ -54,7 +53,6 @@ import org.jetbrains.annotations.Nullable;
* @author mike
*/
public class ShowIntentionActionsHandler implements CodeInsightActionHandler {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler");
@Override
public void invoke(@NotNull final Project project, @NotNull Editor editor, @NotNull PsiFile file) {
@@ -178,28 +176,31 @@ public class ShowIntentionActionsHandler implements CodeInsightActionHandler {
FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.quickFix");
((FeatureUsageTrackerImpl)FeatureUsageTracker.getInstance()).getFixesStats().registerInvocation();
final Pair<PsiFile, Editor> pair = chooseFileForAction(hostFile, hostEditor, action);
PsiDocumentManager.getInstance(project).commitAllDocuments();
Pair<PsiFile, Editor> pair = chooseFileForAction(hostFile, hostEditor, action);
if (pair == null) return false;
CommandProcessor.getInstance().executeCommand(project, () -> TransactionGuard.getInstance().submitTransactionAndWait(() -> {
Runnable r = () -> action.invoke(project, pair.second, pair.first);
try {
if (action.startInWriteAction()) {
WriteAction.run(r::run);
} else {
r.run();
}
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
if (hostEditor != null) {
DaemonCodeAnalyzer.getInstance(project).updateVisibleHighlighters(hostEditor);
}
}), text, null);
CommandProcessor.getInstance().executeCommand(project, () ->
TransactionGuard.getInstance().submitTransactionAndWait(
() -> invokeIntention(action, pair.second, pair.first)), text, null);
return true;
}
private static void invokeIntention(@NotNull IntentionAction action, @NotNull Editor editor, @NotNull PsiFile file) {
if (action.shouldMakeCurrentFileWritable() &&
!FileModificationService.getInstance().preparePsiElementsForWrite(file)) {
return;
}
Runnable r = () -> action.invoke(file.getProject(), editor, file);
if (action.startInWriteAction()) {
WriteAction.run(r::run);
} else {
r.run();
}
}
static Pair<PsiFile, Editor> chooseFileForAction(@NotNull PsiFile hostFile,
@Nullable Editor hostEditor,
@@ -65,6 +65,11 @@ public class SwitchToHtml5Action implements LocalQuickFix, IntentionAction {
applyFix(project);
}
@Override
public boolean shouldMakeCurrentFileWritable() {
return false;
}
private static void applyFix(Project project) {
ExternalResourceManagerEx.getInstanceEx().setDefaultHtmlDoctype(Html5SchemaProvider.getHtml5SchemaLocation(), project);
DaemonCodeAnalyzer.getInstance(project).restart();