intentions in injected and tests

This commit is contained in:
Alexey Kudravtsev
2009-10-16 16:02:41 +04:00
parent 18f02a20f8
commit 8c341ba323
10 changed files with 137 additions and 76 deletions
@@ -73,7 +73,7 @@ public class MyTestInjector {
private static ConcatenationAwareInjector registerForStringVarInitializer(@NotNull Project project,
@NotNull final Language language,
@NonNls final String varName,
@NotNull @NonNls final String varName,
@NonNls final String prefix,
@NonNls final String suffix) {
ConcatenationAwareInjector injector = new ConcatenationAwareInjector() {
@@ -17,14 +17,12 @@ package com.intellij.codeInsight.daemon;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeHighlighting.Pass;
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
import com.intellij.codeInsight.CodeInsightTestCase;
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl;
import com.intellij.codeInsight.daemon.impl.ExternalToolPass;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.TextEditorHighlightingPassRegistrarEx;
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.intellij.codeInspection.InspectionToolProvider;
import com.intellij.codeInspection.LocalInspectionTool;
@@ -271,13 +269,19 @@ public abstract class DaemonAnalyzerTestCase extends CodeInsightTestCase {
toIgnore.add(Pass.VISIBLE_LINE_MARKERS);
toIgnore.add(Pass.LINE_MARKERS);
}
final List<TextEditorHighlightingPass> passes = TextEditorHighlightingPassRegistrarEx.getInstanceEx(getProject()).instantiatePasses(getFile(), getEditor(), toIgnore.toNativeArray());
for (final TextEditorHighlightingPass pass : passes) {
if ((!(pass instanceof ExternalToolPass) && forceExternalValidation()) ||
(pass instanceof ExternalToolPass && !forceExternalValidation() && !doExternalValidation())) {
toIgnore.add(pass.getId());
}
if (!doExternalValidation()) {
toIgnore.add(Pass.EXTERNAL_TOOLS);
}
if (forceExternalValidation()) {
toIgnore.add(Pass.LINE_MARKERS);
toIgnore.add(Pass.LOCAL_INSPECTIONS);
toIgnore.add(Pass.POPUP_HINTS);
toIgnore.add(Pass.POST_UPDATE_ALL);
toIgnore.add(Pass.UPDATE_ALL);
toIgnore.add(Pass.UPDATE_VISIBLE);
toIgnore.add(Pass.UPDATE_OVERRIDEN_MARKERS);
toIgnore.add(Pass.VISIBLE_LINE_MARKERS);
}
CodeInsightTestFixtureImpl.instantiateAndRun(getFile(), getEditor(), toIgnore.toNativeArray());
@@ -316,7 +320,7 @@ public abstract class DaemonAnalyzerTestCase extends CodeInsightTestCase {
IntentionAction intentionAction = findIntentionAction(infos, intentionActionName, editor, file);
assertNotNull(intentionActionName, intentionAction);
intentionAction.invoke(file.getProject(), editor, file);
ShowIntentionActionsHandler.chooseActionAndInvoke(file, editor, intentionAction, intentionActionName);
}
protected static IntentionAction findIntentionAction(final Collection<HighlightInfo> infos, final String intentionActionName, final Editor editor,
@@ -17,10 +17,12 @@ package com.intellij.codeInsight.daemon;
import com.intellij.codeHighlighting.Pass;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.injected.editor.EditorWindow;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.vfs.VirtualFileFilter;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.testFramework.ExpectedHighlightingData;
import com.intellij.testFramework.FileTreeAccessFilter;
import com.intellij.testFramework.LightCodeInsightTestCase;
@@ -74,14 +76,13 @@ public abstract class LightDaemonAnalyzerTestCase extends LightCodeInsightTestCa
protected List<HighlightInfo> doHighlighting() {
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
int[] toIgnore = doFolding() ? ArrayUtil.EMPTY_INT_ARRAY : new int[]{Pass.UPDATE_FOLDING};
Editor editor = getEditor();
PsiFile file = getFile();
//if (editor instanceof EditorWindow) {
// editor = ((EditorWindow)editor).getDelegate();
// file = InjectedLanguageUtil.getTopLevelFile(file);
//}
if (editor instanceof EditorWindow) {
editor = ((EditorWindow)editor).getDelegate();
file = InjectedLanguageUtil.getTopLevelFile(file);
}
return CodeInsightTestFixtureImpl.instantiateAndRun(file, editor, toIgnore);
}
@@ -18,6 +18,7 @@ package com.intellij.codeInsight.daemon.quickFix;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
import com.intellij.lang.Commenter;
import com.intellij.lang.LanguageCommenters;
import com.intellij.openapi.application.ApplicationManager;
@@ -158,8 +159,8 @@ public abstract class LightQuickFixTestCase extends LightDaemonAnalyzerTestCase
doAction(text, actionShouldBeAvailable, testFullPath, testName, myWrapper);
}
protected void invoke(IntentionAction action) throws IncorrectOperationException {
action.invoke(getProject(), getEditor(), getFile());
protected static void invoke(IntentionAction action) throws IncorrectOperationException {
ShowIntentionActionsHandler.chooseActionAndInvoke(getFile(), getEditor(), action, action.getText());
}
protected IntentionAction findActionWithText(final String text) {
@@ -31,6 +31,7 @@ import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
import com.intellij.codeInsight.template.impl.TemplateState;
import com.intellij.ide.DataManager;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
@@ -50,16 +51,17 @@ import com.intellij.psi.IntentionFilterOwner;
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.ui.awt.RelativePoint;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.awt.*;
public class ShowIntentionsPass extends TextEditorHighlightingPass {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.ShowIntentionsPass");
@@ -112,7 +114,9 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass {
if (!myEditor.getContentComponent().hasFocus()) return;
TemplateState state = TemplateManagerImpl.getTemplateState(myEditor);
if (state == null || state.isFinished()) {
DaemonCodeAnalyzerImpl codeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(myProject);
getIntentionActionsToShow();
updateActions(codeAnalyzer);
}
}
@@ -138,7 +142,6 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass {
}
private void getIntentionActionsToShow() {
DaemonCodeAnalyzerImpl codeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(myProject);
if (LookupManager.getInstance(myProject).getActiveLookup() != null) return;
getActionsToShow(myEditor, myFile, myIntentionsInfo, myPassIdToShowIntentionsFor);
@@ -155,23 +158,17 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass {
}
myShowBulb = !myIntentionsInfo.guttersToShow.isEmpty();
if (!myShowBulb) {
for (HighlightInfo.IntentionActionDescriptor action : ContainerUtil.concat(myIntentionsInfo.errorFixesToShow, myIntentionsInfo.inspectionFixesToShow)) {
if (IntentionManagerSettings.getInstance().isShowLightBulb(action.getAction())) {
myShowBulb = true;
break;
}
}
}
if (!myShowBulb) {
for (HighlightInfo.IntentionActionDescriptor descriptor : myIntentionsInfo.intentionsToShow) {
for (HighlightInfo.IntentionActionDescriptor descriptor : ContainerUtil.concat(myIntentionsInfo.errorFixesToShow, myIntentionsInfo.inspectionFixesToShow,myIntentionsInfo.intentionsToShow)) {
final IntentionAction action = descriptor.getAction();
if (IntentionManagerSettings.getInstance().isShowLightBulb(action) && action.isAvailable(myProject, myEditor, myFile)) {
if (IntentionManagerSettings.getInstance().isShowLightBulb(action)) {
myShowBulb = true;
break;
}
}
}
}
private void updateActions(DaemonCodeAnalyzerImpl codeAnalyzer) {
IntentionHintComponent hintComponent = codeAnalyzer.getLastIntentionHint();
if (!myShowBulb || hintComponent == null) {
return;
@@ -195,21 +192,27 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass {
int offset = editor.getCaretModel().getOffset();
Project project = psiFile.getProject();
PsiElement injected = InjectedLanguageManager.getInstance(project).findInjectedElementAt(psiFile, offset);
PsiFile injectedFile;
Editor injectedEditor;
if (injected != null) {
injectedFile = injected.getContainingFile();
injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injectedFile);
}
else {
injectedFile = null;
injectedEditor = null;
}
for (IntentionAction action : IntentionManager.getInstance().getIntentionActions()) {
try {
if (action instanceof PsiElementBaseIntentionAction) {
if (!isInProject || !((PsiElementBaseIntentionAction)action).isAvailable(project, editor, psiElement)) continue;
}
else if (!action.isAvailable(project, editor, psiFile)) {
continue;
}
if (injectedFile != null && isAvailableHere(injectedEditor, injectedFile, injected, isInProject, project, action) ||
isAvailableHere(editor, psiFile, psiElement, isInProject, project, action)
) {
List<IntentionAction> enableDisableIntentionAction = new ArrayList<IntentionAction>();
enableDisableIntentionAction.add(new IntentionHintComponent.EnableDisableIntentionAction(action));
intentions.intentionsToShow.add(new HighlightInfo.IntentionActionDescriptor(action, enableDisableIntentionAction, null));
}
catch (IndexNotReadyException e) {
continue;
}
List<IntentionAction> enableDisableIntentionAction = new ArrayList<IntentionAction>();
enableDisableIntentionAction.add(new IntentionHintComponent.EnableDisableIntentionAction(action));
intentions.intentionsToShow.add(new HighlightInfo.IntentionActionDescriptor(action, enableDisableIntentionAction, null));
}
List<HighlightInfo.IntentionActionDescriptor> actions = QuickFixAction.getAvailableActions(editor, psiFile, passIdToShowIntentionsFor);
@@ -252,4 +255,20 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass {
}
}
}
private static boolean isAvailableHere(Editor editor, PsiFile psiFile, PsiElement psiElement, boolean inProject, Project project,
IntentionAction action) {
try {
if (action instanceof PsiElementBaseIntentionAction) {
if (!inProject || !((PsiElementBaseIntentionAction)action).isAvailable(project, editor, psiElement)) return false;
}
else if (!action.isAvailable(project, editor, psiFile)) {
return false;
}
}
catch (IndexNotReadyException e) {
return false;
}
return true;
}
}
@@ -55,13 +55,11 @@ public class TextEditorHighlightingPassRegistrarImpl extends TextEditorHighlight
private final TextEditorHighlightingPassFactory passFactory;
private final int[] startingPredecessorIds;
private final int[] completionPredecessorIds;
private final boolean runIntentionsPassAfter;
private PassConfig(@NotNull TextEditorHighlightingPassFactory passFactory,
boolean runIntentionsPassAfter,
@NotNull int[] completionPredecessorIds,
@NotNull int[] startingPredecessorIds) {
this.runIntentionsPassAfter = runIntentionsPassAfter;
this.completionPredecessorIds = completionPredecessorIds;
this.startingPredecessorIds = startingPredecessorIds;
this.passFactory = passFactory;
@@ -104,9 +102,7 @@ public class TextEditorHighlightingPassRegistrarImpl extends TextEditorHighlight
@NotNull
public List<TextEditorHighlightingPass> instantiatePasses(@NotNull final PsiFile psiFile, @NotNull final Editor editor, @NotNull final int[] passesToIgnore) {
final int[] nextId = new int[1];
synchronized (this) {
nextId[0] = nextAvailableId;
if (!checkedForCycles) {
checkedForCycles = true;
checkForCycles();
@@ -16,7 +16,6 @@
package com.intellij.codeInsight.intention.impl;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.ShowIntentionsPass;
import com.intellij.codeInsight.hint.HintManager;
@@ -25,8 +24,6 @@ import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.impl.config.IntentionManagerSettings;
import com.intellij.codeInspection.ex.QuickFixWrapper;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.*;
@@ -35,7 +32,6 @@ import com.intellij.openapi.util.Iconable;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.util.IncorrectOperationException;
import gnu.trove.THashSet;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
@@ -47,7 +43,6 @@ import java.util.*;
* @author cdr
*/
class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>, SpeedSearchFilter<IntentionActionWithTextCaching> {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.IntentionListStep");
private final Set<IntentionActionWithTextCaching> myCachedIntentions = new THashSet<IntentionActionWithTextCaching>(ACTION_TEXT_AND_CLASS_EQUALS);
private final Set<IntentionActionWithTextCaching> myCachedErrorFixes = new THashSet<IntentionActionWithTextCaching>(ACTION_TEXT_AND_CLASS_EQUALS);
private final Set<IntentionActionWithTextCaching> myCachedInspectionFixes = new THashSet<IntentionActionWithTextCaching>(ACTION_TEXT_AND_CLASS_EQUALS);
@@ -168,34 +163,14 @@ class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>
HintManager.getInstance().hideAllHints();
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
if (myProject.isDisposed()) return;
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
final PsiFile file = PsiUtilBase.getPsiFileInEditor(myEditor, myProject);
final IntentionAction action = cachedAction.getAction();
if (file == null || !action.isAvailable(myProject, myEditor, file)) {
if (file == null) {
return;
}
Runnable runnable = new Runnable() {
public void run() {
try {
action.invoke(myProject, myEditor, file);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
DaemonCodeAnalyzer.getInstance(myProject).updateVisibleHighlighters(myEditor);
}
};
if (action.startInWriteAction()) {
final Runnable _runnable = runnable;
runnable = new Runnable() {
public void run() {
ApplicationManager.getApplication().runWriteAction(_runnable);
}
};
}
CommandProcessor.getInstance().executeCommand(myProject, runnable, cachedAction.getText(), null);
ShowIntentionActionsHandler.chooseActionAndInvoke(file, myEditor, cachedAction.getAction(), cachedAction.getText());
}
});
}
@@ -29,7 +29,10 @@ import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
import com.intellij.codeInsight.template.impl.TemplateState;
import com.intellij.idea.ActionsBundle;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
@@ -44,6 +47,8 @@ import com.intellij.psi.PsiCodeFragment;
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 org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -52,6 +57,8 @@ import javax.swing.*;
* @author mike
*/
public class ShowIntentionActionsHandler implements CodeInsightActionHandler {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler");
public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) {
PsiDocumentManager.getInstance(project).commitAllDocuments();
@@ -134,4 +141,60 @@ public class ShowIntentionActionsHandler implements CodeInsightActionHandler {
public boolean startInWriteAction() {
return false;
}
public static void chooseActionAndInvoke(PsiFile file, final Editor editor, final IntentionAction action, final String text) {
final Project project = file.getProject();
final Editor editorToApply;
final PsiFile fileToApply;
int offset = editor.getCaretModel().getOffset();
PsiElement injected = InjectedLanguageManager.getInstance(project).findInjectedElementAt(file, offset);
if (injected != null) {
PsiFile injectedFile = injected.getContainingFile();
Editor injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injectedFile);
if (action.isAvailable(project, injectedEditor, injectedFile)) {
editorToApply = injectedEditor;
fileToApply = injectedFile;
}
else if (!action.isAvailable(project, editor, file)) {
return;
}
else {
editorToApply = editor;
fileToApply = file;
}
}
else if (!action.isAvailable(project, editor, file)) {
return;
}
else {
editorToApply = editor;
fileToApply = file;
}
Runnable runnable = new Runnable() {
public void run() {
try {
action.invoke(project, editorToApply, fileToApply);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
DaemonCodeAnalyzer.getInstance(project).updateVisibleHighlighters(editor);
}
};
if (action.startInWriteAction()) {
final Runnable _runnable = runnable;
runnable = new Runnable() {
public void run() {
ApplicationManager.getApplication().runWriteAction(_runnable);
}
};
}
CommandProcessor.getInstance().executeCommand(project, runnable, text, null);
}
}
@@ -236,6 +236,7 @@ public class InjectedLanguageUtil {
return null;
}
@Nullable
public static PsiElement findInjectedElementNoCommitWithOffset(@NotNull PsiFile file, final int offset) {
Project project = file.getProject();
if (InjectedLanguageManager.getInstance(project).isInjectedFragment(file)) return null;
@@ -28,6 +28,7 @@ import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.daemon.impl.*;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.codeInsight.lookup.impl.LookupImpl;
@@ -428,7 +429,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
public void launchAction(@NotNull final IntentionAction action) throws Exception {
new WriteCommandAction(myProjectFixture.getProject()) {
protected void run(final Result result) throws Exception {
action.invoke(getProject(), getEditor(), getFile());
ShowIntentionActionsHandler.chooseActionAndInvoke(getFile(), getEditor(), action, action.getText());
}
}.execute().throwException();