mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
[devkit] IJPL-209927 Make the inspection work in regular plugins (not monorepo)
We need to search for module inclusion contexts also in libraries. (cherry picked from commit c6e9c65aaa3927354bd36fff9af878a0dd85a6eb) IJ-CR-181567 GitOrigin-RevId: 85d4f08facc00c252056f790ca04cbd0379f9b94
This commit is contained in:
committed by
intellij-monorepo-bot
parent
67d829233e
commit
1c94695eb6
@@ -9,11 +9,14 @@ import com.intellij.codeInspection.util.IntentionName
|
||||
import com.intellij.ide.highlighter.XmlFileType
|
||||
import com.intellij.openapi.fileEditor.UniqueVFilePathBuilder
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.SmartPsiElementPointer
|
||||
import com.intellij.psi.createSmartPointer
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.GlobalSearchScopesCore
|
||||
import com.intellij.psi.search.ProjectScope
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import com.intellij.psi.xml.XmlFile
|
||||
@@ -54,10 +57,10 @@ internal class ContentModuleVisibilityInspection : DevKitPluginXmlInspectionBase
|
||||
holder: DomElementAnnotationHolder,
|
||||
) {
|
||||
val currentXmlFile = dependencyValue.xmlElement?.containingFile as? XmlFile ?: return
|
||||
val productionXmlFilesScope = getProjectProductionXmlFilesScope(currentXmlFile.project)
|
||||
val currentModuleIncludingFiles = getInclusionContextsForContentModuleOrPluginXmlFile(currentXmlFile, productionXmlFilesScope)
|
||||
val xmlFilesScope = getXmlFilesScope(currentXmlFile.project)
|
||||
val currentModuleIncludingFiles = getInclusionContextsForContentModuleOrPluginXmlFile(currentXmlFile, xmlFilesScope)
|
||||
val dependencyXmlFile = moduleDependency.xmlElement?.containingFile as? XmlFile ?: return
|
||||
val dependencyIncludingFiles = getInclusionContextsForContentModuleOrPluginXmlFile(dependencyXmlFile, productionXmlFilesScope)
|
||||
val dependencyIncludingFiles = getInclusionContextsForContentModuleOrPluginXmlFile(dependencyXmlFile, xmlFilesScope)
|
||||
|
||||
for (currentModuleInclusionContext in currentModuleIncludingFiles) {
|
||||
for (dependencyInclusionContext in dependencyIncludingFiles) {
|
||||
@@ -149,15 +152,39 @@ internal class ContentModuleVisibilityInspection : DevKitPluginXmlInspectionBase
|
||||
val moduleVirtualFile = xmlFile.virtualFile ?: return emptyList()
|
||||
val psiManager = xmlFile.manager
|
||||
return PluginIdDependenciesIndex.findFilesIncludingContentModule(moduleVirtualFile, scope)
|
||||
.mapNotNull { psiManager.findFile(it) as? XmlFile }
|
||||
.flatMap { xmlFile ->
|
||||
val currentDescriptor = DescriptorUtil.getIdeaPlugin(xmlFile) ?: return@flatMap emptyList()
|
||||
getRootIncludingPlugins(xmlFile, currentDescriptor, registrationPlace = currentDescriptor, scope)
|
||||
}
|
||||
.mapToXmlFileAndIdeaPlugin(psiManager)
|
||||
.withoutLibraryDuplicates(xmlFile.project)
|
||||
.flatMap { (xmlFile, ideaPlugin) -> getRootIncludingPlugins(xmlFile, ideaPlugin, registrationPlace = ideaPlugin, scope) }
|
||||
.distinct()
|
||||
.sortedWith(compareBy<ContentModuleInclusionContext> { it.rootPlugin.pluginIdOrPlainFileName }.thenBy { it.registrationPlace.pluginIdOrPlainFileName })
|
||||
}
|
||||
|
||||
private fun Collection<VirtualFile>.mapToXmlFileAndIdeaPlugin(psiManager: PsiManager): List<Pair<XmlFile, IdeaPlugin>> {
|
||||
return mapNotNull {
|
||||
val xmlFile = psiManager.findFile(it) as? XmlFile ?: return@mapNotNull null
|
||||
val ideaPlugin = DescriptorUtil.getIdeaPlugin(xmlFile) ?: return@mapNotNull null
|
||||
xmlFile to ideaPlugin
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<Pair<XmlFile, IdeaPlugin>>.withoutLibraryDuplicates(project: Project): List<Pair<XmlFile, IdeaPlugin>> {
|
||||
val productionScope = GlobalSearchScopesCore.projectProductionScope(project)
|
||||
return groupBy { it.second.pluginIdOrPlainFileName }
|
||||
.flatMap { (_, files) ->
|
||||
when {
|
||||
files.size == 1 -> files
|
||||
else -> {
|
||||
val productionFiles = files.filter { productionScope.contains(it.first.virtualFile) }
|
||||
return if (productionFiles.size < files.size && productionFiles.isNotEmpty()) {
|
||||
productionFiles
|
||||
} else {
|
||||
files
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class ContentModuleInclusionContext(
|
||||
/** Element of the root `plugin.xml` (or `<idea.platform.prefix>Plugin.xml`) which includes the content module. */
|
||||
val rootPlugin: IdeaPlugin,
|
||||
@@ -193,10 +220,10 @@ internal class ContentModuleVisibilityInspection : DevKitPluginXmlInspectionBase
|
||||
) {
|
||||
val currentXmlFile = dependencyValue.xmlElement?.containingFile as? XmlFile ?: return
|
||||
val project = currentXmlFile.project
|
||||
val productionXmlFilesScope = getProjectProductionXmlFilesScope(project)
|
||||
val currentModuleInclusionContexts = getInclusionContextsForContentModuleOrPluginXmlFile(currentXmlFile, productionXmlFilesScope)
|
||||
val xmlFilesScope = getXmlFilesScope(project)
|
||||
val currentModuleInclusionContexts = getInclusionContextsForContentModuleOrPluginXmlFile(currentXmlFile, xmlFilesScope)
|
||||
val dependencyXmlFile = moduleDependency.xmlElement?.containingFile as? XmlFile ?: return
|
||||
val dependencyInclusionContexts = getInclusionContextsForContentModuleOrPluginXmlFile(dependencyXmlFile, productionXmlFilesScope)
|
||||
val dependencyInclusionContexts = getInclusionContextsForContentModuleOrPluginXmlFile(dependencyXmlFile, xmlFilesScope)
|
||||
for (currentModuleInclusionContext in currentModuleInclusionContexts) {
|
||||
val currentModuleIncludingPlugin = currentModuleInclusionContext.rootPlugin
|
||||
if (dependencyInclusionContexts.any { it.rootPlugin == currentModuleIncludingPlugin }) continue // are included in the same plugin
|
||||
@@ -234,8 +261,13 @@ internal class ContentModuleVisibilityInspection : DevKitPluginXmlInspectionBase
|
||||
}
|
||||
}
|
||||
|
||||
private fun getProjectProductionXmlFilesScope(project: Project): GlobalSearchScope {
|
||||
return GlobalSearchScope.getScopeRestrictedByFileTypes(GlobalSearchScopesCore.projectProductionScope(project), XmlFileType.INSTANCE)
|
||||
private fun getXmlFilesScope(project: Project): GlobalSearchScope {
|
||||
val productionScope = GlobalSearchScopesCore.projectProductionScope(project)
|
||||
val librariesScope = ProjectScope.getLibrariesScope(project)
|
||||
return GlobalSearchScope.getScopeRestrictedByFileTypes(
|
||||
productionScope.union(librariesScope),
|
||||
XmlFileType.INSTANCE
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6,6 +6,7 @@ import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.jetbrains.idea.devkit.DevkitJavaTestsUtil
|
||||
import org.jetbrains.idea.devkit.module.PluginModuleType
|
||||
|
||||
abstract class ContentModuleVisibilityInspectionTestBase : JavaCodeInsightFixtureTestCase() {
|
||||
@@ -927,6 +928,208 @@ class ContentModuleVisibilityInspectionTest : ContentModuleVisibilityInspectionT
|
||||
testHighlighting(testedFile)
|
||||
}
|
||||
|
||||
fun `test should report module dependency that is from different namespace in sources, but from the same namespace in a library`() {
|
||||
// this module is duplicated by the library added with PsiTestUtil.addLibrary below
|
||||
// (namespace in the library is test-namespace, as in com.example.plugin, so no issue would be reported, if the lib descriptor was taken)
|
||||
myFixture.addModuleWithPluginDescriptor(
|
||||
"com.example.plugin.with.internalmodule",
|
||||
"com.example.plugin.with.internalmodule/META-INF/plugin.xml",
|
||||
"""
|
||||
<idea-plugin>
|
||||
<id>com.example.plugin.with.internalmodule</id>
|
||||
<content namespace="another-namespace">
|
||||
<module name="com.example.internalmodule"/>
|
||||
</content>
|
||||
</idea-plugin>
|
||||
""".trimIndent())
|
||||
|
||||
myFixture.addModuleWithPluginDescriptor(
|
||||
"com.example.internalmodule",
|
||||
"com.example.internalmodule/com.example.internalmodule.xml",
|
||||
"""
|
||||
<idea-plugin visibility="internal">
|
||||
</idea-plugin>
|
||||
""".trimIndent())
|
||||
|
||||
myFixture.addModuleWithPluginDescriptor(
|
||||
"com.example.plugin",
|
||||
"com.example.plugin/META-INF/plugin.xml",
|
||||
"""
|
||||
<idea-plugin>
|
||||
<id>com.example.plugin</id>
|
||||
<content namespace="test-namespace">
|
||||
<module name="com.example.currentmodule"/>
|
||||
</content>
|
||||
</idea-plugin>
|
||||
""".trimIndent())
|
||||
|
||||
val currentModuleName = "com.example.currentmodule"
|
||||
val currentModule = PsiTestUtil.addModule(
|
||||
project, PluginModuleType.getInstance(), currentModuleName, myFixture.tempDirFixture.findOrCreateDir(currentModuleName)
|
||||
)
|
||||
PsiTestUtil.addLibrary(
|
||||
currentModule, "${DevkitJavaTestsUtil.TESTDATA_ABSOLUTE_PATH}contentModules/com.example.plugin.with.internal.module.jar"
|
||||
)
|
||||
|
||||
val testedFile = myFixture.addXmlFile(
|
||||
"com.example.currentmodule/com.example.currentmodule.xml",
|
||||
"""
|
||||
<idea-plugin>
|
||||
<dependencies>
|
||||
<module name="<error descr="The 'com.example.internalmodule' module is internal and declared in namespace 'another-namespace' in 'com.example.plugin.with.internalmodule/…/plugin.xml', so it cannot be accessed from module 'com.example.currentmodule', which is declared in namespace 'test-namespace' in 'com.example.plugin/…/plugin.xml'">com.example.internalmodule</error>"/>
|
||||
</dependencies>
|
||||
</idea-plugin>
|
||||
""".trimIndent()
|
||||
)
|
||||
testHighlighting(testedFile)
|
||||
}
|
||||
|
||||
fun `test should report module dependency that is from different namespace and provider in a library`() {
|
||||
myFixture.addModuleWithPluginDescriptor(
|
||||
"com.example.internalmodule",
|
||||
"com.example.internalmodule/com.example.internalmodule.xml",
|
||||
"""
|
||||
<idea-plugin visibility="internal">
|
||||
</idea-plugin>
|
||||
""".trimIndent())
|
||||
|
||||
myFixture.addModuleWithPluginDescriptor(
|
||||
"com.example.plugin",
|
||||
"com.example.plugin/META-INF/plugin.xml",
|
||||
"""
|
||||
<idea-plugin>
|
||||
<id>com.example.plugin</id>
|
||||
<content namespace="test-namespace">
|
||||
<module name="com.example.currentmodule"/>
|
||||
</content>
|
||||
</idea-plugin>
|
||||
""".trimIndent())
|
||||
|
||||
val currentModuleName = "com.example.currentmodule"
|
||||
val currentModule = PsiTestUtil.addModule(
|
||||
project, PluginModuleType.getInstance(), currentModuleName, myFixture.tempDirFixture.findOrCreateDir(currentModuleName)
|
||||
)
|
||||
PsiTestUtil.addLibrary(
|
||||
currentModule,
|
||||
"${DevkitJavaTestsUtil.TESTDATA_ABSOLUTE_PATH}contentModules/com.example.plugin.with.internal.module-another-namespace.jar"
|
||||
)
|
||||
|
||||
val testedFile = myFixture.addXmlFile(
|
||||
"com.example.currentmodule/com.example.currentmodule.xml",
|
||||
"""
|
||||
<idea-plugin>
|
||||
<dependencies>
|
||||
<module name="<error descr="The 'com.example.internalmodule' module is internal and declared in namespace 'another-namespace' in 'plugin.xml', so it cannot be accessed from module 'com.example.currentmodule', which is declared in namespace 'test-namespace' in 'plugin.xml'">com.example.internalmodule</error>"/>
|
||||
</dependencies>
|
||||
</idea-plugin>
|
||||
""".trimIndent()
|
||||
)
|
||||
testHighlighting(testedFile)
|
||||
}
|
||||
|
||||
fun `test should report module dependency that is private in source, but public in library`() {
|
||||
myFixture.addModuleWithPluginDescriptor(
|
||||
"com.example.plugin.with.public.or.private.module",
|
||||
"com.example.plugin.with.public.or.private.module/META-INF/plugin.xml",
|
||||
"""
|
||||
<idea-plugin>
|
||||
<id>com.example.plugin.with.public.or.private.module</id>
|
||||
<content>
|
||||
<module name="com.example.public.or.private.module"/>
|
||||
</content>
|
||||
</idea-plugin>
|
||||
""".trimIndent())
|
||||
|
||||
// this module is duplicated by the library added with PsiTestUtil.addLibrary below
|
||||
myFixture.addModuleWithPluginDescriptor(
|
||||
"com.example.public.or.private.module",
|
||||
"com.example.public.or.private.module/com.example.public.or.private.module.xml",
|
||||
"""
|
||||
<idea-plugin visibility="private">
|
||||
</idea-plugin>
|
||||
""".trimIndent())
|
||||
|
||||
myFixture.addModuleWithPluginDescriptor(
|
||||
"com.example.plugin.with.currentmodule",
|
||||
"com.example.plugin.with.currentmodule/META-INF/plugin.xml",
|
||||
"""
|
||||
<idea-plugin>
|
||||
<id>com.example.plugin.with.currentmodule</id>
|
||||
<content namespace="test-namespace">
|
||||
<module name="com.example.currentmodule"/>
|
||||
</content>
|
||||
</idea-plugin>
|
||||
""".trimIndent())
|
||||
|
||||
val currentModuleName = "com.example.currentmodule"
|
||||
val currentModule = PsiTestUtil.addModule(
|
||||
project, PluginModuleType.getInstance(), currentModuleName, myFixture.tempDirFixture.findOrCreateDir(currentModuleName)
|
||||
)
|
||||
PsiTestUtil.addLibrary(currentModule,
|
||||
"${DevkitJavaTestsUtil.TESTDATA_ABSOLUTE_PATH}contentModules/com.example.public.or.private.module.jar")
|
||||
|
||||
val testedFile = myFixture.addXmlFile(
|
||||
"com.example.currentmodule/com.example.currentmodule.xml",
|
||||
"""
|
||||
<idea-plugin>
|
||||
<dependencies>
|
||||
<module name="<error descr="The 'com.example.public.or.private.module' module is private and declared in plugin 'com.example.plugin.with.public.or.private.module', so it cannot be accessed from module 'com.example.currentmodule' declared in plugin 'com.example.plugin.with.currentmodule'">com.example.public.or.private.module</error>"/>
|
||||
</dependencies>
|
||||
</idea-plugin>
|
||||
""".trimIndent()
|
||||
)
|
||||
testHighlighting(testedFile)
|
||||
}
|
||||
|
||||
fun `test should report module dependency that is private and provided from a library`() {
|
||||
val pluginWithPrivateModuleName = "com.example.plugin.with.private.module"
|
||||
val pluginWithPrivateModuleModule = PsiTestUtil.addModule(
|
||||
myFixture.project, PluginModuleType.getInstance(), pluginWithPrivateModuleName,
|
||||
myFixture.tempDirFixture.findOrCreateDir(pluginWithPrivateModuleName)
|
||||
)
|
||||
myFixture.addXmlFile("com.example.plugin.with.private.module/META-INF/plugin.xml", """
|
||||
<idea-plugin>
|
||||
<id>com.example.plugin.with.private.module</id>
|
||||
<content>
|
||||
<module name="com.example.private.module"/>
|
||||
</content>
|
||||
</idea-plugin>
|
||||
""".trimIndent())
|
||||
|
||||
val privateModuleJarPath = "${DevkitJavaTestsUtil.TESTDATA_ABSOLUTE_PATH}contentModules/com.example.private.module.jar"
|
||||
PsiTestUtil.addLibrary(pluginWithPrivateModuleModule, privateModuleJarPath)
|
||||
|
||||
myFixture.addModuleWithPluginDescriptor(
|
||||
"com.example.plugin.with.currentmodule",
|
||||
"com.example.plugin.with.currentmodule/META-INF/plugin.xml",
|
||||
"""
|
||||
<idea-plugin>
|
||||
<id>com.example.plugin.with.currentmodule</id>
|
||||
<content namespace="test-namespace">
|
||||
<module name="com.example.currentmodule"/>
|
||||
</content>
|
||||
</idea-plugin>
|
||||
""".trimIndent())
|
||||
|
||||
val currentModuleName = "com.example.currentmodule"
|
||||
val currentModule = PsiTestUtil.addModule(
|
||||
project, PluginModuleType.getInstance(), currentModuleName, myFixture.tempDirFixture.findOrCreateDir(currentModuleName)
|
||||
)
|
||||
PsiTestUtil.addLibrary(currentModule, privateModuleJarPath)
|
||||
|
||||
val testedFile = myFixture.addXmlFile(
|
||||
"com.example.currentmodule/com.example.currentmodule.xml",
|
||||
"""
|
||||
<idea-plugin>
|
||||
<dependencies>
|
||||
<module name="<error descr="The 'com.example.private.module' module is private and declared in plugin 'com.example.plugin.with.private.module', so it cannot be accessed from module 'com.example.currentmodule' declared in plugin 'com.example.plugin.with.currentmodule'">com.example.private.module</error>"/>
|
||||
</dependencies>
|
||||
</idea-plugin>
|
||||
""".trimIndent()
|
||||
)
|
||||
testHighlighting(testedFile)
|
||||
}
|
||||
|
||||
private fun testHighlighting(testedFile: PsiFile) {
|
||||
myFixture.testHighlighting(true, true, true, testedFile.virtualFile)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user