mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[plugins] IJPL-251952 constraint resolver: protect against potential self-dependency coming from provideCompatibilityDependenciesForRemainingCandidates
(cherry picked from commit 7635566925dac4e62778ea4f17c9f9c214dce36b) GitOrigin-RevId: 78b3e68cbb2c97871936b28666200003e81fd314
This commit is contained in:
committed by
intellij-monorepo-bot
parent
907d626e79
commit
a676d3e80f
+10
-4
@@ -400,7 +400,10 @@ private class PluginSetConstraintsResolver(
|
||||
}
|
||||
|
||||
val compatibilityDependencies = initContext.provideCompatibilityDependenciesForRemainingCandidates(descriptor, remainingCandidatesView)
|
||||
.mapNotNullTo(ArrayList()) { remainingCandidatesView.resolveReference(it) }
|
||||
.mapNotNullTo(ArrayList()) { dependencyRef ->
|
||||
remainingCandidatesView.resolveReference(dependencyRef)
|
||||
?.takeIf { it !== descriptor }
|
||||
}
|
||||
if (compatibilityDependencies.isNotEmpty()) {
|
||||
contributeDependencies(compatibilityDependencies)
|
||||
}
|
||||
@@ -456,8 +459,11 @@ private class PluginSetConstraintsResolver(
|
||||
val descriptorGraph = DFSTBuilder(DescriptorGraphAdapter(remainingCandidates, resolvedDependents))
|
||||
if (!descriptorGraph.isAcyclic) {
|
||||
for (component in descriptorGraph.components) {
|
||||
if (component.size <= 1) {
|
||||
continue
|
||||
if (component.size == 1) {
|
||||
val selfDependent = component.first() in resolvedDependencies[component.first()].orEmpty()
|
||||
if (!selfDependent) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
val component = component.sortedWith(compareBy { it.pluginId }) // makes result stable
|
||||
val cycleNodesWithDependencies = component.associateWith { ArrayList<IdeaPluginDescriptorImpl>() }
|
||||
@@ -512,7 +518,7 @@ private class PluginSetConstraintsResolver(
|
||||
if (!dfstBuilder.isAcyclic) {
|
||||
for (component in dfstBuilder.components) {
|
||||
if (component.size <= 1) {
|
||||
continue
|
||||
continue // no self-dependency expected: implied by filtering in dependency list construction above
|
||||
}
|
||||
val component = component.sortedWith(compareBy { it.representativeModule.pluginId }) // make result stable
|
||||
val cycleNodesWithDependencies = component.associateWith { ArrayList<RuntimeModuleGroup>() }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.plugins
|
||||
|
||||
import com.intellij.ide.plugins.PluginDependencyAnalysis.DependencyRef
|
||||
import com.intellij.ide.plugins.cl.PluginClassLoader
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
@@ -22,6 +23,7 @@ import com.intellij.testFramework.rules.InMemoryFsExtension
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.Timeout
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
import java.nio.file.FileVisitResult
|
||||
|
||||
@@ -856,6 +858,21 @@ internal class PluginDependenciesTest {
|
||||
|
||||
@Nested
|
||||
inner class ImplicitDependencyAdditionTests {
|
||||
@Test
|
||||
@Timeout(10)
|
||||
fun `soft compatibility dependency on self is ignored`() {
|
||||
plugin("foo") {}.installAt(pluginDirPath)
|
||||
val pluginSet = PluginSetTestBuilder.fromPath(pluginDirPath)
|
||||
.withCompatibilityDependenciesForRemainingCandidatesProvider { descriptor, remainingCandidates ->
|
||||
check(remainingCandidates.resolvePluginId(descriptor.pluginId) === descriptor)
|
||||
sequenceOf(DependencyRef.of(descriptor.pluginId))
|
||||
}
|
||||
.build()
|
||||
|
||||
val foo = pluginSet.getEnabledPlugin("foo")
|
||||
assertThat(pluginSet.resolvedPluginSet?.getDirectResolvedDependencies(foo)).doesNotContain(foo)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `legacy plugin gets implicit java dependency when all modules marker is present`() {
|
||||
// marker enables implicit dependencies for legacy plugins
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
package com.intellij.platform.pluginSystem.testFramework
|
||||
|
||||
import com.intellij.ide.plugins.DiscoveredPluginsList
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptorImpl
|
||||
import com.intellij.ide.plugins.PluginDependencyAnalysis.DependencyRef
|
||||
import com.intellij.ide.plugins.PluginDescriptorLoadingContext
|
||||
import com.intellij.ide.plugins.PluginInitContextFactory
|
||||
import com.intellij.ide.plugins.PluginInitializationContext
|
||||
import com.intellij.ide.plugins.PluginInitializationContext.RemainingCandidatesView
|
||||
import com.intellij.ide.plugins.PluginLoadingErrorReportingPolicy
|
||||
import com.intellij.ide.plugins.PluginMainDescriptor
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
@@ -32,6 +35,8 @@ class PluginSetTestBuilder private constructor(
|
||||
private var customCoreLoader: UrlClassLoader? = null
|
||||
private var productMode: ProductMode = ProductMode.MONOLITH
|
||||
private var explicitPluginSubsetToLoad: Set<PluginId>? = null
|
||||
private var compatibilityDependenciesForRemainingCandidatesProvider:
|
||||
((IdeaPluginDescriptorImpl, RemainingCandidatesView) -> Sequence<DependencyRef>)? = null
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@@ -75,6 +80,12 @@ class PluginSetTestBuilder private constructor(
|
||||
this.explicitPluginSubsetToLoad = pluginsToLoad
|
||||
}
|
||||
|
||||
fun withCompatibilityDependenciesForRemainingCandidatesProvider(
|
||||
provider: (IdeaPluginDescriptorImpl, RemainingCandidatesView) -> Sequence<DependencyRef>,
|
||||
): PluginSetTestBuilder = apply {
|
||||
compatibilityDependenciesForRemainingCandidatesProvider = provider
|
||||
}
|
||||
|
||||
var buildNumber: String
|
||||
get() = productBuildNumber.toString()
|
||||
set(value) {
|
||||
@@ -92,6 +103,15 @@ class PluginSetTestBuilder private constructor(
|
||||
}
|
||||
override val explicitPluginSubsetToLoad: Set<PluginId>? = this@PluginSetTestBuilder.explicitPluginSubsetToLoad
|
||||
override val currentProductModeId: String = productMode.id
|
||||
override fun provideCompatibilityDependenciesForRemainingCandidates(
|
||||
descriptor: IdeaPluginDescriptorImpl,
|
||||
remainingCandidates: RemainingCandidatesView,
|
||||
): Sequence<DependencyRef> {
|
||||
compatibilityDependenciesForRemainingCandidatesProvider?.let { provider ->
|
||||
return provider(descriptor, remainingCandidates)
|
||||
}
|
||||
return super.provideCompatibilityDependenciesForRemainingCandidates(descriptor, remainingCandidates)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,4 +140,4 @@ class PluginSetTestBuilder private constructor(
|
||||
}
|
||||
|
||||
fun build(): PluginSet = buildState().pluginSet
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user