IDEA-221095 Devkit: resolve EPs when used via xinclude or <depends>

GitOrigin-RevId: 52cc521f09a847e043ac1eaba5b5a62bf358d809
This commit is contained in:
Yann Cébron
2019-08-23 17:02:50 +03:00
committed by intellij-monorepo-bot
parent 600e43c052
commit dfac135468
7 changed files with 167 additions and 27 deletions
@@ -63,6 +63,7 @@
<fileBasedIndex implementation="org.jetbrains.idea.devkit.dom.index.IdeaPluginRegistrationIndex"/>
<fileBasedIndex implementation="org.jetbrains.idea.devkit.dom.index.PluginIdModuleIndex"/>
<fileBasedIndex implementation="org.jetbrains.idea.devkit.dom.index.PluginIdDependenciesIndex"/>
<editorTabTitleProvider implementation="org.jetbrains.idea.devkit.dom.ide.PluginDescriptorEditorTabTitleProvider"/>
<useScopeEnlarger implementation="org.jetbrains.idea.devkit.dom.ide.PluginDescriptorUseScopeEnlarger"/>
@@ -3,12 +3,14 @@ package org.jetbrains.idea.devkit.dom.impl;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.impl.include.FileIncludeManager;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.SmartHashSet;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.DomUtil;
import com.intellij.util.xml.XmlName;
@@ -19,8 +21,9 @@ import com.intellij.util.xml.reflect.DomExtender;
import com.intellij.util.xml.reflect.DomExtensionsRegistrar;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.devkit.dom.*;
import org.jetbrains.idea.devkit.dom.index.PluginIdDependenciesIndex;
import org.jetbrains.idea.devkit.dom.index.PluginIdModuleIndex;
import org.jetbrains.idea.devkit.util.DescriptorUtil;
import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
import java.util.*;
@@ -89,36 +92,42 @@ public class ExtensionsDomExtender extends DomExtender<Extensions> {
static Collection<String> getDependencies(IdeaPlugin ideaPlugin) {
Set<String> result = new HashSet<>();
result.add(PluginManagerCore.CORE_PLUGIN_ID);
for (Dependency dependency : ideaPlugin.getDependencies()) {
ContainerUtil.addIfNotNull(result, dependency.getStringValue());
}
if (ideaPlugin.getPluginId() == null) {
final VirtualFile file = DomUtil.getFile(ideaPlugin).getOriginalFile().getVirtualFile();
if (file != null) {
final String fileName = file.getName();
if (!PluginManagerCore.PLUGIN_XML.equals(fileName)) {
final VirtualFile mainPluginXml = file.findFileByRelativePath("../" + PluginManagerCore.PLUGIN_XML);
if (mainPluginXml != null) {
final PsiFile psiFile = PsiManager.getInstance(ideaPlugin.getManager().getProject()).findFile(mainPluginXml);
if (psiFile instanceof XmlFile) {
final XmlFile xmlFile = (XmlFile)psiFile;
final IdeaPlugin mainPlugin = DescriptorUtil.getIdeaPlugin(xmlFile);
if (mainPlugin != null) {
ContainerUtil.addIfNotNull(result, mainPlugin.getPluginId());
for (Dependency dependency : mainPlugin.getDependencies()) {
ContainerUtil.addIfNotNull(result, dependency.getStringValue());
}
}
}
}
}
}
if (ideaPlugin.getPluginId() != null) {
return result;
}
final VirtualFile currentFile = DomUtil.getFile(ideaPlugin).getOriginalFile().getVirtualFile();
if (currentFile == null) {
return result;
}
final Project project = ideaPlugin.getManager().getProject();
final VirtualFile[] includingFiles = FileIncludeManager.getManager(project).getIncludingFiles(currentFile, false);
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
Set<VirtualFile> includingAndDependsFiles = new SmartHashSet<>();
for (VirtualFile virtualFile : includingFiles) {
if (!fileIndex.isUnderSourceRootOfType(virtualFile, JavaModuleSourceRootTypes.PRODUCTION)) {
continue;
}
includingAndDependsFiles.add(virtualFile);
}
final Collection<VirtualFile> dependsToFiles = PluginIdDependenciesIndex.findDependsTo(project, currentFile);
includingAndDependsFiles.addAll(dependsToFiles);
if (includingAndDependsFiles.isEmpty()) {
return result;
}
final Set<String> ids = PluginIdDependenciesIndex.getPluginAndDependsIds(project, includingAndDependsFiles);
result.addAll(ids);
return result;
}
}
@@ -0,0 +1,98 @@
// 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 org.jetbrains.idea.devkit.dom.index;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.GlobalSearchScopesCore;
import com.intellij.util.PathUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.SmartHashSet;
import com.intellij.util.indexing.*;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.KeyDescriptor;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.devkit.dom.Dependency;
import org.jetbrains.idea.devkit.dom.IdeaPlugin;
import java.util.*;
public class PluginIdDependenciesIndex extends ScalarIndexExtension<String> {
private static final ID<String, Void> NAME = ID.create("PluginIdDependenciesIndex");
@NonNls
private static final String FILENAME_KEY_PREFIX = "___FILENAME___";
@NotNull
@Override
public KeyDescriptor<String> getKeyDescriptor() {
return EnumeratorStringDescriptor.INSTANCE;
}
@NotNull
@Override
public ID<String, Void> getName() {
return NAME;
}
@NotNull
@Override
public DataIndexer<String, Void, FileContent> getIndexer() {
return inputData -> {
IdeaPlugin plugin = RegistrationIndexer.obtainIdeaPlugin(inputData);
if (plugin == null) return Collections.emptyMap();
List<String> ids = new SmartList<>();
ContainerUtil.addIfNotNull(ids, plugin.getPluginId());
for (Dependency dependency : plugin.getDependencies()) {
ContainerUtil.addIfNotNull(ids, dependency.getStringValue());
final String configFile = dependency.getConfigFile().getStringValue();
if (configFile != null) {
final String filename = PathUtil.getFileName(configFile);
ids.add(getDependsIndexingKey(filename));
}
}
return ContainerUtil.newHashMap(ids, Collections.nCopies(ids.size(), null));
};
}
@Override
public int getVersion() {
return 0;
}
@NotNull
@Override
public FileBasedIndex.InputFilter getInputFilter() {
return new DefaultFileTypeSpecificInputFilter(StdFileTypes.XML);
}
@Override
public boolean dependsOnFileContent() {
return true;
}
public static Set<String> getPluginAndDependsIds(Project project, Set<VirtualFile> files) {
Set<String> ids = new SmartHashSet<>();
for (VirtualFile file : files) {
final Map<String, Void> data = FileBasedIndex.getInstance().getFileData(NAME, file, project);
ids.addAll(ContainerUtil.filter(data.keySet(), s -> !StringUtil.startsWith(s, FILENAME_KEY_PREFIX)));
}
return ids;
}
public static Collection<VirtualFile> findDependsTo(Project project, VirtualFile file) {
return FileBasedIndex.getInstance().getContainingFiles(NAME, getDependsIndexingKey(file.getName()),
GlobalSearchScopesCore.projectProductionScope(project));
}
private static String getDependsIndexingKey(String filename) {
return FILENAME_KEY_PREFIX + filename;
}
}
@@ -0,0 +1,11 @@
<!-- included from ExtensionsHighlighting.xml can access all its EPs -->
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<myPlugin.foo.bar implementation="java.util.ArrayList" os="<error descr="Unknown enum value 'INVALID_VALUE'">INVALID_VALUE</error>"/>
<completion.contributor/>
<custom.custom/>
<indirect.indirect/>
</extensions>
</idea-plugin>
@@ -0,0 +1,12 @@
<!-- via <depends> from ExtensionsHighlighting.xml can access all its EPs -->
<idea-plugin>
<module value="com.myplugin.depends"/>
<extensions defaultExtensionNs="com.intellij">
<myPlugin.foo.bar implementation="java.util.ArrayList" os="<error descr="Unknown enum value 'INVALID_VALUE'">INVALID_VALUE</error>"/>
<completion.contributor/>
<custom.custom/>
<indirect.indirect/>
</extensions>
</idea-plugin>
@@ -1,4 +1,4 @@
<idea-plugin>
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
<id>com.intellij.myPlugin</id>
<vendor>JetBrains</vendor>
<version>1.0</version>
@@ -12,6 +12,10 @@
</extensionPoints>
<depends>com.intellij.custom</depends>
<depends config-file="../ExtensionsHighlighting-via-depends.xml">com.myplugin.depends</depends>
<xi:include href="ExtensionsHighlighting-included.xml" xpointer="xpointer(/idea-plugin/*)"/>
<extensions defaultExtensionNs="com.intellij">
<<error descr="'implementation' attribute should be defined">myPlugin.ext</error>/>
@@ -159,7 +159,12 @@ class PluginXmlFunctionalTest extends JavaCodeInsightFixtureTestCase {
"public class MyServiceDescriptor { @Attribute public String serviceImplementation; }")
configureByFile()
myFixture.copyFileToProject("ExtensionsHighlighting-included.xml")
myFixture.copyFileToProject("ExtensionsHighlighting-via-depends.xml",)
myFixture.checkHighlighting(true, false, false)
myFixture.testHighlighting("ExtensionsHighlighting-included.xml")
myFixture.testHighlighting("ExtensionsHighlighting-via-depends.xml")
}
void testDependsHighlighting() {