diff --git a/platform/core-api/src/com/intellij/model/psi/PsiExternalReferenceHost.java b/platform/core-api/src/com/intellij/model/psi/PsiExternalReferenceHost.java new file mode 100644 index 000000000000..d5ec6a868bfc --- /dev/null +++ b/platform/core-api/src/com/intellij/model/psi/PsiExternalReferenceHost.java @@ -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. + *
+ * There are two kinds of element references: own references and external references.
+ * 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.
+ *
+ * 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 {
+}
diff --git a/platform/core-api/src/com/intellij/model/psi/PsiSymbolReferenceHints.java b/platform/core-api/src/com/intellij/model/psi/PsiSymbolReferenceHints.java
new file mode 100644
index 000000000000..299d84f8da5f
--- /dev/null
+++ b/platform/core-api/src/com/intellij/model/psi/PsiSymbolReferenceHints.java
@@ -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;
+ }
+ };
+ }
+}
diff --git a/platform/core-api/src/com/intellij/model/psi/PsiSymbolReferenceProvider.java b/platform/core-api/src/com/intellij/model/psi/PsiSymbolReferenceProvider.java
new file mode 100644
index 000000000000..45495579398f
--- /dev/null
+++ b/platform/core-api/src/com/intellij/model/psi/PsiSymbolReferenceProvider.java
@@ -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);
+}
diff --git a/platform/core-api/src/com/intellij/model/psi/PsiSymbolReferenceProviderBean.java b/platform/core-api/src/com/intellij/model/psi/PsiSymbolReferenceProviderBean.java
new file mode 100644
index 000000000000..38b3f6c54312
--- /dev/null
+++ b/platform/core-api/src/com/intellij/model/psi/PsiSymbolReferenceProviderBean.java
@@ -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
+ * 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()}
diff --git a/platform/core-impl/resources/META-INF/CoreImpl.xml b/platform/core-impl/resources/META-INF/CoreImpl.xml
index b45233eb52dd..24a1e2bc92c5 100644
--- a/platform/core-impl/resources/META-INF/CoreImpl.xml
+++ b/platform/core-impl/resources/META-INF/CoreImpl.xml
@@ -11,6 +11,13 @@
+ * 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.
+ * 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