mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[devkit] IJPL-116514 Render EP gutter icons for EP interface classes
GitOrigin-RevId: 43e4e1bdf2645dac421fe5feff43163f72f87520
This commit is contained in:
committed by
intellij-monorepo-bot
parent
4a069c3ac8
commit
b0a1ff1fba
+56
-105
@@ -2,133 +2,84 @@
|
||||
package org.jetbrains.idea.devkit.navigation
|
||||
|
||||
import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.extensions.ProjectExtensionPointName
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.KeyedExtensionCollector
|
||||
import com.intellij.openapi.roots.ProjectFileIndex
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.SmartPointerManager
|
||||
import com.intellij.psi.util.InheritanceUtil
|
||||
import com.intellij.psi.util.PsiTypesUtil
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.idea.devkit.dom.index.ExtensionPointIndex
|
||||
import org.jetbrains.idea.devkit.dom.ExtensionPoint
|
||||
import org.jetbrains.idea.devkit.dom.index.ExtensionPointClassIndex
|
||||
import org.jetbrains.idea.devkit.util.ExtensionPointCandidate
|
||||
import org.jetbrains.idea.devkit.util.PluginRelatedLocatorsUtils
|
||||
import org.jetbrains.uast.UCallExpression
|
||||
import org.jetbrains.uast.UDeclaration
|
||||
import org.jetbrains.uast.UExpression
|
||||
import org.jetbrains.uast.UField
|
||||
import org.jetbrains.uast.UQualifiedReferenceExpression
|
||||
import org.jetbrains.uast.UastCallKind
|
||||
import org.jetbrains.uast.evaluateString
|
||||
import org.jetbrains.uast.expressions.UInjectionHost
|
||||
import org.jetbrains.uast.getParentOfType
|
||||
import org.jetbrains.uast.getUParentForIdentifier
|
||||
import org.jetbrains.uast.sourcePsiElement
|
||||
import org.jetbrains.uast.UClass
|
||||
import org.jetbrains.uast.toUElement
|
||||
|
||||
/**
|
||||
* Provides gutter icon for EP code declaration to matching `<extensionPoint>` in `plugin.xml`.
|
||||
* Provides gutter icon for EP interface class to matching `<extensionPoint>` in `plugin.xml`.
|
||||
*/
|
||||
internal class ExtensionPointDeclarationRelatedItemLineMarkerProvider : DevkitRelatedLineMarkerProviderBase() {
|
||||
|
||||
override fun collectNavigationMarkers(element: PsiElement, result: MutableCollection<in RelatedItemLineMarkerInfo<*>?>) {
|
||||
val uElement = getUParentForIdentifier(element)
|
||||
if (uElement is UField) {
|
||||
if (!isExtensionPointNameDeclarationField(uElement)) return
|
||||
process(resolveEpFqn(uElement), uElement, element.getProject(), result)
|
||||
} else if (uElement is UCallExpression) {
|
||||
if (!isExtensionPointNameDeclarationViaSuperCall(uElement)) return
|
||||
val uClass = element.toUElement(UClass::class.java) ?: return
|
||||
val psiClass = uClass.javaPsi
|
||||
val project = psiClass.project
|
||||
val scope = PluginRelatedLocatorsUtils.getCandidatesScope(project)
|
||||
|
||||
val uDeclaration = checkNotNull(uElement.getParentOfType(UDeclaration::class.java)) { uElement.asSourceString() }
|
||||
process(resolveEpFqn(uElement), uDeclaration, element.getProject(), result)
|
||||
}
|
||||
}
|
||||
val extensionPoints = ExtensionPointClassIndex.getExtensionPointsByClass(project, psiClass, scope)
|
||||
if (extensionPoints.isEmpty()) return
|
||||
|
||||
private fun process(
|
||||
@NonNls epFqn: @NonNls String?,
|
||||
uDeclaration: UDeclaration,
|
||||
project: Project,
|
||||
result: MutableCollection<in RelatedItemLineMarkerInfo<*>?>
|
||||
) {
|
||||
if (epFqn == null) return
|
||||
// Filter to only include EPs where this class is the interface or with.implements, not just the beanClass
|
||||
val relevantEps = filterRelevantExtensionPoints(psiClass, extensionPoints)
|
||||
if (relevantEps.isEmpty()) return
|
||||
|
||||
val point = ExtensionPointIndex.findExtensionPoint(project, PluginRelatedLocatorsUtils.getCandidatesScope(project), epFqn)
|
||||
if (point == null) return
|
||||
val classIdentifier = uClass.uastAnchor?.sourcePsi ?: return
|
||||
|
||||
val identifier = uDeclaration.uastAnchor.sourcePsiElement
|
||||
if (identifier == null) return
|
||||
|
||||
val candidate = ExtensionPointCandidate(SmartPointerManager.createPointer(point.getXmlTag()), epFqn)
|
||||
val info = LineMarkerInfoHelper.createExtensionPointLineMarkerInfo(mutableListOf<ExtensionPointCandidate?>(candidate), identifier)
|
||||
val targets = relevantEps.map { ExtensionPointCandidate(SmartPointerManager.createPointer(it.xmlTag), it.effectiveQualifiedName) }
|
||||
val info = LineMarkerInfoHelper.createExtensionPointLineMarkerInfo(targets, classIdentifier)
|
||||
result.add(info)
|
||||
}
|
||||
|
||||
private fun isExtensionPointNameDeclarationViaSuperCall(uCallExpression: UCallExpression): Boolean {
|
||||
if (uCallExpression.valueArgumentCount != 1) return false
|
||||
if (uCallExpression.kind !== UastCallKind.CONSTRUCTOR_CALL) {
|
||||
if (uCallExpression.kind !== UastCallKind.METHOD_CALL && uCallExpression.methodName != "super") {
|
||||
return false
|
||||
/**
|
||||
* Filters extension points to only include those where the class is referenced as
|
||||
* `interface` or `with.implements`, excluding those where it's only `beanClass`
|
||||
* (it would show hundreds of inlay hints for classes like `LanguageExtensionPoint`).
|
||||
*/
|
||||
private fun filterRelevantExtensionPoints(psiClass: PsiClass, extensionPoints: List<ExtensionPoint>): List<ExtensionPoint> {
|
||||
val classQualifiedName = psiClass.qualifiedName ?: return emptyList()
|
||||
|
||||
val relevantEps = extensionPoints.filter { ep ->
|
||||
// include if class is the EP interface
|
||||
if (ep.`interface`.stringValue == classQualifiedName) {
|
||||
return@filter true
|
||||
}
|
||||
// include if class is the implementationClass of EP's `with`
|
||||
for (withElement in ep.withElements) {
|
||||
if (withElement.attribute.stringValue == "implementationClass" && withElement.implements.stringValue == classQualifiedName) {
|
||||
return@filter true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// Kotlin EP_NAME field with CTOR call -> handled by UField branch
|
||||
if (uCallExpression.getParentOfType(UField::class.java) != null) {
|
||||
return false
|
||||
// handle duplications from Kotlin compiler frontend (OSIP-191)
|
||||
val epsByQualifiedName = relevantEps.groupBy { it.effectiveQualifiedName }
|
||||
return epsByQualifiedName.values.flatMap {
|
||||
if (it.size > 1) {
|
||||
val epsWithoutLibs = extensionPointsWithoutLibs(psiClass, it)
|
||||
if (epsWithoutLibs.any()) {
|
||||
return@flatMap epsWithoutLibs
|
||||
}
|
||||
}
|
||||
it
|
||||
}
|
||||
|
||||
val resolvedMethod = uCallExpression.resolve()
|
||||
if (resolvedMethod == null) return false
|
||||
if (!resolvedMethod.isConstructor()) return false
|
||||
return InheritanceUtil.isInheritor(resolvedMethod.getContainingClass(), KeyedExtensionCollector::class.java.name)
|
||||
}
|
||||
|
||||
|
||||
@NonNls
|
||||
private fun resolveEpFqn(uCallExpression: UCallExpression): @NonNls String? {
|
||||
val uParameter = uCallExpression.getArgumentForParameter(0)
|
||||
if (uParameter == null) return null
|
||||
return uParameter.evaluateString()
|
||||
}
|
||||
|
||||
@NonNls
|
||||
private fun resolveEpFqn(uField: UField): @NonNls String? {
|
||||
val initializer = uField.uastInitializer
|
||||
|
||||
var epNameExpression: UExpression? = null
|
||||
if (initializer is UCallExpression) {
|
||||
epNameExpression = initializer.getArgumentForParameter(0)
|
||||
} else if (initializer is UQualifiedReferenceExpression) {
|
||||
val selector = initializer.selector
|
||||
|
||||
if (selector !is UCallExpression) return null
|
||||
epNameExpression = selector.getArgumentForParameter(0)
|
||||
private fun extensionPointsWithoutLibs(psiClass: PsiClass, relevantEps: List<ExtensionPoint>): List<ExtensionPoint> {
|
||||
val project = psiClass.project
|
||||
val projectFileIndex = ProjectFileIndex.getInstance(project)
|
||||
val epsWithoutLibs = relevantEps.filter {
|
||||
val virtualFile = it.xmlElement?.containingFile?.virtualFile ?: return@filter false
|
||||
!projectFileIndex.isInLibrary(virtualFile)
|
||||
}
|
||||
if (epNameExpression == null) return null
|
||||
|
||||
if (epNameExpression is UInjectionHost) {
|
||||
return epNameExpression.evaluateToString()
|
||||
}
|
||||
// constants
|
||||
return epNameExpression.evaluateString()
|
||||
}
|
||||
|
||||
private fun isExtensionPointNameDeclarationField(uField: UField): Boolean {
|
||||
if (!uField.isFinal) {
|
||||
return false
|
||||
}
|
||||
|
||||
val initializer = uField.uastInitializer
|
||||
if (initializer !is UCallExpression && initializer !is UQualifiedReferenceExpression) {
|
||||
return false
|
||||
}
|
||||
|
||||
val fieldClass = PsiTypesUtil.getPsiClass(uField.getType())
|
||||
if (fieldClass == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
val qualifiedClassName = fieldClass.getQualifiedName()
|
||||
return ExtensionPointName::class.java.name == qualifiedClassName ||
|
||||
ProjectExtensionPointName::class.java.name == qualifiedClassName ||
|
||||
InheritanceUtil.isInheritor(fieldClass, false, KeyedExtensionCollector::class.java.name)
|
||||
return epsWithoutLibs
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
public interface My<caret>BeanClassInterface {
|
||||
}
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
|
||||
import java.lang.String;
|
||||
|
||||
public class MyBeanClassStringEP {
|
||||
|
||||
public static final ExtensionPointName<String> EP_<caret>NAME =
|
||||
ExtensionPointName.create("com.intellij.myBeanClassStringEP");
|
||||
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
public class My<caret>Class {
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
public interface My<caret>Interface {
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
public interface MyMultiple<caret>EPsInterface {
|
||||
}
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
|
||||
import java.lang.String;
|
||||
|
||||
public class MyStringEP {
|
||||
|
||||
public static final ExtensionPointName<String> EP_<caret>NAME =
|
||||
ExtensionPointName.create("com.intellij.myStringEP");
|
||||
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
|
||||
import java.lang.String;
|
||||
|
||||
public class MyStringEPConstructor {
|
||||
|
||||
// private is allowed
|
||||
private static final ExtensionPointName<String> EP_<caret>NAME =
|
||||
new ExtensionPointName<String>("com.intellij.myStringEP");
|
||||
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
import com.intellij.lang.LanguageExtension;
|
||||
import java.lang.String;
|
||||
|
||||
public class MyStringEP {
|
||||
|
||||
public static final LanguageExtension<String> EP_<caret>NAME =
|
||||
new LanguageExtension("com.intellij.myStringEP", "My Default Implementation");
|
||||
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
|
||||
import java.lang.String;
|
||||
|
||||
public class MyStringEPViaConstant {
|
||||
|
||||
public static final String EP_ID = "com.intellij.myStringEP";
|
||||
|
||||
public static final ExtensionPointName<String> EP_<caret>NAME =
|
||||
ExtensionPointName.create(EP_ID);
|
||||
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
import com.intellij.lang.LanguageExtension;
|
||||
|
||||
public class MyStringEPViaLanguageExtensionSuperCall extends LanguageExtension<String> {
|
||||
private My<caret>StringEPViaLanguageExtensionSuperCall() {
|
||||
super("com.intellij.myStringEP")
|
||||
}
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.util.KeyedLazyInstance;
|
||||
|
||||
public class MyStringEP {
|
||||
|
||||
public static final ExtensionPointName<KeyedLazyInstance<String>> EP_<caret>NAME =
|
||||
ExtensionPointName.create("com.intellij.myStringEP");
|
||||
|
||||
}
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
import com.intellij.openapi.extensions.ProjectExtensionPointName;
|
||||
|
||||
import java.lang.String;
|
||||
|
||||
public class MyStringProjectEP {
|
||||
|
||||
public static final ProjectExtensionPointName<String> EP_<caret>NAME =
|
||||
new ProjectExtensionPointName<>("com.intellij.myStringEP");
|
||||
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
public interface MyWith<caret>ImplementsInterface {
|
||||
}
|
||||
+16
-4
@@ -1,11 +1,23 @@
|
||||
<idea-plugin>
|
||||
<extensionPoints>
|
||||
<extensionPoint name="myStringEP" interface="java.lang.String"/>
|
||||
<!-- Basic interface EP -->
|
||||
<extensionPoint name="myInterfaceEP" interface="MyInterface"/>
|
||||
<!-- Basic class EP -->
|
||||
<extensionPoint name="myClassEP" interface="MyClass"/>
|
||||
|
||||
<!-- with.implements EP -->
|
||||
<extensionPoint name="myWithImplementsEP" beanClass="java.lang.Object">
|
||||
<with attribute="implementationClass" implements="MyWithImplementsInterface"/>
|
||||
</extensionPoint>
|
||||
|
||||
<extensionPoint name="myBeanClassStringEP" beanClass="java.lang.String"/>
|
||||
|
||||
<!-- wrong EP name -->
|
||||
<!-- beanClass only (negative test - should NOT show gutter) -->
|
||||
<extensionPoint name="myBeanClassEP" beanClass="MyBeanClassInterface"/>
|
||||
|
||||
<!-- Multiple EPs referencing the same interface -->
|
||||
<extensionPoint name="myMultipleEPs1" interface="MyMultipleEPsInterface"/>
|
||||
<extensionPoint name="myMultipleEPs2" interface="MyMultipleEPsInterface"/>
|
||||
|
||||
<!-- Wrong EP name (for testing no match) -->
|
||||
<extensionPoint name="myStringEP2" interface="java.lang.String"/>
|
||||
</extensionPoints>
|
||||
</idea-plugin>
|
||||
+2
-34
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.navigation;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
@@ -17,36 +17,4 @@ public class ExtensionPointDeclarationRelatedItemLineMarkerProviderTest
|
||||
protected String getExtension() {
|
||||
return ".java";
|
||||
}
|
||||
|
||||
public void testMyStringEP() {
|
||||
assertStringEP();
|
||||
}
|
||||
|
||||
public void testMyStringEPViaConstant() {
|
||||
assertStringEP();
|
||||
}
|
||||
|
||||
public void testMyStringEPConstructor() {
|
||||
assertStringEP();
|
||||
}
|
||||
|
||||
public void testMyStringEPLanguageExtension() {
|
||||
assertStringEP();
|
||||
}
|
||||
|
||||
public void testMyStringProjectEP() {
|
||||
assertStringEP();
|
||||
}
|
||||
|
||||
public void testMyStringKeyedLazyInstanceEP() {
|
||||
assertStringEP();
|
||||
}
|
||||
|
||||
public void testMyStringEPViaLanguageExtensionSuperCall() {
|
||||
assertStringEP();
|
||||
}
|
||||
|
||||
public void testMyBeanClassStringEP() {
|
||||
assertSingleEPDeclaration("MyBeanClassStringEP.java", "com.intellij.myBeanClassStringEP");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
interface My<caret>BeanClassInterface
|
||||
+1
@@ -0,0 +1 @@
|
||||
interface My<caret>Class
|
||||
+1
@@ -0,0 +1 @@
|
||||
interface My<caret>Interface
|
||||
+1
@@ -0,0 +1 @@
|
||||
interface MyMultiple<caret>EPsInterface
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
|
||||
class MyStringEP {
|
||||
|
||||
companion object {
|
||||
private val EP_<caret>NAME = ExtensionPointName.create<String>("com.intellij.myStringEP")
|
||||
}
|
||||
}
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
|
||||
class MyStringEPConstructor {
|
||||
|
||||
companion object {
|
||||
val EP_<caret>NAME = ExtensionPointName<String>("com.intellij.myStringEP")
|
||||
}
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
interface MyStringEPInterface {
|
||||
|
||||
companion object {
|
||||
private val EP_<caret>NAME = ExtensionPointName.create<String>("com.intellij.myStringEP")
|
||||
}
|
||||
}
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
import com.intellij.lang.LanguageExtension
|
||||
|
||||
class MyStringEPLanguageExtension {
|
||||
|
||||
companion object {
|
||||
val EP_<caret>NAME = LanguageExtension<String>("com.intellij.myStringEP", "My Default Implementation")
|
||||
}
|
||||
}
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
|
||||
class MyStringEPViaConstant {
|
||||
|
||||
companion object {
|
||||
val EP_ID = "com.intellij.myStringEP"
|
||||
|
||||
val EP_<caret>NAME = ExtensionPointName.create<String>(EP_ID)
|
||||
}
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
|
||||
class MyStringEPViaInterpolation {
|
||||
|
||||
companion object {
|
||||
const val EP_SHORT_NAME = "myStringEP"
|
||||
private val EP_<caret>NAME = ExtensionPointName.create<String>("com.intellij.$EP_SHORT_NAME")
|
||||
}
|
||||
}
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
import com.intellij.lang.LanguageExtension
|
||||
|
||||
class My<caret>StringEPViaLanguageExtensionSuperCall : LanguageExtension<String>("com.intellij.myStringEP") {}
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
import com.intellij.openapi.extensions.ProjectExtensionPointName
|
||||
|
||||
class MyStringProjectEP {
|
||||
|
||||
companion object {
|
||||
private val EP_<caret>NAME = ProjectExtensionPointName<String>("com.intellij.myStringEP")
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
interface MyWith<caret>ImplementsInterface
|
||||
+16
-4
@@ -1,11 +1,23 @@
|
||||
<idea-plugin>
|
||||
<extensionPoints>
|
||||
<extensionPoint name="myStringEP" interface="java.lang.String"/>
|
||||
<!-- Basic interface EP -->
|
||||
<extensionPoint name="myInterfaceEP" interface="MyInterface"/>
|
||||
<!-- Basic class EP -->
|
||||
<extensionPoint name="myClassEP" interface="MyClass"/>
|
||||
|
||||
<!-- with.implements EP -->
|
||||
<extensionPoint name="myWithImplementsEP" beanClass="java.lang.Object">
|
||||
<with attribute="implementationClass" implements="MyWithImplementsInterface"/>
|
||||
</extensionPoint>
|
||||
|
||||
<extensionPoint name="myBeanClassStringEP" beanClass="java.lang.String"/>
|
||||
|
||||
<!-- wrong EP name -->
|
||||
<!-- beanClass only (negative test - should NOT show gutter) -->
|
||||
<extensionPoint name="myBeanClassEP" beanClass="MyBeanClassInterface"/>
|
||||
|
||||
<!-- Multiple EPs referencing the same interface -->
|
||||
<extensionPoint name="myMultipleEPs1" interface="MyMultipleEPsInterface"/>
|
||||
<extensionPoint name="myMultipleEPs2" interface="MyMultipleEPsInterface"/>
|
||||
|
||||
<!-- Wrong EP name (for testing no match) -->
|
||||
<extensionPoint name="myStringEP2" interface="java.lang.String"/>
|
||||
</extensionPoints>
|
||||
</idea-plugin>
|
||||
+4
-35
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.kotlin.navigation;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
@@ -6,8 +6,9 @@ import org.jetbrains.idea.devkit.kotlin.DevkitKtTestsUtil;
|
||||
import org.jetbrains.idea.devkit.navigation.ExtensionPointDeclarationRelatedItemLineMarkerProviderTestBase;
|
||||
|
||||
@TestDataPath("$CONTENT_ROOT/testData/navigation/extensionPointDeclaration")
|
||||
public class KtExtensionPointDeclarationRelatedItemLineMarkerProviderTest extends
|
||||
ExtensionPointDeclarationRelatedItemLineMarkerProviderTestBase {
|
||||
public class KtExtensionPointDeclarationRelatedItemLineMarkerProviderTest
|
||||
extends ExtensionPointDeclarationRelatedItemLineMarkerProviderTestBase {
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return DevkitKtTestsUtil.TESTDATA_PATH + "navigation/extensionPointDeclaration";
|
||||
@@ -17,36 +18,4 @@ public class KtExtensionPointDeclarationRelatedItemLineMarkerProviderTest extend
|
||||
protected String getExtension() {
|
||||
return ".kt";
|
||||
}
|
||||
|
||||
public void testMyStringEP() {
|
||||
assertStringEP();
|
||||
}
|
||||
|
||||
public void testMyStringEPInterface() {
|
||||
assertStringEP();
|
||||
}
|
||||
|
||||
public void testMyStringEPViaConstant() {
|
||||
assertStringEP();
|
||||
}
|
||||
|
||||
public void testMyStringEPViaInterpolation() {
|
||||
assertStringEP();
|
||||
}
|
||||
|
||||
public void testMyStringEPConstructor() {
|
||||
assertStringEP();
|
||||
}
|
||||
|
||||
public void testMyStringEPLanguageExtension() {
|
||||
assertStringEP();
|
||||
}
|
||||
|
||||
public void testMyStringProjectEP() {
|
||||
assertStringEP();
|
||||
}
|
||||
|
||||
public void testMyStringEPViaLanguageExtensionSuperCall() {
|
||||
assertStringEP();
|
||||
}
|
||||
}
|
||||
|
||||
+34
-3
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.navigation;
|
||||
|
||||
import com.intellij.codeInsight.daemon.GutterMark;
|
||||
@@ -24,8 +24,39 @@ public abstract class ExtensionPointDeclarationRelatedItemLineMarkerProviderTest
|
||||
moduleBuilder.addLibrary("platform-core", PathUtil.getJarPathForClass(LanguageExtension.class));
|
||||
}
|
||||
|
||||
protected void assertStringEP() {
|
||||
assertSingleEPDeclaration(getTestName(false) + getExtension(), "com.intellij.myStringEP");
|
||||
public void testMyInterface() {
|
||||
assertSingleEPDeclaration("MyInterface" + getExtension(), "com.intellij.myInterfaceEP");
|
||||
}
|
||||
|
||||
public void testMyClass() {
|
||||
assertSingleEPDeclaration("MyClass" + getExtension(), "com.intellij.myClassEP");
|
||||
}
|
||||
|
||||
public void testMyWithImplementsInterface() {
|
||||
assertSingleEPDeclaration("MyWithImplementsInterface" + getExtension(), "com.intellij.myWithImplementsEP");
|
||||
}
|
||||
|
||||
public void testMyBeanClassInterface() {
|
||||
// Negative test - should NOT show gutter for beanClass only
|
||||
myFixture.copyFileToProject("extensionPointDeclarationEPs.xml");
|
||||
|
||||
final GutterMark gutter = myFixture.findGutter("MyBeanClassInterface" + getExtension());
|
||||
assertNull("Gutter should not appear for beanClass-only EP", gutter);
|
||||
}
|
||||
|
||||
public void testMyMultipleEPsInterface() {
|
||||
// Should show gutter when multiple EPs reference the same interface
|
||||
VirtualFile pluginXmlFile = myFixture.copyFileToProject("extensionPointDeclarationEPs.xml");
|
||||
PsiFile pluginPsiFile = getPsiManager().findFile(pluginXmlFile);
|
||||
assertNotNull(pluginPsiFile);
|
||||
|
||||
final GutterMark gutter = myFixture.findGutter("MyMultipleEPsInterface" + getExtension());
|
||||
assertNotNull(gutter);
|
||||
|
||||
// Should list both EPs in tooltip
|
||||
DevKitGutterTargetsChecker.checkGutterTargets(gutter,
|
||||
"<html><body> com.intellij.myMultipleEPs1<br> com.intellij.myMultipleEPs2<br></body></html>",
|
||||
DevkitCoreIcons.Gutter.Plugin, "extensionPoint", "extensionPoint");
|
||||
}
|
||||
|
||||
protected void assertSingleEPDeclaration(String filePath, String epFqn) {
|
||||
|
||||
Reference in New Issue
Block a user