mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-02-04 23:39:07 +07:00
IDEA-271872 Devkit: support resolving sub-descriptors for <module>
GitOrigin-RevId: ee6adf98c13f54309db4684bf75e317c44b43610
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5135570523
commit
7c3b56da4b
@@ -6,18 +6,23 @@ import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.module.ModuleUtilCore;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
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.search.GlobalSearchScopes;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.xml.ConvertContext;
|
||||
import com.intellij.util.xml.DomUtil;
|
||||
import com.intellij.util.xml.ElementPresentationManager;
|
||||
import com.intellij.util.xml.ResolvingConverter;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.devkit.DevKitBundle;
|
||||
@@ -30,10 +35,28 @@ import java.util.*;
|
||||
|
||||
public class ModuleDescriptorNameConverter extends ResolvingConverter<IdeaPlugin> {
|
||||
|
||||
@NonNls
|
||||
private static final String SUB_DESCRIPTOR_DELIMITER = "/";
|
||||
@NonNls
|
||||
private static final String SUB_DESCRIPTOR_FILENAME_DELIMITER = ".";
|
||||
|
||||
@Override
|
||||
public String getErrorMessage(@Nullable String s, ConvertContext context) {
|
||||
String value = StringUtil.notNullize(s);
|
||||
|
||||
String filePath;
|
||||
String moduleName;
|
||||
if (isSubDescriptor(value)) {
|
||||
filePath = getSubDescriptorFilePath(value);
|
||||
moduleName = getSubDescriptorModuleName(value);
|
||||
}
|
||||
else {
|
||||
filePath = getDescriptorFilePath(value);
|
||||
moduleName = value;
|
||||
}
|
||||
|
||||
return DevKitBundle.message("plugin.xml.convert.module.descriptor.name",
|
||||
getDescriptorFilePath(s), s);
|
||||
filePath, moduleName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,9 +65,21 @@ public class ModuleDescriptorNameConverter extends ResolvingConverter<IdeaPlugin
|
||||
if (StringUtil.isEmpty(s)) return null;
|
||||
final Module currentModule = context.getModule();
|
||||
if (currentModule == null) return null;
|
||||
final ModuleManager moduleManager = ModuleManager.getInstance(context.getProject());
|
||||
|
||||
final Module module = ModuleManager.getInstance(context.getProject()).findModuleByName(s);
|
||||
return module != null && getDependencies(currentModule).contains(module) ? findForModule(module) : null;
|
||||
if (isSubDescriptor(s)) {
|
||||
final Module module = moduleManager.findModuleByName(getSubDescriptorModuleName(s));
|
||||
if (module != null && (module == currentModule || getDependencies(currentModule).contains(module))) {
|
||||
return findDescriptorFile(module, getSubDescriptorFilePath(s));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
final Module module = moduleManager.findModuleByName(s);
|
||||
if (module != null && getDependencies(currentModule).contains(module)) {
|
||||
return findDescriptorFile(module, getDescriptorFilePath(module.getName()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,13 +90,23 @@ public class ModuleDescriptorNameConverter extends ResolvingConverter<IdeaPlugin
|
||||
|
||||
@NotNull
|
||||
private static String getDisplayName(@NotNull IdeaPlugin plugin) {
|
||||
return DomUtil.getFile(plugin).getVirtualFile().getNameWithoutExtension();
|
||||
final Module module = Objects.requireNonNull(plugin.getModule());
|
||||
final String moduleName = module.getName();
|
||||
|
||||
final VirtualFile virtualFile = DomUtil.getFile(plugin).getVirtualFile();
|
||||
final String fileName = virtualFile.getNameWithoutExtension();
|
||||
if (moduleName.equals(fileName)) {
|
||||
return fileName;
|
||||
}
|
||||
return moduleName + SUB_DESCRIPTOR_DELIMITER + StringUtil.substringAfterLast(fileName, SUB_DESCRIPTOR_FILENAME_DELIMITER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable LookupElement createLookupElement(IdeaPlugin plugin) {
|
||||
return LookupElementBuilder.create(plugin, getDisplayName(plugin))
|
||||
final String displayName = getDisplayName(plugin);
|
||||
return LookupElementBuilder.create(Objects.requireNonNull(getPsiElement(plugin)), displayName)
|
||||
.withIcon(ElementPresentationManager.getIconForClass(ContentDescriptor.ModuleDescriptor.class))
|
||||
.withBoldness(isSubDescriptor(displayName))
|
||||
.withTypeText(plugin.getPackage().getStringValue());
|
||||
}
|
||||
|
||||
@@ -69,17 +114,24 @@ public class ModuleDescriptorNameConverter extends ResolvingConverter<IdeaPlugin
|
||||
public @NotNull Collection<? extends IdeaPlugin> getVariants(ConvertContext context) {
|
||||
final Module currentModule = context.getModule();
|
||||
if (currentModule == null) return Collections.emptyList();
|
||||
final Project project = context.getProject();
|
||||
List<IdeaPlugin> variants = new SmartList<>();
|
||||
|
||||
final Set<Module> dependencies = getDependencies(currentModule);
|
||||
List<IdeaPlugin> variants = new SmartList<>();
|
||||
dependencies.add(currentModule);
|
||||
for (Module module : dependencies) {
|
||||
ContainerUtil.addIfNotNull(variants, findForModule(module));
|
||||
String moduleName = module.getName();
|
||||
processModuleSourceRoots(module, root -> {
|
||||
final Collection<IdeaPlugin> plugins = DescriptorUtil.getPlugins(project, GlobalSearchScopes.directoryScope(project, root, false));
|
||||
variants.addAll(ContainerUtil.filter(plugins, plugin -> DomUtil.getFile(plugin).getName().startsWith(moduleName)));
|
||||
return true;
|
||||
});
|
||||
}
|
||||
return variants;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Set<Module> getDependencies(Module currentModule) {
|
||||
private static Set<Module> getDependencies(@NotNull Module currentModule) {
|
||||
final Set<Module> dependencies = new LinkedHashSet<>();
|
||||
ModuleUtilCore.getDependencies(currentModule, dependencies);
|
||||
dependencies.remove(currentModule);
|
||||
@@ -87,22 +139,48 @@ public class ModuleDescriptorNameConverter extends ResolvingConverter<IdeaPlugin
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static IdeaPlugin findForModule(Module module) {
|
||||
String moduleName = module.getName();
|
||||
final List<VirtualFile> resourceRoots = ModuleRootManager.getInstance(module).getSourceRoots(JavaModuleSourceRootTypes.PRODUCTION);
|
||||
for (VirtualFile root : resourceRoots) {
|
||||
final VirtualFile candidate = root.findChild(getDescriptorFilePath(moduleName));
|
||||
if (candidate == null) continue;
|
||||
private static IdeaPlugin findDescriptorFile(@NotNull Module module, @NotNull String filePath) {
|
||||
Ref<IdeaPlugin> ideaPlugin = Ref.create();
|
||||
processModuleSourceRoots(module, root -> {
|
||||
final VirtualFile candidate = root.findChild(filePath);
|
||||
if (candidate == null) return true;
|
||||
final PsiFile psiFile = PsiManager.getInstance(module.getProject()).findFile(candidate);
|
||||
if (DescriptorUtil.isPluginXml(psiFile)) {
|
||||
return DescriptorUtil.getIdeaPlugin((XmlFile)psiFile);
|
||||
ideaPlugin.set(DescriptorUtil.getIdeaPlugin((XmlFile)psiFile));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return ideaPlugin.get();
|
||||
}
|
||||
|
||||
private static void processModuleSourceRoots(@NotNull Module module, Processor<VirtualFile> processor) {
|
||||
for (VirtualFile root : ModuleRootManager.getInstance(module).getSourceRoots(JavaModuleSourceRootTypes.PRODUCTION)) {
|
||||
if (!processor.process(root)) return;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getDescriptorFilePath(String moduleName) {
|
||||
return moduleName + ".xml";
|
||||
private static String getDescriptorFilePath(@NotNull String fileName) {
|
||||
return fileName + ".xml";
|
||||
}
|
||||
|
||||
private static boolean isSubDescriptor(@NotNull String value) {
|
||||
return StringUtil.contains(value, SUB_DESCRIPTOR_DELIMITER);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getSubDescriptorModuleName(@NotNull String value) {
|
||||
final String moduleName = StringUtil.substringBefore(value, SUB_DESCRIPTOR_DELIMITER);
|
||||
assert moduleName != null : value;
|
||||
return moduleName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getSubDescriptorFilePath(@NotNull String value) {
|
||||
final String moduleName = getSubDescriptorModuleName(value);
|
||||
final String fileName = StringUtil.substringAfter(value, SUB_DESCRIPTOR_DELIMITER);
|
||||
assert fileName != null : value;
|
||||
return getDescriptorFilePath(moduleName + SUB_DESCRIPTOR_FILENAME_DELIMITER + fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,8 @@ public final class PluginIdDependenciesIndex extends PluginXmlIndexBase<String,
|
||||
for (ContentDescriptor.ModuleDescriptor descriptor : plugin.getContent().getModuleEntry()) {
|
||||
final String value = descriptor.getName().getStringValue();
|
||||
if (StringUtil.isNotEmpty(value)) {
|
||||
ids.add(getContentIndexingKey(value));
|
||||
final String escapeSubDescriptorValue = value.replace('/', '.');
|
||||
ids.add(getContentIndexingKey(escapeSubDescriptorValue));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +98,7 @@ public final class PluginIdDependenciesIndex extends PluginXmlIndexBase<String,
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 4;
|
||||
return 5;
|
||||
}
|
||||
|
||||
public static Set<String> getPluginAndDependsIds(Project project, Set<VirtualFile> files) {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
|
||||
<!-- defined in ExtensionsDependencies.xml "main" plugin -->
|
||||
<myPlugin.mainPlugin
|
||||
implementation="java.lang.Integer"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
<content>
|
||||
<module name="ExtensionsDependencies-content"/>
|
||||
<module name="ExtensionsDependencies-content/subDescriptor"/>
|
||||
</content>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<idea-plugin package="mypackage.subpackage">
|
||||
|
||||
</idea-plugin>
|
||||
@@ -6,6 +6,12 @@
|
||||
<content>
|
||||
<module name="anotherModule"/>
|
||||
|
||||
<module name="anotherModule/secondary-descriptor"/>
|
||||
<module name="<error descr="Cannot resolve module descriptor 'anotherModule.INVALID_VALUE.xml' in source roots of module 'anotherModule'">anotherModule/INVALID_VALUE</error>"/>
|
||||
|
||||
<module name="mainModule/sub-descriptor"/>
|
||||
<module name="<error descr="Cannot resolve module descriptor 'mainModule.INVALID_VALUE.xml' in source roots of module 'mainModule'">mainModule/INVALID_VALUE</error>"/>
|
||||
|
||||
<module name="<error descr="Cannot resolve module descriptor 'invalidModuleName.xml' in source roots of module 'invalidModuleName'">invalidModuleName</error>"/>
|
||||
</content>
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<idea-plugin package="mypackage">
|
||||
|
||||
</idea-plugin>
|
||||
@@ -0,0 +1,3 @@
|
||||
<idea-plugin package="mypackage.subpackage">
|
||||
|
||||
</idea-plugin>
|
||||
@@ -0,0 +1,3 @@
|
||||
<idea-plugin package="mypackage.subpackage">
|
||||
|
||||
</idea-plugin>
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
<dependencies>
|
||||
<module name="anotherModule"/>
|
||||
<module name="anotherModule/secondary-descriptor"/>
|
||||
<module name="<error descr="Cannot resolve module descriptor 'invalid.module.xml' in source roots of module 'invalid.module'">invalid.module</error>"/>
|
||||
|
||||
<plugin id="anotherModule.plugin.id"/>
|
||||
|
||||
@@ -11,11 +11,11 @@ import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.PathUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.idea.devkit.DevkitJavaTestsUtil;
|
||||
import org.jetbrains.idea.devkit.inspections.PluginXmlDomInspection;
|
||||
|
||||
@@ -24,17 +24,14 @@ import java.util.List;
|
||||
@TestDataPath("$CONTENT_ROOT/testData/codeInsight/contentDependencyDescriptor")
|
||||
public class PluginXmlContentDependencyDescriptorTest extends JavaCodeInsightFixtureTestCase {
|
||||
|
||||
@NonNls
|
||||
private static final String MAIN_MODULE_NAME = "mainModule";
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return DevkitJavaTestsUtil.TESTDATA_PATH + "codeInsight/contentDependencyDescriptor";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tuneFixture(JavaModuleFixtureBuilder<?> moduleBuilder) throws Exception {
|
||||
String editorUIApi = PathUtil.getJarPathForClass(AnAction.class);
|
||||
moduleBuilder.addLibrary("editor-ui-api", editorUIApi);
|
||||
}
|
||||
|
||||
public void testNonJetBrainsHighlighting() {
|
||||
doHighlightingTest(ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
}
|
||||
@@ -50,13 +47,19 @@ public class PluginXmlContentDependencyDescriptorTest extends JavaCodeInsightFix
|
||||
public void testContentDescriptorModuleNameCompletion() {
|
||||
setupModules("anotherModule");
|
||||
|
||||
List<String> lookupElements = myFixture.getCompletionVariants("META-INF/plugin.xml");
|
||||
assertSameElements(lookupElements, "anotherModule");
|
||||
myFixture.configureFromTempProjectFile(MAIN_MODULE_NAME + "/META-INF/plugin.xml");
|
||||
myFixture.completeBasic();
|
||||
List<String> lookupElements = myFixture.getLookupElementStrings();
|
||||
assertSameElements(lookupElements, "anotherModule", "anotherModule/secondary-descriptor");
|
||||
|
||||
final LookupElementPresentation anotherModule = getLookupElementPresentation("anotherModule");
|
||||
assertEquals(AllIcons.Nodes.Module, anotherModule.getIcon());
|
||||
assertFalse(anotherModule.isItemTextBold());
|
||||
//noinspection SpellCheckingInspection
|
||||
assertEquals("mypackage.subpackage", anotherModule.getTypeText());
|
||||
|
||||
final LookupElementPresentation anotherModuleSecondary = getLookupElementPresentation("anotherModule/secondary-descriptor");
|
||||
assertTrue(anotherModuleSecondary.isItemTextBold());
|
||||
}
|
||||
|
||||
public void testContentDescriptorHighlighting() {
|
||||
@@ -87,24 +90,30 @@ public class PluginXmlContentDependencyDescriptorTest extends JavaCodeInsightFix
|
||||
setupModules(dependencyModuleNames);
|
||||
|
||||
myFixture.enableInspections(new PluginXmlDomInspection());
|
||||
myFixture.testHighlighting(true, false, false, "META-INF/plugin.xml");
|
||||
myFixture.testHighlighting(true, false, false, "mainModule/META-INF/plugin.xml");
|
||||
}
|
||||
|
||||
private void setupModules(String... dependencyModuleNames) {
|
||||
String testName = getTestName(true);
|
||||
myFixture.copyDirectoryToProject("/" + testName + "/mainModule", "/");
|
||||
|
||||
if (dependencyModuleNames.length == 0) return;
|
||||
|
||||
final Module mainModule = addModule(MAIN_MODULE_NAME);
|
||||
for (String moduleName : dependencyModuleNames) {
|
||||
final VirtualFile dependencyModuleRoot =
|
||||
myFixture.copyDirectoryToProject("/" + testName + "/" + moduleName, "/" + moduleName);
|
||||
|
||||
Module dependencyModule = PsiTestUtil.addModule(getProject(), StdModuleTypes.JAVA, moduleName, dependencyModuleRoot);
|
||||
ModuleRootModificationUtil.addDependency(getModule(), dependencyModule);
|
||||
final Module dependencyModule = addModule(moduleName);
|
||||
ModuleRootModificationUtil.addDependency(mainModule, dependencyModule);
|
||||
}
|
||||
}
|
||||
|
||||
private Module addModule(String moduleName) {
|
||||
String testName = getTestName(true);
|
||||
|
||||
final VirtualFile dependencyModuleRoot =
|
||||
myFixture.copyDirectoryToProject("/" + testName + "/" + moduleName, "/" + moduleName);
|
||||
|
||||
Module dependencyModule = PsiTestUtil.addModule(getProject(), StdModuleTypes.JAVA, moduleName, dependencyModuleRoot);
|
||||
PsiTestUtil.addLibrary(dependencyModule, "editor-ui-api", PathUtil.getJarPathForClass(AnAction.class));
|
||||
|
||||
return dependencyModule;
|
||||
}
|
||||
|
||||
private LookupElementPresentation getLookupElementPresentation(String lookupString) {
|
||||
final LookupElement lookupElement = ContainerUtil.find(myFixture.getLookupElements(),
|
||||
element -> element.getLookupString().equals(lookupString));
|
||||
|
||||
@@ -198,13 +198,20 @@ class PluginXmlFunctionalTest extends JavaCodeInsightFixtureTestCase {
|
||||
|
||||
void testExtensionsDependencies() {
|
||||
addExtensionsModule("ExtensionsDependencies-module")
|
||||
|
||||
VirtualFile contentFile = addExtensionsModule("ExtensionsDependencies-content")
|
||||
VirtualFile contentSubDescriptorFile =
|
||||
myFixture.copyFileToProject("ExtensionsDependencies-content.subDescriptor.xml",
|
||||
"/ExtensionsDependencies-content/ExtensionsDependencies-content.subDescriptor.xml")
|
||||
|
||||
doHighlightingTest("ExtensionsDependencies.xml",
|
||||
"ExtensionsDependencies-plugin.xml")
|
||||
|
||||
myFixture.configureFromExistingVirtualFile(contentFile)
|
||||
doHighlightingTest()
|
||||
|
||||
myFixture.configureFromExistingVirtualFile(contentSubDescriptorFile)
|
||||
doHighlightingTest()
|
||||
}
|
||||
|
||||
private VirtualFile addExtensionsModule(String name) {
|
||||
|
||||
Reference in New Issue
Block a user