mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IJPL-252216 preserve OpenProjectTask binary compatibility
Keep the generated data-class ABI stable and route plugin construction through the non-inline builder boundary. Store the post-open file marker in implementation options while retaining compatibility getters and the transient constructor shape. (cherry picked from commit 40094a325e760b8afbd9a82fc7fdee762dc89927) IJ-MR-217434 GitOrigin-RevId: 6faee079e1da873a574433ec646d16231f7f9bb5
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d81bf4adb4
commit
76df17c558
@@ -65,7 +65,10 @@ f:com.intellij.ide.impl.OpenProjectTask
|
||||
- f:component12():Z
|
||||
- f:component13():Z
|
||||
- f:component14():Z
|
||||
- f:component15():java.lang.String
|
||||
- f:component17():Z
|
||||
- f:component2():Z
|
||||
- f:component20():kotlin.jvm.functions.Function2
|
||||
- f:component3():com.intellij.openapi.project.Project
|
||||
- f:component4():Z
|
||||
- f:component5():Z
|
||||
|
||||
@@ -85,21 +85,17 @@ c:com.intellij.ide.impl.DataManagerImpl
|
||||
f:com.intellij.ide.impl.OpenProjectTask
|
||||
- f:asNewProject():com.intellij.ide.impl.OpenProjectTask
|
||||
- sf:build():com.intellij.ide.impl.OpenProjectTask
|
||||
- f:component15():Z
|
||||
- f:component16():java.lang.String
|
||||
- f:component17():java.lang.String
|
||||
- f:component18():Z
|
||||
- f:component19():Z
|
||||
- f:component20():kotlin.jvm.functions.Function1
|
||||
- f:component19():kotlin.jvm.functions.Function1
|
||||
- f:component21():kotlin.jvm.functions.Function2
|
||||
- f:component22():kotlin.jvm.functions.Function2
|
||||
- f:component23():Z
|
||||
- f:component24():kotlin.jvm.functions.Function1
|
||||
- f:component25():java.lang.Object
|
||||
- f:component26():java.nio.file.Path
|
||||
- f:component27():Z
|
||||
- f:copy(Z,Z,com.intellij.openapi.project.Project,Z,Z,com.intellij.openapi.project.Project,java.lang.String,Z,com.intellij.projectImport.ProjectOpenedCallback,I,I,Z,Z,Z,Z,java.lang.String,java.lang.String,Z,Z,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function2,Z,kotlin.jvm.functions.Function1,java.lang.Object,java.nio.file.Path,Z):com.intellij.ide.impl.OpenProjectTask
|
||||
- bs:copy$default(com.intellij.ide.impl.OpenProjectTask,Z,Z,com.intellij.openapi.project.Project,Z,Z,com.intellij.openapi.project.Project,java.lang.String,Z,com.intellij.projectImport.ProjectOpenedCallback,I,I,Z,Z,Z,Z,java.lang.String,java.lang.String,Z,Z,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function2,Z,kotlin.jvm.functions.Function1,java.lang.Object,java.nio.file.Path,Z,I,java.lang.Object):com.intellij.ide.impl.OpenProjectTask
|
||||
- f:component22():Z
|
||||
- f:component23():kotlin.jvm.functions.Function1
|
||||
- f:component24():java.lang.Object
|
||||
- f:component25():java.nio.file.Path
|
||||
- f:component26():Z
|
||||
- f:copy(Z,Z,com.intellij.openapi.project.Project,Z,Z,com.intellij.openapi.project.Project,java.lang.String,Z,com.intellij.projectImport.ProjectOpenedCallback,I,I,Z,Z,Z,java.lang.String,java.lang.String,Z,Z,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function2,Z,kotlin.jvm.functions.Function1,java.lang.Object,java.nio.file.Path,Z):com.intellij.ide.impl.OpenProjectTask
|
||||
- bs:copy$default(com.intellij.ide.impl.OpenProjectTask,Z,Z,com.intellij.openapi.project.Project,Z,Z,com.intellij.openapi.project.Project,java.lang.String,Z,com.intellij.projectImport.ProjectOpenedCallback,I,I,Z,Z,Z,java.lang.String,java.lang.String,Z,Z,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function2,Z,kotlin.jvm.functions.Function1,java.lang.Object,java.nio.file.Path,Z,I,java.lang.Object):com.intellij.ide.impl.OpenProjectTask
|
||||
- f:getBeforeInit():kotlin.jvm.functions.Function1
|
||||
- f:getBeforeOpen():kotlin.jvm.functions.Function2
|
||||
- f:getCallback():com.intellij.projectImport.ProjectOpenedCallback
|
||||
|
||||
@@ -11,6 +11,19 @@ import org.jetbrains.annotations.TestOnly
|
||||
import java.nio.file.Path
|
||||
import java.util.function.Predicate
|
||||
|
||||
private data class OpenProjectTaskImplOptions(
|
||||
@JvmField val delegate: Any?,
|
||||
@JvmField val opensFileAfterProjectOpen: Boolean,
|
||||
)
|
||||
|
||||
private fun Any?.asOpenProjectTaskImplOptions(): OpenProjectTaskImplOptions {
|
||||
return this as? OpenProjectTaskImplOptions ?: OpenProjectTaskImplOptions(delegate = this, opensFileAfterProjectOpen = false)
|
||||
}
|
||||
|
||||
private fun Any?.withOpensFileAfterProjectOpen(value: Boolean): OpenProjectTaskImplOptions {
|
||||
return asOpenProjectTaskImplOptions().copy(opensFileAfterProjectOpen = value)
|
||||
}
|
||||
|
||||
data class OpenProjectTask @Internal constructor(
|
||||
val forceOpenInNewFrame: Boolean,
|
||||
val forceReuseFrame: Boolean = false,
|
||||
@@ -26,15 +39,6 @@ data class OpenProjectTask @Internal constructor(
|
||||
val callback: ProjectOpenedCallback?,
|
||||
val line: Int,
|
||||
val column: Int,
|
||||
/**
|
||||
* Whether whoever opens this project is going to open an editor of its own once opening has finished — a file named on the command
|
||||
* line, for instance.
|
||||
*
|
||||
* The editor area holds back what it would otherwise show while project open is still deciding what goes there, and it can only
|
||||
* hold back what it knows about; this reports work that outlives project open itself.
|
||||
*/
|
||||
@Internal
|
||||
val opensFileAfterProjectOpen: Boolean = false,
|
||||
@Deprecated("Not used")
|
||||
val isRefreshVfsNeeded: Boolean,
|
||||
/**
|
||||
@@ -66,6 +70,80 @@ data class OpenProjectTask @Internal constructor(
|
||||
@Internal
|
||||
val createModule: Boolean,
|
||||
) {
|
||||
/**
|
||||
* Whether whoever opens this project is going to open an editor of its own once opening has finished — a file named on the command
|
||||
* line, for instance.
|
||||
*
|
||||
* The editor area holds back what it would otherwise show while project open is still deciding what goes there, and it can only
|
||||
* hold back what it knows about; this reports work that outlives project open itself.
|
||||
*
|
||||
* This property is deliberately not a primary-constructor parameter: adding one changes the generated data-class ABI.
|
||||
*/
|
||||
@get:Internal
|
||||
val opensFileAfterProjectOpen: Boolean
|
||||
get() = (implOptions as? OpenProjectTaskImplOptions)?.opensFileAfterProjectOpen == true
|
||||
|
||||
/**
|
||||
* Compatibility bridge for plugins compiled against builds where [opensFileAfterProjectOpen] was a primary-constructor parameter.
|
||||
*/
|
||||
@Internal
|
||||
constructor(
|
||||
forceOpenInNewFrame: Boolean,
|
||||
forceReuseFrame: Boolean,
|
||||
projectToClose: Project?,
|
||||
isNewProject: Boolean,
|
||||
useDefaultProjectAsTemplate: Boolean,
|
||||
project: Project?,
|
||||
projectName: String?,
|
||||
showWelcomeScreen: Boolean,
|
||||
callback: ProjectOpenedCallback?,
|
||||
line: Int,
|
||||
column: Int,
|
||||
opensFileAfterProjectOpen: Boolean,
|
||||
isRefreshVfsNeeded: Boolean,
|
||||
runConfigurators: Boolean,
|
||||
runConversionBeforeOpen: Boolean,
|
||||
projectWorkspaceId: String?,
|
||||
projectFrameTypeId: String?,
|
||||
isProjectCreatedWithWizard: Boolean,
|
||||
preloadServices: Boolean,
|
||||
beforeInit: ((Project) -> Unit)?,
|
||||
beforeOpen: (suspend (Project) -> Boolean)?,
|
||||
preparedToOpen: (suspend (Module) -> Unit)?,
|
||||
preventIprLookup: Boolean,
|
||||
processorChooser: ((List<Any>) -> Any)?,
|
||||
implOptions: Any?,
|
||||
projectRootDir: Path?,
|
||||
createModule: Boolean,
|
||||
) : this(
|
||||
forceOpenInNewFrame = forceOpenInNewFrame,
|
||||
forceReuseFrame = forceReuseFrame,
|
||||
projectToClose = projectToClose,
|
||||
isNewProject = isNewProject,
|
||||
useDefaultProjectAsTemplate = useDefaultProjectAsTemplate,
|
||||
project = project,
|
||||
projectName = projectName,
|
||||
showWelcomeScreen = showWelcomeScreen,
|
||||
callback = callback,
|
||||
line = line,
|
||||
column = column,
|
||||
isRefreshVfsNeeded = isRefreshVfsNeeded,
|
||||
runConfigurators = runConfigurators,
|
||||
runConversionBeforeOpen = runConversionBeforeOpen,
|
||||
projectWorkspaceId = projectWorkspaceId,
|
||||
projectFrameTypeId = projectFrameTypeId,
|
||||
isProjectCreatedWithWizard = isProjectCreatedWithWizard,
|
||||
preloadServices = preloadServices,
|
||||
beforeInit = beforeInit,
|
||||
beforeOpen = beforeOpen,
|
||||
preparedToOpen = preparedToOpen,
|
||||
preventIprLookup = preventIprLookup,
|
||||
processorChooser = processorChooser,
|
||||
implOptions = implOptions.withOpensFileAfterProjectOpen(opensFileAfterProjectOpen),
|
||||
projectRootDir = projectRootDir,
|
||||
createModule = createModule,
|
||||
)
|
||||
|
||||
@Internal
|
||||
constructor(
|
||||
forceOpenInNewFrame: Boolean = false,
|
||||
@@ -102,7 +180,7 @@ data class OpenProjectTask @Internal constructor(
|
||||
preparedToOpen = null,
|
||||
processorChooser = null,
|
||||
|
||||
implOptions = null,
|
||||
implOptions = OpenProjectTaskImplOptions(delegate = null, opensFileAfterProjectOpen = false),
|
||||
createModule = true,
|
||||
|
||||
projectRootDir = null,
|
||||
@@ -118,6 +196,22 @@ data class OpenProjectTask @Internal constructor(
|
||||
fun asNewProject(): OpenProjectTask = copy(isNewProject = true, useDefaultProjectAsTemplate = true)
|
||||
fun withProject(project: Project?): OpenProjectTask = copy(project = project)
|
||||
fun withProjectName(projectName: String?): OpenProjectTask = copy(projectName = projectName)
|
||||
|
||||
@Internal
|
||||
fun markAsOpeningFileAfterProjectOpen(): OpenProjectTask = copy(implOptions = implOptions.withOpensFileAfterProjectOpen(value = true))
|
||||
}
|
||||
|
||||
@get:Internal
|
||||
val OpenProjectTask.effectiveImplOptions: Any?
|
||||
get() = when (val options = implOptions) {
|
||||
is OpenProjectTaskImplOptions -> options.delegate
|
||||
else -> options
|
||||
}
|
||||
|
||||
@Internal
|
||||
fun OpenProjectTask.withImplOptions(implOptions: Any?): OpenProjectTask {
|
||||
val options = this.implOptions.asOpenProjectTaskImplOptions().copy(delegate = implOptions)
|
||||
return copy(implOptions = options)
|
||||
}
|
||||
|
||||
class OpenProjectTaskBuilder @PublishedApi internal constructor() {
|
||||
@@ -186,7 +280,7 @@ class OpenProjectTaskBuilder @PublishedApi internal constructor() {
|
||||
createModule = false
|
||||
}
|
||||
|
||||
@PublishedApi internal inline fun build(builder: OpenProjectTaskBuilder.() -> Unit): OpenProjectTask {
|
||||
@PublishedApi internal fun build(builder: OpenProjectTaskBuilder.() -> Unit): OpenProjectTask {
|
||||
builder()
|
||||
if (project != null && createModule) {
|
||||
thisLogger().warn("Project is explicitly set (name=${project?.name}), but createModule is true")
|
||||
@@ -232,5 +326,8 @@ class OpenProjectTaskBuilder @PublishedApi internal constructor() {
|
||||
|
||||
@Internal
|
||||
inline fun OpenProjectTask(buildAction: OpenProjectTaskBuilder.() -> Unit): OpenProjectTask {
|
||||
return OpenProjectTaskBuilder().build(buildAction)
|
||||
val builder = OpenProjectTaskBuilder()
|
||||
builder.buildAction()
|
||||
// Keep the pre-existing build(Function1) call in client bytecode, but do not inline the builder implementation into clients.
|
||||
return builder.build {}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.intellij.ide.impl.OpenProjectTask
|
||||
import com.intellij.ide.impl.ProjectUtil
|
||||
import com.intellij.ide.impl.ProjectUtil.isSameProject
|
||||
import com.intellij.ide.impl.ProjectUtilService
|
||||
import com.intellij.ide.impl.effectiveImplOptions
|
||||
import com.intellij.ide.impl.withImplOptions
|
||||
import com.intellij.ide.lightEdit.LightEdit
|
||||
import com.intellij.idea.AppMode
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
@@ -461,13 +463,12 @@ open class RecentProjectsManagerBase(coroutineScope: CoroutineScope) :
|
||||
|
||||
open suspend fun openProject(projectFile: Path, options: OpenProjectTask): Project? {
|
||||
var effectiveOptions = options
|
||||
if (options.implOptions == null) {
|
||||
if (options.effectiveImplOptions == null) {
|
||||
getProjectMetaInfo(projectFile)?.let { info ->
|
||||
effectiveOptions = effectiveOptions.copy(
|
||||
projectWorkspaceId = info.projectWorkspaceId,
|
||||
projectFrameTypeId = info.projectFrameTypeId,
|
||||
implOptions = OpenProjectImplOptions(recentProjectMetaInfo = info, frameInfo = info.frame)
|
||||
)
|
||||
).withImplOptions(OpenProjectImplOptions(recentProjectMetaInfo = info, frameInfo = info.frame))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1195,13 +1196,13 @@ data class OpenProjectImplOptions(
|
||||
)
|
||||
|
||||
val OpenProjectTask.frame: IdeFrameImpl?
|
||||
@Internal get() = (implOptions as OpenProjectImplOptions?)?.frame
|
||||
@Internal get() = (effectiveImplOptions as OpenProjectImplOptions?)?.frame
|
||||
|
||||
val OpenProjectTask.frameInfo: FrameInfo?
|
||||
@Internal get() = (implOptions as OpenProjectImplOptions?)?.frameInfo
|
||||
@Internal get() = (effectiveImplOptions as OpenProjectImplOptions?)?.frameInfo
|
||||
|
||||
val OpenProjectTask.recentProjectMetaInfo: RecentProjectMetaInfo?
|
||||
@Internal get() = (implOptions as OpenProjectImplOptions?)?.recentProjectMetaInfo
|
||||
@Internal get() = (effectiveImplOptions as OpenProjectImplOptions?)?.recentProjectMetaInfo
|
||||
|
||||
@Internal
|
||||
interface SystemDock {
|
||||
|
||||
@@ -122,13 +122,14 @@ class PlatformProjectOpenProcessor : ProjectOpenProcessor(), CommandLineProjectO
|
||||
projectName = dummyProjectName,
|
||||
runConfigurators = false,
|
||||
runConversionBeforeOpen = false,
|
||||
// both callers of this go on to `openFileFromCommandLine`, which is what releases the hold this asks for
|
||||
opensFileAfterProjectOpen = true,
|
||||
beforeOpen = { project ->
|
||||
project.service<OpenProjectSettingsService>().state.isLocatedInTempDirectory = true
|
||||
options.beforeOpen?.invoke(project) ?: true
|
||||
}
|
||||
)
|
||||
).let {
|
||||
// both callers of this go on to `openFileFromCommandLine`, which is what releases the hold this asks for
|
||||
it.markAsOpeningFileAfterProjectOpen()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTempProjectAndOpenFile(file: Path, options: OpenProjectTask): Project? {
|
||||
@@ -216,7 +217,7 @@ class PlatformProjectOpenProcessor : ProjectOpenProcessor(), CommandLineProjectO
|
||||
options
|
||||
}
|
||||
else {
|
||||
options.copy(projectName = file.fileName.toString(), opensFileAfterProjectOpen = true)
|
||||
options.copy(projectName = file.fileName.toString()).markAsOpeningFileAfterProjectOpen()
|
||||
}
|
||||
)
|
||||
if (project != null && file != baseDir) {
|
||||
@@ -290,7 +291,7 @@ class PlatformProjectOpenProcessor : ProjectOpenProcessor(), CommandLineProjectO
|
||||
options
|
||||
}
|
||||
else {
|
||||
options.copy(projectName = file.fileName.toString(), opensFileAfterProjectOpen = true)
|
||||
options.copy(projectName = file.fileName.toString()).markAsOpeningFileAfterProjectOpen()
|
||||
}
|
||||
)
|
||||
if (project != null && file != baseDir) {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.impl
|
||||
|
||||
import com.intellij.testFramework.assertions.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class OpenProjectTaskTest {
|
||||
@Test
|
||||
fun `implementation options preserve their payload and file marker`() {
|
||||
val originalImplOptions = Any()
|
||||
val replacementImplOptions = Any()
|
||||
val options = OpenProjectTask {
|
||||
implOptions = originalImplOptions
|
||||
opensFileAfterProjectOpen = true
|
||||
}
|
||||
|
||||
assertThat(options.implOptions).isNotSameAs(originalImplOptions)
|
||||
assertThat(options.effectiveImplOptions).isSameAs(originalImplOptions)
|
||||
assertThat(options.opensFileAfterProjectOpen).isTrue()
|
||||
|
||||
val copiedOptions = options.copy(projectName = "copied")
|
||||
assertThat(copiedOptions.effectiveImplOptions).isSameAs(originalImplOptions)
|
||||
assertThat(copiedOptions.opensFileAfterProjectOpen).isTrue()
|
||||
|
||||
val replacedOptions = copiedOptions.withImplOptions(replacementImplOptions)
|
||||
assertThat(replacedOptions.effectiveImplOptions).isSameAs(replacementImplOptions)
|
||||
assertThat(replacedOptions.opensFileAfterProjectOpen).isTrue()
|
||||
|
||||
val defaultOptions = OpenProjectTask()
|
||||
assertThat(defaultOptions.implOptions).isNotNull()
|
||||
assertThat(defaultOptions.effectiveImplOptions).isNull()
|
||||
assertThat(defaultOptions.opensFileAfterProjectOpen).isFalse()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user