diff --git a/plugins/devkit/devkit-core/BUILD.bazel b/plugins/devkit/devkit-core/BUILD.bazel
index 5bca9b6a0b06..6299560fdd56 100644
--- a/plugins/devkit/devkit-core/BUILD.bazel
+++ b/plugins/devkit/devkit-core/BUILD.bazel
@@ -123,6 +123,7 @@ jvm_library(
"//libraries/jackson/jackson",
"//libraries/jackson/databind",
"//libraries/kotlinx/collections-immutable:libraries-kotlinx-collections-immutable",
+ "//platform/workspace/jps",
],
)
@@ -231,6 +232,7 @@ jvm_library(
"//libraries/jackson/jackson:jackson_test_lib",
"//libraries/jackson/databind:databind_test_lib",
"//libraries/kotlinx/collections-immutable:libraries-kotlinx-collections-immutable_test_lib",
+ "//platform/workspace/jps:jps_test_lib",
],
)
### auto-generated section `build intellij.devkit.core` end
diff --git a/plugins/devkit/devkit-core/intellij.devkit.core.iml b/plugins/devkit/devkit-core/intellij.devkit.core.iml
index 28848725a3ce..40b2220cbccf 100644
--- a/plugins/devkit/devkit-core/intellij.devkit.core.iml
+++ b/plugins/devkit/devkit-core/intellij.devkit.core.iml
@@ -123,5 +123,6 @@
+
\ No newline at end of file
diff --git a/plugins/devkit/devkit-core/resources/inlayProviders/devkit.plugin.descriptor.split.mode.kind/preview.xml b/plugins/devkit/devkit-core/resources/inlayProviders/devkit.plugin.descriptor.split.mode.kind/preview.xml
new file mode 100644
index 000000000000..689f14978d56
--- /dev/null
+++ b/plugins/devkit/devkit-core/resources/inlayProviders/devkit.plugin.descriptor.split.mode.kind/preview.xml
@@ -0,0 +1,11 @@
+
+
+
+
+ com.example.backend.plugin
+ JetBrains
+
+
+
+
+
diff --git a/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml b/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml
index 2d5c22baee3a..882a742484bf 100644
--- a/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml
+++ b/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml
@@ -159,15 +159,17 @@
+ description="Enables deferred accurate split-mode icon resolution for DevKit descriptor and directory icons."/>
+
+
diff --git a/plugins/devkit/devkit-core/resources/messages/DevKitBundle.properties b/plugins/devkit/devkit-core/resources/messages/DevKitBundle.properties
index c104133b02b3..c6124de30335 100644
--- a/plugins/devkit/devkit-core/resources/messages/DevKitBundle.properties
+++ b/plugins/devkit/devkit-core/resources/messages/DevKitBundle.properties
@@ -753,6 +753,17 @@ inspections.meta.information.json.schema.display.name=IntelliJ Inspections Metai
inlay.threading.name=IJ Platform threading
# suppress inspection "GrazieInspection"
inlay.threading.description=IntelliJ Platform threading and read/write lock related annotations, e.g., @RequiresEdt, @RequiresReadLock.
Experimental, enabled in IDEA project only.
+inlay.split.mode.module.kind.name=Plugin descriptor split-mode kind
+inlay.split.mode.module.kind.description=Shows whether a plugin descriptor is a frontend, backend, shared, or monolith plugin/content module/XML descriptor.
+inlay.split.mode.module.kind.presentation={0} {1}
+inlay.split.mode.module.kind.tooltip=Split mode compatibility: {0} can be installed into {1}. Reason: {2}
+inlay.split.mode.module.kind.compatibility.frontend=frontend IDE
+inlay.split.mode.module.kind.compatibility.backend=backend IDE
+inlay.split.mode.module.kind.compatibility.shared=both frontend and backend IDE
+inlay.split.mode.module.kind.compatibility.monolith=monolith IDE
+inlay.split.mode.module.kind.content.module=content module
+inlay.split.mode.module.kind.plugin=plugin
+inlay.split.mode.module.kind.xml.descriptor=XML descriptor
inspections.static.initialization.in.extensions.name=Static initialization in extension point implementations
inspections.static.initialization.in.extensions.message=Extension point implementations must not use static initialization
@@ -836,8 +847,8 @@ inspection.message.return.value.without.path.annotation.where.expected=Return va
inspection.remote.dev.missing.runtime.dependency.name=Missing frontend or backend runtime dependency
inspection.remote.dev.missing.runtime.dependency.message=The name of the current module ''{0}'' ends with ''{1}'', but the dependency on ''{2}'' is missing
inspection.remote.dev.missing.runtime.dependency.fix.add=Add the ''{0}'' dependency
-inspection.remote.dev.add.to.split.mode.exclusions.fix.name=Add this violation to the exclusions list
-inspection.remote.dev.add.to.split.mode.exclusions.command.name=Add This Violation to the Exclusions List
+inspection.remote.dev.increase.split.mode.baseline.fix.name=Bypass incremental Split Mode safe-push tests
+inspection.remote.dev.increase.split.mode.baseline.command.name=Increase Split Mode Compatibility Baseline Version
inspection.split.mode.mixed.dependencies.display.name=Split mode compatibility inspection
inspection.split.mode.implicit.module.kind.display.name=Implicit split mode module kind inspection
inspection.remote.dev.mixed.dependencies.message=This module effectively depends on frontend-only and backend-only modules simultaneously. It will not get loaded in Split Mode.
diff --git a/plugins/devkit/devkit-core/resources/remotedevInspectionData/ApiRestrictions.json b/plugins/devkit/devkit-core/resources/remotedevInspectionData/ApiRestrictions.json5
similarity index 59%
rename from plugins/devkit/devkit-core/resources/remotedevInspectionData/ApiRestrictions.json
rename to plugins/devkit/devkit-core/resources/remotedevInspectionData/ApiRestrictions.json5
index 35c684b23be9..63be7ca29d9f 100644
--- a/plugins/devkit/devkit-core/resources/remotedevInspectionData/ApiRestrictions.json
+++ b/plugins/devkit/devkit-core/resources/remotedevInspectionData/ApiRestrictions.json5
@@ -1,317 +1,342 @@
+// Split-mode API restrictions consumed by DevKit inspections.
+// JSON5 comments, single-quoted strings, unquoted field names, and trailing commas are supported.
+//
+// Entry structure:
+// {
+// "apiName": "fully.qualified.ApiName", // Required, unique API identifier used by code inspections.
+// "extensionPointNames": ["com.intellij.extensionPoint"], // Optional. XML extension point names mapped to this API restriction.
+// "targetModules": ["frontend", "backend", "shared"], // Required, non-empty. Allowed values: "frontend", "backend", "shared", "monolith".
+// "restrictionKind": "genericPlatformApi", // Required. Allowed values: "genericPlatformApi", "ui".
+// "hint": "Extra guidance shown by the inspection" // Optional. Added to the text user/agent sees when an error is reported by inspections
+// }
+//
+// APIs with "restrictionKind": "ui" are forbidden in modules with the backendWithNonUiApiPermit policy, others are allowed. These modules are rider and clion specific backend modules
[
- {"apiName": "com.intellij.openapi.wm.ToolWindowFactory", "extensionPointNames": ["com.intellij.toolWindow"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.wm.ToolWindow", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.editor.toolbar.floating.FloatingToolbarProvider", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.ui.DialogWrapper", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.ui.popup.JBPopupFactory", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.fileEditor.FileEditorManagerListener", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.fileEditor.FileEditorProvider", "extensionPointNames": ["com.intellij.fileEditorProvider"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.editor.event.DocumentListener", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.editor.NonWriteAccessTypedHandler", "extensionPointNames": ["com.intellij.nonWriteAccessTypedHandler"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.fileEditor.FileEditorManager.getFocusedEditor", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.execution.services.ServiceViewContributor", "extensionPointNames": ["com.intellij.serviceViewContributor"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.ui.tree.AsyncTreeModel", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.ui.jcef.JBCefClient", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.notification.NotificationGroup", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.jetbrains.rdclient.daemon.FrontendHighlighterSuppressionHandler", "extensionPointNames": ["com.intellij.rdclient.highlighterSuppressionHandler"], "targetModules": ["frontend"]},
- {"apiName": "com.jetbrains.rdclient.actions.base.BackendDelegatingActionCustomization", "extensionPointNames": ["com.intellij.rdclient.actionCustomization"], "targetModules": ["frontend"]},
- {"apiName": "com.jetbrains.rdclient.editorActions.cwm.FrontendEditorActionHandlerStrategyCustomizer", "extensionPointNames": ["com.intellij.rdclient.editorActionHandlerStrategyCustomizer"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.wm.StatusBarWidgetFactory", "extensionPointNames": ["com.intellij.statusBarWidgetFactory"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.application.options.editor.EditorOptionsPageCustomizer", "extensionPointNames": ["com.intellij.generalEditorOptionsCustomizer"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.codeInsight.folding.CollapseBlockHandler", "extensionPointNames": ["com.intellij.codeInsight.folding.collapseBlockHandler"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.editor.LineWrapPositionStrategy", "extensionPointNames": ["com.intellij.lang.lineWrapStrategy"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.editor.actionSystem.EditorActionHandler", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.editor.event.CaretListener", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.editor.event.EditorMouseMotionListener", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.editor.event.EditorMouseListener", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.editor.event.SelectionListener", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.editor.event.VisibleAreaListener", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.editor.ex.FoldingListener", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.ui.popup.JBPopupListener", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.actionSystem.CommonDataKeys.EDITOR", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.actionSystem.PlatformDataKeys.TOOL_WINDOW", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.actionSystem.PlatformCoreDataKeys.SELECTED_ITEM", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.actionSystem.PlatformCoreDataKeys.SELECTED_ITEMS", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.actionSystem.PlatformCoreDataKeys.CONTEXT_COMPONENT", "extensionPointNames": [], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.codeInsight.lookup.impl.LookupDisplayStrategy", "extensionPointNames": ["com.intellij.lookup.displayStrategy"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.codeInsight.lookup.LookupBottomPanelProvider", "extensionPointNames": ["com.intellij.lookup.bottomPanelProvider"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.codeInsight.lookup.LookupBottomPanelAdvertiserCustomizer", "extensionPointNames": ["com.intellij.lookup.bottomPanelAdvertiserCustomizer"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.codeInsight.lookup.LookupMayHaveCustomPreviewProvider", "extensionPointNames": ["com.intellij.lookup.may.have.custom.preview.provider"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.codeInsight.completion.TemplateParameterTraversalPolicy", "extensionPointNames": ["com.intellij.templateParameterTraversalPolicy"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.options.UnnamedConfigurable", "extensionPointNames": ["com.intellij.codeCompletionConfigurable", "com.intellij.generalEditorOptionsExtension", "com.intellij.inlineCompletionConfigurable", "com.intellij.mlCodeCompletionConfigurable"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.profile.codeInspection.ui.ErrorOptionsProvider", "extensionPointNames": ["com.intellij.errorOptionsProvider"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.application.options.editor.CodeFoldingOptionsProvider", "extensionPointNames": ["com.intellij.codeFoldingOptionsProvider"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.application.options.editor.AutoImportOptionsProvider", "extensionPointNames": ["com.intellij.autoImportOptionsProvider"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.application.options.editor.EditorOptionsProvider", "extensionPointNames": ["com.intellij.editorOptionsProvider"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.application.options.editor.InlineDocsAdditionalConfigurable", "extensionPointNames": ["com.intellij.editorAppearanceInlineDocHandler"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.openapi.roots.ui.configuration.LibrarySettingsProvider", "extensionPointNames": ["com.intellij.librarySettingsProvider"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.profile.codeInspection.ui.InspectionProfileActionProvider", "extensionPointNames": ["com.intellij.inspectionProfileActionProvider"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.profile.codeInspection.ui.InspectionTreeAdvertiser", "extensionPointNames": ["com.intellij.inspectionTreeAdvertiser"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.analysis.problemsView.toolWindow.ProblemsViewPanelProvider", "extensionPointNames": ["com.intellij.problemsViewPanelProvider"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.analysis.problemsView.toolWindow.HighlightingProblemFactory", "extensionPointNames": ["com.intellij.problemsViewHighlightingProblemFactory"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.find.impl.livePreview.EditorSearchAreaProvider", "extensionPointNames": ["com.intellij.editorSearchAreaProvider"], "targetModules": ["frontend"]},
- {"apiName": "com.intellij.codeInsight.intention.impl.IntentionPopupProvider", "extensionPointNames": ["com.intellij.intentionPopupProvider"], "targetModules": ["frontend"]},
+ // frontend ui apis
+ {"apiName": "com.intellij.openapi.wm.ToolWindowFactory", "extensionPointNames": ["com.intellij.toolWindow"], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.wm.ToolWindow", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.editor.toolbar.floating.FloatingToolbarProvider", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.ui.DialogWrapper", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.ui.popup.JBPopupFactory", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.ui.tree.AsyncTreeModel", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.ui.jcef.JBCefClient", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.wm.StatusBarWidgetFactory", "extensionPointNames": ["com.intellij.statusBarWidgetFactory"], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.fileEditor.FileEditorManagerListener", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.fileEditor.FileEditorProvider", "extensionPointNames": ["com.intellij.fileEditorProvider"], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.fileEditor.FileEditorManager.getFocusedEditor", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.execution.services.ServiceViewContributor", "extensionPointNames": ["com.intellij.serviceViewContributor"], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.editor.event.CaretListener", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.editor.event.EditorMouseMotionListener", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.editor.event.EditorMouseListener", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.editor.event.SelectionListener", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.editor.event.VisibleAreaListener", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.ui.popup.JBPopupListener", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.editor.ex.FoldingListener", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.analysis.problemsView.toolWindow.ProblemsViewPanelProvider", "extensionPointNames": ["com.intellij.problemsViewPanelProvider"], "targetModules": ["frontend"], "restrictionKind": "ui"},
+ {"apiName": "com.intellij.openapi.options.Configurable", "extensionPointNames": ["com.intellij.applicationConfigurable", "com.intellij.projectConfigurable"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+
+
+ // frontend generic apis
+ {"apiName": "com.intellij.openapi.editor.event.DocumentListener", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.editor.NonWriteAccessTypedHandler", "extensionPointNames": ["com.intellij.nonWriteAccessTypedHandler"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.notification.NotificationGroup", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.jetbrains.rdclient.daemon.FrontendHighlighterSuppressionHandler", "extensionPointNames": ["com.intellij.rdclient.highlighterSuppressionHandler"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.jetbrains.rdclient.actions.base.BackendDelegatingActionCustomization", "extensionPointNames": ["com.intellij.rdclient.actionCustomization"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.jetbrains.rdclient.editorActions.cwm.FrontendEditorActionHandlerStrategyCustomizer", "extensionPointNames": ["com.intellij.rdclient.editorActionHandlerStrategyCustomizer"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.application.options.editor.EditorOptionsPageCustomizer", "extensionPointNames": ["com.intellij.generalEditorOptionsCustomizer"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.folding.CollapseBlockHandler", "extensionPointNames": ["com.intellij.codeInsight.folding.collapseBlockHandler"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.editor.actionSystem.EditorActionHandler", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.actionSystem.CommonDataKeys.EDITOR", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.actionSystem.PlatformDataKeys.TOOL_WINDOW", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.actionSystem.PlatformCoreDataKeys.SELECTED_ITEM", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.actionSystem.PlatformCoreDataKeys.SELECTED_ITEMS", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.actionSystem.PlatformCoreDataKeys.CONTEXT_COMPONENT", "extensionPointNames": [], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.lookup.impl.LookupDisplayStrategy", "extensionPointNames": ["com.intellij.lookup.displayStrategy"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.lookup.LookupBottomPanelProvider", "extensionPointNames": ["com.intellij.lookup.bottomPanelProvider"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.lookup.LookupBottomPanelAdvertiserCustomizer", "extensionPointNames": ["com.intellij.lookup.bottomPanelAdvertiserCustomizer"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.lookup.LookupMayHaveCustomPreviewProvider", "extensionPointNames": ["com.intellij.lookup.may.have.custom.preview.provider"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.completion.TemplateParameterTraversalPolicy", "extensionPointNames": ["com.intellij.templateParameterTraversalPolicy"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.options.UnnamedConfigurable", "extensionPointNames": ["com.intellij.codeCompletionConfigurable", "com.intellij.generalEditorOptionsExtension", "com.intellij.inlineCompletionConfigurable", "com.intellij.mlCodeCompletionConfigurable"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.profile.codeInspection.ui.ErrorOptionsProvider", "extensionPointNames": ["com.intellij.errorOptionsProvider"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.application.options.editor.CodeFoldingOptionsProvider", "extensionPointNames": ["com.intellij.codeFoldingOptionsProvider"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.application.options.editor.AutoImportOptionsProvider", "extensionPointNames": ["com.intellij.autoImportOptionsProvider"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.application.options.editor.EditorOptionsProvider", "extensionPointNames": ["com.intellij.editorOptionsProvider"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.application.options.editor.InlineDocsAdditionalConfigurable", "extensionPointNames": ["com.intellij.editorAppearanceInlineDocHandler"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.roots.ui.configuration.LibrarySettingsProvider", "extensionPointNames": ["com.intellij.librarySettingsProvider"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.profile.codeInspection.ui.InspectionProfileActionProvider", "extensionPointNames": ["com.intellij.inspectionProfileActionProvider"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.profile.codeInspection.ui.InspectionTreeAdvertiser", "extensionPointNames": ["com.intellij.inspectionTreeAdvertiser"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.analysis.problemsView.toolWindow.HighlightingProblemFactory", "extensionPointNames": ["com.intellij.problemsViewHighlightingProblemFactory"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.find.impl.livePreview.EditorSearchAreaProvider", "extensionPointNames": ["com.intellij.editorSearchAreaProvider"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.intention.impl.IntentionPopupProvider", "extensionPointNames": ["com.intellij.intentionPopupProvider"], "targetModules": ["frontend"], "restrictionKind": "genericPlatformApi"},
- {"apiName": "com.intellij.openapi.vfs.VirtualFileManager", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.vfs.VfsUtil", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.psi.stubs.StubIndex", "extensionPointNames": ["com.intellij.stubIndex"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.psi.stubs.StubIndexExtension", "extensionPointNames": ["com.intellij.stubIndex"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.util.indexing.IndexExtension", "extensionPointNames": ["com.intellij.fileBasedIndex"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.util.indexing.FileBasedIndexExtension", "extensionPointNames": ["com.intellij.fileBasedIndex"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.configurations.ConfigurationType", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.psi.search.searches.ReferencesSearch", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.model.search.SearchService", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.util.Query", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.hints.InlayHintsProvider", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.hints.declarative.InlayHintsProvider", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.daemon.LineMarkerProvider", "extensionPointNames": ["com.intellij.codeInsight.lineMarkerProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInspection.LocalInspectionTool", "extensionPointNames": ["com.intellij.localInspection"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInspection.incorrectFormatting.IncorrectFormattingResultHandlerProvider", "extensionPointNames": ["com.intellij.resultHandlerProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.psi.PsiReferenceContributor", "extensionPointNames": ["com.intellij.psi.referenceContributor"], "targetModules": ["backend"]},
- {"apiName": "com.jetbrains.jsonSchema.extension.JsonSchemaProviderFactory", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.actions.RunConfigurationProducer", "extensionPointNames": ["com.intellij.runConfigurationProducer"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.structureView.StructureViewBuilder", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.vfs.AsyncFileListener", "extensionPointNames": ["com.intellij.vfs.asyncListener", "com.intellij.vfs.asyncListenerBackgroundable"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.psi.ResolveScopeProvider", "extensionPointNames": ["com.intellij.resolveScopeProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.vfs.VirtualFileListener", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.platform.backend.workspace.WorkspaceModelChangeListener", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.project.ProjectManagerListener", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.process.ProcessHandler", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.actionSystem.CommonDataKeys.SYMBOLS", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.actionSystem.PlatformCoreDataKeys.MODULE", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.actionSystem.LangDataKeys.MODULE_CONTEXT", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.actionSystem.LangDataKeys.MODIFIABLE_MODULE_MODEL", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.completion.CompletionPreselectionBehaviourProvider", "extensionPointNames": ["com.intellij.completion.preselectionBehaviourProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.completion.ml.ContextFeatureProvider", "extensionPointNames": ["com.intellij.completion.ml.contextFeatures"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.internal.ml.completion.RankingModelProvider", "extensionPointNames": ["com.intellij.completion.ml.model"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.completion.ml.ElementFeatureProvider", "extensionPointNames": ["com.intellij.completion.ml.elementFeatures"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.completion.PlainTextSymbolCompletionContributor", "extensionPointNames": ["com.intellij.completion.plainTextSymbol"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.lang.WordCompletionElementFilter", "extensionPointNames": ["com.intellij.codeInsight.wordCompletionFilter"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.completion.ml.MLFeatureProvider", "extensionPointNames": ["com.intellij.internal.ml.featureProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.modcompletion.ModCompletionItemProvider", "extensionPointNames": ["com.intellij.modcompletion.completionItemProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.modcompletion.ModCompletionItemFilter", "extensionPointNames": ["com.intellij.modcompletion.completionItemFilter"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.completion.command.CommandCompletionFactory", "extensionPointNames": ["com.intellij.codeInsight.completion.command.factory"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.completion.command.CommandProvider", "extensionPointNames": ["com.intellij.codeInsight.completion.command.provider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.completion.command.commands.IntentionCommandSkipper", "extensionPointNames": ["com.intellij.codeInsight.completion.intention.skipper"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.completion.command.commands.ErrorFixCommandProvider", "extensionPointNames": ["com.intellij.codeInsight.completion.error.intention"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.completion.command.commands.IntentionCommandOffsetProvider", "extensionPointNames": ["com.intellij.codeInsight.completion.intention.offset.provider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.lang.refactoring.RefactoringSupportProvider", "extensionPointNames": ["com.intellij.lang.refactoringSupport"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.lang.refactoring.NamesValidator", "extensionPointNames": ["com.intellij.lang.namesValidator"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.rename.RenameHandler", "extensionPointNames": ["com.intellij.renameHandler"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.rename.RenamePsiElementProcessorBase", "extensionPointNames": ["com.intellij.renamePsiElementProcessor"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.psi.impl.file.UpdateAddedFileProcessor", "extensionPointNames": ["com.intellij.updateAddedFileProcessor"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.rename.naming.AutomaticRenamerFactory", "extensionPointNames": ["com.intellij.automaticRenamerFactory"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.rename.NameSuggestionProvider", "extensionPointNames": ["com.intellij.nameSuggestionProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.rename.RenamerFactory", "extensionPointNames": ["com.intellij.renamerFactory"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.RefactoringHelper", "extensionPointNames": ["com.intellij.refactoring.helper"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.lang.refactoring.InlineActionHandler", "extensionPointNames": ["com.intellij.inlineActionHandler"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.lang.refactoring.InlineHandler", "extensionPointNames": ["com.intellij.refactoring.inlineHandler"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.rename.ResolveSnapshotProvider", "extensionPointNames": ["com.intellij.rename.inplace.resolveSnapshotProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.rename.RenameInputValidator", "extensionPointNames": ["com.intellij.renameInputValidator"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.listeners.RefactoringElementListenerProvider", "extensionPointNames": ["com.intellij.refactoring.elementListenerProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.find.FindInProjectSearchEngine", "extensionPointNames": ["com.intellij.findInProjectSearchEngine"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.QualifiedNameProvider", "extensionPointNames": ["com.intellij.qualifiedNameProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.VirtualFileQualifiedNameProvider", "extensionPointNames": ["com.intellij.virtualFileQualifiedNameProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.roots.TestSourcesFilter", "extensionPointNames": ["com.intellij.testSourcesFilter"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.classMembers.ClassMembersRefactoringSupport", "extensionPointNames": ["com.intellij.lang.refactoringSupport.classMembersRefactoringSupport"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.copy.CopyHandlerDelegate", "extensionPointNames": ["com.intellij.refactoring.copyHandler"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.move.MoveHandlerDelegate", "extensionPointNames": ["com.intellij.refactoring.moveHandler"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.introduceParameterObject.IntroduceParameterObjectDelegate", "extensionPointNames": ["com.intellij.refactoring.introduceParameterObject"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.memberPushDown.PushDownDelegate", "extensionPointNames": ["com.intellij.refactoring.pushDown"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.move.moveClassesOrPackages.MoveDirectoryWithClassesHelper", "extensionPointNames": ["com.intellij.refactoring.moveDirectoryWithClassesHelper"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.safeDelete.SafeDeleteProcessorDelegate", "extensionPointNames": ["com.intellij.refactoring.safeDeleteProcessor"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.RefactoringActionHandler", "extensionPointNames": ["com.intellij.refactoring.extractIncludeHandler"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.changeSignature.ChangeSignatureUsageProcessor", "extensionPointNames": ["com.intellij.refactoring.changeSignatureUsageProcessor"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.move.moveFilesOrDirectories.MoveFileHandler", "extensionPointNames": ["com.intellij.moveFileHandler"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.rename.symbol.SymbolRenameTargetFactory", "extensionPointNames": ["com.intellij.rename.symbolRenameTargetFactory"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.actions.RenameFileActionProvider", "extensionPointNames": ["com.intellij.renameFileActionProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.changeSignature.inplace.LanguageChangeSignatureDetector", "extensionPointNames": ["com.intellij.changeSignatureDetector"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.suggested.SuggestedRefactoringSupport", "extensionPointNames": ["com.intellij.suggestedRefactoringSupport"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.changeSignature.ChangeSignatureUsageProvider", "extensionPointNames": ["com.intellij.changeSignature.usageProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeHighlighting.TextEditorHighlightingPassFactoryRegistrar", "extensionPointNames": ["com.intellij.highlightingPassFactory"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.RunConfigurationProducerSuppressor", "extensionPointNames": ["com.intellij.runConfigurationProducerSuppressor"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.psi.search.IndexPatternProvider", "extensionPointNames": ["com.intellij.indexPatternProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInspection.reference.RefGraphAnnotator", "extensionPointNames": ["com.intellij.refGraphAnnotator"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.daemon.impl.HighlightVisitor", "extensionPointNames": ["com.intellij.highlightVisitor"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.daemon.impl.analysis.ErrorQuickFixProvider", "extensionPointNames": ["com.intellij.errorQuickFixProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.paths.PathReferenceProvider", "extensionPointNames": ["com.intellij.pathReferenceProvider", "com.intellij.anchorReferenceProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.paths.DynamicContextProvider", "extensionPointNames": ["com.intellij.dynamicContextProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider", "extensionPointNames": ["com.intellij.codeInsight.unresolvedReferenceQuickFixProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.lang.ExternalAnnotatorsFilter", "extensionPointNames": ["com.intellij.daemon.externalAnnotatorsFilter"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.daemon.ChangeLocalityDetector", "extensionPointNames": ["com.intellij.daemon.changeLocalityDetector"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.daemon.ImplicitUsageProvider", "extensionPointNames": ["com.intellij.implicitUsageProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.lang.injection.ConcatenationAwareInjector", "extensionPointNames": ["com.intellij.concatenationAwareInjector"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.psi.injection.ReferenceInjector", "extensionPointNames": ["com.intellij.referenceInjector"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.lang.annotation.ExternalAnnotator", "extensionPointNames": ["com.intellij.externalAnnotator"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.lang.findUsages.FindUsagesProvider", "extensionPointNames": ["com.intellij.lang.findUsagesProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.lang.cacheBuilder.WordsScanner", "extensionPointNames": ["com.intellij.cacheBuilder"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.model.search.Searcher", "extensionPointNames": ["com.intellij.searcher"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.psi.search.SearchScopeProvider", "extensionPointNames": ["com.intellij.searchScopesProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.util.gotoByName.GotoActionAliasMatcher", "extensionPointNames": ["com.intellij.gotoActionAliasMatcher"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.navigation.ChooseByNameContributor", "extensionPointNames": ["com.intellij.gotoClassContributor", "com.intellij.gotoSymbolContributor", "com.intellij.gotoFileContributor"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.navigation.GotoRelatedProvider", "extensionPointNames": ["com.intellij.gotoRelatedProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.navigation.AnonymousElementProvider", "extensionPointNames": ["com.intellij.anonymousElementProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributorFactory", "extensionPointNames": ["com.intellij.searchEverywhereContributor"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.searcheverywhere.SEResultsEqualityProvider", "extensionPointNames": ["com.intellij.searchEverywhereResultsEqualityProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.searcheverywhere.SearchEverywhereMlService", "extensionPointNames": ["com.intellij.searchEverywhereMlService"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.searcheverywhere.SearchEverywhereMlContributorReplacement", "extensionPointNames": ["com.intellij.searchEverywhereMlContributorReplacement"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.searcheverywhere.SearchEverywhereSpellingCorrectorFactory", "extensionPointNames": ["com.intellij.searchEverywhereSpellingCorrector"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.searcheverywhere.SearchEverywhereEssentialContributorMarker", "extensionPointNames": ["com.intellij.searchEverywhereEssentialContributorsMarker"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.searcheverywhere.remote.RemoteSearchEverywhereConverterSupplier", "extensionPointNames": ["com.intellij.searchEverywhereRemoteConverter"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.searcheverywhere.SearchEverywhereReorderingService", "extensionPointNames": ["com.intellij.searchEverywhereReorderingService"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.searcheverywhere.SearchEverywherePreviewPrimaryUsageFinder", "extensionPointNames": ["com.intellij.searchEverywherePreviewPrimaryUsageFinder"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.SearchEverywhereManagerFactory", "extensionPointNames": ["com.intellij.searchEverywhere.manager"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.runAnything.activity.RunAnythingProvider", "extensionPointNames": ["com.intellij.runAnything.executionProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.runAnything.handlers.RunAnythingCommandHandler", "extensionPointNames": ["com.intellij.runAnything.commandHandler"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.runAnything.groups.RunAnythingHelpGroup", "extensionPointNames": ["com.intellij.runAnything.helpGroup"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.runAnything.commands.RunAnythingCommandCustomizer", "extensionPointNames": ["com.intellij.runAnything.commandCustomizer"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.highlighting.HighlightUsagesHandlerFactory", "extensionPointNames": ["com.intellij.highlightUsagesHandlerFactory"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.usages.UsageTargetProvider", "extensionPointNames": ["com.intellij.usageTargetProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.usages.UsageToPsiElementProvider", "extensionPointNames": ["com.intellij.usageToPsiElementProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.find.impl.FindInProjectExtension", "extensionPointNames": ["com.intellij.findInProjectExtension"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.model.psi.PsiSymbolDeclarationProvider", "extensionPointNames": ["com.intellij.psi.declarationProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.navigation.actions.TypeDeclarationProvider", "extensionPointNames": ["com.intellij.typeDeclarationProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.navigation.GotoTargetRendererProvider", "extensionPointNames": ["com.intellij.gotoTargetRendererProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.navigation.GotoTargetPresentationProvider", "extensionPointNames": ["com.intellij.gotoTargetPresentationProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.find.usages.symbol.SymbolSearchTargetFactory", "extensionPointNames": ["com.intellij.lang.symbolSearchTarget"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.find.findUsages.FindUsagesHandlerFactory", "extensionPointNames": ["com.intellij.findUsagesHandlerFactory"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.find.findUsages.CustomUsageSearcher", "extensionPointNames": ["com.intellij.customUsageSearcher"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.platform.ide.navigation.NavigationHandler", "extensionPointNames": ["com.intellij.navigation.navigationHandler"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.impl.RunConfigurationTemplateProvider", "extensionPointNames": ["com.intellij.runConfigurationTemplateProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.configurations.RunConfigurationsSettings", "extensionPointNames": ["com.intellij.runConfigurationsSettings"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.runners.ProgramRunner", "extensionPointNames": ["com.intellij.programRunner"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.task.ProjectTaskRunner", "extensionPointNames": ["com.intellij.projectTaskRunner"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.Executor", "extensionPointNames": ["com.intellij.executor"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.runToolbar.RunToolbarProcess", "extensionPointNames": ["com.intellij.runToolbarProcess"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.ExecutionTargetProvider", "extensionPointNames": ["com.intellij.executionTargetProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.BeforeRunTaskProvider", "extensionPointNames": ["com.intellij.stepsBeforeRunProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.impl.RunConfigurationBeforeRunProviderDelegate", "extensionPointNames": ["com.intellij.runConfigurationBeforeRunProviderDelegate"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.target.RunConfigurationTargetEnvironmentAdjuster$Factory", "extensionPointNames": ["com.intellij.runConfigurationTargetEnvironmentAdjusterFactory"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.target.TargetEnvironmentType", "extensionPointNames": ["com.intellij.executionTargetType"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.target.LanguageRuntimeType", "extensionPointNames": ["com.intellij.executionTargetLanguageRuntimeType"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.filters.ConsoleFilterProvider", "extensionPointNames": ["com.intellij.consoleFilterProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.filters.ConsoleInputFilterProvider", "extensionPointNames": ["com.intellij.consoleInputFilterProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.actions.ConsoleActionsPostProcessor", "extensionPointNames": ["com.intellij.consoleActionsPostProcessor"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.junit.RuntimeConfigurationProducer", "extensionPointNames": ["com.intellij.configurationProducer"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.lineMarker.RunLineMarkerContributor", "extensionPointNames": ["com.intellij.runLineMarkerContributor"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.actions.MultipleRunLocationsProvider", "extensionPointNames": ["com.intellij.multipleRunLocationsProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.dashboard.RunDashboardCustomizer", "extensionPointNames": ["com.intellij.runDashboardCustomizer"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.dashboard.LegacyRunDashboardServiceSubstitutor", "extensionPointNames": ["com.intellij.legacyRunDashboardServiceSubstitutor"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.dashboard.RunDashboardDefaultTypesProvider", "extensionPointNames": ["com.intellij.runDashboardDefaultTypesProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.navigation.MethodNavigationOffsetProvider", "extensionPointNames": ["com.intellij.methodNavigationOffsetProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.testIntegration.TestFinder", "extensionPointNames": ["com.intellij.testFinder"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.testIntegration.TestLocationProvider", "extensionPointNames": ["com.intellij.testSrcLocator"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.testIntegration.TestCreator", "extensionPointNames": ["com.intellij.testCreator"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.hierarchy.HierarchyProvider", "extensionPointNames": ["com.intellij.callHierarchyProvider", "com.intellij.methodHierarchyProvider", "com.intellij.typeHierarchyProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.TargetElementUtilExtender", "extensionPointNames": ["com.intellij.targetElementUtilExtender"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.TargetElementEvaluator", "extensionPointNames": ["com.intellij.targetElementEvaluator"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.psi.impl.cache.impl.id.IdIndexer", "extensionPointNames": ["com.intellij.idIndexer"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.daemon.ProblemHighlightFilter", "extensionPointNames": ["com.intellij.problemHighlightFilter"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.filters.Filter", "extensionPointNames": ["com.intellij.analyzeStacktraceFilter"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.unscramble.StacktraceTabContentProvider", "extensionPointNames": ["com.intellij.analyzeStacktraceRunContentProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.actions.SearchEverywhereClassifier", "extensionPointNames": ["com.intellij.searchEverywhereClassifier"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.util.gotoByName.GotoFileCustomizer", "extensionPointNames": ["com.intellij.gotoFileCustomizer"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.util.fuzzyMatching.GotoFileFuzzyMatcherFactory", "extensionPointNames": ["com.intellij.gotoFileFuzzyMatcherFactory"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.slicer.SliceLanguageSupportProvider", "extensionPointNames": ["com.intellij.lang.sliceProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.console.ConsoleHistoryModelProvider", "extensionPointNames": ["com.intellij.consoleHistoryModelProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.execution.update.RunningApplicationUpdaterProvider", "extensionPointNames": ["com.intellij.runningApplicationUpdaterProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.hint.ImplementationViewSessionFactory", "extensionPointNames": ["com.intellij.implementationViewSessionFactory"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.hint.ImplementationViewDocumentFactory", "extensionPointNames": ["com.intellij.implementationViewDocumentFactory"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.platform.backend.documentation.DocumentationTargetProvider", "extensionPointNames": ["com.intellij.platform.backend.documentation.targetProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.platform.backend.documentation.SymbolDocumentationTargetProvider", "extensionPointNames": ["com.intellij.platform.backend.documentation.symbolTargetProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.platform.backend.documentation.PsiDocumentationTargetProvider", "extensionPointNames": ["com.intellij.platform.backend.documentation.psiTargetProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.platform.backend.documentation.LookupElementDocumentationTargetProvider", "extensionPointNames": ["com.intellij.platform.backend.documentation.lookupElementTargetProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.platform.backend.documentation.InlineDocumentationProvider", "extensionPointNames": ["com.intellij.platform.backend.documentation.inlineDocumentationProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.platform.backend.documentation.DocumentationLinkHandler", "extensionPointNames": ["com.intellij.platform.backend.documentation.linkHandler"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.refactoring.safeDelete.api.SafeDeleteTargetProvider", "extensionPointNames": ["com.intellij.safeDeleteTargetProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.navigation.DirectNavigationProvider", "extensionPointNames": ["com.intellij.lang.directNavigationProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.codeInsight.navigation.SymbolTypeProvider", "extensionPointNames": ["com.intellij.lang.symbolTypeProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.application.ApplicationListener", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.project.ProjectListener", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.project.ProjectCloseListener", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.openapi.project.VetoableProjectManagerListener", "extensionPointNames": [], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.projectView.TreeStructureProvider", "extensionPointNames": ["com.intellij.treeStructureProvider"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.projectView.impl.AbstractProjectViewPane", "extensionPointNames": ["com.intellij.projectViewPane"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.projectView.impl.ProjectViewPaneSelectionHelper", "extensionPointNames": ["com.intellij.projectViewPaneSelectionHelper"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.projectView.ProjectViewNodeDecorator", "extensionPointNames": ["com.intellij.projectViewNodeDecorator"], "targetModules": ["backend"]},
- {"apiName": "com.intellij.ide.projectView.ProjectViewNestingRulesProvider", "extensionPointNames": ["com.intellij.projectViewNestingRulesProvider"], "targetModules": ["backend"]},
+ // backend generic apis
+ {"apiName": "com.intellij.openapi.vfs.VirtualFileManager", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.vfs.VfsUtil", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.roots.FileIndex", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.roots.ModuleFileIndex", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.roots.ProjectFileIndex", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.stubs.StubIndex", "extensionPointNames": ["com.intellij.stubIndex"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.stubs.StubIndexExtension", "extensionPointNames": ["com.intellij.stubIndex"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.util.indexing.IndexExtension", "extensionPointNames": ["com.intellij.fileBasedIndex"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.util.indexing.FileBasedIndexExtension", "extensionPointNames": ["com.intellij.fileBasedIndex"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.configurations.ConfigurationType", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.search.searches.ReferencesSearch", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.model.search.SearchService", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.util.Query", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.hints.InlayHintsProvider", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.hints.declarative.InlayHintsProvider", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.daemon.LineMarkerProvider", "extensionPointNames": ["com.intellij.codeInsight.lineMarkerProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInspection.LocalInspectionTool", "extensionPointNames": ["com.intellij.localInspection"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInspection.incorrectFormatting.IncorrectFormattingResultHandlerProvider", "extensionPointNames": ["com.intellij.resultHandlerProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.PsiReferenceContributor", "extensionPointNames": ["com.intellij.psi.referenceContributor"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.jetbrains.jsonSchema.extension.JsonSchemaProviderFactory", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.actions.RunConfigurationProducer", "extensionPointNames": ["com.intellij.runConfigurationProducer"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.structureView.StructureViewBuilder", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.vfs.AsyncFileListener", "extensionPointNames": ["com.intellij.vfs.asyncListener", "com.intellij.vfs.asyncListenerBackgroundable"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.ResolveScopeProvider", "extensionPointNames": ["com.intellij.resolveScopeProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.vfs.VirtualFileListener", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.platform.backend.workspace.WorkspaceModelChangeListener", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.project.ProjectManagerListener", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.process.ProcessHandler", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.actionSystem.CommonDataKeys.SYMBOLS", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.actionSystem.PlatformCoreDataKeys.MODULE", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.actionSystem.LangDataKeys.MODULE_CONTEXT", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.actionSystem.LangDataKeys.MODIFIABLE_MODULE_MODEL", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.completion.CompletionPreselectionBehaviourProvider", "extensionPointNames": ["com.intellij.completion.preselectionBehaviourProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.completion.ml.ContextFeatureProvider", "extensionPointNames": ["com.intellij.completion.ml.contextFeatures"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.internal.ml.completion.RankingModelProvider", "extensionPointNames": ["com.intellij.completion.ml.model"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.completion.ml.ElementFeatureProvider", "extensionPointNames": ["com.intellij.completion.ml.elementFeatures"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.completion.PlainTextSymbolCompletionContributor", "extensionPointNames": ["com.intellij.completion.plainTextSymbol"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.WordCompletionElementFilter", "extensionPointNames": ["com.intellij.codeInsight.wordCompletionFilter"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.completion.ml.MLFeatureProvider", "extensionPointNames": ["com.intellij.internal.ml.featureProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.modcompletion.ModCompletionItemProvider", "extensionPointNames": ["com.intellij.modcompletion.completionItemProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.modcompletion.ModCompletionItemFilter", "extensionPointNames": ["com.intellij.modcompletion.completionItemFilter"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.completion.command.CommandCompletionFactory", "extensionPointNames": ["com.intellij.codeInsight.completion.command.factory"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.completion.command.CommandProvider", "extensionPointNames": ["com.intellij.codeInsight.completion.command.provider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.completion.command.commands.IntentionCommandSkipper", "extensionPointNames": ["com.intellij.codeInsight.completion.intention.skipper"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.completion.command.commands.ErrorFixCommandProvider", "extensionPointNames": ["com.intellij.codeInsight.completion.error.intention"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.completion.command.commands.IntentionCommandOffsetProvider", "extensionPointNames": ["com.intellij.codeInsight.completion.intention.offset.provider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.refactoring.RefactoringSupportProvider", "extensionPointNames": ["com.intellij.lang.refactoringSupport"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.refactoring.NamesValidator", "extensionPointNames": ["com.intellij.lang.namesValidator"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.rename.RenameHandler", "extensionPointNames": ["com.intellij.renameHandler"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.rename.RenamePsiElementProcessorBase", "extensionPointNames": ["com.intellij.renamePsiElementProcessor"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.impl.file.UpdateAddedFileProcessor", "extensionPointNames": ["com.intellij.updateAddedFileProcessor"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.rename.naming.AutomaticRenamerFactory", "extensionPointNames": ["com.intellij.automaticRenamerFactory"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.rename.NameSuggestionProvider", "extensionPointNames": ["com.intellij.nameSuggestionProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.rename.RenamerFactory", "extensionPointNames": ["com.intellij.renamerFactory"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.RefactoringHelper", "extensionPointNames": ["com.intellij.refactoring.helper"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.refactoring.InlineActionHandler", "extensionPointNames": ["com.intellij.inlineActionHandler"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.refactoring.InlineHandler", "extensionPointNames": ["com.intellij.refactoring.inlineHandler"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.rename.ResolveSnapshotProvider", "extensionPointNames": ["com.intellij.rename.inplace.resolveSnapshotProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.rename.RenameInputValidator", "extensionPointNames": ["com.intellij.renameInputValidator"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.listeners.RefactoringElementListenerProvider", "extensionPointNames": ["com.intellij.refactoring.elementListenerProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.find.FindInProjectSearchEngine", "extensionPointNames": ["com.intellij.findInProjectSearchEngine"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.QualifiedNameProvider", "extensionPointNames": ["com.intellij.qualifiedNameProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.VirtualFileQualifiedNameProvider", "extensionPointNames": ["com.intellij.virtualFileQualifiedNameProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.roots.TestSourcesFilter", "extensionPointNames": ["com.intellij.testSourcesFilter"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.classMembers.ClassMembersRefactoringSupport", "extensionPointNames": ["com.intellij.lang.refactoringSupport.classMembersRefactoringSupport"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.copy.CopyHandlerDelegate", "extensionPointNames": ["com.intellij.refactoring.copyHandler"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.move.MoveHandlerDelegate", "extensionPointNames": ["com.intellij.refactoring.moveHandler"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.introduceParameterObject.IntroduceParameterObjectDelegate", "extensionPointNames": ["com.intellij.refactoring.introduceParameterObject"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.memberPushDown.PushDownDelegate", "extensionPointNames": ["com.intellij.refactoring.pushDown"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.move.moveClassesOrPackages.MoveDirectoryWithClassesHelper", "extensionPointNames": ["com.intellij.refactoring.moveDirectoryWithClassesHelper"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.safeDelete.SafeDeleteProcessorDelegate", "extensionPointNames": ["com.intellij.refactoring.safeDeleteProcessor"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.RefactoringActionHandler", "extensionPointNames": ["com.intellij.refactoring.extractIncludeHandler"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.changeSignature.ChangeSignatureUsageProcessor", "extensionPointNames": ["com.intellij.refactoring.changeSignatureUsageProcessor"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.move.moveFilesOrDirectories.MoveFileHandler", "extensionPointNames": ["com.intellij.moveFileHandler"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.rename.symbol.SymbolRenameTargetFactory", "extensionPointNames": ["com.intellij.rename.symbolRenameTargetFactory"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.actions.RenameFileActionProvider", "extensionPointNames": ["com.intellij.renameFileActionProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.changeSignature.inplace.LanguageChangeSignatureDetector", "extensionPointNames": ["com.intellij.changeSignatureDetector"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.suggested.SuggestedRefactoringSupport", "extensionPointNames": ["com.intellij.suggestedRefactoringSupport"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.changeSignature.ChangeSignatureUsageProvider", "extensionPointNames": ["com.intellij.changeSignature.usageProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeHighlighting.TextEditorHighlightingPassFactoryRegistrar", "extensionPointNames": ["com.intellij.highlightingPassFactory"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.RunConfigurationProducerSuppressor", "extensionPointNames": ["com.intellij.runConfigurationProducerSuppressor"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.search.IndexPatternProvider", "extensionPointNames": ["com.intellij.indexPatternProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInspection.reference.RefGraphAnnotator", "extensionPointNames": ["com.intellij.refGraphAnnotator"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.daemon.impl.HighlightVisitor", "extensionPointNames": ["com.intellij.highlightVisitor"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.daemon.impl.analysis.ErrorQuickFixProvider", "extensionPointNames": ["com.intellij.errorQuickFixProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.paths.PathReferenceProvider", "extensionPointNames": ["com.intellij.pathReferenceProvider", "com.intellij.anchorReferenceProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.paths.DynamicContextProvider", "extensionPointNames": ["com.intellij.dynamicContextProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider", "extensionPointNames": ["com.intellij.codeInsight.unresolvedReferenceQuickFixProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.ExternalAnnotatorsFilter", "extensionPointNames": ["com.intellij.daemon.externalAnnotatorsFilter"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.daemon.ChangeLocalityDetector", "extensionPointNames": ["com.intellij.daemon.changeLocalityDetector"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.daemon.ImplicitUsageProvider", "extensionPointNames": ["com.intellij.implicitUsageProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.injection.ConcatenationAwareInjector", "extensionPointNames": ["com.intellij.concatenationAwareInjector"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.injection.ReferenceInjector", "extensionPointNames": ["com.intellij.referenceInjector"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.annotation.ExternalAnnotator", "extensionPointNames": ["com.intellij.externalAnnotator"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.findUsages.FindUsagesProvider", "extensionPointNames": ["com.intellij.lang.findUsagesProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.cacheBuilder.WordsScanner", "extensionPointNames": ["com.intellij.cacheBuilder"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.model.search.Searcher", "extensionPointNames": ["com.intellij.searcher"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.search.SearchScopeProvider", "extensionPointNames": ["com.intellij.searchScopesProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.util.gotoByName.GotoActionAliasMatcher", "extensionPointNames": ["com.intellij.gotoActionAliasMatcher"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.navigation.ChooseByNameContributor", "extensionPointNames": ["com.intellij.gotoClassContributor", "com.intellij.gotoSymbolContributor", "com.intellij.gotoFileContributor"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.navigation.GotoRelatedProvider", "extensionPointNames": ["com.intellij.gotoRelatedProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.navigation.AnonymousElementProvider", "extensionPointNames": ["com.intellij.anonymousElementProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributorFactory", "extensionPointNames": ["com.intellij.searchEverywhereContributor"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.searcheverywhere.SEResultsEqualityProvider", "extensionPointNames": ["com.intellij.searchEverywhereResultsEqualityProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.searcheverywhere.SearchEverywhereMlService", "extensionPointNames": ["com.intellij.searchEverywhereMlService"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.searcheverywhere.SearchEverywhereMlContributorReplacement", "extensionPointNames": ["com.intellij.searchEverywhereMlContributorReplacement"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.searcheverywhere.SearchEverywhereSpellingCorrectorFactory", "extensionPointNames": ["com.intellij.searchEverywhereSpellingCorrector"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.searcheverywhere.SearchEverywhereEssentialContributorMarker", "extensionPointNames": ["com.intellij.searchEverywhereEssentialContributorsMarker"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.searcheverywhere.remote.RemoteSearchEverywhereConverterSupplier", "extensionPointNames": ["com.intellij.searchEverywhereRemoteConverter"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.searcheverywhere.SearchEverywhereReorderingService", "extensionPointNames": ["com.intellij.searchEverywhereReorderingService"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.searcheverywhere.SearchEverywherePreviewPrimaryUsageFinder", "extensionPointNames": ["com.intellij.searchEverywherePreviewPrimaryUsageFinder"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.SearchEverywhereManagerFactory", "extensionPointNames": ["com.intellij.searchEverywhere.manager"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.runAnything.activity.RunAnythingProvider", "extensionPointNames": ["com.intellij.runAnything.executionProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.runAnything.handlers.RunAnythingCommandHandler", "extensionPointNames": ["com.intellij.runAnything.commandHandler"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.runAnything.groups.RunAnythingHelpGroup", "extensionPointNames": ["com.intellij.runAnything.helpGroup"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.runAnything.commands.RunAnythingCommandCustomizer", "extensionPointNames": ["com.intellij.runAnything.commandCustomizer"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.highlighting.HighlightUsagesHandlerFactory", "extensionPointNames": ["com.intellij.highlightUsagesHandlerFactory"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.usages.UsageTargetProvider", "extensionPointNames": ["com.intellij.usageTargetProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.usages.UsageToPsiElementProvider", "extensionPointNames": ["com.intellij.usageToPsiElementProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.find.impl.FindInProjectExtension", "extensionPointNames": ["com.intellij.findInProjectExtension"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.model.psi.PsiSymbolDeclarationProvider", "extensionPointNames": ["com.intellij.psi.declarationProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.navigation.actions.TypeDeclarationProvider", "extensionPointNames": ["com.intellij.typeDeclarationProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.navigation.GotoTargetRendererProvider", "extensionPointNames": ["com.intellij.gotoTargetRendererProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.navigation.GotoTargetPresentationProvider", "extensionPointNames": ["com.intellij.gotoTargetPresentationProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.find.usages.symbol.SymbolSearchTargetFactory", "extensionPointNames": ["com.intellij.lang.symbolSearchTarget"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.find.findUsages.FindUsagesHandlerFactory", "extensionPointNames": ["com.intellij.findUsagesHandlerFactory"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.find.findUsages.CustomUsageSearcher", "extensionPointNames": ["com.intellij.customUsageSearcher"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.platform.ide.navigation.NavigationHandler", "extensionPointNames": ["com.intellij.navigation.navigationHandler"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.impl.RunConfigurationTemplateProvider", "extensionPointNames": ["com.intellij.runConfigurationTemplateProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.configurations.RunConfigurationsSettings", "extensionPointNames": ["com.intellij.runConfigurationsSettings"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.runners.ProgramRunner", "extensionPointNames": ["com.intellij.programRunner"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.task.ProjectTaskRunner", "extensionPointNames": ["com.intellij.projectTaskRunner"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.Executor", "extensionPointNames": ["com.intellij.executor"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.runToolbar.RunToolbarProcess", "extensionPointNames": ["com.intellij.runToolbarProcess"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.ExecutionTargetProvider", "extensionPointNames": ["com.intellij.executionTargetProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.BeforeRunTaskProvider", "extensionPointNames": ["com.intellij.stepsBeforeRunProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.impl.RunConfigurationBeforeRunProviderDelegate", "extensionPointNames": ["com.intellij.runConfigurationBeforeRunProviderDelegate"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.target.RunConfigurationTargetEnvironmentAdjuster$Factory", "extensionPointNames": ["com.intellij.runConfigurationTargetEnvironmentAdjusterFactory"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.target.TargetEnvironmentType", "extensionPointNames": ["com.intellij.executionTargetType"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.target.LanguageRuntimeType", "extensionPointNames": ["com.intellij.executionTargetLanguageRuntimeType"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.filters.ConsoleFilterProvider", "extensionPointNames": ["com.intellij.consoleFilterProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.filters.ConsoleInputFilterProvider", "extensionPointNames": ["com.intellij.consoleInputFilterProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.actions.ConsoleActionsPostProcessor", "extensionPointNames": ["com.intellij.consoleActionsPostProcessor"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.junit.RuntimeConfigurationProducer", "extensionPointNames": ["com.intellij.configurationProducer"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.lineMarker.RunLineMarkerContributor", "extensionPointNames": ["com.intellij.runLineMarkerContributor"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.actions.MultipleRunLocationsProvider", "extensionPointNames": ["com.intellij.multipleRunLocationsProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.dashboard.RunDashboardCustomizer", "extensionPointNames": ["com.intellij.runDashboardCustomizer"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.dashboard.LegacyRunDashboardServiceSubstitutor", "extensionPointNames": ["com.intellij.legacyRunDashboardServiceSubstitutor"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.dashboard.RunDashboardDefaultTypesProvider", "extensionPointNames": ["com.intellij.runDashboardDefaultTypesProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.navigation.MethodNavigationOffsetProvider", "extensionPointNames": ["com.intellij.methodNavigationOffsetProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.testIntegration.TestFinder", "extensionPointNames": ["com.intellij.testFinder"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.testIntegration.TestLocationProvider", "extensionPointNames": ["com.intellij.testSrcLocator"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.testIntegration.TestCreator", "extensionPointNames": ["com.intellij.testCreator"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.hierarchy.HierarchyProvider", "extensionPointNames": ["com.intellij.callHierarchyProvider", "com.intellij.methodHierarchyProvider", "com.intellij.typeHierarchyProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.TargetElementUtilExtender", "extensionPointNames": ["com.intellij.targetElementUtilExtender"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.TargetElementEvaluator", "extensionPointNames": ["com.intellij.targetElementEvaluator"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.impl.cache.impl.id.IdIndexer", "extensionPointNames": ["com.intellij.idIndexer"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.daemon.ProblemHighlightFilter", "extensionPointNames": ["com.intellij.problemHighlightFilter"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.filters.Filter", "extensionPointNames": ["com.intellij.analyzeStacktraceFilter"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.unscramble.StacktraceTabContentProvider", "extensionPointNames": ["com.intellij.analyzeStacktraceRunContentProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.actions.SearchEverywhereClassifier", "extensionPointNames": ["com.intellij.searchEverywhereClassifier"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.util.gotoByName.GotoFileCustomizer", "extensionPointNames": ["com.intellij.gotoFileCustomizer"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.util.fuzzyMatching.GotoFileFuzzyMatcherFactory", "extensionPointNames": ["com.intellij.gotoFileFuzzyMatcherFactory"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.slicer.SliceLanguageSupportProvider", "extensionPointNames": ["com.intellij.lang.sliceProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.console.ConsoleHistoryModelProvider", "extensionPointNames": ["com.intellij.consoleHistoryModelProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.execution.update.RunningApplicationUpdaterProvider", "extensionPointNames": ["com.intellij.runningApplicationUpdaterProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.hint.ImplementationViewSessionFactory", "extensionPointNames": ["com.intellij.implementationViewSessionFactory"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.hint.ImplementationViewDocumentFactory", "extensionPointNames": ["com.intellij.implementationViewDocumentFactory"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.platform.backend.documentation.DocumentationTargetProvider", "extensionPointNames": ["com.intellij.platform.backend.documentation.targetProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.platform.backend.documentation.SymbolDocumentationTargetProvider", "extensionPointNames": ["com.intellij.platform.backend.documentation.symbolTargetProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.platform.backend.documentation.PsiDocumentationTargetProvider", "extensionPointNames": ["com.intellij.platform.backend.documentation.psiTargetProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.platform.backend.documentation.LookupElementDocumentationTargetProvider", "extensionPointNames": ["com.intellij.platform.backend.documentation.lookupElementTargetProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.platform.backend.documentation.InlineDocumentationProvider", "extensionPointNames": ["com.intellij.platform.backend.documentation.inlineDocumentationProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.platform.backend.documentation.DocumentationLinkHandler", "extensionPointNames": ["com.intellij.platform.backend.documentation.linkHandler"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.refactoring.safeDelete.api.SafeDeleteTargetProvider", "extensionPointNames": ["com.intellij.safeDeleteTargetProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.navigation.DirectNavigationProvider", "extensionPointNames": ["com.intellij.lang.directNavigationProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.navigation.SymbolTypeProvider", "extensionPointNames": ["com.intellij.lang.symbolTypeProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.application.ApplicationListener", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.project.ProjectListener", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.project.ProjectCloseListener", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.project.VetoableProjectManagerListener", "extensionPointNames": [], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.projectView.TreeStructureProvider", "extensionPointNames": ["com.intellij.treeStructureProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.projectView.impl.AbstractProjectViewPane", "extensionPointNames": ["com.intellij.projectViewPane"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.projectView.impl.ProjectViewPaneSelectionHelper", "extensionPointNames": ["com.intellij.projectViewPaneSelectionHelper"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.projectView.ProjectViewNodeDecorator", "extensionPointNames": ["com.intellij.projectViewNodeDecorator"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.projectView.ProjectViewNestingRulesProvider", "extensionPointNames": ["com.intellij.projectViewNestingRulesProvider"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.intention.IntentionAction", "extensionPointNames": ["com.intellij.intentionAction"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.editor.actions.FlipCommaIntention.Flipper", "extensionPointNames": ["com.intellij.flipCommaIntention.flipper"], "targetModules": ["backend"], "restrictionKind": "genericPlatformApi"},
- {"apiName": "com.intellij.lang.ParserDefinition", "extensionPointNames": ["com.intellij.lang.parserDefinition"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.psi.FileViewProviderFactory", "extensionPointNames": ["com.intellij.lang.fileViewProviderFactory"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.lang.ASTFactory", "extensionPointNames": ["com.intellij.lang.ast.factory", "lang.ast.factory"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.lang.PsiParser", "extensionPointNames": [], "targetModules": ["shared"]},
- {"apiName": "com.intellij.lexer.Lexer", "extensionPointNames": [], "targetModules": ["shared"]},
- {"apiName": "com.intellij.psi.LanguageInjector", "extensionPointNames": ["com.intellij.languageInjector"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.lang.injection.MultiHostInjector", "extensionPointNames": ["com.intellij.multiHostInjector"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.psi.ElementDescriptionProvider", "extensionPointNames": ["com.intellij.elementDescriptionProvider"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.psi.ElementManipulator", "extensionPointNames": ["com.intellij.lang.elementManipulator"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.openapi.editor.bidi.BidiRegionsSeparator", "extensionPointNames": ["com.intellij.bidiRegionsSeparator"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.openapi.editor.actions.WordBoundaryFilter", "extensionPointNames": ["com.intellij.wordBoundaryFilter"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.openapi.options.colors.ColorAndFontDescriptorsProvider", "extensionPointNames": ["com.intellij.colorAndFontDescriptorProvider"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.application.options.GeneralCodeStyleOptionsProvider", "extensionPointNames": ["com.intellij.generalCodeStyleOptionsProvider"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.psi.codeStyle.FileTypeIndentOptionsProvider", "extensionPointNames": ["com.intellij.fileTypeIndentOptionsProvider"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider", "extensionPointNames": ["com.intellij.langCodeStyleSettingsProvider"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.psi.codeStyle.LanguageCodeStyleSettingsContributor", "extensionPointNames": ["com.intellij.langCodeStyleSettingsContributor"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.psi.codeStyle.PredefinedCodeStyle", "extensionPointNames": ["com.intellij.predefinedCodeStyle"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.psi.templateLanguages.MultipleLangCommentProvider", "extensionPointNames": ["com.intellij.multiLangCommenter"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.psi.codeStyle.arrangement.Rearranger", "extensionPointNames": ["com.intellij.lang.rearranger"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.SelectionQuotingTypedHandler.UnquotingFilter", "extensionPointNames": ["com.intellij.selectionUnquotingFilter"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.openapi.editor.actions.FlipCommaIntention.Flipper", "extensionPointNames": ["com.intellij.flipCommaIntention.flipper"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.lang.Commenter", "extensionPointNames": ["com.intellij.lang.commenter"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.QuoteHandler", "extensionPointNames": ["com.intellij.quoteHandler", "com.intellij.lang.quoteHandler"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.TypedHandlerDelegate", "extensionPointNames": ["com.intellij.typedHandler"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.moveUpDown.StatementUpDownMover", "extensionPointNames": ["com.intellij.statementUpDownMover"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.formatting.InjectedFormattingOptionsProvider", "extensionPointNames": ["com.intellij.formatting.injectedOptions"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.lang.folding.FoldingBuilder", "extensionPointNames": ["com.intellij.lang.foldingBuilder"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.openapi.editor.IndentStrategy", "extensionPointNames": ["com.intellij.lang.indentStrategy"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.psi.codeStyle.lineIndent.LineIndentProvider", "extensionPointNames": ["com.intellij.lineIndentProvider"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.ExtendWordSelectionHandler", "extensionPointNames": ["com.intellij.extendWordSelectionHandler"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.moveLeftRight.MoveElementLeftRightHandler", "extensionPointNames": ["com.intellij.moveLeftRightHandler"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.JoinLinesHandlerDelegate", "extensionPointNames": ["com.intellij.joinLinesHandler"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.BackspaceModeOverride", "extensionPointNames": ["com.intellij.editor.backspaceModeOverride"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.TypingActionsExtension", "extensionPointNames": ["com.intellij.typingActionsExtension"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.BackspaceHandlerDelegate", "extensionPointNames": ["com.intellij.backspaceHandlerDelegate"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.CodeBlockProvider", "extensionPointNames": ["com.intellij.codeBlockProvider"], "targetModules": ["shared"]},
- {"apiName": "com.intellij.codeInsight.highlighting.CodeBlockSupportHandler", "extensionPointNames": ["com.intellij.codeBlockSupportHandler"], "targetModules": ["shared"]},
+ // shared generic apis
+ {"apiName": "com.intellij.lang.ParserDefinition", "extensionPointNames": ["com.intellij.lang.parserDefinition"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.FileViewProviderFactory", "extensionPointNames": ["com.intellij.lang.fileViewProviderFactory"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.ASTFactory", "extensionPointNames": ["com.intellij.lang.ast.factory", "lang.ast.factory"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.PsiParser", "extensionPointNames": [], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lexer.Lexer", "extensionPointNames": [], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.LanguageInjector", "extensionPointNames": ["com.intellij.languageInjector"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.injection.MultiHostInjector", "extensionPointNames": ["com.intellij.multiHostInjector"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.ElementManipulator", "extensionPointNames": ["com.intellij.lang.elementManipulator"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.editor.bidi.BidiRegionsSeparator", "extensionPointNames": ["com.intellij.bidiRegionsSeparator"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.editor.actions.WordBoundaryFilter", "extensionPointNames": ["com.intellij.wordBoundaryFilter"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.editor.LineWrapPositionStrategy", "extensionPointNames": ["com.intellij.lang.lineWrapStrategy"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.options.colors.ColorAndFontDescriptorsProvider", "extensionPointNames": ["com.intellij.colorAndFontDescriptorProvider"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.application.options.GeneralCodeStyleOptionsProvider", "extensionPointNames": ["com.intellij.generalCodeStyleOptionsProvider"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.codeStyle.FileTypeIndentOptionsProvider", "extensionPointNames": ["com.intellij.fileTypeIndentOptionsProvider"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider", "extensionPointNames": ["com.intellij.langCodeStyleSettingsProvider"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.codeStyle.LanguageCodeStyleSettingsContributor", "extensionPointNames": ["com.intellij.langCodeStyleSettingsContributor"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.codeStyle.PredefinedCodeStyle", "extensionPointNames": ["com.intellij.predefinedCodeStyle"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.templateLanguages.MultipleLangCommentProvider", "extensionPointNames": ["com.intellij.multiLangCommenter"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.codeStyle.arrangement.Rearranger", "extensionPointNames": ["com.intellij.lang.rearranger"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.SelectionQuotingTypedHandler.UnquotingFilter", "extensionPointNames": ["com.intellij.selectionUnquotingFilter"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.Commenter", "extensionPointNames": ["com.intellij.lang.commenter"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.QuoteHandler", "extensionPointNames": ["com.intellij.quoteHandler", "com.intellij.lang.quoteHandler"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.TypedHandlerDelegate", "extensionPointNames": ["com.intellij.typedHandler"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.moveUpDown.StatementUpDownMover", "extensionPointNames": ["com.intellij.statementUpDownMover"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.formatting.InjectedFormattingOptionsProvider", "extensionPointNames": ["com.intellij.formatting.injectedOptions"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.folding.FoldingBuilder", "extensionPointNames": ["com.intellij.lang.foldingBuilder"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.openapi.editor.IndentStrategy", "extensionPointNames": ["com.intellij.lang.indentStrategy"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.codeStyle.lineIndent.LineIndentProvider", "extensionPointNames": ["com.intellij.lineIndentProvider"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.ExtendWordSelectionHandler", "extensionPointNames": ["com.intellij.extendWordSelectionHandler"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.moveLeftRight.MoveElementLeftRightHandler", "extensionPointNames": ["com.intellij.moveLeftRightHandler"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.JoinLinesHandlerDelegate", "extensionPointNames": ["com.intellij.joinLinesHandler"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.BackspaceModeOverride", "extensionPointNames": ["com.intellij.editor.backspaceModeOverride"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.TypingActionsExtension", "extensionPointNames": ["com.intellij.typingActionsExtension"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.BackspaceHandlerDelegate", "extensionPointNames": ["com.intellij.backspaceHandlerDelegate"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.CodeBlockProvider", "extensionPointNames": ["com.intellij.codeBlockProvider"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.highlighting.CodeBlockSupportHandler", "extensionPointNames": ["com.intellij.codeBlockSupportHandler"], "targetModules": ["shared"], "restrictionKind": "genericPlatformApi"},
- {"apiName": "com.intellij.codeInsight.editorActions.CopyPastePostProcessor", "extensionPointNames": ["com.intellij.copyPastePostProcessor"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.CopyPastePreProcessor", "extensionPointNames": ["com.intellij.copyPastePreProcessor"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.PreserveIndentOnPasteBean", "extensionPointNames": ["com.intellij.preserveIndentOnPaste"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.psi.impl.source.codeStyle.PreFormatProcessor", "extensionPointNames": ["com.intellij.preFormatProcessor"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.psi.impl.source.codeStyle.PostFormatProcessor", "extensionPointNames": ["com.intellij.postFormatProcessor"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.lang.CustomAutoFormatSyntaxErrorsVerifier", "extensionPointNames": ["com.intellij.lang.formatter.syntaxErrorsVerifier"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.formatting.service.FormattingService", "extensionPointNames": ["com.intellij.formattingService"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.ide.PasteProvider", "extensionPointNames": ["com.intellij.customPasteProvider"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.formatting.FormattingModelBuilder", "extensionPointNames": ["com.intellij.lang.formatter"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.lang.LanguageFormattingRestriction", "extensionPointNames": ["com.intellij.lang.formatter.restriction"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.psi.formatter.WhiteSpaceFormattingStrategy", "extensionPointNames": ["com.intellij.lang.whiteSpaceFormattingStrategy"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.enter.EnterBetweenBracesDelegate", "extensionPointNames": ["com.intellij.enterBetweenBracesDelegate"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegate", "extensionPointNames": ["com.intellij.enterHandlerDelegate"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter", "extensionPointNames": ["com.intellij.enterHandlerDelegate"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.codeInsight.editorActions.smartEnter.SmartEnterProcessor", "extensionPointNames": ["com.intellij.lang.smartEnterProcessor"], "targetModules": ["backend", "shared"]},
- {"apiName": "com.intellij.codeInsight.highlighting.BraceMatcher", "extensionPointNames": ["com.intellij.braceMatcher", "com.intellij.lang.braceMatcher"], "targetModules": ["backend", "shared"]},
+ // backend or shared generic apis - ideally shared (better UX), but depending on implementation may require resolve, so backend is also allowed
+ {"apiName": "com.intellij.codeInsight.editorActions.CopyPastePostProcessor", "extensionPointNames": ["com.intellij.copyPastePostProcessor"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.CopyPastePreProcessor", "extensionPointNames": ["com.intellij.copyPastePreProcessor"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.PreserveIndentOnPasteBean", "extensionPointNames": ["com.intellij.preserveIndentOnPaste"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.impl.source.codeStyle.PreFormatProcessor", "extensionPointNames": ["com.intellij.preFormatProcessor"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.impl.source.codeStyle.PostFormatProcessor", "extensionPointNames": ["com.intellij.postFormatProcessor"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.CustomAutoFormatSyntaxErrorsVerifier", "extensionPointNames": ["com.intellij.lang.formatter.syntaxErrorsVerifier"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.formatting.service.FormattingService", "extensionPointNames": ["com.intellij.formattingService"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.ide.PasteProvider", "extensionPointNames": ["com.intellij.customPasteProvider"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.formatting.FormattingModelBuilder", "extensionPointNames": ["com.intellij.lang.formatter"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.lang.LanguageFormattingRestriction", "extensionPointNames": ["com.intellij.lang.formatter.restriction"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.psi.formatter.WhiteSpaceFormattingStrategy", "extensionPointNames": ["com.intellij.lang.whiteSpaceFormattingStrategy"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.enter.EnterBetweenBracesDelegate", "extensionPointNames": ["com.intellij.enterBetweenBracesDelegate"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegate", "extensionPointNames": ["com.intellij.enterHandlerDelegate"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter", "extensionPointNames": ["com.intellij.enterHandlerDelegate"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.editorActions.smartEnter.SmartEnterProcessor", "extensionPointNames": ["com.intellij.lang.smartEnterProcessor"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
+ {"apiName": "com.intellij.codeInsight.highlighting.BraceMatcher", "extensionPointNames": ["com.intellij.braceMatcher", "com.intellij.lang.braceMatcher"], "targetModules": ["backend", "shared"], "restrictionKind": "genericPlatformApi"},
- {"apiName": "com.intellij.openapi.util.registry.RegistryValueListener", "extensionPointNames": [], "targetModules": ["frontend", "backend"], "hint": "Registry values are different on frontend and backend, prefer listening to them explicitly in desired IDE part"},
- {"apiName": "com.intellij.ide.plugins.DynamicPluginListener", "extensionPointNames": [], "targetModules": ["frontend", "backend"], "hint": "Plugin lists are different on frontend and backend, prefer listening to them explicitly in desired IDE part"},
- {"apiName": "com.intellij.openapi.options.Configurable", "extensionPointNames": ["com.intellij.applicationConfigurable", "com.intellij.projectConfigurable"], "targetModules": ["frontend", "backend"]},
- {"apiName": "com.intellij.lang.annotation.Annotator", "extensionPointNames": ["com.intellij.annotator"], "targetModules": ["frontend", "backend"], "hint": "Resolve-dependent annotators belong to the backend, while lightweight ones belong to frontend"},
- {"apiName": "com.intellij.lang.annotation.ContributedReferencesAnnotator", "extensionPointNames": ["com.intellij.contributedReferencesAnnotator"], "targetModules": ["frontend", "backend"], "hint": "Resolve-dependent annotators belong to the backend, while lightweight ones belong to frontend"},
+ // frontend or backend generic apis - suggested to be explicitly registered in a dedicated module type to make sure the developer understands where the code is going to be executed.
+ // example: shared plugin loading listener with logic touching VFS will not effectively work in frontend, so either there must be two different implementations, or a single registered where the necessary resources (VFS) exist
+ {"apiName": "com.intellij.openapi.util.registry.RegistryValueListener", "extensionPointNames": [], "targetModules": ["frontend", "backend"], "restrictionKind": "genericPlatformApi", "hint": "Registry values are different on frontend and backend, prefer listening to them explicitly in desired IDE part"},
+ {"apiName": "com.intellij.ide.plugins.DynamicPluginListener", "extensionPointNames": [], "targetModules": ["frontend", "backend"], "restrictionKind": "genericPlatformApi", "hint": "Plugin lists are different on frontend and backend, prefer listening to them explicitly in desired IDE part"},
+ {"apiName": "com.intellij.lang.annotation.Annotator", "extensionPointNames": ["com.intellij.annotator"], "targetModules": ["frontend", "backend"], "restrictionKind": "genericPlatformApi", "hint": "Resolve-dependent annotators belong to the backend, while lightweight ones belong to frontend"},
+ {"apiName": "com.intellij.lang.annotation.ContributedReferencesAnnotator", "extensionPointNames": ["com.intellij.contributedReferencesAnnotator"], "targetModules": ["frontend", "backend"], "restrictionKind": "genericPlatformApi", "hint": "Resolve-dependent annotators belong to the backend, while lightweight ones belong to frontend"},
- {"apiName": "com.intellij.psi.codeStyle.arrangement.std.ArrangementUiComponent.Factory", "extensionPointNames": ["com.intellij.rearranger.ui"], "targetModules": ["frontend", "shared"], "hint": "Language supporting extensions belong to shared, if the language supports injections. Otherwise frontend."},
- {"apiName": "com.intellij.openapi.options.colors.ColorSettingsPage", "extensionPointNames": ["com.intellij.colorSettingsPage"], "targetModules": ["frontend", "shared"], "hint": "Language supporting extensions belong to shared, if the language supports injections. Otherwise frontend."},
- {"apiName": "com.intellij.application.options.colors.ColorAndFontPanelFactory", "extensionPointNames": ["com.intellij.colorAndFontPanelFactory"], "targetModules": ["frontend", "shared"], "hint": "Language supporting extensions belong to shared, if the language supports injections. Otherwise frontend."},
- {"apiName": "com.intellij.psi.codeStyle.CodeStyleSettingsProvider", "extensionPointNames": ["com.intellij.codeStyleSettingsProvider"], "targetModules": ["frontend", "shared"], "hint": "Language supporting extensions belong to shared, if the language supports injections. Otherwise frontend."},
- {"apiName": "com.intellij.openapi.fileTypes.SyntaxHighlighter", "extensionPointNames": ["com.intellij.syntaxHighlighter", "com.intellij.lang.syntaxHighlighter"], "targetModules": ["frontend", "shared"], "hint": "Language supporting extensions belong to shared, if the language supports injections. Otherwise frontend."},
- {"apiName": "com.intellij.openapi.fileTypes.SyntaxHighlighterFactory", "extensionPointNames": ["com.intellij.lang.syntaxHighlighterFactory"], "targetModules": ["frontend", "shared"], "hint": "Language supporting extensions belong to shared, if the language supports injections. Otherwise frontend."},
- {"apiName": "com.intellij.openapi.fileTypes.EditorHighlighterProvider", "extensionPointNames": ["com.intellij.editorHighlighterProvider"], "targetModules": ["frontend", "shared"], "hint": "Language supporting extensions belong to shared, if the language supports injections. Otherwise frontend."}
-]
\ No newline at end of file
+ // frontend or shared generic apis
+ {"apiName": "com.intellij.openapi.options.colors.ColorSettingsPage", "extensionPointNames": ["com.intellij.colorSettingsPage"], "targetModules": ["frontend", "shared"], "restrictionKind": "genericPlatformApi", "hint": "Language supporting extensions belong to shared, if the language supports injections. Otherwise frontend."},
+ {"apiName": "com.intellij.application.options.colors.ColorAndFontPanelFactory", "extensionPointNames": ["com.intellij.colorAndFontPanelFactory"], "targetModules": ["frontend", "shared"], "restrictionKind": "genericPlatformApi", "hint": "Language supporting extensions belong to shared, if the language supports injections. Otherwise frontend."},
+ {"apiName": "com.intellij.psi.codeStyle.CodeStyleSettingsProvider", "extensionPointNames": ["com.intellij.codeStyleSettingsProvider"], "targetModules": ["frontend", "shared"], "restrictionKind": "genericPlatformApi", "hint": "Language supporting extensions belong to shared, if the language supports injections. Otherwise frontend."},
+ {"apiName": "com.intellij.openapi.fileTypes.SyntaxHighlighter", "extensionPointNames": ["com.intellij.syntaxHighlighter", "com.intellij.lang.syntaxHighlighter"], "targetModules": ["frontend", "shared"], "restrictionKind": "genericPlatformApi", "hint": "Language supporting extensions belong to shared, if the language supports injections. Otherwise frontend."},
+ {"apiName": "com.intellij.openapi.fileTypes.SyntaxHighlighterFactory", "extensionPointNames": ["com.intellij.lang.syntaxHighlighterFactory"], "targetModules": ["frontend", "shared"], "restrictionKind": "genericPlatformApi", "hint": "Language supporting extensions belong to shared, if the language supports injections. Otherwise frontend."},
+ {"apiName": "com.intellij.openapi.fileTypes.EditorHighlighterProvider", "extensionPointNames": ["com.intellij.editorHighlighterProvider"], "targetModules": ["frontend", "shared"], "restrictionKind": "genericPlatformApi", "hint": "Language supporting extensions belong to shared, if the language supports injections. Otherwise frontend."}
+]
diff --git a/plugins/devkit/devkit-core/resources/remotedevInspectionData/DevKitSplitModeInspectionExclusions.json b/plugins/devkit/devkit-core/resources/remotedevInspectionData/DevKitSplitModeInspectionExclusions.json
deleted file mode 100644
index 245718b55be2..000000000000
--- a/plugins/devkit/devkit-core/resources/remotedevInspectionData/DevKitSplitModeInspectionExclusions.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "exclusions": [
- {
- "inspection": "SplitModeApiUsage",
- "file": "community/python/python-type-engine/src/com/intellij/python/typeEngine/PyTypeEngineStatusBarWidget.kt",
- "line": 49,
- "reason": "PY-90092: Python LSP/type-engine tools were moved from PyCharm Pro into PyCharm Community. The type engine status bar widget is monolith-only UI that has not been split into frontend/backend yet."
- },
- {
- "inspection": "SplitModeApiUsage",
- "file": "community/python/python-type-engine/src/com/intellij/python/typeEngine/PyTypeEngineStatusBarWidget.kt",
- "line": 132,
- "reason": "PY-90092: JBPopupFactory usage in the monolith-only Python type engine status bar widget (not yet split for remote dev)."
- },
- {
- "inspection": "SplitModeXmlApiUsage",
- "file": "community/python/python-type-engine/resources/intellij.python.typeEngine.xml",
- "line": 42,
- "reason": "PY-90092: statusBarWidgetFactory registration for the monolith-only Python type engine widget (not yet split for remote dev)."
- }
- ]
-}
diff --git a/plugins/devkit/devkit-core/resources/remotedevInspectionData/MonorepoFeaturesWithoutSplitModeSupport.json5 b/plugins/devkit/devkit-core/resources/remotedevInspectionData/MonorepoFeaturesWithoutSplitModeSupport.json5
new file mode 100644
index 000000000000..01f0ab6276c7
--- /dev/null
+++ b/plugins/devkit/devkit-core/resources/remotedevInspectionData/MonorepoFeaturesWithoutSplitModeSupport.json5
@@ -0,0 +1,51 @@
+// Monorepo features that are not inspected by DevKit split-mode inspections yet.
+// This file is the source of truth for SplitModeExcludedModules.xml IDE scopes.
+// Use pathPatterns for repository paths and moduleNames for IntelliJ module names.\
+
+// After making changes to this file run the SplitModeExcludedModulesScopeConsistencyTest
+// and apply changes to the config files generated from the MonorepoFeaturesWithoutSplitModeSupport.json5
+{
+ pathPatterns: [
+ "plugins/llm//*",
+ "plugins/llm-experimental//*",
+ "plugins/llm-installer//*",
+ "plugins/llm-sandbox//*",
+ "community/python//*",
+ "language-server//*"
+ ],
+
+ moduleNames: [
+ "intellij.platform.resources",
+ "intellij.platform.ui.jcef",
+ "intellij.platform.util",
+ "intellij.platform.projectModel",
+ "intellij.platform.projectModel.impl",
+ "intellij.platform.refactoring",
+ "intellij.platform.split",
+ "intellij.platform.split.connection",
+ "intellij.platform.ide.bootstrap",
+ "intellij.platform.ide.core",
+ "intellij.platform.ide.core.impl",
+ "intellij.platform.ide.impl",
+ "intellij.platform.indexing",
+ "intellij.platform.indexing.impl",
+ "intellij.platform.lang",
+ "intellij.platform.lang.core",
+ "intellij.platform.lang.impl",
+ "intellij.platform.editor.ex",
+ "intellij.platform.editor.ui",
+ "intellij.platform.frontend.split",
+ "intellij.platform.frontend.split.base",
+ "intellij.platform.ide",
+ "intellij.platform.analysis",
+ "intellij.platform.analysis.impl",
+ "intellij.platform.backend.split",
+ "intellij.platform.codeStyle",
+ "intellij.platform.codeStyle.impl",
+ "intellij.platform.commercial",
+ "intellij.platform.commercial.license",
+ "intellij.platform.completion.common",
+ "intellij.platform.core",
+ "intellij.platform.core.impl",
+ ],
+}
diff --git a/plugins/devkit/devkit-core/resources/remotedevInspectionData/PredefinedModuleKinds.json b/plugins/devkit/devkit-core/resources/remotedevInspectionData/PredefinedModuleKinds.json
deleted file mode 100644
index fbc56e470b3a..000000000000
--- a/plugins/devkit/devkit-core/resources/remotedevInspectionData/PredefinedModuleKinds.json
+++ /dev/null
@@ -1,190 +0,0 @@
-[
- {"moduleName": "intellij.platform.monolith", "moduleKind": "monolith"},
-
- {"moduleName": "intellij.platform.frontend", "moduleKind": "frontend"},
- {"moduleName": "intellij.platform.frontend.split", "moduleKind": "frontend"},
- {"moduleName": "intellij.platform.plugins.frontend.split", "moduleKind": "frontend"},
- {"moduleName": "com.intellij.jetbrains.client", "moduleKind": "frontend"},
- {"moduleName": "com.intellij.jetbrains.client.git", "moduleKind": "frontend"},
- {"moduleName": "intellij.cwm.frontend", "moduleKind": "frontend"},
- {"moduleName": "intellij.cwm.connection.frontend.split", "moduleKind": "frontend"},
-
- {"moduleName": "intellij.platform.backend", "moduleKind": "backend"},
- {"moduleName": "intellij.platform.backend.split", "moduleKind": "backend"},
- {"moduleName": "intellij.platform.kernel.backend", "moduleKind": "backend"},
- {"moduleName": "com.jetbrains.remoteDevelopment", "moduleKind": "backend"},
- {"moduleName": "intellij.cwm", "moduleKind": "backend"},
- {"moduleName": "intellij.cwm.plugin", "moduleKind": "backend"},
- {"moduleName": "intellij.cwm.plugin.provisioner", "moduleKind": "backend"},
- {"moduleName": "intellij.cwm.connection.backend", "moduleKind": "backend"},
- {"moduleName": "intellij.cwm.connection.backend.license", "moduleKind": "backend"},
- {"moduleName": "intellij.cwm.vcs", "moduleKind": "backend"},
- {"moduleName": "intellij.cwm.enabler", "moduleKind": "backend"},
- {"moduleName": "intellij.cwm.enabler.core", "moduleKind": "backend"},
- {"moduleName": "intellij.codeWithMe.abstract.main", "moduleKind": "backend"},
- {"moduleName": "intellij.codeWithMe.idea.community.main", "moduleKind": "backend"},
- {"moduleName": "intellij.codeWithMe.idea.ultimate.main.android", "moduleKind": "backend"},
- {"moduleName": "intellij.codeWithMe.datagrip.main", "moduleKind": "backend"},
- {"moduleName": "intellij.codeWithMe.pycharm.community.main", "moduleKind": "backend"},
- {"moduleName": "intellij.codeWithMe.appcode.main", "moduleKind": "backend"},
-
- {"moduleName": "intellij.cwm.connection", "moduleKind": "shared"},
- {"moduleName": "intellij.cwm.plugin.common", "moduleKind": "shared"},
- {"moduleName": "intellij.rd.client.base", "moduleKind": "shared"},
- {"moduleName": "intellij.rd.client", "moduleKind": "shared"},
- {"moduleName": "intellij.driver.client", "moduleKind": "shared"},
- {"moduleName": "intellij.driver.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.driver.model", "moduleKind": "shared"},
- {"moduleName": "intellij.driver.sdk", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.analysis", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.analysis.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.boot", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.bootstrap", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.bootstrap.coroutine", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.bootstrap.dev", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.buildScripts", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.buildScripts.api", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.buildScripts.bazel", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.buildScripts.codeOptimizer", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.buildScripts.devBuildServer", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.buildScripts.downloader", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.buildScripts.licenses", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.buildScripts.productDsl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.buildScripts.usages", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.codeStyle", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.codeStyle.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.concurrency", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.configurationStore.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.core", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.core.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.core.nio.fs", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.core.ui", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.diagnostic", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.diagnostic.freezeAnalyzer", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.diagnostic.startUpPerformanceReporter", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.diagnostic.telemetry", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.diagnostic.telemetry.agent.extension", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.diagnostic.telemetry.exporters", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.diagnostic.telemetry.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.diagnostic.telemetry.rt", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.editor", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.editor.ex", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.editor.ui", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.eel", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.eel.codegen", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.eel.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.eel.impl.base", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.eel.nioFs", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.eel.nioFs.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.eel.provider", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.eel.tcp", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.eelHelper", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.extensions", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.foldings", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.icons", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.icons.api", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.icons.api.rendering", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.icons.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.icons.impl.intellij", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.bootstrap", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.bootstrap.eel", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.bootstrap.kernel", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.codeinsight.inline", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.concurrency", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.core", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.core.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.core.plugins", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.internal", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.rpc", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.ui", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.util.io", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.util.io.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.ide.util.netty", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.kernel", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.kernel.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.lang", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.lang.core", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.lang.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.locking.impl", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.project", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.runtime.repository", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.base", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.base.multiplatform", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.classLoader", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.commonsLangV2Shim", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.coroutines", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.diff", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.ex", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.http", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.immutableKeyValueStore", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.immutableKeyValueStore.benchmark", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.io.storages", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.jdom", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.multiplatform", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.nanoxml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.progress", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.rt", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.rt.java8", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.text.matching", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.trove", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.troveCompileOnly", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.ui", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.xmlDom", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.util.zip", "moduleKind": "shared"},
- {"moduleName": "intellij.remoteDev.util", "moduleKind": "shared"},
-
- {"pluginId": "com.intellij.modules.ultimate", "moduleKind": "shared"},
- {"pluginId": "com.intellij.modules.lang", "moduleKind": "shared"},
-
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/PlatformLangPlugin.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/PlatformLangComponents.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/idea/PriorityEditorLangActions.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/idea/PlatformActions.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/PlatformExecutionActions.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/idea/ExecutionActions.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/idea/LangActions.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/idea/UsageViewActions.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/idea/ProblemsViewActions.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/Core.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/CoreImpl.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/Analysis.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/AnalysisImpl.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/WorkspaceModel.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/WorkspaceModelImpl.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/ProjectModel.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/ProjectModelImpl.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/ProjectModelPlatform.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/Indexing.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/Editor.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/EditorEx.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/IdeCore.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/PlatformExtensionPoints.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/MinimapExtensionPoints.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/Refactoring.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/LangExtensionPoints.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/PlatformExtensions.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/PlatformExecutionExtensions.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/LangExtensions.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/ProjectModelLangExtensions.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/SearchEverywhereCodeInsightContributors.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/OpenTelemetryExtensions.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/WorkspaceModelExtensions.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/intellij.platform.feedback.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/IJent.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/intellij.platform.syntax.psi.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/CompletionExtensionPoints.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/RefactoringExtensionPoints.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/RefactoringLangExtensionPoints.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/FormatterExtensionPoints.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/EditorExtensionPoints.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/CodeStyle.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/META-INF/RemoteDevUtil.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/intellij.platform.project.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/intellij.platform.ide.progress.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.platform.resources", "descriptorRelativePath": "src/intellij.platform.experiment.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.rd.client.base", "descriptorRelativePath": "resources/intellij.rd.client.base.xml", "moduleKind": "shared"},
- {"moduleName": "intellij.rd.client", "descriptorRelativePath": "resources/intellij.rd.client.xml", "moduleKind": "shared"}
-]
diff --git a/plugins/devkit/devkit-core/resources/remotedevInspectionData/SplitModeProjectBaselineVersion.json5 b/plugins/devkit/devkit-core/resources/remotedevInspectionData/SplitModeProjectBaselineVersion.json5
new file mode 100644
index 000000000000..f55ceb797af7
--- /dev/null
+++ b/plugins/devkit/devkit-core/resources/remotedevInspectionData/SplitModeProjectBaselineVersion.json5
@@ -0,0 +1,10 @@
+// The file carries the current project baseline version for Split Mode Compatibility safe-push checks.
+// Increase currentProjectBaselineVersion only when incremental Split Mode Compatibility tests incorrectly
+// report pre-existing violations after large refactorings.
+// Changing this value is a legal bypass: the affected safe push may skip the incremental Split Mode
+// Compatibility tests for that run, allowing the refactoring to proceed while the baseline catches up.
+// Do not use it for real new violations. Fix those instead; see Split Mode documentation IJPL-A-632.
+// Contact the RemDev team in #ij-remote-dev if unsure.
+{
+ "currentProjectBaselineVersion": 12
+}
diff --git a/plugins/devkit/devkit-core/resources/remotedevInspectionData/SplitModeQodanaAnalysisScope.json b/plugins/devkit/devkit-core/resources/remotedevInspectionData/SplitModeQodanaAnalysisScope.json
index 0e33b5e6a800..a7be3960de15 100644
--- a/plugins/devkit/devkit-core/resources/remotedevInspectionData/SplitModeQodanaAnalysisScope.json
+++ b/plugins/devkit/devkit-core/resources/remotedevInspectionData/SplitModeQodanaAnalysisScope.json
@@ -1,406 +1,3 @@
{
- "moduleNames": [
- "intellij.ml.llm",
- "intellij.ml.llm.activation",
- "intellij.ml.llm.activation.config",
- "intellij.ml.llm.activation.data.mock",
- "intellij.ml.llm.activation.data.model",
- "intellij.ml.llm.activation.data.repos",
- "intellij.ml.llm.activation.facade",
- "intellij.ml.llm.activation.facade.impl",
- "intellij.ml.llm.activation.ij",
- "intellij.ml.llm.activation.ij.daemon",
- "intellij.ml.llm.activation.ij.grazie",
- "intellij.ml.llm.activation.platform",
- "intellij.ml.llm.activation.platform.tests",
- "intellij.ml.llm.activation.presentation",
- "intellij.ml.llm.activation.presentation.tests",
- "intellij.ml.llm.activation.state.impl",
- "intellij.ml.llm.activation.state.impl.tests",
- "intellij.ml.llm.activation.state.manager",
- "intellij.ml.llm.activation.state.model",
- "intellij.ml.llm.activation.tests.runtime",
- "intellij.ml.llm.activation.util",
- "intellij.ml.llm.activation.util.tests",
- "intellij.ml.llm.agents",
- "intellij.ml.llm.agents.acp",
- "intellij.ml.llm.agents.acp.embeddedMcp",
- "intellij.ml.llm.agents.acp.embeddedMcp.tests",
- "intellij.ml.llm.agents.acp.json",
- "intellij.ml.llm.agents.acp.tests",
- "intellij.ml.llm.agents.acp.view.tests",
- "intellij.ml.llm.agents.contrib",
- "intellij.ml.llm.agents.contrib.contract",
- "intellij.ml.llm.agents.contrib.ide.datagrip",
- "intellij.ml.llm.agents.contrib.ide.idea",
- "intellij.ml.llm.agents.contrib.ide.pycharm",
- "intellij.ml.llm.agents.contrib.ide.rider",
- "intellij.ml.llm.agents.contrib.ide.rubymine",
- "intellij.ml.llm.agents.contrib.ide.rubymine.tests",
- "intellij.ml.llm.agents.contrib.shared.vcs",
- "intellij.ml.llm.agents.contrib.tests",
- "intellij.ml.llm.agents.frontend",
- "intellij.ml.llm.agents.frontend.tests",
- "intellij.ml.llm.agents.impl",
- "intellij.ml.llm.agents.impl.tests",
- "intellij.ml.llm.agents.shared",
- "intellij.ml.llm.agents.skills",
- "intellij.ml.llm.agents.skills.tests",
- "intellij.ml.llm.android",
- "intellij.ml.llm.android.tests",
- "intellij.ml.llm.apiTestsWithJava",
- "intellij.ml.llm.aui.events",
- "intellij.ml.llm.aui.events.tests",
- "intellij.ml.llm.automation",
- "intellij.ml.llm.build",
- "intellij.ml.llm.chat",
- "intellij.ml.llm.chat.completion",
- "intellij.ml.llm.chat.completion.tests",
- "intellij.ml.llm.chat.frontend",
- "intellij.ml.llm.chat.history.migration",
- "intellij.ml.llm.chat.shared",
- "intellij.ml.llm.chat.tests",
- "intellij.ml.llm.chat.testsWithKotlin",
- "intellij.ml.llm.chatInputLanguage",
- "intellij.ml.llm.chatInputLanguage.grazie",
- "intellij.ml.llm.chatInputLanguage.markdown",
- "intellij.ml.llm.chatInputLanguage.tests",
- "intellij.ml.llm.chatInputLanguage.testsWithJava",
- "intellij.ml.llm.chatInputLanguage.testsWithKotlin",
- "intellij.ml.llm.cloudEnabledTests",
- "intellij.ml.llm.cloudEnabledTests.withJava",
- "intellij.ml.llm.cloudEnabledTests.withMcp",
- "intellij.ml.llm.codeEngine",
- "intellij.ml.llm.codeEngine.tests",
- "intellij.ml.llm.codeGeneration",
- "intellij.ml.llm.codeGeneration.tests",
- "intellij.ml.llm.completion",
- "intellij.ml.llm.completion.cloud.testFramework",
- "intellij.ml.llm.completion.latest",
- "intellij.ml.llm.completion.nextEdits.proxy",
- "intellij.ml.llm.completion.testFramework",
- "intellij.ml.llm.completion.tests",
- "intellij.ml.llm.content",
- "intellij.ml.llm.context",
- "intellij.ml.llm.context.airules",
- "intellij.ml.llm.context.airules.tests",
- "intellij.ml.llm.context.ide",
- "intellij.ml.llm.context.llm",
- "intellij.ml.llm.context.runtime",
- "intellij.ml.llm.context.runtime.jvm",
- "intellij.ml.llm.context.runtime.jvm.tests",
- "intellij.ml.llm.contextRankerFeatures",
- "intellij.ml.llm.core",
- "intellij.ml.llm.core.grazieClient",
- "intellij.ml.llm.core.httpClient",
- "intellij.ml.llm.core.tests",
- "intellij.ml.llm.core.tests.runtime",
- "intellij.ml.llm.cpp",
- "intellij.ml.llm.cpp.cmake",
- "intellij.ml.llm.cpp.common",
- "intellij.ml.llm.cpp.completion",
- "intellij.ml.llm.cpp.nextEdits.backend",
- "intellij.ml.llm.cpp.tests",
- "intellij.ml.llm.cpp.testsClassic",
- "intellij.ml.llm.css",
- "intellij.ml.llm.css.completion",
- "intellij.ml.llm.css.less.completion",
- "intellij.ml.llm.css.nextEdits.backend",
- "intellij.ml.llm.css.postcss.completion",
- "intellij.ml.llm.css.sass.completion",
- "intellij.ml.llm.css.tests",
- "intellij.ml.llm.devkit",
- "intellij.ml.llm.devkit.tests",
- "intellij.ml.llm.diagram.frontend",
- "intellij.ml.llm.domains",
- "intellij.ml.llm.domains.ide",
- "intellij.ml.llm.editor.backend",
- "intellij.ml.llm.editor.common",
- "intellij.ml.llm.editor.frontend",
- "intellij.ml.llm.embeddings",
- "intellij.ml.llm.embeddings.latest",
- "intellij.ml.llm.embeddings.tests",
- "intellij.ml.llm.erb.completion",
- "intellij.ml.llm.erb.completion.tests",
- "intellij.ml.llm.experimental",
- "intellij.ml.llm.experimental.aidiff",
- "intellij.ml.llm.experimental.aidiff.tests",
- "intellij.ml.llm.experimental.build",
- "intellij.ml.llm.experimental.insights",
- "intellij.ml.llm.experimental.insights.java",
- "intellij.ml.llm.experimental.insights.kotlin",
- "intellij.ml.llm.experimental.insights.provenance",
- "intellij.ml.llm.experimental.insights.python",
- "intellij.ml.llm.experimental.insights.tests",
- "intellij.ml.llm.experimental.recap",
- "intellij.ml.llm.experimental.recap.tests",
- "intellij.ml.llm.experiments",
- "intellij.ml.llm.experiments.platformAb",
- "intellij.ml.llm.experiments.platformAb.tests",
- "intellij.ml.llm.experiments.tests",
- "intellij.ml.llm.figma",
- "intellij.ml.llm.git.nextEdits.backend",
- "intellij.ml.llm.github",
- "intellij.ml.llm.github.latest",
- "intellij.ml.llm.gitlab",
- "intellij.ml.llm.go",
- "intellij.ml.llm.go.completion",
- "intellij.ml.llm.go.embeddings",
- "intellij.ml.llm.go.inlinePromptDetector",
- "intellij.ml.llm.go.inlinePromptDetector.tests",
- "intellij.ml.llm.go.nextEdits.backend",
- "intellij.ml.llm.go.tests",
- "intellij.ml.llm.gradle",
- "intellij.ml.llm.groovy.inlinePromptDetector",
- "intellij.ml.llm.html.completion",
- "intellij.ml.llm.html.nextEdits.backend",
- "intellij.ml.llm.html.tests",
- "intellij.ml.llm.httpClient",
- "intellij.ml.llm.idea.product.modules",
- "intellij.ml.llm.ideolog",
- "intellij.ml.llm.inlinePromptDetector",
- "intellij.ml.llm.inlinePromptDetector.tests",
- "intellij.ml.llm.integration.testFramework",
- "intellij.ml.llm.integration.testFramework.tests",
- "intellij.ml.llm.integration.tests",
- "intellij.ml.llm.java",
- "intellij.ml.llm.java.completion",
- "intellij.ml.llm.java.domains",
- "intellij.ml.llm.java.embeddings",
- "intellij.ml.llm.java.embeddings.tests",
- "intellij.ml.llm.java.inlinePromptDetector",
- "intellij.ml.llm.java.inlinePromptDetector.tests",
- "intellij.ml.llm.java.nextEdits.backend",
- "intellij.ml.llm.java.tests",
- "intellij.ml.llm.javaee",
- "intellij.ml.llm.javaee.jpa",
- "intellij.ml.llm.javaee.spring",
- "intellij.ml.llm.javaee.spring.completion",
- "intellij.ml.llm.javaee.spring.data",
- "intellij.ml.llm.javaee.spring.mvc",
- "intellij.ml.llm.javaee.spring.security",
- "intellij.ml.llm.javascript",
- "intellij.ml.llm.javascript.astro",
- "intellij.ml.llm.javascript.astro.completion",
- "intellij.ml.llm.javascript.astro.nextEdits.backend",
- "intellij.ml.llm.javascript.completion",
- "intellij.ml.llm.javascript.embeddings",
- "intellij.ml.llm.javascript.inlinePromptDetector",
- "intellij.ml.llm.javascript.latest",
- "intellij.ml.llm.javascript.nextEdits.backend",
- "intellij.ml.llm.javascript.nextEdits.ultimate.backend",
- "intellij.ml.llm.javascript.svelte",
- "intellij.ml.llm.javascript.svelte.completion",
- "intellij.ml.llm.javascript.svelte.nextEdits.backend",
- "intellij.ml.llm.javascript.tests",
- "intellij.ml.llm.javascript.vue",
- "intellij.ml.llm.javascript.vue.completion",
- "intellij.ml.llm.javascript.vue.nextEdits.backend",
- "intellij.ml.llm.json.completion",
- "intellij.ml.llm.json.nextEdits.backend",
- "intellij.ml.llm.json.tests",
- "intellij.ml.llm.jupyter.common",
- "intellij.ml.llm.jupyter.common.nextEdits.backend",
- "intellij.ml.llm.jupyter.common.nextEdits.frontend",
- "intellij.ml.llm.jupyter.kotlin",
- "intellij.ml.llm.jupyter.kotlin.completion",
- "intellij.ml.llm.jupyter.python",
- "intellij.ml.llm.jupyter.python.completion",
- "intellij.ml.llm.jupyter.python.nextEdits.backend",
- "intellij.ml.llm.jupyter.python.tests",
- "intellij.ml.llm.jupyter.tests",
- "intellij.ml.llm.kotlin",
- "intellij.ml.llm.kotlin.completion",
- "intellij.ml.llm.kotlin.embeddings",
- "intellij.ml.llm.kotlin.inlinePromptDetector",
- "intellij.ml.llm.kotlin.j2k",
- "intellij.ml.llm.kotlin.nextEdits.backend",
- "intellij.ml.llm.kotlin.tests",
- "intellij.ml.llm.libraries.grazie",
- "intellij.ml.llm.libraries.grazie.cloud",
- "intellij.ml.llm.libraries.jcp",
- "intellij.ml.llm.libraries.junie.a2a",
- "intellij.ml.llm.libraries.molecule",
- "intellij.ml.llm.licensetool",
- "intellij.ml.llm.localization",
- "intellij.ml.llm.logicalStructure",
- "intellij.ml.llm.markdown.completion",
- "intellij.ml.llm.markdown.completion.tests",
- "intellij.ml.llm.markdown.nextEdits.backend",
- "intellij.ml.llm.maven",
- "intellij.ml.llm.mcp",
- "intellij.ml.llm.mcp.embedded",
- "intellij.ml.llm.mcp.json",
- "intellij.ml.llm.mcp.perforce",
- "intellij.ml.llm.mcp.tests",
- "intellij.ml.llm.mdx.nextEdits.backend",
- "intellij.ml.llm.microservices",
- "intellij.ml.llm.nextEdits.acp.backend",
- "intellij.ml.llm.nextEdits.agents.backend",
- "intellij.ml.llm.nextEdits.backend",
- "intellij.ml.llm.nextEdits.common",
- "intellij.ml.llm.nextEdits.frontend",
- "intellij.ml.llm.nextEdits.monolith",
- "intellij.ml.llm.nextEdits.testFramework",
- "intellij.ml.llm.nextEdits.tests",
- "intellij.ml.llm.performanceTesting",
- "intellij.ml.llm.performanceTesting.embeddings",
- "intellij.ml.llm.performanceTesting.embeddings.commands",
- "intellij.ml.llm.php",
- "intellij.ml.llm.php.completion",
- "intellij.ml.llm.php.embeddings",
- "intellij.ml.llm.php.inlinePromptDetector",
- "intellij.ml.llm.php.inlinePromptDetector.tests",
- "intellij.ml.llm.php.mcp",
- "intellij.ml.llm.php.mcp.tests",
- "intellij.ml.llm.php.nextEdits.backend",
- "intellij.ml.llm.php.tests",
- "intellij.ml.llm.platform",
- "intellij.ml.llm.playground",
- "intellij.ml.llm.playground.latest",
- "intellij.ml.llm.privacy",
- "intellij.ml.llm.privacy.filter",
- "intellij.ml.llm.privacy.shared",
- "intellij.ml.llm.privacy.shared.tests",
- "intellij.ml.llm.privacy.tests",
- "intellij.ml.llm.properties.completion",
- "intellij.ml.llm.properties.completion.tests",
- "intellij.ml.llm.provider",
- "intellij.ml.llm.provider.anthropic",
- "intellij.ml.llm.provider.google",
- "intellij.ml.llm.provider.lmstudio",
- "intellij.ml.llm.provider.ollama",
- "intellij.ml.llm.provider.ollama.tests",
- "intellij.ml.llm.provider.openai",
- "intellij.ml.llm.provider.openai.tests",
- "intellij.ml.llm.python",
- "intellij.ml.llm.python.completion",
- "intellij.ml.llm.python.domains",
- "intellij.ml.llm.python.embeddings",
- "intellij.ml.llm.python.inlinePromptDetector",
- "intellij.ml.llm.python.nextEdits.backend",
- "intellij.ml.llm.python.tests",
- "intellij.ml.llm.python.ultimate",
- "intellij.ml.llm.qodana",
- "intellij.ml.llm.qodana.agents",
- "intellij.ml.llm.qodana.agents.tests",
- "intellij.ml.llm.qodana.common",
- "intellij.ml.llm.qodana.inspectionKts",
- "intellij.ml.llm.qodana.inspectionKts.tests",
- "intellij.ml.llm.qodana.inspectionsGenerator",
- "intellij.ml.llm.rbs.completion",
- "intellij.ml.llm.rbs.completion.tests",
- "intellij.ml.llm.rider",
- "intellij.ml.llm.rider.cpp",
- "intellij.ml.llm.rider.cpp.completion",
- "intellij.ml.llm.rider.cpp.nextEdits.backend",
- "intellij.ml.llm.rider.csharp",
- "intellij.ml.llm.rider.csharp.completion",
- "intellij.ml.llm.rider.csharp.inlinePromptDetector",
- "intellij.ml.llm.rider.csharp.nextEdits.backend",
- "intellij.ml.llm.rider.csharp.razor",
- "intellij.ml.llm.rider.dotTools",
- "intellij.ml.llm.rider.fsharp",
- "intellij.ml.llm.rider.fsharp.completion",
- "intellij.ml.llm.rider.godot.completion",
- "intellij.ml.llm.rider.hlsl.completion",
- "intellij.ml.llm.rider.shaderlab.completion",
- "intellij.ml.llm.rider.unrealengine.completion",
- "intellij.ml.llm.ruby",
- "intellij.ml.llm.ruby.completion",
- "intellij.ml.llm.ruby.embeddings",
- "intellij.ml.llm.ruby.embeddings.tests",
- "intellij.ml.llm.ruby.inlinePromptDetector",
- "intellij.ml.llm.ruby.inlinePromptDetector.tests",
- "intellij.ml.llm.ruby.mcp",
- "intellij.ml.llm.ruby.mcp.tests",
- "intellij.ml.llm.ruby.nextEdits.backend",
- "intellij.ml.llm.ruby.test",
- "intellij.ml.llm.rust",
- "intellij.ml.llm.rust.completion",
- "intellij.ml.llm.rust.nextEdits.backend",
- "intellij.ml.llm.rust.test",
- "intellij.ml.llm.sandbox",
- "intellij.ml.llm.sandbox.build",
- "intellij.ml.llm.sandbox.selfReviewDaemon",
- "intellij.ml.llm.sandbox.spec",
- "intellij.ml.llm.sandbox.spec.mcp",
- "intellij.ml.llm.sandbox.spec.wysiwyg",
- "intellij.ml.llm.searchEverywhere",
- "intellij.ml.llm.searchEverywhere.embeddings",
- "intellij.ml.llm.searchEverywhere.embeddings.datagrip",
- "intellij.ml.llm.searchEverywhere.embeddings.radler",
- "intellij.ml.llm.searchEverywhere.embeddings.rider",
- "intellij.ml.llm.searchEverywhere.embeddings.rider.tests",
- "intellij.ml.llm.searchEverywhere.tests",
- "intellij.ml.llm.sh",
- "intellij.ml.llm.smartChat",
- "intellij.ml.llm.smartChat.embeddings",
- "intellij.ml.llm.space",
- "intellij.ml.llm.space.latest",
- "intellij.ml.llm.sql",
- "intellij.ml.llm.sql.completion",
- "intellij.ml.llm.sql.completion.tests",
- "intellij.ml.llm.sql.datagrip",
- "intellij.ml.llm.sql.embeddings",
- "intellij.ml.llm.sql.inlinePromptDetector",
- "intellij.ml.llm.sql.inlinePromptDetector.tests",
- "intellij.ml.llm.sql.tests",
- "intellij.ml.llm.starter",
- "intellij.ml.llm.starter.tests",
- "intellij.ml.llm.tasks",
- "intellij.ml.llm.telemetry",
- "intellij.ml.llm.terminal",
- "intellij.ml.llm.terminal.completion",
- "intellij.ml.llm.terminal.completion.tests",
- "intellij.ml.llm.terminal.context",
- "intellij.ml.llm.terminal.context.tests",
- "intellij.ml.llm.terminal.tests",
- "intellij.ml.llm.terraform.completion",
- "intellij.ml.llm.tests",
- "intellij.ml.llm.testsWithKotlinAndJava",
- "intellij.ml.llm.testsWithPython",
- "intellij.ml.llm.text.completion",
- "intellij.ml.llm.textmate",
- "intellij.ml.llm.textmate.tests",
- "intellij.ml.llm.tokenizer",
- "intellij.ml.llm.tokenizer.tests",
- "intellij.ml.llm.uiTestGeneration",
- "intellij.ml.llm.vcs",
- "intellij.ml.llm.vcs.completion",
- "intellij.ml.llm.vcs.completion.tests",
- "intellij.ml.llm.vcs.core",
- "intellij.ml.llm.vcs.latest",
- "intellij.ml.llm.vcs.markdown",
- "intellij.ml.llm.vcs.tests",
- "intellij.ml.llm.voice",
- "intellij.ml.llm.xdebugger.completion",
- "intellij.ml.llm.xdebugger.completion.tests",
- "intellij.ml.llm.xml.completion",
- "intellij.ml.llm.xml.nextEdits.backend",
- "intellij.ml.llm.xml.tests",
- "intellij.ml.llm.yaml.completion",
- "intellij.ml.llm.yaml.inlinePromptDetector",
- "intellij.ml.llm.yaml.inlinePromptDetector.tests",
- "intellij.ml.llm.yaml.javaee.spring.completion",
- "intellij.ml.llm.yaml.json.completion",
- "intellij.ml.llm.yaml.nextEdits.backend",
- "intellij.ml.llm.yaml.tests",
- "intellij.platform.recentFiles",
- "intellij.platform.recentFiles.backend",
- "intellij.platform.recentFiles.frontend",
- "intellij.platform.recentFiles.plugin",
- "intellij.swagger",
- "intellij.swagger.codegen",
- "intellij.swagger.core",
- "intellij.swagger.core.tests",
- "intellij.swagger.endpoints",
- "intellij.swagger.endpoints.tests",
- "intellij.swagger.gradle",
- "intellij.swagger.java",
- "intellij.swagger.maven",
- "intellij.hibernate.debugger",
- "intellij.hibernate.debugger.core",
- "intellij.hibernate.debugger.ide"
- ]
+ "moduleNames": []
}
diff --git a/plugins/devkit/devkit-core/src/dom/impl/PluginDescriptorDomFileDescription.java b/plugins/devkit/devkit-core/src/dom/impl/PluginDescriptorDomFileDescription.java
index d586ebdc95ac..cdeae327a79c 100644
--- a/plugins/devkit/devkit-core/src/dom/impl/PluginDescriptorDomFileDescription.java
+++ b/plugins/devkit/devkit-core/src/dom/impl/PluginDescriptorDomFileDescription.java
@@ -25,11 +25,9 @@ final class PluginDescriptorDomFileDescription extends DomFileDescription = listOf(
+ ".idea/scopes/$SPLIT_MODE_EXCLUDED_MODULES_SCOPE_FILE_NAME",
+ ".idea.bazel/scopes/$SPLIT_MODE_EXCLUDED_MODULES_SCOPE_FILE_NAME",
+)
+
+internal fun createSplitModeExcludedModulesScopeXml(
+ resourceReader: SplitModeInspectionResourceReader,
+ readMode: SplitModeInspectionResourceReadMode,
+): String {
+ val configurationText = requireNotNull(
+ resourceReader.readText(MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RESOURCE_PATH, readMode)
+ ) {
+ "Cannot load $MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH"
+ }
+ return createSplitModeExcludedModulesScopeXml(configurationText)
+}
+
+internal fun createSplitModeExcludedModulesScopeXml(json5Text: String): String {
+ val configuration = parseMonorepoFeaturesWithoutSplitModeSupport(json5Text)
+ val scopePattern = createSplitModeExcludedModulesScopePattern(configuration)
+ return """
+
+
+
+ """.trimIndent() + "\n"
+}
+
+private fun parseMonorepoFeaturesWithoutSplitModeSupport(json5Text: String): MonorepoFeaturesWithoutSplitModeSupportFile {
+ val normalizedJson = try {
+ json5.readTree(json5Text).toString()
+ }
+ catch (e: JsonProcessingException) {
+ throw IllegalArgumentException("Cannot parse $MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH", e)
+ }
+ catch (e: IOException) {
+ throw IllegalArgumentException("Cannot parse $MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH", e)
+ }
+
+ val configuration = try {
+ json.decodeFromString(normalizedJson)
+ }
+ catch (e: SerializationException) {
+ throw IllegalArgumentException("Cannot parse $MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH", e)
+ }
+ catch (e: IllegalArgumentException) {
+ throw IllegalArgumentException("Cannot parse $MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH", e)
+ }
+
+ validateEntries("pathPatterns", configuration.pathPatterns) { entry ->
+ require(!entry.startsWith("file:")) {
+ "pathPatterns entries must not include the generated 'file:' prefix: $entry"
+ }
+ }
+ validateEntries("moduleNames", configuration.moduleNames) { entry ->
+ require('/' !in entry && '[' !in entry && ']' !in entry) {
+ "moduleNames entries must be raw module names: $entry"
+ }
+ }
+ return configuration
+}
+
+private fun createSplitModeExcludedModulesScopePattern(configuration: MonorepoFeaturesWithoutSplitModeSupportFile): String {
+ val pathPatterns = configuration.pathPatterns.map { "file:$it" }
+ val modulePatterns = configuration.moduleNames.map { "file[$it]:*/" }
+ val patterns = pathPatterns + modulePatterns
+ require(patterns.isNotEmpty()) {
+ "$MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH must define at least one pathPatterns or moduleNames entry"
+ }
+ require(patterns.size == patterns.toSet().size) {
+ "$MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH contains entries that generate duplicate scope patterns"
+ }
+ return patterns.joinToString("||")
+}
+
+private fun validateEntries(
+ fieldName: String,
+ entries: List,
+ validateEntry: (String) -> Unit,
+) {
+ val duplicates = entries.groupingBy { it }.eachCount().filterValues { it > 1 }.keys
+ require(duplicates.isEmpty()) {
+ "$MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH contains duplicate $fieldName entries: ${duplicates.joinToString()}"
+ }
+
+ for (entry in entries) {
+ require(entry.isNotBlank()) {
+ "$MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH contains blank $fieldName entry"
+ }
+ require(entry == entry.trim()) {
+ "$MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH contains $fieldName entry with leading or trailing whitespace: $entry"
+ }
+ require("||" !in entry) {
+ "$MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH entries must not contain scope pattern separators: $entry"
+ }
+ validateEntry(entry)
+ }
+}
+
+private fun String.escapeXmlAttributeValue(): String {
+ return buildString(length) {
+ for (character in this@escapeXmlAttributeValue) {
+ when (character) {
+ '&' -> append("&")
+ '"' -> append(""")
+ '<' -> append("<")
+ '>' -> append(">")
+ else -> append(character)
+ }
+ }
+ }
+}
+
+@Serializable
+private data class MonorepoFeaturesWithoutSplitModeSupportFile(
+ @SerialName("pathPatterns")
+ val pathPatterns: List = emptyList(),
+
+ @SerialName("moduleNames")
+ val moduleNames: List = emptyList(),
+)
+
+private val json5: ObjectMapper = JsonMapper.builder()
+ .enable(
+ JsonReadFeature.ALLOW_JAVA_COMMENTS,
+ JsonReadFeature.ALLOW_SINGLE_QUOTES,
+ JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES,
+ JsonReadFeature.ALLOW_TRAILING_COMMA,
+ )
+ .build()
+
+private val json = Json {
+ ignoreUnknownKeys = true
+ isLenient = true
+}
diff --git a/plugins/devkit/devkit-core/src/inspections/remotedev/OWNERSHIP b/plugins/devkit/devkit-core/src/inspections/remotedev/OWNERSHIP
new file mode 100644
index 000000000000..ae0e0a60ad1c
--- /dev/null
+++ b/plugins/devkit/devkit-core/src/inspections/remotedev/OWNERSHIP
@@ -0,0 +1 @@
+owner 'RD Split Kernel'
\ No newline at end of file
diff --git a/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeApiUsageInspection.kt b/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeApiUsageInspection.kt
index 33a1814122d2..33101d897113 100644
--- a/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeApiUsageInspection.kt
+++ b/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeApiUsageInspection.kt
@@ -17,7 +17,7 @@ import org.jetbrains.annotations.VisibleForTesting
import org.jetbrains.idea.devkit.inspections.DevKitUastInspectionBase
import org.jetbrains.idea.devkit.inspections.remotedev.SplitModeInspectionUtil.buildModuleKindMismatchMessage
import org.jetbrains.idea.devkit.inspections.remotedev.SplitModeInspectionUtil.buildModuleKindMismatchTooltipMessage
-import org.jetbrains.idea.devkit.inspections.remotedev.analysis.SplitModeModuleKindResolver.doesApiKindMatchExpectedModuleKind
+import org.jetbrains.idea.devkit.inspections.remotedev.analysis.SplitModeModuleKindResolver.isApiUsageAllowed
import org.jetbrains.idea.devkit.inspections.remotedev.analysis.ModuleAnalysis
import org.jetbrains.idea.devkit.inspections.remotedev.analysis.SplitModeApiRestrictionsService
import org.jetbrains.idea.devkit.inspections.remotedev.analysis.SplitModeQodanaInspectionScopeLimiter
@@ -26,7 +26,6 @@ import org.jetbrains.uast.UCallExpression
import org.jetbrains.uast.UClass
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UExpression
-import org.jetbrains.uast.UField
import org.jetbrains.uast.UMethod
import org.jetbrains.uast.UQualifiedReferenceExpression
import org.jetbrains.uast.USimpleNameReferenceExpression
@@ -38,7 +37,7 @@ import org.jetbrains.uast.visitor.AbstractUastVisitor
@VisibleForTesting
@ApiStatus.Internal
-class SplitModeApiUsageInspection : DevKitUastInspectionBase(UClass::class.java, UField::class.java, UMethod::class.java) {
+class SplitModeApiUsageInspection : DevKitUastInspectionBase(UClass::class.java, UMethod::class.java) {
override fun isAllowed(holder: ProblemsHolder): Boolean {
return super.isAllowed(holder)
@@ -115,29 +114,25 @@ class SplitModeApiUsageInspection : DevKitUastInspectionBase(UClass::class.java,
val resolvedApi = resolveApiUsage(expression) ?: return
val sourcePsi = expression.sourcePsi ?: return
val restrictionsService = SplitModeApiRestrictionsService.getInstance(sourcePsi.project)
- val expectedModuleKind = restrictionsService.getCodeApiKind(resolvedApi.qualifiedName, resolvedApi.owner) ?: return
+ val apiRestriction = restrictionsService.getCodeApiRestriction(resolvedApi.qualifiedName, resolvedApi.owner) ?: return
+ val expectedModuleKind = apiRestriction.targetModuleKind
val currentModuleType = currentModuleAnalysis.resolvedModuleKind
- if (!doesApiKindMatchExpectedModuleKind(currentModuleType, expectedModuleKind)) {
+ if (!isApiUsageAllowed(currentModuleAnalysis, apiRestriction)) {
val hint = restrictionsService.getCodeApiHint(resolvedApi.qualifiedName)
val message = buildModuleKindMismatchMessage(resolvedApi.qualifiedName, expectedModuleKind, currentModuleType, hint)
val tooltipMessage = buildModuleKindMismatchTooltipMessage(resolvedApi.qualifiedName, expectedModuleKind, currentModuleType, hint)
val module = ModuleUtilCore.findModuleForPsiElement(sourcePsi) ?: return
- if (SplitModeInspectionExclusionsService.getInstance(sourcePsi.project).isExcluded(sourcePsi, SPLIT_MODE_API_USAGE_SHORT_NAME)) {
- return
- }
val regularFixes = SplitModeDependencyQuickFixes.createMismatchFixes(module, null, expectedModuleKind)
- val suppressionFix =
- SplitModeInspectionExclusionsService.getInstance(sourcePsi.project).createSuppressionFixIfApplicable(sourcePsi,
- SPLIT_MODE_API_USAGE_SHORT_NAME)
- val fixes = if (suppressionFix != null) regularFixes + suppressionFix else regularFixes
+ val suppressionFixes = SplitModeInspectionExclusionsService.getInstance(sourcePsi.project).createCommonSuppressionQuickFixes()
+ val fixes = regularFixes + suppressionFixes
descriptors.add(
manager.createProblemDescriptor(
sourcePsi,
null,
message,
- ProblemHighlightType.WEAK_WARNING,
+ ProblemHighlightType.WARNING,
tooltipMessage,
isOnTheFly,
*fixes,
diff --git a/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeDependencyQuickFixes.kt b/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeDependencyQuickFixes.kt
index 849934867a5d..d64331f077dd 100644
--- a/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeDependencyQuickFixes.kt
+++ b/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeDependencyQuickFixes.kt
@@ -1,6 +1,7 @@
// Copyright 2000-2026 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.remotedev
+import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
@@ -188,18 +189,29 @@ internal object SplitModeDependencyQuickFixes {
override fun startInWriteAction(): Boolean = IntentionPreviewUtils.isIntentionPreviewActive()
+ override fun generatePreview(project: Project, previewDescriptor: ProblemDescriptor): IntentionPreviewInfo {
+ if (previewDescriptor.psiElement.containingFile !is XmlFile) {
+ return IntentionPreviewInfo.EMPTY
+ }
+ return super.generatePreview(project, previewDescriptor)
+ }
+
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val ideaPlugin = findQuickFixTargetDescriptor(descriptor) ?: return
val module = findTargetModule(descriptor)
val xmlFile = ideaPlugin.xmlElement?.containingFile ?: return
- if (!IntentionPreviewUtils.prepareElementForWrite(xmlFile)) return
if (IntentionPreviewUtils.isIntentionPreviewActive()) {
- applyDependencyFixInPreview(ideaPlugin, module, desiredModuleKind)
+ if (IntentionPreviewUtils.isPreviewElement(xmlFile)) {
+ applyDependencyFixInPreview(ideaPlugin, module, desiredModuleKind)
+ }
return
}
- val commandName: @NlsContexts.Command String = message("inspection.remote.dev.make.only.kind.dependencies.fix.progress.title", desiredModuleKind.id)
+ if (!IntentionPreviewUtils.prepareElementForWrite(xmlFile)) return
+
+ val commandName: @NlsContexts.Command String =
+ message("inspection.remote.dev.make.only.kind.dependencies.fix.progress.title", desiredModuleKind.id)
runWithModalProgressBlocking(project, commandName) {
applyDependencyFix(project, ideaPlugin, module, desiredModuleKind, commandName)
@@ -223,18 +235,29 @@ internal object SplitModeDependencyQuickFixes {
override fun startInWriteAction(): Boolean = IntentionPreviewUtils.isIntentionPreviewActive()
+ override fun generatePreview(project: Project, previewDescriptor: ProblemDescriptor): IntentionPreviewInfo {
+ if (previewDescriptor.psiElement.containingFile !is XmlFile) {
+ return IntentionPreviewInfo.EMPTY
+ }
+ return super.generatePreview(project, previewDescriptor)
+ }
+
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val ideaPlugin = findQuickFixTargetDescriptor(descriptor) ?: return
val module = findTargetModule(descriptor)
val xmlFile = ideaPlugin.xmlElement?.containingFile ?: return
- if (!IntentionPreviewUtils.prepareElementForWrite(xmlFile)) return
if (IntentionPreviewUtils.isIntentionPreviewActive()) {
- applyDependencyFixInPreview(ideaPlugin, module, desiredModuleKind)
+ if (IntentionPreviewUtils.isPreviewElement(xmlFile)) {
+ applyDependencyFixInPreview(ideaPlugin, module, desiredModuleKind)
+ }
return
}
- val commandName: @NlsContexts.Command String = message("inspection.remote.dev.make.only.kind.dependencies.fix.progress.title", desiredModuleKind.id)
+ if (!IntentionPreviewUtils.prepareElementForWrite(xmlFile)) return
+
+ val commandName: @NlsContexts.Command String =
+ message("inspection.remote.dev.make.only.kind.dependencies.fix.progress.title", desiredModuleKind.id)
runWithModalProgressBlocking(project, commandName) {
applyDependencyFix(project, ideaPlugin, module, desiredModuleKind, commandName)
diff --git a/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeImplicitModuleKindInspection.kt b/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeImplicitModuleKindInspection.kt
index 4f45ae10d714..c555bf4a8a4c 100644
--- a/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeImplicitModuleKindInspection.kt
+++ b/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeImplicitModuleKindInspection.kt
@@ -28,11 +28,8 @@ internal class SplitModeImplicitModuleKindInspection : DevKitPluginXmlInspection
val module = element.module ?: return
val currentXmlFile = holder.fileElement.file
- val xmlElement = element.xmlElement ?: return
+ if (element.xmlElement == null) return
val exclusionsService = SplitModeInspectionExclusionsService.getInstance(currentXmlFile.project)
- if (exclusionsService.isExcluded(xmlElement, SPLIT_MODE_IMPLICIT_MODULE_KIND_SHORT_NAME)) {
- return
- }
val moduleAnalysis = SplitModeModuleKindResolver.getOrComputeModuleAnalysis(module, currentXmlFile)
if (!SplitModeInspectionUtil.isImplicitFrontendOrBackendMainPluginXml(currentXmlFile, moduleAnalysis)) {
@@ -41,11 +38,8 @@ internal class SplitModeImplicitModuleKindInspection : DevKitPluginXmlInspection
val regularFixes =
SplitModeDependencyQuickFixes.createAddExplicitDependenciesFixes(module, element, moduleAnalysis.resolvedModuleKind.kind)
- val suppressionFix = exclusionsService.createSuppressionFixIfApplicable(
- xmlElement,
- SPLIT_MODE_IMPLICIT_MODULE_KIND_SHORT_NAME,
- )
- val quickFixes = if (suppressionFix != null) regularFixes + suppressionFix else regularFixes
+ val suppressionFixes = exclusionsService.createCommonSuppressionQuickFixes()
+ val quickFixes = regularFixes + suppressionFixes
holder.createProblem(
element,
ProblemHighlightType.WEAK_WARNING,
diff --git a/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeInspectionExclusions.kt b/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeInspectionExclusions.kt
index b04fda16d873..90708497040c 100644
--- a/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeInspectionExclusions.kt
+++ b/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeInspectionExclusions.kt
@@ -3,7 +3,6 @@
package org.jetbrains.idea.devkit.inspections.remotedev
-import com.intellij.codeInsight.intention.FileModifier.SafeTypeForPreview
import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
@@ -12,7 +11,6 @@ import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.diagnostic.logger
-import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.fileEditor.OpenFileDescriptor
import com.intellij.openapi.project.IntelliJProjectUtil
import com.intellij.openapi.project.Project
@@ -21,9 +19,8 @@ import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.writeText
-import com.intellij.psi.PsiDocumentManager
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiFile
+import com.fasterxml.jackson.core.json.JsonReadFeature
+import com.fasterxml.jackson.databind.json.JsonMapper
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationException
@@ -31,24 +28,9 @@ import kotlinx.serialization.json.Json
import org.jetbrains.idea.devkit.DevKitBundle.message
import java.io.IOException
-internal const val EXCLUSIONS_FILE_NAME: String = "DevKitSplitModeInspectionExclusions.json"
-internal const val EXCLUSIONS_RESOURCE_PATH: String = "remotedevInspectionData/$EXCLUSIONS_FILE_NAME"
-internal const val EXCLUSIONS_RELATIVE_PATH: String =
- "community/plugins/devkit/devkit-core/resources/$EXCLUSIONS_RESOURCE_PATH"
-
-internal const val SPLIT_MODE_API_USAGE_SHORT_NAME: String = "SplitModeApiUsage"
-internal const val SPLIT_MODE_XML_API_USAGE_SHORT_NAME: String = "SplitModeXmlApiUsage"
-internal const val SPLIT_MODE_MIXED_DEPENDENCIES_SHORT_NAME: String = "SplitModeMixedDependencies"
-internal const val SPLIT_MODE_IMPLICIT_MODULE_KIND_SHORT_NAME: String = "SplitModeImplicitModuleKind"
-internal const val MISSING_RUNTIME_DEPENDENCY_SHORT_NAME: String = "MissingFrontendOrBackendRuntimeDependency"
-
-@SafeTypeForPreview
-internal data class SplitModeInspectionExclusionProblem(
- val inspection: String,
- val file: String,
- val line: Int,
- val reason: String = "",
-)
+internal const val PROJECT_BASELINE_VERSION_FILE_NAME: String = "SplitModeProjectBaselineVersion.json5"
+internal const val PROJECT_BASELINE_VERSION_RELATIVE_PATH: String =
+ "community/plugins/devkit/devkit-core/resources/remotedevInspectionData/$PROJECT_BASELINE_VERSION_FILE_NAME"
@Service(Service.Level.PROJECT)
internal class SplitModeInspectionExclusionsService(private val project: Project) {
@@ -56,55 +38,22 @@ internal class SplitModeInspectionExclusionsService(private val project: Project
fun getInstance(project: Project): SplitModeInspectionExclusionsService = project.service()
}
- private val resourceReader = SplitModeInspectionResourceReader.getInstance(project)
-
- private val exclusionsResource = object : SplitModeInspectionReloadableResource(
- resourceReader = resourceReader,
- resourcePath = EXCLUSIONS_RESOURCE_PATH,
- readMode = SplitModeInspectionResourceReadMode.PROJECT_ONLY,
- ) {
- override fun parse(text: String): SplitModeInspectionExclusionsSnapshot {
- return SplitModeInspectionExclusionsSnapshot(parseExclusionsFile(text).exclusions)
- }
-
- override fun getDefaultValue(): SplitModeInspectionExclusionsSnapshot {
- return SplitModeInspectionExclusionsSnapshot()
- }
+ fun createCommonSuppressionQuickFixes(): Array {
+ if (!isBaselineFixAvailable()) return LocalQuickFix.EMPTY_ARRAY
+ return arrayOf(IncreaseSplitModeProjectBaselineVersionFix())
}
- fun createSuppressionFixIfApplicable(
- element: PsiElement,
- inspectionShortName: String,
- ): LocalQuickFix? {
- if (!isExclusionFixAvailable()) return null
- val problem = createProblem(inspectionShortName, element) ?: return null
- return AddToSplitModeInspectionExclusionsFix(problem)
+ fun increaseProjectBaselineVersion(): VirtualFile? {
+ val baselineVersionFile = findOrCreateProjectBaselineVersionFile() ?: return null
+ val currentFile = parseProjectBaselineVersionFile(VfsUtilCore.loadText(baselineVersionFile))
+ val updatedFile = currentFile.copy(
+ currentProjectBaselineVersion = currentFile.currentProjectBaselineVersion + 1,
+ )
+ baselineVersionFile.writeText(createProjectBaselineVersionJson5(updatedFile))
+ return baselineVersionFile
}
- fun isExcluded(element: PsiElement, inspectionShortName: String): Boolean {
- val problem = createProblem(inspectionShortName, element) ?: return false
- return isExcluded(problem)
- }
-
- fun isExcluded(problem: SplitModeInspectionExclusionProblem): Boolean {
- return getSnapshot().exclusions.any { it.matches(problem) }
- }
-
- fun appendExclusion(problem: SplitModeInspectionExclusionProblem): VirtualFile? {
- val exclusionsFile = findOrCreateExclusionsFile() ?: return null
- val currentFile = SplitModeInspectionExclusionsFile(getSnapshot().exclusions)
- val newEntry = problem.toEntry()
- if (currentFile.exclusions.any { it.matches(newEntry) }) {
- return exclusionsFile
- }
-
- val updatedFile = currentFile.copy(exclusions = currentFile.exclusions + newEntry)
- exclusionsFile.writeText(json.encodeToString(updatedFile) + "\n")
- exclusionsResource.invalidate()
- return exclusionsFile
- }
-
- private fun isExclusionFixAvailable(): Boolean {
+ private fun isBaselineFixAvailable(): Boolean {
return IntelliJProjectUtil.isIntelliJPlatformProject(project) && getProjectRoot() != null
}
@@ -112,152 +61,98 @@ internal class SplitModeInspectionExclusionsService(private val project: Project
return project.guessProjectDir()
}
- private fun getProjectRelativePath(file: PsiFile): String? {
- val virtualFile = file.originalFile.virtualFile ?: file.virtualFile ?: return null
- val projectRoot = getProjectRoot() ?: return null
- return VfsUtilCore.getRelativePath(virtualFile, projectRoot, '/')
- }
-
- private fun createProblem(
- inspectionShortName: String,
- element: PsiElement,
- ): SplitModeInspectionExclusionProblem? {
- val file = element.containingFile ?: return null
- val filePath = getProjectRelativePath(file) ?: return null
- val line = getLineNumber(file, element) ?: return null
- return SplitModeInspectionExclusionProblem(
- inspection = inspectionShortName,
- file = filePath,
- line = line,
- reason = "",
- )
- }
-
- private fun getLineNumber(file: PsiFile, element: PsiElement): Int? {
- val document = PsiDocumentManager.getInstance(file.project).getDocument(file)
- ?: file.viewProvider.document
- ?: return null
- return document.getLineNumber(element.textRange.startOffset) + 1
- }
-
- private fun getSnapshot(): SplitModeInspectionExclusionsSnapshot {
- return exclusionsResource.getValue()
- }
-
- private fun findOrCreateExclusionsFile(): VirtualFile? {
+ private fun findOrCreateProjectBaselineVersionFile(): VirtualFile? {
val projectRoot = getProjectRoot() ?: return null
return try {
val parentDirectory = VfsUtil.createDirectoryIfMissing(projectRoot, EXCLUSIONS_DIRECTORY_RELATIVE_PATH)
- parentDirectory.findChild(EXCLUSIONS_FILE_NAME)
- ?: parentDirectory.createChildData(this, EXCLUSIONS_FILE_NAME).also { file ->
- file.writeText(INITIAL_EXCLUSIONS_JSON)
+ parentDirectory.findChild(PROJECT_BASELINE_VERSION_FILE_NAME)
+ ?: parentDirectory.createChildData(this, PROJECT_BASELINE_VERSION_FILE_NAME).also { file ->
+ file.writeText(createProjectBaselineVersionJson5(SplitModeProjectBaselineVersionFile(currentProjectBaselineVersion = 0)))
}
}
catch (e: IOException) {
- LOG.warn("Cannot create $EXCLUSIONS_RELATIVE_PATH", e)
+ LOG.warn("Cannot create $PROJECT_BASELINE_VERSION_RELATIVE_PATH", e)
null
}
}
- private fun parseExclusionsFile(text: String): SplitModeInspectionExclusionsFile {
+ private fun parseProjectBaselineVersionFile(text: String): SplitModeProjectBaselineVersionFile {
if (text.isBlank()) {
- return SplitModeInspectionExclusionsFile()
+ return SplitModeProjectBaselineVersionFile(currentProjectBaselineVersion = 0)
}
return try {
- json.decodeFromString(text)
+ val normalizedJson = json5.readTree(text).toString()
+ json.decodeFromString(normalizedJson)
}
catch (e: SerializationException) {
- LOG.warn("Cannot parse $EXCLUSIONS_RELATIVE_PATH", e)
- SplitModeInspectionExclusionsFile()
+ LOG.warn("Cannot parse $PROJECT_BASELINE_VERSION_RELATIVE_PATH", e)
+ SplitModeProjectBaselineVersionFile(currentProjectBaselineVersion = 0)
+ }
+ catch (e: IOException) {
+ LOG.warn("Cannot parse $PROJECT_BASELINE_VERSION_RELATIVE_PATH", e)
+ SplitModeProjectBaselineVersionFile(currentProjectBaselineVersion = 0)
}
catch (e: IllegalArgumentException) {
- LOG.warn("Cannot parse $EXCLUSIONS_RELATIVE_PATH", e)
- SplitModeInspectionExclusionsFile()
+ LOG.warn("Cannot parse $PROJECT_BASELINE_VERSION_RELATIVE_PATH", e)
+ SplitModeProjectBaselineVersionFile(currentProjectBaselineVersion = 0)
}
}
-
- private fun SplitModeInspectionExclusionEntry.matches(problem: SplitModeInspectionExclusionProblem): Boolean {
- if (inspection != problem.inspection) return false
- if (file != problem.file) return false
- if (line != problem.line) return false
- return true
- }
-
- private fun SplitModeInspectionExclusionEntry.matches(other: SplitModeInspectionExclusionEntry): Boolean {
- if (inspection != other.inspection) return false
- if (file != other.file) return false
- if (line != other.line) return false
- return true
- }
-
- private fun SplitModeInspectionExclusionProblem.toEntry(): SplitModeInspectionExclusionEntry {
- return SplitModeInspectionExclusionEntry(
- inspection = inspection,
- file = file,
- line = line,
- reason = reason,
- )
- }
}
-private class AddToSplitModeInspectionExclusionsFix(
- private val problem: SplitModeInspectionExclusionProblem,
-) : LocalQuickFix, LowPriorityAction {
+private class IncreaseSplitModeProjectBaselineVersionFix : LocalQuickFix, LowPriorityAction {
override fun getName(): String = familyName
override fun getFamilyName(): String {
- return message("inspection.remote.dev.add.to.split.mode.exclusions.fix.name")
+ return message("inspection.remote.dev.increase.split.mode.baseline.fix.name")
}
override fun startInWriteAction(): Boolean = false
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
- val exclusionsFile = WriteCommandAction.writeCommandAction(project)
- .withName(message("inspection.remote.dev.add.to.split.mode.exclusions.command.name"))
+ val baselineVersionFile = WriteCommandAction.writeCommandAction(project)
+ .withName(message("inspection.remote.dev.increase.split.mode.baseline.command.name"))
.compute {
- SplitModeInspectionExclusionsService.getInstance(project).appendExclusion(problem)
+ SplitModeInspectionExclusionsService.getInstance(project).increaseProjectBaselineVersion()
}
- if (exclusionsFile == null) {
+ if (baselineVersionFile == null) {
return
}
- val document = FileDocumentManager.getInstance().getDocument(exclusionsFile)
- val lastLine = maxOf((document?.lineCount ?: 1) - 1, 0)
- OpenFileDescriptor(project, exclusionsFile, lastLine, 0).navigate(true)
+ OpenFileDescriptor(project, baselineVersionFile, 0, 0).navigate(true)
}
}
-private data class SplitModeInspectionExclusionsSnapshot(
- val exclusions: List = emptyList(),
-)
-
@Serializable
-internal data class SplitModeInspectionExclusionsFile(
- @SerialName("exclusions")
- val exclusions: List = emptyList(),
-)
-
-@Serializable
-internal data class SplitModeInspectionExclusionEntry(
- @SerialName("inspection")
- val inspection: String,
-
- @SerialName("file")
- val file: String = "",
-
- @SerialName("line")
- val line: Int = -1,
-
- @SerialName("reason")
- val reason: String? = null,
+private data class SplitModeProjectBaselineVersionFile(
+ @SerialName("currentProjectBaselineVersion")
+ val currentProjectBaselineVersion: Int,
)
private val LOG: Logger = logger()
private const val EXCLUSIONS_DIRECTORY_RELATIVE_PATH: String = "community/plugins/devkit/devkit-core/resources/remotedevInspectionData"
-private const val INITIAL_EXCLUSIONS_JSON: String = "{ \"exclusions\": [] }\n"
+private val json5 = JsonMapper.builder()
+ .enable(
+ JsonReadFeature.ALLOW_JAVA_COMMENTS,
+ JsonReadFeature.ALLOW_SINGLE_QUOTES,
+ JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES,
+ JsonReadFeature.ALLOW_TRAILING_COMMA,
+ )
+ .build()
+
+private fun createProjectBaselineVersionJson5(file: SplitModeProjectBaselineVersionFile): String {
+ return """
+ // The file carries the current project baseline version for Split Mode Compatibility safe-push checks.
+ // Increase currentProjectBaselineVersion only when incremental Split Mode Compatibility tests incorrectly
+ // report pre-existing violations after large refactorings.
+ // Changing this value is a legal bypass: the affected safe push may skip the incremental Split Mode
+ // Compatibility tests for that run, allowing the refactoring to proceed while the baseline catches up.
+ // Do not use it for real new violations. Fix those instead; see Split Mode documentation IJPL-A-632.
+ // Contact the RemDev team in #ij-remote-dev if unsure.
+ """.trimIndent() + "\n" + json.encodeToString(file) + "\n"
+}
private val json = Json {
ignoreUnknownKeys = true
diff --git a/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeInspectionUtil.kt b/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeInspectionUtil.kt
index d8d3b865685b..d0c544366deb 100644
--- a/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeInspectionUtil.kt
+++ b/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeInspectionUtil.kt
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nls
import org.jetbrains.idea.devkit.DevKitBundle
import org.jetbrains.idea.devkit.dom.ContentDescriptor.ModuleDescriptor
import org.jetbrains.idea.devkit.dom.index.PluginIdDependenciesIndex
+import org.jetbrains.idea.devkit.inspections.remotedev.analysis.ApiUsagePolicy
import org.jetbrains.idea.devkit.inspections.remotedev.analysis.ModuleAnalysis
import org.jetbrains.idea.devkit.inspections.remotedev.analysis.ResolvedModuleKind
import org.jetbrains.idea.devkit.inspections.remotedev.analysis.SplitModeAnalysisFlags
@@ -187,7 +188,7 @@ internal object SplitModeInspectionUtil {
restrictionsService.getPredefinedModuleKind(module, ideaPlugin = ideaPlugin)
}
- return predefinedModuleKind != null
+ return predefinedModuleKind != null && predefinedModuleKind.apiUsagePolicy == ApiUsagePolicy.DEFAULT
}
fun shouldSuppressForSingleModuleExternalPlugin(file: PsiFile): Boolean {
diff --git a/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeMixedDependenciesInspection.kt b/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeMixedDependenciesInspection.kt
index aa5200fe5362..5098809561a2 100644
--- a/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeMixedDependenciesInspection.kt
+++ b/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeMixedDependenciesInspection.kt
@@ -27,20 +27,13 @@ internal class SplitModeMixedDependenciesInspection : DevKitPluginXmlInspectionB
val module = element.module ?: return
val currentXmlFile = holder.fileElement.file
- val xmlElement = element.xmlElement ?: return
- if (SplitModeInspectionExclusionsService.getInstance(currentXmlFile.project)
- .isExcluded(xmlElement, SPLIT_MODE_MIXED_DEPENDENCIES_SHORT_NAME)) {
- return
- }
+ if (element.xmlElement == null) return
val moduleAnalysis = SplitModeModuleKindResolver.getOrComputeModuleAnalysis(module, currentXmlFile)
if (moduleAnalysis.resolvedModuleKind.kind == SplitModeApiRestrictionsService.ModuleKind.MIXED) {
val regularFixes = SplitModeDependencyQuickFixes.createMixedModuleFixes(module, element)
- val suppressionFix = SplitModeInspectionExclusionsService.getInstance(currentXmlFile.project).createSuppressionFixIfApplicable(
- xmlElement,
- SPLIT_MODE_MIXED_DEPENDENCIES_SHORT_NAME,
- )
- val quickFixes = if (suppressionFix != null) regularFixes + suppressionFix else regularFixes
+ val suppressionFixes = SplitModeInspectionExclusionsService.getInstance(currentXmlFile.project).createCommonSuppressionQuickFixes()
+ val quickFixes = regularFixes + suppressionFixes
val mixedDependenciesMessage = buildMixedModuleDependenciesMessage(moduleAnalysis.resolvedModuleKind.reasoning)
holder.createProblem(
element,
diff --git a/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeXmlApiUsageInspection.kt b/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeXmlApiUsageInspection.kt
index bf23a38ce2bb..c519a01525de 100644
--- a/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeXmlApiUsageInspection.kt
+++ b/plugins/devkit/devkit-core/src/inspections/remotedev/SplitModeXmlApiUsageInspection.kt
@@ -11,7 +11,7 @@ import org.jetbrains.idea.devkit.inspections.remotedev.SplitModeInspectionUtil.b
import org.jetbrains.idea.devkit.inspections.remotedev.analysis.SplitModeApiRestrictionsService
import org.jetbrains.idea.devkit.inspections.remotedev.analysis.SplitModeQodanaInspectionScopeLimiter
import org.jetbrains.idea.devkit.inspections.remotedev.analysis.SplitModeModuleKindResolver
-import org.jetbrains.idea.devkit.inspections.remotedev.analysis.SplitModeModuleKindResolver.doesApiKindMatchExpectedModuleKind
+import org.jetbrains.idea.devkit.inspections.remotedev.analysis.SplitModeModuleKindResolver.isApiUsageAllowed
import org.jetbrains.idea.devkit.util.DescriptorUtil
internal class SplitModeXmlApiUsageInspection : DevKitPluginXmlInspectionBase() {
@@ -19,7 +19,8 @@ internal class SplitModeXmlApiUsageInspection : DevKitPluginXmlInspectionBase()
override fun isAllowed(holder: DomElementAnnotationHolder): Boolean {
return super.isAllowed(holder)
&& SplitModeInspectionUtil.isAllowedForSplitModeInspection(holder.fileElement.file)
- && SplitModeQodanaInspectionScopeLimiter.getInstance(holder.fileElement.file.project).shouldInspectFileInQodanaMode(holder.fileElement.file)
+ && SplitModeQodanaInspectionScopeLimiter.getInstance(holder.fileElement.file.project)
+ .shouldInspectFileInQodanaMode(holder.fileElement.file)
}
override fun checkDomElement(element: DomElement, holder: DomElementAnnotationHolder, helper: DomHighlightingHelper) {
@@ -30,25 +31,20 @@ internal class SplitModeXmlApiUsageInspection : DevKitPluginXmlInspectionBase()
val module = element.module ?: return
val currentXmlFile = holder.fileElement.file
val restrictionsService = SplitModeApiRestrictionsService.getInstance(currentXmlFile.project)
- val expectedModuleKind = restrictionsService.getExtensionPointKind(extensionPointName) ?: return
+ val apiRestriction = restrictionsService.getExtensionPointRestriction(extensionPointName) ?: return
+ val expectedModuleKind = apiRestriction.targetModuleKind
val moduleAnalysis = SplitModeModuleKindResolver.getOrComputeModuleAnalysis(module, currentXmlFile)
if (SplitModeInspectionUtil.shouldReportSinglePluginLevelErrorInsteadOfManyNestedErrors(currentXmlFile, moduleAnalysis)) return
val actualModuleKind = moduleAnalysis.resolvedModuleKind
- if (doesApiKindMatchExpectedModuleKind(actualModuleKind, expectedModuleKind)) return
+ if (isApiUsageAllowed(moduleAnalysis, apiRestriction)) return
val currentlyOpenedDescriptor = DescriptorUtil.getIdeaPlugin(holder.fileElement.file)
val hint = restrictionsService.getExtensionPointHint(extensionPointName)
- val xmlElement = element.xmlElement ?: return
- if (SplitModeInspectionExclusionsService.getInstance(currentXmlFile.project).isExcluded(xmlElement, SPLIT_MODE_XML_API_USAGE_SHORT_NAME)) {
- return
- }
+ if (element.xmlElement == null) return
val regularFixes = SplitModeDependencyQuickFixes.createMismatchFixes(module, currentlyOpenedDescriptor, expectedModuleKind)
- val suppressionFix = SplitModeInspectionExclusionsService.getInstance(currentXmlFile.project).createSuppressionFixIfApplicable(
- xmlElement,
- SPLIT_MODE_XML_API_USAGE_SHORT_NAME,
- )
- val fixes = if (suppressionFix != null) regularFixes + suppressionFix else regularFixes
+ val suppressionFixes = SplitModeInspectionExclusionsService.getInstance(currentXmlFile.project).createCommonSuppressionQuickFixes()
+ val fixes = regularFixes + suppressionFixes
holder.createProblem(
element,
buildModuleKindMismatchMessage(extensionPointName, expectedModuleKind, actualModuleKind, hint),
diff --git a/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeAnalysisModel.kt b/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeAnalysisModel.kt
index 9d9573392214..7c7d25d29bc4 100644
--- a/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeAnalysisModel.kt
+++ b/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeAnalysisModel.kt
@@ -6,8 +6,14 @@ import com.intellij.openapi.util.NlsSafe
internal data class ModuleAnalysis(
val resolvedModuleKind: ResolvedModuleKind,
val evidence: ModuleKindEvidence = ModuleKindEvidence(),
+ val apiUsagePolicy: ApiUsagePolicy = ApiUsagePolicy.DEFAULT,
)
+internal enum class ApiUsagePolicy(val id: String) {
+ DEFAULT("default"),
+ BACKEND_WITH_NON_UI_API_PERMIT("backendWithNonUiApiPermit"),
+}
+
internal data class ModuleKindEvidence(
val hasOwnFrontendEvidence: Boolean = false,
val hasOwnBackendEvidence: Boolean = false,
diff --git a/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeApiRestrictionsService.kt b/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeApiRestrictionsService.kt
index b6d07b3ab43c..4ff80c335bfd 100644
--- a/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeApiRestrictionsService.kt
+++ b/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeApiRestrictionsService.kt
@@ -14,6 +14,9 @@ import com.intellij.openapi.util.NlsSafe
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.psi.PsiModifierListOwner
import com.intellij.psi.xml.XmlFile
+import com.fasterxml.jackson.core.json.JsonReadFeature
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.databind.json.JsonMapper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -45,8 +48,8 @@ class SplitModeApiRestrictionsService(
companion object {
private val LOG: Logger = logger()
- private const val API_RESTRICTIONS_RESOURCE_PATH = "remotedevInspectionData/ApiRestrictions.json"
- private const val PREDEFINED_MODULE_KINDS_RESOURCE_PATH = "remotedevInspectionData/PredefinedModuleKinds.json"
+ private const val API_RESTRICTIONS_RESOURCE_PATH = "remotedevInspectionData/ApiRestrictions.json5"
+ private const val PREDEFINED_MODULE_KINDS_RESOURCE_PATH = "remotedevInspectionData/PredefinedModuleKinds.json5"
private const val BACKEND_API_ANNOTATION = "com.intellij.util.remdev.BackendApi"
private const val FRONTEND_API_ANNOTATION = "com.intellij.util.remdev.FrontendApi"
@@ -96,10 +99,29 @@ class SplitModeApiRestrictionsService(
}
}
+ enum class ApiRestrictionKind(val id: String) {
+ GENERIC_PLATFORM_API("genericPlatformApi"),
+ UI("ui"),
+ }
+
+ private enum class PredefinedModuleKindEntryKind(val id: String) {
+ MODULE_ID("moduleId"),
+ PLUGIN_ID("pluginId"),
+ XML_DESCRIPTOR_FILE("xmlDescriptorFile"),
+ }
+
private val json = Json {
ignoreUnknownKeys = true
isLenient = true
}
+ private val json5: ObjectMapper = JsonMapper.builder()
+ .enable(
+ JsonReadFeature.ALLOW_JAVA_COMMENTS,
+ JsonReadFeature.ALLOW_SINGLE_QUOTES,
+ JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES,
+ JsonReadFeature.ALLOW_TRAILING_COMMA,
+ )
+ .build()
private val resourceReader = SplitModeInspectionResourceReader.getInstance(project)
private val backgroundLoadScheduled = AtomicBoolean(false)
@@ -135,10 +157,18 @@ class SplitModeApiRestrictionsService(
}
fun getCodeApiKind(apiName: String, apiOwner: PsiModifierListOwner?): ModuleKind? {
- return getAnnotatedApiKind(apiOwner) ?: getRestrictionsSnapshot().codeRestrictions[apiName]
+ return getCodeApiRestriction(apiName, apiOwner)?.targetModuleKind
}
- fun getExtensionPointKind(extensionPointName: String): ModuleKind? {
+ internal fun getCodeApiRestriction(apiName: String, apiOwner: PsiModifierListOwner?): ApiRestrictionMatch? {
+ val annotatedApiKind = getAnnotatedApiKind(apiOwner)
+ if (annotatedApiKind != null) {
+ return ApiRestrictionMatch(annotatedApiKind, ApiRestrictionKind.GENERIC_PLATFORM_API)
+ }
+ return getRestrictionsSnapshot().codeRestrictions[apiName]
+ }
+
+ internal fun getExtensionPointRestriction(extensionPointName: String): ApiRestrictionMatch? {
val restrictions = getRestrictionsSnapshot()
val apiName = restrictions.extensionPointToApiName[extensionPointName] ?: return null
return restrictions.codeRestrictions[apiName]
@@ -156,11 +186,11 @@ class SplitModeApiRestrictionsService(
fun getPredefinedDependencyKind(dependencyId: String): ModuleKind? {
val predefinedModuleKinds = getRestrictionsSnapshot().predefinedModuleKinds
- val moduleKind = predefinedModuleKinds.moduleNames[dependencyId]
- if (moduleKind != null) {
- return moduleKind
+ val moduleInfo = predefinedModuleKinds.moduleIds[dependencyId]
+ if (moduleInfo != null) {
+ return moduleInfo.moduleKind
}
- return predefinedModuleKinds.pluginIds[dependencyId]
+ return predefinedModuleKinds.pluginIds[dependencyId]?.moduleKind
}
internal fun getPredefinedModuleKind(
@@ -172,10 +202,11 @@ class SplitModeApiRestrictionsService(
val descriptorRelativePath = if (descriptorFile == null) null else computeDescriptorRelativePath(module, descriptorFile)
if (descriptorRelativePath != null) {
val selector = DescriptorPathSelector(module.name, descriptorRelativePath)
- val moduleKind = lookup.descriptorPaths[selector]
- if (moduleKind != null) {
+ val moduleInfo = lookup.descriptorPaths[selector]
+ if (moduleInfo != null) {
return PredefinedModuleKindMatch(
- moduleKind = moduleKind,
+ moduleKind = moduleInfo.moduleKind,
+ apiUsagePolicy = moduleInfo.apiUsagePolicy,
cacheKey = "descriptor|${module.name}|$descriptorRelativePath",
reasoning = "Predefined module kind for descriptor '$descriptorRelativePath' in module '${module.name}'",
)
@@ -185,10 +216,11 @@ class SplitModeApiRestrictionsService(
if (ideaPlugin != null) {
val pluginSelectorIds = collectPluginSelectorIds(ideaPlugin)
for (pluginSelectorId in pluginSelectorIds) {
- val moduleKind = lookup.pluginIds[pluginSelectorId]
- if (moduleKind != null) {
+ val moduleInfo = lookup.pluginIds[pluginSelectorId]
+ if (moduleInfo != null) {
return PredefinedModuleKindMatch(
- moduleKind = moduleKind,
+ moduleKind = moduleInfo.moduleKind,
+ apiUsagePolicy = moduleInfo.apiUsagePolicy,
cacheKey = "plugin|$pluginSelectorId",
reasoning = "Predefined module kind for plugin/module id '$pluginSelectorId'",
)
@@ -196,9 +228,10 @@ class SplitModeApiRestrictionsService(
}
}
- val moduleKind = lookup.moduleNames[module.name] ?: return null
+ val moduleInfo = lookup.moduleIds[module.name] ?: return null
return PredefinedModuleKindMatch(
- moduleKind = moduleKind,
+ moduleKind = moduleInfo.moduleKind,
+ apiUsagePolicy = moduleInfo.apiUsagePolicy,
cacheKey = "module|${module.name}",
reasoning = "Predefined module kind for module '${module.name}'",
)
@@ -293,7 +326,8 @@ class SplitModeApiRestrictionsService(
readMode = readMode,
) {
override fun parse(text: String): RestrictionsLookup {
- return buildApiRestrictionsLookup(json.decodeFromString>(text))
+ val normalizedJson = json5.readTree(text).toString()
+ return buildApiRestrictionsLookup(json.decodeFromString>(normalizedJson))
}
override fun getDefaultValue(): RestrictionsLookup {
@@ -311,7 +345,8 @@ class SplitModeApiRestrictionsService(
readMode = readMode,
) {
override fun parse(text: String): PredefinedModuleKindsLookup {
- return buildPredefinedModuleKindsLookup(json.decodeFromString>(text))
+ val normalizedJson = json5.readTree(text).toString()
+ return buildPredefinedModuleKindsLookup(json.decodeFromString>(normalizedJson))
}
override fun getDefaultValue(): PredefinedModuleKindsLookup {
@@ -321,13 +356,14 @@ class SplitModeApiRestrictionsService(
}
private fun buildApiRestrictionsLookup(data: List): RestrictionsLookup {
- val codeRestrictions = mutableMapOf()
+ val codeRestrictions = mutableMapOf()
val extensionPointToApiName = mutableMapOf()
val apiHints = mutableMapOf()
for (restriction in data) {
val targetModuleKind = toTargetModuleKind(restriction)
- val existingCodeRestriction = codeRestrictions.putIfAbsent(restriction.apiName, targetModuleKind)
+ val apiRestriction = ApiRestrictionMatch(targetModuleKind, parseApiRestrictionKind(restriction.restrictionKind))
+ val existingCodeRestriction = codeRestrictions.putIfAbsent(restriction.apiName, apiRestriction)
check(existingCodeRestriction == null) {
"Duplicate API restriction for '${restriction.apiName}'"
}
@@ -337,7 +373,7 @@ class SplitModeApiRestrictionsService(
for (extensionPointName in restriction.extensionPointNames) {
val existingApiName = extensionPointToApiName[extensionPointName]
val existingExtensionPointRestriction = if (existingApiName == null) null else codeRestrictions[existingApiName]
- check(existingExtensionPointRestriction == null || existingExtensionPointRestriction == targetModuleKind) {
+ check(existingExtensionPointRestriction == null || existingExtensionPointRestriction == apiRestriction) {
"Conflicting extension point restriction for '$extensionPointName'"
}
if (existingApiName == null) {
@@ -354,50 +390,47 @@ class SplitModeApiRestrictionsService(
}
private fun buildPredefinedModuleKindsLookup(data: List): PredefinedModuleKindsLookup {
- val moduleNames = mutableMapOf()
- val pluginIds = mutableMapOf()
- val descriptorPaths = mutableMapOf()
+ val moduleIds = mutableMapOf()
+ val pluginIds = mutableMapOf()
+ val descriptorPaths = mutableMapOf()
- for ((moduleName, pluginId, descriptorRelativePath, moduleKindId) in data) {
+ for ((entryKindId, entryId, moduleName, descriptorRelativePath, moduleKindId, apiUsagePolicyId) in data) {
val moduleKind = parsePredefinedModuleKind(moduleKindId)
- val hasModuleName = !moduleName.isNullOrBlank()
- val hasPluginId = !pluginId.isNullOrBlank()
-
- check(hasModuleName != hasPluginId) {
- "Predefined module kind must specify exactly one of moduleName or pluginId"
- }
- check(descriptorRelativePath == null || hasModuleName) {
- "descriptorRelativePath is only supported together with moduleName"
- }
- check(descriptorRelativePath == null || descriptorRelativePath.isNotBlank()) {
- "descriptorRelativePath must not be blank"
- }
-
- if (descriptorRelativePath != null) {
- val selector = DescriptorPathSelector(moduleName!!, descriptorRelativePath)
- val previousModuleKind = descriptorPaths.putIfAbsent(selector, moduleKind)
- check(previousModuleKind == null) {
- "Duplicate predefined module kind for descriptor '${selector.descriptorRelativePath}' in module '${selector.moduleName}'"
+ val moduleInfo = PredefinedModuleKindInfo(moduleKind, parseApiUsagePolicy(apiUsagePolicyId))
+ when (parsePredefinedModuleKindEntryKind(entryKindId)) {
+ PredefinedModuleKindEntryKind.MODULE_ID -> {
+ check(moduleName == null) { "Predefined moduleId entry must not specify moduleName" }
+ check(descriptorRelativePath == null) { "Predefined moduleId entry must not specify descriptorRelativePath" }
+ check(!entryId.isNullOrBlank()) { "Predefined moduleId entry must specify non-blank id" }
+ val previousModuleKind = moduleIds.putIfAbsent(entryId, moduleInfo)
+ check(previousModuleKind == null) {
+ "Duplicate predefined module kind for module id '$entryId'"
+ }
}
- continue
- }
-
- if (hasModuleName) {
- val previousModuleKind = moduleNames.putIfAbsent(moduleName, moduleKind)
- check(previousModuleKind == null) {
- "Duplicate predefined module kind for module '$moduleName'"
+ PredefinedModuleKindEntryKind.PLUGIN_ID -> {
+ check(moduleName == null) { "Predefined pluginId entry must not specify moduleName" }
+ check(descriptorRelativePath == null) { "Predefined pluginId entry must not specify descriptorRelativePath" }
+ check(!entryId.isNullOrBlank()) { "Predefined pluginId entry must specify non-blank id" }
+ val previousModuleKind = pluginIds.putIfAbsent(entryId, moduleInfo)
+ check(previousModuleKind == null) {
+ "Duplicate predefined module kind for plugin/module id '$entryId'"
+ }
}
- }
- else {
- val previousModuleKind = pluginIds.putIfAbsent(pluginId!!, moduleKind)
- check(previousModuleKind == null) {
- "Duplicate predefined module kind for plugin/module id '$pluginId'"
+ PredefinedModuleKindEntryKind.XML_DESCRIPTOR_FILE -> {
+ check(entryId == null) { "Predefined xmlDescriptorFile entry must not specify id" }
+ check(!moduleName.isNullOrBlank()) { "Predefined xmlDescriptorFile entry must specify non-blank moduleName" }
+ check(!descriptorRelativePath.isNullOrBlank()) { "Predefined xmlDescriptorFile entry must specify non-blank descriptorRelativePath" }
+ val selector = DescriptorPathSelector(moduleName, descriptorRelativePath)
+ val previousModuleKind = descriptorPaths.putIfAbsent(selector, moduleInfo)
+ check(previousModuleKind == null) {
+ "Duplicate predefined module kind for descriptor '${selector.descriptorRelativePath}' in module '${selector.moduleName}'"
+ }
}
}
}
return PredefinedModuleKindsLookup(
- moduleNames = moduleNames,
+ moduleIds = moduleIds,
pluginIds = pluginIds,
descriptorPaths = descriptorPaths,
)
@@ -426,6 +459,27 @@ class SplitModeApiRestrictionsService(
return moduleKind
}
+ private fun parseApiRestrictionKind(restrictionKindId: String): ApiRestrictionKind {
+ return ApiRestrictionKind.entries.firstOrNull { it.id.equals(restrictionKindId, ignoreCase = true) }
+ ?: error("Unknown split-mode API restriction kind '$restrictionKindId'")
+ }
+
+ private fun parsePredefinedModuleKindEntryKind(entryKindId: String): PredefinedModuleKindEntryKind {
+ return PredefinedModuleKindEntryKind.entries.firstOrNull { it.id == entryKindId }
+ ?: error("Unknown predefined module kind entry kind '$entryKindId'")
+ }
+
+ private fun parseApiUsagePolicy(apiUsagePolicyId: String?): ApiUsagePolicy {
+ if (apiUsagePolicyId == null) {
+ return ApiUsagePolicy.DEFAULT
+ }
+ return when (apiUsagePolicyId) {
+ ApiUsagePolicy.DEFAULT.id -> ApiUsagePolicy.DEFAULT
+ ApiUsagePolicy.BACKEND_WITH_NON_UI_API_PERMIT.id -> ApiUsagePolicy.BACKEND_WITH_NON_UI_API_PERMIT
+ else -> error("Unknown split-mode API usage policy '$apiUsagePolicyId'")
+ }
+ }
+
private fun parsePredefinedModuleKind(moduleKindId: String): ModuleKind {
val moduleKind = parseModuleKindId(moduleKindId)
check(moduleKind != ModuleKind.MIXED) { "'mixed' is not supported in predefined module kinds" }
@@ -467,13 +521,13 @@ class SplitModeApiRestrictionsService(
}
private data class RestrictionsLookup(
- val codeRestrictions: Map = emptyMap(),
+ val codeRestrictions: Map = emptyMap(),
val extensionPointToApiName: Map = emptyMap(),
val apiHints: Map = emptyMap(),
)
private data class RestrictionsSnapshot(
- val codeRestrictions: Map = emptyMap(),
+ val codeRestrictions: Map = emptyMap(),
val extensionPointToApiName: Map = emptyMap(),
val apiHints: Map = emptyMap(),
val predefinedModuleKinds: PredefinedModuleKindsLookup = PredefinedModuleKindsLookup(),
@@ -481,25 +535,36 @@ class SplitModeApiRestrictionsService(
internal data class PredefinedModuleKindMatch(
val moduleKind: ModuleKind,
+ val apiUsagePolicy: ApiUsagePolicy,
val cacheKey: String,
val reasoning: @NlsSafe String,
)
+ internal data class ApiRestrictionMatch(
+ val targetModuleKind: ModuleKind,
+ val restrictionKind: ApiRestrictionKind,
+ )
+
private data class DescriptorPathSelector(
val moduleName: String,
val descriptorRelativePath: String,
)
private data class PredefinedModuleKindsLookup(
- val moduleNames: Map = emptyMap(),
- val pluginIds: Map = emptyMap(),
- val descriptorPaths: Map = emptyMap(),
+ val moduleIds: Map = emptyMap(),
+ val pluginIds: Map = emptyMap(),
+ val descriptorPaths: Map = emptyMap(),
) {
fun size(): Int {
- return moduleNames.size + pluginIds.size + descriptorPaths.size
+ return moduleIds.size + pluginIds.size + descriptorPaths.size
}
}
+ private data class PredefinedModuleKindInfo(
+ val moduleKind: ModuleKind,
+ val apiUsagePolicy: ApiUsagePolicy,
+ )
+
@Serializable
private data class ApiRestriction(
@SerialName("apiName")
@@ -511,22 +576,31 @@ class SplitModeApiRestrictionsService(
@SerialName("targetModules")
val targetModules: List,
+ @SerialName("restrictionKind")
+ val restrictionKind: String = ApiRestrictionKind.GENERIC_PLATFORM_API.id,
+
@SerialName("hint")
val hint: @Nls String? = null,
)
@Serializable
private data class PredefinedModuleKind(
+ @SerialName("kind")
+ val kind: String,
+
+ @SerialName("id")
+ val id: String? = null,
+
@SerialName("moduleName")
val moduleName: String? = null,
- @SerialName("pluginId")
- val pluginId: String? = null,
-
@SerialName("descriptorRelativePath")
val descriptorRelativePath: String? = null,
@SerialName("moduleKind")
val moduleKind: String,
+
+ @SerialName("apiUsagePolicy")
+ val apiUsagePolicy: String? = null,
)
}
diff --git a/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeDescriptorDependencyAnalyzer.kt b/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeDescriptorDependencyAnalyzer.kt
index 99d7c0ad7259..7aa5a7dbe1a3 100644
--- a/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeDescriptorDependencyAnalyzer.kt
+++ b/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeDescriptorDependencyAnalyzer.kt
@@ -87,7 +87,9 @@ internal object SplitModeDescriptorDependencyAnalyzer {
val descriptorLocation = getDescriptorLocation(ideaPlugin)
val accumulator = DependencyFactsAccumulator(descriptorLocation)
val directDependencies = collectDirectDependencies(ideaPlugin).toList()
- for ((dependencyName, dependencyDescriptors) in directDependencies) {
+ for (dependency in directDependencies) {
+ val dependencyName = dependency.name
+ val dependencyDescriptors = dependency.resolveDescriptors()
var hasPredefinedDependencyFacts = false
for (dependencyDescriptor in dependencyDescriptors) {
val predefinedDependencyFacts = getPredefinedDependencyFacts(dependencyDescriptor) ?: continue
@@ -118,7 +120,9 @@ internal object SplitModeDescriptorDependencyAnalyzer {
return accumulator.toDependencyFacts()
}
- for ((dependencyName, dependencyDescriptors) in directDependencies) {
+ for (dependency in directDependencies) {
+ val dependencyName = dependency.name
+ val dependencyDescriptors = dependency.resolveDescriptors()
for (dependencyDescriptor in dependencyDescriptors) {
val dependencyFacts = getOrComputeOwnDescriptorDependencyFacts(dependencyDescriptor, analysisStates)
accumulator.recordTransitiveDependencies(dependencyName, dependencyFacts)
@@ -162,7 +166,9 @@ internal object SplitModeDescriptorDependencyAnalyzer {
continue
}
val dependencyName = dependency.rawText ?: dependency.stringValue ?: continue
- yield(DirectDependency(dependencyName, resolvePluginDependencyDescriptors(ideaPlugin, dependencyName)))
+ yield(DirectDependency(dependencyName) {
+ resolvePluginDependencyDescriptors(ideaPlugin, dependencyName)
+ })
}
val pluginDependencies = ideaPlugin.dependencies
@@ -172,12 +178,16 @@ internal object SplitModeDescriptorDependencyAnalyzer {
for (moduleDescriptor in pluginDependencies.moduleEntry) {
val dependencyName = moduleDescriptor.name.stringValue ?: continue
- yield(DirectDependency(dependencyName, listOfNotNull(moduleDescriptor.name.value)))
+ yield(DirectDependency(dependencyName) {
+ listOfNotNull(moduleDescriptor.name.value)
+ })
}
for (pluginDescriptor in pluginDependencies.plugin) {
val dependencyName = pluginDescriptor.id.stringValue ?: continue
- yield(DirectDependency(dependencyName, resolvePluginDependencyDescriptors(ideaPlugin, dependencyName)))
+ yield(DirectDependency(dependencyName) {
+ resolvePluginDependencyDescriptors(ideaPlugin, dependencyName)
+ })
}
}
.distinctBy { it.name }
@@ -378,10 +388,14 @@ private class DependencyFactsAccumulator(
}
}
-private data class DirectDependency(
+private class DirectDependency(
val name: String,
- val descriptors: List,
-)
+ descriptorResolver: () -> List,
+) {
+ private val descriptors by lazy(LazyThreadSafetyMode.NONE) { descriptorResolver() }
+
+ fun resolveDescriptors(): List = descriptors
+}
private data class ContentModuleDependency(
val moduleName: String,
diff --git a/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeModuleKindIcons.kt b/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeModuleKindIcons.kt
index ac2c9d1ef6bd..4fd6db3b588f 100644
--- a/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeModuleKindIcons.kt
+++ b/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeModuleKindIcons.kt
@@ -5,25 +5,33 @@ import com.intellij.devkit.core.icons.DevkitCoreIcons.BackendModule
import com.intellij.devkit.core.icons.DevkitCoreIcons.FrontendModule
import com.intellij.devkit.core.icons.DevkitCoreIcons.SharedModule
import com.intellij.icons.AllIcons
+import com.intellij.lang.xml.XMLLanguage
+import com.intellij.openapi.application.smartReadAction
import com.intellij.openapi.project.DumbService
+import com.intellij.openapi.project.Project
import com.intellij.openapi.util.NlsSafe
-import com.intellij.openapi.util.registry.Registry
+import com.intellij.openapi.util.registry.RegistryManager
+import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
+import com.intellij.psi.util.CachedValueProvider
+import com.intellij.psi.util.CachedValuesManager
+import com.intellij.psi.xml.XmlFile
+import com.intellij.ui.IconDeferrer
import org.jetbrains.annotations.ApiStatus
+import org.jetbrains.idea.devkit.util.DescriptorUtil
import javax.swing.Icon
@ApiStatus.Internal
object SplitModeModuleKindIcons {
- @JvmStatic
- fun isCustomIconsEnabled(): Boolean {
- return Registry.`is`("devkit.split.mode.custom.icons", false)
- }
-
@JvmStatic
fun getDescriptorIcon(descriptorFile: PsiFile): Icon? {
- if (!isCustomIconsEnabled() || DumbService.isDumb(descriptorFile.project)) return null
- val kind = recognizeSplitModeModuleKind(descriptorFile)?.kind ?: return null
- return getKindIcon(kind, descriptorFile.name)
+ val fastIcon = getFastDescriptorIcon(descriptorFile) ?: return null
+ if (!isAccurateIconsEnabled() || DumbService.isDumb(descriptorFile.project)) return fastIcon
+
+ val virtualFile = descriptorFile.virtualFile ?: return fastIcon
+ return IconDeferrer.getInstance().deferAsync(fastIcon, DescriptorIconDeferredKey(descriptorFile.project, virtualFile)) {
+ getAccurateDescriptorIcon(descriptorFile, fastIcon)
+ }
}
@JvmStatic
@@ -43,4 +51,64 @@ object SplitModeModuleKindIcons {
private fun followsSharedModuleNamingConvention(moduleName: @NlsSafe String): Boolean {
return moduleName.endsWith(".shared.xml") || moduleName.endsWith(".common.xml") || moduleName.contains(".frontback")
}
+
+ private fun isAccurateIconsEnabled(): Boolean {
+ return RegistryManager.getInstance().`is`("devkit.split.mode.custom.icons")
+ }
+
+ private fun getFastDescriptorIcon(descriptorFile: PsiFile): Icon? {
+ val kind = getOrComputeModuleKindFast(descriptorFile) ?: return null
+ return getKindIcon(kind, descriptorFile.name)
+ }
+
+ private suspend fun getAccurateDescriptorIcon(descriptorFile: PsiFile, fastIcon: Icon): Icon {
+ return smartReadAction(descriptorFile.project) {
+ val kind = recognizeSplitModeModuleKind(descriptorFile)?.kind
+ kind?.let { getKindIcon(it, descriptorFile.name) } ?: fastIcon
+ }
+ }
+
+ private fun recognizeLightweightModuleKind(descriptorFile: PsiFile): SplitModeApiRestrictionsService.ModuleKind? {
+ val explicitDependencyKinds = collectExplicitDependencyKinds(descriptorFile)
+ return when {
+ explicitDependencyKinds.size > 1 -> SplitModeApiRestrictionsService.ModuleKind.MIXED
+ explicitDependencyKinds.size == 1 -> explicitDependencyKinds.single()
+ else -> inferModuleKindFromFileName(descriptorFile.name)
+ }
+ }
+
+ private fun getOrComputeModuleKindFast(descriptorFile: PsiFile): SplitModeApiRestrictionsService.ModuleKind? {
+ return CachedValuesManager.getCachedValue(descriptorFile) {
+ CachedValueProvider.Result.create(
+ recognizeLightweightModuleKind(descriptorFile),
+ descriptorFile.manager.modificationTracker.forLanguage(XMLLanguage.INSTANCE),
+ )
+ }
+ }
+
+ private fun collectExplicitDependencyKinds(descriptorFile: PsiFile): Set {
+ val xmlFile = descriptorFile as? XmlFile ?: return emptySet()
+ val ideaPlugin = DescriptorUtil.getIdeaPlugin(xmlFile) ?: return emptySet()
+ val explicitDependencyKinds = LinkedHashSet()
+ for (dependencyName in SplitModeDescriptorDependencyAnalyzer.collectDirectDependencyNames(ideaPlugin)) {
+ val dependencyKind = recognizeExplicitDependencyKind(dependencyName) ?: continue
+ explicitDependencyKinds.add(dependencyKind)
+ }
+ return explicitDependencyKinds
+ }
+
+ private fun inferModuleKindFromFileName(descriptorFileName: @NlsSafe String): SplitModeApiRestrictionsService.ModuleKind? {
+ return when {
+ descriptorFileName == "plugin.xml" -> SplitModeApiRestrictionsService.ModuleKind.SHARED
+ descriptorFileName.endsWith(".frontend.xml") || descriptorFileName.endsWith(".frontend.split.xml") -> SplitModeApiRestrictionsService.ModuleKind.FRONTEND
+ descriptorFileName.endsWith(".backend.xml") || descriptorFileName.endsWith(".backend.split.xml") -> SplitModeApiRestrictionsService.ModuleKind.BACKEND
+ followsSharedModuleNamingConvention(descriptorFileName) -> SplitModeApiRestrictionsService.ModuleKind.SHARED
+ else -> null
+ }
+ }
}
+
+private data class DescriptorIconDeferredKey(
+ val project: Project,
+ val virtualFile: VirtualFile,
+)
diff --git a/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeModuleKindResolver.kt b/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeModuleKindResolver.kt
index a556b2356976..89a0c400c980 100644
--- a/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeModuleKindResolver.kt
+++ b/plugins/devkit/devkit-core/src/inspections/remotedev/analysis/SplitModeModuleKindResolver.kt
@@ -1,15 +1,27 @@
// Copyright 2000-2026 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.remotedev.analysis
+import com.intellij.lang.xml.XMLLanguage
import com.intellij.openapi.diagnostic.debug
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleUtilCore
+import com.intellij.openapi.roots.ProjectRootModificationTracker
+import com.intellij.openapi.util.Key
+import com.intellij.psi.util.CachedValue
+import com.intellij.psi.util.CachedValueProvider
+import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.xml.XmlFile
import org.jetbrains.idea.devkit.inspections.remotedev.SplitModeInspectionUtil.findDependingContentModuleEntriesInFile
import org.jetbrains.idea.devkit.module.PluginModuleType
import org.jetbrains.idea.devkit.util.DescriptorUtil
+private val MODULE_ID_ANALYSIS_KEY =
+ Key.create>("SplitModeModuleKindResolver.moduleIdAnalysis")
+
+private val MODULE_DESCRIPTOR_ANALYSIS_KEY =
+ Key.create>("SplitModeModuleKindResolver.moduleDescriptorAnalysis")
+
internal object SplitModeModuleKindResolver {
private val LOG = logger()
@@ -20,17 +32,47 @@ internal object SplitModeModuleKindResolver {
return expectedKind.accepts(actualApiUsageModuleKind.kind)
}
+ fun isApiUsageAllowed(
+ actualModuleAnalysis: ModuleAnalysis,
+ apiRestriction: SplitModeApiRestrictionsService.ApiRestrictionMatch,
+ ): Boolean {
+ val actualModuleKind = actualModuleAnalysis.resolvedModuleKind
+ return doesApiKindMatchExpectedModuleKind(actualModuleKind, apiRestriction.targetModuleKind)
+ || actualModuleKind.kind == SplitModeApiRestrictionsService.ModuleKind.BACKEND
+ && actualModuleAnalysis.apiUsagePolicy == ApiUsagePolicy.BACKEND_WITH_NON_UI_API_PERMIT
+ && apiRestriction.restrictionKind == SplitModeApiRestrictionsService.ApiRestrictionKind.GENERIC_PLATFORM_API
+ }
+
fun getOrComputeModuleAnalysis(module: Module, descriptorFile: XmlFile? = null): ModuleAnalysis {
val xmlDescriptor = descriptorFile ?: PluginModuleType.getContentModuleDescriptorXml(module) ?: PluginModuleType.getPluginXml(module)
if (xmlDescriptor == null) {
return ModuleAnalysis(ResolvedModuleKind(SplitModeApiRestrictionsService.ModuleKind.SHARED, ""))
}
+ val cacheKey = if (descriptorFile == null) MODULE_ID_ANALYSIS_KEY else MODULE_DESCRIPTOR_ANALYSIS_KEY
+ return CachedValuesManager.getManager(module.project).getCachedValue(xmlDescriptor, cacheKey, {
+ CachedValueProvider.Result.create(
+ computeModuleAnalysis(module, descriptorFile),
+ ProjectRootModificationTracker.getInstance(module.project),
+ xmlDescriptor.manager.modificationTracker.forLanguage(XMLLanguage.INSTANCE),
+ )
+ }, false)
+ }
+
+ private fun computeModuleAnalysis(module: Module, descriptorFile: XmlFile? = null): ModuleAnalysis {
+ val xmlDescriptor = descriptorFile ?: PluginModuleType.getContentModuleDescriptorXml(module) ?: PluginModuleType.getPluginXml(module)
+ if (xmlDescriptor == null) {
+ return ModuleAnalysis(ResolvedModuleKind(SplitModeApiRestrictionsService.ModuleKind.SHARED, ""))
+ }
+
val parsedXmlDescriptor = DescriptorUtil.getIdeaPlugin(xmlDescriptor)
val predefinedModuleKind =
SplitModeApiRestrictionsService.getInstance(module.project).getPredefinedModuleKind(module, xmlDescriptor, parsedXmlDescriptor)
if (predefinedModuleKind != null) {
- return ModuleAnalysis(ResolvedModuleKind(predefinedModuleKind.moduleKind, predefinedModuleKind.reasoning))
+ return ModuleAnalysis(
+ resolvedModuleKind = ResolvedModuleKind(predefinedModuleKind.moduleKind, predefinedModuleKind.reasoning),
+ apiUsagePolicy = predefinedModuleKind.apiUsagePolicy,
+ )
}
if (parsedXmlDescriptor == null) {
return ModuleAnalysis(ResolvedModuleKind(SplitModeApiRestrictionsService.ModuleKind.SHARED, ""))
diff --git a/plugins/devkit/devkit-core/src/navigation/DescriptorSplitModeInlayHintsProvider.kt b/plugins/devkit/devkit-core/src/navigation/DescriptorSplitModeInlayHintsProvider.kt
new file mode 100644
index 000000000000..1b81e5ee1632
--- /dev/null
+++ b/plugins/devkit/devkit-core/src/navigation/DescriptorSplitModeInlayHintsProvider.kt
@@ -0,0 +1,147 @@
+// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package org.jetbrains.idea.devkit.navigation
+
+import com.intellij.codeInsight.hints.declarative.HintFormat
+import com.intellij.codeInsight.hints.declarative.InlayHintsCollector
+import com.intellij.codeInsight.hints.declarative.InlayHintsProvider
+import com.intellij.codeInsight.hints.declarative.InlayTreeSink
+import com.intellij.codeInsight.hints.declarative.InlineInlayPosition
+import com.intellij.codeInsight.hints.declarative.OwnBypassCollector
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.module.ModuleUtilCore
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.registry.Registry
+import com.intellij.openapi.util.text.StringUtil
+import com.intellij.psi.PsiFile
+import com.intellij.psi.xml.XmlFile
+import com.intellij.psi.xml.XmlToken
+import com.intellij.psi.xml.XmlTokenType
+import com.intellij.xml.util.XmlUtil
+import org.jetbrains.idea.devkit.DevKitBundle
+import org.jetbrains.idea.devkit.inspections.remotedev.SplitModeInspectionUtil.findDependingContentModuleEntriesInFile
+import org.jetbrains.idea.devkit.inspections.remotedev.analysis.SplitModeApiRestrictionsService.ModuleKind
+import org.jetbrains.idea.devkit.inspections.remotedev.analysis.recognizeSplitModeModuleKind
+import org.jetbrains.idea.devkit.module.PluginModuleType
+
+internal class DescriptorSplitModeInlayHintsProvider : InlayHintsProvider {
+
+ override fun createCollector(file: PsiFile, editor: Editor): InlayHintsCollector? {
+ if (!isDescriptorSplitModeInlayEnabled()) return null
+ val xmlFile = file as? XmlFile ?: return null
+ if (findIdeaPluginRootTagNameToken(xmlFile) == null) return null
+ return DescriptorSplitModeInlayHintsCollector()
+ }
+
+ private class DescriptorSplitModeInlayHintsCollector : OwnBypassCollector {
+ override fun collectHintsForFile(file: PsiFile, sink: InlayTreeSink) {
+ val xmlFile = file as? XmlFile ?: return
+ val tagNameToken = findIdeaPluginRootTagNameToken(xmlFile) ?: return
+ val inlayInfo = getDescriptorSplitModeInlayInfo(xmlFile) ?: return
+
+ sink.addPresentation(
+ InlineInlayPosition(tagNameToken.textRange.endOffset, true),
+ tooltip = inlayInfo.tooltip,
+ hintFormat = HintFormat.default,
+ ) {
+ text(inlayInfo.text)
+ }
+ }
+
+ override fun shouldSuggestToggling(project: Project, editor: Editor, file: PsiFile): Boolean {
+ return isDescriptorSplitModeInlayEnabled() && file is XmlFile && findIdeaPluginRootTagNameToken(file) != null
+ }
+ }
+}
+
+internal data class DescriptorSplitModeInlayInfo(
+ val text: String,
+ val tooltip: String,
+)
+
+internal fun getDescriptorSplitModeInlayInfo(xmlFile: XmlFile): DescriptorSplitModeInlayInfo? {
+ val recognizedModuleKind = recognizeSplitModeModuleKind(xmlFile) ?: return null
+ val descriptorKindMessageKey = getDescriptorKindMessageKey(xmlFile)
+ val descriptorKind = DevKitBundle.message(descriptorKindMessageKey)
+ return DescriptorSplitModeInlayInfo(
+ DevKitBundle.message(
+ "inlay.split.mode.module.kind.presentation",
+ getPresentableModuleKind(recognizedModuleKind.kind),
+ descriptorKind,
+ ),
+ DevKitBundle.message(
+ "inlay.split.mode.module.kind.tooltip",
+ descriptorKind,
+ getCompatibilityTarget(recognizedModuleKind.kind),
+ normalizeTooltipReasoning(recognizedModuleKind.reasoning),
+ ),
+ )
+}
+
+private fun normalizeTooltipReasoning(reasoning: String): String {
+ return reasoning.lineSequence().map(String::trim).filter(String::isNotEmpty).joinToString(" ")
+}
+
+private fun isDescriptorSplitModeInlayEnabled(): Boolean {
+ return Registry.`is`("devkit.split.mode.inlay.plugin.descriptor.kind")
+}
+
+private fun getPresentableModuleKind(kind: ModuleKind): String {
+ val presentableId = when (kind) {
+ ModuleKind.FRONTEND -> ModuleKind.FRONTEND.id
+ ModuleKind.BACKEND -> ModuleKind.BACKEND.id
+ ModuleKind.SHARED -> ModuleKind.SHARED.id
+ ModuleKind.MONOLITH,
+ ModuleKind.MIXED,
+ -> ModuleKind.MONOLITH.id
+ is ModuleKind.Composite -> kind.id
+ }
+ return StringUtil.capitalize(presentableId)
+}
+
+private fun getCompatibilityTarget(kind: ModuleKind): String {
+ val messageKey = when (kind) {
+ ModuleKind.FRONTEND -> "inlay.split.mode.module.kind.compatibility.frontend"
+ ModuleKind.BACKEND -> "inlay.split.mode.module.kind.compatibility.backend"
+ ModuleKind.SHARED -> "inlay.split.mode.module.kind.compatibility.shared"
+ ModuleKind.MONOLITH,
+ ModuleKind.MIXED,
+ -> "inlay.split.mode.module.kind.compatibility.monolith"
+ is ModuleKind.Composite -> "inlay.split.mode.module.kind.compatibility.shared"
+ }
+ return DevKitBundle.message(messageKey)
+}
+
+private fun getDescriptorKindMessageKey(xmlFile: XmlFile): String {
+ if (xmlFile.name == "plugin.xml") {
+ return "inlay.split.mode.module.kind.plugin"
+ }
+ if (isContentModuleDescriptor(xmlFile)) {
+ return "inlay.split.mode.module.kind.content.module"
+ }
+ return "inlay.split.mode.module.kind.xml.descriptor"
+}
+
+private fun isContentModuleDescriptor(xmlFile: XmlFile): Boolean {
+ val module = ModuleUtilCore.findModuleForPsiElement(xmlFile)
+ if (PluginModuleType.getContentModuleDescriptorXml(module)?.virtualFile == xmlFile.virtualFile) {
+ return true
+ }
+ if (module != null && xmlFile.name in computePossibleContentModuleDescriptorNames(module.name)) {
+ return true
+ }
+ return findDependingContentModuleEntriesInFile(xmlFile).any()
+}
+
+private fun computePossibleContentModuleDescriptorNames(moduleName: String): List {
+ return listOf(
+ "$moduleName.xml",
+ "${moduleName.replace(".main", "")}.xml",
+ "${moduleName.replace("_", ".").replace(".main", "")}.xml",
+ )
+}
+
+private fun findIdeaPluginRootTagNameToken(xmlFile: XmlFile): XmlToken? {
+ val rootTag = xmlFile.rootTag ?: return null
+ val tagNameToken = XmlUtil.getTokenOfType(rootTag, XmlTokenType.XML_NAME) ?: return null
+ return tagNameToken.takeIf(::isIdeaPluginElementNameLeaf)
+}
diff --git a/plugins/devkit/devkit-core/src/navigation/DescriptorsIncludingContentModuleLineMarkerProvider.kt b/plugins/devkit/devkit-core/src/navigation/DescriptorsIncludingContentModuleLineMarkerProvider.kt
index 26862b1b18b8..9400b6ffbe6c 100644
--- a/plugins/devkit/devkit-core/src/navigation/DescriptorsIncludingContentModuleLineMarkerProvider.kt
+++ b/plugins/devkit/devkit-core/src/navigation/DescriptorsIncludingContentModuleLineMarkerProvider.kt
@@ -47,15 +47,6 @@ internal class DescriptorsIncludingContentModuleLineMarkerProvider : DevkitRelat
}
}
- private fun isIdeaPluginElementNameLeaf(leaf: PsiElement): Boolean {
- if (leaf !is XmlToken) return false
- if (leaf.getNode().elementType != XmlTokenType.XML_NAME) return false
- val prev = PsiTreeUtil.getPrevSiblingOfType(leaf, XmlToken::class.java)
- if (prev == null || prev.node.elementType !== XmlTokenType.XML_START_TAG_START) return false
- if (!leaf.textMatches("idea-plugin")) return false
- return DomUtil.getDomElement(leaf) is IdeaPlugin
- }
-
private fun findDependingContentModuleEntries(element: PsiElement): List {
val xmlFile = element.containingFile as? XmlFile ?: return emptyList()
return findDependingContentModuleEntriesInFile(xmlFile).toList()
@@ -109,4 +100,13 @@ internal class DescriptorsIncludingContentModuleLineMarkerProvider : DevkitRelat
return moduleDescriptor.loading.value?.value ?: "optional"
}
}
-}
\ No newline at end of file
+}
+
+internal fun isIdeaPluginElementNameLeaf(leaf: PsiElement): Boolean {
+ if (leaf !is XmlToken) return false
+ if (leaf.getNode().elementType != XmlTokenType.XML_NAME) return false
+ val prev = PsiTreeUtil.getPrevSiblingOfType(leaf, XmlToken::class.java)
+ if (prev == null || prev.node.elementType !== XmlTokenType.XML_START_TAG_START) return false
+ if (!leaf.textMatches("idea-plugin")) return false
+ return DomUtil.getDomElement(leaf) is IdeaPlugin
+}
diff --git a/plugins/devkit/devkit-java-tests/BUILD.bazel b/plugins/devkit/devkit-java-tests/BUILD.bazel
index cd19877bcd46..597850b02102 100644
--- a/plugins/devkit/devkit-java-tests/BUILD.bazel
+++ b/plugins/devkit/devkit-java-tests/BUILD.bazel
@@ -130,6 +130,8 @@ jvm_library(
"//java/compiler:compiler-tests_test_lib",
"//java/testFramework",
"//java/testFramework:testFramework_test_lib",
+ "//plugins/junit",
+ "//plugins/junit:junit_test_lib",
"//xml/dom-tests",
"//xml/dom-tests:dom-tests_test_lib",
"//plugins/properties:properties-backend",
diff --git a/plugins/devkit/devkit-java-tests/intellij.devkit.java.tests.iml b/plugins/devkit/devkit-java-tests/intellij.devkit.java.tests.iml
index c670a24091db..bef533ff9cdb 100644
--- a/plugins/devkit/devkit-java-tests/intellij.devkit.java.tests.iml
+++ b/plugins/devkit/devkit-java-tests/intellij.devkit.java.tests.iml
@@ -44,6 +44,7 @@
+
diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/descriptor/PluginDescriptorSplitModeIconsTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/descriptor/PluginDescriptorSplitModeIconsTest.kt
index c6498be00711..c25ba738a6b7 100644
--- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/descriptor/PluginDescriptorSplitModeIconsTest.kt
+++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/descriptor/PluginDescriptorSplitModeIconsTest.kt
@@ -2,11 +2,11 @@
package org.jetbrains.idea.devkit.descriptor
import com.intellij.devkit.core.icons.DevkitCoreIcons
+import com.intellij.ide.IconProvider
import com.intellij.icons.AllIcons.Nodes.Plugin
import com.intellij.openapi.application.invokeAndWaitIfNeeded
import com.intellij.openapi.application.runReadActionBlocking
import com.intellij.openapi.project.IntelliJProjectUtil
-import com.intellij.openapi.util.registry.Registry
import com.intellij.psi.PsiManager
import com.intellij.testFramework.IndexingTestUtil
import com.intellij.testFramework.PsiTestUtil
@@ -38,45 +38,85 @@ internal class PluginDescriptorSplitModeIconsTest {
@Test
@RegistryKey(key = "devkit.plugin.directory.icons", value = "true")
- fun `descriptor and directory icons follow split mode kind`() {
- Registry.get("devkit.split.mode.custom.icons").setValue(true)
+ @RegistryKey(key = "devkit.split.mode.custom.icons", value = "false")
+ fun `descriptor and directory icons use fast split mode kind when accurate icons are disabled`() {
IntelliJProjectUtil.markAsIntelliJPlatformProject(project, true)
try {
- createModuleDescriptor("module.shared", "module.shared.xml", """
-
-
- """.trimIndent())
- createSharedPluginDescriptor("""
-
-
- """.trimIndent())
- createFrontendPluginDescriptor("""
-
-
-
-
-
- """.trimIndent())
- createModuleDescriptor("module.backend", "module.backend.xml", """
-
-
-
-
-
- """.trimIndent())
- IndexingTestUtil.waitUntilIndexesAreReady(project)
+ createSplitModeIconFixtures()
assertFileIcon("shared.plugin/resources/META-INF/plugin.xml", Plugin)
assertFileIcon("module.shared/resources/module.shared.xml", DevkitCoreIcons.SharedModule)
assertFileIcon("frontend.plugin/resources/META-INF/plugin.xml", DevkitCoreIcons.FrontendModule)
+ assertFileIcon(
+ "intellij.transitive.frontend/resources/intellij.transitive.frontend.xml",
+ DevkitCoreIcons.FrontendModule,
+ )
assertFileIcon("module.backend/resources/module.backend.xml", DevkitCoreIcons.BackendModule)
+ assertFileIcon("transitive.consumer/resources/META-INF/plugin.xml", Plugin)
+ assertDirectoryIcon("frontend.plugin", DevkitCoreIcons.FrontendModule)
+ assertDirectoryIcon("transitive.consumer", Plugin)
}
finally {
IntelliJProjectUtil.markAsIntelliJPlatformProject(project, false)
- Registry.get("devkit.split.mode.custom.icons").setValue(false)
}
}
+ @Test
+ @RegistryKey(key = "devkit.plugin.directory.icons", value = "true")
+ @RegistryKey(key = "devkit.split.mode.custom.icons", value = "true")
+ fun `descriptor and directory icons resolve accurate split mode kind when enabled`() {
+ IntelliJProjectUtil.markAsIntelliJPlatformProject(project, true)
+ try {
+ createSplitModeIconFixtures()
+
+ assertFileIcon("transitive.consumer/resources/META-INF/plugin.xml", DevkitCoreIcons.FrontendModule)
+ assertDirectoryIcon("transitive.consumer", DevkitCoreIcons.FrontendModule)
+ }
+ finally {
+ IntelliJProjectUtil.markAsIntelliJPlatformProject(project, false)
+ }
+ }
+
+ private fun createSplitModeIconFixtures() {
+ createModuleDescriptor("module.shared", "module.shared.xml", """
+
+
+ """.trimIndent())
+ createSharedPluginDescriptor("""
+
+
+ """.trimIndent())
+ createFrontendPluginDescriptor("""
+
+
+
+
+
+ """.trimIndent())
+ createModuleDescriptor("intellij.transitive.frontend", "intellij.transitive.frontend.xml", """
+
+
+
+
+
+ """.trimIndent())
+ createModuleDescriptor("module.backend", "module.backend.xml", """
+
+
+
+
+
+ """.trimIndent())
+ createPluginDescriptor("transitive.consumer", """
+
+
+
+
+
+ """.trimIndent())
+ IndexingTestUtil.waitUntilIndexesAreReady(project)
+ }
+
private fun createModuleDescriptor(moduleName: String, descriptorName: String, descriptorText: String) {
val moduleRoot = projectModel.baseProjectDir.newVirtualDirectory(moduleName)
val module = PsiTestUtil.addModule(project, PluginModuleType.getInstance(), moduleName, moduleRoot)
@@ -86,18 +126,14 @@ internal class PluginDescriptorSplitModeIconsTest {
}
private fun createFrontendPluginDescriptor(descriptorText: String) {
- val moduleName = "frontend.plugin"
- val moduleRoot = projectModel.baseProjectDir.newVirtualDirectory(moduleName)
- val module = PsiTestUtil.addModule(project, PluginModuleType.getInstance(), moduleName, moduleRoot)
- val resourcesRoot = projectModel.baseProjectDir.newVirtualDirectory("$moduleName/resources")
- PsiTestUtil.addSourceRoot(module, resourcesRoot, JavaResourceRootType.RESOURCE)
- val descriptorFile =
- projectModel.baseProjectDir.newVirtualFile("$moduleName/resources/META-INF/plugin.xml", descriptorText.toByteArray())
- PluginBuildConfiguration.getInstance(module)!!.setPluginXmlFromVirtualFile(descriptorFile)
+ createPluginDescriptor("frontend.plugin", descriptorText)
}
private fun createSharedPluginDescriptor(descriptorText: String) {
- val moduleName = "shared.plugin"
+ createPluginDescriptor("shared.plugin", descriptorText)
+ }
+
+ private fun createPluginDescriptor(moduleName: String, descriptorText: String) {
val moduleRoot = projectModel.baseProjectDir.newVirtualDirectory(moduleName)
val module = PsiTestUtil.addModule(project, PluginModuleType.getInstance(), moduleName, moduleRoot)
val resourcesRoot = projectModel.baseProjectDir.newVirtualDirectory("$moduleName/resources")
@@ -109,13 +145,28 @@ internal class PluginDescriptorSplitModeIconsTest {
private fun assertFileIcon(relativePath: String, expectedIcon: Icon) {
assertIcon(expectedIcon) {
- PsiManager.getInstance(project).findFile(projectModel.baseProjectDir.virtualFileRoot.findFileByRelativePath(relativePath)!!)!!
+ val file = PsiManager.getInstance(project).findFile(projectModel.baseProjectDir.virtualFileRoot.findFileByRelativePath(relativePath)!!)!!
+ PsiIconUtil.getIconFromProviders(file, 0)
}
}
- private fun assertIcon(expectedIcon: Icon, psiElementProvider: () -> com.intellij.psi.PsiElement) {
+ private fun assertDirectoryIcon(relativePath: String, expectedIcon: Icon) {
+ assertIcon(expectedIcon) {
+ val directory = PsiManager.getInstance(project)
+ .findDirectory(projectModel.baseProjectDir.virtualFileRoot.findFileByRelativePath(relativePath)!!)!!
+ getScaffoldingDirectoryIconProvider().getIcon(directory, 0)
+ }
+ }
+
+ private fun getScaffoldingDirectoryIconProvider(): IconProvider {
+ return IconProvider.EXTENSION_POINT_NAME.extensionList.single {
+ it.javaClass.name == "com.intellij.devkit.scaffolding.ScaffoldingDirectoryIconProvider"
+ }
+ }
+
+ private fun assertIcon(expectedIcon: Icon, iconProvider: () -> Icon?) {
val iconFromProviders = runReadActionBlocking {
- PsiIconUtil.getIconFromProviders(psiElementProvider(), 0)
+ iconProvider()
}
checkNotNull(iconFromProviders)
awaitDeferredIcons(iconFromProviders)
@@ -130,13 +181,13 @@ internal class PluginDescriptorSplitModeIconsTest {
is DeferredIconImpl<*> -> runBlocking {
icon.awaitEvaluation()
}
- is RetrievableIcon -> awaitDeferredIcons(icon.retrieveIcon())
is CompositeIcon -> {
for (i in 0 until icon.iconCount) {
val nestedIcon = icon.getIcon(i) ?: continue
awaitDeferredIcons(nestedIcon)
}
}
+ is RetrievableIcon -> awaitDeferredIcons(icon.retrieveIcon())
}
}
}
diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/MissingFrontendOrBackendRuntimeDependencyInspectionTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/MissingFrontendOrBackendRuntimeDependencyInspectionTest.kt
index 4389faf6b390..1c70394f903a 100644
--- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/MissingFrontendOrBackendRuntimeDependencyInspectionTest.kt
+++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/MissingFrontendOrBackendRuntimeDependencyInspectionTest.kt
@@ -1,18 +1,12 @@
// 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.openapi.command.WriteCommandAction
-import com.intellij.openapi.fileEditor.FileEditorManager
-import com.intellij.openapi.project.IntelliJProjectUtil
-import com.intellij.openapi.vfs.VfsUtil
-import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.psi.PsiFile
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.inspections.remotedev.EXCLUSIONS_RELATIVE_PATH
import org.jetbrains.idea.devkit.inspections.remotedev.MissingFrontendOrBackendRuntimeDependencyInspection
import org.jetbrains.idea.devkit.module.PluginModuleType
@@ -49,48 +43,6 @@ internal class MissingFrontendOrBackendRuntimeDependencyInspectionTest : JavaCod
fun testShouldNotCrashOnCyclicDependencyInFrontend() = testShouldNotCrashOnCyclicDependency("frontend")
fun testShouldNotCrashOnCyclicDependencyInBackend() = testShouldNotCrashOnCyclicDependency("backend")
- fun testShouldNotReportExcludedFrontendDependency() {
- myFixture.addSplitModeExclusionsFile(splitModeExclusionsJson(
- missingRuntimeDependencyExclusion("intellij.test.feature.frontend.xml", 2)
- ))
-
- val testedFile = myFixture.addXmlFile("intellij.test.feature.frontend.xml", """
-
-
-
-
-
- """.trimIndent()
- )
- testHighlighting(testedFile)
- }
-
- fun testShouldReportWhenExclusionsFileIsEmpty() {
- myFixture.addSplitModeExclusionsFile("")
- testReportDependency("frontend")
- }
-
- fun testExclusionsInvalidatedAfterJsonChange() {
- val exclusionsFile = myFixture.addSplitModeExclusionsFile("""{ "exclusions": [] }""")
- val testedFile = myFixture.addXmlFile("intellij.test.feature.frontend.xml", """
-
-
-
-
-
- """.trimIndent()
- )
- assertTrue(hasMissingFrontendRuntimeDependencyWarning(testedFile))
-
- WriteCommandAction.runWriteCommandAction(project) {
- VfsUtil.saveText(exclusionsFile.virtualFile, splitModeExclusionsJson(
- missingRuntimeDependencyExclusion("intellij.test.feature.frontend.xml", 2)
- ))
- }
-
- assertFalse(hasMissingFrontendRuntimeDependencyWarning(testedFile))
- }
-
private fun testReportDependency(frontendOrBackend: String) {
val testedFile = myFixture.addXmlFile("intellij.test.feature.$frontendOrBackend.xml", """
@@ -212,13 +164,6 @@ internal class MissingFrontendOrBackendRuntimeDependencyInspectionTest : JavaCod
private fun testHighlighting(testedFile: PsiFile) {
myFixture.testHighlighting(true, true, true, testedFile.virtualFile)
}
-
- private fun hasMissingFrontendRuntimeDependencyWarning(testedFile: PsiFile): Boolean {
- val expectedDescription = "The name of the current module 'intellij.test.feature.frontend' ends with '.frontend', " +
- "but the dependency on 'intellij.platform.frontend' is missing"
- myFixture.configureFromExistingVirtualFile(testedFile.virtualFile)
- return myFixture.doHighlighting().any { it.description == expectedDescription }
- }
}
internal class MissingFrontendOrBackendRuntimeDependencyFixTest : JavaCodeInsightFixtureTestCase() {
@@ -236,57 +181,6 @@ internal class MissingFrontendOrBackendRuntimeDependencyFixTest : JavaCodeInsigh
fun testAddingBackendDependencyWhenDependenciesElementDoesNotExist() = testAddingDependencyWhenDependenciesElementDoesNotExist("backend")
- fun testAddToExclusionsFixIsHiddenOutsideIntelliJProject() {
- IntelliJProjectUtil.markAsIntelliJPlatformProject(project, false)
-
- val testedFile = myFixture.addXmlFile("intellij.test.feature.frontend.xml", """
- plugin>
-
-
- """.trimIndent()
- )
- myFixture.configureFromExistingVirtualFile(testedFile.virtualFile)
-
- val splitModeFixes = myFixture.getAllQuickFixes().map { it.text }
- assertFalse(splitModeFixes.contains(addToExclusionsFixName()))
- }
-
- fun testAddToExclusionsFixIsLastAndAppendsEntry() {
- IntelliJProjectUtil.markAsIntelliJPlatformProject(project, true)
-
- val testedFile = myFixture.addXmlFile("intellij.test.feature.frontend.xml", """
- plugin>
-
-
- """.trimIndent()
- )
- myFixture.configureFromExistingVirtualFile(testedFile.virtualFile)
-
- val dependencyFixName = addRuntimeDependencyFixName("frontend")
- val exclusionsFixName = addToExclusionsFixName()
- val splitModeFixes = myFixture.getAllQuickFixes()
- .map { it.text }
- .filter { it == dependencyFixName || it == exclusionsFixName }
- assertSameElements(splitModeFixes, dependencyFixName, exclusionsFixName)
- assertEquals(exclusionsFixName, splitModeFixes.last())
-
- val intention = myFixture.findSingleIntention(exclusionsFixName)
- myFixture.launchAction(intention)
-
- val exclusionsFile = myFixture.findFileInTempDir(EXCLUSIONS_RELATIVE_PATH)
- val exclusionsText = VfsUtilCore.loadText(exclusionsFile)
- assertTrue(exclusionsText.contains("\"inspection\": \"MissingFrontendOrBackendRuntimeDependency\""))
- assertTrue(exclusionsText.contains("\"file\": \"intellij.test.feature.frontend.xml\""))
- assertTrue(exclusionsText.contains("\"line\": 1"))
- assertTrue(exclusionsText.contains("\"reason\": \"\""))
-
- val fileEditorManager = FileEditorManager.getInstance(project)
- assertEquals(exclusionsFile, fileEditorManager.selectedEditor?.file)
- val selectedTextEditor = fileEditorManager.selectedTextEditor
- assertNotNull(selectedTextEditor)
- assertEquals(selectedTextEditor!!.document.lineCount - 1, selectedTextEditor.caretModel.logicalPosition.line)
- }
-
private fun testAddingDependency(frontendOrBackend: String) {
doTest(
frontendOrBackend,
@@ -328,42 +222,12 @@ internal class MissingFrontendOrBackendRuntimeDependencyFixTest : JavaCodeInsigh
assertTrue(fileText.contains(""))
assertTrue(fileText.contains("intellij.platform.$frontendOrBackend"))
}
-
}
private fun CodeInsightTestFixture.addXmlFile(relativePath: String, @Language("XML") fileText: String): PsiFile {
return this.addFileToProject(relativePath, fileText)
}
-private fun CodeInsightTestFixture.addSplitModeExclusionsFile(@Language("JSON") fileText: String): PsiFile {
- return addFileToProject(EXCLUSIONS_RELATIVE_PATH, fileText)
-}
-
-private fun splitModeExclusionsJson(entry: String): String {
- return """
- {
- "exclusions": [
- $entry
- ]
- }
- """.trimIndent()
-}
-
-private fun missingRuntimeDependencyExclusion(file: String, line: Int, reason: String = "Documented test exclusion"): String {
- return """
- {
- "inspection": "MissingFrontendOrBackendRuntimeDependency",
- "file": "$file",
- "line": $line,
- "reason": "$reason"
- }
- """.trimIndent()
-}
-
private fun addRuntimeDependencyFixName(frontendOrBackend: String): String {
return "Make module 'intellij.test.feature.$frontendOrBackend' work in '$frontendOrBackend' only"
}
-
-private fun addToExclusionsFixName(): String {
- return "Add this violation to the exclusions list"
-}
\ No newline at end of file
diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeApiRestrictionsSourceModeTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeApiRestrictionsSourceModeTest.kt
index f841d38bff3c..ce7b398e5436 100644
--- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeApiRestrictionsSourceModeTest.kt
+++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeApiRestrictionsSourceModeTest.kt
@@ -7,7 +7,7 @@ import org.jetbrains.idea.devkit.inspections.remotedev.analysis.SplitModeApiRest
import org.junit.Assert
private const val API_RESTRICTIONS_PROJECT_RELATIVE_PATH =
- "community/plugins/devkit/devkit-core/resources/remotedevInspectionData/ApiRestrictions.json"
+ "community/plugins/devkit/devkit-core/resources/remotedevInspectionData/ApiRestrictions.json5"
internal class SplitModeApiRestrictionsSourceModeTest : BasePlatformTestCase() {
fun testProjectApiRestrictionsOverrideBundledListWhenProjectModeEnabled() {
@@ -36,6 +36,29 @@ internal class SplitModeApiRestrictionsSourceModeTest : BasePlatformTestCase() {
}
}
+ fun testProjectApiRestrictionKindCanBeRead() {
+ withApiRestrictionsSourceMode(
+ "project",
+ """
+ // Project-mode restrictions may use JSON5 comments.
+ [
+ {apiName: 'custom.split.mode.ui.api', targetModules: ['frontend'], restrictionKind: 'ui'},
+ /* Generic platform APIs may be explicitly marked as non-UI restrictions. */
+ {apiName: 'custom.split.mode.generic.api', targetModules: ['frontend'], restrictionKind: 'genericPlatformApi'},
+ ]
+ """.trimIndent(),
+ ) { service ->
+ Assert.assertEquals(
+ SplitModeApiRestrictionsService.ApiRestrictionKind.UI,
+ service.getCodeApiRestriction("custom.split.mode.ui.api", null)?.restrictionKind,
+ )
+ Assert.assertEquals(
+ SplitModeApiRestrictionsService.ApiRestrictionKind.GENERIC_PLATFORM_API,
+ service.getCodeApiRestriction("custom.split.mode.generic.api", null)?.restrictionKind,
+ )
+ }
+ }
+
fun testProjectApiRestrictionsReloadAfterProjectFileChange() {
withApiRestrictionsSourceMode(
"project",
diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeDependencyQuickFixesTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeDependencyQuickFixesTest.kt
index 31abc060a4c9..7f3a2798dd29 100644
--- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeDependencyQuickFixesTest.kt
+++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeDependencyQuickFixesTest.kt
@@ -55,8 +55,12 @@ internal class SplitModeDependencyQuickFixesTest : JavaCodeInsightFixtureTestCas
)
myFixture.configureFromExistingVirtualFile(pluginXml.virtualFile)
- launchActionAndWait("Make module 'unique.module.name.quick.fix.1' work in 'frontend' only") {
- getModuleDependencyNames(pluginXml).contains("intellij.platform.frontend")
+ val intention = myFixture.findSingleIntention("Make module 'unique.module.name.quick.fix.1' work in 'frontend' only")
+ myFixture.checkPreviewAndLaunchAction(intention)
+ timeoutRunBlocking {
+ waitUntil("Quick fix was not applied", 5.seconds) {
+ getModuleDependencyNames(pluginXml).contains("intellij.platform.frontend")
+ }
}
val result = myFixture.file.text
@@ -293,7 +297,7 @@ internal class SplitModeDependencyQuickFixesTest : JavaCodeInsightFixtureTestCas
- />
+ />
""".trimIndent()
diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeExcludedModulesScopeConsistencyTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeExcludedModulesScopeConsistencyTest.kt
new file mode 100644
index 000000000000..20ba813aa0f7
--- /dev/null
+++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeExcludedModulesScopeConsistencyTest.kt
@@ -0,0 +1,55 @@
+// Copyright 2000-2026 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.openapi.application.PathManager
+import com.intellij.testFramework.junit5.TestApplication
+import com.intellij.testFramework.junit5.fixture.projectFixture
+import org.jetbrains.idea.devkit.inspections.remotedev.MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH
+import org.jetbrains.idea.devkit.inspections.remotedev.SPLIT_MODE_EXCLUDED_MODULES_SCOPE_RELATIVE_PATHS
+import org.jetbrains.idea.devkit.inspections.remotedev.SplitModeInspectionResourceReadMode
+import org.jetbrains.idea.devkit.inspections.remotedev.SplitModeInspectionResourceReader
+import org.jetbrains.idea.devkit.inspections.remotedev.createSplitModeExcludedModulesScopeXml
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+import kotlin.io.path.exists
+import kotlin.io.path.readText
+import kotlin.io.path.writeText
+
+private const val UPDATE_SPLIT_MODE_EXCLUDED_MODULES_SCOPE_PROPERTY = "devkit.split.mode.excluded.modules.scope.update"
+
+@TestApplication
+internal class SplitModeExcludedModulesScopeConsistencyTest {
+ companion object {
+ private val projectFixture = projectFixture()
+ }
+
+ private val project get() = projectFixture.get()
+
+ @Test
+ fun `SplitModeExcludedModules scopes are generated from monorepo features without split mode support`() {
+ val projectRoot = getMonorepoRoot()
+ val expectedXml = createSplitModeExcludedModulesScopeXml(
+ SplitModeInspectionResourceReader.getInstance(project),
+ SplitModeInspectionResourceReadMode.BUNDLED_ONLY,
+ )
+
+ for (relativePath in SPLIT_MODE_EXCLUDED_MODULES_SCOPE_RELATIVE_PATHS) {
+ val scopeFile = projectRoot.resolve(relativePath)
+ if (java.lang.Boolean.getBoolean(UPDATE_SPLIT_MODE_EXCLUDED_MODULES_SCOPE_PROPERTY)) {
+ scopeFile.writeText(expectedXml)
+ }
+
+ val actualXml = scopeFile.readText()
+ assertEquals(
+ expectedXml,
+ actualXml,
+ "$relativePath must be generated from $MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH",
+ )
+ }
+ }
+
+ private fun getMonorepoRoot() = sequenceOf(PathManager.getHomeDir(), PathManager.getHomeDir().parent)
+ .filterNotNull()
+ .firstOrNull { it.resolve(MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH).exists() }
+ ?: PathManager.getHomeDir()
+}
diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeInspectionExclusionsReloadTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeInspectionExclusionsReloadTest.kt
index 2a4ad44faea9..6b82f35bf96e 100644
--- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeInspectionExclusionsReloadTest.kt
+++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeInspectionExclusionsReloadTest.kt
@@ -1,50 +1,62 @@
// Copyright 2000-2026 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.openapi.application.runWriteAction
+import com.intellij.openapi.project.IntelliJProjectUtil
+import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.testFramework.fixtures.BasePlatformTestCase
-import org.jetbrains.idea.devkit.inspections.remotedev.EXCLUSIONS_RELATIVE_PATH
-import org.jetbrains.idea.devkit.inspections.remotedev.SPLIT_MODE_API_USAGE_SHORT_NAME
-import org.jetbrains.idea.devkit.inspections.remotedev.SplitModeInspectionExclusionProblem
+import org.jetbrains.idea.devkit.inspections.remotedev.PROJECT_BASELINE_VERSION_RELATIVE_PATH
import org.jetbrains.idea.devkit.inspections.remotedev.SplitModeInspectionExclusionsService
import org.junit.Assert
internal class SplitModeInspectionExclusionsReloadTest : BasePlatformTestCase() {
- fun testExclusionsReloadAfterProjectFileChange() {
- val exclusionsFile = createProjectResourceFile(
+ fun testQuickFixesContainOnlyBaselineByDefault() {
+ IntelliJProjectUtil.markAsIntelliJPlatformProject(project, true)
+ val fixes = SplitModeInspectionExclusionsService.getInstance(project).createCommonSuppressionQuickFixes()
+
+ Assert.assertEquals(
+ listOf("Bypass incremental Split Mode safe-push tests"),
+ fixes.map { it.familyName },
+ )
+ }
+
+ fun testBaselineVersionIncreasesExistingProjectFile() {
+ val baselineVersionFile = createProjectResourceFile(
project,
- EXCLUSIONS_RELATIVE_PATH,
+ PROJECT_BASELINE_VERSION_RELATIVE_PATH,
"""
+ // Keep this comment.
{
- "exclusions": [
- {"inspection": "$SPLIT_MODE_API_USAGE_SHORT_NAME", "file": "src/example.kt", "line": 7}
- ]
+ "currentProjectBaselineVersion": 41
}
""".trimIndent(),
)
- val service = SplitModeInspectionExclusionsService.getInstance(project)
- val problem = SplitModeInspectionExclusionProblem(
- inspection = SPLIT_MODE_API_USAGE_SHORT_NAME,
- file = "src/example.kt",
- line = 7,
- )
try {
- Assert.assertTrue(service.isExcluded(problem))
+ val updatedFile = runWriteAction {
+ SplitModeInspectionExclusionsService.getInstance(project).increaseProjectBaselineVersion()
+ }
- createProjectResourceFile(
- project,
- EXCLUSIONS_RELATIVE_PATH,
+ Assert.assertEquals(baselineVersionFile, updatedFile)
+ Assert.assertEquals(
"""
+ // The file carries the current project baseline version for Split Mode Compatibility safe-push checks.
+ // Increase currentProjectBaselineVersion only when incremental Split Mode Compatibility tests incorrectly
+ // report pre-existing violations after large refactorings.
+ // Changing this value is a legal bypass: the affected safe push may skip the incremental Split Mode
+ // Compatibility tests for that run, allowing the refactoring to proceed while the baseline catches up.
+ // Do not use it for real new violations. Fix those instead; see Split Mode documentation IJPL-A-632.
+ // Contact the RemDev team in #ij-remote-dev if unsure.
{
- "exclusions": []
+ "currentProjectBaselineVersion": 42
}
- """.trimIndent(),
- )
- Assert.assertFalse(service.isExcluded(problem))
+ """.trimIndent(),
+ VfsUtilCore.loadText(baselineVersionFile),
+ )
}
finally {
- deleteProjectResourceFile(project, exclusionsFile)
+ deleteProjectResourceFile(project, baselineVersionFile)
}
}
}
diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModePredefinedModuleKindsAdditionalFileTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModePredefinedModuleKindsAdditionalFileTest.kt
index fc020a961913..2eb81c8d0606 100644
--- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModePredefinedModuleKindsAdditionalFileTest.kt
+++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModePredefinedModuleKindsAdditionalFileTest.kt
@@ -7,7 +7,7 @@ import org.jetbrains.idea.devkit.inspections.remotedev.analysis.SplitModeApiRest
import org.junit.Assert
private const val PREDEFINED_MODULE_KINDS_PROJECT_RELATIVE_PATH =
- "community/plugins/devkit/devkit-core/resources/remotedevInspectionData/PredefinedModuleKinds.json"
+ "community/plugins/devkit/devkit-core/resources/remotedevInspectionData/PredefinedModuleKinds.json5"
internal class SplitModePredefinedModuleKindsSourceModeTest : BasePlatformTestCase() {
fun testProjectPredefinedModuleKindsOverrideBundledListWhenProjectModeEnabled() {
@@ -15,7 +15,8 @@ internal class SplitModePredefinedModuleKindsSourceModeTest : BasePlatformTestCa
"project",
"""
[
- {"moduleName": "custom.split.mode.frontend", "moduleKind": "frontend"}
+ // JSON5 project overrides are accepted.
+ {kind: 'moduleId', id: 'custom.split.mode.frontend', moduleKind: 'frontend'},
]
""".trimIndent(),
) { service ->
@@ -49,7 +50,7 @@ internal class SplitModePredefinedModuleKindsSourceModeTest : BasePlatformTestCa
"project",
"""
[
- {"moduleName": "custom.split.mode.frontend", "moduleKind": "frontend"}
+ {kind: 'moduleId', id: 'custom.split.mode.frontend', moduleKind: 'frontend'},
]
""".trimIndent(),
) { service ->
@@ -65,7 +66,7 @@ internal class SplitModePredefinedModuleKindsSourceModeTest : BasePlatformTestCa
PREDEFINED_MODULE_KINDS_PROJECT_RELATIVE_PATH,
"""
[
- {"moduleName": "custom.split.mode.backend", "moduleKind": "backend"}
+ {kind: 'moduleId', id: 'custom.split.mode.backend', moduleKind: 'backend'},
]
""".trimIndent(),
)
diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeXmlApiUsageInspectionTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeXmlApiUsageInspectionTest.kt
index 97d32f8680cd..0535a4f653d0 100644
--- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeXmlApiUsageInspectionTest.kt
+++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/SplitModeXmlApiUsageInspectionTest.kt
@@ -1053,6 +1053,81 @@ No frontend or backend dependencies were found for descriptor 'unique.module.nam
.setValue(true, testRootDisposable)
}
+ fun testNonUiExtensionsInBackendWithNonUiApiPermitModule() {
+ val pluginXml = addModuleWithXmlDescriptor(
+ moduleName = "intellij.clion.radler.core",
+ descriptorRelativePathToResourcesDirectory = "META-INF/plugin.xml",
+ """
+
+
+
+
+
+
+ """.trimIndent()
+ )
+ myFixture.configureFromExistingVirtualFile(pluginXml.virtualFile)
+
+ myFixture.checkHighlighting()
+ }
+
+ fun testFrontendApiExtensionInOrdinaryBackendModule() {
+ val pluginXml = addModuleWithXmlDescriptor(
+ moduleName = "unique.module.name.64",
+ descriptorRelativePathToResourcesDirectory = "META-INF/plugin.xml",
+ """
+
+
+
+
+
+ <rdclient.actionCustomization/>
+
+
+ """.trimIndent()
+ )
+ myFixture.configureFromExistingVirtualFile(pluginXml.virtualFile)
+
+ myFixture.checkHighlighting()
+ }
+
+ fun testUiExtensionInBackendWithNonUiApiPermitModule() {
+ val pluginXml = addModuleWithXmlDescriptor(
+ moduleName = "intellij.clion.radler.core",
+ descriptorRelativePathToResourcesDirectory = "META-INF/plugin.xml",
+ """
+
+
+ <toolWindow/>
+
+
+ """.trimIndent()
+ )
+ myFixture.configureFromExistingVirtualFile(pluginXml.virtualFile)
+
+ myFixture.checkHighlighting()
+ }
+
+ fun testBackendWithNonUiApiPermitModuleIsBackendDependencyEvidence() {
+ val pluginXml = addModuleWithXmlDescriptor(
+ moduleName = "unique.module.name.65",
+ descriptorRelativePathToResourcesDirectory = "META-INF/plugin.xml",
+ """
+
+
+
+
+
+ <lang.parserDefinition/>
+
+
+ """.trimIndent()
+ )
+ myFixture.configureFromExistingVirtualFile(pluginXml.virtualFile)
+
+ myFixture.checkHighlighting()
+ }
+
fun testSharedExtensionInBackendModule() {
val pluginXml = addModuleWithXmlDescriptor(
moduleName = "unique.module.name.48",
diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/navigation/DescriptorSplitModeInlayHintsProviderTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/navigation/DescriptorSplitModeInlayHintsProviderTest.kt
new file mode 100644
index 000000000000..b44c73242886
--- /dev/null
+++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/navigation/DescriptorSplitModeInlayHintsProviderTest.kt
@@ -0,0 +1,256 @@
+// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package org.jetbrains.idea.devkit.navigation
+
+import com.intellij.codeInsight.hints.declarative.InlayProviderPassInfo
+import com.intellij.codeInsight.hints.declarative.impl.DeclarativeInlayHintsPass
+import com.intellij.codeInsight.hints.declarative.impl.inlayRenderer.DeclarativeInlayRenderer
+import com.intellij.codeInsight.hints.declarative.impl.views.InlayPresentationList
+import com.intellij.codeInsight.hints.declarative.impl.views.TextInlayPresentationEntry
+import com.intellij.codeInsight.multiverse.codeInsightContext
+import com.intellij.openapi.actionSystem.ex.ActionUtil
+import com.intellij.openapi.progress.EmptyProgressIndicator
+import com.intellij.openapi.util.registry.Registry
+import com.intellij.psi.xml.XmlFile
+import com.intellij.testFramework.PsiTestUtil
+import com.intellij.testFramework.TestDataPath
+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
+
+@TestDataPath($$"$CONTENT_ROOT/testData/navigation/descriptorsIncludingContentModule")
+internal class DescriptorSplitModeInlayHintsProviderTest : JavaCodeInsightFixtureTestCase() {
+
+ override fun getBasePath() = DevkitJavaTestsUtil.TESTDATA_PATH + "navigation/descriptorsIncludingContentModule"
+
+ fun testFrontendContentModuleInlay() {
+ createModuleWithModuleDescriptor("declaring.module", "declaring.module.xml", """
+
+
+
+
+
+ """.trimIndent()
+ )
+
+ createModuleWithModuleDescriptor("test.module", "test.module.xml", """
+
+
+
+
+
+ """.trimIndent()
+ )
+
+ testDescriptorInlay(
+ descriptorPath = "test.module/test.module.xml",
+ expectedInlayText = "Frontend content module",
+ expectedTooltip = expectedTooltip(
+ descriptorKind = "content module",
+ compatibilityTarget = "frontend IDE",
+ reason = "Frontend dependency 'intellij.platform.frontend' from descriptor 'test.module.xml' in module 'test.module'",
+ ),
+ )
+ }
+
+ fun testSharedContentModuleInlay() {
+ createModuleWithModuleDescriptor("declaring.module", "declaring.module.xml", """
+
+
+
+
+
+ """.trimIndent()
+ )
+
+ createModuleWithModuleDescriptor("test.module", "test.module.xml", """
+
+
+
+ """.trimIndent()
+ )
+
+ testDescriptorInlay(
+ descriptorPath = "test.module/test.module.xml",
+ expectedInlayText = "Shared content module",
+ expectedTooltip = expectedTooltip(
+ descriptorKind = "content module",
+ compatibilityTarget = "both frontend and backend IDE",
+ reason = "No frontend or backend dependencies were found for descriptor 'test.module.xml' in module 'test.module'",
+ ),
+ )
+ }
+
+ fun testBackendPluginInlay() {
+ createModuleWithModuleDescriptor("root.plugin", "plugin.xml", """
+
+
+
+
+
+ """.trimIndent()
+ )
+
+ testDescriptorInlay(
+ descriptorPath = "root.plugin/plugin.xml",
+ expectedInlayText = "Backend plugin",
+ expectedTooltip = expectedTooltip(
+ descriptorKind = "plugin",
+ compatibilityTarget = "backend IDE",
+ reason = "Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in module 'root.plugin'",
+ ),
+ )
+ }
+
+ fun testMixedContentModuleInlayUsesMonolithPresentation() {
+ createModuleWithModuleDescriptor("declaring.module", "declaring.module.xml", """
+
+
+
+
+
+ """.trimIndent()
+ )
+
+ createModuleWithModuleDescriptor("test.module", "test.module.xml", """
+
+
+
+
+
+
+ """.trimIndent()
+ )
+
+ testDescriptorInlay(
+ descriptorPath = "test.module/test.module.xml",
+ expectedInlayText = "Monolith content module",
+ expectedTooltip = expectedTooltip(
+ descriptorKind = "content module",
+ compatibilityTarget = "monolith IDE",
+ reason = """
+ Frontend dependency 'intellij.platform.frontend' from descriptor 'test.module.xml' in module 'test.module'
+
+ Backend dependency 'intellij.platform.backend' from descriptor 'test.module.xml' in module 'test.module'
+ """.trimIndent(),
+ ),
+ )
+ }
+
+ fun testMonolithPluginInlay() {
+ createModuleWithModuleDescriptor("root.plugin", "plugin.xml", """
+
+
+
+
+
+ """.trimIndent()
+ )
+
+ testDescriptorInlay(
+ descriptorPath = "root.plugin/plugin.xml",
+ expectedInlayText = "Monolith plugin",
+ expectedTooltip = expectedTooltip(
+ descriptorKind = "plugin",
+ compatibilityTarget = "monolith IDE",
+ reason = "Monolith dependency 'intellij.platform.monolith' from descriptor 'plugin.xml' in module 'root.plugin'",
+ ),
+ )
+ }
+
+ fun testNonPluginXmlDescriptorInlay() {
+ createModuleWithModuleDescriptor("root.plugin", "root.plugin.optional.xml", """
+
+
+
+
+
+ """.trimIndent()
+ )
+
+ testDescriptorInlay(
+ descriptorPath = "root.plugin/root.plugin.optional.xml",
+ expectedInlayText = "Backend XML descriptor",
+ expectedTooltip = expectedTooltip(
+ descriptorKind = "XML descriptor",
+ compatibilityTarget = "backend IDE",
+ reason = "Backend dependency 'intellij.platform.backend' from descriptor 'root.plugin.optional.xml' in module 'root.plugin'",
+ ),
+ )
+ }
+
+ fun testRegistryDisablesInlay() {
+ Registry.get("devkit.split.mode.inlay.plugin.descriptor.kind").setValue(false, testRootDisposable)
+
+ createModuleWithModuleDescriptor("root.plugin", "plugin.xml", """
+
+
+
+
+
+ """.trimIndent()
+ )
+
+ myFixture.configureFromTempProjectFile("root.plugin/plugin.xml")
+
+ runInlayPass()
+
+ assertEmpty(myFixture.editor.inlayModel.getInlineElementsInRange(0, myFixture.editor.document.textLength))
+ }
+
+ private fun createModuleWithModuleDescriptor(
+ moduleName: String,
+ moduleDescriptorName: String,
+ @Language("XML") moduleDescriptorText: String,
+ ) {
+ PsiTestUtil.addModule(
+ project,
+ PluginModuleType.getInstance(),
+ moduleName,
+ myFixture.tempDirFixture.findOrCreateDir(moduleName)
+ )
+ myFixture.addFileToProject("$moduleName/$moduleDescriptorName", moduleDescriptorText)
+ }
+
+ private fun testDescriptorInlay(
+ descriptorPath: String,
+ expectedInlayText: String,
+ expectedTooltip: String,
+ ) {
+ val xmlFile = myFixture.configureFromTempProjectFile(descriptorPath) as XmlFile
+
+ runInlayPass()
+
+ val inlay = myFixture.editor.inlayModel
+ .getInlineElementsInRange(0, myFixture.editor.document.textLength, DeclarativeInlayRenderer::class.java)
+ .single()
+ assertEquals(expectedInlayText, inlay.renderer.presentationLists.single().getText())
+ assertEquals(expectedTooltip, inlay.renderer.toInlayData().single().tooltip)
+
+ val inlayInfo = getDescriptorSplitModeInlayInfo(xmlFile)
+ assertNotNull(inlayInfo)
+ assertEquals(expectedInlayText, inlayInfo!!.text)
+ assertEquals(expectedTooltip, inlayInfo.tooltip)
+ }
+
+ private fun expectedTooltip(descriptorKind: String, compatibilityTarget: String, reason: String): String {
+ val normalizedReason = reason.lineSequence().map(String::trim).filter(String::isNotEmpty).joinToString(" ")
+ return "Split mode compatibility: $descriptorKind can be installed into $compatibilityTarget. Reason: $normalizedReason"
+ }
+
+ private fun runInlayPass() {
+ val providerInfo = InlayProviderPassInfo(DescriptorSplitModeInlayHintsProvider(), "test.inlay.provider", emptyMap())
+ val pass = ActionUtil.underModalProgress(project, "") {
+ DeclarativeInlayHintsPass(myFixture.file, myFixture.editor, listOf(providerInfo), isPreview = false)
+ }
+ pass.setContext(myFixture.file.codeInsightContext)
+ ActionUtil.underModalProgress(project, "") {
+ pass.doCollectInformation(EmptyProgressIndicator())
+ }
+ pass.applyInformationToEditor()
+ }
+
+ private fun InlayPresentationList.getText(): String {
+ return getEntries().joinToString(separator = "") { (it as TextInlayPresentationEntry).text }
+ }
+}
diff --git a/plugins/devkit/devkit-kotlin-fir-tests/testSrc/org/jetbrains/idea/devkit/k2/inspections/remotedev/SplitModeApiUsageInspectionTest.kt b/plugins/devkit/devkit-kotlin-fir-tests/testSrc/org/jetbrains/idea/devkit/k2/inspections/remotedev/SplitModeApiUsageInspectionTest.kt
index dcd6b2a69549..66849d7ef601 100644
--- a/plugins/devkit/devkit-kotlin-fir-tests/testSrc/org/jetbrains/idea/devkit/k2/inspections/remotedev/SplitModeApiUsageInspectionTest.kt
+++ b/plugins/devkit/devkit-kotlin-fir-tests/testSrc/org/jetbrains/idea/devkit/k2/inspections/remotedev/SplitModeApiUsageInspectionTest.kt
@@ -112,6 +112,36 @@ class SplitModeApiUsageInspectionTest : LightJavaCodeInsightFixtureTestCase() {
""".trimIndent()
)
+ myFixture.addClass(
+ """
+ package com.intellij.openapi.roots;
+
+ public interface FileIndex {}
+ """.trimIndent()
+ )
+
+ myFixture.addClass(
+ """
+ package com.intellij.openapi.roots;
+
+ import com.intellij.openapi.project.Project;
+
+ public interface ProjectFileIndex extends FileIndex {
+ static ProjectFileIndex getInstance(Project project) {
+ return null;
+ }
+ }
+ """.trimIndent()
+ )
+
+ myFixture.addClass(
+ """
+ package com.intellij.openapi.roots;
+
+ public interface ModuleFileIndex extends FileIndex {}
+ """.trimIndent()
+ )
+
myFixture.addClass(
"""
package com.intellij.openapi.options;
@@ -237,22 +267,22 @@ class SplitModeApiUsageInspectionTest : LightJavaCodeInsightFixtureTestCase() {
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.fileEditor.FileEditorManager;
- class CustomToolWindowFactory: ToolWindowFactory {}
+Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">ToolWindowFactory {}
class BackendService {
fun doStuff() {
// no warning here expected
VirtualFileManager.getInstance()
- FileEditorManager.getInstance().getFocusedEditor()
+Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">FileEditorManager.getInstance().getFocusedEditor()
}
}
""".trimIndent()
@@ -306,11 +336,11 @@ Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in m
class SharedLangModule {
fun test() {
- VirtualFileManager.getInstance()
+Predefined module kind for plugin/module id 'com.intellij.modules.lang'">VirtualFileManager.getInstance()
}
}
""".trimIndent()
@@ -344,11 +374,11 @@ Predefined module kind for plugin/module id 'com.intellij.modules.lang'">Virtual
class FrontendService {
fun doStuff() {
- VirtualFileManager.getInstance()
+Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">VirtualFileManager.getInstance()
}
}
""".trimIndent()
@@ -357,7 +387,60 @@ Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in
myFixture.checkHighlighting()
}
- fun testConfigurableApiInBackendModule() {
+ fun testFileIndexApiInFrontendModule() {
+ configurePluginXml(
+ """
+
+
+
+
+
+ """.trimIndent()
+ )
+
+ myFixture.configureByText(
+ "FrontendFileIndexService.kt", """
+ package com.example.frontend
+
+ import com.intellij.openapi.project.Project
+ import com.intellij.openapi.roots.FileIndex
+ import com.intellij.openapi.roots.ModuleFileIndex
+ import com.intellij.openapi.roots.ProjectFileIndex
+
+ class FrontendFileIndexService(private val project: Project) {
+ fun doStuff() {
+ ProjectFileIndex.getInstance(project)
+ }
+ }
+
+ class FrontendFileIndex : FileIndex
+
+ class FrontendProjectFileIndex : ProjectFileIndex
+
+ class FrontendModuleFileIndex : ModuleFileIndex
+ """.trimIndent()
+ )
+
+ myFixture.checkHighlighting()
+ }
+
+ fun testFrontendOrBackendApiInBackendModule() {
configurePluginXml(
"""
@@ -369,12 +452,12 @@ Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in
)
myFixture.configureByText(
- "BackendConfigurable.kt", """
+ "BackendDynamicPluginListener.kt", """
package com.example.backend
- import com.intellij.openapi.options.Configurable
+ import com.intellij.ide.plugins.DynamicPluginListener
- class BackendConfigurable : Configurable
+ class BackendDynamicPluginListener : DynamicPluginListener
""".trimIndent()
)
@@ -398,11 +481,11 @@ Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in
import com.intellij.openapi.fileEditor.FileEditorManagerListener
- class BackendFileEditorListener : FileEditorManagerListener
+Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">FileEditorManagerListener
""".trimIndent()
)
@@ -426,11 +509,11 @@ Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in m
import com.intellij.lang.ParserDefinition
- class FrontendParserDefinition : ParserDefinition
+Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">ParserDefinition
""".trimIndent()
)
@@ -454,11 +537,11 @@ Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in
import com.intellij.openapi.project.ProjectManagerListener
- class FrontendProjectManagerListener : ProjectManagerListener
+Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">ProjectManagerListener
""".trimIndent()
)
@@ -490,11 +573,11 @@ Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in
class FrontendService {
fun doStuff() {
- VirtualFileManager.getInstance()
+Frontend dependency 'intellij.platform.frontend' from descriptor 'light_idea_test_case.xml' in module 'light_idea_test_case'">VirtualFileManager.getInstance()
}
}
""".trimIndent()
@@ -522,11 +605,11 @@ Frontend dependency 'intellij.platform.frontend' from descriptor 'light_idea_tes
class FrontendService {
fun doStuff() {
- AnnotatedBackendApi.getInstance()
+Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">AnnotatedBackendApi.getInstance()
}
}
""".trimIndent()
@@ -554,11 +637,11 @@ Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in
class BackendService {
fun doStuff() {
- AnnotatedFrontendApi.getInstance()
+Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">AnnotatedFrontendApi.getInstance()
}
}
""".trimIndent()
@@ -589,19 +672,19 @@ Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in m
// both warnings are expected in a shared module
class SharedService {
fun testFrontendApi() {
- class MyToolWindow: ToolWindowFactory {}
+No frontend or backend dependencies were found for module 'light_idea_test_case'">ToolWindowFactory {}
}
fun testBackendApi() {
- VirtualFileManager.getInstance()
+No frontend or backend dependencies were found for module 'light_idea_test_case'">VirtualFileManager.getInstance()
}
}
""".trimIndent()
@@ -627,13 +710,13 @@ No frontend or backend dependencies were found for module 'light_idea_test_case'
import com.intellij.ide.plugins.DynamicPluginListener
- class SharedDynamicPluginListener : DynamicPluginListener
+No frontend or backend dependencies were found for module 'light_idea_test_case'">DynamicPluginListener
""".trimIndent()
)
@@ -732,7 +815,9 @@ No frontend or backend dependencies were found for module 'light_idea_test_case'
""".trimIndent()
)
- launchActionAndWait("Make module 'light_idea_test_case' work in 'frontend' only") {
+ val intention = myFixture.findSingleIntention("Make module 'light_idea_test_case' work in 'frontend' only")
+ assertNull(myFixture.getIntentionPreviewText(intention))
+ launchActionAndWait(intention) {
getModuleDependencyNames().contains("intellij.platform.frontend")
}
@@ -854,7 +939,8 @@ No frontend or backend dependencies were found for module 'light_idea_test_case'
)
addCurrentModuleDependencies("intellij.platform.frontend")
- launchActionAndWait("Make module 'light_idea_test_case' work in 'backend' only") {
+ val intention = myFixture.findSingleIntention("Make module 'light_idea_test_case' work in 'backend' only")
+ launchActionAndWait(intention) {
!getModuleDependencyNames().contains("intellij.platform.frontend")
}
@@ -879,11 +965,6 @@ No frontend or backend dependencies were found for module 'light_idea_test_case'
}
}
- private fun launchActionAndWait(intentionText: String, condition: () -> Boolean) {
- val intention = myFixture.findSingleIntention(intentionText)
- launchActionAndWait(intention, condition)
- }
-
private fun launchActionAndWait(intention: IntentionAction, condition: () -> Boolean) {
myFixture.launchAction(intention)
timeoutRunBlocking {
diff --git a/plugins/devkit/intellij.devkit.mcp/BUILD.bazel b/plugins/devkit/intellij.devkit.mcp/BUILD.bazel
index 1e6f73955803..afcd9607052c 100644
--- a/plugins/devkit/intellij.devkit.mcp/BUILD.bazel
+++ b/plugins/devkit/intellij.devkit.mcp/BUILD.bazel
@@ -28,6 +28,9 @@ jvm_library(
"//platform/lang-core",
"//platform/util",
"//java/java-psi-api:psi",
+ "//platform/analysis-api:analysis",
+ "//platform/analysis-impl",
+ "//platform/projectModel-api:projectModel",
"//libraries/kotlinx/serialization/json",
"//libraries/kotlinx/serialization/core",
"//platform/progress/shared:ide-progress",
@@ -53,6 +56,9 @@ jvm_library(
"//platform/lang-core:lang-core_test_lib",
"//platform/util:util_test_lib",
"//java/java-psi-api:psi_test_lib",
+ "//platform/analysis-api:analysis_test_lib",
+ "//platform/analysis-impl:analysis-impl_test_lib",
+ "//platform/projectModel-api:projectModel_test_lib",
"//libraries/kotlinx/serialization/json:json_test_lib",
"//libraries/kotlinx/serialization/core:core_test_lib",
"//platform/progress/shared:ide-progress_test_lib",
diff --git a/plugins/devkit/intellij.devkit.mcp/intellij.devkit.mcp.iml b/plugins/devkit/intellij.devkit.mcp/intellij.devkit.mcp.iml
index e22095f8a645..143cab4a32d2 100644
--- a/plugins/devkit/intellij.devkit.mcp/intellij.devkit.mcp.iml
+++ b/plugins/devkit/intellij.devkit.mcp/intellij.devkit.mcp.iml
@@ -38,6 +38,9 @@
+
+
+
diff --git a/plugins/devkit/intellij.devkit.mcp/resources/intellij.devkit.mcp.xml b/plugins/devkit/intellij.devkit.mcp/resources/intellij.devkit.mcp.xml
index 251609bb9f84..09d0823cb3f6 100644
--- a/plugins/devkit/intellij.devkit.mcp/resources/intellij.devkit.mcp.xml
+++ b/plugins/devkit/intellij.devkit.mcp/resources/intellij.devkit.mcp.xml
@@ -1,13 +1,21 @@
+
-
-
+
-
+
+
+
+
+
+
+
+
+
diff --git a/plugins/devkit/intellij.devkit.mcp/src/DevKitMcpToolset.kt b/plugins/devkit/intellij.devkit.mcp/src/DevKitMcpToolset.kt
index f5c51d696620..0265eba2a894 100644
--- a/plugins/devkit/intellij.devkit.mcp/src/DevKitMcpToolset.kt
+++ b/plugins/devkit/intellij.devkit.mcp/src/DevKitMcpToolset.kt
@@ -31,6 +31,8 @@ import java.util.Collections
import java.util.EnumSet
import kotlin.time.Duration.Companion.milliseconds
+private const val DEFAULT_SPLIT_MODE_COMPATIBILITY_ANALYSIS_TIMEOUT_MILLISECONDS: Int = 5 * 60 * 1000
+
class DevKitMcpToolset : McpToolset {
@McpTool
@McpDescription(
@@ -94,6 +96,41 @@ class DevKitMcpToolset : McpToolset {
return recognizeSplitModeModuleKindForPath(descriptorPath)
}
+ @McpTool
+ @McpDescription(
+ """
+ |Recognizes the Split Mode API kind for a fully qualified API name using the same DevKit restriction data
+ |as the remdev inspections.
+ |Returns the target module kind when the API is listed in DevKit split-mode restrictions.
+ """
+ )
+ @Suppress("unused", "FunctionName")
+ suspend fun recognize_split_mode_api_kind(
+ @McpDescription("Fully qualified code API name, for example `com.intellij.openapi.ui.DialogWrapper`.")
+ apiName: String,
+ ): RecognizeSplitModeApiKindResult {
+ return recognizeSplitModeApiKind(apiName)
+ }
+
+ @McpTool
+ @McpDescription(
+ """
+ |Collects Split Mode compatibility issues for all supported files under the given directory.
+ |Runs only the DevKit split-mode compatibility inspection whitelist and returns every found issue.
+ |Whitelisted inspections: SplitModeApiUsage, SplitModeXmlApiUsage, SplitModeMixedDependencies,
+ |SplitModeImplicitModuleKind, MissingFrontendOrBackendRuntimeDependency.
+ """
+ )
+ @Suppress("unused", "FunctionName")
+ suspend fun collect_split_mode_compatibility_issues(
+ @McpDescription(Constants.RELATIVE_PATH_IN_PROJECT_DESCRIPTION)
+ directoryPath: String,
+ @McpDescription("Analysis timeout in milliseconds.")
+ analysisTimeout: Int = DEFAULT_SPLIT_MODE_COMPATIBILITY_ANALYSIS_TIMEOUT_MILLISECONDS,
+ ): SplitModeCompatibilityIssuesResult {
+ return collectSplitModeCompatibilityIssues(directoryPath, analysisTimeout)
+ }
+
@McpTool
@McpDescription("""
|Analyzes the usage of the Read/Write lock for the method under the caret.
@@ -169,12 +206,14 @@ class DevKitMcpToolset : McpToolset {
mapper: (ConstraintType) -> T,
): Pair>>, Boolean> {
val project = currentCoroutineContext().project
- val file = VirtualFileManager.getInstance().findFileByNioPath(project.resolveInProject(filePath)) ?: throw McpExpectedError("Virtual file not found")
+ val file = VirtualFileManager.getInstance().findFileByNioPath(project.resolveInProject(filePath))
+ ?: throw McpExpectedError("Virtual file not found")
val pointer = readAction {
val document = FileDocumentManager.getInstance().getDocument(file)
val psiTree = PsiManager.getInstance(project).findFile(file) ?: throw McpExpectedError("PsiFile not found")
val offset = document?.getLineStartOffset(line - 1)?.plus(column - 1) ?: throw McpExpectedError("Invalid line/column")
- val method = LockReqPsiOps.forLanguage(psiTree.language).extractTargetElement(psiTree, offset) ?: throw McpExpectedError("No method found at the specified position")
+ val method = LockReqPsiOps.forLanguage(psiTree.language).extractTargetElement(psiTree, offset)
+ ?: throw McpExpectedError("No method found at the specified position")
SmartPointerManager.createPointer(method)
}
@@ -183,15 +222,18 @@ class DevKitMcpToolset : McpToolset {
val result = withTimeoutOrNull(timeout.milliseconds) {
@Suppress("HardCodedStringLiteral")
withBackgroundProgress(project, "Analyzing Locking Requirements usage for AI", true) {
- LockReqAnalyzerParallelBFS().analyzeMethodStreaming(pointer, AnalysisConfig.forProject(project, requirementSet), project, object : LockReqConsumer {
- override fun onPath(path: ExecutionPath) {
- val lockType = mapper(path.lockRequirement.constraintType)
- val locations = path.methodChain.map {
- SourceLocation(it.containingClassName ?: "", it.methodName)
- }
- list.add(lockType to locations)
- }
- })
+ LockReqAnalyzerParallelBFS().analyzeMethodStreaming(pointer,
+ AnalysisConfig.forProject(project, requirementSet),
+ project,
+ object : LockReqConsumer {
+ override fun onPath(path: ExecutionPath) {
+ val lockType = mapper(path.lockRequirement.constraintType)
+ val locations = path.methodChain.map {
+ SourceLocation(it.containingClassName ?: "", it.methodName)
+ }
+ list.add(lockType to locations)
+ }
+ })
}
}
val timeout = result == null
@@ -199,7 +241,7 @@ class DevKitMcpToolset : McpToolset {
}
enum class LockType {
- READ_ASSERTION, WRITE_ASSERTION, WRITE_INTENT_ASSERTION, NO_READ_ASSERTION
+ READ_ASSERTION, WRITE_ASSERTION, WRITE_INTENT_ASSERTION, NO_READ_ASSERTION
}
enum class ThreadType {
@@ -250,4 +292,50 @@ class DevKitMcpToolset : McpToolset {
@property:McpDescription("Reasoning produced by the same DevKit module-kind analysis used by the remdev inspections.")
val reasoning: String,
)
+
+ @Serializable
+ data class RecognizeSplitModeApiKindResult(
+ @property:McpDescription("Fully qualified code API name that was recognized.")
+ val apiName: String,
+ @property:McpDescription("Target Split Mode module kind for this API, or null when no restriction matches.")
+ val kindId: String?,
+ @property:McpDescription("Optional hint from the DevKit split-mode restrictions data.")
+ val hint: String?,
+ )
+
+ @Serializable
+ data class SplitModeCompatibilityIssuesResult(
+ @property:McpDescription("Directory path that was analyzed, relative to the project root when provided that way.")
+ val directoryPath: String,
+ @property:McpDescription("Split Mode inspection short names used for this analysis.")
+ val inspectionIds: List,
+ @property:McpDescription("Number of supported source files inspected under the directory.")
+ val inspectedFileCount: Int,
+ @property:McpDescription("All found Split Mode compatibility issues from the whitelisted inspections.")
+ val issues: List,
+ @property:McpDescription(Constants.TIMED_OUT_DESCRIPTION)
+ val timedOut: Boolean,
+ )
+
+ @Serializable
+ data class SplitModeCompatibilityIssue(
+ @property:McpDescription("Inspection short name that reported the issue.")
+ val inspectionId: String,
+ @property:McpDescription("Problem highlight type reported by the inspection.")
+ val severity: String,
+ @property:McpDescription("Problem file path, relative to the project root when possible.")
+ val filePath: String,
+ @property:McpDescription("1-based start line, if available.")
+ val line: Int?,
+ @property:McpDescription("1-based start column, if available.")
+ val column: Int?,
+ @property:McpDescription("1-based end line, if available.")
+ val endLine: Int?,
+ @property:McpDescription("1-based end column, if available.")
+ val endColumn: Int?,
+ @property:McpDescription("Rendered inspection problem description.")
+ val description: String,
+ @property:McpDescription("Quick-fix family names available in batch mode.")
+ val quickFixes: List,
+ )
}
diff --git a/plugins/devkit/intellij.devkit.mcp/src/DevKitSplitModeCompatibilityInspectionApi.kt b/plugins/devkit/intellij.devkit.mcp/src/DevKitSplitModeCompatibilityInspectionApi.kt
new file mode 100644
index 000000000000..b752b87579e5
--- /dev/null
+++ b/plugins/devkit/intellij.devkit.mcp/src/DevKitSplitModeCompatibilityInspectionApi.kt
@@ -0,0 +1,208 @@
+// 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.devkit.mcp
+
+import com.intellij.codeInspection.InspectionEngine
+import com.intellij.codeInspection.ProblemDescriptor
+import com.intellij.codeInspection.ProblemDescriptorBase
+import com.intellij.codeInspection.ProblemDescriptorUtil
+import com.intellij.codeInspection.ex.LocalInspectionToolWrapper
+import com.intellij.mcpserver.mcpFail
+import com.intellij.mcpserver.project
+import com.intellij.mcpserver.util.resolveInProject
+import com.intellij.openapi.application.smartReadAction
+import com.intellij.openapi.fileEditor.FileDocumentManager
+import com.intellij.openapi.progress.EmptyProgressIndicator
+import com.intellij.openapi.progress.ProgressManager
+import com.intellij.openapi.progress.checkCanceled
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.roots.ProjectFileIndex
+import com.intellij.openapi.util.TextRange
+import com.intellij.openapi.vfs.VfsUtilCore
+import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.openapi.vfs.VirtualFileManager
+import com.intellij.openapi.vfs.VirtualFileVisitor
+import com.intellij.platform.ide.progress.withBackgroundProgress
+import com.intellij.psi.PsiFile
+import com.intellij.psi.PsiManager
+import com.intellij.util.PairProcessor
+import kotlinx.coroutines.currentCoroutineContext
+import kotlinx.coroutines.withTimeoutOrNull
+import kotlin.time.Duration.Companion.milliseconds
+
+private val SPLIT_MODE_COMPATIBILITY_INSPECTION_IDS = listOf(
+ "SplitModeApiUsage",
+ "SplitModeXmlApiUsage",
+ "SplitModeMixedDependencies",
+ "SplitModeImplicitModuleKind",
+ "MissingFrontendOrBackendRuntimeDependency",
+)
+
+private val SPLIT_MODE_COMPATIBILITY_FILE_EXTENSIONS = setOf("java", "kt", "kts", "xml")
+
+internal suspend fun collectSplitModeCompatibilityIssues(
+ directoryPath: String,
+ analysisTimeout: Int,
+): DevKitMcpToolset.SplitModeCompatibilityIssuesResult {
+ val project = currentCoroutineContext().project
+ val resolvedDirectoryPath = project.resolveInProject(directoryPath)
+ val directory = VirtualFileManager.getInstance().findFileByNioPath(resolvedDirectoryPath)
+ ?: VirtualFileManager.getInstance().refreshAndFindFileByNioPath(resolvedDirectoryPath)
+ ?: mcpFail("Directory not found: $directoryPath")
+ if (!directory.isDirectory) {
+ mcpFail("Not a directory: $directoryPath")
+ }
+
+ loadSplitModeRestrictions(project)
+
+ var result = SplitModeCompatibilityInspectionRunResult(emptyList(), 0)
+ val timedOut = withTimeoutOrNull(analysisTimeout.milliseconds) {
+ @Suppress("HardCodedStringLiteral")
+ withBackgroundProgress(project, "Collecting Split Mode compatibility issues", true) {
+ val inspectionFiles = smartReadAction(project) {
+ collectInspectionFiles(directory, project)
+ }
+
+ val issues = mutableListOf()
+ var inspectedFileCount = 0
+ for (virtualFile in inspectionFiles) {
+ checkCanceled()
+ val fileIssues = smartReadAction(project) {
+ val psiManager = PsiManager.getInstance(project)
+ val psiFile = psiManager.findFile(virtualFile) ?: return@smartReadAction null
+ val tools = getSplitModeCompatibilityInspectionTools(project)
+ inspectSplitModeCompatibilityFile(project, psiFile, tools)
+ } ?: continue
+ inspectedFileCount++
+ issues += fileIssues
+ }
+ result = SplitModeCompatibilityInspectionRunResult(issues, inspectedFileCount)
+ }
+ } == null
+
+ return DevKitMcpToolset.SplitModeCompatibilityIssuesResult(
+ directoryPath = directoryPath,
+ inspectionIds = SPLIT_MODE_COMPATIBILITY_INSPECTION_IDS,
+ inspectedFileCount = result.inspectedFileCount,
+ issues = result.issues.sortedWith(compareBy(
+ { it.filePath },
+ { it.line ?: Int.MAX_VALUE },
+ { it.column ?: Int.MAX_VALUE },
+ { it.inspectionId },
+ { it.description },
+ )),
+ timedOut = timedOut,
+ )
+}
+
+private fun getSplitModeCompatibilityInspectionTools(project: Project): List {
+ return SPLIT_MODE_COMPATIBILITY_INSPECTION_IDS.map { inspectionId ->
+ val wrapper = LocalInspectionToolWrapper.findTool2RunInBatch(project, null, inspectionId)
+ ?: mcpFail("Inspection not found: $inspectionId")
+ val localWrapper = wrapper as? LocalInspectionToolWrapper
+ ?: mcpFail("Inspection is not a local inspection: $inspectionId")
+ localWrapper.createCopy()
+ }
+}
+
+private fun collectInspectionFiles(root: VirtualFile, project: Project): List {
+ val projectFileIndex = ProjectFileIndex.getInstance(project)
+ val files = mutableListOf()
+ VfsUtilCore.visitChildrenRecursively(root, object : VirtualFileVisitor() {
+ override fun visitFile(file: VirtualFile): Boolean {
+ ProgressManager.checkCanceled()
+ if (projectFileIndex.isUnderIgnored(file)) {
+ return false
+ }
+ if (file.isDirectory) {
+ return true
+ }
+
+ val extension = file.extension?.lowercase()
+ if (extension in SPLIT_MODE_COMPATIBILITY_FILE_EXTENSIONS && projectFileIndex.getModuleForFile(file, true) != null) {
+ files += file
+ }
+ return true
+ }
+ })
+ return files
+}
+
+private fun inspectSplitModeCompatibilityFile(
+ project: Project,
+ psiFile: PsiFile,
+ tools: List,
+): List {
+ val descriptorsByTool = InspectionEngine.inspectEx(
+ tools,
+ psiFile,
+ psiFile.textRange,
+ psiFile.textRange,
+ false,
+ true,
+ true,
+ EmptyProgressIndicator(),
+ PairProcessor.alwaysTrue(),
+ )
+
+ return descriptorsByTool.flatMap { (tool, descriptors) ->
+ descriptors.map { descriptor ->
+ descriptor.toSplitModeCompatibilityIssue(project, tool.shortName)
+ }
+ }
+}
+
+private fun ProblemDescriptor.toSplitModeCompatibilityIssue(
+ project: Project,
+ inspectionId: String,
+): DevKitMcpToolset.SplitModeCompatibilityIssue {
+ val textRange = (this as? ProblemDescriptorBase)?.textRange ?: psiElement?.textRange
+ val virtualFile = (this as? ProblemDescriptorBase)?.containingFile ?: psiElement?.containingFile?.virtualFile
+ val position = computePosition(virtualFile, textRange)
+ return DevKitMcpToolset.SplitModeCompatibilityIssue(
+ inspectionId = inspectionId,
+ severity = highlightType.name,
+ filePath = virtualFile?.toProjectRelativePath(project) ?: "",
+ line = position?.line,
+ column = position?.column,
+ endLine = position?.endLine,
+ endColumn = position?.endColumn,
+ description = ProblemDescriptorUtil.renderDescriptionMessage(this, psiElement, false),
+ quickFixes = fixes?.map { it.familyName }?.distinct().orEmpty(),
+ )
+}
+
+private fun computePosition(
+ virtualFile: VirtualFile?,
+ textRange: TextRange?,
+): SourcePosition? {
+ if (virtualFile == null || textRange == null) {
+ return null
+ }
+ val document = FileDocumentManager.getInstance().getDocument(virtualFile) ?: return null
+ val startOffset = textRange.startOffset.coerceIn(0, document.textLength)
+ val endOffset = textRange.endOffset.coerceIn(startOffset, document.textLength)
+ return SourcePosition(
+ line = document.getLineNumber(startOffset) + 1,
+ column = startOffset - document.getLineStartOffset(document.getLineNumber(startOffset)) + 1,
+ endLine = document.getLineNumber(endOffset) + 1,
+ endColumn = endOffset - document.getLineStartOffset(document.getLineNumber(endOffset)) + 1,
+ )
+}
+
+private fun VirtualFile.toProjectRelativePath(project: Project): String {
+ val basePath = project.basePath ?: return path
+ val relativePath = path.removePrefix(basePath).removePrefix("/")
+ return relativePath.ifEmpty { path }
+}
+
+private data class SourcePosition(
+ val line: Int,
+ val column: Int,
+ val endLine: Int,
+ val endColumn: Int,
+)
+
+private data class SplitModeCompatibilityInspectionRunResult(
+ val issues: List,
+ val inspectedFileCount: Int,
+)
diff --git a/plugins/devkit/intellij.devkit.mcp/src/DevKitSplitModeRecognitionApi.kt b/plugins/devkit/intellij.devkit.mcp/src/DevKitSplitModeRecognitionApi.kt
index 53187ddd02eb..b2ff98dfc088 100644
--- a/plugins/devkit/intellij.devkit.mcp/src/DevKitSplitModeRecognitionApi.kt
+++ b/plugins/devkit/intellij.devkit.mcp/src/DevKitSplitModeRecognitionApi.kt
@@ -5,6 +5,7 @@ import com.intellij.mcpserver.mcpFail
import com.intellij.mcpserver.project
import com.intellij.mcpserver.util.resolveInProject
import com.intellij.openapi.application.readAction
+import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiManager
import kotlinx.coroutines.currentCoroutineContext
@@ -19,22 +20,16 @@ internal suspend fun recognizeSplitModeModuleKindForPath(descriptorPath: String)
val project = currentCoroutineContext().project
val resolvedDescriptorPath = project.resolveInProject(descriptorPath)
val descriptorVirtualFile = VirtualFileManager.getInstance().findFileByNioPath(resolvedDescriptorPath)
- ?: VirtualFileManager.getInstance().refreshAndFindFileByNioPath(resolvedDescriptorPath)
- ?: mcpFail("File not found: $descriptorPath")
+ ?: VirtualFileManager.getInstance().refreshAndFindFileByNioPath(resolvedDescriptorPath)
+ ?: mcpFail("File not found: $descriptorPath")
- val service = SplitModeApiRestrictionsService.getInstance(project)
- service.scheduleLoadRestrictions()
- withTimeoutOrNull(5.seconds) {
- while (!service.isLoaded()) {
- delay(50.milliseconds)
- }
- } ?: mcpFail("Timed out waiting for split-mode module restrictions to load")
+ loadSplitModeRestrictions(project)
val recognizedKind = readAction {
val psiFile = PsiManager.getInstance(project).findFile(descriptorVirtualFile)
?: mcpFail("Psi file not found: $descriptorPath")
recognizeSplitModeModuleKind(psiFile)
- ?: mcpFail("Descriptor is not an IntelliJ plugin XML file or no IntelliJ module was found: $descriptorPath")
+ ?: mcpFail("Descriptor is not an IntelliJ plugin XML file or no IntelliJ module was found: $descriptorPath")
}
return DevKitMcpToolset.RecognizeIjModuleKindResult(
@@ -44,3 +39,25 @@ internal suspend fun recognizeSplitModeModuleKindForPath(descriptorPath: String)
reasoning = recognizedKind.reasoning,
)
}
+
+internal suspend fun recognizeSplitModeApiKind(apiName: String): DevKitMcpToolset.RecognizeSplitModeApiKindResult {
+ val project = currentCoroutineContext().project
+ val service = loadSplitModeRestrictions(project)
+ val apiKind = service.getCodeApiKind(apiName, null)
+ return DevKitMcpToolset.RecognizeSplitModeApiKindResult(
+ apiName = apiName,
+ kindId = apiKind?.id,
+ hint = service.getCodeApiHint(apiName),
+ )
+}
+
+internal suspend fun loadSplitModeRestrictions(project: Project): SplitModeApiRestrictionsService {
+ val service = SplitModeApiRestrictionsService.getInstance(project)
+ service.scheduleLoadRestrictions()
+ withTimeoutOrNull(5.seconds) {
+ while (!service.isLoaded()) {
+ delay(50.milliseconds)
+ }
+ } ?: mcpFail("Timed out waiting for split-mode module restrictions to load")
+ return service
+}