Don't reparse in the UI thread for the "Highlight Usages" pass

Just moving the handler creation to background is not enough, since
java's HighlightSuppressedWarningsHandler requires editor visible range,
which has to be calculated on EDT, so pre-calculate it first, and pass
to the handler factory then.

This fixes CPP-9373.
This commit is contained in:
Dmitry Kozhevnikov
2018-01-23 16:13:49 +03:00
parent 19bb6565f4
commit 24d67e360b
6 changed files with 85 additions and 17 deletions
@@ -17,6 +17,7 @@ package com.intellij.codeInsight.highlighting;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.ProperTextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiElement;
@@ -24,18 +25,30 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiLiteralExpression;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public class HighlightSuppressedWarningsFactory extends HighlightUsagesHandlerFactoryBase {
@Nullable
@Override
public HighlightUsagesHandlerBase createHighlightUsagesHandler(@NotNull Editor editor, @NotNull PsiFile file, @NotNull PsiElement target) {
public HighlightUsagesHandlerBase createHighlightUsagesHandler(@NotNull Editor editor,
@NotNull PsiFile file,
@NotNull PsiElement target) {
throw new UnsupportedOperationException("Use createHighlightUsagesHandler(editor, file, target, visibleRange)");
}
@Override
public HighlightUsagesHandlerBase createHighlightUsagesHandler(@NotNull Editor editor, @NotNull PsiFile file, @NotNull PsiElement target,
@NotNull ProperTextRange visibleRange) {
final PsiAnnotation annotation = PsiTreeUtil.getParentOfType(target, PsiAnnotation.class);
if (annotation != null && Comparing.strEqual(SuppressWarnings.class.getName(), annotation.getQualifiedName())) {
final VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null && !virtualFile.getFileType().isBinary()) {
return new HighlightSuppressedWarningsHandler(editor, file, annotation, PsiTreeUtil.getParentOfType(target, PsiLiteralExpression.class));
return new HighlightSuppressedWarningsHandler(editor, file, annotation,
PsiTreeUtil.getParentOfType(target, PsiLiteralExpression.class), visibleRange);
}
}
return null;
@@ -45,13 +45,19 @@ class HighlightSuppressedWarningsHandler extends HighlightUsagesHandlerBase<PsiL
private final PsiAnnotation myTarget;
private final PsiLiteralExpression mySuppressedExpression;
@NotNull
private final ProperTextRange myPriorityRange;
HighlightSuppressedWarningsHandler(@NotNull Editor editor, @NotNull PsiFile file, @NotNull PsiAnnotation target, @Nullable PsiLiteralExpression suppressedExpression) {
HighlightSuppressedWarningsHandler(@NotNull Editor editor,
@NotNull PsiFile file,
@NotNull PsiAnnotation target,
@Nullable PsiLiteralExpression suppressedExpression,
@NotNull ProperTextRange priorityRange) {
super(editor, file);
myTarget = target;
mySuppressedExpression = suppressedExpression;
myPriorityRange = VisibleHighlightingPassFactory.calculateVisibleRange(myEditor);
myPriorityRange = priorityRange;
}
@Override
@@ -37,6 +37,7 @@ import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.ProperTextRange;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
@@ -58,32 +59,33 @@ public class IdentifierHighlighterPass extends TextEditorHighlightingPass {
private final Collection<TextRange> myReadAccessRanges = Collections.synchronizedList(new ArrayList<>());
private final Collection<TextRange> myWriteAccessRanges = Collections.synchronizedList(new ArrayList<>());
private final int myCaretOffset;
private final HighlightUsagesHandlerBase<PsiElement> myHighlightUsagesHandler;
private final ProperTextRange myVisibleRange;
IdentifierHighlighterPass(@NotNull Project project, @NotNull PsiFile file, @NotNull Editor editor) {
super(project, editor.getDocument(), false);
myFile = file;
myEditor = editor;
myCaretOffset = myEditor.getCaretModel().getOffset();
myHighlightUsagesHandler = HighlightUsagesHandler.createCustomHandler(myEditor, myFile);
myVisibleRange = VisibleHighlightingPassFactory.calculateVisibleRange(myEditor);
}
@Override
public void doCollectInformation(@NotNull final ProgressIndicator progress) {
if (myHighlightUsagesHandler != null) {
List<PsiElement> targets = myHighlightUsagesHandler.getTargets();
myHighlightUsagesHandler.computeUsages(targets);
final List<TextRange> readUsages = myHighlightUsagesHandler.getReadUsages();
final HighlightUsagesHandlerBase<PsiElement> highlightUsagesHandler = HighlightUsagesHandler.createCustomHandler(myEditor, myFile, myVisibleRange);
if (highlightUsagesHandler != null) {
List<PsiElement> targets = highlightUsagesHandler.getTargets();
highlightUsagesHandler.computeUsages(targets);
final List<TextRange> readUsages = highlightUsagesHandler.getReadUsages();
for (TextRange readUsage : readUsages) {
LOG.assertTrue(readUsage != null, "null text range from " + myHighlightUsagesHandler);
LOG.assertTrue(readUsage != null, "null text range from " + highlightUsagesHandler);
}
myReadAccessRanges.addAll(readUsages);
final List<TextRange> writeUsages = myHighlightUsagesHandler.getWriteUsages();
final List<TextRange> writeUsages = highlightUsagesHandler.getWriteUsages();
for (TextRange writeUsage : writeUsages) {
LOG.assertTrue(writeUsage != null, "null text range from " + myHighlightUsagesHandler);
LOG.assertTrue(writeUsage != null, "null text range from " + highlightUsagesHandler);
}
myWriteAccessRanges.addAll(writeUsages);
if (!myHighlightUsagesHandler.highlightReferences()) return;
if (!highlightUsagesHandler.highlightReferences()) return;
}
int flags = TargetElementUtil.ELEMENT_NAME_ACCEPTED | TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED;
@@ -19,6 +19,7 @@ package com.intellij.codeInsight.highlighting;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.TargetElementUtil;
import com.intellij.codeInsight.daemon.impl.IdentifierUtil;
import com.intellij.codeInsight.daemon.impl.VisibleHighlightingPassFactory;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.find.EditorSearchSession;
import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter;
@@ -28,6 +29,7 @@ import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.actionSystem.Shortcut;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
@@ -41,6 +43,7 @@ import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ProperTextRange;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.WindowManager;
@@ -152,8 +155,19 @@ public class HighlightUsagesHandler extends HighlightHandlerBase {
@Nullable
public static <T extends PsiElement> HighlightUsagesHandlerBase<T> createCustomHandler(@NotNull Editor editor, @NotNull PsiFile file) {
ApplicationManager.getApplication().assertIsDispatchThread();
ProperTextRange visibleRange = VisibleHighlightingPassFactory.calculateVisibleRange(editor);
return createCustomHandler(editor, file, visibleRange);
}
/**
* @see HighlightUsagesHandlerFactory#createHighlightUsagesHandler(Editor, PsiFile, ProperTextRange)
*/
@Nullable
public static <T extends PsiElement> HighlightUsagesHandlerBase<T> createCustomHandler(@NotNull Editor editor, @NotNull PsiFile file,
@NotNull ProperTextRange visibleRange) {
for (HighlightUsagesHandlerFactory factory : Extensions.getExtensions(HighlightUsagesHandlerFactory.EP_NAME)) {
final HighlightUsagesHandlerBase handler = factory.createHighlightUsagesHandler(editor, file);
final HighlightUsagesHandlerBase handler = factory.createHighlightUsagesHandler(editor, file, visibleRange);
if (handler != null) {
//noinspection unchecked
return handler;
@@ -18,6 +18,7 @@ package com.intellij.codeInsight.highlighting;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.util.ProperTextRange;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -32,4 +33,16 @@ public interface HighlightUsagesHandlerFactory {
@Nullable
HighlightUsagesHandlerBase createHighlightUsagesHandler(@NotNull Editor editor, @NotNull PsiFile file);
/**
* @param visibleRange To avoid parsing in EDT, these factory methods should be called in a background thread
* (as implementation use the PSI element under cursor to choose the specific handler).
* However, some handlers require the editor visible range, which must be calculated in EDT,
* so it's passed externally
*/
@Nullable
default HighlightUsagesHandlerBase createHighlightUsagesHandler(@NotNull Editor editor, @NotNull PsiFile file, @NotNull ProperTextRange visibleRange) {
return createHighlightUsagesHandler(editor, file);
}
}
@@ -17,6 +17,7 @@ package com.intellij.codeInsight.highlighting;
import com.intellij.codeInsight.TargetElementUtil;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.ProperTextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
@@ -29,12 +30,31 @@ public abstract class HighlightUsagesHandlerFactoryBase implements HighlightUsag
@Nullable
@Override
public final HighlightUsagesHandlerBase createHighlightUsagesHandler(@NotNull Editor editor, @NotNull PsiFile file) {
int offset = TargetElementUtil.adjustOffset(file, editor.getDocument(), editor.getCaretModel().getOffset());
PsiElement target = file.findElementAt(offset);
PsiElement target = findTarget(editor, file);
if (target == null) return null;
return createHighlightUsagesHandler(editor, file, target);
}
@Nullable
@Override
public final HighlightUsagesHandlerBase createHighlightUsagesHandler(@NotNull Editor editor, @NotNull PsiFile file,
@NotNull ProperTextRange visibleRange) {
PsiElement target = findTarget(editor, file);
if (target == null) return null;
return createHighlightUsagesHandler(editor, file, target, visibleRange);
}
@Nullable
public abstract HighlightUsagesHandlerBase createHighlightUsagesHandler(@NotNull Editor editor, @NotNull PsiFile file, @NotNull PsiElement target);
@Nullable
public HighlightUsagesHandlerBase createHighlightUsagesHandler(@NotNull Editor editor, @NotNull PsiFile file, @NotNull PsiElement target,
@NotNull ProperTextRange visibleRange) {
return createHighlightUsagesHandler(editor, file, target);
}
private static PsiElement findTarget(@NotNull Editor editor, @NotNull PsiFile file) {
int offset = TargetElementUtil.adjustOffset(file, editor.getDocument(), editor.getCaretModel().getOffset());
return file.findElementAt(offset);
}
}