[remote development tooling] IJPL-231068 Sync split mode inspections state with master branch to offer devs who do not use nightly builds the same tooling that the safe push checks use

GitOrigin-RevId: be32cc21e0147ac93fefaef9dfd802483f3d98aa
This commit is contained in:
Nikita Katkov
2026-08-20 18:45:32 +00:00
committed by intellij-monorepo-bot
parent 4395850ca3
commit 76883f9413
47 changed files with 2179 additions and 1521 deletions
+2
View File
@@ -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
@@ -123,5 +123,6 @@
<orderEntry type="module" module-name="intellij.libraries.jackson" />
<orderEntry type="module" module-name="intellij.libraries.jackson.databind" />
<orderEntry type="module" module-name="intellij.libraries.kotlinx.collections.immutable" />
<orderEntry type="module" module-name="intellij.platform.workspace.jps" />
</component>
</module>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ModuleNotRegisteredAsPluginContent -->
<!--suppress PluginXmlPluginLogo -->
<idea-plugin>
<id>com.example.backend.plugin</id>
<vendor>JetBrains</vendor>
<!--/*<# Backend XML descriptor #>*/-->
<dependencies>
<module name="intellij.platform.backend"/>
</dependencies>
</idea-plugin>
@@ -159,15 +159,17 @@
<registryKey key="devkit.split.mode.report.implicit.module.kind" defaultValue="true"
description="Enables reporting errors about modules that effectively work only on frontend or backend, but do not explicitly state that fact via platform dependency"/>
<registryKey key="devkit.split.mode.custom.icons" defaultValue="false"
description="Enables custom file and directory icons for split-mode frontend/backend/shared modules in DevKit."/>
description="Enables deferred accurate split-mode icon resolution for DevKit descriptor and directory icons."/>
<registryKey key="devkit.split.mode.inlay.plugin.descriptor.kind" defaultValue="true"
description="Shows inline split-mode compatibility hints for DevKit plugin descriptors."/>
<registryKey key="devkit.split.mode.run.jps.to.bazel.in.quick.fix" defaultValue="false"
description="Automatically run JPS to Bazel conversion after applying a fix that touches runtime/compile dependencies"/>
<registryKey key="devkit.split.mode.analysis.api.restrictions.source" defaultValue="[bundled*|project|project-or-bundled]"
description="Source of ApiRestrictions.json for DevKit split-mode inspections."
description="Source of ApiRestrictions.json5 for DevKit split-mode inspections."
restartRequired="true"/>
<registryKey key="devkit.split.mode.analysis.predefined.module.kinds.source" defaultValue="[bundled*|project|project-or-bundled]"
description="Source of PredefinedModuleKinds.json for DevKit split-mode inspections."
description="Source of PredefinedModuleKinds.json5 for DevKit split-mode inspections."
restartRequired="true"/>
<registryKey key="devkit.split.mode.qodana.analysis.scope.source" defaultValue="[bundled|project*|project-or-bundled]"
description="Source of SplitModeQodanaAnalysisScope.json for DevKit split-mode inspections."
@@ -781,6 +783,15 @@
implementationClass="org.jetbrains.idea.devkit.references.DevKitRelatedPropertiesProvider"/>
<codeInsight.lineMarkerProvider language="XML"
implementationClass="org.jetbrains.idea.devkit.navigation.DescriptorsIncludingContentModuleLineMarkerProvider"/>
<codeInsight.declarativeInlayProvider
providerId="devkit.plugin.descriptor.split.mode.kind"
bundle="messages.DevKitBundle"
nameKey="inlay.split.mode.module.kind.name"
descriptionKey="inlay.split.mode.module.kind.description"
group="OTHER_GROUP"
implementationClass="org.jetbrains.idea.devkit.navigation.DescriptorSplitModeInlayHintsProvider"
isEnabledByDefault="true"
language="XML"/>
<psi.referenceContributor
language="Properties"
implementation="org.jetbrains.idea.devkit.references.MessageBundleReferenceContributor"/>
@@ -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., <code>@RequiresEdt</code>, <code>@RequiresReadLock</code>.<br><br>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.
@@ -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."}
]
// 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."}
]
@@ -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)."
}
]
}
@@ -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",
],
}
@@ -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"}
]
@@ -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
}
@@ -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": []
}
@@ -25,11 +25,9 @@ final class PluginDescriptorDomFileDescription extends DomFileDescription<IdeaPl
IdeaPlugin ideaPlugin = DescriptorUtil.getIdeaPlugin(file);
if (ideaPlugin == null) return null;
if (SplitModeModuleKindIcons.isCustomIconsEnabled()) {
Icon splitModeIcon = SplitModeModuleKindIcons.getDescriptorIcon(file);
if (splitModeIcon != null) {
return splitModeIcon;
}
Icon splitModeIcon = SplitModeModuleKindIcons.getDescriptorIcon(file);
if (splitModeIcon != null) {
return splitModeIcon;
}
if (ideaPlugin.isV2Descriptor()) {
@@ -45,23 +45,16 @@ internal class MissingFrontendOrBackendRuntimeDependencyInspection : DevKitPlugi
val requiredModuleKind = recognizeExplicitDependencyKind(requiredRuntimeDependency)
?: error("Unsupported split-mode runtime dependency: $requiredRuntimeDependency")
val reportedElement = if (dependencies.exists()) dependencies else element
val reportedXmlElement = reportedElement.xmlElement ?: return
if (reportedElement.xmlElement == null) return
val currentXmlFile = holder.fileElement.file
if (SplitModeInspectionExclusionsService.getInstance(currentXmlFile.project).isExcluded(reportedXmlElement,
MISSING_RUNTIME_DEPENDENCY_SHORT_NAME)) {
return
}
val regularFixes = arrayOf(
SplitModeDependencyQuickFixes.createAddExplicitDependencyFix(
currentModuleName,
requiredModuleKind,
)
)
val suppressionFix = SplitModeInspectionExclusionsService.getInstance(currentXmlFile.project).createSuppressionFixIfApplicable(
reportedXmlElement,
MISSING_RUNTIME_DEPENDENCY_SHORT_NAME,
)
val fixes = if (suppressionFix != null) regularFixes + suppressionFix else regularFixes
val suppressionFixes = SplitModeInspectionExclusionsService.getInstance(currentXmlFile.project).createCommonSuppressionQuickFixes()
val fixes = regularFixes + suppressionFixes
holder.createProblem(
reportedElement,
message(
@@ -0,0 +1,156 @@
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:Suppress("HardCodedStringLiteral")
package org.jetbrains.idea.devkit.inspections.remotedev
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.core.json.JsonReadFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.json.JsonMapper
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationException
import kotlinx.serialization.json.Json
import java.io.IOException
internal const val MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_FILE_NAME: String = "MonorepoFeaturesWithoutSplitModeSupport.json5"
internal const val MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RESOURCE_PATH: String =
"remotedevInspectionData/$MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_FILE_NAME"
internal const val MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RELATIVE_PATH: String =
"community/plugins/devkit/devkit-core/resources/$MONOREPO_FEATURES_WITHOUT_SPLIT_MODE_SUPPORT_RESOURCE_PATH"
internal const val SPLIT_MODE_EXCLUDED_MODULES_SCOPE_FILE_NAME: String = "SplitModeExcludedModules.xml"
internal val SPLIT_MODE_EXCLUDED_MODULES_SCOPE_RELATIVE_PATHS: List<String> = 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 """
<component name="DependencyValidationManager">
<scope name="SplitModeExcludedModules" pattern="${scopePattern.escapeXmlAttributeValue()}" />
</component>
""".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<MonorepoFeaturesWithoutSplitModeSupportFile>(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<String>,
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("&amp;")
'"' -> append("&quot;")
'<' -> append("&lt;")
'>' -> append("&gt;")
else -> append(character)
}
}
}
}
@Serializable
private data class MonorepoFeaturesWithoutSplitModeSupportFile(
@SerialName("pathPatterns")
val pathPatterns: List<String> = emptyList(),
@SerialName("moduleNames")
val moduleNames: List<String> = 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
}
@@ -0,0 +1 @@
owner 'RD Split Kernel'
@@ -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,
@@ -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)
@@ -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,
@@ -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<SplitModeInspectionExclusionsSnapshot>(
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<LocalQuickFix> {
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<VirtualFile?, Throwable> {
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<SplitModeInspectionExclusionEntry> = emptyList(),
)
@Serializable
internal data class SplitModeInspectionExclusionsFile(
@SerialName("exclusions")
val exclusions: List<SplitModeInspectionExclusionEntry> = 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<SplitModeInspectionExclusionsService>()
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
@@ -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 {
@@ -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,
@@ -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),
@@ -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,
@@ -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<SplitModeApiRestrictionsService>()
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<List<ApiRestriction>>(text))
val normalizedJson = json5.readTree(text).toString()
return buildApiRestrictionsLookup(json.decodeFromString<List<ApiRestriction>>(normalizedJson))
}
override fun getDefaultValue(): RestrictionsLookup {
@@ -311,7 +345,8 @@ class SplitModeApiRestrictionsService(
readMode = readMode,
) {
override fun parse(text: String): PredefinedModuleKindsLookup {
return buildPredefinedModuleKindsLookup(json.decodeFromString<List<PredefinedModuleKind>>(text))
val normalizedJson = json5.readTree(text).toString()
return buildPredefinedModuleKindsLookup(json.decodeFromString<List<PredefinedModuleKind>>(normalizedJson))
}
override fun getDefaultValue(): PredefinedModuleKindsLookup {
@@ -321,13 +356,14 @@ class SplitModeApiRestrictionsService(
}
private fun buildApiRestrictionsLookup(data: List<ApiRestriction>): RestrictionsLookup {
val codeRestrictions = mutableMapOf<String, ModuleKind>()
val codeRestrictions = mutableMapOf<String, ApiRestrictionMatch>()
val extensionPointToApiName = mutableMapOf<String, String>()
val apiHints = mutableMapOf<String, String>()
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<PredefinedModuleKind>): PredefinedModuleKindsLookup {
val moduleNames = mutableMapOf<String, ModuleKind>()
val pluginIds = mutableMapOf<String, ModuleKind>()
val descriptorPaths = mutableMapOf<DescriptorPathSelector, ModuleKind>()
val moduleIds = mutableMapOf<String, PredefinedModuleKindInfo>()
val pluginIds = mutableMapOf<String, PredefinedModuleKindInfo>()
val descriptorPaths = mutableMapOf<DescriptorPathSelector, PredefinedModuleKindInfo>()
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<String, ModuleKind> = emptyMap(),
val codeRestrictions: Map<String, ApiRestrictionMatch> = emptyMap(),
val extensionPointToApiName: Map<String, String> = emptyMap(),
val apiHints: Map<String, String> = emptyMap(),
)
private data class RestrictionsSnapshot(
val codeRestrictions: Map<String, ModuleKind> = emptyMap(),
val codeRestrictions: Map<String, ApiRestrictionMatch> = emptyMap(),
val extensionPointToApiName: Map<String, String> = emptyMap(),
val apiHints: Map<String, String> = 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<String, ModuleKind> = emptyMap(),
val pluginIds: Map<String, ModuleKind> = emptyMap(),
val descriptorPaths: Map<DescriptorPathSelector, ModuleKind> = emptyMap(),
val moduleIds: Map<String, PredefinedModuleKindInfo> = emptyMap(),
val pluginIds: Map<String, PredefinedModuleKindInfo> = emptyMap(),
val descriptorPaths: Map<DescriptorPathSelector, PredefinedModuleKindInfo> = 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<String>,
@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,
)
}
@@ -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<IdeaPlugin>,
)
descriptorResolver: () -> List<IdeaPlugin>,
) {
private val descriptors by lazy(LazyThreadSafetyMode.NONE) { descriptorResolver() }
fun resolveDescriptors(): List<IdeaPlugin> = descriptors
}
private data class ContentModuleDependency(
val moduleName: String,
@@ -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<SplitModeApiRestrictionsService.ModuleKind> {
val xmlFile = descriptorFile as? XmlFile ?: return emptySet()
val ideaPlugin = DescriptorUtil.getIdeaPlugin(xmlFile) ?: return emptySet()
val explicitDependencyKinds = LinkedHashSet<SplitModeApiRestrictionsService.ModuleKind>()
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,
)
@@ -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<CachedValue<ModuleAnalysis>>("SplitModeModuleKindResolver.moduleIdAnalysis")
private val MODULE_DESCRIPTOR_ANALYSIS_KEY =
Key.create<CachedValue<ModuleAnalysis>>("SplitModeModuleKindResolver.moduleDescriptorAnalysis")
internal object SplitModeModuleKindResolver {
private val LOG = logger<SplitModeModuleKindResolver>()
@@ -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, ""))
@@ -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<String> {
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)
}
@@ -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<ModuleDescriptor> {
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"
}
}
}
}
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
}
@@ -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",
@@ -44,6 +44,7 @@
<orderEntry type="module" module-name="intellij.platform.testFramework.junit5.codeInsight" />
<orderEntry type="module" module-name="intellij.java.compiler.tests" scope="TEST" />
<orderEntry type="module" module-name="intellij.java.testFramework" scope="TEST" />
<orderEntry type="module" module-name="intellij.junit" scope="TEST" />
<orderEntry type="module" module-name="intellij.xml.dom.tests" scope="TEST" />
<orderEntry type="module" module-name="intellij.properties.backend" />
<orderEntry type="module" module-name="intellij.platform.core.ui" />
@@ -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", """
<idea-plugin>
</idea-plugin>
""".trimIndent())
createSharedPluginDescriptor("""
<idea-plugin>
</idea-plugin>
""".trimIndent())
createFrontendPluginDescriptor("""
<idea-plugin>
<dependencies>
<module name="intellij.platform.frontend"/>
</dependencies>
</idea-plugin>
""".trimIndent())
createModuleDescriptor("module.backend", "module.backend.xml", """
<idea-plugin>
<dependencies>
<module name="intellij.platform.backend"/>
</dependencies>
</idea-plugin>
""".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", """
<idea-plugin>
</idea-plugin>
""".trimIndent())
createSharedPluginDescriptor("""
<idea-plugin>
</idea-plugin>
""".trimIndent())
createFrontendPluginDescriptor("""
<idea-plugin>
<dependencies>
<module name="intellij.platform.frontend"/>
</dependencies>
</idea-plugin>
""".trimIndent())
createModuleDescriptor("intellij.transitive.frontend", "intellij.transitive.frontend.xml", """
<idea-plugin>
<dependencies>
<module name="intellij.platform.frontend"/>
</dependencies>
</idea-plugin>
""".trimIndent())
createModuleDescriptor("module.backend", "module.backend.xml", """
<idea-plugin>
<dependencies>
<module name="intellij.platform.backend"/>
</dependencies>
</idea-plugin>
""".trimIndent())
createPluginDescriptor("transitive.consumer", """
<idea-plugin>
<dependencies>
<module name="intellij.transitive.frontend"/>
</dependencies>
</idea-plugin>
""".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())
}
}
}
@@ -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", """
<idea-plugin>
<dependencies>
<!-- no dependency -->
</dependencies>
</idea-plugin>
""".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", """
<idea-plugin>
<dependencies>
<!-- no dependency -->
</dependencies>
</idea-plugin>
""".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", """
<idea-plugin>
@@ -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", """
<idea-<caret>plugin>
<!-- no dependency -->
</idea-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", """
<idea-<caret>plugin>
<!-- no dependency -->
</idea-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("<dependencies>"))
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"
}
@@ -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",
@@ -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
<module name="intellij.platform.core"/>
</dependencies>
<extensions defaultExtensionNs="com.intellij">
<applicationConfigurable<caret>/>
<annotator<caret>/>
</extensions>
</idea-plugin>
""".trimIndent()
@@ -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()
}
@@ -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)
}
}
}
@@ -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(),
)
@@ -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",
"""
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<rdclient.actionCustomization/>
<lang.parserDefinition/>
</extensions>
</idea-plugin>
""".trimIndent()
)
myFixture.configureFromExistingVirtualFile(pluginXml.virtualFile)
myFixture.checkHighlighting()
}
fun testFrontendApiExtensionInOrdinaryBackendModule() {
val pluginXml = addModuleWithXmlDescriptor(
moduleName = "unique.module.name.64",
descriptorRelativePathToResourcesDirectory = "META-INF/plugin.xml",
"""
<idea-plugin>
<dependencies>
<module name="intellij.platform.backend"/>
</dependencies>
<extensions defaultExtensionNs="com.intellij">
<<warning>rdclient.actionCustomization</warning>/>
</extensions>
</idea-plugin>
""".trimIndent()
)
myFixture.configureFromExistingVirtualFile(pluginXml.virtualFile)
myFixture.checkHighlighting()
}
fun testUiExtensionInBackendWithNonUiApiPermitModule() {
val pluginXml = addModuleWithXmlDescriptor(
moduleName = "intellij.clion.radler.core",
descriptorRelativePathToResourcesDirectory = "META-INF/plugin.xml",
"""
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<<warning>toolWindow</warning>/>
</extensions>
</idea-plugin>
""".trimIndent()
)
myFixture.configureFromExistingVirtualFile(pluginXml.virtualFile)
myFixture.checkHighlighting()
}
fun testBackendWithNonUiApiPermitModuleIsBackendDependencyEvidence() {
val pluginXml = addModuleWithXmlDescriptor(
moduleName = "unique.module.name.65",
descriptorRelativePathToResourcesDirectory = "META-INF/plugin.xml",
"""
<idea-plugin>
<dependencies>
<module name="intellij.clion.radler.core"/>
</dependencies>
<extensions defaultExtensionNs="com.intellij">
<<warning>lang.parserDefinition</warning>/>
</extensions>
</idea-plugin>
""".trimIndent()
)
myFixture.configureFromExistingVirtualFile(pluginXml.virtualFile)
myFixture.checkHighlighting()
}
fun testSharedExtensionInBackendModule() {
val pluginXml = addModuleWithXmlDescriptor(
moduleName = "unique.module.name.48",
@@ -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", """
<idea-plugin>
<content>
<module name="test.module"/>
</content>
</idea-plugin>
""".trimIndent()
)
createModuleWithModuleDescriptor("test.module", "test.module.xml", """
<idea-plugin>
<dependencies>
<module name="intellij.platform.frontend"/>
</dependencies>
</idea-plugin>
""".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", """
<idea-plugin>
<content>
<module name="test.module"/>
</content>
</idea-plugin>
""".trimIndent()
)
createModuleWithModuleDescriptor("test.module", "test.module.xml", """
<idea-plugin>
<!-- any -->
</idea-plugin>
""".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", """
<idea-plugin>
<dependencies>
<module name="intellij.platform.backend"/>
</dependencies>
</idea-plugin>
""".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", """
<idea-plugin>
<content>
<module name="test.module"/>
</content>
</idea-plugin>
""".trimIndent()
)
createModuleWithModuleDescriptor("test.module", "test.module.xml", """
<idea-plugin>
<dependencies>
<module name="intellij.platform.frontend"/>
<module name="intellij.platform.backend"/>
</dependencies>
</idea-plugin>
""".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", """
<idea-plugin>
<dependencies>
<module name="intellij.platform.monolith"/>
</dependencies>
</idea-plugin>
""".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", """
<idea-plugin>
<dependencies>
<module name="intellij.platform.backend"/>
</dependencies>
</idea-plugin>
""".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", """
<idea-plugin>
<dependencies>
<module name="intellij.platform.backend"/>
</dependencies>
</idea-plugin>
""".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 }
}
}
@@ -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: <weak_warning descr="'com.intellij.openapi.wm.ToolWindowFactory' should be used in 'frontend' module type. Actual module type is 'backend'.
class CustomToolWindowFactory: <warning descr="'com.intellij.openapi.wm.ToolWindowFactory' should be used in 'frontend' module type. Actual module type is 'backend'.
Computed module kind reasoning:
Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">ToolWindowFactory</weak_warning> {}
Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">ToolWindowFactory</warning> {}
class BackendService {
fun doStuff() {
// no warning here expected
VirtualFileManager.getInstance()
<weak_warning descr="'com.intellij.openapi.fileEditor.FileEditorManager.getFocusedEditor' should be used in 'frontend' module type. Actual module type is 'backend'.
<warning descr="'com.intellij.openapi.fileEditor.FileEditorManager.getFocusedEditor' should be used in 'frontend' module type. Actual module type is 'backend'.
Computed module kind reasoning:
Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">FileEditorManager.getInstance().getFocusedEditor()</weak_warning>
Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">FileEditorManager.getInstance().getFocusedEditor()</warning>
}
}
""".trimIndent()
@@ -306,11 +336,11 @@ Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in m
class SharedLangModule {
fun test() {
<weak_warning descr="'com.intellij.openapi.vfs.VirtualFileManager' should be used in 'backend' module type. Actual module type is 'shared'.
<warning descr="'com.intellij.openapi.vfs.VirtualFileManager' should be used in 'backend' module type. Actual module type is 'shared'.
Computed module kind reasoning:
Predefined module kind for plugin/module id 'com.intellij.modules.lang'">VirtualFileManager</weak_warning>.getInstance()
Predefined module kind for plugin/module id 'com.intellij.modules.lang'">VirtualFileManager</warning>.getInstance()
}
}
""".trimIndent()
@@ -344,11 +374,11 @@ Predefined module kind for plugin/module id 'com.intellij.modules.lang'">Virtual
class FrontendService {
fun doStuff() {
<weak_warning descr="'com.intellij.openapi.vfs.VirtualFileManager' should be used in 'backend' module type. Actual module type is 'frontend'.
<warning descr="'com.intellij.openapi.vfs.VirtualFileManager' should be used in 'backend' module type. Actual module type is 'frontend'.
Computed module kind reasoning:
Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">VirtualFileManager</weak_warning>.getInstance()
Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">VirtualFileManager</warning>.getInstance()
}
}
""".trimIndent()
@@ -357,7 +387,60 @@ Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in
myFixture.checkHighlighting()
}
fun testConfigurableApiInBackendModule() {
fun testFileIndexApiInFrontendModule() {
configurePluginXml(
"""
<idea-plugin>
<dependencies>
<module name="intellij.platform.frontend"/>
</dependencies>
</idea-plugin>
""".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() {
<warning descr="'com.intellij.openapi.roots.ProjectFileIndex' should be used in 'backend' module type. Actual module type is 'frontend'.
Computed module kind reasoning:
Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">ProjectFileIndex</warning>.getInstance(project)
}
}
class FrontendFileIndex : <warning descr="'com.intellij.openapi.roots.FileIndex' should be used in 'backend' module type. Actual module type is 'frontend'.
Computed module kind reasoning:
Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">FileIndex</warning>
class FrontendProjectFileIndex : <warning descr="'com.intellij.openapi.roots.ProjectFileIndex' should be used in 'backend' module type. Actual module type is 'frontend'.
Computed module kind reasoning:
Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">ProjectFileIndex</warning>
class FrontendModuleFileIndex : <warning descr="'com.intellij.openapi.roots.ModuleFileIndex' should be used in 'backend' module type. Actual module type is 'frontend'.
Computed module kind reasoning:
Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">ModuleFileIndex</warning>
""".trimIndent()
)
myFixture.checkHighlighting()
}
fun testFrontendOrBackendApiInBackendModule() {
configurePluginXml(
"""
<idea-plugin>
@@ -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 : <weak_warning descr="'com.intellij.openapi.fileEditor.FileEditorManagerListener' should be used in 'frontend' module type. Actual module type is 'backend'.
class BackendFileEditorListener : <warning descr="'com.intellij.openapi.fileEditor.FileEditorManagerListener' should be used in 'frontend' module type. Actual module type is 'backend'.
Computed module kind reasoning:
Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">FileEditorManagerListener</weak_warning>
Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">FileEditorManagerListener</warning>
""".trimIndent()
)
@@ -426,11 +509,11 @@ Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in m
import com.intellij.lang.ParserDefinition
class FrontendParserDefinition : <weak_warning descr="'com.intellij.lang.ParserDefinition' should be used in 'shared' module type. Actual module type is 'frontend'.
class FrontendParserDefinition : <warning descr="'com.intellij.lang.ParserDefinition' should be used in 'shared' module type. Actual module type is 'frontend'.
Computed module kind reasoning:
Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">ParserDefinition</weak_warning>
Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">ParserDefinition</warning>
""".trimIndent()
)
@@ -454,11 +537,11 @@ Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in
import com.intellij.openapi.project.ProjectManagerListener
class FrontendProjectManagerListener : <weak_warning descr="'com.intellij.openapi.project.ProjectManagerListener' should be used in 'backend' module type. Actual module type is 'frontend'.
class FrontendProjectManagerListener : <warning descr="'com.intellij.openapi.project.ProjectManagerListener' should be used in 'backend' module type. Actual module type is 'frontend'.
Computed module kind reasoning:
Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">ProjectManagerListener</weak_warning>
Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">ProjectManagerListener</warning>
""".trimIndent()
)
@@ -490,11 +573,11 @@ Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in
class FrontendService {
fun doStuff() {
<weak_warning descr="'com.intellij.openapi.vfs.VirtualFileManager' should be used in 'backend' module type. Actual module type is 'frontend'.
<warning descr="'com.intellij.openapi.vfs.VirtualFileManager' should be used in 'backend' module type. Actual module type is 'frontend'.
Computed module kind reasoning:
Frontend dependency 'intellij.platform.frontend' from descriptor 'light_idea_test_case.xml' in module 'light_idea_test_case'">VirtualFileManager</weak_warning>.getInstance()
Frontend dependency 'intellij.platform.frontend' from descriptor 'light_idea_test_case.xml' in module 'light_idea_test_case'">VirtualFileManager</warning>.getInstance()
}
}
""".trimIndent()
@@ -522,11 +605,11 @@ Frontend dependency 'intellij.platform.frontend' from descriptor 'light_idea_tes
class FrontendService {
fun doStuff() {
<weak_warning descr="'com.example.annotated.AnnotatedBackendApi' should be used in 'backend' module type. Actual module type is 'frontend'.
<warning descr="'com.example.annotated.AnnotatedBackendApi' should be used in 'backend' module type. Actual module type is 'frontend'.
Computed module kind reasoning:
Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">AnnotatedBackendApi</weak_warning>.getInstance()
Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">AnnotatedBackendApi</warning>.getInstance()
}
}
""".trimIndent()
@@ -554,11 +637,11 @@ Frontend dependency 'intellij.platform.frontend' from descriptor 'plugin.xml' in
class BackendService {
fun doStuff() {
<weak_warning descr="'com.example.annotated.AnnotatedFrontendApi' should be used in 'frontend' module type. Actual module type is 'backend'.
<warning descr="'com.example.annotated.AnnotatedFrontendApi' should be used in 'frontend' module type. Actual module type is 'backend'.
Computed module kind reasoning:
Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">AnnotatedFrontendApi</weak_warning>.getInstance()
Backend dependency 'intellij.platform.backend' from descriptor 'plugin.xml' in module 'light_idea_test_case'">AnnotatedFrontendApi</warning>.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: <weak_warning descr="'com.intellij.openapi.wm.ToolWindowFactory' should be used in 'frontend' module type. Actual module type is 'shared'.
class MyToolWindow: <warning descr="'com.intellij.openapi.wm.ToolWindowFactory' should be used in 'frontend' module type. Actual module type is 'shared'.
Computed module kind reasoning:
No frontend or backend dependencies were found for module 'light_idea_test_case'">ToolWindowFactory</weak_warning> {}
No frontend or backend dependencies were found for module 'light_idea_test_case'">ToolWindowFactory</warning> {}
}
fun testBackendApi() {
<weak_warning descr="'com.intellij.openapi.vfs.VirtualFileManager' should be used in 'backend' module type. Actual module type is 'shared'.
<warning descr="'com.intellij.openapi.vfs.VirtualFileManager' should be used in 'backend' module type. Actual module type is 'shared'.
Computed module kind reasoning:
No frontend or backend dependencies were found for module 'light_idea_test_case'">VirtualFileManager</weak_warning>.getInstance()
No frontend or backend dependencies were found for module 'light_idea_test_case'">VirtualFileManager</warning>.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 : <weak_warning descr="'com.intellij.ide.plugins.DynamicPluginListener' should be used in 'frontend or backend' module type. Actual module type is 'shared'.
class SharedDynamicPluginListener : <warning descr="'com.intellij.ide.plugins.DynamicPluginListener' should be used in 'frontend or backend' module type. Actual module type is 'shared'.
Plugin lists are different on frontend and backend, prefer listening to them explicitly in desired IDE part
Computed module kind reasoning:
No frontend or backend dependencies were found for module 'light_idea_test_case'">DynamicPluginListener</weak_warning>
No frontend or backend dependencies were found for module 'light_idea_test_case'">DynamicPluginListener</warning>
""".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 {
@@ -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",
@@ -38,6 +38,9 @@
<orderEntry type="module" module-name="intellij.platform.lang.core" />
<orderEntry type="module" module-name="intellij.platform.util" />
<orderEntry type="module" module-name="intellij.java.psi" />
<orderEntry type="module" module-name="intellij.platform.analysis" />
<orderEntry type="module" module-name="intellij.platform.analysis.impl" />
<orderEntry type="module" module-name="intellij.platform.projectModel" />
<orderEntry type="module" module-name="intellij.libraries.kotlinx.serialization.json" />
<orderEntry type="module" module-name="intellij.libraries.kotlinx.serialization.core" />
<orderEntry type="module" module-name="intellij.platform.ide.progress" />
@@ -1,13 +1,21 @@
<idea-plugin>
<!-- region Generated dependencies - run `Generate Product Layouts` to regenerate -->
<dependencies>
<module name="intellij.java.backend"/>
<!-- region Generated dependencies - run `Generate Product Layouts` to regenerate -->
<plugin id="com.intellij.mcpServer"/>
<module name="intellij.java.backend"/>
<module name="intellij.devkit.core"/>
<module name="intellij.devkit.scaffolding"/>
<module name="intellij.java.psi"/>
<!-- endregion -->
<module name="intellij.libraries.kotlinx.serialization.core"/>
<module name="intellij.libraries.kotlinx.serialization.json"/>
<module name="intellij.platform.analysis"/>
<module name="intellij.platform.analysis.impl"/>
<module name="intellij.platform.core"/>
<module name="intellij.platform.ide.progress"/>
<module name="intellij.platform.lang.core"/>
<module name="intellij.platform.projectModel"/>
</dependencies>
<!-- endregion -->
<extensions defaultExtensionNs="com.intellij.mcpServer">
<mcpToolset implementation="com.intellij.devkit.mcp.DevKitMcpToolset" />
@@ -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<List<Pair<T, List<SourceLocation>>>, 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 ?: "<null>", 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 ?: "<null>", 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<String>,
@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<SplitModeCompatibilityIssue>,
@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<String>,
)
}
@@ -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<DevKitMcpToolset.SplitModeCompatibilityIssue>()
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<LocalInspectionToolWrapper> {
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<VirtualFile> {
val projectFileIndex = ProjectFileIndex.getInstance(project)
val files = mutableListOf<VirtualFile>()
VfsUtilCore.visitChildrenRecursively(root, object : VirtualFileVisitor<Unit>() {
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<LocalInspectionToolWrapper>,
): List<DevKitMcpToolset.SplitModeCompatibilityIssue> {
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) ?: "<unknown>",
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<DevKitMcpToolset.SplitModeCompatibilityIssue>,
val inspectedFileCount: Int,
)
@@ -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
}