mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[devkit] IJPL-185820: Report com.intellij.* plugin aliases for non-JetBrains plugins
GitOrigin-RevId: 26c9c810566975039824615253eebf1e9332a21b
This commit is contained in:
committed by
intellij-monorepo-bot
parent
7bf4fae01e
commit
bd1ae3e686
+11
@@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Reports restricted plugin module aliases in non-JetBrains plugin descriptors.
|
||||
</p>
|
||||
<p>
|
||||
Aliases starting with <code>com.intellij.*</code> are reserved for plugins developed by JetBrains and must not be declared
|
||||
by third-party plugins.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -551,6 +551,13 @@
|
||||
implementationClass="org.jetbrains.idea.devkit.inspections.ContentModuleNamespaceInspection"
|
||||
key="inspection.content.module.namespace.name"/>
|
||||
|
||||
<localInspection language="XML" applyToDialects="false"
|
||||
projectType="INTELLIJ_PLUGIN"
|
||||
groupPathKey="inspections.group.path" groupKey="inspections.group.descriptor"
|
||||
enabledByDefault="true" level="ERROR"
|
||||
implementationClass="org.jetbrains.idea.devkit.inspections.WrongPluginModuleAliasInspection"
|
||||
key="inspection.plugin.module.alias.name"/>
|
||||
|
||||
<localInspection language="UAST"
|
||||
projectType="INTELLIJ_PLUGIN"
|
||||
enabledByDefault="true"
|
||||
|
||||
@@ -837,4 +837,6 @@ plugins.php.description=PHP language
|
||||
plugins.ruby.description=Ruby language
|
||||
plugins.rust.description=Rust language
|
||||
inspection.use.optimized.eel.functions.display.name=Use optimized function from EelApi
|
||||
inspections.plugin.keys.in.platform.registry=Plugin keys defined in platform regitry.properties
|
||||
inspections.plugin.keys.in.platform.registry=Plugin keys defined in platform regitry.properties
|
||||
inspection.plugin.module.alias.name=Invalid plugin module alias
|
||||
inspection.plugin.module.alias.message=Plugin module alias must not start with 'com.intellij.*' in non-JetBrains plugins
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.inspections
|
||||
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.openapi.project.IntelliJProjectUtil
|
||||
import com.intellij.util.xml.DomElement
|
||||
import com.intellij.util.xml.DomUtil
|
||||
import com.intellij.util.xml.GenericAttributeValue
|
||||
import com.intellij.util.xml.highlighting.DomElementAnnotationHolder
|
||||
import com.intellij.util.xml.highlighting.DomHighlightingHelper
|
||||
import org.jetbrains.idea.devkit.DevKitBundle.message
|
||||
import org.jetbrains.idea.devkit.dom.IdeaPlugin
|
||||
import org.jetbrains.idea.devkit.dom.PluginModule
|
||||
|
||||
internal class WrongPluginModuleAliasInspection : DevKitPluginXmlInspectionBase() {
|
||||
|
||||
private val reservedPrefix = "com.intellij."
|
||||
|
||||
override fun checkDomElement(element: DomElement, holder: DomElementAnnotationHolder, helper: DomHighlightingHelper) {
|
||||
val module = element as? PluginModule ?: return
|
||||
if (IntelliJProjectUtil.isIntelliJPlatformProject(module.xmlElement?.project) || isDevelopedByJetBrains(element)) return
|
||||
|
||||
val value: GenericAttributeValue<String> = module.value
|
||||
val alias = value.value ?: return
|
||||
if (alias.startsWith(reservedPrefix)) {
|
||||
holder.createProblem(value, message("inspection.plugin.module.alias.message"))
|
||||
}
|
||||
}
|
||||
|
||||
private fun isDevelopedByJetBrains(element: PluginModule): Boolean {
|
||||
val vendor = DomUtil.findDomElement(element.xmlElement, IdeaPlugin::class.java)?.vendor ?: return false
|
||||
return PluginManagerCore.isDevelopedByJetBrains(vendor.stringValue)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -47,6 +47,7 @@ jvm_library(
|
||||
"//plugins/devkit/devkit-tests:testFramework_test_lib",
|
||||
"//platform/testFramework",
|
||||
"//platform/testFramework:testFramework_test_lib",
|
||||
"//platform/testFramework/junit5/codeInsight",
|
||||
"//java/compiler:compiler-tests_test_lib",
|
||||
"//java/testFramework",
|
||||
"//xml/dom-tests:dom-tests_test_lib",
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.usageView" />
|
||||
<orderEntry type="module" module-name="intellij.devkit.testFramework" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework.junit5.codeInsight" />
|
||||
<orderEntry type="module" module-name="intellij.java.compiler.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.java.testFramework" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.xml.dom.tests" scope="TEST" />
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.inspections
|
||||
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.openapi.project.IntelliJProjectUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.platform.testFramework.junit5.codeInsight.fixture.codeInsightFixture
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import com.intellij.testFramework.junit5.fixture.TestFixture
|
||||
import com.intellij.testFramework.junit5.fixture.moduleFixture
|
||||
import com.intellij.testFramework.junit5.fixture.projectFixture
|
||||
import com.intellij.testFramework.junit5.fixture.tempPathFixture
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.Arguments
|
||||
import org.junit.jupiter.params.provider.MethodSource
|
||||
import java.nio.file.Path
|
||||
import java.util.stream.Stream
|
||||
import kotlin.streams.asStream
|
||||
|
||||
@TestApplication
|
||||
class WrongPluginModuleAliasInspectionTest {
|
||||
|
||||
private val tempDir: TestFixture<Path> = tempPathFixture()
|
||||
private val project: TestFixture<Project> = projectFixture(tempDir, openAfterCreation = true)
|
||||
|
||||
@Suppress("unused") // required by codeInsightFixture
|
||||
private val module by project.moduleFixture(tempDir, addPathToSourceRoot = true)
|
||||
private val fixture = codeInsightFixture(project, tempDir)
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
fixture.get().enableInspections(WrongPluginModuleAliasInspection())
|
||||
}
|
||||
|
||||
@DisplayName("Plugin module alias inspection test")
|
||||
@ParameterizedTest(name = "{0} when vendor is ''{1}'', module prefix is ''{2}'', and IntelliJ Platform project is {3}")
|
||||
@MethodSource("testCases")
|
||||
fun testPluginModuleAlias(
|
||||
testExpectationPrefix: String,
|
||||
vendor: String,
|
||||
modulePrefix: String,
|
||||
isIntelliJProject: Boolean,
|
||||
) {
|
||||
if (isIntelliJProject) {
|
||||
IntelliJProjectUtil.markAsIntelliJPlatformProject(project.get(), true)
|
||||
}
|
||||
|
||||
val moduleValue = "${modulePrefix}myFeature"
|
||||
val errorTag = if (testExpectationPrefix == ERROR_EXPECTED) {
|
||||
"""<error descr="Plugin module alias must not start with 'com.intellij.*' in non-JetBrains plugins">$moduleValue</error>"""
|
||||
}
|
||||
else {
|
||||
moduleValue
|
||||
}
|
||||
|
||||
doTest("""
|
||||
<idea-plugin>
|
||||
<vendor>$vendor</vendor>
|
||||
<module value="$errorTag"/>
|
||||
</idea-plugin>
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
private fun doTest(@Language("XML") xml: String) {
|
||||
fixture.get().apply {
|
||||
configureByText("plugin.xml", xml)
|
||||
testHighlighting(false, false, true)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ERROR_EXPECTED = "should report error"
|
||||
private const val ERROR_NOT_EXPECTED = "should not report error"
|
||||
|
||||
@JvmStatic
|
||||
fun testCases(): Stream<Arguments> =
|
||||
cartesianProduct(
|
||||
listOf("JetBrains", "JetBrains s.r.o.", "JetBrains, Google", "Acme"),
|
||||
listOf("com.intellij.", "com.example."),
|
||||
listOf(true, false)
|
||||
).map { (vendor, prefix, isIntelliJProject) ->
|
||||
val expectError = !PluginManagerCore.isDevelopedByJetBrains(vendor) && prefix == "com.intellij." && !isIntelliJProject
|
||||
val testExpectationPrefix = if (expectError) ERROR_EXPECTED else ERROR_NOT_EXPECTED
|
||||
Arguments.of(testExpectationPrefix, vendor, prefix, isIntelliJProject)
|
||||
}.asStream()
|
||||
|
||||
private fun <A, B, C> cartesianProduct(
|
||||
listA: List<A>,
|
||||
listB: List<B>,
|
||||
listC: List<C>,
|
||||
): Sequence<Triple<A, B, C>> = sequence {
|
||||
for (a in listA) {
|
||||
for (b in listB) {
|
||||
for (c in listC) {
|
||||
yield(Triple(a, b, c))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user