mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Unloadable PsiReferenceContributor
GitOrigin-RevId: 762a3d5a70c32b3dcba601167ef55195fc2ef8ad
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5628961271
commit
098d0ef15d
@@ -7,6 +7,8 @@ import com.intellij.openapi.fileTypes.FileTypeRegistry;
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.ArrayUtilRt;
|
||||
import com.intellij.util.ConcurrencyUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -108,6 +110,8 @@ public abstract class Language extends UserDataHolderBase {
|
||||
}
|
||||
|
||||
public static void unregisterLanguage(@NotNull Language language) {
|
||||
IElementType.unregisterElementTypes(language);
|
||||
ReferenceProvidersRegistry.getInstance().unloadRegistrar(language);
|
||||
ourRegisteredLanguages.remove(language.getClass());
|
||||
ourRegisteredIDs.remove(language.getID());
|
||||
for (String mimeType : language.getMimeTypes()) {
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.intellij.psi;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.util.KeyedLazyInstance;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@@ -42,7 +43,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @see PsiReferenceProviderBean
|
||||
*/
|
||||
public abstract class PsiReferenceContributor implements Disposable {
|
||||
public static final ExtensionPointName<PsiReferenceContributor> EP_NAME = ExtensionPointName.create("com.intellij.psi.referenceContributor");
|
||||
public static final ExtensionPointName<KeyedLazyInstance<PsiReferenceContributor>> EP_NAME = ExtensionPointName.create("com.intellij.psi.referenceContributor");
|
||||
|
||||
public abstract void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar);
|
||||
|
||||
|
||||
+3
-15
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.
|
||||
*/
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
package com.intellij.psi.impl.source.resolve.reference;
|
||||
|
||||
@@ -60,6 +46,8 @@ public abstract class ReferenceProvidersRegistry {
|
||||
return getInstance().doGetReferencesFromProviders(context, hints);
|
||||
}
|
||||
|
||||
public abstract void unloadRegistrar(@NotNull Language language);
|
||||
|
||||
@NotNull
|
||||
protected abstract PsiReference[] doGetReferencesFromProviders(@NotNull PsiElement context, @NotNull PsiReferenceService.Hints hints);
|
||||
}
|
||||
+4
@@ -74,6 +74,10 @@ public abstract class NamedObjectProviderBinding implements ProviderBinding {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return myNamesToProvidersMap.isEmpty() && myNamesToProvidersMapInsensitive.isEmpty();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract String getName(@NotNull PsiElement position);
|
||||
|
||||
|
||||
+34
-6
@@ -1,8 +1,10 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.psi.impl.source.resolve.reference;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.patterns.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReferenceProvider;
|
||||
@@ -14,6 +16,7 @@ import com.intellij.util.containers.ConcurrentFactoryMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -57,7 +60,14 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar {
|
||||
public <T extends PsiElement> void registerReferenceProvider(@NotNull ElementPattern<T> pattern,
|
||||
@NotNull PsiReferenceProvider provider,
|
||||
double priority) {
|
||||
if (myInitialized && !ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
registerReferenceProvider(pattern, provider, priority, null);
|
||||
}
|
||||
|
||||
public <T extends PsiElement> void registerReferenceProvider(@NotNull ElementPattern<T> pattern,
|
||||
@NotNull PsiReferenceProvider provider,
|
||||
double priority,
|
||||
@Nullable Disposable parentDisposable) {
|
||||
if (myInitialized && !ApplicationManager.getApplication().isUnitTestMode() && parentDisposable == null) {
|
||||
LOG.error("Reference provider registration is only allowed from PsiReferenceContributor");
|
||||
}
|
||||
|
||||
@@ -72,12 +82,12 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar {
|
||||
for (PatternCondition<? super String> condition1 : conditions1) {
|
||||
if (condition1 instanceof ValuePatternCondition) {
|
||||
final Collection<String> strings = ((ValuePatternCondition)condition1).getValues();
|
||||
registerNamedReferenceProvider(ArrayUtilRt.toStringArray(strings), nameCondition, scope, true, provider, priority, pattern);
|
||||
registerNamedReferenceProvider(ArrayUtilRt.toStringArray(strings), nameCondition, scope, true, provider, priority, pattern, parentDisposable);
|
||||
return;
|
||||
}
|
||||
if (condition1 instanceof CaseInsensitiveValuePatternCondition) {
|
||||
final String[] strings = ((CaseInsensitiveValuePatternCondition)condition1).getValues();
|
||||
registerNamedReferenceProvider(strings, nameCondition, scope, false, provider, priority, pattern);
|
||||
registerNamedReferenceProvider(strings, nameCondition, scope, false, provider, priority, pattern, parentDisposable);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -89,22 +99,31 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar {
|
||||
myBindingsMap.put(scope, providerBinding = new SimpleProviderBinding());
|
||||
}
|
||||
providerBinding.registerProvider(provider, pattern, priority);
|
||||
if (parentDisposable != null) {
|
||||
Disposer.register(parentDisposable, () -> unregisterReferenceProvider(scope, provider));
|
||||
}
|
||||
|
||||
myBindingCache.clear();
|
||||
}
|
||||
|
||||
public void unregisterReferenceProvider(@NotNull Class scope, @NotNull PsiReferenceProvider provider) {
|
||||
myBindingsMap.get(scope).unregisterProvider(provider);
|
||||
final SimpleProviderBinding binding = myBindingsMap.get(scope);
|
||||
if (binding != null) {
|
||||
binding.unregisterProvider(provider);
|
||||
if (binding.isEmpty()) {
|
||||
myBindingsMap.remove(scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void registerNamedReferenceProvider(@NotNull String[] names,
|
||||
final PsiNamePatternCondition<?> nameCondition,
|
||||
@NotNull Class scopeClass,
|
||||
final boolean caseSensitive,
|
||||
@NotNull PsiReferenceProvider provider,
|
||||
final double priority,
|
||||
@NotNull ElementPattern pattern) {
|
||||
@NotNull ElementPattern pattern,
|
||||
@Nullable Disposable parentDisposable) {
|
||||
NamedObjectProviderBinding providerBinding = myNamedBindingsMap.get(scopeClass);
|
||||
|
||||
if (providerBinding == null) {
|
||||
@@ -116,6 +135,15 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar {
|
||||
});
|
||||
}
|
||||
providerBinding.registerProvider(names, pattern, caseSensitive, provider, priority);
|
||||
if (parentDisposable != null) {
|
||||
NamedObjectProviderBinding finalProviderBinding = providerBinding;
|
||||
Disposer.register(parentDisposable, () -> {
|
||||
finalProviderBinding.unregisterProvider(provider);
|
||||
if (finalProviderBinding.isEmpty()) {
|
||||
myNamedBindingsMap.remove(scopeClass);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+50
-17
@@ -1,28 +1,20 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.
|
||||
*/
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.psi.impl.source.resolve.reference;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.LanguageExtension;
|
||||
import com.intellij.lang.LanguageUtil;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.extensions.ExtensionPointListener;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.extensions.PluginDescriptor;
|
||||
import com.intellij.openapi.project.IndexNotReadyException;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.KeyedLazyInstance;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
@@ -33,17 +25,49 @@ import java.util.*;
|
||||
|
||||
public class ReferenceProvidersRegistryImpl extends ReferenceProvidersRegistry {
|
||||
private static final LanguageExtension<PsiReferenceContributor> CONTRIBUTOR_EXTENSION =
|
||||
new LanguageExtension<>(PsiReferenceContributor.EP_NAME.getName());
|
||||
new LanguageExtension<>(PsiReferenceContributor.EP_NAME);
|
||||
private static final LanguageExtension<PsiReferenceProviderBean> REFERENCE_PROVIDER_EXTENSION =
|
||||
new LanguageExtension<>(PsiReferenceProviderBean.EP_NAME.getName());
|
||||
|
||||
private final Map<Language, PsiReferenceRegistrarImpl> myRegistrars = ContainerUtil.newConcurrentMap();
|
||||
|
||||
public ReferenceProvidersRegistryImpl() {
|
||||
if (Extensions.getRootArea().hasExtensionPoint(PsiReferenceContributor.EP_NAME)) {
|
||||
PsiReferenceContributor.EP_NAME.addExtensionPointListener(new ExtensionPointListener<KeyedLazyInstance<PsiReferenceContributor>>() {
|
||||
@Override
|
||||
public void extensionAdded(@NotNull KeyedLazyInstance<PsiReferenceContributor> extension,
|
||||
@NotNull PluginDescriptor pluginDescriptor) {
|
||||
Language language = Language.findLanguageByID(extension.getKey());
|
||||
if (language == Language.ANY) {
|
||||
for (PsiReferenceRegistrarImpl registrar : myRegistrars.values()) {
|
||||
registerContributedReferenceProviders(registrar, extension.getInstance());
|
||||
}
|
||||
}
|
||||
else if (language != null) {
|
||||
Set<Language> languageAndDialects = LanguageUtil.getAllDerivedLanguages(language);
|
||||
for (Language languageOrDialect : languageAndDialects) {
|
||||
final PsiReferenceRegistrarImpl registrar = myRegistrars.get(languageOrDialect);
|
||||
if (registrar != null) {
|
||||
registerContributedReferenceProviders(registrar, extension.getInstance());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extensionRemoved(@NotNull KeyedLazyInstance<PsiReferenceContributor> extension,
|
||||
@NotNull PluginDescriptor pluginDescriptor) {
|
||||
Disposer.dispose(extension.getInstance());
|
||||
}
|
||||
}, ApplicationManager.getApplication());
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiReferenceRegistrarImpl createRegistrar(Language language) {
|
||||
PsiReferenceRegistrarImpl registrar = new PsiReferenceRegistrarImpl();
|
||||
for (PsiReferenceContributor contributor : CONTRIBUTOR_EXTENSION.allForLanguageOrAny(language)) {
|
||||
contributor.registerReferenceProviders(registrar);
|
||||
registerContributedReferenceProviders(registrar, contributor);
|
||||
}
|
||||
|
||||
List<PsiReferenceProviderBean> referenceProviderBeans = REFERENCE_PROVIDER_EXTENSION.allForLanguageOrAny(language);
|
||||
@@ -75,6 +99,10 @@ public class ReferenceProvidersRegistryImpl extends ReferenceProvidersRegistry {
|
||||
return registrar;
|
||||
}
|
||||
|
||||
private static void registerContributedReferenceProviders(PsiReferenceRegistrarImpl registrar, PsiReferenceContributor contributor) {
|
||||
contributor.registerReferenceProviders(new TrackingReferenceRegistrar(registrar, contributor));
|
||||
Disposer.register(ApplicationManager.getApplication(), contributor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -92,6 +120,11 @@ public class ReferenceProvidersRegistryImpl extends ReferenceProvidersRegistry {
|
||||
return registrar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadRegistrar(@NotNull Language language) {
|
||||
myRegistrars.remove(language);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
// 1. we create priorities map: "priority" -> non-empty references from providers
|
||||
|
||||
+4
@@ -49,4 +49,8 @@ class SimpleProviderBinding implements ProviderBinding {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return myProviderPairs.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.psi.impl.source.resolve.reference;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReferenceProvider;
|
||||
import com.intellij.psi.PsiReferenceRegistrar;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class TrackingReferenceRegistrar extends PsiReferenceRegistrar {
|
||||
private final PsiReferenceRegistrarImpl myDelegate;
|
||||
private final Disposable myDisposable;
|
||||
|
||||
public TrackingReferenceRegistrar(PsiReferenceRegistrarImpl delegate, Disposable disposable) {
|
||||
myDelegate = delegate;
|
||||
myDisposable = disposable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends PsiElement> void registerReferenceProvider(@NotNull ElementPattern<T> pattern,
|
||||
@NotNull PsiReferenceProvider provider,
|
||||
double priority) {
|
||||
myDelegate.registerReferenceProvider(pattern, provider, priority, myDisposable);
|
||||
}
|
||||
}
|
||||
-2
@@ -50,7 +50,6 @@ import com.intellij.openapi.vfs.newvfs.FileSystemInterface;
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent;
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.StubVirtualFile;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.testFramework.LightVirtualFile;
|
||||
import com.intellij.ui.GuiUtils;
|
||||
import com.intellij.util.*;
|
||||
@@ -301,7 +300,6 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
if (fileType instanceof LanguageFileType) {
|
||||
final LanguageFileType languageFileType = (LanguageFileType)fileType;
|
||||
if (!languageFileType.isSecondary()) {
|
||||
IElementType.unregisterElementTypes(languageFileType.getLanguage());
|
||||
Language.unregisterLanguage(languageFileType.getLanguage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,7 +538,7 @@
|
||||
<extensionPoint name="psi.fileReferenceHelper"
|
||||
interface="com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceHelper"/>
|
||||
|
||||
<extensionPoint name="psi.referenceContributor" beanClass="com.intellij.psi.impl.source.resolve.reference.PsiReferenceContributorEP">
|
||||
<extensionPoint name="psi.referenceContributor" beanClass="com.intellij.psi.impl.source.resolve.reference.PsiReferenceContributorEP" dynamic="true">
|
||||
<with attribute="implementation" implements="com.intellij.psi.PsiReferenceContributor"/>
|
||||
</extensionPoint>
|
||||
|
||||
@@ -642,7 +642,7 @@
|
||||
<extensionPoint name="navbar" interface="com.intellij.ide.navigationToolbar.NavBarModelExtension"/>
|
||||
|
||||
<extensionPoint name="renameHandler" interface="com.intellij.refactoring.rename.RenameHandler"/>
|
||||
<extensionPoint name="renamePsiElementProcessor" interface="com.intellij.refactoring.rename.RenamePsiElementProcessor"/>
|
||||
<extensionPoint name="renamePsiElementProcessor" interface="com.intellij.refactoring.rename.RenamePsiElementProcessor" dynamic="true"/>
|
||||
<extensionPoint name="updateAddedFileProcessor" interface="com.intellij.psi.impl.file.UpdateAddedFileProcessor"/>
|
||||
<extensionPoint name="moveFileHandler" interface="com.intellij.refactoring.move.moveFilesOrDirectories.MoveFileHandler"/>
|
||||
<extensionPoint name="automaticRenamerFactory" interface="com.intellij.refactoring.rename.naming.AutomaticRenamerFactory"/>
|
||||
@@ -672,7 +672,7 @@
|
||||
<extensionPoint name="colorAndFontPanelFactory" interface="com.intellij.application.options.colors.ColorAndFontPanelFactory"/>
|
||||
<extensionPoint name="colorAndFontDescriptorProvider" interface="com.intellij.openapi.options.colors.ColorAndFontDescriptorsProvider"/>
|
||||
|
||||
<extensionPoint name="codeInsight.parameterInfo" beanClass="com.intellij.lang.LanguageExtensionPoint">
|
||||
<extensionPoint name="codeInsight.parameterInfo" beanClass="com.intellij.lang.LanguageExtensionPoint" dynamic="true">
|
||||
<with attribute="implementationClass" implements="com.intellij.lang.parameterInfo.ParameterInfoHandler"/>
|
||||
</extensionPoint>
|
||||
<extensionPoint name="codeInsight.parameterInfo.listener" interface="com.intellij.codeInsight.hint.ParameterInfoListener" />
|
||||
|
||||
Reference in New Issue
Block a user