mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
clear references to dom problem holders on a PSI change (needed for IDEA-225622 to avoid leaks)
instead of user data with a complicated CachedValue-based uptodateness check, keep holders in a single map GitOrigin-RevId: 381ceeb72ccdea854ae433764b97a1cefc5d1662
This commit is contained in:
committed by
intellij-monorepo-bot
parent
57756544af
commit
1b600a5f5f
+30
-34
@@ -11,19 +11,16 @@ import com.intellij.codeInspection.ex.InspectionToolWrapper;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.profile.ProfileChangeAdapter;
|
||||
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
|
||||
import com.intellij.psi.util.CachedValue;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.impl.source.xml.XmlFileImpl;
|
||||
import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.EventDispatcher;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import com.intellij.util.xml.DomElement;
|
||||
import com.intellij.util.xml.DomFileElement;
|
||||
import com.intellij.util.xml.DomUtil;
|
||||
@@ -32,12 +29,11 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DomElementAnnotationsManagerImpl extends DomElementAnnotationsManager {
|
||||
public static final Object LOCK = new Object();
|
||||
static final Object LOCK = new Object();
|
||||
|
||||
private static final Key<DomElementsProblemsHolderImpl> DOM_PROBLEM_HOLDER_KEY = Key.create("DomProblemHolder");
|
||||
private static final Key<CachedValue<Boolean>> CACHED_VALUE_KEY = Key.create("DomProblemHolderCachedValue");
|
||||
private final EventDispatcher<DomHighlightingListener> myDispatcher = EventDispatcher.create(DomHighlightingListener.class);
|
||||
|
||||
private static final DomElementsProblemsHolder EMPTY_PROBLEMS_HOLDER = new DomElementsProblemsHolder() {
|
||||
@@ -75,11 +71,11 @@ public class DomElementAnnotationsManagerImpl extends DomElementAnnotationsManag
|
||||
}
|
||||
|
||||
};
|
||||
private final Project myProject;
|
||||
private final Map<XmlTag, DomElementsProblemsHolderImpl> myHolders = ContainerUtil.createWeakMap();
|
||||
|
||||
public DomElementAnnotationsManagerImpl(@NotNull Project project) {
|
||||
myProject = project;
|
||||
project.getMessageBus().connect().subscribe(ProfileChangeAdapter.TOPIC, new ProfileChangeAdapter() {
|
||||
MessageBusConnection connection = project.getMessageBus().connect();
|
||||
connection.subscribe(ProfileChangeAdapter.TOPIC, new ProfileChangeAdapter() {
|
||||
@Override
|
||||
public void profileActivated(InspectionProfile oldProfile, @Nullable InspectionProfile profile) {
|
||||
dropAnnotationsCache();
|
||||
@@ -90,11 +86,14 @@ public class DomElementAnnotationsManagerImpl extends DomElementAnnotationsManag
|
||||
dropAnnotationsCache();
|
||||
}
|
||||
});
|
||||
connection.subscribe(PsiModificationTracker.TOPIC, this::dropAnnotationsCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropAnnotationsCache() {
|
||||
incModificationCount();
|
||||
synchronized (LOCK) {
|
||||
myHolders.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public final List<DomElementProblemDescriptor> appendProblems(@NotNull DomFileElement element, @NotNull DomElementAnnotationHolder annotationHolder, Class<? extends DomElementsInspection> inspectionClass) {
|
||||
@@ -107,40 +106,37 @@ public class DomElementAnnotationsManagerImpl extends DomElementAnnotationsManag
|
||||
return Collections.unmodifiableList(holderImpl);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private DomElementsProblemsHolderImpl _getOrCreateProblemsHolder(final DomFileElement element) {
|
||||
DomElementsProblemsHolderImpl holder;
|
||||
final DomElement rootElement = element.getRootElement();
|
||||
final XmlTag rootTag = rootElement.getXmlTag();
|
||||
XmlTag rootTag = element.getRootElement().getXmlTag();
|
||||
if (rootTag == null) return new DomElementsProblemsHolderImpl(element);
|
||||
|
||||
holder = rootTag.getUserData(DOM_PROBLEM_HOLDER_KEY);
|
||||
if (isHolderOutdated(element.getFile()) || holder == null) {
|
||||
holder = new DomElementsProblemsHolderImpl(element);
|
||||
rootTag.putUserData(DOM_PROBLEM_HOLDER_KEY, holder);
|
||||
final CachedValue<Boolean> cachedValue = CachedValuesManager.getManager(myProject).createCachedValue(
|
||||
() -> new CachedValueProvider.Result<>(Boolean.FALSE, element, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT,
|
||||
this, ProjectRootManager.getInstance(myProject)), false);
|
||||
cachedValue.getValue();
|
||||
element.getFile().putUserData(CACHED_VALUE_KEY, cachedValue);
|
||||
}
|
||||
return holder;
|
||||
return myHolders.computeIfAbsent(rootTag, __ -> new DomElementsProblemsHolderImpl(element));
|
||||
}
|
||||
|
||||
public static boolean isHolderUpToDate(DomElement element) {
|
||||
public boolean isHolderUpToDate(DomElement element) {
|
||||
return !isHolderOutdated(DomUtil.getFile(element));
|
||||
}
|
||||
|
||||
public void outdateProblemHolder(DomElement element) {
|
||||
XmlTag rootTag = getRootTagIfParsed(DomUtil.getFile(element));
|
||||
synchronized (LOCK) {
|
||||
return !isHolderOutdated(DomUtil.getFile(element));
|
||||
if (rootTag != null) {
|
||||
myHolders.remove(rootTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void outdateProblemHolder(final DomElement element) {
|
||||
private boolean isHolderOutdated(XmlFile file) {
|
||||
synchronized (LOCK) {
|
||||
DomUtil.getFile(element).putUserData(CACHED_VALUE_KEY, null);
|
||||
XmlTag rootTag = getRootTagIfParsed(file);
|
||||
return rootTag == null || !myHolders.containsKey(rootTag);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isHolderOutdated(final XmlFile file) {
|
||||
final CachedValue<Boolean> cachedValue = file.getUserData(CACHED_VALUE_KEY);
|
||||
return cachedValue == null || !cachedValue.hasUpToDateValue();
|
||||
@Nullable
|
||||
private static XmlTag getRootTagIfParsed(@NotNull XmlFile file) {
|
||||
return ((XmlFileImpl)file).isContentsLoaded() ? file.getRootTag() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -152,7 +148,7 @@ public class DomElementAnnotationsManagerImpl extends DomElementAnnotationsManag
|
||||
synchronized (LOCK) {
|
||||
final XmlTag tag = fileElement.getRootElement().getXmlTag();
|
||||
if (tag != null) {
|
||||
final DomElementsProblemsHolder readyHolder = tag.getUserData(DOM_PROBLEM_HOLDER_KEY);
|
||||
DomElementsProblemsHolder readyHolder = myHolders.get(tag);
|
||||
if (readyHolder != null) {
|
||||
return readyHolder;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class DefaultDomAnnotator implements Annotator {
|
||||
public <T extends DomElement> void runInspection(@Nullable final DomElementsInspection<T> inspection, final DomFileElement<T> fileElement, List<? super Annotation> toFill) {
|
||||
if (inspection == null) return;
|
||||
DomElementAnnotationsManagerImpl annotationsManager = getAnnotationsManager(fileElement);
|
||||
if (DomElementAnnotationsManagerImpl.isHolderUpToDate(fileElement) && annotationsManager.getProblemHolder(fileElement).isInspectionCompleted(inspection)) return;
|
||||
if (annotationsManager.isHolderUpToDate(fileElement) && annotationsManager.getProblemHolder(fileElement).isInspectionCompleted(inspection)) return;
|
||||
|
||||
DomElementAnnotationHolderImpl annotationHolder = new DomElementAnnotationHolderImpl(true, fileElement);
|
||||
inspection.checkFileElement(fileElement, annotationHolder);
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.intellij.util.containers.ClassMap;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.xml.DomElement;
|
||||
import com.intellij.util.xml.DomUtil;
|
||||
import com.intellij.util.xml.highlighting.DomElementAnnotationsManager;
|
||||
import com.intellij.util.xml.highlighting.DomElementAnnotationsManagerImpl;
|
||||
import com.intellij.util.xml.highlighting.DomElementsErrorPanel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -104,7 +105,7 @@ public class DomUIFactoryImpl extends DomUIFactory {
|
||||
isProcessingChange = true;
|
||||
try {
|
||||
for (final DomElement element : elements) {
|
||||
DomElementAnnotationsManagerImpl.outdateProblemHolder(element);
|
||||
((DomElementAnnotationsManagerImpl)DomElementAnnotationsManager.getInstance(element.getManager().getProject())).outdateProblemHolder(element);
|
||||
}
|
||||
CommittableUtil.updateHighlighting(panel);
|
||||
}
|
||||
|
||||
+1
-2
@@ -21,7 +21,6 @@ import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.SimpleModificationTracker;
|
||||
import com.intellij.util.xml.DomElement;
|
||||
import com.intellij.util.xml.DomFileElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -29,7 +28,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.EventListener;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class DomElementAnnotationsManager extends SimpleModificationTracker {
|
||||
public abstract class DomElementAnnotationsManager {
|
||||
|
||||
public static DomElementAnnotationsManager getInstance(Project project) {
|
||||
return ServiceManager.getService(project, DomElementAnnotationsManager.class);
|
||||
|
||||
@@ -157,12 +157,11 @@ public class DomHighlightingLiteTest extends DomTestCase {
|
||||
|
||||
public void testHolderRecreationAfterChange() {
|
||||
myAnnotationsManager.appendProblems(myElement, createHolder(), MyDomElementsInspection.class);
|
||||
assertTrue(DomElementAnnotationsManagerImpl.isHolderUpToDate(myElement));
|
||||
assertTrue(myAnnotationsManager.isHolderUpToDate(myElement));
|
||||
final DomElementsProblemsHolder holder = myAnnotationsManager.getProblemHolder(myElement);
|
||||
|
||||
myElement.incModificationCount();
|
||||
assertFalse(DomElementAnnotationsManagerImpl.isHolderUpToDate(myElement));
|
||||
assertSame(holder, myAnnotationsManager.getProblemHolder(myElement));
|
||||
getPsiManager().dropPsiCaches();
|
||||
assertFalse(myAnnotationsManager.isHolderUpToDate(myElement));
|
||||
|
||||
myAnnotationsManager.appendProblems(myElement, createHolder(), MyDomElementsInspection.class);
|
||||
assertNotSame(holder, assertNotEmptyHolder(myAnnotationsManager.getProblemHolder(myElement)));
|
||||
|
||||
@@ -34,7 +34,6 @@ import java.lang.reflect.Type;
|
||||
* @author peter
|
||||
*/
|
||||
public class MockDomFileElement extends UserDataHolderBase implements DomFileElement<DomElement> {
|
||||
private long myModCount = 0;
|
||||
private DomFileDescription<DomElement> myFileDescription;
|
||||
|
||||
public void setFileDescription(final DomFileDescription<DomElement> fileDescription) {
|
||||
@@ -230,10 +229,7 @@ public class MockDomFileElement extends UserDataHolderBase implements DomFileEle
|
||||
|
||||
@Override
|
||||
public long getModificationCount() {
|
||||
return myModCount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void incModificationCount() {
|
||||
myModCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user