optimization: do not iterate all range markers in the document, use the visible area only (part of IJPL-162151 Scrolling is slow)

GitOrigin-RevId: 4353aab31f4af5e3c50662669f94b823b01d3031
This commit is contained in:
Alexey Kudravtsev
2024-10-04 15:39:49 +02:00
committed by intellij-monorepo-bot
parent 87f94339b9
commit 5a4227cc44
20 changed files with 251 additions and 248 deletions

View File

@@ -17,7 +17,7 @@ class JavaIntentionsOrderProvider : IntentionsOrderProvider {
}
private fun isCompilationFix(context: CachedIntentions, intention: IntentionActionWithTextCaching): Boolean {
if (intention.fixRange?.contains(context.offset) == false) return false
if (intention.fixRange?.containsOffset(context.offset) == false) return false
val isInspectionHighlighting = context.highlightInfoType?.isInspectionHighlightInfoType == true
return context.errorFixes.contains(intention) && !isInspectionHighlighting
}

View File

@@ -29,6 +29,7 @@ import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.util.PingProgress;
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
import com.intellij.openapi.util.Segment;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
@@ -57,6 +58,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BooleanSupplier;
@@ -629,18 +631,23 @@ public class ImportHelperTest extends LightDaemonAnalyzerTestCase {
UIUtil.dispatchAllInvocationEvents();
CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = false;
DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(true);
@NotNull Editor editor = getEditor();
Editor editor = getEditor();
TextRange visibleRange = editor.calculateVisibleRange();
assertTrue(visibleRange.toString(), visibleRange.getStartOffset() > 5000 && visibleRange.getEndOffset() < 10_000); // sanity check that visible range has been indeed changed
List<HighlightInfo> errors = highlightErrors();
assertNotEmpty(errors);
List<HighlightInfo> errors = ContainerUtil.sorted(highlightErrors(), Segment.BY_START_OFFSET_THEN_END_OFFSET);
assertSize(1000, errors);
UnresolvedReferenceQuickFixUpdaterImpl updater = (UnresolvedReferenceQuickFixUpdaterImpl)UnresolvedReferenceQuickFixUpdater.getInstance(getProject());
for (HighlightInfo error : errors) {
updater.waitForBackgroundJobIfStartedInTests(error);
List<HintAction> hints = ShowAutoImportPass.extractHints(error);
String message = error + " hasHints: " + error.hasHint() + "; hints:" + hints + "; visibleRange:" + visibleRange + "; contains: " + visibleRange.contains(error);
assertEquals(message, error.hasHint(), visibleRange.contains(error));
for (int i = 0; i < errors.size(); i++) {
HighlightInfo error = errors.get(i);
if (visibleRange.contains(error)) { // we care only for visible errors; invisible ones may or may not be computed
updater.waitForBackgroundJobIfStartedInTests(error, 60, TimeUnit.SECONDS);
if (!error.hasHint()) {
List<HintAction> hints = ShowAutoImportPass.extractHints(error);
String message = error + ": " + i + " hasHints: "+error.hasHint() + "; hints:" + hints + "; visibleRange:" + visibleRange + "; contains: " + visibleRange.contains(error);
fail(message);
}
}
}
}
}

View File

@@ -668,6 +668,7 @@ com.intellij.codeInsight.daemon.impl.HighlightInfo$Builder
- a:unescapedToolTip(java.lang.String):com.intellij.codeInsight.daemon.impl.HighlightInfo$Builder
c:com.intellij.codeInsight.daemon.impl.HighlightInfo$IntentionActionDescriptor
- <init>(com.intellij.codeInsight.intention.IntentionAction,java.util.List,java.lang.String,javax.swing.Icon,com.intellij.codeInsight.daemon.HighlightDisplayKey,com.intellij.lang.annotation.ProblemGroup,com.intellij.lang.annotation.HighlightSeverity):V
- <init>(com.intellij.codeInsight.intention.IntentionAction,java.util.List,java.lang.String,javax.swing.Icon,com.intellij.codeInsight.daemon.HighlightDisplayKey,com.intellij.lang.annotation.ProblemGroup,com.intellij.lang.annotation.HighlightSeverity,com.intellij.openapi.util.Segment):V
- equals(java.lang.Object):Z
- getAction():com.intellij.codeInsight.intention.IntentionAction
- getDisplayName():java.lang.String

View File

@@ -187,14 +187,16 @@ final class AnnotatorRunner {
false, 0, injectedInfo.getProblemGroup(), injectedInfo.toolId, injectedInfo.getGutterIconRenderer(), injectedInfo.getGroup(), injectedInfo.unresolvedReference);
patched.setHint(injectedInfo.hasHint());
List<HighlightInfo.IntentionActionDescriptor> quickFixes = new ArrayList<>();
injectedInfo.findRegisteredQuickFix((descriptor, quickfixTextRange) -> {
List<TextRange> editableQF = injectedLanguageManager.intersectWithAllEditableFragments(injectedPsi, quickfixTextRange);
for (TextRange editableRange : editableQF) {
TextRange hostEditableRange = documentWindow.injectedToHost(editableRange);
patched.registerFix(descriptor.getAction(), descriptor.myOptions, descriptor.getDisplayName(), hostEditableRange, descriptor.myKey);
quickFixes.add(descriptor.withFixRange(hostEditableRange));
}
return null;
});
patched.registerFixes(quickFixes);
patched.markFromInjection();
outHostInfos.add(patched);
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
/* Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. */
package com.intellij.codeInsight.daemon.impl;
import com.intellij.codeHighlighting.Pass;
@@ -7,6 +7,7 @@ import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.daemon.impl.actions.DisableHighlightingIntentionAction;
import com.intellij.codeInsight.daemon.impl.actions.IntentionActionWithFixAllOption;
import com.intellij.codeInsight.intention.*;
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper;
import com.intellij.codeInspection.ex.InspectionToolWrapper;
@@ -56,7 +57,6 @@ import static com.intellij.openapi.util.NlsContexts.Tooltip;
@ApiStatus.NonExtendable
public class HighlightInfo implements Segment {
private static final Logger LOG = Logger.getInstance(HighlightInfo.class);
/**
* Short name of the {@link com.intellij.codeInsight.daemon.impl.HighlightVisitorBasedInspection} tool, which needs to be treated differently from other inspections:
* it doesn't have "disable" or "suppress" quickfixes
@@ -70,7 +70,7 @@ public class HighlightInfo implements Segment {
private static final byte AFTER_END_OF_LINE_MASK = 0x4;
private static final byte FILE_LEVEL_ANNOTATION_MASK = 0x8;
private static final byte NEEDS_UPDATE_ON_TYPING_MASK = 0x10;
/** true if this HighlightInfo was created as an error for some unresolved reference, so there likely will be some "Import" quickfixes after {@link com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider} being asked about em */
/** true if this HighlightInfo was created as an error for some unresolved reference, so there likely will be some "Import" quickfixes after {@link UnresolvedReferenceQuickFixProvider} being asked about em */
private static final byte UNRESOLVED_REFERENCE_QUICK_FIXES_COMPUTED_MASK = 0x20;
@MagicConstant(intValues = {HAS_HINT_MASK, FROM_INJECTION_MASK, AFTER_END_OF_LINE_MASK, FILE_LEVEL_ANNOTATION_MASK, NEEDS_UPDATE_ON_TYPING_MASK, UNRESOLVED_REFERENCE_QUICK_FIXES_COMPUTED_MASK})
@@ -87,13 +87,17 @@ public class HighlightInfo implements Segment {
* @deprecated use {@link #findRegisteredQuickFix(BiFunction)} instead
*/
@Deprecated
@Unmodifiable
public List<Pair<IntentionActionDescriptor, TextRange>> quickFixActionRanges;
/**
* @deprecated use {@link #findRegisteredQuickFix(BiFunction)} instead
*/
@Deprecated
@Unmodifiable
public List<Pair<IntentionActionDescriptor, RangeMarker>> quickFixActionMarkers;
private @Unmodifiable List<IntentionActionDescriptor> myIntentionActionDescriptors = List.of();
private final @DetailedDescription String description;
private final @Tooltip String toolTip;
private final @NotNull HighlightSeverity severity;
@@ -105,9 +109,9 @@ public class HighlightInfo implements Segment {
* Quick fix text range: the range within which the Alt-Enter should open the quick fix popup.
* Might be bigger than (getStartOffset(), getEndOffset()) when it's deemed more usable,
* e.g., when "import class" fix wanted to be Alt-Entered from everywhere at the same line.
*
*/
private long fixRange;
private @Nullable("null means it's the same as highlighter") RangeMarker fixMarker;
/**
* @see FlagConstant for allowed values
*/
@@ -117,10 +121,9 @@ public class HighlightInfo implements Segment {
private @Nullable Object fileLevelComponentsStorage;
private @Nullable("null means it the same as highlighter") RangeMarker fixMarker;
private volatile RangeHighlighterEx highlighter;
/**
* in case this HighlightInfo is created to highlight unresolved reference, store this reference here to be able to call {@link com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider} later
* in case this HighlightInfo is created to highlight unresolved reference, store this reference here to be able to call {@link UnresolvedReferenceQuickFixProvider} later
*/
final PsiReference unresolvedReference;
@@ -171,34 +174,19 @@ public class HighlightInfo implements Segment {
}
/**
* Find the quickfix (among ones added by {@link #registerFix}) selected by returning non-null value from the {@code predicate}
* Find the quickfix (among ones added by {@link #registerFixes}) selected by returning non-null value from the {@code predicate}
* and return that value, or null if the quickfix was not found.
*/
public <T> T findRegisteredQuickFix(@NotNull BiFunction<? super @NotNull IntentionActionDescriptor, ? super @NotNull TextRange, ? extends @Nullable T> predicate) {
Set<IntentionActionDescriptor> processed = new HashSet<>();
List<Pair<IntentionActionDescriptor, RangeMarker>> markers;
List<Pair<IntentionActionDescriptor, TextRange>> ranges;
synchronized (this) {
markers = quickFixActionMarkers;
ranges = quickFixActionRanges;
}
// prefer range markers as having more actual offsets
T result = find(markers, processed, predicate);
if (result != null) return result;
return find(ranges, processed, predicate);
}
private static @Nullable <T> T find(@Nullable List<? extends Pair<IntentionActionDescriptor, ? extends Segment>> markers,
@NotNull Set<? super IntentionActionDescriptor> processed,
@NotNull BiFunction<? super @NotNull IntentionActionDescriptor, ? super @NotNull TextRange, ? extends T> predicate) {
if (markers != null) {
for (Pair<IntentionActionDescriptor, ? extends Segment> pair : markers) {
Segment segment = pair.second;
TextRange range = segment instanceof RangeMarker ? ((RangeMarker)segment).isValid() ? ((RangeMarker)segment).getTextRange() : null : (TextRange)segment;
if (range == null) continue;
IntentionActionDescriptor descriptor = pair.first;
for (IntentionActionDescriptor descriptor : myIntentionActionDescriptors) {
TextRange fixRange = descriptor.getFixRange();
if (fixRange == null) {
fixRange = TextRange.create(this);
}
if (!processed.add(descriptor)) continue;
T result = predicate.apply(descriptor, range);
T result = predicate.apply(descriptor, fixRange);
if (result != null) {
return result;
}
@@ -500,10 +488,8 @@ public class HighlightInfo implements Segment {
if (getDescription() != null) s += ", description='" + getDescription() + "'";
s += "; severity=" + getSeverity();
synchronized (this) {
if (quickFixActionRanges != null) {
s += "; quickFixes: " + StringUtil.join(
quickFixActionRanges, q -> ReportingClassSubstitutor.getClassToReport(q.getFirst().myAction).getName(), ", ");
}
s += "; quickFixes: " + StringUtil.join(
myIntentionActionDescriptors, q -> ReportingClassSubstitutor.getClassToReport(q.myAction).getName(), ", ");
}
if (gutterIconRenderer != null) {
s += "; gutter: " + gutterIconRenderer;
@@ -514,6 +500,9 @@ public class HighlightInfo implements Segment {
if (forcedTextAttributesKey != null) {
s += "; forcedTextAttributesKey: " + forcedTextAttributesKey;
}
if (unresolvedReference != null) {
s += "; unresolvedReference: " + unresolvedReference;
}
return s;
}
@@ -633,11 +622,12 @@ public class HighlightInfo implements Segment {
List<? extends Annotation.QuickFixInfo> fixes = batchMode ? annotation.getBatchFixes() : annotation.getQuickFixes();
if (fixes != null) {
for (Annotation.QuickFixInfo quickFixInfo : fixes) {
TextRange range = quickFixInfo.textRange;
HighlightDisplayKey k = quickFixInfo.key != null ? quickFixInfo.key : HighlightDisplayKey.find(ANNOTATOR_INSPECTION_SHORT_NAME);
info.registerFix(quickFixInfo.quickFix, null, HighlightDisplayKey.getDisplayNameByKey(k), range, k);
}
List<IntentionActionDescriptor> qfrs = ContainerUtil.map(fixes, af -> {
TextRange range = af.textRange;
HighlightDisplayKey k = af.key != null ? af.key : HighlightDisplayKey.find(ANNOTATOR_INSPECTION_SHORT_NAME);
return new IntentionActionDescriptor(af.quickFix, null, HighlightDisplayKey.getDisplayNameByKey(k), null, k, annotation.getProblemGroup(), info.getSeverity(), range);
});
info.registerFixes(qfrs);
}
return info;
@@ -705,15 +695,23 @@ public class HighlightInfo implements Segment {
public static class IntentionActionDescriptor {
private final IntentionAction myAction;
volatile List<? extends IntentionAction> myOptions;
volatile List<? extends IntentionAction> myOptions; // null means not initialized yet
final @Nullable HighlightDisplayKey myKey;
private final ProblemGroup myProblemGroup;
private final HighlightSeverity mySeverity;
private final @Nls String myDisplayName;
private final Icon myIcon;
private Boolean myCanCleanup;
private TextRange myFixRange;
/**
* either {@link TextRange} (when the info is just created) or {@link RangeMarker} (when the info is bound to the document)
* maybe null or empty, in which case it's considered to be equal to the info's range
*/
private Segment myFixRange;
/**
* @deprecated use {@link #IntentionActionDescriptor(IntentionAction, List, String, Icon, HighlightDisplayKey, ProblemGroup, HighlightSeverity, Segment)}
*/
@Deprecated
public IntentionActionDescriptor(@NotNull IntentionAction action,
@Nullable List<? extends IntentionAction> options,
@Nullable @Nls String displayName,
@@ -721,6 +719,17 @@ public class HighlightInfo implements Segment {
@Nullable HighlightDisplayKey key,
@Nullable ProblemGroup problemGroup,
@Nullable HighlightSeverity severity) {
this(action, options, displayName, icon, key, problemGroup, severity, null);
}
public IntentionActionDescriptor(@NotNull IntentionAction action,
@Nullable List<? extends IntentionAction> options,
@Nullable @Nls String displayName,
@Nullable Icon icon,
@Nullable HighlightDisplayKey key,
@Nullable ProblemGroup problemGroup,
@Nullable HighlightSeverity severity,
@Nullable Segment fixRange) {
myAction = action;
myOptions = options;
myDisplayName = displayName;
@@ -728,9 +737,11 @@ public class HighlightInfo implements Segment {
myKey = key;
myProblemGroup = problemGroup;
mySeverity = severity;
myFixRange = fixRange;
}
@Nullable IntentionActionDescriptor copyWithEmptyAction() {
@Nullable
IntentionActionDescriptor withEmptyAction() {
if (myKey == null || myKey.getID().equals(ANNOTATOR_INSPECTION_SHORT_NAME)) {
// No need to show "Inspection 'Annotator' options" quick fix, it wouldn't be actionable.
return null;
@@ -739,7 +750,11 @@ public class HighlightInfo implements Segment {
String displayName = HighlightDisplayKey.getDisplayNameByKey(myKey);
if (displayName == null) return null;
return new IntentionActionDescriptor(new EmptyIntentionAction(displayName), myOptions, myDisplayName, myIcon,
myKey, myProblemGroup, mySeverity);
myKey, myProblemGroup, mySeverity, myFixRange);
}
@NotNull
IntentionActionDescriptor withFixRange(@NotNull TextRange fixRange) {
return new IntentionActionDescriptor(myAction, myOptions, myDisplayName, myIcon, myKey, myProblemGroup, mySeverity, fixRange);
}
public @NotNull IntentionAction getAction() {
@@ -887,11 +902,8 @@ public class HighlightInfo implements Segment {
* Used to check intention's availability at given offset
*/
public TextRange getFixRange() {
return myFixRange;
}
void setFixRange(@NotNull TextRange fixRange) {
myFixRange = fixRange;
Segment range = myFixRange;
return range instanceof TextRange tr ? tr : range instanceof RangeMarker marker ? marker.getTextRange() : null;
}
}
@@ -927,61 +939,71 @@ public class HighlightInfo implements Segment {
/**
* @deprecated Use {@link Builder#registerFix(IntentionAction, List, String, TextRange, HighlightDisplayKey)} instead
* Invoking this method might lead to disappearing/flickering quick fixes, due to inherent data races because of the unrestricted call context.
*/
@Deprecated
public synchronized // synchronized to avoid concurrent access to quickFix* fields; TODO rework to lock-free
void registerFix(@Nullable IntentionAction action,
public
void registerFix(@NotNull IntentionAction action,
@Nullable List<? extends IntentionAction> options,
@Nullable @Nls String displayName,
@Nullable TextRange fixRange,
@Nullable HighlightDisplayKey key) {
if (action == null) return;
if (fixRange == null) fixRange = new TextRange(getActualStartOffset(), getActualEndOffset());
if (quickFixActionRanges == null) {
quickFixActionRanges = ContainerUtil.createLockFreeCopyOnWriteList();
registerFixes(List.of(new IntentionActionDescriptor(action, options, displayName, null, key, myProblemGroup, getSeverity(), fixRange)));
}
synchronized // synchronized to avoid concurrent access to quickFix* fields; TODO rework to lock-free
void registerFixes(@NotNull List<? extends @NotNull IntentionActionDescriptor> fixes) {
if (fixes.isEmpty()) {
return;
}
IntentionActionDescriptor desc =
new IntentionActionDescriptor(action, options, displayName, null, key, getProblemGroup(), getSeverity());
quickFixActionRanges.add(Pair.create(desc, fixRange));
if (fixMarker != null && fixMarker.isValid()) {
this.fixRange = TextRangeScalarUtil.toScalarRange(fixMarker);
}
else {
RangeMarker fixMarker = this.fixMarker;
RangeHighlighterEx highlighter = this.highlighter;
Document document = fixMarker != null ? fixMarker.getDocument() :
highlighter != null ? highlighter.getDocument() :
quickFixActionMarkers != null && !quickFixActionMarkers.isEmpty() && quickFixActionMarkers.get(0).getSecond() != null ? quickFixActionMarkers.get(0).getSecond().getDocument() :
null;
if (document != null) {
// coerce fixRange inside document
int newEnd = Math.min(document.getTextLength(), TextRangeScalarUtil.endOffset(this.fixRange));
int newStart = Math.min(newEnd, TextRangeScalarUtil.startOffset(this.fixRange));
this.fixRange = TextRangeScalarUtil.toScalarRange(newStart, newEnd);
Document document = null;
List<IntentionActionDescriptor> result = new ArrayList<>(myIntentionActionDescriptors.size() + fixes.size());
result.addAll(myIntentionActionDescriptors);
for (IntentionActionDescriptor descriptor : fixes) {
if (descriptor.myAction instanceof HintAction) {
setHint(true);
}
if (descriptor.myFixRange instanceof RangeMarker marker) {
document = marker.getDocument();
}
TextRange fixRange = descriptor.getFixRange();
if (fixRange == null) {
fixRange = TextRange.create(this);
descriptor = descriptor.withFixRange(fixRange);
}
result.add(descriptor);
this.fixRange = TextRangeScalarUtil.union(this.fixRange, TextRangeScalarUtil.toScalarRange(fixRange));
}
this.fixRange = TextRangeScalarUtil.union(this.fixRange, TextRangeScalarUtil.toScalarRange(fixRange));
if (action instanceof HintAction) {
setHint(true);
myIntentionActionDescriptors = List.copyOf(result);
RangeHighlighterEx highlighter = this.highlighter;
if (document == null) {
RangeMarker fixMarker = this.fixMarker;
document = fixMarker != null ? fixMarker.getDocument() :
highlighter != null ? highlighter.getDocument() :
null;
}
RangeHighlighterEx myHighlighter = highlighter;
if (myHighlighter != null && myHighlighter.isValid()) {
// highlighter already has been created, we need to update quickFixActionMarkers
long highlighterRange = TextRangeScalarUtil.toScalarRange(myHighlighter);
Long2ObjectMap<RangeMarker> cache = reuseRangeMarkerCacheIfCreated(highlighterRange);
updateQuickFixFields(myHighlighter.getDocument(), cache, highlighterRange);
if (document != null) {
// coerce fixRange inside document
int newEnd = Math.min(document.getTextLength(), TextRangeScalarUtil.endOffset(this.fixRange));
int newStart = Math.min(newEnd, TextRangeScalarUtil.startOffset(this.fixRange));
this.fixRange = TextRangeScalarUtil.toScalarRange(newStart, newEnd);
}
if (highlighter != null && highlighter.isValid()) {
//highlighter already has been created, we need to update quickFixActionMarkers
long highlighterRange = TextRangeScalarUtil.toScalarRange(highlighter);
Long2ObjectMap<RangeMarker> cache = getRangeMarkerCache();
updateQuickFixFields(highlighter.getDocument(), cache, highlighterRange);
}
}
private @NotNull Long2ObjectMap<RangeMarker> reuseRangeMarkerCacheIfCreated(long targetRange) {
@NotNull
private Long2ObjectMap<RangeMarker> getRangeMarkerCache() {
Long2ObjectMap<RangeMarker> cache = new Long2ObjectOpenHashMap<>();
if (quickFixActionMarkers != null) {
for (Pair<IntentionActionDescriptor, RangeMarker> pair : quickFixActionMarkers) {
RangeMarker marker = pair.getSecond();
if (marker.isValid() && TextRangeScalarUtil.toScalarRange(marker) == targetRange) {
cache.put(targetRange, marker);
break;
}
for (IntentionActionDescriptor pair : myIntentionActionDescriptors) {
Segment fixRange = pair.myFixRange;
if (fixRange instanceof RangeMarker marker && marker.isValid()) {
cache.put(TextRangeScalarUtil.toScalarRange(marker), marker);
break;
}
}
return cache;
@@ -989,20 +1011,16 @@ public class HighlightInfo implements Segment {
public synchronized //TODO rework to lock-free
void unregisterQuickFix(@NotNull Condition<? super IntentionAction> condition) {
if (quickFixActionRanges != null) {
quickFixActionRanges.removeIf(pair -> condition.value(pair.first.getAction()));
}
if (quickFixActionMarkers != null) {
quickFixActionMarkers.removeIf(pair -> condition.value(pair.first.getAction()));
}
myIntentionActionDescriptors = List.copyOf(ContainerUtil.filter(myIntentionActionDescriptors, descriptor -> !condition.value(descriptor.getAction())));
}
public synchronized IntentionAction getSameFamilyFix(@NotNull IntentionActionWithFixAllOption action) {
if (quickFixActionRanges == null) return null;
for (Pair<IntentionActionDescriptor, TextRange> range : quickFixActionRanges) {
IntentionAction other = IntentionActionDelegate.unwrap(range.first.myAction);
for (IntentionActionDescriptor descriptor : myIntentionActionDescriptors) {
IntentionAction other = IntentionActionDelegate.unwrap(descriptor.getAction());
if (other instanceof IntentionActionWithFixAllOption &&
action.belongsToMyFamily((IntentionActionWithFixAllOption)other)) return other;
action.belongsToMyFamily((IntentionActionWithFixAllOption)other)) {
return other;
}
}
return null;
}
@@ -1038,25 +1056,11 @@ public class HighlightInfo implements Segment {
synchronized void updateQuickFixFields(@NotNull Document document,
@NotNull Long2ObjectMap<RangeMarker> range2markerCache,
long finalHighlighterRange) {
if (quickFixActionMarkers != null && quickFixActionRanges != null && quickFixActionRanges.size() == quickFixActionMarkers.size() +1) {
// markers already created, make quickFixRanges <-> quickFixMarkers consistent by adding new marker to the quickFixMarkers if necessary
Pair<IntentionActionDescriptor, TextRange> last = ContainerUtil.getLastItem(quickFixActionRanges);
Segment textRange = last.getSecond();
if (textRange.getEndOffset() <= document.getTextLength()) {
RangeMarker marker = getOrCreate(document, range2markerCache, TextRangeScalarUtil.toScalarRange(textRange));
quickFixActionMarkers.add(Pair.create(last.getFirst(), marker));
for (IntentionActionDescriptor descriptor : myIntentionActionDescriptors) {
Segment fixRange = descriptor.myFixRange;
if (fixRange instanceof TextRange tr) {
descriptor.myFixRange = getOrCreate(document, range2markerCache, TextRangeScalarUtil.toScalarRange(tr));
}
return;
}
if (quickFixActionRanges != null && quickFixActionMarkers == null) {
List<Pair<IntentionActionDescriptor, RangeMarker>> list = new ArrayList<>(quickFixActionRanges.size());
for (Pair<IntentionActionDescriptor, TextRange> pair : quickFixActionRanges) {
TextRange textRange = pair.second;
if (textRange.getEndOffset() > document.getTextLength()) continue;
RangeMarker marker = getOrCreate(document, range2markerCache, TextRangeScalarUtil.toScalarRange(textRange));
list.add(Pair.create(pair.first, marker));
}
quickFixActionMarkers = ContainerUtil.createLockFreeCopyOnWriteList(list);
}
if (fixRange == finalHighlighterRange) {
fixMarker = null; // null means it the same as highlighter's range
@@ -1093,32 +1097,19 @@ public class HighlightInfo implements Segment {
boolean isInjectionRelated() {
return HighlightInfoUpdaterImpl.isInjectionRelated(toolId);
}
static @NotNull HighlightInfo createComposite(@NotNull List<? extends HighlightInfo> infos) {
// derive composite's offsets from an result with tooltip, if present
// derive composite's offsets from an info with tooltip, if present
HighlightInfo anchorInfo = ContainerUtil.find(infos, info -> info.getToolTip() != null);
if (anchorInfo == null) anchorInfo = infos.get(0);
HighlightInfo result = new HighlightInfo(null, null, anchorInfo.type, anchorInfo.startOffset, anchorInfo.endOffset,
HighlightInfo info = new HighlightInfo(null, null, anchorInfo.type, anchorInfo.startOffset, anchorInfo.endOffset,
createCompositeDescription(infos), createCompositeTooltip(infos),
anchorInfo.type.getSeverity(null), false, null, false, 0,
anchorInfo.getProblemGroup(), null, anchorInfo.getGutterIconRenderer(), anchorInfo.getGroup(),
null);
result.highlighter = anchorInfo.getHighlighter();
//result.myIntentionActionDescriptors = ContainerUtil.concat(ContainerUtil.map(infos, i->((HighlightInfo)i).myIntentionActionDescriptors));
List<Pair<IntentionActionDescriptor, RangeMarker>> markers = ContainerUtil.emptyList();
List<Pair<IntentionActionDescriptor, TextRange>> ranges = ContainerUtil.emptyList();
for (HighlightInfo info : infos) {
if (info.quickFixActionMarkers != null) {
if (markers == ContainerUtil.<Pair<IntentionActionDescriptor, RangeMarker>>emptyList()) markers = new ArrayList<>();
markers.addAll(info.quickFixActionMarkers);
}
if (info.quickFixActionRanges != null) {
if (ranges == ContainerUtil.<Pair<IntentionActionDescriptor, TextRange>>emptyList()) ranges = new ArrayList<>();
ranges.addAll(info.quickFixActionRanges);
}
}
result.quickFixActionMarkers = ContainerUtil.createLockFreeCopyOnWriteList(markers);
result.quickFixActionRanges = ContainerUtil.createLockFreeCopyOnWriteList(ranges);
return result;
info.highlighter = anchorInfo.getHighlighter();
info.myIntentionActionDescriptors = ContainerUtil.concat(ContainerUtil.map(infos, i->((HighlightInfo)i).myIntentionActionDescriptors));
return info;
}
private static @Nullable @NlsSafe String createCompositeDescription(@NotNull List<? extends HighlightInfo> infos) {
StringBuilder description = new StringBuilder();

View File

@@ -16,6 +16,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xml.util.XmlStringUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -47,7 +48,7 @@ final class HighlightInfoB implements HighlightInfo.Builder {
private Object toolId;
private PsiElement psiElement;
private int group;
private final List<FixInfo> fixes = new ArrayList<>();
private final List<HighlightInfo.IntentionActionDescriptor> fixes = new ArrayList<>();
private boolean created;
private PsiReference unresolvedReference;
@@ -222,13 +223,6 @@ final class HighlightInfoB implements HighlightInfo.Builder {
unresolvedReference = ref;
}
private record FixInfo(@NotNull IntentionAction action,
@Nullable List<? extends IntentionAction> options,
@Nls @Nullable String displayName,
@Nullable TextRange fixRange,
@Nullable HighlightDisplayKey key) {
}
@Override
public HighlightInfo.@NotNull Builder registerFix(@NotNull IntentionAction action,
@Nullable List<? extends IntentionAction> options,
@@ -236,7 +230,8 @@ final class HighlightInfoB implements HighlightInfo.Builder {
@Nullable TextRange fixRange,
@Nullable HighlightDisplayKey key) {
assertNotCreated();
fixes.add(new FixInfo(action, options, displayName, fixRange, key));
// both problemGroup and severity are null here since they might haven't been set yet; we'll pass actual values later, in createUnconditionally()
fixes.add(new HighlightInfo.IntentionActionDescriptor(action, options, displayName, null, key, null, null, fixRange));
return this;
}
@@ -262,9 +257,10 @@ final class HighlightInfoB implements HighlightInfo.Builder {
escapedToolTip, severity, isAfterEndOfLine, myNeedsUpdateOnTyping, isFileLevelAnnotation,
navigationShift,
problemGroup, toolId, gutterIconRenderer, group, unresolvedReference);
for (FixInfo fix : fixes) {
info.registerFix(fix.action(), fix.options(), fix.displayName(), fix.fixRange(), fix.key());
}
// fill IntentionActionDescriptor.problemGroup and IntentionActionDescriptor.severity - they can be null because .registerFix() might have been called before .problemGroup() and .severity()
List<HighlightInfo.IntentionActionDescriptor> iads = ContainerUtil.map(fixes, fixInfo -> new HighlightInfo.IntentionActionDescriptor(
fixInfo.getAction(), fixInfo.myOptions, fixInfo.getDisplayName(), fixInfo.getIcon(), fixInfo.myKey, problemGroup, severity, fixInfo.getFixRange()));
info.registerFixes(iads);
return info;
}

View File

@@ -26,6 +26,7 @@ import com.intellij.openapi.util.TextRangeScalarUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.injected.InjectedFileViewProvider;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.ThreeState;
import com.intellij.util.concurrency.EdtExecutorService;
@@ -300,7 +301,10 @@ public final class HighlightingSessionImpl implements HighlightingSession {
return "HighlightingSessionImpl: " +
"myVisibleRange:"+myVisibleRange+
"; myPsiFile: "+myPsiFile+ " (" + myPsiFile.getClass() + ")"+
(myIsEssentialHighlightingOnly ? "; essentialHighlightingOnly":"");
(myIsEssentialHighlightingOnly ? "; essentialHighlightingOnly":"") +
(isCanceled() ? "; canceled" : "") +
(myProgressIndicator.isCanceled() ? "indicator: "+ myProgressIndicator : "")
;
}
// compute additional stuff in background thread

View File

@@ -29,7 +29,7 @@ public class CleanupIntentionMenuContributor implements IntentionMenuContributor
actionDescriptors.add(new HighlightInfo.IntentionActionDescriptor(manager.createCleanupAllIntention(),
manager.getCleanupIntentionOptions(),
InspectionsBundle.message("action.description.code.cleanup.options"),
null, null, null, null));
null, null, null, null, null));
return true;
}
}

View File

@@ -151,7 +151,7 @@ final class DoNotShowInspectionIntentionMenuContributor implements IntentionMenu
String displayName = displayNames.get(shortName);
HighlightInfo.IntentionActionDescriptor actionDescriptor =
new HighlightInfo.IntentionActionDescriptor(intentionAction, null, displayName, null,
key, null, HighlightSeverity.INFORMATION);
key, null, HighlightSeverity.INFORMATION, range);
(problemDescriptor.getHighlightType() == ProblemHighlightType.ERROR
? outIntentions.errorFixesToShow
: outIntentions.intentionsToShow).add(actionDescriptor);

View File

@@ -26,7 +26,7 @@ final class EditorNotificationIntentionMenuContributor implements IntentionMenuC
List<IntentionActionWithOptions> actions = EditorNotifications.getInstance(project).getStoredFileLevelIntentions(fileEditor);
for (IntentionActionWithOptions action : actions) {
intentions.notificationActionsToShow.add(new HighlightInfo.IntentionActionDescriptor(
action, action.getOptions(), null, null, null, null, null));
action, action.getOptions(), null, null, null, null, null, null));
}
}
}

View File

@@ -243,7 +243,7 @@ final class InjectedGeneralHighlightingPass extends ProgressableTextEditorHighli
}
resultSink.accept(InjectedLanguageManagerImpl.INJECTION_BACKGROUND_TOOL_ID, injectedPsi, result);
}
@NotNull
private static List<HighlightInfo> createPatchedInfos(@NotNull HighlightInfo info,
@NotNull PsiFile injectedPsi,
@NotNull DocumentWindow documentWindow,
@@ -276,10 +276,13 @@ final class InjectedGeneralHighlightingPass extends ProgressableTextEditorHighli
info.findRegisteredQuickFix((descriptor, quickfixTextRange) -> {
List<TextRange> editableQF = injectedLanguageManager.intersectWithAllEditableFragments(injectedPsi, quickfixTextRange);
for (TextRange editableRange : editableQF) {
TextRange hostEditableRange = documentWindow.injectedToHost(editableRange);
patched.registerFix(descriptor.getAction(), descriptor.myOptions, descriptor.getDisplayName(), hostEditableRange, descriptor.myKey);
}
List<HighlightInfo.IntentionActionDescriptor> fixes =
ContainerUtil.map(editableQF, editableRange ->
{
TextRange patchedFixRange = documentWindow.injectedToHost(editableRange);
return descriptor.withFixRange(patchedFixRange);
});
patched.registerFixes(fixes);
return null;
});
patched.markFromInjection();

View File

@@ -152,7 +152,7 @@ public final class ShowIntentionsPass extends TextEditorHighlightingPass impleme
});
if (!hasAvailableAction[0] && unavailableAction[0] != null) {
HighlightInfo.IntentionActionDescriptor emptyActionDescriptor = unavailableAction[0].copyWithEmptyAction();
HighlightInfo.IntentionActionDescriptor emptyActionDescriptor = unavailableAction[0].withEmptyAction();
if (emptyActionDescriptor != null) {
outList.add(emptyActionDescriptor);
}
@@ -326,7 +326,6 @@ public final class ShowIntentionsPass extends TextEditorHighlightingPass impleme
boolean added = false;
for (HighlightInfo.IntentionActionDescriptor fix : additionalFixes) {
if (!ContainerUtil.exists(fixes, descriptor -> descriptor.getAction().getText().equals(fix.getAction().getText()))) {
fix.setFixRange(info.getFixTextRange());
fixes.add(fix);
added = true;
}
@@ -391,7 +390,7 @@ public final class ShowIntentionsPass extends TextEditorHighlightingPass impleme
enableDisableIntentionAction.add(new AssignShortcutToIntentionAction(action));
}
HighlightInfo.IntentionActionDescriptor descriptor =
new HighlightInfo.IntentionActionDescriptor(action, enableDisableIntentionAction, null, null, null, null, null);
new HighlightInfo.IntentionActionDescriptor(action, enableDisableIntentionAction, null, null, null, null, null, null);
if (!currentFixes.contains(descriptor)) {
intentions.intentionsToShow.add(descriptor);
}

View File

@@ -2,8 +2,6 @@
package com.intellij.codeInsight.daemon.impl;
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider;
@@ -25,13 +23,11 @@ import com.intellij.openapi.util.*;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.util.concurrency.AppScheduledExecutorService;
import org.jetbrains.annotations.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Manages execution of {@link UnresolvedReferenceQuickFixUpdater#registerQuickFixesLater(PsiReference, HighlightInfo.Builder)} in background.
@@ -57,20 +53,24 @@ public final class UnresolvedReferenceQuickFixUpdaterImpl implements UnresolvedR
for (HighlightInfo info : infos) {
PsiReference reference = info.unresolvedReference;
if (reference == null) continue;
if (info.isUnresolvedReferenceQuickFixesComputed()) continue;
Future<?> job;
PsiElement refElement = ReadAction.compute(() -> reference.getElement());
Future<?> job = refElement.getUserData(JOB);
if (job == null) {
CompletableFuture<Object> newFuture = new CompletableFuture<>();
job = ((UserDataHolderEx)refElement).putUserDataIfAbsent(JOB, newFuture);
if (job == newFuture) {
try {
ReadAction.run(() -> registerReferenceFixes(info, editor, file, reference, new ProperTextRange(file.getTextRange())));
newFuture.complete(null);
}
catch (Throwable t) {
newFuture.completeExceptionally(t);
}
CompletableFuture<Object> newFuture = null;
synchronized (info) {
if (info.isUnresolvedReferenceQuickFixesComputed()) continue;
job = refElement.getUserData(JOB);
if (job == null) {
newFuture = new CompletableFuture<>();
job = ((UserDataHolderEx)refElement).putUserDataIfAbsent(JOB, newFuture);
}
}
if (job == newFuture) {
try {
ReadAction.run(() -> registerReferenceFixes(info, editor, file, reference, new ProperTextRange(file.getTextRange())));
newFuture.complete(null);
}
catch (Throwable t) {
newFuture.completeExceptionally(t);
}
}
try {
@@ -96,31 +96,20 @@ public final class UnresolvedReferenceQuickFixUpdaterImpl implements UnresolvedR
public void startComputingNextQuickFixes(@NotNull PsiFile file, @NotNull Editor editor, @NotNull ProperTextRange visibleRange) {
ApplicationManager.getApplication().assertIsNonDispatchThread();
ApplicationManager.getApplication().assertReadAccessAllowed();
int offset = editor.getCaretModel().getOffset();
Project project = file.getProject();
Document document = editor.getDocument();
AtomicInteger unresolvedInfosProcessed = new AtomicInteger();
// compute unresolved refs suggestions from the caret to two pages down (in case the user is scrolling down, which is often the case)
int startOffset = Math.max(0, visibleRange.getStartOffset());
int endOffset = Math.min(document.getTextLength(), visibleRange.getEndOffset()+visibleRange.getLength());
// first, compute quick fixes close to the caret
DaemonCodeAnalyzerEx.processHighlights(document, project, HighlightSeverity.ERROR, offset,
document.getTextLength(), info -> {
if (!info.isUnresolvedReference()) {
return true;
}
startUnresolvedRefsJob(info, editor, file, visibleRange);
// start no more than two jobs
return unresolvedInfosProcessed.incrementAndGet() <= 2;
});
// then, compute quickfixes inside the entire visible area, to show import hints for all unresolved references in vicinity if enabled
if (DaemonCodeAnalyzerSettings.getInstance().isImportHintEnabled() &&
DaemonCodeAnalyzer.getInstance(myProject).isImportHintsEnabled(file)) {
DaemonCodeAnalyzerEx.processHighlights(document, project, HighlightSeverity.ERROR, visibleRange.getStartOffset(),
visibleRange.getEndOffset(), info -> {
if (info.isUnresolvedReference()) {
startUnresolvedRefsJob(info, editor, file, visibleRange);
}
return true;
});
}
DaemonCodeAnalyzerEx.processHighlights(document, project, HighlightSeverity.ERROR, startOffset, endOffset, info -> {
if (!info.isUnresolvedReference()) {
return true;
}
startUnresolvedRefsJob(info, editor, file, visibleRange);
return true;
});
}
private void startUnresolvedRefsJob(@NotNull HighlightInfo info, @NotNull Editor editor, @NotNull PsiFile file,
@@ -133,19 +122,25 @@ public final class UnresolvedReferenceQuickFixUpdaterImpl implements UnresolvedR
PsiReference reference = info.unresolvedReference;
if (reference == null) return;
PsiElement refElement = reference.getElement();
Future<?> job = refElement.getUserData(JOB);
if (job != null) {
return;
}
if (info.isUnresolvedReferenceQuickFixesComputed()) return;
job = ForkJoinPool.commonPool().submit(ThreadContext.captureThreadContext(() ->
((ApplicationImpl)ApplicationManager.getApplication()).executeByImpatientReader(
() -> ProgressIndicatorUtils.runInReadActionWithWriteActionPriority(
synchronized (info) {
Future<?> job = refElement.getUserData(JOB);
if (job != null) {
return;
}
if (!info.isUnresolvedReferenceQuickFixesComputed()) {
job = ForkJoinPool.commonPool().submit(ThreadContext.captureThreadContext(() ->
((ApplicationImpl)ApplicationManager.getApplication()).executeByImpatientReader(
() -> ProgressIndicatorUtils.runInReadActionWithWriteActionPriority(
() -> registerReferenceFixes(info, editor, file, reference, visibleRange), new DaemonProgressIndicator()))), null);
refElement.putUserData(JOB, job);
refElement.putUserData(JOB, job);
}
}
}
private void registerReferenceFixes(@NotNull HighlightInfo info, @NotNull Editor editor, @NotNull PsiFile file, @NotNull PsiReference reference,
private void registerReferenceFixes(@NotNull HighlightInfo info,
@NotNull Editor editor,
@NotNull PsiFile file,
@NotNull PsiReference reference,
@NotNull ProperTextRange visibleRange) {
ApplicationManager.getApplication().assertIsNonDispatchThread();
ApplicationManager.getApplication().assertReadAccessAllowed();
@@ -155,25 +150,30 @@ public final class UnresolvedReferenceQuickFixUpdaterImpl implements UnresolvedR
// this will be restarted anyway on smart mode switch
return;
}
AtomicBoolean changed = new AtomicBoolean();
try {
UnresolvedReferenceQuickFixProvider.registerReferenceFixes(
reference, new QuickFixActionRegistrarImpl(info) {
@Override
void doRegister(@NotNull IntentionAction action,
@Nls(capitalization = Nls.Capitalization.Sentence) @Nullable String displayName,
@Nullable TextRange fixRange,
@Nullable HighlightDisplayKey key) {
super.doRegister(action, displayName, fixRange, key);
changed.set(true);
}
});
info.setUnresolvedReferenceQuickFixesComputed();
List<HighlightInfo.IntentionActionDescriptor> quickfixes = new ArrayList<>();
UnresolvedReferenceQuickFixProvider.registerReferenceFixes(
reference, new QuickFixActionRegistrarImpl(info) {
@Override
void doRegister(@NotNull IntentionAction action,
@Nls(capitalization = Nls.Capitalization.Sentence) @Nullable String displayName,
@Nullable TextRange fixRange,
@Nullable HighlightDisplayKey key) {
quickfixes.add(new HighlightInfo.IntentionActionDescriptor(action, null, displayName, null, key, info.getProblemGroup(),
info.getSeverity(),fixRange));
}
});
synchronized (info) {
try {
if (!info.isUnresolvedReferenceQuickFixesComputed()) {
info.registerFixes(quickfixes);
info.setUnresolvedReferenceQuickFixesComputed();
}
}
finally {
referenceElement.putUserData(JOB, null);
}
}
finally {
referenceElement.putUserData(JOB, null);
}
if (!changed.get() || ApplicationManager.getApplication().isHeadlessEnvironment()) {
if (quickfixes.isEmpty() || ApplicationManager.getApplication().isHeadlessEnvironment()) {
return;
}
TextEditorHighlightingPass showAutoImportPass = new ShowAutoImportPass(file, editor, visibleRange);
@@ -191,12 +191,12 @@ public final class UnresolvedReferenceQuickFixUpdaterImpl implements UnresolvedR
}
@TestOnly
void waitForBackgroundJobIfStartedInTests(@NotNull HighlightInfo info) throws InterruptedException, ExecutionException, TimeoutException {
void waitForBackgroundJobIfStartedInTests(@NotNull HighlightInfo info, int timeout, @NotNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
PsiReference reference = info.unresolvedReference;
if (reference == null) return;
Future<?> job = reference.getElement().getUserData(JOB);
if (job != null) {
job.get(60, TimeUnit.SECONDS);
job.get(timeout, unit);
}
}
}

View File

@@ -23,7 +23,7 @@ class DeclarativeHintsTogglingIntentionMenuContributor : IntentionMenuContributo
val context = Context.gather(hostFile.project, hostEditor, hostFile) ?: return
for (providerInfo in context.providersToToggle) {
val action = DeclarativeHintsTogglingIntention(providerInfo.providerId, providerInfo.providerName, providerInfo.providerEnabled)
val descriptor = HighlightInfo.IntentionActionDescriptor(action, mutableListOf(), null, null, null, null, HighlightSeverity.INFORMATION)
val descriptor = HighlightInfo.IntentionActionDescriptor(action, listOf(), null, null, null, null, HighlightSeverity.INFORMATION, null)
intentions.intentionsToShow.add(descriptor)
}
val settings = DeclarativeInlayHintsSettings.getInstance()
@@ -46,7 +46,7 @@ class DeclarativeHintsTogglingIntentionMenuContributor : IntentionMenuContributo
DeclarativeHintsTogglingOptionIntention.Mode.EnableProviderAndOption
}
val action = DeclarativeHintsTogglingOptionIntention(optionId, providerId, providersWithOption.providerName, optionInfo.name, mode)
val descriptor = HighlightInfo.IntentionActionDescriptor(action, mutableListOf(), null, null, null, null, HighlightSeverity.INFORMATION)
val descriptor = HighlightInfo.IntentionActionDescriptor(action, listOf(), null, null, null, null, HighlightSeverity.INFORMATION, null)
intentions.intentionsToShow.add(descriptor)
}
}

View File

@@ -187,7 +187,7 @@ public final class CachedIntentions implements IntentionContainer {
intentionAction.updateFromPresentation(presentation);
if (!filter.test(intentionAction)) continue;
HighlightInfo.IntentionActionDescriptor descriptor = new HighlightInfo.IntentionActionDescriptor(
intentionAction, Collections.emptyList(), intentionAction.getText(), intentionAction.getIcon(0), null, null, null);
intentionAction, Collections.emptyList(), intentionAction.getText(), intentionAction.getIcon(0), null, null, null, null);
descriptors.add(descriptor);
hasSeparatorAbove = false;
}

View File

@@ -163,15 +163,15 @@ public class IntentionListStep implements ListPopupStep<IntentionActionWithTextC
}
for (IntentionAction optionIntention : action.getOptionIntentions()) {
intentions.intentionsToShow.add(
new HighlightInfo.IntentionActionDescriptor(optionIntention, null, null, getIcon(optionIntention), null, null, null));
new HighlightInfo.IntentionActionDescriptor(optionIntention, null, null, getIcon(optionIntention), null, null, null, null));
}
for (IntentionAction optionFix : action.getOptionErrorFixes()) {
intentions.errorFixesToShow.add(
new HighlightInfo.IntentionActionDescriptor(optionFix, null, null, getIcon(optionFix), null, null, null));
new HighlightInfo.IntentionActionDescriptor(optionFix, null, null, getIcon(optionFix), null, null, null, null));
}
for (IntentionAction optionFix : action.getOptionInspectionFixes()) {
intentions.inspectionFixesToShow.add(
new HighlightInfo.IntentionActionDescriptor(optionFix, null, null, getIcon(optionFix), null, null, null));
new HighlightInfo.IntentionActionDescriptor(optionFix, null, null, getIcon(optionFix), null, null, null, null));
}
intentions.setTitle(title);

View File

@@ -45,7 +45,7 @@ class SuggestedRefactoringIntentionContributor : IntentionMenuContributor {
// we add it into 'errorFixesToShow' if it's not empty to always be at the top of the list
// we don't add into it if it's empty to keep the color of the bulb
val collectionToAdd = intentions.inspectionFixesToShow
collectionToAdd.add(HighlightInfo.IntentionActionDescriptor(intention, null, null, icon, null, null, null))
collectionToAdd.add(HighlightInfo.IntentionActionDescriptor(intention, null, null, icon, null, null, null, null))
}
private fun suggestRefactoringIntention(hostFile: PsiFile, offset: Int): MyIntention? {

View File

@@ -5,5 +5,5 @@ fun foo() {
fun bar(l: Float) {
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.NumberConversionFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddConversionCallFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.NumberConversionFix

View File

@@ -5,5 +5,5 @@ fun foo() {
fun bar(l: Float) {
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.NumberConversionFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddConversionCallFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.NumberConversionFix

View File

@@ -57,7 +57,7 @@ public class ResourceBundleEditorShowQuickFixesAction extends AnAction {
AllIcons.Actions.IntentionBulb,
sourceKey,
null,
null));
null, null));
isQuickFixListEmpty = false;
}
}