mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
decoupling CachedValueManager from PSI
This commit is contained in:
+2
-2
@@ -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<Places, PsiElement> cachedValue = context.getManager().getCachedValuesManager().createParameterizedCachedValue(this, false);
|
||||
((ParameterizedCachedValueImpl<Places, PsiElement>)cachedValue).setValue(result);
|
||||
((PsiParameterizedCachedValue<Places, PsiElement>)cachedValue).setValue(result);
|
||||
|
||||
for (PsiElement operand : operands) {
|
||||
operand.putUserData(INJECTED_PSI_IN_CONCATENATION, cachedValue);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<T,P> implements ParameterizedCachedValue<T,P> {
|
||||
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<T,P> myProvider;
|
||||
private final boolean myTrackValue;
|
||||
|
||||
private final MyTimedReference<T> myData = new MyTimedReference<T>();
|
||||
|
||||
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<T,P> provider, boolean trackValue) {
|
||||
myManager = manager;
|
||||
myProvider = provider;
|
||||
myTrackValue = trackValue;
|
||||
}
|
||||
|
||||
private static class Data<T> 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<T> 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<T> 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<T> 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<T> computeData(T value, Object[] dependencies) {
|
||||
if (dependencies == null) {
|
||||
return new Data<T>(value, null, null);
|
||||
}
|
||||
|
||||
TLongArrayList timeStamps = new TLongArrayList();
|
||||
List<Object> deps = new ArrayList<Object>();
|
||||
collectDependencies(timeStamps, deps, dependencies);
|
||||
if (myTrackValue) {
|
||||
collectDependencies(timeStamps, deps, new Object[]{value});
|
||||
}
|
||||
|
||||
myLastPsiTimeStamp = myManager.getModificationTracker().getModificationCount();
|
||||
|
||||
return new Data<T>(value, ArrayUtil.toObjectArray(deps), timeStamps.toNativeArray());
|
||||
}
|
||||
|
||||
private void collectDependencies(TLongArrayList timeStamps, List<Object> 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<T,P> getValueProvider() {
|
||||
return myProvider;
|
||||
}
|
||||
|
||||
public T setValue(final CachedValueProvider.Result<T> result) {
|
||||
w.lock();
|
||||
|
||||
try {
|
||||
T value = result.getValue();
|
||||
setValue(value, result);
|
||||
return value;
|
||||
}
|
||||
finally {
|
||||
w.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyTimedReference<T> extends TimedReference<SoftReference<Data<T>>> {
|
||||
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<T> data) {
|
||||
set(new SoftReference<Data<T>>(data));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Data<T> getData() {
|
||||
final SoftReference<Data<T>> ref = get();
|
||||
return ref != null ? ref.get() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<T> extends CachedValueBase<T> {
|
||||
|
||||
private final PsiManager myManager;
|
||||
protected long myLastPsiTimeStamp = -1;
|
||||
|
||||
public PsiCachedValue(PsiManager manager) {
|
||||
super();
|
||||
myManager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Data<T> computeData(T value, Object[] dependencies) {
|
||||
Data<T> 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;
|
||||
}
|
||||
}
|
||||
@@ -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<T> extends PsiCachedValue<T> implements CachedValue<T> {
|
||||
private CachedValueProvider<T> myProvider;
|
||||
|
||||
public PsiCachedValueImpl(PsiManager manager, CachedValueProvider<T> 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<T> result = myProvider.compute();
|
||||
value = result == null ? null : result.getValue();
|
||||
|
||||
setValue(value, result);
|
||||
|
||||
return value;
|
||||
}
|
||||
finally {
|
||||
w.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public CachedValueProvider<T> getValueProvider() {
|
||||
return myProvider;
|
||||
}
|
||||
}
|
||||
@@ -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 <T> CachedValue<T> createCachedValue(@NotNull CachedValueProvider<T> provider, boolean trackValue) {
|
||||
return trackValue ? new PsiCachedValueImpl<T>(myManager, provider) {
|
||||
@Override
|
||||
protected Object[] getDependencies(CachedValueProvider.Result<T> result) {
|
||||
return getDependenciesPlusValue(result);
|
||||
}
|
||||
} : new PsiCachedValueImpl<T>(myManager, provider) {
|
||||
};
|
||||
}
|
||||
|
||||
public <T, P> ParameterizedCachedValue<T, P> createParameterizedCachedValue(@NotNull ParameterizedCachedValueProvider<T, P> provider,
|
||||
boolean trackValue) {
|
||||
return trackValue ? new PsiParameterizedCachedValue<T, P>(myManager, provider) {
|
||||
@Override
|
||||
public boolean isFromMyProject(Project project) {
|
||||
return myProject == project;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object[] getDependencies(CachedValueProvider.Result<T> tResult) {
|
||||
return getDependenciesPlusValue(tResult);
|
||||
}
|
||||
} : new PsiParameterizedCachedValue<T, P>(myManager, provider) {
|
||||
@Override
|
||||
public boolean isFromMyProject(Project project) {
|
||||
return myProject == project;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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<CachedValuesManager> myCachedValuesManager = new NotNullLazyValue<CachedValuesManager>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected CachedValuesManager compute() {
|
||||
return CachedValuesManager.getManager(myProject);
|
||||
}
|
||||
};
|
||||
|
||||
private final List<PsiTreeChangePreprocessor> myTreeChangePreprocessors = ContainerUtil.createEmptyCOWList();
|
||||
private final List<PsiTreeChangeListener> 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 {
|
||||
|
||||
@@ -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<T,P> extends PsiCachedValue<T> implements ParameterizedCachedValue<T,P> {
|
||||
|
||||
private final ParameterizedCachedValueProvider<T,P> myProvider;
|
||||
|
||||
public PsiParameterizedCachedValue(PsiManager manager, @NotNull ParameterizedCachedValueProvider<T, P> 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<T> result = myProvider.compute(param);
|
||||
value = result == null ? null : result.getValue();
|
||||
|
||||
setValue(value, result);
|
||||
|
||||
return value;
|
||||
}
|
||||
finally {
|
||||
w.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public ParameterizedCachedValueProvider<T,P> getValueProvider() {
|
||||
return myProvider;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
@@ -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> {
|
||||
|
||||
T getValue();
|
||||
|
||||
CachedValueProvider<T> getValueProvider();
|
||||
|
||||
boolean hasUpToDateValue();
|
||||
}
|
||||
@@ -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<T> {
|
||||
@Nullable
|
||||
Result<T> compute();
|
||||
|
||||
class Result<T> {
|
||||
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 <T> Result<T> createSingleDependency(T value, Object dependency) {
|
||||
return create(value, dependency);
|
||||
}
|
||||
|
||||
public static <T> Result<T> create(T value, Object... dependencies) {
|
||||
return new Result<T>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 <T> CachedValue<T> createCachedValue(@NotNull CachedValueProvider<T> provider, boolean trackValue);
|
||||
public abstract <T,P> ParameterizedCachedValue<T,P> createParameterizedCachedValue(@NotNull ParameterizedCachedValueProvider<T,P> provider, boolean trackValue);
|
||||
|
||||
public <T> CachedValue<T> createCachedValue(@NotNull CachedValueProvider<T> provider) {
|
||||
return createCachedValue(provider, true);
|
||||
}
|
||||
|
||||
public <T, D extends UserDataHolder, P> T getParameterizedCachedValue(@NotNull D dataHolder,
|
||||
@NotNull Key<ParameterizedCachedValue<T,P>> key,
|
||||
@NotNull ParameterizedCachedValueProvider<T, P> provider,
|
||||
boolean trackValue,
|
||||
P parameter) {
|
||||
|
||||
ParameterizedCachedValue<T,P> 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, D extends UserDataHolder> T getCachedValue(@NotNull D dataHolder,
|
||||
@NotNull Key<CachedValue<T>> key,
|
||||
@NotNull CachedValueProvider<T> provider,
|
||||
boolean trackValue);
|
||||
}
|
||||
@@ -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<T, P> {
|
||||
|
||||
@Nullable
|
||||
T getValue(P param);
|
||||
|
||||
ParameterizedCachedValueProvider<T,P> getValueProvider();
|
||||
|
||||
boolean hasUpToDateValue();
|
||||
}
|
||||
@@ -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<T, P> {
|
||||
@Nullable
|
||||
CachedValueProvider.Result<T> compute(P param);
|
||||
}
|
||||
+65
-141
@@ -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<T> implements CachedValue<T> {
|
||||
private static final Object NULL = new Object();
|
||||
/**
|
||||
* @author Dmitry Avdeev
|
||||
*/
|
||||
public abstract class CachedValueBase<T> {
|
||||
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<T> myProvider;
|
||||
private final boolean myTrackValue;
|
||||
|
||||
private final MyTimedReference<T> myData = new MyTimedReference<T>();
|
||||
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<T> 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<T> computeData(T value, Object[] dependencies) {
|
||||
if (dependencies == null) {
|
||||
return new Data<T>(value, null, null);
|
||||
}
|
||||
|
||||
TLongArrayList timeStamps = new TLongArrayList();
|
||||
List<Object> deps = new ArrayList<Object>();
|
||||
collectDependencies(timeStamps, deps, dependencies);
|
||||
|
||||
return new Data<T>(value, ArrayUtil.toObjectArray(deps), timeStamps.toNativeArray());
|
||||
}
|
||||
|
||||
private static class Data<T> 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<T> 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<T> result) {
|
||||
myData.setData(computeData(value == null ? (T) NULL : value, result == null ? null : result.getDependencyItems()));
|
||||
protected void setValue(final T value, final CachedValueProvider.Result<T> 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<T> implements CachedValue<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Object[] getDependencies(CachedValueProvider.Result<T> result) {
|
||||
return result == null ? null : result.getDependencyItems();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Object[] getDependenciesPlusValue(CachedValueProvider.Result<T> 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<T> implements CachedValue<T> {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private T getUpToDateOrNull() {
|
||||
protected T getUpToDateOrNull() {
|
||||
final Data<T> data = myData.getData();
|
||||
|
||||
if (data != null) {
|
||||
@@ -160,9 +112,8 @@ public class CachedValueImpl<T> implements CachedValue<T> {
|
||||
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<T> implements CachedValue<T> {
|
||||
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<T> computeData(T value, Object[] dependencies) {
|
||||
if (dependencies == null) {
|
||||
return new Data<T>(value, null, null);
|
||||
}
|
||||
|
||||
TLongArrayList timeStamps = new TLongArrayList();
|
||||
List<Object> deps = new ArrayList<Object>();
|
||||
collectDependencies(timeStamps, deps, dependencies);
|
||||
if (myTrackValue) {
|
||||
collectDependencies(timeStamps, deps, new Object[]{value});
|
||||
}
|
||||
|
||||
myLastPsiTimeStamp = myManager.getModificationTracker().getModificationCount();
|
||||
|
||||
return new Data<T>(value, ArrayUtil.toObjectArray(deps), timeStamps.toNativeArray());
|
||||
}
|
||||
|
||||
private void collectDependencies(TLongArrayList timeStamps, List<Object> resultingDeps, Object[] dependencies) {
|
||||
protected void collectDependencies(TLongArrayList timeStamps, List<Object> resultingDeps, Object[] dependencies) {
|
||||
for (Object dependency : dependencies) {
|
||||
if (dependency == null || dependency == NULL) continue;
|
||||
if (dependency instanceof Object[]) {
|
||||
@@ -212,13 +142,13 @@ public class CachedValueImpl<T> implements CachedValue<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T> implements CachedValue<T> {
|
||||
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<T> getValueProvider() {
|
||||
return myProvider;
|
||||
}
|
||||
|
||||
public T setValue(final CachedValueProvider.Result<T> result) {
|
||||
w.lock();
|
||||
|
||||
@@ -273,6 +177,26 @@ public class CachedValueImpl<T> implements CachedValue<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public abstract boolean isFromMyProject(Project project);
|
||||
|
||||
protected static class Data<T> 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<T> extends TimedReference<SoftReference<Data<T>>> {
|
||||
private boolean myIsLocked;
|
||||
|
||||
@@ -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<T> extends CachedValueBase<T> implements CachedValue<T> {
|
||||
|
||||
private final CachedValueProvider<T> myProvider;
|
||||
|
||||
public CachedValueImpl(@NotNull CachedValueProvider<T> 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<T> result = myProvider.compute();
|
||||
value = result == null ? null : result.getValue();
|
||||
|
||||
setValue(value, result);
|
||||
|
||||
return value;
|
||||
}
|
||||
finally {
|
||||
w.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public CachedValueProvider<T> getValueProvider() {
|
||||
return myProvider;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
<T> CachedValue<T> createCachedValue(@NotNull CachedValueProvider<T> provider, boolean trackValue);
|
||||
<T,P> ParameterizedCachedValue<T,P> createParameterizedCachedValue(@NotNull ParameterizedCachedValueProvider<T,P> provider, boolean trackValue);
|
||||
|
||||
}
|
||||
+18
-11
@@ -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 <T> CachedValue<T> createCachedValue(@NotNull CachedValueProvider<T> provider, boolean trackValue) {
|
||||
return new CachedValueImpl<T>(myManager, provider, trackValue);
|
||||
return myFactory.createCachedValue(provider, trackValue);
|
||||
}
|
||||
|
||||
public <T,P> ParameterizedCachedValue<T,P> createParameterizedCachedValue(@NotNull ParameterizedCachedValueProvider<T,P> provider, boolean trackValue) {
|
||||
return new ParameterizedCachedValueImpl<T,P>(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;
|
||||
}
|
||||
}
|
||||
@@ -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 <T> CachedValue<T> createCachedValue(@NotNull CachedValueProvider<T> provider, boolean trackValue) {
|
||||
return trackValue ? new CachedValueImpl<T>(provider) {
|
||||
@Override
|
||||
protected Object[] getDependencies(CachedValueProvider.Result<T> result) {
|
||||
return getDependenciesPlusValue(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFromMyProject(Project project) {
|
||||
return myProject == project;
|
||||
}
|
||||
} : new CachedValueImpl<T>(provider) {
|
||||
|
||||
@Override
|
||||
public boolean isFromMyProject(Project project) {
|
||||
return myProject == project;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public <T, P> ParameterizedCachedValue<T, P> createParameterizedCachedValue(@NotNull ParameterizedCachedValueProvider<T, P> provider,
|
||||
boolean trackValue) {
|
||||
return trackValue ? new ParameterizedCachedValueImpl<T, P>(provider) {
|
||||
@Override
|
||||
public boolean isFromMyProject(Project project) {
|
||||
return myProject == project;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object[] getDependencies(CachedValueProvider.Result<T> tResult) {
|
||||
return getDependenciesPlusValue(tResult);
|
||||
}
|
||||
} : new ParameterizedCachedValueImpl<T, P>(provider) {
|
||||
@Override
|
||||
public boolean isFromMyProject(Project project) {
|
||||
return myProject == project;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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<T,P> extends CachedValueBase<T> implements ParameterizedCachedValue<T,P> {
|
||||
|
||||
private final ParameterizedCachedValueProvider<T,P> myProvider;
|
||||
|
||||
public ParameterizedCachedValueImpl(@NotNull ParameterizedCachedValueProvider<T,P> 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<T> result = myProvider.compute(param);
|
||||
value = result == null ? null : result.getValue();
|
||||
|
||||
setValue(value, result);
|
||||
|
||||
return value;
|
||||
}
|
||||
finally {
|
||||
w.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public ParameterizedCachedValueProvider<T,P> getValueProvider() {
|
||||
return myProvider;
|
||||
}
|
||||
}
|
||||
@@ -140,6 +140,9 @@
|
||||
serviceImplementation="com.intellij.pom.core.impl.PomModelImpl"/>
|
||||
<projectService serviceInterface="com.intellij.psi.impl.include.FileIncludeManager"
|
||||
serviceImplementation="com.intellij.psi.impl.include.FileIncludeManagerImpl"/>
|
||||
<projectService serviceInterface="com.intellij.util.CachedValuesFactory"
|
||||
serviceImplementation="com.intellij.psi.impl.PsiCachedValuesFactory"/>
|
||||
|
||||
|
||||
<projectService serviceInterface="com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable"
|
||||
serviceImplementation="com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable"/>
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
<extensionPoint name="projectUndoProvider" interface="com.intellij.openapi.command.impl.UndoProvider"
|
||||
area="IDEA_PROJECT"/>
|
||||
|
||||
<extensionPoint name="cachedValuesFactory" interface="com.intellij.util.CachedValuesFactory" area="IDEA_PROJECT"/>
|
||||
|
||||
<extensionPoint name="syntaxHighlighter"
|
||||
beanClass="com.intellij.openapi.extensions.KeyedFactoryEPBean"/>
|
||||
|
||||
|
||||
@@ -114,6 +114,9 @@
|
||||
|
||||
<projectService serviceInterface="com.intellij.openapi.project.DumbService" serviceImplementation="com.intellij.openapi.project.DumbServiceImpl"/>
|
||||
|
||||
<projectService serviceInterface="com.intellij.psi.util.CachedValuesManager"
|
||||
serviceImplementation="com.intellij.util.CachedValuesManagerImpl"/>
|
||||
|
||||
<projectService serviceInterface="com.intellij.openapi.vcs.impl.projectlevelman.AllVcsesI"
|
||||
serviceImplementation="com.intellij.openapi.vcs.impl.projectlevelman.AllVcses"/>
|
||||
|
||||
|
||||
+1
-6
@@ -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;
|
||||
|
||||
@@ -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<XmlNSDescriptor> cachedValue = defaultDescriptorsCache.get(namespace);
|
||||
if (cachedValue == null) {
|
||||
defaultDescriptorsCache.put(namespace, cachedValue = new CachedValueImpl<XmlNSDescriptor>(getManager(), new CachedValueProvider<XmlNSDescriptor>() {
|
||||
defaultDescriptorsCache.put(namespace, cachedValue = new PsiCachedValueImpl<XmlNSDescriptor>(getManager(), new CachedValueProvider<XmlNSDescriptor>() {
|
||||
public Result<XmlNSDescriptor> 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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user