mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[api] add ability to provide external symbol references to elements which support them
GitOrigin-RevId: 8d4484c67589795e23444f85b9d85a6f64903be5
This commit is contained in:
committed by
intellij-monorepo-bot
parent
eb6e65d4b3
commit
529ea32cf8
@@ -0,0 +1,20 @@
|
||||
// Copyright 2000-2020 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.model.psi;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
/**
|
||||
* Elements which support external references should implement this interface.
|
||||
* <p>
|
||||
* There are two kinds of element references: own references and external references.<br/>
|
||||
* Own references are references the element knows about, they are usually used by language support.
|
||||
* Element doesn't know about external references since, for example, they might be contributed by plugins.
|
||||
* External references are used for navigation/Find Usages/etc as well as own references.
|
||||
* <p>
|
||||
* The element must implement this interface to support hosting external references,
|
||||
* so this mechanism is effectively opt-in.
|
||||
*
|
||||
* @see PsiElement#getOwnReferences
|
||||
*/
|
||||
public interface PsiExternalReferenceHost extends PsiElement {
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2000-2020 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.model.psi;
|
||||
|
||||
import com.intellij.model.Symbol;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface PsiSymbolReferenceHints {
|
||||
|
||||
/**
|
||||
* Provider may return only references which could be resolved to symbols of this type if the type is not {@code null}.
|
||||
*
|
||||
* @return type of expected target symbol
|
||||
*/
|
||||
@Nullable
|
||||
default Class<? extends Symbol> getTargetClass() {
|
||||
Symbol target = getTarget();
|
||||
return target != null ? target.getClass() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider may return only references which could be resolved to specified symbol if the symbol is not {@code null}.
|
||||
*
|
||||
* @return expected target symbol
|
||||
*/
|
||||
@Nullable
|
||||
default Symbol getTarget() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider may return references which contain specified offset if the offset is greater than or equal to 0;
|
||||
* in this case the offset is guaranteed to be within {@code [0, element.getTextLength())}.
|
||||
*
|
||||
* @return offset in the element for which references are queried, or {@code null} if the offset doesn't matter
|
||||
*/
|
||||
@Nullable
|
||||
default Integer getOffsetInElement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static PsiSymbolReferenceHints offsetHint(int offsetInElement) {
|
||||
assert offsetInElement >= 0;
|
||||
return new PsiSymbolReferenceHints() {
|
||||
@Override
|
||||
public Integer getOffsetInElement() {
|
||||
return offsetInElement;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright 2000-2020 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.model.psi;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface PsiSymbolReferenceProvider {
|
||||
|
||||
@NotNull
|
||||
Collection<? extends PsiSymbolReference> getReferences(@NotNull PsiExternalReferenceHost element, @NotNull PsiSymbolReferenceHints hints);
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright 2000-2020 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.model.psi;
|
||||
|
||||
import com.intellij.diagnostic.PluginException;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.model.Symbol;
|
||||
import com.intellij.openapi.extensions.CustomLoadingExtensionPointBean;
|
||||
import com.intellij.openapi.extensions.PluginDescriptor;
|
||||
import com.intellij.openapi.extensions.RequiredElement;
|
||||
import com.intellij.util.xmlb.annotations.Attribute;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class PsiSymbolReferenceProviderBean extends CustomLoadingExtensionPointBean<PsiSymbolReferenceProvider> {
|
||||
|
||||
/**
|
||||
* {@link Language#getID() id} of the language for which references are provided.<br/>
|
||||
* The references will be provided for the specified language and its {@linkplain Language#getBaseLanguage() base languages}.
|
||||
*/
|
||||
@Attribute
|
||||
@RequiredElement
|
||||
public String hostLanguage;
|
||||
|
||||
/**
|
||||
* Fully qualified name of the class of the PsiElement for which references are provided.<br/>
|
||||
* The references will be provided for the specified class and its superclasses.
|
||||
*/
|
||||
@Attribute
|
||||
@RequiredElement
|
||||
public String hostElementClass;
|
||||
|
||||
/**
|
||||
* Fully qualified name of the common supertype of all symbols that this provider's references could resolve to.
|
||||
*/
|
||||
@Attribute
|
||||
@RequiredElement
|
||||
public String targetClass;
|
||||
|
||||
@Attribute
|
||||
@RequiredElement
|
||||
public String implementationClass;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected String getImplementationClassName() {
|
||||
return implementationClass;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Language getHostLanguage() {
|
||||
Language language = Language.findLanguageByID(hostLanguage);
|
||||
if (language == null) {
|
||||
throw new PluginException("Cannot find language '" + hostLanguage + "'", getPluginDescriptor().getPluginId());
|
||||
}
|
||||
return language;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Class<? extends PsiExternalReferenceHost> getHostElementClass() {
|
||||
return loadClass(hostElementClass);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Class<? extends Symbol> getResolveTargetClass() {
|
||||
return loadClass(targetClass);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> Class<T> loadClass(@NotNull String fqn) {
|
||||
PluginDescriptor pluginDescriptor = getPluginDescriptor();
|
||||
try {
|
||||
return (Class<T>)Class.forName(fqn, true, pluginDescriptor.getPluginClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new PluginException(e, pluginDescriptor.getPluginId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2000-2020 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.model.psi;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Entry point for obtaining {@link PsiSymbolReference}s from {@link PsiElement}.
|
||||
*/
|
||||
public interface PsiSymbolReferenceService {
|
||||
|
||||
@NotNull
|
||||
static PsiSymbolReferenceService getService() {
|
||||
return ServiceManager.getService(PsiSymbolReferenceService.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all (own and external) references from this element
|
||||
*/
|
||||
@NotNull
|
||||
Iterable<? extends PsiSymbolReference> getReferences(@NotNull PsiElement element);
|
||||
|
||||
/**
|
||||
* @return all (own and external) references from this element, which match {@code hints}
|
||||
*/
|
||||
@NotNull
|
||||
Iterable<? extends PsiSymbolReference> getReferences(@NotNull PsiElement element, @NotNull PsiSymbolReferenceHints hints);
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
// Copyright 2000-2018 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.
|
||||
// Copyright 2000-2020 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;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.model.psi.PsiSymbolReference;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Iconable;
|
||||
import com.intellij.openapi.util.Key;
|
||||
@@ -13,11 +14,14 @@ import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.util.ArrayFactory;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.ApiStatus.Experimental;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* The common base interface for all elements of the PSI tree.
|
||||
* <p/>
|
||||
@@ -429,6 +433,26 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
@Contract(pure=true)
|
||||
boolean isWritable();
|
||||
|
||||
/**
|
||||
* The returned references are expected to be used by language support,
|
||||
* for example in Java `foo` element in `foo = 42` expression has a reference,
|
||||
* which is used by Java language support to compute expected type of the assignment.
|
||||
* <p>
|
||||
* On the other hand {@code "bar"} literal in {@code new File("bar")} is a string literal,
|
||||
* and from Java language perspective it has no references,
|
||||
* but the framework support "knows" that this literal contains the reference to a file.
|
||||
* These are external references.
|
||||
*
|
||||
* @return collection of references from this element, or empty collection if there are no such references
|
||||
* @see com.intellij.model.psi.PsiExternalReferenceHost
|
||||
* @see com.intellij.model.psi.PsiSymbolReferenceService#getReferences(PsiElement)
|
||||
*/
|
||||
@Experimental
|
||||
@NotNull
|
||||
default Iterable<? extends PsiSymbolReference> getOwnReferences() {
|
||||
return Arrays.asList(getReferences());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reference from this PSI element to another PSI element (or elements), if one exists.
|
||||
* If the element has multiple associated references (see {@link #getReferences()}
|
||||
|
||||
@@ -11,6 +11,13 @@
|
||||
<extensionPoint name="psi.referenceContributor" beanClass="com.intellij.psi.impl.source.resolve.reference.PsiReferenceContributorEP" dynamic="true">
|
||||
<with attribute="implementation" implements="com.intellij.psi.PsiReferenceContributor"/>
|
||||
</extensionPoint>
|
||||
<extensionPoint name="psi.symbolReferenceProvider"
|
||||
dynamic="true"
|
||||
beanClass="com.intellij.model.psi.PsiSymbolReferenceProviderBean">
|
||||
<with attribute="hostElementClass" implements="com.intellij.model.psi.PsiExternalReferenceHost"/>
|
||||
<with attribute="targetClass" implements="com.intellij.model.Symbol"/>
|
||||
<with attribute="implementationClass" implements="com.intellij.model.psi.PsiSymbolReferenceProvider"/>
|
||||
</extensionPoint>
|
||||
<extensionPoint name="lang.ast.factory" beanClass="com.intellij.lang.LanguageExtensionPoint" dynamic="true">
|
||||
<with attribute="implementationClass" implements="com.intellij.lang.ASTFactory"/>
|
||||
</extensionPoint>
|
||||
|
||||
Reference in New Issue
Block a user