diff --git a/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java b/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java index 71aa2899ec1d..7d2329aa88fe 100644 --- a/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java @@ -15,29 +15,22 @@ */ package com.intellij.semantic; -import com.intellij.lang.ASTNode; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerAdapter; -import com.intellij.openapi.util.Key; import com.intellij.openapi.util.LowMemoryWatcher; import com.intellij.openapi.util.RecursionGuard; import com.intellij.openapi.util.RecursionManager; import com.intellij.patterns.ElementPattern; -import com.intellij.psi.*; -import com.intellij.psi.impl.PsiFileEx; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiManager; import com.intellij.psi.impl.PsiManagerEx; -import com.intellij.psi.impl.source.tree.LazyParseableElement; import com.intellij.psi.util.PsiModificationTracker; -import com.intellij.util.ConcurrencyUtil; import com.intellij.util.NullableFunction; import com.intellij.util.Processor; import com.intellij.util.SmartList; -import com.intellij.util.containers.ConcurrentWeakHashMap; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.MultiMap; -import com.intellij.util.containers.StripedLockConcurrentHashMap; +import com.intellij.util.containers.*; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.pico.IdeaPicoContainer; import gnu.trove.THashMap; @@ -46,7 +39,8 @@ import org.jetbrains.annotations.Nullable; import java.lang.ref.SoftReference; import java.util.*; -import java.util.concurrent.ConcurrentMap; +import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.concurrent.atomic.AtomicInteger; /** @@ -60,7 +54,7 @@ public class SemServiceImpl extends SemService{ return o2.getUniqueId() - o1.getUniqueId(); } }; - private final ConcurrentWeakHashMap> myCache = new ConcurrentWeakHashMap>(); + private final ConcurrentWeakHashMap> myCache = new ConcurrentWeakHashMap>(); private final MultiMap> myProducers; private final MultiMap myInheritors; private final Project myProject; @@ -163,13 +157,7 @@ public class SemServiceImpl extends SemService{ @Override public void clearCache() { - for (PsiElement element : myCache.keySet()) { - final FileChunk chunk = obtainChunk(element); - if (chunk != null) { - chunk.unhinge(); - } - myCache.remove(element); - } + myCache.clear(); } @Override @@ -197,12 +185,7 @@ public class SemServiceImpl extends SemService{ @Override @Nullable public List getSemElements(final SemKey key, @NotNull final PsiElement psi) { - final PsiElement root = getRootElement(psi); - if (root == null) { - return Collections.emptyList(); - } - - List cached = _getCachedSemElements(key, true, psi, root); + List cached = _getCachedSemElements(key, true, psi); if (cached != null) { return cached; } @@ -218,23 +201,15 @@ public class SemServiceImpl extends SemService{ } if (stamp.mayCacheNow()) { - final ConcurrentMap> persistent = cacheOrGetMap(psi, root); + final SemCacheChunk persistent = getOrCreateChunk(psi); for (SemKey semKey : map.keySet()) { - persistent.putIfAbsent(semKey, map.get(semKey)); + persistent.putSemElements(semKey, map.get(semKey)); } } return new ArrayList(result); } - @Nullable - private static PsiElement getRootElement(@NotNull PsiElement psi) { - if (psi instanceof PsiDirectory || psi instanceof PsiDirectoryContainer) { - return psi; - } - return psi.getContainingFile(); - } - @NotNull private List createSemElements(SemKey key, PsiElement psi) { List result = null; @@ -260,24 +235,20 @@ public class SemServiceImpl extends SemService{ @Override @Nullable public List getCachedSemElements(SemKey key, @NotNull PsiElement psi) { - return _getCachedSemElements(key, false, psi, getRootElement(psi)); + return _getCachedSemElements(key, false, psi); } @Nullable - private List _getCachedSemElements(SemKey key, boolean paranoid, final PsiElement element, - @Nullable PsiElement root) { - final FileChunk chunk = obtainChunk(root); + private List _getCachedSemElements(SemKey key, boolean paranoid, final PsiElement element) { + final SemCacheChunk chunk = obtainChunk(element); if (chunk == null) return null; - final ConcurrentMap> map = chunk.map.get(element); - if (map == null) return null; - List singleList = null; LinkedHashSet result = null; final List inheritors = (List)myInheritors.get(key); //noinspection ForLoopReplaceableByForEach for (int i = 0; i < inheritors.size(); i++) { - List cached = (List)map.get(inheritors.get(i)); + List cached = (List)chunk.getSemElements(inheritors.get(i)); if (cached == null && paranoid) { return null; @@ -309,72 +280,45 @@ public class SemServiceImpl extends SemService{ } @Nullable - private FileChunk obtainChunk(@Nullable PsiElement root) { - final SoftReference ref = myCache.get(root); + private SemCacheChunk obtainChunk(@Nullable PsiElement root) { + final SoftReference ref = myCache.get(root); return ref == null ? null : ref.get(); } @Override public void setCachedSemElement(SemKey key, @NotNull PsiElement psi, @Nullable T semElement) { - final PsiElement rootElement = getRootElement(psi); - if (rootElement != null) { - cacheOrGetMap(psi, rootElement).put(key, ContainerUtil.createMaybeSingletonList(semElement)); - } + getOrCreateChunk(psi).putSemElements(key, ContainerUtil.createMaybeSingletonList(semElement)); } @Override public void clearCachedSemElements(@NotNull PsiElement psi) { - final FileChunk chunk = obtainChunk(getRootElement(psi)); - if (chunk != null) { - chunk.map.remove(psi); - } + myCache.remove(psi); } - private ConcurrentMap> cacheOrGetMap(final PsiElement element, @NotNull PsiElement root) { - FileChunk chunk = obtainChunk(root); + private SemCacheChunk getOrCreateChunk(final PsiElement element) { + SemCacheChunk chunk = obtainChunk(element); if (chunk == null) { synchronized (myCache) { - chunk = obtainChunk(root); + chunk = obtainChunk(element); if (chunk == null) { - myCache.put(root, new SoftReference(chunk = new FileChunk(root))); + myCache.put(element, new SoftReference(chunk = new SemCacheChunk())); } } } - - ConcurrentMap> map = chunk.map.get(element); - if (map == null) { - map = ConcurrencyUtil.cacheOrGet(chunk.map, element, new StripedLockConcurrentHashMap>()); - } - return map; + return chunk; } - private static class FileChunk { - private static final Key SEM_SERVICE_CHUNK = Key.create("semServiceChunkHardReference"); - final ConcurrentMap>> map = new StripedLockConcurrentHashMap>>(); - @Nullable final PsiElement anchor; + private static class SemCacheChunk { + private final ConcurrentIntObjectMap> map = new StripedLockIntObjectConcurrentHashMap>(); - FileChunk(PsiElement root) { - if (root instanceof PsiFile) { - if (!(root instanceof PsiFileEx) || ((PsiFileEx)root).isContentsLoaded()) { - final ASTNode node = root.getNode(); - if (node instanceof LazyParseableElement && ((LazyParseableElement)node).isParsed()) { - final PsiElement child = root.getFirstChild(); - if (child != null) { - anchor = child; - child.putUserData(SEM_SERVICE_CHUNK, this); - return; - } - } - } - } - anchor = null; + public List getSemElements(SemKey key) { + return map.get(key.getUniqueId()); } - void unhinge() { - if (anchor != null) { - anchor.putUserData(SEM_SERVICE_CHUNK, null); - } + public void putSemElements(SemKey key, List elements) { + map.put(key.getUniqueId(), elements); } + } }