diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/IncreaseLanguageLevelFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/IncreaseLanguageLevelFix.java
index fe5f6ea7ad37..d2720899a142 100644
--- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/IncreaseLanguageLevelFix.java
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/IncreaseLanguageLevelFix.java
@@ -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;
diff --git a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java
index 6cc93d4cd165..cbe7edc14d84 100644
--- a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java
+++ b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java
@@ -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();
}
});
}
diff --git a/platform/analysis-api/src/com/intellij/codeInsight/intention/IntentionAction.java b/platform/analysis-api/src/com/intellij/codeInsight/intention/IntentionAction.java
index ba47b7f5e045..bec79d488ec3 100644
--- a/platform/analysis-api/src/com/intellij/codeInsight/intention/IntentionAction.java
+++ b/platform/analysis-api/src/com/intellij/codeInsight/intention/IntentionAction.java
@@ -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
diff --git a/platform/analysis-api/src/com/intellij/codeInsight/intention/IntentionLike.java b/platform/analysis-api/src/com/intellij/codeInsight/intention/IntentionLike.java
new file mode 100644
index 000000000000..3408ae0d84a7
--- /dev/null
+++ b/platform/analysis-api/src/com/intellij/codeInsight/intention/IntentionLike.java
@@ -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.
+ *
+ * By default, as a heuristic, returns the same as {@link #startInWriteAction()}.
+ *
+ * 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();
+ }
+
+}
diff --git a/platform/analysis-api/src/com/intellij/codeInsight/intention/impl/PriorityActionWrapper.java b/platform/analysis-api/src/com/intellij/codeInsight/intention/impl/PriorityActionWrapper.java
index a3fe520fde2e..3585489432ca 100644
--- a/platform/analysis-api/src/com/intellij/codeInsight/intention/impl/PriorityActionWrapper.java
+++ b/platform/analysis-api/src/com/intellij/codeInsight/intention/impl/PriorityActionWrapper.java
@@ -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() {
diff --git a/platform/analysis-api/src/com/intellij/codeInspection/LocalQuickFix.java b/platform/analysis-api/src/com/intellij/codeInspection/LocalQuickFix.java
index 585e89de8f38..8904d1475c61 100644
--- a/platform/analysis-api/src/com/intellij/codeInspection/LocalQuickFix.java
+++ b/platform/analysis-api/src/com/intellij/codeInspection/LocalQuickFix.java
@@ -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}
*
* 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 {
+public interface LocalQuickFix extends QuickFix, IntentionLike {
LocalQuickFix[] EMPTY_ARRAY = new LocalQuickFix[0];
}
diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ExternalAnnotatorInspectionVisitor.java b/platform/analysis-impl/src/com/intellij/codeInspection/ExternalAnnotatorInspectionVisitor.java
index 2dfa17da3ab8..4c3a69791191 100644
--- a/platform/analysis-impl/src/com/intellij/codeInspection/ExternalAnnotatorInspectionVisitor.java
+++ b/platform/analysis-impl/src/com/intellij/codeInspection/ExternalAnnotatorInspectionVisitor.java
@@ -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();
diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java
index 774ee7101b93..5c6d17c4c560 100644
--- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java
+++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java
@@ -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];
}
diff --git a/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityIntentionActionWrapper.java b/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityIntentionActionWrapper.java
index dfeb5a00e13c..3a8ea981c469 100644
--- a/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityIntentionActionWrapper.java
+++ b/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityIntentionActionWrapper.java
@@ -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();
diff --git a/platform/lang-api/src/com/intellij/codeInspection/IntentionWrapper.java b/platform/lang-api/src/com/intellij/codeInspection/IntentionWrapper.java
index 7453e518bbc7..8c2511e8f42f 100644
--- a/platform/lang-api/src/com/intellij/codeInspection/IntentionWrapper.java
+++ b/platform/lang-api/src/com/intellij/codeInspection/IntentionWrapper.java
@@ -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();
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java
index 7da35aed0061..fae9f85394e3 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java
@@ -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);
}
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java
index 9924badcc318..56dd5ef5f0a8 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java
@@ -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 pair = chooseFileForAction(hostFile, hostEditor, action);
+ PsiDocumentManager.getInstance(project).commitAllDocuments();
+
+ Pair 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 chooseFileForAction(@NotNull PsiFile hostFile,
@Nullable Editor hostEditor,
diff --git a/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/SwitchToHtml5Action.java b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/SwitchToHtml5Action.java
index d62c4947c951..afe471c35f2b 100644
--- a/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/SwitchToHtml5Action.java
+++ b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/SwitchToHtml5Action.java
@@ -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();