diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java index 373bd59226c5..a7de16327dc0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java @@ -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 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 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) { diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java index e2cf7ebe8d1c..9ebc6df534a4 100644 --- a/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java @@ -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.emptyList() : new ArrayList(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 filter(final List infos, HighlightSeverity minSeverity) { ArrayList result = new ArrayList(); for (final HighlightInfo info : infos) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java index 879648af8665..f988e5532859 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java @@ -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; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/IdentifierHighlighterPassFactory.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/IdentifierHighlighterPassFactory.java index c68c34d2bed9..33a14383e27f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/IdentifierHighlighterPassFactory.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/IdentifierHighlighterPassFactory.java @@ -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) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java index 1adc5c7e5d3a..590ae6aa6282 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java @@ -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 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; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowAutoImportPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowAutoImportPass.java index c45190dd03fb..7dd43425380b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowAutoImportPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowAutoImportPass.java @@ -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 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; } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPassFactory.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPassFactory.java index 2af00f2444ae..4581b570e113 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPassFactory.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPassFactory.java @@ -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 diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index fbd95b004b39..3a61e6d759de 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -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); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java index b2e83c0a1458..02846e295044 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java @@ -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() { @@ -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 from, final Collection 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() { @@ -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); }