From c7285bb5d30cf4485a11ca1202d2fc395191b3e0 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 1 Sep 2009 14:33:18 +0400 Subject: [PATCH] decoupling CachedValueManager from PSI --- .../JavaConcatenationInjectorManager.java | 4 +- .../src/com/intellij/psi/PsiManager.java | 2 + .../com/intellij/psi/meta/PsiMetaData.java | 3 +- .../intellij/facet/impl/FacetFinderImpl.java | 2 +- .../src/com/intellij/mock/MockPsiManager.java | 8 +- .../impl/ParameterizedCachedValueImpl.java | 295 ------------------ .../com/intellij/psi/impl/PsiCachedValue.java | 78 +++++ .../intellij/psi/impl/PsiCachedValueImpl.java | 56 ++++ .../psi/impl/PsiCachedValuesFactory.java | 54 ++++ .../com/intellij/psi/impl/PsiManagerImpl.java | 12 +- .../psi/impl/PsiParameterizedCachedValue.java | 64 ++++ .../impl/include/FileIncludeManagerImpl.java | 2 +- .../intellij/psi/impl/meta/MetaRegistry.java | 4 +- .../impl/providers/FileReferenceSet.java | 4 +- .../tree/injected/InjectedLanguageUtil.java | 2 +- .../com/intellij/psi/util/CachedValue.java | 25 ++ .../psi/util/CachedValueProvider.java | 61 ++++ .../psi/util/CachedValuesManager.java | 86 +++++ .../psi/util/ParameterizedCachedValue.java | 28 ++ .../ParameterizedCachedValueProvider.java | 23 ++ .../com/intellij/util/CachedValueBase.java} | 206 ++++-------- .../com/intellij/util/CachedValueImpl.java | 65 ++++ .../intellij/util/CachedValuesFactory.java | 17 + .../util}/CachedValuesManagerImpl.java | 29 +- .../util/DefaultCachedValuesFactory.java | 59 ++++ .../util/ParameterizedCachedValueImpl.java | 64 ++++ .../src/META-INF/LangExtensions.xml | 3 + .../src/META-INF/PlatformExtensionPoints.xml | 2 + .../src/META-INF/PlatformExtensions.xml | 3 + .../DomElementAnnotationsManagerImpl.java | 7 +- .../psi/impl/source/xml/XmlDocumentImpl.java | 6 +- 31 files changed, 799 insertions(+), 475 deletions(-) delete mode 100644 platform/lang-impl/src/com/intellij/psi/impl/ParameterizedCachedValueImpl.java create mode 100644 platform/lang-impl/src/com/intellij/psi/impl/PsiCachedValue.java create mode 100644 platform/lang-impl/src/com/intellij/psi/impl/PsiCachedValueImpl.java create mode 100644 platform/lang-impl/src/com/intellij/psi/impl/PsiCachedValuesFactory.java create mode 100644 platform/lang-impl/src/com/intellij/psi/impl/PsiParameterizedCachedValue.java create mode 100644 platform/platform-api/src/com/intellij/psi/util/CachedValue.java create mode 100644 platform/platform-api/src/com/intellij/psi/util/CachedValueProvider.java create mode 100644 platform/platform-api/src/com/intellij/psi/util/CachedValuesManager.java create mode 100644 platform/platform-api/src/com/intellij/psi/util/ParameterizedCachedValue.java create mode 100644 platform/platform-api/src/com/intellij/psi/util/ParameterizedCachedValueProvider.java rename platform/{lang-impl/src/com/intellij/psi/impl/CachedValueImpl.java => platform-impl/src/com/intellij/util/CachedValueBase.java} (57%) create mode 100644 platform/platform-impl/src/com/intellij/util/CachedValueImpl.java create mode 100644 platform/platform-impl/src/com/intellij/util/CachedValuesFactory.java rename platform/{lang-impl/src/com/intellij/psi/impl => platform-impl/src/com/intellij/util}/CachedValuesManagerImpl.java (66%) create mode 100644 platform/platform-impl/src/com/intellij/util/DefaultCachedValuesFactory.java create mode 100644 platform/platform-impl/src/com/intellij/util/ParameterizedCachedValueImpl.java diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/injected/JavaConcatenationInjectorManager.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/injected/JavaConcatenationInjectorManager.java index 575762ab084a..aea014e2bfc6 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/injected/JavaConcatenationInjectorManager.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/injected/JavaConcatenationInjectorManager.java @@ -10,8 +10,8 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.ModificationTracker; import com.intellij.psi.*; -import com.intellij.psi.impl.ParameterizedCachedValueImpl; import com.intellij.psi.impl.PsiManagerEx; +import com.intellij.psi.impl.PsiParameterizedCachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.ParameterizedCachedValue; import com.intellij.psi.util.ParameterizedCachedValueProvider; @@ -123,7 +123,7 @@ public class JavaConcatenationInjectorManager implements ProjectComponent, Modif if (registrar.result != null) { // store this everywhere ParameterizedCachedValue cachedValue = context.getManager().getCachedValuesManager().createParameterizedCachedValue(this, false); - ((ParameterizedCachedValueImpl)cachedValue).setValue(result); + ((PsiParameterizedCachedValue)cachedValue).setValue(result); for (PsiElement operand : operands) { operand.putUserData(INJECTED_PSI_IN_CONCATENATION, cachedValue); diff --git a/platform/lang-api/src/com/intellij/psi/PsiManager.java b/platform/lang-api/src/com/intellij/psi/PsiManager.java index 622a51c84948..ed170a7641d5 100644 --- a/platform/lang-api/src/com/intellij/psi/PsiManager.java +++ b/platform/lang-api/src/com/intellij/psi/PsiManager.java @@ -150,6 +150,8 @@ public abstract class PsiManager extends UserDataHolderBase { * which are automatically recalculated based on changes of the elements on which they depend. * * @return the cached values manager instance. + * @deprecated + * @see CachedValuesManager#getManager(com.intellij.openapi.project.Project) */ @NotNull public abstract CachedValuesManager getCachedValuesManager(); diff --git a/platform/lang-api/src/com/intellij/psi/meta/PsiMetaData.java b/platform/lang-api/src/com/intellij/psi/meta/PsiMetaData.java index d9a4af7638f5..3bbbdf97168b 100644 --- a/platform/lang-api/src/com/intellij/psi/meta/PsiMetaData.java +++ b/platform/lang-api/src/com/intellij/psi/meta/PsiMetaData.java @@ -17,7 +17,6 @@ package com.intellij.psi.meta; import com.intellij.psi.PsiElement; import com.intellij.psi.filters.ElementFilter; -import com.intellij.psi.util.CachedValue; import org.jetbrains.annotations.NonNls; /** @@ -39,7 +38,7 @@ public interface PsiMetaData { /** * @return objects this meta data depends on. - * @see CachedValue + * @see com.intellij.psi.util.CachedValue */ Object[] getDependences(); } diff --git a/platform/lang-impl/src/com/intellij/facet/impl/FacetFinderImpl.java b/platform/lang-impl/src/com/intellij/facet/impl/FacetFinderImpl.java index f4d685869bac..1c9d42606c5b 100644 --- a/platform/lang-impl/src/com/intellij/facet/impl/FacetFinderImpl.java +++ b/platform/lang-impl/src/com/intellij/facet/impl/FacetFinderImpl.java @@ -14,9 +14,9 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.Module; import com.intellij.psi.PsiManager; +import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.CachedValue; -import com.intellij.psi.util.CachedValueProvider; import com.intellij.util.SmartList; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.NotNull; diff --git a/platform/lang-impl/src/com/intellij/mock/MockPsiManager.java b/platform/lang-impl/src/com/intellij/mock/MockPsiManager.java index a455b8656eee..f283fdfeef9c 100644 --- a/platform/lang-impl/src/com/intellij/mock/MockPsiManager.java +++ b/platform/lang-impl/src/com/intellij/mock/MockPsiManager.java @@ -9,10 +9,7 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.impl.CachedValuesManagerImpl; -import com.intellij.psi.impl.PsiManagerEx; -import com.intellij.psi.impl.PsiModificationTrackerImpl; -import com.intellij.psi.impl.PsiTreeChangeEventImpl; +import com.intellij.psi.impl.*; import com.intellij.psi.impl.cache.CacheManager; import com.intellij.psi.impl.cache.impl.CompositeCacheManager; import com.intellij.psi.impl.file.impl.FileManager; @@ -24,6 +21,7 @@ import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.util.IncorrectOperationException; import com.intellij.util.ThrowableRunnable; +import com.intellij.util.CachedValuesManagerImpl; import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -112,7 +110,7 @@ public class MockPsiManager extends PsiManagerEx { @NotNull public CachedValuesManager getCachedValuesManager() { if (myCachedValuesManager == null) { - myCachedValuesManager = new CachedValuesManagerImpl(this); + myCachedValuesManager = new CachedValuesManagerImpl(myProject, new PsiCachedValuesFactory(this)); } return myCachedValuesManager; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/ParameterizedCachedValueImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/ParameterizedCachedValueImpl.java deleted file mode 100644 index cf88e0b15b40..000000000000 --- a/platform/lang-impl/src/com/intellij/psi/impl/ParameterizedCachedValueImpl.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Created by IntelliJ IDEA. - * User: mike - * Date: Jun 6, 2002 - * Time: 5:41:42 PM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ -package com.intellij.psi.impl; - -import com.intellij.openapi.Disposable; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.ModificationTracker; -import com.intellij.openapi.util.Ref; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; -import com.intellij.psi.util.CachedValueProvider; -import com.intellij.psi.util.ParameterizedCachedValue; -import com.intellij.psi.util.ParameterizedCachedValueProvider; -import com.intellij.psi.util.PsiModificationTracker; -import com.intellij.reference.SoftReference; -import com.intellij.util.TimedReference; -import com.intellij.util.ArrayUtil; -import com.intellij.util.concurrency.JBLock; -import com.intellij.util.concurrency.JBReentrantReadWriteLock; -import com.intellij.util.concurrency.LockFactory; -import gnu.trove.TLongArrayList; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.ref.Reference; -import java.util.ArrayList; -import java.util.List; - -public class ParameterizedCachedValueImpl implements ParameterizedCachedValue { - private static final Object NULL = new Object(); - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.CachedValueImpl"); - - private final PsiManager myManager; - private final ParameterizedCachedValueProvider myProvider; - private final boolean myTrackValue; - - private final MyTimedReference myData = new MyTimedReference(); - - private volatile long myLastPsiTimeStamp = -1; - private final JBReentrantReadWriteLock rw = LockFactory.createReadWriteLock(); - private final JBLock r = rw.readLock(); - private final JBLock w = rw.writeLock(); - - public ParameterizedCachedValueImpl(@NotNull PsiManager manager, @NotNull ParameterizedCachedValueProvider provider, boolean trackValue) { - myManager = manager; - myProvider = provider; - myTrackValue = trackValue; - } - - private static class Data implements Disposable { - private final T myValue; - private final Object[] myDependencies; - private final long[] myTimeStamps; - - private Data(final T value, final Object[] dependencies, final long[] timeStamps) { - myValue = value; - myDependencies = dependencies; - myTimeStamps = timeStamps; - } - - public void dispose() { - if (myValue instanceof Disposable) { - Disposer.dispose((Disposable)myValue); - } - } - } - - @Nullable - public T getValue(P param) { - r.lock(); - - T value; - try { - value = getUpToDateOrNull(); - if (value != null) { - return value == NULL ? null : value; - } - } finally { - r.unlock(); - } - - w.lock(); - - try { - value = getUpToDateOrNull(); - if (value != null) { - return value == NULL ? null : value; - } - - CachedValueProvider.Result result = myProvider.compute(param); - value = result == null ? null : result.getValue(); - - setValue(value, result); - - return value; - } - finally { - w.unlock(); - } - } - - private void setValue(final T value, final CachedValueProvider.Result result) { - myData.setData(computeData(value == null ? (T) NULL : value, result == null ? null : result.getDependencyItems())); - if (result != null) { - myData.setIsLocked(result.isLockValue()); - } - else { - myData.setIsLocked(false); - } - } - - public void setDataLocked(boolean value) { - myData.setIsLocked(value); - } - - public boolean hasUpToDateValue() { - r.lock(); - - try { - return getUpToDateOrNull() != null; - } - finally { - r.unlock(); - } - } - - @Nullable - private T getUpToDateOrNull() { - final Data data = myData.getData(); - - if (data != null) { - T value = data.myValue; - if (isUpToDate(data)) { - return value; - } - if (value instanceof Disposable) { - Disposer.dispose((Disposable)value); - } - } - return null; - } - - private boolean isUpToDate(@NotNull Data data) { - if (data.myTimeStamps == null) return true; - if (myManager.isDisposed()) return false; - - for (int i = 0; i < data.myDependencies.length; i++) { - Object dependency = data.myDependencies[i]; - if (dependency == null) continue; - if (isDependencyOutOfDate(dependency, data.myTimeStamps[i])) return false; - } - - return true; - } - - private boolean isDependencyOutOfDate(Object dependency, long oldTimeStamp) { - if (dependency instanceof PsiElement && - myLastPsiTimeStamp == myManager.getModificationTracker().getModificationCount()) { - return false; - } - final long timeStamp = getTimeStamp(dependency); - return timeStamp < 0 || timeStamp != oldTimeStamp; - } - - private Data computeData(T value, Object[] dependencies) { - if (dependencies == null) { - return new Data(value, null, null); - } - - TLongArrayList timeStamps = new TLongArrayList(); - List deps = new ArrayList(); - collectDependencies(timeStamps, deps, dependencies); - if (myTrackValue) { - collectDependencies(timeStamps, deps, new Object[]{value}); - } - - myLastPsiTimeStamp = myManager.getModificationTracker().getModificationCount(); - - return new Data(value, ArrayUtil.toObjectArray(deps), timeStamps.toNativeArray()); - } - - private void collectDependencies(TLongArrayList timeStamps, List resultingDeps, Object[] dependencies) { - for (Object dependency : dependencies) { - if (dependency == null || dependency == NULL) continue; - if (dependency instanceof Object[]) { - collectDependencies(timeStamps, resultingDeps, (Object[])dependency); - } - else { - resultingDeps.add(dependency); - timeStamps.add(getTimeStamp(dependency)); - } - } - } - - private long getTimeStamp(Object dependency) { - if (dependency instanceof Reference){ - final Object original = ((Reference)dependency).get(); - if(original == null) return -1; - return getTimeStamp(original); - } - - if (dependency instanceof Ref) { - final Object original = ((Ref)dependency).get(); - if(original == null) return -1; - return getTimeStamp(original); - } - - if (dependency instanceof ModificationTracker) { - return ((ModificationTracker)dependency).getModificationCount(); - } - - if (dependency instanceof PsiDirectory) { - return myManager.getModificationTracker().getOutOfCodeBlockModificationCount(); - } - - if (dependency instanceof PsiElement) { - PsiElement element = (PsiElement)dependency; - if (!element.isValid()) return -1; - PsiFile containingFile = element.getContainingFile(); - if (containingFile == null) return -1; - return containingFile.getModificationStamp(); - } - - if (dependency == PsiModificationTracker.MODIFICATION_COUNT) { - return myManager.getModificationTracker().getModificationCount(); - } - else if (dependency == PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) { - return myManager.getModificationTracker().getOutOfCodeBlockModificationCount(); - } - else if (dependency == PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT) { - return myManager.getModificationTracker().getJavaStructureModificationCount(); - } - else if (dependency instanceof Document) { - return ((Document)dependency).getModificationStamp(); - } - else { - LOG.error("Wrong dependency type: " + dependency.getClass()); - return -1; - } - } - - public ParameterizedCachedValueProvider getValueProvider() { - return myProvider; - } - - public T setValue(final CachedValueProvider.Result result) { - w.lock(); - - try { - T value = result.getValue(); - setValue(value, result); - return value; - } - finally { - w.unlock(); - } - } - - private static class MyTimedReference extends TimedReference>> { - private boolean myIsLocked; - - - public MyTimedReference() { - super(null); - } - - public void setIsLocked(final boolean isLocked) { - myIsLocked = isLocked; - } - - protected boolean isLocked() { - return super.isLocked() || myIsLocked; - } - - public void setData(final Data data) { - set(new SoftReference>(data)); - } - - @Nullable - public Data getData() { - final SoftReference> ref = get(); - return ref != null ? ref.get() : null; - } - } -} diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiCachedValue.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiCachedValue.java new file mode 100644 index 000000000000..4f891fee9029 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiCachedValue.java @@ -0,0 +1,78 @@ +package com.intellij.psi.impl; + +import com.intellij.psi.PsiManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiModificationTracker; +import com.intellij.openapi.project.Project; +import com.intellij.util.CachedValueBase; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Avdeev + */ +public class PsiCachedValue extends CachedValueBase { + + private final PsiManager myManager; + protected long myLastPsiTimeStamp = -1; + + public PsiCachedValue(PsiManager manager) { + super(); + myManager = manager; + } + + @Override + protected Data computeData(T value, Object[] dependencies) { + Data data = super.computeData(value, dependencies); + + myLastPsiTimeStamp = myManager.getModificationTracker().getModificationCount(); + + return data; + } + + @Override + protected boolean isUpToDate(@NotNull Data data) { + return !myManager.isDisposed() && super.isUpToDate(data); + } + + @Override + protected boolean isDependencyOutOfDate(Object dependency, long oldTimeStamp) { + return !(dependency instanceof PsiElement && myLastPsiTimeStamp == myManager.getModificationTracker().getModificationCount()) && + super.isDependencyOutOfDate(dependency, oldTimeStamp); + + } + + @Override + protected long getTimeStamp(Object dependency) { + + if (dependency instanceof PsiDirectory) { + return myManager.getModificationTracker().getOutOfCodeBlockModificationCount(); + } + + if (dependency instanceof PsiElement) { + PsiElement element = (PsiElement)dependency; + if (!element.isValid()) return -1; + PsiFile containingFile = element.getContainingFile(); + if (containingFile == null) return -1; + return containingFile.getModificationStamp(); + } + + if (dependency == PsiModificationTracker.MODIFICATION_COUNT) { + return myManager.getModificationTracker().getModificationCount(); + } + else if (dependency == PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) { + return myManager.getModificationTracker().getOutOfCodeBlockModificationCount(); + } + else if (dependency == PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT) { + return myManager.getModificationTracker().getJavaStructureModificationCount(); + } + + return super.getTimeStamp(dependency); + } + + @Override + public boolean isFromMyProject(Project project) { + return myManager.getProject() == project; + } +} diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiCachedValueImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiCachedValueImpl.java new file mode 100644 index 000000000000..789babcf4319 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiCachedValueImpl.java @@ -0,0 +1,56 @@ +package com.intellij.psi.impl; + +import com.intellij.psi.PsiManager; +import com.intellij.psi.util.CachedValue; +import com.intellij.psi.util.CachedValueProvider; +import org.jetbrains.annotations.Nullable; + +/** + * @author Dmitry Avdeev + */ +public class PsiCachedValueImpl extends PsiCachedValue implements CachedValue { + private CachedValueProvider myProvider; + + public PsiCachedValueImpl(PsiManager manager, CachedValueProvider provider) { + super(manager); + myProvider = provider; + } + @Nullable + public T getValue() { + + r.lock(); + + T value; + try { + value = getUpToDateOrNull(); + if (value != null) { + return value == NULL ? null : value; + } + } finally { + r.unlock(); + } + + w.lock(); + + try { + value = getUpToDateOrNull(); + if (value != null) { + return value == NULL ? null : value; + } + + CachedValueProvider.Result result = myProvider.compute(); + value = result == null ? null : result.getValue(); + + setValue(value, result); + + return value; + } + finally { + w.unlock(); + } + } + + public CachedValueProvider getValueProvider() { + return myProvider; + } +} diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiCachedValuesFactory.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiCachedValuesFactory.java new file mode 100644 index 000000000000..8151c2e9904d --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiCachedValuesFactory.java @@ -0,0 +1,54 @@ +package com.intellij.psi.impl; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiManager; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.ParameterizedCachedValueProvider; +import com.intellij.psi.util.ParameterizedCachedValue; +import com.intellij.psi.util.CachedValue; +import com.intellij.util.*; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Avdeev + */ +public class PsiCachedValuesFactory implements CachedValuesFactory { + + private final Project myProject; + private final PsiManager myManager; + + public PsiCachedValuesFactory(PsiManager manager) { + myManager = manager; + myProject = manager.getProject(); + } + + public CachedValue createCachedValue(@NotNull CachedValueProvider provider, boolean trackValue) { + return trackValue ? new PsiCachedValueImpl(myManager, provider) { + @Override + protected Object[] getDependencies(CachedValueProvider.Result result) { + return getDependenciesPlusValue(result); + } + } : new PsiCachedValueImpl(myManager, provider) { + }; + } + + public ParameterizedCachedValue createParameterizedCachedValue(@NotNull ParameterizedCachedValueProvider provider, + boolean trackValue) { + return trackValue ? new PsiParameterizedCachedValue(myManager, provider) { + @Override + public boolean isFromMyProject(Project project) { + return myProject == project; + } + + @Override + protected Object[] getDependencies(CachedValueProvider.Result tResult) { + return getDependenciesPlusValue(tResult); + } + } : new PsiParameterizedCachedValue(myManager, provider) { + @Override + public boolean isFromMyProject(Project project) { + return myProject == project; + } + }; + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiManagerImpl.java index e02079b81691..4870b608251e 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiManagerImpl.java @@ -22,6 +22,7 @@ import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileFilter; import com.intellij.psi.*; @@ -64,7 +65,13 @@ public class PsiManagerImpl extends PsiManagerEx implements ProjectComponent { private final CacheManager myCacheManager; private final PsiModificationTrackerImpl myModificationTracker; private final ResolveCache myResolveCache; - private final CachedValuesManager myCachedValuesManager; + private final NotNullLazyValue myCachedValuesManager = new NotNullLazyValue() { + @NotNull + @Override + protected CachedValuesManager compute() { + return CachedValuesManager.getManager(myProject); + } + }; private final List myTreeChangePreprocessors = ContainerUtil.createEmptyCOWList(); private final List myTreeChangeListeners = ContainerUtil.createEmptyCOWList(); @@ -119,7 +126,6 @@ public class PsiManagerImpl extends PsiManagerEx implements ProjectComponent { myModificationTracker = new PsiModificationTrackerImpl(myProject); myTreeChangePreprocessors.add(myModificationTracker); myResolveCache = new ResolveCache(this); - myCachedValuesManager = new CachedValuesManagerImpl(this); if (startupManager != null) { ((StartupManagerEx)startupManager).registerPreStartupActivity( @@ -695,7 +701,7 @@ public class PsiManagerImpl extends PsiManagerEx implements ProjectComponent { @NotNull public CachedValuesManager getCachedValuesManager() { - return myCachedValuesManager; + return myCachedValuesManager.getValue(); } public void moveDirectory(@NotNull final PsiDirectory dir, @NotNull PsiDirectory newParent) throws IncorrectOperationException { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiParameterizedCachedValue.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiParameterizedCachedValue.java new file mode 100644 index 000000000000..1f9f740c6822 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiParameterizedCachedValue.java @@ -0,0 +1,64 @@ +/* + * Created by IntelliJ IDEA. + * User: mike + * Date: Jun 6, 2002 + * Time: 5:41:42 PM + * To change template for new class use + * Code Style | Class Templates options (Tools | IDE Options). + */ +package com.intellij.psi.impl; + +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.ParameterizedCachedValueProvider; +import com.intellij.psi.util.ParameterizedCachedValue; +import com.intellij.psi.PsiManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class PsiParameterizedCachedValue extends PsiCachedValue implements ParameterizedCachedValue { + + private final ParameterizedCachedValueProvider myProvider; + + public PsiParameterizedCachedValue(PsiManager manager, @NotNull ParameterizedCachedValueProvider provider) { + super(manager); + myProvider = provider; + } + + @Nullable + public T getValue(P param) { + r.lock(); + + T value; + try { + value = getUpToDateOrNull(); + if (value != null) { + return value == NULL ? null : value; + } + } finally { + r.unlock(); + } + + w.lock(); + + try { + value = getUpToDateOrNull(); + if (value != null) { + return value == NULL ? null : value; + } + + CachedValueProvider.Result result = myProvider.compute(param); + value = result == null ? null : result.getValue(); + + setValue(value, result); + + return value; + } + finally { + w.unlock(); + } + } + + public ParameterizedCachedValueProvider getValueProvider() { + return myProvider; + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeManagerImpl.java index 175b94a6208c..b4c2d72537ed 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/include/FileIncludeManagerImpl.java @@ -33,7 +33,7 @@ import com.intellij.psi.util.ParameterizedCachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.MultiMap; -import com.intellij.util.ArrayUtil; +import com.intellij.util.*; import java.util.ArrayList; import java.util.List; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/meta/MetaRegistry.java b/platform/lang-impl/src/com/intellij/psi/impl/meta/MetaRegistry.java index 695c510c531c..c41d7e9c03ef 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/meta/MetaRegistry.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/meta/MetaRegistry.java @@ -8,13 +8,13 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.UserDataCache; import com.intellij.patterns.ElementPattern; import com.intellij.psi.PsiElement; +import com.intellij.psi.util.CachedValue; +import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.filters.position.PatternFilter; import com.intellij.psi.meta.MetaDataContributor; import com.intellij.psi.meta.MetaDataRegistrar; import com.intellij.psi.meta.PsiMetaData; -import com.intellij.psi.util.CachedValue; -import com.intellij.psi.util.CachedValueProvider; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java index 7d8fc938712b..d5a31a0a8c37 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java @@ -9,10 +9,10 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; -import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; -import com.intellij.psi.util.PsiModificationTracker; +import com.intellij.psi.util.CachedValue; +import com.intellij.psi.util.*; import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java index 71fe926db88a..652080ca46cb 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java @@ -16,7 +16,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; -import com.intellij.psi.impl.ParameterizedCachedValueImpl; +import com.intellij.util.ParameterizedCachedValueImpl; import com.intellij.psi.impl.PsiDocumentManagerImpl; import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.impl.source.DummyHolder; diff --git a/platform/platform-api/src/com/intellij/psi/util/CachedValue.java b/platform/platform-api/src/com/intellij/psi/util/CachedValue.java new file mode 100644 index 000000000000..a42a9426a82c --- /dev/null +++ b/platform/platform-api/src/com/intellij/psi/util/CachedValue.java @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2007 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.util; + +public interface CachedValue { + + T getValue(); + + CachedValueProvider getValueProvider(); + + boolean hasUpToDateValue(); +} diff --git a/platform/platform-api/src/com/intellij/psi/util/CachedValueProvider.java b/platform/platform-api/src/com/intellij/psi/util/CachedValueProvider.java new file mode 100644 index 000000000000..04e6a3cc58e2 --- /dev/null +++ b/platform/platform-api/src/com/intellij/psi/util/CachedValueProvider.java @@ -0,0 +1,61 @@ +/* + * Copyright 2000-2007 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.util; + +import org.jetbrains.annotations.Nullable; + +public interface CachedValueProvider { + @Nullable + Result compute(); + + class Result { + private final T myValue; + private final Object[] myDependencyItems; + private boolean myLockValue = false; + + public Result(T value, Object... dependencyItems) { + myValue = value; + myDependencyItems = dependencyItems; + } + + public T getValue() { + return myValue; + } + + public Object[] getDependencyItems() { + return myDependencyItems; + } + + public static Result createSingleDependency(T value, Object dependency) { + return create(value, dependency); + } + + public static Result create(T value, Object... dependencies) { + return new Result(value, dependencies); + } + + public boolean isLockValue() { + return myLockValue; + } + + /** + * If the value is locked it won't be released after 60 seconds of inactivity + */ + public void setLockValue(final boolean lockValue) { + myLockValue = lockValue; + } + } +} diff --git a/platform/platform-api/src/com/intellij/psi/util/CachedValuesManager.java b/platform/platform-api/src/com/intellij/psi/util/CachedValuesManager.java new file mode 100644 index 000000000000..2a1ca8d6615c --- /dev/null +++ b/platform/platform-api/src/com/intellij/psi/util/CachedValuesManager.java @@ -0,0 +1,86 @@ +/* + * Copyright 2000-2007 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.util; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.UserDataHolder; +import com.intellij.openapi.util.UserDataHolderEx; +import com.intellij.openapi.components.ServiceManager; +import org.jetbrains.annotations.NotNull; + +public abstract class CachedValuesManager { + + public static CachedValuesManager getManager(@NotNull Project project) { + return ServiceManager.getService(project, CachedValuesManager.class); + } + + /** + * Creates new CachedValue instance with given provider. + * + * @param provider computes values. + * @param trackValue if value tracking required. T should be trackable in this case. + * @return new CachedValue instance. + */ + public abstract CachedValue createCachedValue(@NotNull CachedValueProvider provider, boolean trackValue); + public abstract ParameterizedCachedValue createParameterizedCachedValue(@NotNull ParameterizedCachedValueProvider provider, boolean trackValue); + + public CachedValue createCachedValue(@NotNull CachedValueProvider provider) { + return createCachedValue(provider, true); + } + + public T getParameterizedCachedValue(@NotNull D dataHolder, + @NotNull Key> key, + @NotNull ParameterizedCachedValueProvider provider, + boolean trackValue, + P parameter) { + + ParameterizedCachedValue value; + + if (dataHolder instanceof UserDataHolderEx) { + UserDataHolderEx dh = (UserDataHolderEx)dataHolder; + value = dh.getUserData(key); + if (value == null) { + value = createParameterizedCachedValue(provider, trackValue); + value = dh.putUserDataIfAbsent(key, value); + } + } + else { + synchronized (dataHolder) { + value = dataHolder.getUserData(key); + if (value == null) { + value = createParameterizedCachedValue(provider, trackValue); + dataHolder.putUserData(key, value); + } + } + } + return value.getValue(parameter); + } + + /** + * Utility method storing created cached values in a {@link com.intellij.openapi.util.UserDataHolder}. + * + * @param dataHolder holder to store the cached value, e.g. a PsiElement. + * @param key key to store the cached value. + * @param provider provider creating the cached value. + * @param trackValue if value tracking required. T should be trackable in this case. + * @return up-to-date value. + */ + public abstract T getCachedValue(@NotNull D dataHolder, + @NotNull Key> key, + @NotNull CachedValueProvider provider, + boolean trackValue); +} diff --git a/platform/platform-api/src/com/intellij/psi/util/ParameterizedCachedValue.java b/platform/platform-api/src/com/intellij/psi/util/ParameterizedCachedValue.java new file mode 100644 index 000000000000..6f6a260d1ae7 --- /dev/null +++ b/platform/platform-api/src/com/intellij/psi/util/ParameterizedCachedValue.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2007 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.util; + +import org.jetbrains.annotations.Nullable; + +public interface ParameterizedCachedValue { + + @Nullable + T getValue(P param); + + ParameterizedCachedValueProvider getValueProvider(); + + boolean hasUpToDateValue(); +} \ No newline at end of file diff --git a/platform/platform-api/src/com/intellij/psi/util/ParameterizedCachedValueProvider.java b/platform/platform-api/src/com/intellij/psi/util/ParameterizedCachedValueProvider.java new file mode 100644 index 000000000000..10fd41258d20 --- /dev/null +++ b/platform/platform-api/src/com/intellij/psi/util/ParameterizedCachedValueProvider.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2007 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.util; + +import org.jetbrains.annotations.Nullable; + +public interface ParameterizedCachedValueProvider { + @Nullable + CachedValueProvider.Result compute(P param); +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/psi/impl/CachedValueImpl.java b/platform/platform-impl/src/com/intellij/util/CachedValueBase.java similarity index 57% rename from platform/lang-impl/src/com/intellij/psi/impl/CachedValueImpl.java rename to platform/platform-impl/src/com/intellij/util/CachedValueBase.java index a8ef7f0eacf5..17201d9224c0 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/CachedValueImpl.java +++ b/platform/platform-impl/src/com/intellij/util/CachedValueBase.java @@ -1,12 +1,4 @@ -/* - * Created by IntelliJ IDEA. - * User: mike - * Date: Jun 6, 2002 - * Time: 5:41:42 PM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ -package com.intellij.psi.impl; +package com.intellij.util; import com.intellij.openapi.Disposable; import com.intellij.openapi.project.Project; @@ -14,16 +6,10 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.ModificationTracker; import com.intellij.openapi.util.Ref; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; -import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; -import com.intellij.psi.util.PsiModificationTracker; import com.intellij.reference.SoftReference; -import com.intellij.util.TimedReference; import com.intellij.util.ArrayUtil; +import com.intellij.util.TimedReference; import com.intellij.util.concurrency.JBLock; import com.intellij.util.concurrency.JBReentrantReadWriteLock; import com.intellij.util.concurrency.LockFactory; @@ -35,88 +21,38 @@ import java.lang.ref.Reference; import java.util.ArrayList; import java.util.List; -public class CachedValueImpl implements CachedValue { - private static final Object NULL = new Object(); +/** + * @author Dmitry Avdeev + */ +public abstract class CachedValueBase { + protected static final Object NULL = new Object(); private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.CachedValueImpl"); - - private final PsiManager myManager; - private final CachedValueProvider myProvider; - private final boolean myTrackValue; private final MyTimedReference myData = new MyTimedReference(); + protected final JBLock r; + protected final JBLock w; - private long myLastPsiTimeStamp = -1; - private final JBLock r; - private final JBLock w; - - public CachedValueImpl(@NotNull PsiManager manager, @NotNull CachedValueProvider provider, boolean trackValue) { - myManager = manager; - myProvider = provider; - myTrackValue = trackValue; + public CachedValueBase() { JBReentrantReadWriteLock rw = LockFactory.createReadWriteLock(); r = rw.readLock(); w = rw.writeLock(); } - public boolean isFromMyProject(Project project) { - return project == myManager.getProject(); + + protected Data computeData(T value, Object[] dependencies) { + if (dependencies == null) { + return new Data(value, null, null); + } + + TLongArrayList timeStamps = new TLongArrayList(); + List deps = new ArrayList(); + collectDependencies(timeStamps, deps, dependencies); + + return new Data(value, ArrayUtil.toObjectArray(deps), timeStamps.toNativeArray()); } - private static class Data implements Disposable { - private final T myValue; - private final Object[] myDependencies; - private final long[] myTimeStamps; - - public Data(final T value, final Object[] dependencies, final long[] timeStamps) { - myValue = value; - myDependencies = dependencies; - myTimeStamps = timeStamps; - } - - public void dispose() { - if (myValue instanceof Disposable) { - Disposer.dispose((Disposable)myValue); - } - } - } - - @Nullable - public T getValue() { - - r.lock(); - - T value; - try { - value = getUpToDateOrNull(); - if (value != null) { - return value == NULL ? null : value; - } - } finally { - r.unlock(); - } - - w.lock(); - - try { - value = getUpToDateOrNull(); - if (value != null) { - return value == NULL ? null : value; - } - - CachedValueProvider.Result result = myProvider.compute(); - value = result == null ? null : result.getValue(); - - setValue(value, result); - - return value; - } - finally { - w.unlock(); - } - } - - private void setValue(final T value, final CachedValueProvider.Result result) { - myData.setData(computeData(value == null ? (T) NULL : value, result == null ? null : result.getDependencyItems())); + protected void setValue(final T value, final CachedValueProvider.Result result) { + myData.setData(computeData(value == null ? (T) NULL : value, getDependencies(result))); if (result != null) { myData.setIsLocked(result.isLockValue()); } @@ -125,6 +61,22 @@ public class CachedValueImpl implements CachedValue { } } + @Nullable + protected Object[] getDependencies(CachedValueProvider.Result result) { + return result == null ? null : result.getDependencyItems(); + } + + @Nullable + protected Object[] getDependenciesPlusValue(CachedValueProvider.Result result) { + if (result == null) { + return null; + } + else { + Object[] items = result.getDependencyItems(); + return result.getValue() == null ? items : ArrayUtil.append(items, result.getValue()); + } + } + public void clear() { myData.set(null); } @@ -145,7 +97,7 @@ public class CachedValueImpl implements CachedValue { } @Nullable - private T getUpToDateOrNull() { + protected T getUpToDateOrNull() { final Data data = myData.getData(); if (data != null) { @@ -160,9 +112,8 @@ public class CachedValueImpl implements CachedValue { return null; } - private boolean isUpToDate(@NotNull Data data) { + protected boolean isUpToDate(@NotNull Data data) { if (data.myTimeStamps == null) return true; - if (myManager.isDisposed()) return false; for (int i = 0; i < data.myDependencies.length; i++) { Object dependency = data.myDependencies[i]; @@ -173,33 +124,12 @@ public class CachedValueImpl implements CachedValue { return true; } - private boolean isDependencyOutOfDate(Object dependency, long oldTimeStamp) { - if (dependency instanceof PsiElement && - myLastPsiTimeStamp == myManager.getModificationTracker().getModificationCount()) { - return false; - } + protected boolean isDependencyOutOfDate(Object dependency, long oldTimeStamp) { final long timeStamp = getTimeStamp(dependency); return timeStamp < 0 || timeStamp != oldTimeStamp; } - private Data computeData(T value, Object[] dependencies) { - if (dependencies == null) { - return new Data(value, null, null); - } - - TLongArrayList timeStamps = new TLongArrayList(); - List deps = new ArrayList(); - collectDependencies(timeStamps, deps, dependencies); - if (myTrackValue) { - collectDependencies(timeStamps, deps, new Object[]{value}); - } - - myLastPsiTimeStamp = myManager.getModificationTracker().getModificationCount(); - - return new Data(value, ArrayUtil.toObjectArray(deps), timeStamps.toNativeArray()); - } - - private void collectDependencies(TLongArrayList timeStamps, List resultingDeps, Object[] dependencies) { + protected void collectDependencies(TLongArrayList timeStamps, List resultingDeps, Object[] dependencies) { for (Object dependency : dependencies) { if (dependency == null || dependency == NULL) continue; if (dependency instanceof Object[]) { @@ -212,13 +142,13 @@ public class CachedValueImpl implements CachedValue { } } - private long getTimeStamp(Object dependency) { + protected long getTimeStamp(Object dependency) { if (dependency instanceof Reference){ final Object original = ((Reference)dependency).get(); if(original == null) return -1; return getTimeStamp(original); } - + if (dependency instanceof Ref) { final Object original = ((Ref)dependency).get(); if(original == null) return -1; @@ -228,38 +158,12 @@ public class CachedValueImpl implements CachedValue { if (dependency instanceof ModificationTracker) { return ((ModificationTracker)dependency).getModificationCount(); } - - if (dependency instanceof PsiDirectory) { - return myManager.getModificationTracker().getOutOfCodeBlockModificationCount(); - } - - if (dependency instanceof PsiElement) { - PsiElement element = (PsiElement)dependency; - if (!element.isValid()) return -1; - PsiFile containingFile = element.getContainingFile(); - if (containingFile == null) return -1; - return containingFile.getModificationStamp(); - } - - if (dependency == PsiModificationTracker.MODIFICATION_COUNT) { - return myManager.getModificationTracker().getModificationCount(); - } - else if (dependency == PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) { - return myManager.getModificationTracker().getOutOfCodeBlockModificationCount(); - } - else if (dependency == PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT) { - return myManager.getModificationTracker().getJavaStructureModificationCount(); - } else { LOG.error("Wrong dependency type: " + dependency.getClass()); return -1; } } - public CachedValueProvider getValueProvider() { - return myProvider; - } - public T setValue(final CachedValueProvider.Result result) { w.lock(); @@ -273,6 +177,26 @@ public class CachedValueImpl implements CachedValue { } } + public abstract boolean isFromMyProject(Project project); + + protected static class Data implements Disposable { + private final T myValue; + private final Object[] myDependencies; + private final long[] myTimeStamps; + + public Data(final T value, final Object[] dependencies, final long[] timeStamps) { + myValue = value; + myDependencies = dependencies; + myTimeStamps = timeStamps; + } + + public void dispose() { + if (myValue instanceof Disposable) { + Disposer.dispose((Disposable)myValue); + } + } + } + private static class MyTimedReference extends TimedReference>> { private boolean myIsLocked; diff --git a/platform/platform-impl/src/com/intellij/util/CachedValueImpl.java b/platform/platform-impl/src/com/intellij/util/CachedValueImpl.java new file mode 100644 index 000000000000..013bcd99fb32 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/util/CachedValueImpl.java @@ -0,0 +1,65 @@ +/* + * Created by IntelliJ IDEA. + * User: mike + * Date: Jun 6, 2002 + * Time: 5:41:42 PM + * To change template for new class use + * Code Style | Class Templates options (Tools | IDE Options). + */ +package com.intellij.util; + +import com.intellij.psi.util.CachedValue; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.util.CachedValueBase; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class CachedValueImpl extends CachedValueBase implements CachedValue { + + private final CachedValueProvider myProvider; + + public CachedValueImpl(@NotNull CachedValueProvider provider) { + super(); + myProvider = provider; + } + + @Nullable + public T getValue() { + + r.lock(); + + T value; + try { + value = getUpToDateOrNull(); + if (value != null) { + return value == NULL ? null : value; + } + } finally { + r.unlock(); + } + + w.lock(); + + try { + value = getUpToDateOrNull(); + if (value != null) { + return value == NULL ? null : value; + } + + CachedValueProvider.Result result = myProvider.compute(); + value = result == null ? null : result.getValue(); + + setValue(value, result); + + return value; + } + finally { + w.unlock(); + } + } + + public CachedValueProvider getValueProvider() { + return myProvider; + } + +} diff --git a/platform/platform-impl/src/com/intellij/util/CachedValuesFactory.java b/platform/platform-impl/src/com/intellij/util/CachedValuesFactory.java new file mode 100644 index 000000000000..0d9e756b3043 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/util/CachedValuesFactory.java @@ -0,0 +1,17 @@ +package com.intellij.util; + +import com.intellij.psi.util.CachedValue; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.ParameterizedCachedValue; +import com.intellij.psi.util.ParameterizedCachedValueProvider; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Avdeev + */ +public interface CachedValuesFactory { + + CachedValue createCachedValue(@NotNull CachedValueProvider provider, boolean trackValue); + ParameterizedCachedValue createParameterizedCachedValue(@NotNull ParameterizedCachedValueProvider provider, boolean trackValue); + +} diff --git a/platform/lang-impl/src/com/intellij/psi/impl/CachedValuesManagerImpl.java b/platform/platform-impl/src/com/intellij/util/CachedValuesManagerImpl.java similarity index 66% rename from platform/lang-impl/src/com/intellij/psi/impl/CachedValuesManagerImpl.java rename to platform/platform-impl/src/com/intellij/util/CachedValuesManagerImpl.java index cf9b174575d3..5ed4ff39a75c 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/CachedValuesManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/util/CachedValuesManagerImpl.java @@ -1,10 +1,10 @@ -package com.intellij.psi.impl; +package com.intellij.util; -import com.intellij.psi.PsiManager; -import com.intellij.psi.util.*; import com.intellij.openapi.util.UserDataHolder; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.UserDataHolderEx; +import com.intellij.openapi.project.Project; +import com.intellij.psi.util.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,18 +12,21 @@ import org.jetbrains.annotations.Nullable; * @author ven */ public class CachedValuesManagerImpl extends CachedValuesManager { - private final PsiManager myManager; - public CachedValuesManagerImpl(PsiManager manager) { - myManager = manager; + private final Project myProject; + private final CachedValuesFactory myFactory; + + public CachedValuesManagerImpl(Project project, CachedValuesFactory factory) { + myProject = project; + myFactory = factory == null ? new DefaultCachedValuesFactory(project) : factory; } public CachedValue createCachedValue(@NotNull CachedValueProvider provider, boolean trackValue) { - return new CachedValueImpl(myManager, provider, trackValue); + return myFactory.createCachedValue(provider, trackValue); } public ParameterizedCachedValue createParameterizedCachedValue(@NotNull ParameterizedCachedValueProvider provider, boolean trackValue) { - return new ParameterizedCachedValueImpl(myManager, provider, trackValue); + return myFactory.createParameterizedCachedValue(provider, trackValue); } @Override @@ -37,20 +40,20 @@ public class CachedValuesManagerImpl extends CachedValuesManager { if (dataHolder instanceof UserDataHolderEx) { UserDataHolderEx dh = (UserDataHolderEx)dataHolder; value = dh.getUserData(key); - if (value instanceof CachedValueImpl && !((CachedValueImpl)value).isFromMyProject(myManager.getProject())) { + if (value instanceof CachedValueBase && !((CachedValueBase)value).isFromMyProject(myProject)) { value = null; dataHolder.putUserData(key, null); } if (value == null) { value = createCachedValue(provider, trackValue); - assert ((CachedValueImpl)value).isFromMyProject(myManager.getProject()); + assert ((CachedValueBase)value).isFromMyProject(myProject); value = dh.putUserDataIfAbsent(key, value); } } else { synchronized (dataHolder) { value = dataHolder.getUserData(key); - if (value instanceof CachedValueImpl && !((CachedValueImpl)value).isFromMyProject(myManager.getProject())) { + if (value instanceof CachedValueBase && !((CachedValueBase)value).isFromMyProject(myProject)) { value = null; } if (value == null) { @@ -61,4 +64,8 @@ public class CachedValuesManagerImpl extends CachedValuesManager { } return value.getValue(); } + + public Project getProject() { + return myProject; + } } diff --git a/platform/platform-impl/src/com/intellij/util/DefaultCachedValuesFactory.java b/platform/platform-impl/src/com/intellij/util/DefaultCachedValuesFactory.java new file mode 100644 index 000000000000..6bee6868794d --- /dev/null +++ b/platform/platform-impl/src/com/intellij/util/DefaultCachedValuesFactory.java @@ -0,0 +1,59 @@ +package com.intellij.util; + +import com.intellij.psi.util.ParameterizedCachedValueProvider; +import com.intellij.openapi.project.Project; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.ParameterizedCachedValue; +import com.intellij.psi.util.*; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Avdeev + */ +public class DefaultCachedValuesFactory implements CachedValuesFactory { + private final Project myProject; + + public DefaultCachedValuesFactory(Project project) { + myProject = project; + } + + public CachedValue createCachedValue(@NotNull CachedValueProvider provider, boolean trackValue) { + return trackValue ? new CachedValueImpl(provider) { + @Override + protected Object[] getDependencies(CachedValueProvider.Result result) { + return getDependenciesPlusValue(result); + } + + @Override + public boolean isFromMyProject(Project project) { + return myProject == project; + } + } : new CachedValueImpl(provider) { + + @Override + public boolean isFromMyProject(Project project) { + return myProject == project; + } + }; + } + + public ParameterizedCachedValue createParameterizedCachedValue(@NotNull ParameterizedCachedValueProvider provider, + boolean trackValue) { + return trackValue ? new ParameterizedCachedValueImpl(provider) { + @Override + public boolean isFromMyProject(Project project) { + return myProject == project; + } + + @Override + protected Object[] getDependencies(CachedValueProvider.Result tResult) { + return getDependenciesPlusValue(tResult); + } + } : new ParameterizedCachedValueImpl(provider) { + @Override + public boolean isFromMyProject(Project project) { + return myProject == project; + } + }; + } +} diff --git a/platform/platform-impl/src/com/intellij/util/ParameterizedCachedValueImpl.java b/platform/platform-impl/src/com/intellij/util/ParameterizedCachedValueImpl.java new file mode 100644 index 000000000000..c5fb75a4e388 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/util/ParameterizedCachedValueImpl.java @@ -0,0 +1,64 @@ +/* + * Created by IntelliJ IDEA. + * User: mike + * Date: Jun 6, 2002 + * Time: 5:41:42 PM + * To change template for new class use + * Code Style | Class Templates options (Tools | IDE Options). + */ +package com.intellij.util; + +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.ParameterizedCachedValue; +import com.intellij.psi.util.ParameterizedCachedValueProvider; +import com.intellij.util.CachedValueBase; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class ParameterizedCachedValueImpl extends CachedValueBase implements ParameterizedCachedValue { + + private final ParameterizedCachedValueProvider myProvider; + + public ParameterizedCachedValueImpl(@NotNull ParameterizedCachedValueProvider provider) { + super(); + myProvider = provider; + } + + @Nullable + public T getValue(P param) { + r.lock(); + + T value; + try { + value = getUpToDateOrNull(); + if (value != null) { + return value == NULL ? null : value; + } + } finally { + r.unlock(); + } + + w.lock(); + + try { + value = getUpToDateOrNull(); + if (value != null) { + return value == NULL ? null : value; + } + + CachedValueProvider.Result result = myProvider.compute(param); + value = result == null ? null : result.getValue(); + + setValue(value, result); + + return value; + } + finally { + w.unlock(); + } + } + + public ParameterizedCachedValueProvider getValueProvider() { + return myProvider; + } +} diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index f9e99f8fb8a9..f6926c464177 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -140,6 +140,9 @@ serviceImplementation="com.intellij.pom.core.impl.PomModelImpl"/> + + diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index 0c0cdc56daa5..0413b84c8824 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -48,6 +48,8 @@ + + diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index c18423adc459..10e7c7457992 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -114,6 +114,9 @@ + + diff --git a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationsManagerImpl.java b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationsManagerImpl.java index 3ae92b17923f..14f523b56899 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationsManagerImpl.java +++ b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationsManagerImpl.java @@ -22,7 +22,6 @@ import com.intellij.profile.Profile; import com.intellij.profile.ProfileChangeAdapter; import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; -import com.intellij.psi.PsiManager; import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; @@ -99,11 +98,7 @@ public class DomElementAnnotationsManagerImpl extends DomElementAnnotationsManag private final ProjectRootManager myProjectRootManager; private final CachedValuesManager myCachedValuesManager; private long myModificationCount; - - public DomElementAnnotationsManagerImpl(Project project, InspectionProfileManager manager, ProjectRootManager projectRootManager, - PsiManager psiManager) { - this(project, manager, projectRootManager, psiManager.getCachedValuesManager()); - } + public DomElementAnnotationsManagerImpl(Project project, final InspectionProfileManager inspectionProfileManager, ProjectRootManager projectRootManager, final CachedValuesManager cachedValuesManager) { myCachedValuesManager = cachedValuesManager; diff --git a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlDocumentImpl.java b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlDocumentImpl.java index 2475fb930038..906bb5ca769c 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlDocumentImpl.java +++ b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlDocumentImpl.java @@ -11,7 +11,7 @@ import com.intellij.pom.impl.PomTransactionBase; import com.intellij.pom.xml.XmlAspect; import com.intellij.pom.xml.impl.events.XmlDocumentChangedImpl; import com.intellij.psi.*; -import com.intellij.psi.impl.CachedValueImpl; +import com.intellij.psi.impl.PsiCachedValueImpl; import com.intellij.psi.impl.meta.MetaRegistry; import com.intellij.psi.impl.source.html.dtd.HtmlNSDescriptorImpl; import com.intellij.psi.impl.source.tree.TreeElement; @@ -133,7 +133,7 @@ public class XmlDocumentImpl extends XmlElementImpl implements XmlDocument { CachedValue cachedValue = defaultDescriptorsCache.get(namespace); if (cachedValue == null) { - defaultDescriptorsCache.put(namespace, cachedValue = new CachedValueImpl(getManager(), new CachedValueProvider() { + defaultDescriptorsCache.put(namespace, cachedValue = new PsiCachedValueImpl(getManager(), new CachedValueProvider() { public Result compute() { final XmlNSDescriptor defaultNSDescriptorInner = getDefaultNSDescriptorInner(namespace, strict); @@ -145,7 +145,7 @@ public class XmlDocumentImpl extends XmlElementImpl implements XmlDocument { ? defaultNSDescriptorInner.getDependences() : ExternalResourceManager.getInstance()); } - }, false)); + })); } return cachedValue.getValue(); }