diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml
index 41b50d3ba..b71c925b5 100644
--- a/resources/META-INF/plugin.xml
+++ b/resources/META-INF/plugin.xml
@@ -171,6 +171,7 @@
+
diff --git a/src/com/magento/idea/magento2plugin/indexes/IndexManager.java b/src/com/magento/idea/magento2plugin/indexes/IndexManager.java
index 9653d5c14..56aaad711 100644
--- a/src/com/magento/idea/magento2plugin/indexes/IndexManager.java
+++ b/src/com/magento/idea/magento2plugin/indexes/IndexManager.java
@@ -23,6 +23,7 @@
import com.magento.idea.magento2plugin.stubs.indexes.mftf.DataIndex;
import com.magento.idea.magento2plugin.stubs.indexes.mftf.PageIndex;
import com.magento.idea.magento2plugin.stubs.indexes.mftf.SectionIndex;
+import com.magento.idea.magento2plugin.stubs.indexes.mftf.TestExtendsIndex;
import com.magento.idea.magento2plugin.stubs.indexes.mftf.TestNameIndex;
import com.magento.idea.magento2plugin.stubs.indexes.xml.AclResourceIndex;
import com.magento.idea.magento2plugin.stubs.indexes.xml.DeclarativeSchemaElementsIndex;
@@ -68,6 +69,7 @@ public static void manualReindex() {
PageIndex.KEY,
SectionIndex.KEY,
TestNameIndex.KEY,
+ TestExtendsIndex.KEY,
//graphql
GraphQlResolverIndex.KEY
};
diff --git a/src/com/magento/idea/magento2plugin/reference/provider/mftf/TestExtendedByReferenceProvider.java b/src/com/magento/idea/magento2plugin/reference/provider/mftf/TestExtendedByReferenceProvider.java
new file mode 100644
index 000000000..4de9f7536
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/reference/provider/mftf/TestExtendedByReferenceProvider.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+package com.magento.idea.magento2plugin.reference.provider.mftf;
+
+import com.intellij.ide.highlighter.XmlFileType;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.PsiReferenceProvider;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.xml.XmlAttributeValue;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.util.ProcessingContext;
+import com.intellij.util.indexing.FileBasedIndex;
+import com.magento.idea.magento2plugin.magento.files.MftfTest;
+import com.magento.idea.magento2plugin.reference.xml.PolyVariantReferenceBase;
+import com.magento.idea.magento2plugin.stubs.indexes.mftf.TestExtendsIndex;
+import com.magento.idea.magento2plugin.util.xml.XmlPsiTreeUtil;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+public class TestExtendedByReferenceProvider extends PsiReferenceProvider {
+
+ @NotNull
+ @Override
+ public PsiReference[] getReferencesByElement(
+ final @NotNull PsiElement element,
+ final @NotNull ProcessingContext context
+ ) {
+ final List extendedByReferences = new ArrayList<>();
+ final String testName = StringUtil.unquoteString(element.getText());
+ final Collection containingFiles = FileBasedIndex.getInstance()
+ .getContainingFiles(
+ TestExtendsIndex.KEY,
+ testName,
+ GlobalSearchScope.getScopeRestrictedByFileTypes(
+ GlobalSearchScope.allScope(element.getProject()),
+ XmlFileType.INSTANCE
+ )
+ );
+ final PsiManager psiManager = PsiManager.getInstance(element.getProject());
+ final List psiElements = new ArrayList<>();
+
+ for (final VirtualFile virtualFile: containingFiles) {
+ final PsiFile file = psiManager.findFile(virtualFile);
+
+ if (!(file instanceof XmlFile)) {
+ continue;
+ }
+ final XmlFile xmlFile = (XmlFile) file;
+
+ final Collection valueElements = XmlPsiTreeUtil
+ .findAttributeValueElements(
+ xmlFile,
+ MftfTest.TEST_TAG,
+ MftfTest.EXTENDS_ATTRIBUTE,
+ testName
+ );
+
+ psiElements.addAll(valueElements);
+ }
+
+ if (!psiElements.isEmpty()) {
+ extendedByReferences.add(new PolyVariantReferenceBase(element, psiElements));
+ }
+
+ return extendedByReferences.toArray(new PsiReference[0]);
+ }
+}
diff --git a/src/com/magento/idea/magento2plugin/reference/xml/XmlReferenceContributor.java b/src/com/magento/idea/magento2plugin/reference/xml/XmlReferenceContributor.java
index 3b1016eee..5abe9bf86 100644
--- a/src/com/magento/idea/magento2plugin/reference/xml/XmlReferenceContributor.java
+++ b/src/com/magento/idea/magento2plugin/reference/xml/XmlReferenceContributor.java
@@ -264,6 +264,19 @@ public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar)
)
);
+ //
+ registrar.registerReferenceProvider(
+ XmlPatterns.xmlAttributeValue().withParent(XmlPatterns.xmlAttribute()
+ .withName(MftfTest.NAME_ATTRIBUTE)
+ .withParent(XmlPatterns.xmlTag().withName(MftfTest.TEST_TAG)
+ .withParent(XmlPatterns.xmlTag().withName(MftfTest.ROOT_TAG))
+ )
+ ),
+ new CompositeReferenceProvider(
+ new TestExtendedByReferenceProvider()
+ )
+ );
+
//
registrar.registerReferenceProvider(
XmlPatterns.xmlAttributeValue().withParent(
diff --git a/src/com/magento/idea/magento2plugin/stubs/indexes/mftf/TestExtendsIndex.java b/src/com/magento/idea/magento2plugin/stubs/indexes/mftf/TestExtendsIndex.java
new file mode 100644
index 000000000..9a6506823
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/stubs/indexes/mftf/TestExtendsIndex.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+package com.magento.idea.magento2plugin.stubs.indexes.mftf;
+
+import com.intellij.ide.highlighter.XmlFileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.xml.XmlDocument;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.util.indexing.DataIndexer;
+import com.intellij.util.indexing.FileBasedIndex;
+import com.intellij.util.indexing.FileContent;
+import com.intellij.util.indexing.ID;
+import com.intellij.util.indexing.ScalarIndexExtension;
+import com.intellij.util.io.EnumeratorStringDescriptor;
+import com.intellij.util.io.KeyDescriptor;
+import com.magento.idea.magento2plugin.magento.files.MftfTest;
+import com.magento.idea.magento2plugin.project.Settings;
+import gnu.trove.THashMap;
+import java.util.Map;
+import org.jetbrains.annotations.NotNull;
+
+public class TestExtendsIndex extends ScalarIndexExtension {
+
+ public static final ID KEY = ID.create(
+ "com.magento.idea.magento2plugin.stubs.indexes.mftf.test_extends_index"
+ );
+
+ private final KeyDescriptor myKeyDescriptor = new EnumeratorStringDescriptor();
+
+ @NotNull
+ @Override
+ @SuppressWarnings("PMD.CognitiveComplexity")
+ public DataIndexer getIndexer() {
+ return inputData -> {
+ final Map map = new THashMap<>();
+ final PsiFile psiFile = inputData.getPsiFile();
+ final Project project = psiFile.getProject();
+
+ if (!Settings.isEnabled(project)
+ || !Settings.isMftfSupportEnabled(project)
+ || !(psiFile instanceof XmlFile)
+ ) {
+ return map;
+ }
+ final XmlDocument xmlDocument = ((XmlFile) psiFile).getDocument();
+
+ if (xmlDocument == null) {
+ return map;
+ }
+ final XmlTag xmlRootTag = xmlDocument.getRootTag();
+
+ if (xmlRootTag == null
+ || !xmlRootTag.getName().equals(MftfTest.ROOT_TAG)) {
+ return map;
+ }
+ final XmlTag[] xmlTags = PsiTreeUtil.getChildrenOfType(
+ psiFile.getFirstChild(),
+ XmlTag.class
+ );
+
+ if (xmlTags == null) {
+ return map;
+ }
+
+ for (final XmlTag childTag : xmlRootTag.getSubTags()) {
+ final String name = childTag.getAttributeValue(MftfTest.EXTENDS_ATTRIBUTE);
+
+ if (name == null || name.isEmpty()) {
+ continue;
+ }
+ map.put(name, null);
+ }
+
+ return map;
+ };
+ }
+
+ @NotNull
+ @Override
+ public ID getName() {
+ return KEY;
+ }
+
+ @NotNull
+ @Override
+ public KeyDescriptor getKeyDescriptor() {
+ return this.myKeyDescriptor;
+ }
+
+ @NotNull
+ @Override
+ public FileBasedIndex.InputFilter getInputFilter() {
+ return file ->
+ file.getFileType() == XmlFileType.INSTANCE
+ && file.getPath().contains(MftfTest.FILE_DIR_PARENTS);
+ }
+
+ @Override
+ public boolean dependsOnFileContent() {
+ return true;
+ }
+
+ @Override
+ public int getVersion() {
+ return 1;
+ }
+}