prevent AnnotationHolderImpl from extension, make AnnotationSessionImpl.computeWithSession() the only available mechanism to obtain anno holder

GitOrigin-RevId: 5565124fe4655c87730d3978b92672ed0eea4f90
This commit is contained in:
Alexey Kudravtsev
2024-03-20 12:20:29 +01:00
committed by intellij-monorepo-bot
parent 7714170a67
commit 7a16a7a4c0
13 changed files with 273 additions and 221 deletions

View File

@@ -5,7 +5,7 @@ import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.analysis.AnnotationSessionImpl;
import com.intellij.codeInsight.daemon.impl.AnnotationSessionImpl;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
import com.intellij.codeInspection.ex.Tools;
@@ -329,11 +329,11 @@ public class InspectionValidatorWrapper implements Validator {
private Map<ProblemDescriptor, HighlightDisplayLevel> runXmlFileSchemaValidation(@NotNull XmlFile xmlFile) {
Map<ProblemDescriptor, HighlightDisplayLevel> problemsMap = new LinkedHashMap<>();
return AnnotationSessionImpl.computeWithSession(xmlFile, false, holder -> {
List<ExternalAnnotator<?,?>> annotators = ExternalLanguageAnnotators.allForFile(XMLLanguage.INSTANCE, xmlFile);
for (ExternalAnnotator<?, ?> annotator : annotators) {
processAnnotator(xmlFile, holder, annotator);
for (Annotation annotation : holder) {
List<ExternalAnnotator<?, ?>> annotators = ExternalLanguageAnnotators.allForFile(XMLLanguage.INSTANCE, xmlFile);
for (ExternalAnnotator<?, ?> annotator : annotators) {
AnnotationSessionImpl.computeWithSession(xmlFile, false, annotator, annotationHolder -> {
processAnnotator(xmlFile, ((AnnotationHolderImpl)annotationHolder), annotator);
for (Annotation annotation : ((AnnotationHolderImpl)annotationHolder)) {
HighlightInfo info = HighlightInfo.fromAnnotation(annotator, annotation);
if (info.getSeverity() == HighlightSeverity.INFORMATION) continue;
@@ -342,17 +342,19 @@ public class InspectionValidatorWrapper implements Validator {
if (startElement == null || endElement == null) continue;
ProblemDescriptor descriptor =
myInspectionManager.createProblemDescriptor(startElement, endElement, info.getDescription(), ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
myInspectionManager.createProblemDescriptor(startElement, endElement, info.getDescription(),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
false);
HighlightDisplayLevel level = info.getSeverity() == HighlightSeverity.ERROR? HighlightDisplayLevel.ERROR: HighlightDisplayLevel.WARNING;
HighlightDisplayLevel level =
info.getSeverity() == HighlightSeverity.ERROR ? HighlightDisplayLevel.ERROR : HighlightDisplayLevel.WARNING;
problemsMap.put(descriptor, level);
}
}
holder.assertAllAnnotationsCreated();
if (!holder.hasAnnotations()) return Collections.emptyMap();
return problemsMap;
});
((AnnotationHolderImpl)annotationHolder).assertAllAnnotationsCreated();
return null;
});
}
if (problemsMap.isEmpty()) return Collections.emptyMap();
return problemsMap;
}
private static <X, Y> void processAnnotator(@NotNull XmlFile xmlFile, AnnotationHolderImpl holder, ExternalAnnotator<X, Y> annotator) {
@@ -360,7 +362,7 @@ public class InspectionValidatorWrapper implements Validator {
if (initial != null) {
Y result = annotator.doAnnotate(initial);
if (result != null) {
holder.applyExternalAnnotatorWithContext(xmlFile, annotator, result);
holder.applyExternalAnnotatorWithContext(xmlFile, result);
}
}
}

View File

@@ -13,7 +13,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ObjectUtils;
import com.intellij.util.ReflectionUtilRt;
import com.intellij.util.SmartList;
import com.intellij.xml.util.XmlStringUtil;
@@ -21,21 +20,20 @@ import org.jetbrains.annotations.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/**
* Use {@link AnnotationHolder} instead. The members of this class can suddenly change or disappear.
*/
@ApiStatus.Internal
@ApiStatus.NonExtendable
sealed public class AnnotationHolderImpl extends SmartList<@NotNull Annotation> implements AnnotationHolder
permits AnnotatorRunner.AnnotatorSpecificHolder {
final public class AnnotationHolderImpl extends SmartList<@NotNull Annotation> implements AnnotationHolder {
private static final Logger LOG = Logger.getInstance(AnnotationHolderImpl.class);
private final AnnotationSession myAnnotationSession;
private final boolean myBatchMode;
private Annotator myCurrentAnnotator;
private ExternalAnnotator<?, ?> myExternalAnnotator;
private final AtomicReference<PsiElement> myCurrentElement = new AtomicReference<>();
private final @NotNull Object/*Annotator|ExternalAnnotator*/ myAnnotator;
/**
* @deprecated Do not instantiate the AnnotationHolderImpl directly, please use the one provided via {@link Annotator#annotate(PsiElement, AnnotationHolder)} instead
*/
@@ -44,6 +42,17 @@ sealed public class AnnotationHolderImpl extends SmartList<@NotNull Annotation>
public AnnotationHolderImpl(@NotNull AnnotationSession session, boolean batchMode) {
myAnnotationSession = session;
myBatchMode = batchMode;
myAnnotator = (Annotator)(element, holder) -> {};
}
@ApiStatus.Internal
AnnotationHolderImpl(@NotNull Object/*Annotator|ExternalAnnotator*/ annotator, @NotNull AnnotationSession session, boolean batchMode) {
myAnnotator = annotator;
myAnnotationSession = session;
myBatchMode = batchMode;
if (!(annotator instanceof Annotator) && !(annotator instanceof ExternalAnnotator<?,?>)) {
throw new IllegalArgumentException("annotator must be instanceof Annotator|ExternalAnnotator but got "+annotator.getClass());
}
}
@Override
@@ -197,34 +206,39 @@ sealed public class AnnotationHolderImpl extends SmartList<@NotNull Annotation>
@Override
public @NotNull AnnotationBuilder newAnnotation(@NotNull HighlightSeverity severity, @NotNull @Nls String message) {
return createBuilder(severity, message, myCurrentElement, ObjectUtils.chooseNotNull(myCurrentAnnotator, myExternalAnnotator));
return createBuilder(severity, message);
}
@Override
public @NotNull AnnotationBuilder newSilentAnnotation(@NotNull HighlightSeverity severity) {
return createBuilder(severity, null, myCurrentElement, ObjectUtils.chooseNotNull(myCurrentAnnotator, myExternalAnnotator));
return createBuilder(severity, null);
}
@NotNull
protected B createBuilder(@NotNull HighlightSeverity severity, @Nls String message, PsiElement currentElement, Object currentAnnotator) {
return new B(this, severity, message, currentElement, currentAnnotator);
private B createBuilder(@NotNull HighlightSeverity severity, @Nls String message) {
return new B(this, severity, message, myCurrentElement.get(), myAnnotator);
}
private PsiElement myCurrentElement;
@ApiStatus.Internal
public void runAnnotatorWithContext(@NotNull PsiElement element, @NotNull Annotator annotator) {
myCurrentAnnotator = annotator;
myCurrentElement = element;
annotator.annotate(element, this);
myCurrentElement = null;
myCurrentAnnotator = null;
public void runAnnotatorWithContext(@NotNull PsiElement element) {
myCurrentElement.set(element);
((Annotator)myAnnotator).annotate(element, this);
}
/**
* use {@link #runAnnotatorWithContext(PsiElement)}
*/
@ApiStatus.Internal
public <R> void applyExternalAnnotatorWithContext(@NotNull PsiFile file, @NotNull ExternalAnnotator<?,R> annotator, R result) {
myExternalAnnotator = annotator;
myCurrentElement = file;
annotator.apply(file, result, this);
myCurrentElement = null;
myExternalAnnotator = null;
@Deprecated(forRemoval = true)
public void runAnnotatorWithContext(PsiElement element, Annotator annotator) {
myCurrentElement.set(element);
annotator.annotate(element, this);
}
@ApiStatus.Internal
public <R> void applyExternalAnnotatorWithContext(@NotNull PsiFile file, R result) {
myCurrentElement.set(file);
//noinspection unchecked
((ExternalAnnotator<?,R>)myAnnotator).apply(file, result, this);
}
// to assert each AnnotationBuilder did call .create() in the end

View File

@@ -0,0 +1,82 @@
// 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.lang.annotation.*;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.UserDataHolder;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Function;
@ApiStatus.Internal
public final class AnnotationSessionImpl extends AnnotationSession {
private final UserDataHolder myDataHolder = new UserDataHolderBase();
private volatile TextRange myPriorityRange;
private volatile HighlightSeverity myMinimumSeverity;
private AnnotationSessionImpl(@NotNull PsiFile file) {
super(file);
}
@ApiStatus.Internal
@NotNull
public static AnnotationSession create(@NotNull PsiFile file) {
return new AnnotationSessionImpl(file);
}
/**
* @return text range (inside the {@link #getFile()}) for which annotators should be calculated sooner than for the remaining range in the file.
* Usually this priority range corresponds to the range visible on screen.
*/
public @NotNull TextRange getPriorityRange() {
return Objects.requireNonNullElseGet(myPriorityRange, ()->getFile().getTextRange());
}
@ApiStatus.Internal
void setVR(@NotNull TextRange range) {
myPriorityRange = range;
}
@Override
public <T> @Nullable T getUserData(@NotNull Key<T> key) {
return myDataHolder.getUserData(key);
}
@Override
public <T> void putUserData(@NotNull Key<T> key, @Nullable T value) {
myDataHolder.putUserData(key, value);
}
void setMinimumSeverity(@Nullable HighlightSeverity severity) {
myMinimumSeverity = severity;
}
@Override
public HighlightSeverity getMinimumSeverity() {
return myMinimumSeverity;
}
@ApiStatus.Internal
public static <T> T computeWithSession(@NotNull PsiFile psiFile, boolean batchMode, @NotNull Annotator annotator, @NotNull Function<? super AnnotationHolder, T> runnable) {
return computeWithSession(batchMode, annotator, new AnnotationSessionImpl(psiFile), runnable);
}
@ApiStatus.Internal
public static <T> T computeWithSession(@NotNull PsiFile psiFile, boolean batchMode, @NotNull ExternalAnnotator<?,?> annotator, @NotNull Function<? super AnnotationHolder, T> runnable) {
return computeWithSession(batchMode, annotator, new AnnotationSessionImpl(psiFile), runnable);
}
static <T> T computeWithSession(boolean batchMode,
@NotNull Object annotator,
@NotNull AnnotationSessionImpl session,
@NotNull Function<? super AnnotationHolderImpl, T> runnable) {
AnnotationHolderImpl holder = new AnnotationHolderImpl(annotator, session, batchMode);
return runnable.apply(holder);
}
}

View File

@@ -10,9 +10,7 @@ import com.intellij.injected.editor.DocumentWindow;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageAnnotators;
import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationSession;
import com.intellij.lang.annotation.Annotator;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
@@ -30,11 +28,9 @@ import com.intellij.util.ReflectionUtil;
import com.intellij.util.containers.CollectionFactory;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashingStrategy;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
@@ -127,25 +123,6 @@ final class AnnotatorRunner {
}
}
static final class AnnotatorSpecificHolder extends AnnotationHolderImpl {
private final @NotNull Annotator myAnnotator;
private final @NotNull AtomicReference<? extends PsiElement> myCurrentElement;
AnnotatorSpecificHolder(@NotNull Annotator annotator,
@NotNull AtomicReference<? extends PsiElement> currentElement,
@NotNull AnnotationSession annotationSession,
boolean batchMode) {
super(annotationSession, batchMode);
myAnnotator = annotator;
myCurrentElement = currentElement;
}
@Override
protected @NotNull B createBuilder(@NotNull HighlightSeverity severity, @Nls String message, PsiElement __, Object ___) {
return super.createBuilder(severity, message, myCurrentElement.get(), myAnnotator);
}
}
private void runAnnotator(@NotNull Annotator annotator,
@NotNull List<? extends PsiElement> insideThenOutside,
@NotNull Map<Annotator, Set<Language>> supportedLanguages, @NotNull HighlightInfoUpdater highlightInfoUpdater) {
@@ -153,48 +130,46 @@ final class AnnotatorRunner {
if (supported.isEmpty()) {
return;
}
AtomicReference<PsiElement> currentElement = new AtomicReference<>();
// create AnnotationHolderImpl for each Annotator to make it immutable thread-safe converter to the corresponding HighlightInfo
AnnotationHolderImpl annotationHolder = new AnnotatorSpecificHolder(annotator, currentElement,
AnnotatorRunner.this.myHighlightInfoHolder.getAnnotationSession(),
AnnotatorRunner.this.myBatchMode);
HighlightersRecycler emptyElementRecycler = new HighlightersRecycler(); // no need to call incinerate/release because it's always empty
for (PsiElement element : insideThenOutside) {
if (!supported.contains(element.getLanguage())) {
continue;
}
if (myDumb && !DumbService.isDumbAware(annotator)) {
continue;
}
ProgressManager.checkCanceled();
currentElement.set(element);
int sizeBefore = annotationHolder.size();
annotator.annotate(element, annotationHolder);
int sizeAfter = annotationHolder.size();
List<HighlightInfo> newInfos;
if (sizeBefore == sizeAfter) {
newInfos = List.of();
}
else {
newInfos = new ArrayList<>(sizeAfter - sizeBefore);
for (int i = sizeBefore; i < sizeAfter; i++) {
Annotation annotation = annotationHolder.get(i);
HighlightInfo info = HighlightInfo.fromAnnotation(annotator.getClass(), annotation, myBatchMode);
info.setGroup(-1); // prevent DefaultHighlightProcessor from removing this info, we want to control it ourselves via `psiElementVisited` below
addConvertedToHostInfo(info, newInfos);
if (LOG.isDebugEnabled()) {
LOG.debug("runAnnotator annotation="+annotation+" -> "+newInfos);
}
myAnnotatorStatisticsCollector.reportAnnotationProduced(annotator, annotation);
AnnotationSessionImpl.computeWithSession(myBatchMode, annotator, (AnnotationSessionImpl)myHighlightInfoHolder.getAnnotationSession(), annotationHolder -> {
HighlightersRecycler emptyElementRecycler = new HighlightersRecycler(); // no need to call incinerate/release because it's always empty
for (PsiElement element : insideThenOutside) {
if (!supported.contains(element.getLanguage())) {
continue;
}
results.addAll(newInfos);
if (myDumb && !DumbService.isDumbAware(annotator)) {
continue;
}
ProgressManager.checkCanceled();
int sizeBefore = annotationHolder.size();
annotationHolder.runAnnotatorWithContext(element);
int sizeAfter = annotationHolder.size();
List<HighlightInfo> newInfos;
if (sizeBefore == sizeAfter) {
newInfos = List.of();
}
else {
newInfos = new ArrayList<>(sizeAfter - sizeBefore);
for (int i = sizeBefore; i < sizeAfter; i++) {
Annotation annotation = annotationHolder.get(i);
HighlightInfo info = HighlightInfo.fromAnnotation(annotator.getClass(), annotation, myBatchMode);
info.setGroup(-1); // prevent DefaultHighlightProcessor from removing this info, we want to control it ourselves via `psiElementVisited` below
addConvertedToHostInfo(info, newInfos);
if (LOG.isDebugEnabled()) {
LOG.debug("runAnnotator annotation="+annotation+" -> "+newInfos);
}
myAnnotatorStatisticsCollector.reportAnnotationProduced(annotator, annotation);
}
results.addAll(newInfos);
}
Document hostDocument = myPsiFile.getFileDocument();
if (hostDocument instanceof DocumentWindow w) hostDocument = w.getDelegate();
highlightInfoUpdater.psiElementVisited(annotator.getClass(), element, newInfos, hostDocument, myPsiFile, myProject,
emptyElementRecycler, myHighlightingSession);
}
Document hostDocument = myPsiFile.getFileDocument();
if (hostDocument instanceof DocumentWindow w) hostDocument = w.getDelegate();
highlightInfoUpdater.psiElementVisited(annotator.getClass(), element, newInfos, hostDocument, myPsiFile, myProject,
emptyElementRecycler, myHighlightingSession);
}
return null;
});
}
private static void addPatchedInfos(@NotNull HighlightInfo info,

View File

@@ -6,7 +6,6 @@ import com.intellij.codeHighlighting.Pass;
import com.intellij.codeHighlighting.RainbowHighlighter;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.RainbowVisitor;
import com.intellij.codeInsight.daemon.impl.analysis.AnnotationSessionImpl;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightingLevelManager;
import com.intellij.codeInsight.highlighting.PassRunningAssert;

View File

@@ -1,66 +1,24 @@
// Copyright 2000-2023 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.analysis;
import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl;
import com.intellij.lang.annotation.AnnotationSession;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.UserDataHolder;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Function;
/**
* Do not use, for binary compatibility only
*/
@Deprecated(forRemoval = true)
@ApiStatus.Internal
public final class AnnotationSessionImpl extends AnnotationSession {
private final UserDataHolder myDataHolder = new UserDataHolderBase();
private volatile TextRange myPriorityRange;
private volatile HighlightSeverity myMinimumSeverity;
public class AnnotationSessionImpl {
@ApiStatus.Internal
AnnotationSessionImpl(@NotNull PsiFile file) {
super(file);
}
/**
* @return text range (inside the {@link #getFile()}) for which annotators should be calculated sooner than for the remaining range in the file.
* Usually this priority range corresponds to the range visible on screen.
*/
public @NotNull TextRange getPriorityRange() {
return Objects.requireNonNullElseGet(myPriorityRange, ()->getFile().getTextRange());
}
@ApiStatus.Internal
public void setVR(@NotNull TextRange range) {
myPriorityRange = range;
}
@Override
public <T> @Nullable T getUserData(@NotNull Key<T> key) {
return myDataHolder.getUserData(key);
}
@Override
public <T> void putUserData(@NotNull Key<T> key, @Nullable T value) {
myDataHolder.putUserData(key, value);
}
public void setMinimumSeverity(@Nullable HighlightSeverity severity) {
myMinimumSeverity = severity;
}
@Override
public HighlightSeverity getMinimumSeverity() {
return myMinimumSeverity;
}
public static <T> T computeWithSession(@NotNull PsiFile psiFile, boolean batchMode, @NotNull Function<? super AnnotationHolderImpl, T> runnable) {
AnnotationHolderImpl holder = new AnnotationHolderImpl(new AnnotationSessionImpl(psiFile), batchMode);
AnnotationSession session = com.intellij.codeInsight.daemon.impl.AnnotationSessionImpl.create(psiFile);
AnnotationHolderImpl holder = new AnnotationHolderImpl(session, batchMode);
return runnable.apply(holder);
}
}

View File

@@ -1,6 +1,7 @@
// Copyright 2000-2023 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.analysis;
import com.intellij.codeInsight.daemon.impl.AnnotationSessionImpl;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.HighlightInfoFilter;
import com.intellij.lang.annotation.AnnotationSession;
@@ -23,7 +24,7 @@ public class HighlightInfoHolder {
public HighlightInfoHolder(@NotNull PsiFile contextFile, @NotNull HighlightInfoFilter @NotNull ... filters) {
myContextFile = contextFile;
myAnnotationSession = new AnnotationSessionImpl(contextFile);
myAnnotationSession = AnnotationSessionImpl.create(contextFile);
myFilters = filters;
myInfos = new ArrayList<>(Math.max(10, contextFile.getTextLength() / 800)); // extrapolated from the most error-packed AbstractTreeUI
}

View File

@@ -1,8 +1,10 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInspection;
import com.intellij.codeInsight.daemon.impl.analysis.AnnotationSessionImpl;
import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl;
import com.intellij.codeInsight.daemon.impl.AnnotationSessionImpl;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.ExternalAnnotator;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.diagnostic.Logger;
@@ -10,6 +12,8 @@ import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class ExternalAnnotatorInspectionVisitor extends PsiElementVisitor {
private static final Logger LOG = Logger.getInstance(ExternalAnnotatorInspectionVisitor.class);
@@ -44,10 +48,10 @@ public class ExternalAnnotatorInspectionVisitor extends PsiElementVisitor {
if (annotationResult == null) {
return ProblemDescriptor.EMPTY_ARRAY;
}
return ReadAction.compute(() -> AnnotationSessionImpl.computeWithSession(file, true, annotationHolder -> {
annotationHolder.applyExternalAnnotatorWithContext(file, annotator, annotationResult);
annotationHolder.assertAllAnnotationsCreated();
return ProblemDescriptorUtil.convertToProblemDescriptors(annotationHolder, file);
return ReadAction.compute(() -> AnnotationSessionImpl.computeWithSession(file, true, annotator, annotationHolder -> {
((AnnotationHolderImpl)annotationHolder).applyExternalAnnotatorWithContext(file, annotationResult);
((AnnotationHolderImpl)annotationHolder).assertAllAnnotationsCreated();
return ProblemDescriptorUtil.convertToProblemDescriptors((List<? extends Annotation>)annotationHolder, file);
}));
}
return ProblemDescriptor.EMPTY_ARRAY;

View File

@@ -2,7 +2,6 @@
package com.intellij.codeInsight.daemon.impl;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.daemon.impl.analysis.AnnotationSessionImpl;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightingLevelManager;
import com.intellij.codeInspection.InspectionProfile;
import com.intellij.codeInspection.ex.InspectionProfileImpl;
@@ -54,6 +53,7 @@ public final class ExternalToolPass extends ProgressableTextEditorHighlightingPa
final @NotNull PsiFile psiRoot;
final @NotNull K collectedInfo;
volatile V annotationResult;
volatile AnnotationHolderImpl annotationHolder;
MyData(@NotNull ExternalAnnotator<K,V> annotator, @NotNull PsiFile psiRoot, @NotNull K collectedInfo) {
this.annotator = annotator;
@@ -142,39 +142,36 @@ public final class ExternalToolPass extends ProgressableTextEditorHighlightingPa
}
long modificationStampBefore = myDocument.getModificationStamp();
AnnotationSessionImpl.computeWithSession(myFile, false, annotationHolder -> {
Update update = new Update(myFile) {
@Override
public void setRejected() {
super.setRejected();
if (!myProject.isDisposed()) { // Project close in EDT might call MergeUpdateQueue.dispose which calls setRejected in EDT
doFinish(convertToHighlights(annotationHolder));
}
Update update = new Update(myFile) {
@Override
public void setRejected() {
super.setRejected();
if (!myProject.isDisposed()) { // Project close in EDT might call MergeUpdateQueue.dispose which calls setRejected in EDT
doFinish();
}
}
@Override
public void run() {
if (documentChanged(modificationStampBefore) || myProject.isDisposed()) {
return;
}
// have to instantiate new indicator because the old one (progress) might have already been canceled
DaemonProgressIndicator indicator = new DaemonProgressIndicator();
BackgroundTaskUtil.runUnderDisposeAwareIndicator(myProject, () -> {
// run annotators outside the read action because they could start OSProcessHandler
runChangeAware(myDocument, () -> doAnnotate());
ReadAction.run(() -> {
ProgressManager.checkCanceled();
if (!documentChanged(modificationStampBefore)) {
doApply(annotationHolder);
doFinish(convertToHighlights(annotationHolder));
}
});
}, indicator);
@Override
public void run() {
if (documentChanged(modificationStampBefore) || myProject.isDisposed()) {
return;
}
};
ExternalAnnotatorManager.getInstance().queue(update);
return null;
});
// have to instantiate new indicator because the old one (progress) might have already been canceled
DaemonProgressIndicator indicator = new DaemonProgressIndicator();
BackgroundTaskUtil.runUnderDisposeAwareIndicator(myProject, () -> {
// run annotators outside the read action because they could start OSProcessHandler
runChangeAware(myDocument, () -> doAnnotate());
ReadAction.run(() -> {
ProgressManager.checkCanceled();
if (!documentChanged(modificationStampBefore)) {
doApply();
doFinish();
}
});
}, indicator);
}
};
ExternalAnnotatorManager.getInstance().queue(update);
}
@Override
@@ -206,24 +203,27 @@ public final class ExternalToolPass extends ProgressableTextEditorHighlightingPa
private static <K, V> void doAnnotate(@NotNull MyData<K, V> data) {
try {
data.annotationResult = data.annotator.doAnnotate(data.collectedInfo);
AnnotationSessionImpl.computeWithSession(data.psiRoot, false, data.annotator, annotationHolder -> {
data.annotationHolder = (AnnotationHolderImpl)annotationHolder;
data.annotationResult = data.annotator.doAnnotate(data.collectedInfo);
return null;
});
}
catch (Throwable t) {
processError(t, data.annotator, data.psiRoot);
}
}
private void doApply(@NotNull AnnotationHolderImpl annotationHolder) {
private void doApply() {
for (MyData<?,?> data : myAnnotationData) {
doApply(data, annotationHolder);
doApply(data);
}
annotationHolder.assertAllAnnotationsCreated();
}
private static <K, V> void doApply(@NotNull MyData<K, V> data, @NotNull AnnotationHolderImpl annotationHolder) {
private static <K, V> void doApply(@NotNull MyData<K, V> data) {
if (data.annotationResult != null && data.psiRoot.isValid()) {
try {
annotationHolder.applyExternalAnnotatorWithContext(data.psiRoot, data.annotator, data.annotationResult);
data.annotationHolder.applyExternalAnnotatorWithContext(data.psiRoot, data.annotationResult);
}
catch (Throwable t) {
processError(t, data.annotator, data.psiRoot);
@@ -231,11 +231,11 @@ public final class ExternalToolPass extends ProgressableTextEditorHighlightingPa
}
}
private static @NotNull List<HighlightInfo> convertToHighlights(@NotNull AnnotationHolderImpl holder) {
return ContainerUtil.map(holder, annotation -> HighlightInfo.fromAnnotation(annotation));
}
private void doFinish(@NotNull List<? extends HighlightInfo> highlights) {
private void doFinish() {
List<HighlightInfo> highlights = myAnnotationData.stream()
.flatMap(data ->
ContainerUtil.notNullize(data.annotationHolder).stream().map(annotation -> HighlightInfo.fromAnnotation(data.annotator, annotation)))
.toList();
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
BackgroundUpdateHighlightersUtil.setHighlightersInRange(myRestrictRange, highlights, markupModel, getId(), myHighlightingSession);

View File

@@ -2,7 +2,7 @@
package com.intellij.testFramework.fixtures;
import com.intellij.codeInsight.daemon.impl.*;
import com.intellij.codeInsight.daemon.impl.analysis.AnnotationSessionImpl;
import com.intellij.codeInsight.daemon.impl.AnnotationSessionImpl;
import com.intellij.codeInsight.editorActions.smartEnter.SmartEnterProcessor;
import com.intellij.codeInsight.editorActions.smartEnter.SmartEnterProcessors;
import com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler;
@@ -322,10 +322,10 @@ public final class CodeInsightTestUtil {
@NotNull Consumer<? super Out> resultChecker) {
Out result = annotator.doAnnotate(in);
resultChecker.accept(result);
return AnnotationSessionImpl.computeWithSession(psiFile, false, annotationHolder -> {
ApplicationManager.getApplication().runReadAction(() -> annotationHolder.applyExternalAnnotatorWithContext(psiFile, annotator, result));
annotationHolder.assertAllAnnotationsCreated();
return List.copyOf(annotationHolder);
return AnnotationSessionImpl.computeWithSession(psiFile, false, annotator, annotationHolder -> {
ApplicationManager.getApplication().runReadAction(() -> ((AnnotationHolderImpl)annotationHolder).applyExternalAnnotatorWithContext(psiFile, result));
((AnnotationHolderImpl)annotationHolder).assertAllAnnotationsCreated();
return List.copyOf(((AnnotationHolderImpl)annotationHolder));
});
}
@@ -335,12 +335,12 @@ public final class CodeInsightTestUtil {
@NotNull
public static List<Annotation> testAnnotator(@NotNull Annotator annotator, @NotNull PsiElement @NotNull... elements) {
PsiFile psiFile = elements[0].getContainingFile();
return AnnotationSessionImpl.computeWithSession(psiFile, false, annotationHolder -> {
return AnnotationSessionImpl.computeWithSession(psiFile, false, annotator, annotationHolder -> {
for (PsiElement element : elements) {
annotationHolder.runAnnotatorWithContext(element, annotator);
((AnnotationHolderImpl)annotationHolder).runAnnotatorWithContext(element);
}
annotationHolder.assertAllAnnotationsCreated();
return List.copyOf(annotationHolder);
((AnnotationHolderImpl)annotationHolder).assertAllAnnotationsCreated();
return List.copyOf(((AnnotationHolderImpl)annotationHolder));
});
}

View File

@@ -15,10 +15,11 @@
*/
package org.intellij.plugins.xpathView.util;
import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl;
import com.intellij.codeInsight.daemon.impl.AnnotationSessionImpl;
import com.intellij.lang.ASTNode;
import com.intellij.lang.LanguageAnnotators;
import com.intellij.lang.annotation.Annotation;
import com.intellij.codeInsight.daemon.impl.analysis.AnnotationSessionImpl;
import com.intellij.lang.annotation.Annotator;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.diagnostic.Logger;
@@ -28,6 +29,8 @@ import com.intellij.psi.xml.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public final class MyPsiUtil {
private static final Logger LOG = Logger.getInstance(MyPsiUtil.class);
@@ -155,9 +158,9 @@ public final class MyPsiUtil {
file.accept(new PsiRecursiveElementVisitor() {
@Override
public void visitElement(@NotNull PsiElement element) {
AnnotationSessionImpl.computeWithSession(file, false, holder -> {
holder.runAnnotatorWithContext(element, annotator);
for (Annotation annotation : holder) {
AnnotationSessionImpl.computeWithSession(file, false, annotator, annotationHolder -> {
((AnnotationHolderImpl)annotationHolder).runAnnotatorWithContext(element);
for (Annotation annotation : (List<Annotation>)annotationHolder) {
if (annotation.getSeverity() == HighlightSeverity.ERROR) {
error[0] = annotation.getMessage();
break;

View File

@@ -2,17 +2,20 @@
package com.intellij.util.xml.highlighting;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.daemon.impl.analysis.AnnotationSessionImpl;
import com.intellij.codeInsight.daemon.impl.AnnotationSessionImpl;
import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.InspectionProfile;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ex.InspectionToolWrapper;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.project.Project;
import com.intellij.profile.ProfileChangeAdapter;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.source.xml.XmlFileImpl;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.psi.xml.XmlFile;
@@ -196,7 +199,7 @@ public class DomElementAnnotationsManagerImpl extends DomElementAnnotationsManag
return problemHolder.getAllProblems(inspection);
}
return AnnotationSessionImpl.computeWithSession(domFileElement.getFile(), false, annotationHolder -> {
return AnnotationSessionImpl.computeWithSession(domFileElement.getFile(), false, MyDomElementFakeAnnotator.INSTANCE, annotationHolder -> {
DomElementAnnotationHolder holder = new DomElementAnnotationHolderImpl(onTheFly, domFileElement, annotationHolder);
inspection.checkFileElement(domFileElement, holder);
//noinspection unchecked
@@ -204,6 +207,14 @@ public class DomElementAnnotationsManagerImpl extends DomElementAnnotationsManag
});
}
private static class MyDomElementFakeAnnotator implements Annotator {
private static final MyDomElementFakeAnnotator INSTANCE = new MyDomElementFakeAnnotator();
@Override
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
}
}
public List<DomElementsInspection<?>> getSuitableDomInspections(final DomFileElement<?> fileElement, boolean enabledOnly) {
Class<?> rootType = fileElement.getRootElementClass();
final InspectionProfile profile = getInspectionProfile(fileElement);

View File

@@ -2,11 +2,12 @@
package com.intellij.util.xml;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.daemon.impl.AnnotationSessionImpl;
import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.InspectionProfile;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
import com.intellij.codeInsight.daemon.impl.analysis.AnnotationSessionImpl;
import com.intellij.lang.annotation.Annotator;
import com.intellij.mock.MockInspectionProfile;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
@@ -21,6 +22,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
public class DomHighlightingLiteTest extends DomTestCase {
@@ -118,7 +120,8 @@ public class DomHighlightingLiteTest extends DomTestCase {
}
private DomElementAnnotationHolderImpl createHolder() {
return AnnotationSessionImpl.computeWithSession(myElement.getFile(), false, holder -> new DomElementAnnotationHolderImpl(true, myElement, holder));
Annotator annotator = (element, holder) -> {};
return AnnotationSessionImpl.computeWithSession(myElement.getFile(), false, annotator, holder -> new DomElementAnnotationHolderImpl(true, myElement, holder));
}
private static DomElementsProblemsHolderImpl assertNotEmptyHolder(final DomElementsProblemsHolder holder1) {
@@ -168,7 +171,7 @@ public class DomHighlightingLiteTest extends DomTestCase {
}
};
final StringBuilder s = new StringBuilder();
AnnotationSessionImpl.computeWithSession(myElement.getFile(), false, toFill -> {
AnnotationSessionImpl.computeWithSession(myElement.getFile(), false, annotator, annotationHolder -> {
final MyDomElementsInspection inspection = new MyDomElementsInspection() {
@Override
@@ -176,15 +179,15 @@ public class DomHighlightingLiteTest extends DomTestCase {
s.append("visited");
}
};
annotator.runInspection(inspection, myElement, toFill);
annotator.runInspection(inspection, myElement, annotationHolder);
assertEquals("visited", s.toString());
final DomElementsProblemsHolderImpl holder = assertNotEmptyHolder(myAnnotationsManager.getProblemHolder(myElement));
assertEmpty(toFill);
assertEmpty((Collection<?>)annotationHolder);
annotator.runInspection(inspection, myElement, toFill);
annotator.runInspection(inspection, myElement, annotationHolder);
assertEquals("visited", s.toString());
assertSame(holder, assertNotEmptyHolder(myAnnotationsManager.getProblemHolder(myElement)));
assertEmpty(toFill);
assertEmpty((Collection<?>)annotationHolder);
return null;
});