show autoimport popup when type space after class name, even if visible pass hasnt been run

This commit is contained in:
Alexey Kudravtsev
2009-11-20 12:27:45 +03:00
parent c697a90629
commit cbaaee3ad5
9 changed files with 70 additions and 41 deletions
@@ -15,6 +15,7 @@
*/
package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
@@ -129,12 +130,12 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
DaemonCodeAnalyzerImpl codeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(project);
boolean canImportHere = true;
if (classes.length == 1
&& com.intellij.codeInsight.CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY
&& (allowCaretNearRef || !isCaretNearRef(editor, myRef))
&& !JspPsiUtil.isInJspFile(psiFile)
&& codeAnalyzer.canChangeFileSilently(psiFile)
&& !hasUnresolvedImportWhichCanImport(psiFile, classes[0].getName())) {
&& (canImportHere = canImportHere(allowCaretNearRef, editor, psiFile, classes[0].getName()))
&& CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY
&& codeAnalyzer.canChangeFileSilently(psiFile)) {
CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
public void run() {
action.execute();
@@ -142,13 +143,20 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
});
return false;
}
if (doShow) {
if (doShow && canImportHere) {
String hintText = ShowAutoImportPass.getMessage(classes.length > 1, classes[0].getQualifiedName());
HintManager.getInstance().showQuestionHint(editor, hintText, myRef.getTextOffset(), myRef.getTextRange().getEndOffset(), action);
}
return true;
}
private boolean canImportHere(boolean allowCaretNearRef, Editor editor, PsiFile psiFile, String exampleClassName) {
return (allowCaretNearRef || !isCaretNearRef(editor, myRef)) &&
!JspPsiUtil.isInJspFile(psiFile) &&
!hasUnresolvedImportWhichCanImport(psiFile, exampleClassName);
}
protected abstract boolean isQualified(T reference);
public boolean showHint(final Editor editor) {
@@ -68,6 +68,11 @@ import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.*;
public abstract class DaemonAnalyzerTestCase extends CodeInsightTestCase {
@@ -286,7 +291,7 @@ public abstract class DaemonAnalyzerTestCase extends CodeInsightTestCase {
CodeInsightTestFixtureImpl.instantiateAndRun(getFile(), getEditor(), toIgnore.toNativeArray());
if (doTestLineMarkers()) {
if (!canChangeDocumentDuringHighlighting()) {
Document document = getDocument(getFile());
assertTrue(((DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject())).getFileStatusMap().allDirtyScopesAreNull(document));
}
@@ -295,6 +300,23 @@ public abstract class DaemonAnalyzerTestCase extends CodeInsightTestCase {
return infos == null ? Collections.<HighlightInfo>emptyList() : new ArrayList<HighlightInfo>(infos);
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
protected @interface CanChangeDocumentDuringHighlighting {}
private boolean canChangeDocumentDuringHighlighting() {
String methodName = "test" + getTestName(false);
Method method = null;
try {
method = getClass().getDeclaredMethod(methodName);
}
catch (NoSuchMethodException e) {
fail(methodName);
}
CanChangeDocumentDuringHighlighting annotation = method.getAnnotation(CanChangeDocumentDuringHighlighting.class);
return annotation != null;
}
public static List<HighlightInfo> filter(final List<HighlightInfo> infos, HighlightSeverity minSeverity) {
ArrayList<HighlightInfo> result = new ArrayList<HighlightInfo>();
for (final HighlightInfo info : infos) {
@@ -269,10 +269,7 @@ public class DaemonListeners implements Disposable {
if (file instanceof PsiCodeFragment) return true;
Project project = file.getProject();
if (!ModuleUtil.projectContainsFile(project, virtualFile, false)) return false;
FileEditor[] editors = FileEditorManager.getInstance(myProject).getEditors(virtualFile);
for (FileEditor editor : editors) {
if (!editor.isModified()) return false;
}
if (!FileDocumentManager.getInstance().isFileModified(virtualFile)) return false;
FilePath path = new FilePathImpl(virtualFile);
boolean vcsIsThinking = !VcsDirtyScopeManager.getInstance(myProject).whatFilesDirty(Arrays.asList(path)).isEmpty();
if (vcsIsThinking) return false;
@@ -33,9 +33,7 @@ import org.jetbrains.annotations.NotNull;
public class IdentifierHighlighterPassFactory extends AbstractProjectComponent implements TextEditorHighlightingPassFactory {
public IdentifierHighlighterPassFactory(Project project, TextEditorHighlightingPassRegistrar highlightingPassRegistrar) {
super(project);
highlightingPassRegistrar.registerTextEditorHighlightingPass(this, new int[]{
Pass.UPDATE_VISIBLE
}, null, false, -1);
highlightingPassRegistrar.registerTextEditorHighlightingPass(this, new int[]{Pass.UPDATE_VISIBLE}, null, false, -1);
}
public TextEditorHighlightingPass createHighlightingPass(@NotNull final PsiFile file, @NotNull final Editor editor) {
@@ -17,6 +17,7 @@
package com.intellij.codeInsight.daemon.impl;
import com.intellij.codeHighlighting.HighlightingPass;
import com.intellij.codeHighlighting.Pass;
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
import com.intellij.concurrency.Job;
import com.intellij.concurrency.JobImpl;
@@ -37,8 +38,8 @@ import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.SmartList;
@@ -202,7 +203,7 @@ public abstract class PassExecutorService implements Disposable {
toBeSubmitted.put(key, scheduledPass);
for (int predecessorId : pass.getCompletionPredecessorIds()) {
ScheduledPass predecessor = findOrCreatePredecessorPass(fileEditors, document, toBeSubmitted, textEditorHighlightingPasses, freePasses,
updateProgress, threadsToStartCountdown, jobPriority, predecessorId);
updateProgress, threadsToStartCountdown, jobPriority, predecessorId, passId);
if (predecessor != null) {
predecessor.mySuccessorsOnCompletion.add(scheduledPass);
scheduledPass.myRunningPredecessorsCount.incrementAndGet();
@@ -210,7 +211,7 @@ public abstract class PassExecutorService implements Disposable {
}
for (int predecessorId : pass.getStartingPredecessorIds()) {
ScheduledPass predecessor = findOrCreatePredecessorPass(fileEditors, document, toBeSubmitted, textEditorHighlightingPasses, freePasses,
updateProgress, threadsToStartCountdown, jobPriority, predecessorId);
updateProgress, threadsToStartCountdown, jobPriority, predecessorId, passId);
if (predecessor != null) {
predecessor.mySuccessorsOnSubmit.add(scheduledPass);
scheduledPass.myRunningPredecessorsCount.incrementAndGet();
@@ -230,12 +231,17 @@ public abstract class PassExecutorService implements Disposable {
final DaemonProgressIndicator updateProgress,
final AtomicInteger myThreadsToStartCountdown,
final int jobPriority,
final int predecessorId) {
final int predecessorId, int passId) {
Pair<Document, Integer> predkey = Pair.create(document, predecessorId);
ScheduledPass predecessor = toBeSubmitted.get(predkey);
if (predecessor == null) {
TextEditorHighlightingPass textEditorPass = findPassById(predecessorId, textEditorHighlightingPasses);
predecessor = textEditorPass == null ? null : createScheduledPass(fileEditors, textEditorPass, toBeSubmitted, textEditorHighlightingPasses,freePasses,
if (textEditorPass == null && predecessorId == Pass.UPDATE_VISIBLE && passId != Pass.UPDATE_ALL && findPassById(Pass.UPDATE_ALL, textEditorHighlightingPasses) != null) {
// when UPDATE_VISIBLE pass is not going to run, pretend that all dependent passes are depend on UPDATE_ALL pass instead
return findOrCreatePredecessorPass(fileEditors, document, toBeSubmitted, textEditorHighlightingPasses, freePasses, updateProgress,
myThreadsToStartCountdown, jobPriority, Pass.UPDATE_ALL, passId);
}
predecessor = textEditorPass == null ? null : createScheduledPass(fileEditors, textEditorPass, toBeSubmitted, textEditorHighlightingPasses, freePasses,
updateProgress, myThreadsToStartCountdown, jobPriority);
}
return predecessor;
@@ -24,6 +24,7 @@ import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.HintAction;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
@@ -78,8 +79,9 @@ public class ShowAutoImportPass extends TextEditorHighlightingPass {
}
public void doApplyInformationToEditor() {
ApplicationManager.getApplication().assertIsDispatchThread();
if (!myEditor.getContentComponent().hasFocus()) return;
Application application = ApplicationManager.getApplication();
application.assertIsDispatchThread();
if (!application.isUnitTestMode() && !myEditor.getContentComponent().hasFocus()) return;
List<HighlightInfo> visibleHighlights = getVisibleHighlights(myStartOffset, myEndOffset, myProject, myEditor);
int caretOffset = myEditor.getCaretModel().getOffset();
@@ -89,10 +91,9 @@ public class ShowAutoImportPass extends TextEditorHighlightingPass {
if (info.startOffset <= caretOffset && showAddImportHint(info)) return;
}
for (int i = 0; i < visibleHighlights.size(); i++) {
for (HighlightInfo visibleHighlight : visibleHighlights) {
ProgressManager.checkCanceled();
HighlightInfo info = visibleHighlights.get(i);
if (info.startOffset > caretOffset && showAddImportHint(info)) return;
if (visibleHighlight.startOffset > caretOffset && showAddImportHint(visibleHighlight)) return;
}
}
@@ -40,10 +40,7 @@ import org.jetbrains.annotations.Nullable;
public class ShowIntentionsPassFactory extends AbstractProjectComponent implements TextEditorHighlightingPassFactory {
public ShowIntentionsPassFactory(Project project, TextEditorHighlightingPassRegistrar highlightingPassRegistrar) {
super(project);
highlightingPassRegistrar.registerTextEditorHighlightingPass(this, new int[]{
Pass.UPDATE_VISIBLE,
Pass.UPDATE_ALL,
}, null, false, Pass.POPUP_HINTS);
highlightingPassRegistrar.registerTextEditorHighlightingPass(this, new int[]{Pass.UPDATE_ALL,}, null, false, Pass.POPUP_HINTS);
}
@NonNls
@@ -331,7 +331,7 @@ public abstract class UsefulTestCase extends TestCase {
public static void assertEmpty(final Object[] array) {
assertOrderedEquals(array);
}
public static void assertEmpty(final Collection<?> collection) {
assertEmpty(null, collection);
}
@@ -47,7 +47,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
private final VcsGuess myGuess;
private final SynchronizedLife myLife;
private MyProgressHolder myProgressHolder;
private final MyProgressHolder myProgressHolder;
public VcsDirtyScopeManagerImpl(Project project, ChangeListManager changeListManager, ProjectLevelVcsManager vcsManager) {
myProject = project;
@@ -104,7 +104,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
}
});
if (lifeDrop.isDone() && (! lifeDrop.isSuspened())) {
if (lifeDrop.isDone() && !lifeDrop.isSuspened()) {
myChangeListManager.scheduleUpdate();
}
}
@@ -153,8 +153,8 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
convertPaths(dirsRecursivelyDirty, dirsConverted);
}
});
final boolean haveStuff = ((filesConverted != null) && (! filesConverted.isEmpty())) ||
((dirsConverted != null) && (! dirsConverted.isEmpty()));
final boolean haveStuff = filesConverted != null && ! filesConverted.isEmpty()
|| dirsConverted != null && ! dirsConverted.isEmpty();
if (! haveStuff) return false;
return takeDirt(new Consumer<DirtBuilder>() {
@@ -183,11 +183,11 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
};
final LifeDrop lifeDrop = myLife.doIfAlive(runnable);
if (lifeDrop.isDone() && (! lifeDrop.isSuspened()) && (Boolean.TRUE.equals(wasNotEmptyRef.get()))) {
if (lifeDrop.isDone() && !lifeDrop.isSuspened() && Boolean.TRUE.equals(wasNotEmptyRef.get())) {
myChangeListManager.scheduleUpdate();
}
// no sense in checking correct here any more: vcs is searched for asynchronously
return (! lifeDrop.isDone());
return !lifeDrop.isDone();
}
private void convert(@Nullable final Collection<VirtualFile> from, final Collection<VcsRoot> to) {
@@ -211,8 +211,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
convert(dirsRecursivelyDirty, dirsConverted);
}
});
final boolean haveStuff = ((filesConverted != null) && (! filesConverted.isEmpty())) ||
((dirsConverted != null) && (! dirsConverted.isEmpty()));
final boolean haveStuff = filesConverted != null && ! filesConverted.isEmpty() || dirsConverted != null && ! dirsConverted.isEmpty();
if (! haveStuff) return false;
return takeDirt(new Consumer<DirtBuilder>() {
@@ -369,10 +368,11 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
currentHolderRef.set(new MyProgressHolder(new DirtBuilder(myDirtBuilder), null));
}
});
final VcsInvalidated inProgressInvalidated = inProgressHolderRef.get().calculateInvalidated();
final VcsInvalidated currentInvalidated = currentHolderRef.get().calculateInvalidated();
final VcsInvalidated inProgressInvalidated = inProgressHolderRef.get() == null ? null : inProgressHolderRef.get().calculateInvalidated();
final VcsInvalidated currentInvalidated = currentHolderRef.get() == null ? null : currentHolderRef.get().calculateInvalidated();
for (FilePath fp : files) {
if (inProgressInvalidated != null && inProgressInvalidated.isFileDirty(fp) || currentInvalidated.isFileDirty(fp)) {
if (inProgressInvalidated != null && inProgressInvalidated.isFileDirty(fp)
|| currentInvalidated != null && currentInvalidated.isFileDirty(fp)) {
result.add(fp);
}
}
@@ -457,7 +457,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
public LifeDrop doIfAliveAndNotSuspended(final Runnable runnable) {
synchronized (myLock) {
synchronized (myLock) {
if (LifeStages.ALIVE.equals(myStage) && (! mySuspended)) {
if (LifeStages.ALIVE.equals(myStage) && ! mySuspended) {
runnable.run();
return new LifeDrop(true, mySuspended);
}