mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-04 17:20:55 +07:00
do not rely on ExternalAnnotatorManager.wait(), wait for this particular task instead to fix IJPL-28996 Lock in ExternalAnnotatorManager.waitForAllExecuted
GitOrigin-RevId: 71a742c28d352e58e79b761195991412a60498ef
This commit is contained in:
committed by
intellij-monorepo-bot
parent
3f22b0fdbe
commit
1536b4f8fe
@@ -26,20 +26,21 @@ import com.intellij.openapi.progress.ProgressManager;
|
|||||||
import com.intellij.openapi.progress.util.BackgroundTaskUtil;
|
import com.intellij.openapi.progress.util.BackgroundTaskUtil;
|
||||||
import com.intellij.openapi.project.DumbAware;
|
import com.intellij.openapi.project.DumbAware;
|
||||||
import com.intellij.openapi.project.DumbService;
|
import com.intellij.openapi.project.DumbService;
|
||||||
|
import com.intellij.openapi.util.ProperTextRange;
|
||||||
import com.intellij.openapi.util.TextRange;
|
import com.intellij.openapi.util.TextRange;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
|
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
|
||||||
import com.intellij.psi.FileViewProvider;
|
import com.intellij.psi.FileViewProvider;
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile;
|
||||||
|
import com.intellij.util.TimeoutUtil;
|
||||||
|
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread;
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import com.intellij.util.ui.update.Update;
|
import com.intellij.util.ui.update.Update;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public final class ExternalToolPass extends ProgressableTextEditorHighlightingPass implements DumbAware {
|
public final class ExternalToolPass extends ProgressableTextEditorHighlightingPass implements DumbAware {
|
||||||
@@ -47,6 +48,7 @@ public final class ExternalToolPass extends ProgressableTextEditorHighlightingPa
|
|||||||
|
|
||||||
private final List<MyData<?,?>> myAnnotationData = Collections.synchronizedList(new ArrayList<>());
|
private final List<MyData<?,?>> myAnnotationData = Collections.synchronizedList(new ArrayList<>());
|
||||||
private volatile @NotNull List<? extends HighlightInfo> myHighlightInfos = Collections.emptyList();
|
private volatile @NotNull List<? extends HighlightInfo> myHighlightInfos = Collections.emptyList();
|
||||||
|
private volatile boolean externalUpdateTaskCompleted; // true when the task in ExternalAnnotatorManager.getInstance().queue() was completed
|
||||||
|
|
||||||
private static final class MyData<K,V> {
|
private static final class MyData<K,V> {
|
||||||
final @NotNull ExternalAnnotator<K,V> annotator;
|
final @NotNull ExternalAnnotator<K,V> annotator;
|
||||||
@@ -145,31 +147,41 @@ public final class ExternalToolPass extends ProgressableTextEditorHighlightingPa
|
|||||||
ExternalAnnotatorManager.getInstance().queue(new Update(myFile) {
|
ExternalAnnotatorManager.getInstance().queue(new Update(myFile) {
|
||||||
@Override
|
@Override
|
||||||
public void setRejected() {
|
public void setRejected() {
|
||||||
super.setRejected();
|
try {
|
||||||
if (!myProject.isDisposed()) { // Project close in EDT might call MergeUpdateQueue.dispose which calls setRejected in EDT
|
super.setRejected();
|
||||||
doFinish();
|
if (!myProject.isDisposed()) { // Project close in EDT might call MergeUpdateQueue.dispose which calls setRejected in EDT
|
||||||
|
doFinish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
externalUpdateTaskCompleted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (documentChanged(modificationStampBefore) || myProject.isDisposed()) {
|
try {
|
||||||
return;
|
if (documentChanged(modificationStampBefore) || myProject.isDisposed()) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// have to instantiate new indicator because the old one (progress) might have already been canceled
|
// have to instantiate new indicator because the old one (progress) might have already been canceled
|
||||||
DaemonProgressIndicator indicator = new DaemonProgressIndicator();
|
DaemonProgressIndicator indicator = new DaemonProgressIndicator();
|
||||||
BackgroundTaskUtil.runUnderDisposeAwareIndicator(myProject, () -> {
|
BackgroundTaskUtil.runUnderDisposeAwareIndicator(myProject, () -> {
|
||||||
// run annotators outside the read action because they could start OSProcessHandler
|
// run annotators outside the read action because they could start OSProcessHandler
|
||||||
runChangeAware(myDocument, () -> doAnnotate());
|
runChangeAware(myDocument, () -> doAnnotate());
|
||||||
ReadAction.run(() -> {
|
ReadAction.run(() -> {
|
||||||
ProgressManager.checkCanceled();
|
ProgressManager.checkCanceled();
|
||||||
if (!documentChanged(modificationStampBefore)) {
|
if (!documentChanged(modificationStampBefore)) {
|
||||||
doApply();
|
doApply();
|
||||||
doFinish();
|
doFinish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, indicator);
|
}, indicator);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
externalUpdateTaskCompleted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -177,11 +189,13 @@ public final class ExternalToolPass extends ProgressableTextEditorHighlightingPa
|
|||||||
@Override
|
@Override
|
||||||
public @NotNull List<HighlightInfo> getInfos() {
|
public @NotNull List<HighlightInfo> getInfos() {
|
||||||
ApplicationManager.getApplication().assertIsNonDispatchThread();
|
ApplicationManager.getApplication().assertIsNonDispatchThread();
|
||||||
try {
|
long deadline = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(60);
|
||||||
ExternalAnnotatorManager.getInstance().waitForAllExecuted(1, TimeUnit.MINUTES);
|
|
||||||
}
|
while (!externalUpdateTaskCompleted) {
|
||||||
catch (ExecutionException | InterruptedException | TimeoutException e) {
|
ProgressManager.checkCanceled();
|
||||||
throw new RuntimeException(e);
|
TimeoutUtil.sleep(1);
|
||||||
|
Thread.yield();
|
||||||
|
if (System.currentTimeMillis() > deadline) break;
|
||||||
}
|
}
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return (List<HighlightInfo>)myHighlightInfos;
|
return (List<HighlightInfo>)myHighlightInfos;
|
||||||
@@ -231,16 +245,19 @@ public final class ExternalToolPass extends ProgressableTextEditorHighlightingPa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresBackgroundThread
|
||||||
private void doFinish() {
|
private void doFinish() {
|
||||||
List<HighlightInfo> highlights = myAnnotationData.stream()
|
List<HighlightInfo> highlights = myAnnotationData.stream()
|
||||||
.flatMap(data ->
|
.flatMap(data ->
|
||||||
ContainerUtil.notNullize(data.annotationHolder).stream().map(annotation -> HighlightInfo.fromAnnotation(data.annotator, annotation)))
|
ContainerUtil.notNullize(data.annotationHolder).stream().map(annotation -> HighlightInfo.fromAnnotation(data.annotator, annotation)))
|
||||||
.toList();
|
.toList();
|
||||||
MarkupModelEx markupModel = (MarkupModelEx)DocumentMarkupModel.forDocument(myDocument, myProject, true);
|
MarkupModelEx markupModel = (MarkupModelEx)DocumentMarkupModel.forDocument(myDocument, myProject, true);
|
||||||
// use the method which doesn't retrieve a HighlightingSession from the indicator, because we likely destroyed the one already
|
HighlightingSessionImpl.runInsideHighlightingSession(myFile, getColorsScheme(), ProperTextRange.create(myFile.getTextRange()), false, session -> {
|
||||||
BackgroundUpdateHighlightersUtil.setHighlightersInRange(myRestrictRange, highlights, markupModel, getId(), getHighlightingSession());
|
// use the method which doesn't retrieve a HighlightingSession from the indicator, because we likely destroyed the one already
|
||||||
DaemonCodeAnalyzerEx.getInstanceEx(myProject).getFileStatusMap().markFileUpToDate(myDocument, getId());
|
BackgroundUpdateHighlightersUtil.setHighlightersInRange(myRestrictRange, highlights, markupModel, getId(), session);
|
||||||
myHighlightInfos = highlights;
|
DaemonCodeAnalyzerEx.getInstanceEx(myProject).getFileStatusMap().markFileUpToDate(myDocument, getId());
|
||||||
|
myHighlightInfos = highlights;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void processError(@NotNull Throwable t, @NotNull ExternalAnnotator<?,?> annotator, @NotNull PsiFile root) {
|
private static void processError(@NotNull Throwable t, @NotNull ExternalAnnotator<?,?> annotator, @NotNull PsiFile root) {
|
||||||
|
|||||||
Reference in New Issue
Block a user