more cheap reference registrar structures, only modified during initialization (and in some tests)

This commit is contained in:
peter
2013-07-30 13:25:12 +02:00
parent 1f205df00e
commit 28b3553b7b
4 changed files with 31 additions and 49 deletions
@@ -21,38 +21,37 @@ import com.intellij.patterns.ElementPattern;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReferenceProvider;
import com.intellij.psi.PsiReferenceService;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.ProcessingContext;
import com.intellij.util.containers.ConcurrentHashMap;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.SmartList;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.Map;
/**
* @author maxim
*/
public abstract class NamedObjectProviderBinding<Provider> implements ProviderBinding<Provider> {
private final ConcurrentMap<String, List<ProviderInfo<Provider, ElementPattern>>> myNamesToProvidersMap = new ConcurrentHashMap<String, List<ProviderInfo<Provider,ElementPattern>>>(5);
private final ConcurrentMap<String, List<ProviderInfo<Provider, ElementPattern>>> myNamesToProvidersMapInsensitive = new ConcurrentHashMap<String, List<ProviderInfo<Provider, ElementPattern>>>(5);
private final Map<String, List<ProviderInfo<Provider, ElementPattern>>> myNamesToProvidersMap = new THashMap<String, List<ProviderInfo<Provider,ElementPattern>>>(5);
private final Map<String, List<ProviderInfo<Provider, ElementPattern>>> myNamesToProvidersMapInsensitive = new THashMap<String, List<ProviderInfo<Provider, ElementPattern>>>(5);
public void registerProvider(@NonNls @NotNull String[] names,
@NotNull ElementPattern filter,
boolean caseSensitive,
@NotNull Provider provider,
final double priority) {
final ConcurrentMap<String, List<ProviderInfo<Provider, ElementPattern>>> map = caseSensitive ? myNamesToProvidersMap : myNamesToProvidersMapInsensitive;
final Map<String, List<ProviderInfo<Provider, ElementPattern>>> map = caseSensitive ? myNamesToProvidersMap : myNamesToProvidersMapInsensitive;
for (final String attributeName : names) {
List<ProviderInfo<Provider, ElementPattern>> psiReferenceProviders = map.get(attributeName);
if (psiReferenceProviders == null) {
String key = caseSensitive ? attributeName : attributeName.toLowerCase();
psiReferenceProviders = ConcurrencyUtil.cacheOrGet(map, key, ContainerUtil.<ProviderInfo<Provider,ElementPattern>>createLockFreeCopyOnWriteList());
map.put(key, psiReferenceProviders = new SmartList<ProviderInfo<Provider, ElementPattern>>());
}
psiReferenceProviders.add(new ProviderInfo<Provider,ElementPattern>(provider, filter, priority));
@@ -15,32 +15,30 @@
*/
package com.intellij.psi.impl.source.resolve.reference;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.patterns.*;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReferenceProvider;
import com.intellij.psi.PsiReferenceRegistrar;
import com.intellij.psi.PsiReferenceService;
import com.intellij.psi.filters.ElementFilter;
import com.intellij.psi.filters.position.FilterPattern;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.ProcessingContext;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ConcurrentFactoryMap;
import com.intellij.util.containers.ConcurrentHashMap;
import com.intellij.util.containers.FactoryMap;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
/**
* @author Dmitry Avdeev
*/
public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar {
private final ConcurrentMap<Class, SimpleProviderBinding<PsiReferenceProvider>> myBindingsMap = new ConcurrentHashMap<Class, SimpleProviderBinding<PsiReferenceProvider>>();
private final ConcurrentMap<Class, NamedObjectProviderBinding<PsiReferenceProvider>> myNamedBindingsMap = new ConcurrentHashMap<Class, NamedObjectProviderBinding<PsiReferenceProvider>>();
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.resolve.reference.PsiReferenceRegistrarImpl");
private final Map<Class, SimpleProviderBinding<PsiReferenceProvider>> myBindingsMap = new THashMap<Class, SimpleProviderBinding<PsiReferenceProvider>>();
private final Map<Class, NamedObjectProviderBinding<PsiReferenceProvider>> myNamedBindingsMap = new THashMap<Class, NamedObjectProviderBinding<PsiReferenceProvider>>();
private final FactoryMap<Class, Class[]> myKnownSupers = new ConcurrentFactoryMap<Class, Class[]>() {
@Override
protected Class[] create(Class key) {
@@ -61,22 +59,20 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar {
return result.toArray(new Class[result.size()]);
}
};
private boolean myInitialized;
/**
* @deprecated {@see com.intellij.psi.PsiReferenceContributor
*/
public void registerReferenceProvider(@Nullable ElementFilter elementFilter,
@NotNull Class scope,
@NotNull PsiReferenceProvider provider,
double priority) {
PsiElementPattern.Capture<PsiElement> capture = PlatformPatterns.psiElement(scope);
registerReferenceProvider(capture.and(new FilterPattern(elementFilter)), provider, priority);
public void markInitialized() {
myInitialized = true;
}
@Override
public <T extends PsiElement> void registerReferenceProvider(@NotNull ElementPattern<T> pattern,
@NotNull PsiReferenceProvider provider,
double priority) {
if (myInitialized && !ApplicationManager.getApplication().isUnitTestMode()) {
LOG.error("Reference provider registration is only allowed from PsiReferenceContributor");
}
myKnownSupers.clear(); // we should clear the cache
final Class scope = pattern.getCondition().getInitialCondition().getAcceptedClass();
final List<PatternCondition<? super T>> conditions = pattern.getCondition().getConditions();
@@ -101,26 +97,11 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar {
break;
}
while (true) {
SimpleProviderBinding<PsiReferenceProvider> providerBinding = myBindingsMap.get(scope);
if (providerBinding != null) {
providerBinding.registerProvider(provider, pattern, priority);
return;
}
SimpleProviderBinding<PsiReferenceProvider> binding = new SimpleProviderBinding<PsiReferenceProvider>();
binding.registerProvider(provider, pattern, priority);
if (myBindingsMap.putIfAbsent(scope, binding) == null) break;
SimpleProviderBinding<PsiReferenceProvider> providerBinding = myBindingsMap.get(scope);
if (providerBinding == null) {
myBindingsMap.put(scope, providerBinding = new SimpleProviderBinding<PsiReferenceProvider>());
}
}
/**
* @deprecated {@link com.intellij.psi.PsiReferenceContributor}
*/
public void registerReferenceProvider(@Nullable ElementFilter elementFilter,
@NotNull Class scope,
@NotNull PsiReferenceProvider provider) {
registerReferenceProvider(elementFilter, scope, provider, DEFAULT_PRIORITY);
providerBinding.registerProvider(provider, pattern, priority);
}
public void unregisterReferenceProvider(@NotNull Class scope, @NotNull PsiReferenceProvider provider) {
@@ -139,14 +120,13 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar {
NamedObjectProviderBinding<PsiReferenceProvider> providerBinding = myNamedBindingsMap.get(scopeClass);
if (providerBinding == null) {
providerBinding = ConcurrencyUtil.cacheOrGet(myNamedBindingsMap, scopeClass, new NamedObjectProviderBinding<PsiReferenceProvider>() {
myNamedBindingsMap.put(scopeClass, providerBinding = new NamedObjectProviderBinding<PsiReferenceProvider>() {
@Override
protected String getName(final PsiElement position) {
return nameCondition.getPropertyValue(position);
}
});
}
providerBinding.registerProvider(names, pattern, caseSensitive, provider, priority);
}
@@ -155,7 +135,7 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar {
* @deprecated
*/
public void registerReferenceProvider(@NotNull Class scope, @NotNull PsiReferenceProvider provider) {
registerReferenceProvider(null, scope, provider);
registerReferenceProvider(PlatformPatterns.psiElement(scope), provider, DEFAULT_PRIORITY);
}
@NotNull
@@ -73,6 +73,9 @@ public class ReferenceProvidersRegistryImpl extends ReferenceProvidersRegistry {
});
}
}
registrar.markInitialized();
return registrar;
}
};
@@ -22,7 +22,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReferenceProvider;
import com.intellij.psi.PsiReferenceService;
import com.intellij.util.ProcessingContext;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -36,7 +36,7 @@ import java.util.List;
* To change this template use Options | File Templates.
*/
public class SimpleProviderBinding<Provider> implements ProviderBinding<Provider> {
private final List<ProviderInfo<Provider, ElementPattern>> myProviderPairs = ContainerUtil.createLockFreeCopyOnWriteList();
private final List<ProviderInfo<Provider, ElementPattern>> myProviderPairs = new SmartList<ProviderInfo<Provider, ElementPattern>>();
public void registerProvider(Provider provider, ElementPattern pattern, double priority) {
myProviderPairs.add(new ProviderInfo<Provider, ElementPattern>(provider, pattern, priority));