Skip to content

Latest commit

 

History

History
1130 lines (974 loc) · 80.8 KB

development-plan.md

File metadata and controls

1130 lines (974 loc) · 80.8 KB

NetBeans Kotlin Plugin — Long-Term Development Plan

Context

The kotlin-netbeans plugin (JetBrains, abandoned in 2020) provides Kotlin support in NetBeans IDE. The goal is to revive the project under a new name, clean up the infrastructure, migrate to the K2 compiler API, and bring language support to a level comparable to the IDEA plugin.

Key constraints:

  • Existing packages (org.jetbrains.kotlin.*) are not renamed; new and substantially reworked code goes into io.github.nbplugins.kotlin.nbm.*.
  • Current state (0.11.x): K2-only architecture, Kotlin 2.3.21, platform era 253.
  • Java 17 — runtime for tests.

Cross-cutting Task — Dependency Updates

Throughout all stages (A and B): when touching any module or dependency, update it to the latest compatible version. Not a separate stage — done along the way.

Guidelines:

  • NetBeans Platform API (target cluster) — latest stable release
  • Maven plugins (nbm-maven-plugin, maven-compiler-plugin, etc.) — latest versions
  • Test dependencies (JUnit, etc.) — latest versions
  • kotlin-compiler: 1.9.25 (FE1.0 default) through B2–B6 (0.6.x). Bumps to 2.x in stage C after K2 migration completes.
  • IntelliJ platform: 193+241 mix in 0.5.x; core/core-impl/util bumps to 232 in B3 (0.6.x); K2 migration in stage C adds analysis-api-*-for-ide artefacts.
  • Java source/target: can be raised above 17 after B2.x if the ecosystem allows.

Stage Order

  • A1 — Rename artifact and plugin metadata
  • A2 — GitHub Actions CI/CD
  • A3 — MIME type: switch to text/x-kotlin, override built-in NB services
  • A4.1 — Maven multi-module: install lib/*.jar as Maven artifacts (no compilation)
  • A4.2 — PATCHED JARs generated by Maven build (PatchingJars module); removed from git
  • A4.3 — kotlin-formatter: compile from sources (submodules/Kotlin@v1.3.72); remove lib/kotlin-formatter-1.0.jar
  • A4.4 — kotlin-compiler: split into two JARs (compiler / compiler-intellij-platform); all bundled deps replaced by explicit Maven coords; removed ASM patches and kotlin-compiler-patched.pom
  • A4.5 — Eliminated strip-based ASM patches; replaced with Ant extraction (<present> selector, <zipfileset exclude>); removed dead patch tools from patches-src/
  • A4.6 — kotlin-converter: compile from sources; remove PatchImportConversionKt, PatchFqnPart
  • A4.7 — kotlin-ide-common: compile from sources; remove PatchKotlinIdeCommon
  • A4.8 — KotlinCompilerIntellijPlatform: replace PatchAstLoadingFilter, PatchExtensionsAddGetExtensions with source classes in patches/
  • A4.9 — openapi-formatter, idea-formatter: replaced with code-style:241.194 and code-style-impl:241.194 (JetBrains Maven); removed PatchContainerUtilAddMissing
  • A4.10 — intellij-core: replaced with core:193.7288.26 + core-impl:193.7288.26 (direct Maven deps of Nbm); removed IntellijCore wrapper, PatchingJars, patches-src/, lib/
  • A4.11 — Eliminate KotlinCompiler and KotlinCompilerIntellijPlatform submodules; use kotlin-compiler:1.3.72 directly with exclusions; move patched classes (Extensions, ContainerUtilRt, message bundles) into Nbm
  • B1 — Research K2 Analysis API, choose architectural approach
  • B2 — Bump kotlin-compiler 1.3.72 → 1.9.25 (FE1.0 preserved). See docs/plans/B2.0-bump-1.9.md. Ships as 0.6.x.
  • B3 — Bump IntelliJ core/core-impl/util 193 → 232 (code-style stays 241); rebase PatchedCoreImpl on 232 (not deleted — external 232 ≠ shaded 232 in kotlin-compiler). PR #36.
  • B4 — Replace KotlinFormatter source module with binary artifact org.jetbrains.kotlin:formatter:231-1.9.20-506-IJ8109.175; re-enable formatting/indentation tests. PR #37.
  • B5 — Replace KotlinIdeCommon source module with binary artifacts (base-fe10-analysis/code-insight/obsolete-compat/base-psi:231-1.9.20-506-IJ8109.175); re-enable intentions/quickfixes tests. 163 tests pass.
  • B6 — Repoint KotlinConverter → submodules/IntellijCommunity@232 (no binary artifact available for j2k); re-enable J2K/diagnostics tests
  • C — K2 Analysis API migration (C1–C10 complete). Ships as 0.7.x.
  • D — Compiler upgrade to kotlin-compiler-ir-for-ide 2.3.21 + analysis-api 2.3.21, platform 253 (D1–D7 ✅). Ships as 0.8.x.
  • E — Editor UX polish and missing features (E1–E12). Ships as 0.9.x+. (E1–E8 ✅, E8.5 ✅)

B3–B6 ship as 0.6.x on feature/kotlin-compiler-only; single PR after B6 passes all 169 tests. Stage C ships as 0.7.x; C1–C10 complete. Stage D ships as 0.8.x.


Track A — Infrastructure

A1. Rename Artifact and Plugin Metadata

  • Update pom.xml
  • Create src/main/nbm/manifest.mf with OpenIDE-Module-Name
  • layer.xml — no display-name changes needed
  • Bundle.properties — no changes needed (name set via manifest.mf)
  • setup-local-repo.sh — no groupId/artifactId references to the main plugin
Field Before After
groupId Kotlin io.github.nbplugins
artifactId kotlin.netbeans.plugin netbeans-plugin-kotlin-nbm
version 0.3.30-SNAPSHOT 0.4.0-SNAPSHOT
<name> in pom.xml Kotlin Netbeans Plugin Kotlin
OpenIDE-Module (NB code-name) Kotlin.kotlin.netbeans.plugin io.github.nbplugins.kotlin
OpenIDE-Module-Name (NB UI) Kotlin Kotlin Support

Source packages are not renamed.


A2. GitHub Actions CI/CD

  • Rename branch master → main
  • Copy and adapt .github/workflows/build.yml from NetbeansClaudeCodePlugin
  • Copy build-scripts/autotag.sh
  • Research licenses (Apache-2.0 / JetBrains / IntelliJ Community) — whether Maven Central deployment is allowed (deferred)
  • Configure publishing (Maven Central or GitHub Packages) (deferred)

Base on .github/workflows/build.yml and build-scripts/autotag.sh from NetbeansClaudeCodePlugin. Adaptations:

  • Main branch: main
  • Replace all repository references with io.github.nbkotlinplugin/netbeans-kotlin-plugin
  • Xvfb: remove explicit xvfb-run — Xvfb is started automatically by pom.xml
  • Documentation: remove the pandoc step

Versioning scheme:

  • pom.xml holds MAJOR.MINOR.0-SNAPSHOT — only MAJOR.MINOR matters to CI
  • CI computes the version from git tags: base tag MAJOR.MINOR + commit count → MAJOR.MINOR.N

Release cycle:

  • Starting a release: bump pom.xml to new MAJOR.MINOR.0-SNAPSHOT → CI creates base tag
  • During development: add changes to CHANGELOG.md (no version heading)
  • Finishing a release: add heading # MAJOR.MINOR or # MAJOR.MINOR (YYYY-MM-DD) to CHANGELOG.md → CI sees the signal, creates tag MAJOR.MINOR.N, publishes GitHub Release, auto-replaces heading with # MAJOR.MINOR.N (date)
  • Patch releases on an old branch: branch release/MAJOR.MINOR, same mechanism

CHANGELOG.md rules:

  • Heading # MAJOR.MINOR — only when finishing a release (CI signal)
  • During development — bullet lines at the very top of the file, no heading
  • Each bullet starts with a past-tense verb: Fixed, Added, Improved, etc.
  • Changes described from the user's perspective, not implementation
  • Bullet committed together with the code change, never separately

Commit message rules:

  • Start with a past-tense verb: Fixed ..., Added ..., Improved ...
  • Subject describes what was done; body (if needed) — how and why
  • When closing a GitHub issue: subject = CHANGELOG bullet text; body contains Resolves: #N
  • Release-finish commit: "Requested release MAJOR.MINOR"

Branch naming:

  • bugfix/<description> — bug fixes
  • feature/<description> — new features
  • release/MAJOR.MINOR — patch branches for old versions
  • Backports: bugfix/MAJOR.MINOR/<description>

A3. MIME Type — Override Built-in NB Support

  • Study registration of org.netbeans.modules.languages.kotlin in NB sources
  • Choose override mechanism
  • Replace text/x-kt with text/x-kotlin in all plugin registrations
  • Register our services with higher priority than the built-in ones

NetBeans 12+ includes basic .kt highlighting via org.netbeans.modules.languages.kotlin (MIME type text/x-kotlin). Our plugin currently uses text/x-kt.

Goal: switch to text/x-kotlin with our services taking precedence over the built-in NB ones.

Override mechanism chosen after research: position in layer.xml, supersedes in @ServiceProvider, or a module-level conflict declaration.


A4. Remove JARs from Repository + Maven Multi-Module

Phase 4.1 — Maven multi-module: copy existing JARs

  • Create root pom.xml with packaging=pom
  • Create bundled-jars/ submodule with child modules for each JAR
  • Move the main plugin into plugin/
  • Package ASM patches as a jar-patches/ submodule
  • Delete setup-local-repo.sh
  • Remove lib/*.jar and lib/*.jar.bak from git
pom.xml (root, packaging=pom)
├── bundled-jars/
│   ├── pom.xml
│   ├── kotlin-ide-common/pom.xml      — installs lib/kotlin-ide-common.jar
│   ├── kotlin-formatter/pom.xml       — installs lib/kotlin-formatter.jar
│   ├── kotlin-converter/pom.xml       — installs lib/kotlin-converter.jar
│   ├── intellij-core/pom.xml          — installs lib/intellij-core.jar
│   └── ...
└── plugin/pom.xml                     — main plugin module (former root pom)

Phase 4.2 — PATCHED JARs generated by Maven build

  • Create PatchingJars/ Maven module — compiles patches-src/*.java + ASM into a fat JAR
  • Each bundled-jars module applies its patch chain via exec-maven-plugin → installs target/patched.jar
  • Remove lib/*-PATCHED.jar and lib/kotlin-compiler-1.3.72-PATCHED.pom from git
  • Move lib/kotlin-compiler-1.3.72-PATCHED.pom → bundled-jars/KotlinCompiler/kotlin-compiler-patched.pom
JAR Phase 4.1 Phase 4.2
kotlin-compiler-1.3.72 lib/ (PATCHED, in git) Maven Central → patched by build
kotlin-formatter lib/ (PATCHED, in git) lib/ original → patched by build
kotlin-ide-common lib/ (PATCHED, in git) lib/ original → patched by build
kotlin-converter lib/ (PATCHED, in git) lib/ original → patched by build
intellij-core lib/ (PATCHED, in git) lib/ original → patched by build
openapi-formatter, idea-formatter lib/ lib/ (unchanged)

Phase 4.3 — kotlin-formatter: compile from sources

  • Add sparse git submodule submodules/Kotlin (JetBrains/kotlin@v1.3.72), sparse-checkout idea/formatter
  • Rewrite bundled-jars/KotlinFormatter/pom.xml: packaging jar, compile with kotlin-maven-plugin from submodules/Kotlin/idea/formatter/src/; fallback — extract embedded sources from lib/kotlin-formatter-1.0.jar
  • Remove lib/kotlin-formatter-1.0.jar from git
  • Remove PatchFormatterBody.java from patches-src/ (not needed when compiling from source)

Dependencies compiled against: netbeans-plugin-kotlin-openapi-formatter, idea-formatter, intellij-core, netbeans-plugin-kotlin-compiler, org.jetbrains:annotations.

Phase 4.4 — kotlin-compiler: compile replacement classes from sources

  • Reuse submodules/Kotlin (already added in 4.3); sparse-checkout extended to compiler/ as needed
  • Compile replacement/patched classes from sources instead of ASM bytecode manipulation
  • Remove remaining ASM patch steps for kotlin-compiler from bundled-jars/KotlinCompiler/pom.xml
  • Remove no-longer-needed patch tools from patches-src/

Phase 4.5 — Eliminate strip-based ASM patches

  • Replace PatchStripConflicts (intellij-core vs kotlin-compiler conflict resolution) with Ant <present> selector
  • Replace PatchStripBundled (ConcurrentRefHashMap, plugin-owned classes, picocontainer, guava) with Ant <zipfileset exclude> and <delete>
  • Delete dead patch tools from patches-src/: PatchStripConflicts, PatchStripBundled, PatchConcurrentRefHashMap, PatchConcurrentWeakHashMap, PatchExtensionsAddSetRootArea
  • Rename intermediate patched.jar → ${project.build.finalName}.jar in all bundled-jars modules

Phase 4.6 — kotlin-converter: compile from sources

  • Add sparse-checkout for kotlin-converter sources in submodules/Kotlin (j2k/, idea/idea-core/, idea/ide-common/, idea/idea-analysis/)
  • Rewrite bundled-jars/KotlinConverter/pom.xml: compile from sources with kotlin-maven-plugin
  • Remove lib/kotlin-converter-1.0.jar from git
  • Remove PatchImportConversionKt.java and PatchFqnPart.java from patches-src/

Phase 4.7 — kotlin-ide-common: compile from sources

  • Add sparse-checkout for kotlin-ide-common sources in submodules/Kotlin (idea/ide-common/)
  • Rewrite bundled-jars/KotlinIdeCommon/pom.xml: compile from sources
  • Remove PatchKotlinIdeCommon.java from patches-src/
  • Remove lib/kotlin-ide-common-1.0.jar from git
  • Add stubs in Nbm/src for new abstract methods introduced by v1.3.72 API
  • Replace stubs with real implementations (getResolutionFacadeByFile, getResolutionFacadeByModuleInfo, getResolutionFacade(platform), tryGetFrontendService, analyzeWithAllCompilerChecks)

Phase 4.8 — KotlinCompilerIntellijPlatform: replace stub patches with source classes

  • Move PatchAstLoadingFilter logic to a source class in patches/ (stub that always returns)
  • Move PatchExtensionsAddGetExtensions logic to a source class in patches/
  • Remove PatchAstLoadingFilter.java and PatchExtensionsAddGetExtensions.java from patches-src/

Phase 4.9 — openapi-formatter, idea-formatter: compile from sources ✓ Done

  • Add sparse-checkout for openapi/idea formatter sources in submodules/IntellijCommunity
  • Rewrite bundled-jars/OpenapiFormatter/ and bundled-jars/IdeaFormatter/pom.xml: compile from sources
  • Remove lib/openapi-formatter-1.0.jar and lib/idea-formatter-1.0.jar from git
  • Remove PatchContainerUtilAddMissing.java from patches-src/

Phase 4.10 — intellij-core: replaced with Maven artifacts ✓ Done

  • Add sparse-checkout for intellij-core sources in submodules/IntellijCommunity
  • Replace lib/intellij-core-1.0.jar with core:193.7288.26 + core-impl:193.7288.26 as direct Maven deps of Nbm
  • Remove IntellijCore bundled-jars wrapper module
  • Delete PatchingJars/ module and patches-src/ directory entirely
  • Delete lib/ directory

Phase 4.11 — Eliminate KotlinCompiler and KotlinCompilerIntellijPlatform submodules

  • Replace netbeans-plugin-kotlin-compiler dep in Nbm with direct kotlin-compiler:1.3.72 dep, with <exclusions> for packages already provided by other deps (com/google, javaslang, org/picocontainer, etc.)
  • Move patches/com/intellij/openapi/extensions/Extensions.java → Nbm/src/main/java/
  • Move patches/com/intellij/util/containers/ContainerUtilRt.java → Nbm/src/main/java/
  • Move patches/messages/JavaCoreBundle.properties and JavaErrorMessages.properties → Nbm/src/main/resources/messages/
  • Remove patches/com/intellij/util/AstLoadingFilter.java patch (class already present in core:193.7288.26)
  • Delete bundled-jars/KotlinCompiler/ and bundled-jars/KotlinCompilerIntellijPlatform/ modules
  • Remove both modules from root pom.xml reactor
  • Verify build and tests pass

Class conflict strategy: kotlin-compiler:1.3.72 embeds 3245 com/intellij/** classes; 1123 of them duplicate core:193 + core-impl:193 + util:193 with different bytecodes. In the NBM classloader the Nbm main JAR loads first, then ext/ JARs in dependency order. Since core:193 is declared before kotlin-compiler in Nbm/pom.xml, core:193 classes win. The remaining 1370 Java PSI classes (CoreJavaFileManager, PsiAnnotation, etc.) are unique to kotlin-compiler and required at runtime — they are not available as separate Maven artifacts for the 193 era.


Track B — Infrastructure Bump to Kotlin 1.9.25 + IntelliJ 232

B1. Research K2 Analysis API ✓ done

  • Study the structure of submodules/IntelliJCommunity/plugins/kotlin
  • Find a standalone mode for K2 (analysis-api-standalone-for-ide)
  • Write an ADR with the chosen approach → docs/adr/B1-k2-analysis-api-approach.md

B2. Bump kotlin-compiler 1.3.72 → 1.9.25 ✓ done

Detailed plan: docs/plans/B2.0-bump-1.9.md

Ships as 0.6.x (branch feature/kotlin-compiler-only).

kotlin-compiler:1.9.25 ships a 232-era shaded com.intellij.* snapshot — aligned with the external IntelliJ platform era we will pin in B3. FE1.0 (BindingContext, ClassDescriptor, TopDownAnalyzerFacadeForJVM) stays intact throughout B2–B6; Nbm call sites are not rewritten.

A PatchedCoreImpl module was added to strip 193-era platform classes that conflicted with the 1.9.25 shaded snapshot — it is removed in B3 once the external platform aligns to 232.

Done in B2: kotlin.version 1.3.72 → 1.9.25; <languageVersion> 1.3 → 1.9; 49 tests temporarily disabled (formatter/indentation/intentions fail due to binary incompat in bundled-jars still compiled from submodules/Kotlin@v1.3.72); fixed in B4–B6.


B3. Bump IntelliJ core 193 → 232; rebase PatchedCoreImpl ✓ done (PR #36)

  • Bump core, core-impl, util from 193.7288.26 → 232.9921.47 in parent pom.xml
  • code-style, code-style-impl stay at 241.194
  • PatchedCoreImpl rebased from 193 → 232 (same strip-overlap approach; NOT deleted because core-impl:232.9921.47 release and the 232-era snapshot shaded inside kotlin-compiler:1.9.25 differ — CoreApplicationEnvironment diverged enough to break test init if the external JAR wins)
  • Added VfsBundle stub (com.intellij.openapi.vfs) — removed from core:232, used by BuiltInsReferenceResolver
  • bundled-jars/* still compile against core:193 (unchanged until B4–B6)

Gate: 120/120 tests pass; no regressions.


B4. Replace KotlinFormatter with binary artifact ✓ done (PR #37)

Instead of repointing to IntellijCommunity 232 sources, used ready binary artifact org.jetbrains.kotlin:formatter:231-1.9.20-506-IJ8109.175 from JetBrains Space Maven repo.

  • Deleted bundled-jars/KotlinFormatter entirely
  • Added JetBrains Space repo and org.jetbrains.kotlin:formatter binary dependency
  • Added runtime stubs bridging 241-era formatter API against kotlin-compiler:1.9.25 shaded classes: DynamicBundle, FormatTextRanges, MultiMap, ObjectIntMap/ObjectIntHashMap, ObjectUtils (+reachabilityFence), misc/registry.properties
  • Removed try/catch (NoSuchFieldError) fallbacks in KotlinIndentTask.kt and formatUtils.kt
  • Re-enabled 36 formatting/indentation tests

Gate: 154 tests pass.


B5. Replace KotlinIdeCommon with binary artifacts ✓ done

Source compilation abandoned — 232-era base-fe10-analysis/src mixes K2 API classes that can't compile without K2 Analysis API deps. Used 4 pre-built JARs from JetBrains Space (packages.jetbrains.team/maven/p/ki/maven):

  • org.jetbrains.kotlin:base-fe10-analysis:231-1.9.20-506-IJ8109.175
  • org.jetbrains.kotlin:base-fe10-code-insight:231-1.9.20-506-IJ8109.175
  • org.jetbrains.kotlin:base-fe10-obsolete-compat:231-1.9.20-506-IJ8109.175
  • org.jetbrains.kotlin:base-psi:231-1.9.20-506-IJ8109.175

Nbm source adaptations: ImportInsertHelper / KotlinCacheService / ResolutionFacade API changes (231 era); @OptIn(FrontendInternals::class) on service methods; NotPropertyList.kt added (missing from 231 JARs); jvmTarget bumped 11 → 17. Re-enabled 8 + 1 = 9 tests.

Gate: 163 tests pass.


B6. Repoint KotlinConverter → IntellijCommunity 232

  • Source paths: submodules/Kotlin/j2k/src → submodules/IntellijCommunity/plugins/kotlin/j2k/old/src (FE1.0 converter lives in old/; K2 converter is in new/)
  • Bump kotlin-maven-plugin in KotlinConverter to 1.9.25; drop <languageVersion>1.3</languageVersion>
  • Re-validate two replacer-plugin patches (emptyList(), runWriteAction)
  • Re-enable J2KTest (5 methods) and DiagnosticsTest (1 method)

Gate: all 169 tests pass.


Track C — K2 Analysis API Migration ✓ complete (0.7.x)

Starting point after B6: BindingContext (FE1.0), kotlin-compiler:1.9.25. Target after C10: KaSession/KaSymbol (K2 Analysis API), kotlin-compiler:2.0.21.

Strategy:

  1. C1 ✓ done (PR #42) — Bump kotlin-compiler 1.9.25 → 2.0.21. Add analysis-api-*-for-ide:2.0.21 to classpath. Fix FE1.0 call sites for 2.0.21 API changes. Verify: all 169 tests pass, no analysis call-site changes yet. submodules/Kotlin stays at 1.9.25 (K2 Analysis API runtime is provided by the -for-ide JARs, not by the submodule sources).
  2. C2 — Bump platform JARs and Kotlin submodule to 242/2.0.21-era:
    • submodules/Kotlin → v2.0.21 (sparse checkout: only /*.md, /*.txt)
    • Bump binary platform JARs core, core-impl, util from 232.9921.47/241.194 to 242.26775.26
    • Bump base-fe10-* from 231-1.9.20-506-IJ8109.175 to 242-era version
    • Add CoreImpl and KotlinCompiler reactor modules
    • KotlinConverter/pom.xml and submodules/IntellijCommunity unchanged (stay at 232-era)
    • Verify: all tests pass, no analysis call-site changes yet.
  3. ✅ C3 — Set up StandaloneAnalysisAPISession alongside existing KotlinEnvironment (analysis-api-standalone-for-ide). Both analysis paths available simultaneously.
  4. ✅ C4 — Migrate resolve/, idea/util/ — BindingContext → analyze { } / KaSession
  5. ✅ C5 — Migrate completion/ — K2 primary path (KaCompletionProvider, KaCompletionProposalFactory); K1 fallback preserved. Fixed collectBinaryJars to handle file:-prefixed !/-suffixed classpath URLs from NetBeans Maven integration.
  6. ✅ C6 — Migrate highlighter/semanticanalyzer/ — K2 primary path (KaSemanticHighlightingVisitor); K1 fallback preserved. Added MultiMap(Map) constructor stub. Fixed KtFunctionType parameter guard and split analyze {} blocks so deprecated-highlight failures don't discard symbol highlights.
  7. ✅ C7 — Migrate hints/, intentions/, fixes/ — K2 primary path (KaImplementMembersFix, 7 K2 intentions, KaUnusedImportsComputer); K1 fallback preserved. Fixed hint-not-disappearing bug (wrapWithInvalidate for quick-fixes) and duplicate-member bug (declaredMemberScope filter). Registered DataObject save listener so hints reappear after Ctrl+Z + Ctrl+S.
  8. ✅ C8 — Migrate navigation/ — K2 primary path (KaNavigationUtils: resolveToSourcePsi, renderDeclarationTooltip, getSmartCastDescription); K1 fallback preserved in navigate() and getToolTip().
  9. ✅ C9 — Migrate structurescanner/, filesystem/lightclasses/. Added code folding (+/− controls, KotlinFoldTypeProvider); K2 Navigator panel (KaStructureScanner); KaLightClassGenerator. PR #52.
  10. ✅ C10 — Remove KotlinEnvironment and all remaining BindingContext fallback code; remove KotlinIdeCommon module (all base-fe10-* deps eliminated with FE1.0 code). Added temporary FirIncompatibleClassExpressionChecker workaround for KT-75035/KT-83463 (null source crash); ported KaRemoveEmptyClassBodyIntention, KaRemoveEmptyPrimaryConstructorIntention; fixed last-line computeSuggestions skip bug.

Note on C3 ordering: submodules/IntellijCommunity intentionally stays at 232-era through C3–C10. Both KotlinIdeCommon (compiles base/fe10/analysis/src) and KotlinConverter (compiles j2k/old/src) build successfully against 242 platform JARs from 232-era sources — verified after C2.

ADR: docs/adr/B1-k2-analysis-api-approach.md.


Track D — Platform and Compiler Upgrade to Era 253 / Kotlin 2.3.21 (0.8.x)

Starting point after C10: K2 Analysis API, kotlin-compiler:2.0.21 shaded (193-era com.intellij.*), platform core/core-impl/util at 242, code-style at 241. Target (achieved): kotlin-compiler-ir-for-ide:2.3.21 unshaded, platform era 253, analysis-api 2.3.21.

Each substage is a separate branch (refactor/dN-...) and PR targeting upstream/main.

  • ✅ D1 (refactor/d1-bump-kotlin-compile-version) — Decouple kotlin-maven-plugin from bundled runtime: added kotlin.compile.version=2.2.21; pluginManagement uses it; bumped kotlin.runtime.languageVersion 1.9 → 2.2; upgraded gmavenplus-plugin to 4.2.0 + Groovy 4.0.32 (Java 25 support). languageVersion stays 2.2 until context-receivers → context-parameters migration. PR #56.
  • ✅ D2 (refactor/d2-remove-submodules) — No public j2k-new binary artifact exists; removed KotlinConverter module from reactor and netbeans-plugin-kotlin-converter dep from Nbm; stubbed Java2KotlinConverter (shows "not available" dialog); removed J2KTest; configured submodules/IntellijCommunity as sparse (root-only checkout). J2K will be reimplemented in E6. PR #57.
  • ✅ D3+D5 (refactor/d3-d4-compiler-platform-253) — Replace kotlin-compiler:2.0.21 (shaded) with kotlin-compiler-ir-for-ide:2.3.21 (unshaded); bump analysis-api-*-for-ide 2.0.21 → 2.3.21; remove FirIncompatibleClassExpressionChecker workaround (KT-75035 fixed in ≥ 2.1.20). New KotlinCompilerCliBase module extracts all classes absent from -for-ide and platform JARs (set-difference from fat kotlin-compiler.jar); CoreImpl repacks platform 253 as before. Explicit new runtime deps: kotlinx-collections-immutable-jvm:0.3.7, caffeine:3.1.8. Registry stub updated to expose Companion inner class (analysis-api 2.3.21 requirement).
  • ✅ bugfix/jdk-invisible-in-k2-session — Register JDK home as a KtSdkModule dependency in KotlinAnalysisAPISession; register CodeInsightContextManagerStub service; strip bundled fastutil from KotlinCompilerCliBase (conflicts with intellij-deps-fastutil in util:253); bump intellij-deps-fastutil 8.5.11-18 → 8.5.13-jb4. Fixes false type errors and broken semantic highlighting for code that uses JDK types.
  • ✅ D5 (refactor/d5-remove-stubs) — Removed 17 dead compatibility stubs from Nbm/src/main/java/com/intellij/: shaded-1.9.25 stubs (DynamicBundle, FormatTextRanges, Extensions, ObjectUtils, DependantSpacingImpl, …) and 193-era platform bridges (ServiceManager, DataLoader, ObjectIntHashMap, MultiMap, ContainerUtilRt, …). Retained 16 stubs still needed: formatter runtime stubs (Formatter, CustomCodeStyleSettingsManager, CodeStyleSettingsService, ConcurrentCollectionFactory, ConcurrencyUtil), compile-only stubs (Configurable, IndentOptionsEditor, Editor, CodeStyleSettingsCustomizable), extension-point base classes (CodeStyleSettingsProvider, LanguageCodeStyleSettingsProvider), Registry/RegistryValue (analysis-api 2.3.21 Companion wrapper), CodeInsightContextManagerStub (K2 service), and plugin-specific providers. 145 tests pass.
  • ✅ D6 (refactor/d6-formatter-from-sources, PR #65) — Replaced org.jetbrains.kotlin:formatter:231-1.9.20-506-IJ8109.175 with bundled-jars/KotlinFormatter built from submodules/IntellijCommunity/plugins/kotlin/formatter/minimal/src/ (253-era sources). 9 UI-panel files excluded from compilation; deferred to E5.
  • ✅ D7 (refactor/d7-platform-253, PR #66) — Bumped platform JARs core/core-impl/util/ code-style/code-style-impl 242/241 → 253. Added Registry, RegistryValue, ConcurrentCollectionFactory, ConcurrencyUtil, CodeInsightContextManager stubs to satisfy analysis-api 2.3.21 and kotlin-compiler-ir-for-ide 2.3.21 requirements at runtime.

Track E — Editor UX Polish and Missing Features (0.9.x+)

Priority order: E1 → E2 → E3 → E4 → E5 → E6 → E7 → E8 → E9 → E10 → E11 → E12

  • E1 — Editor UX polish (sub-items in priority order):

    • K2 semantic highlighting live-update: fixed drift while typing unsaved changes (PR #71)
    • FUNCTION_CALL, EXTENSION_FUNCTION_CALL, SUSPEND_FUNCTION_CALL, CONSTRUCTOR_CALL semantic tokens added to KotlinHighlightingAttributes and KaSemanticHighlightingVisitor
    • Fonts & Colors: 50+ named color categories matching IDEA exactly, organised in 10 groups; 3 theme XMLs in highlighter/colors/: FlatLafLight.xml (IntelliJ Light), FlatLafDark.xml (Darcula), NetBeans55.xml (Classic NetBeans) (branch feature/e2-idea-color-parity)
    • Fonts & Colors preview: semantic highlights applied to preview sample via PreviewSemanticHighlightsLoader (branch feature/e2-idea-color-parity)
    • Source / History toolbar buttons for .kt files: registered MultiViewElement (History view) alongside Source; removed empty Visual tab (PR #74)
    • Reformat selection: CSL Reformat action works on a selected range; Format context menu item added (PR #76)
    • Auto-indent on paste: KotlinIndentTask handles paste events, preserving relative indentation of pasted block (PR #77)
    • Completion filtering: dot-receiver completion uses receiver type's member scope; only members and applicable extensions are shown (no locals, outer-class members, or imported classes)
    • Completion signatures: RHS shows (param: Type): ReturnType for functions and : Type for properties, rendered via K2 KaTypeRendererForSource inside analyze {}
    • Completion icons: Kotlin-accurate icons (val, var, method, extension function, suspend function, interface, enum, object, type alias, parameter) via bundled-jars/KotlinIcons (SVG→PNG from IntelliJ Community sources at build time)
    • Completion deduplication and IDEA-like sort order: locals first, then type members (properties before methods), then package/import scope; duplicates (same name+signature) suppressed
    • Hover tooltip: pausing the mouse over a Kotlin identifier shows a popup with a syntax-highlighted signature, container info, and KDoc sections; Ctrl+hover shows identical content; completion documentation popup shows each candidate's own docs (not always the first candidate's)
    • False-positive QUALIFIED_EXPRESSION_WITHOUT_SELECTOR — investigated; no longer reproduced with K2 2.3.21
    • ClassNotFoundException: org.codehaus.plexus.util.PropertyUtils SEVERE on J2SE project open: replaced Maven Embedder utility with Properties.load() (PR #75).
  • E2 — Extended diagnostics and highlighting:

    • @Deprecated symbols: grey-strike rendering via KaSymbol.deprecationStatus (added as KOTLIN_DEPRECATED token in color parity work, branch feature/e2-idea-color-parity)
    • Unused variables / unused parameters: K2 KaDiagnosticProvider checks
    • Full K2 diagnostic set (exhaustive when, type mismatch, unresolved reference) exposed in the NetBeans gutter + error stripe
  • E3 — Parameter info and inlay hints:

    • Ctrl+P (ParameterInfo): CSL ParameterInfo service; function signature popup with active parameter highlighted (PR #86)
    • Inlay hints (parameter names at call sites): deferred — no public NetBeans 23 inlay-hints API found
  • E4 — Extended intentions and quick-fixes matching IDEA set:

    • 43 code intentions (Groups A–H): missing when branches, if↔when conversions, string template↔concat↔buildString conversions, lambda↔reference↔anonymous function conversions, forEach↔for loop, named argument add/remove, brace add/remove, property accessor generation, De Morgan's law, type argument insert/remove, null-safety fixes, type mismatch fixes, modifier fixes, and more (PR #87)
    • 17 K2 quick-fixes from IDEA with infrastructure for standalone PSI mutation (PR #90)
  • E5 — Formatter settings UI (PR #93):

    • KotlinCodeStyleSerializer / KotlinCodeStylePreferences — JDOM-based XML serialization (diff-from-defaults)
    • KotlinCodeStylePreferencesProvider — NbPreferences bridge; ProjectCodeStyleStorage — per-project .kotlin-code-style.xml
    • Tools→Options→Kotlin: KotlinOptionsPanelController + KotlinOptionsPanel with IDEA-style layout: StyleBar (KotlinStyleBar + KotlinSchemeManager with Kotlin Official / Obsolete / IDE defaults profiles)
      • JSplitPane (6-tab panel | live preview via KotlinFormattingPreviewPane)
    • All 6 panels: KotlinFormatterIndentPanel, KotlinFormatterSpacesPanel, KotlinFormatterCodeGenPanel (wrapping), KotlinFormatterBlankLinesPanel, KotlinFormatterImportsPanel, KotlinFormatterOtherPanel
    • OptionTreePanel — reusable JTree with checkbox/combobox renderers
    • Per-project: KotlinProjectOptionsPanelController + KotlinProjectCustomizerProvider
  • E6 — New Kotlin Class wizard (PR #TBD):

    • Registered all 10 templates (Class, Interface, Data class, Enum, Annotation, Sealed class, Sealed interface, Abstract class, Object, File) in layer.xml; previously @TemplateRegistration annotations were silently ignored due to -proc:none
    • Added KtDataClassWizardIterator, KtAnnotationWizardIterator, KtSealedClassWizardIterator, KtSealedInterfaceWizardIterator, KtAbstractClassWizardIterator
    • FQN support (com.example.MyClass → package + short name) already present in TargetChooserPanelGUI
  • E7 — Find Usages (Alt+F7):

    • KaFindUsagesComputer — K2 core: resolves target PSI at cursor, iterates all project KtFiles, collects OffsetRanges via sym.psi == targetPsi comparison
    • KotlinWhereUsedPlugin — RefactoringPlugin wiring: extracts document/offset from lookup, calls computer, adds KotlinFindUsagesResultElement entries to bag
    • KotlinWhereUsedRefactoringUI — RefactoringUI adapter: resolves symbol name for dialog title, no options panel
    • KotlinActionsImplementationProvider — added canFindUsages / doFindUsages
    • KotlinRefactoringsFactory — added WhereUsedQuery branch
    • layer.xml — fixed silently-broken Rename refactoring (added Services/ entries for factory + provider, missing because -proc:none suppresses @ServiceProvider); added WhereUsedAction.shadow to editor popup and file-node context menu (mirrors x-java registration that refactoring-api adds only for Java)
  • E8 — Navigate menu parity with Java:

    • Go to Declaration (Ctrl+B) and Go to Source (Ctrl+Shift+B): KotlinDeclarationFinder registered via KotlinLanguage.getDeclarationFinder(); wires into existing CslEditorKit/GoToDeclarationAction chain already in layer.xml
    • Go to Test/Tested class (Ctrl+Alt+T): KotlinTestLocator (TestLocator SPI, global ServiceProvider); convention-based Foo ↔ FooTest name matching
    • Go to Super Implementation (Ctrl+Shift+P): KotlinGoToSuperTypeAction + KotlinOverridingMethods.overrides() (K2 allOverriddenSymbols); registered as custom action with keybinding in KotlinKeyBindings.xml (CSL does not auto-provide this; Java-only in java.editor)
    • Go to Implementation (Ctrl+Alt+B): KotlinGoToImplementationsAction + KotlinOverridingMethods.overriddenBy(); scans project KtFiles similarly to Find Usages
    • Inspect Members (Ctrl+Shift+F12): KotlinShowMembersAction opens and focuses the Navigator window (popup-text "Inspect Members"); existing KaStructureScanner already populates Navigator content
    • Editor right-click Navigate submenu (Editors/text/x-kotlin/Popup/goto) registered to mirror Java's submenu: goto-source, goto-declaration, GotoOppositeAction shadow (Go to Test), goto-super-implementation, goto-implementation, separator, kotlin-inspect-members
    • Inspect Hierarchy (Alt+Shift+F12): deferred to E8.5 — needs TypeHierarchyQuery SPI, separate from CSL DefaultLanguageConfig
  • E8.5 — Inspect Hierarchy (Alt+Shift+F12): type hierarchy tree; TypeHierarchyQuery SPI investigation required

  • E9 — Refactoring rewrites via K2 Analysis API + IDEA source reuse

    Strategy: compile IDEA K2 refactoring sources from submodules/IntellijCommunity/plugins/kotlin/refactorings/kotlin.refactorings.k2/ inside the KotlinRefactoring reactor module via maven-resources-plugin (same pattern as KotlinFormatter / KotlinHighlighting), then add thin stubs for IDE-only types absent at runtime (WriteCommandAction, ApplicationManager, DataContext, OccurrencesChooser). NetBeans RefactoringPlugin / RefactoringUI adapters call into the compiled IDEA engine — no manual re-implementation of algorithms. E9.1 and E9.2 (Safe Delete) are the only hand-written exceptions (trivially built on K2 analyze {} + Find Usages).

    KotlinRefactoring reactor module — introduced in E9.3; jar module that compiles IDEA refactoring sources from submodules/IntellijCommunity together with local stubs and compatibility shims. Follows the same maven-resources-plugin copy pattern as KotlinFormatter / KotlinHighlighting. The Nbm module depends on this jar; both are part of the root reactor so mvn package from root is the correct build command (the NBM plugin resolves inter-module dependencies via the workspace reader within a single invocation; a separate mvn install step is not needed).

    Runtime service injection pattern — IDEA's codeInliner/ engine calls services (PsiSearchHelper, ShortenReferencesFacility, …) via service<T>() / T.getInstance(). In standalone mode these are missing. The pattern used in E9.3 and applicable to all future E9.x refactorings:

    1. Register a no-op or NB-aware implementation in KotlinAnalysisAPISession.registerStandaloneServices() / installNoOpPsiSearchHelper() before the refactoring engine is first called.
    2. Register missing extension points (e.g. com.intellij.referencesSearch) in registerHighlightInfoFilterEP().
    3. Document every added stub/service in docs/stubs.md.

    Cursor-on-declaration-or-usage — every Ka*Computer must resolve the target declaration from the caret regardless of whether the caret is on the declaration itself or on a reference to it. Standard approach (used in E9.3, required for E9.4+):

    1. Find the leaf element at the caret: ktFile.findElementAt(offset).
    2. Walk up to a KtNameReferenceExpression; if found, call K2 analyze { ref.mainReference.resolveToSymbol()?.psi } — this gives the declaring element directly.
    3. Only if step 2 yields nothing, fall back to PsiTreeUtil.getParentOfType(element, KtXxx::class.java) to handle the case where the caret is on the declaration keyword or name token.
    • E9.1 — Rename (Alt+Shift+R): K2-based KaRenameComputer (hand-written; PR #101)

    • E9.2 — Safe Delete: K2-based KaSafeDeleteComputer (hand-written; PR #102)

      • Hand-written: K2 analyze {} + KaFindUsagesComputer → collect all usages → Problem(false, "Used in N places") if any; on confirm delete declaration
      • NetBeans adapter: KotlinSafeDeletePlugin / KotlinSafeDeleteUI in Nbm
    • E9.3 — Inline variable / property (Ctrl+Alt+N) — IDEA codeInliner/ engine port

      • IDEA sources (compiled into KotlinRefactoring via maven-resources-plugin): kotlin.refactorings.k2/inline/codeInliner/{CodeInliner, CodeToInlineBuilder, CallableUsageReplacementStrategy, PropertyUsageReplacementStrategy, InlinePostProcessor, InlinePreprocessorUtil, introduceValue}.kt; kotlin.refactorings.common/inline/codeInliner/{AbstractCodeInliner, AbstractCodeToInlineBuilder, AbstractInlinePostProcessor, AbstractPropertyUsageReplacementStrategy, CodeToInline, CommentHolder, InlineDataKeys, inlineUtils, MutableCodeToInline, ReplacementPerformer, UsageReplacementStrategy}.kt; kotlin.refactorings.common/inline/{AbstractKotlinInlinePropertyHandler, AbstractKotlinInlinePropertyProcessor, AbstractKotlinInlinePropertyDialog}.kt plus their abstract parents (AbstractKotlinInlineNamedDeclarationProcessor, AbstractKotlinDeclarationInlineProcessor, AbstractKotlinInlineDialog, KotlinInlineActionHandler).
      • Stubs/service registrations (see docs/stubs.md for details): BaseRefactoringProcessor (JVM linkage stub in Nbm/src/main/java/), UsageViewDescriptor (compile-only interface), NoOpPsiSearchHelper (project service, registered in KotlinAnalysisAPISession), KotlinSymbolBasedShortenReferencesFacility (application service wrapping IDEA internal SymbolBasedShortenReferencesFacility via delegation, in KotlinRefactoring).
      • NetBeans adapter (in Nbm):
        1. KotlinInlineVariablePlugin — NB RefactoringPlugin; KaInlineVariableComputer drives extractInitialization + createReplacementStrategyForProperty; per-usage strategy.createReplacer(usage).invoke() loop inside NbDocument.runAtomicAsUser; followed by KotlinFormatterUtils.formatRange on each inserted range. Flow control stays on NB side — IDEA's BaseRefactoringProcessor.run() is intentionally not invoked.
        2. KotlinInlineVariableUI — NB RefactoringUI; preview pane lists usage ranges.
        3. KotlinInlineVariableRefactoring — AbstractRefactoring carrying doc + offset.
        4. KotlinInlineVariableAction — BaseAction("kotlin-inline-variable"), Ctrl+Alt+N; registered in Refactor menu and Editors/text/x-kotlin/Actions/ in layer.xml.
      • Caret or a selected identifier resolution works on declaration and any usage — see Cursor-on-declaration-or-usage in E9 strategy above.
      • Supports local val and a local var with its sole definition in the declaration initializer. A K2-backed standalone-source scan rejects assignments and increment/decrement writes before the IDEA engine is invoked and identifies the conflicting expression; receiver/member/accessor, Java, and index-only write coverage remain outside this adapter's scope.
    • E9.4 — Inline function (Ctrl+Alt+N)

      • IDEA sources: inline/codeInliner/CodeInliner.kt, inline/codeInliner/CodeToInlineBuilder.kt, inline/codeInliner/CallableUsageReplacementStrategy.kt, inline/codeInliner/introduceValue.kt, inline/KotlinInlineFunctionProcessor.kt
      • Stubs: WriteCommandAction, ApplicationManager
      • NetBeans adapter: KaInlineFunctionComputer; KotlinInlineFunctionPlugin / KotlinInlineFunctionUI (option: this occurrence / all) in Nbm
    • E9.5 — Extract function (Ctrl+Alt+M)

      • IDEA sources: introduce/extractionEngine/ExtractionDataAnalyzer.kt, introduce/extractionEngine/Generator.kt, introduce/extractionEngine/KotlinTypeDescriptor.kt, introduce/extractionEngine/KotlinNameSuggester.kt, extractFunction/ExtractableCodeDescriptor.kt, extractFunction/ExtractionData.kt, extractFunction/ExtractionResult.kt, extractFunction/parametersUtil.kt, extractFunction/Parameter.kt
      • Stubs: WriteCommandAction, ApplicationManager, ProgressManager
      • Risk: computeExitPointSnapshot — verify availability in analysis-api:2.3.21 standalone; fallback: manual PSI visitor for return expressions
      • NetBeans adapter: KaExtractFunctionComputer; KotlinExtractFunctionPlugin / KotlinExtractFunctionUI (name input + param table) in Nbm
    • E9.6 — Introduce variable (Ctrl+Alt+V)

      • IDEA sources: introduce/introduceVariable/K2IntroduceVariableHandler.kt, introduce/introduceVariable/KotlinIntroduceVariableServiceK2Impl.kt, introduce/introduceVariable/introduceVariableUtil.kt, introduce/K2SemanticMatcher.kt, introduce/K2ExtractableSubstringInfo.kt
      • Stubs: OccurrencesChooser (→ replace all, or NB dialog); Editor not passed — computer operates headlessly
      • NetBeans adapter: KaIntroduceVariableComputer; KotlinIntroduceVariablePlugin / KotlinIntroduceVariableUI in Nbm
    • E9.7 — Move Declaration (Refactor menu; no F6 keybinding to avoid a NetBeans conflict)

      • IDEA sources ported (kotlin.refactorings.move.k2/src/): descriptor/{K2MoveDescriptor, K2MoveSourceDescriptor, K2MoveTargetDescriptor, K2MoveOperationDescriptor}.kt, processor/{K2MoveDeclarationsRefactoringProcessor, moveUtil, moveUsageUtil, moveConflictUtil}.kt, processor/conflict/** (all 10 conflict checkers — visibility, name-clash, overridden-in-subclass, sealed-class-hierarchy, type-parameter-usage, implicit-package-prefix, module-dependency, internal-member-usage, actual/expect, plus helpers). Excluded (out of scope): K2MoveHandler.kt (IDE action dispatch), ui/** (Swing — NB has its own text-field UI), K2MoveFilesOrDirectoriesRefactoringProcessor.kt (file/dir moves; F4.1 now ports its Kotlin handler through a lifecycle-free adapter), K2ChangePackageDescriptor.kt/processor (separate F4.2 feature).
      • Single-module architecture: this plugin has no multi-module/multiplatform project model anywhere (confirmed via dedicated research — every NetBeans project gets one isolated K2 analysis session). SingletonModule/ModuleUtilCore/ModuleType stubs (KotlinRefactoring/src/main/kotlin/com/intellij/openapi/module/) model this correctly rather than faking multi-module support; cross-module conflict checks (module-dependency/internal-member/actual-expect) always correctly report no conflict.
      • Real (non-stub) KaModule bridge: org.jetbrains.kotlin.idea.base.projectStructure.kaModuleBridge.kt resolves Module.toKaSourceModuleContainingElement/getKaModuleOfTypeSafe via analyze(element) { useSiteModule } instead of an IDE project-structure index lookup.
      • Hierarchy/inheritor search (functionOverriddenInSubclassConflict, sealedClassesConflict) uses the standalone K2 build-session bridge: KotlinStandaloneInheritorSearch scans Kotlin source files for inheritors and override chains, and the compatible OverridingDeclarations.forEachOverridingElement / KotlinSearchUsagesSupport APIs expose those results to copied IDEA code. Java/library results and full IDEA-index conflict coverage remain unavailable.
      • KotlinMoveUsageSearchService (new interface in KotlinRefactoring, real impl KotlinMoveUsageSearchServiceImpl registered from Nbm's KotlinAnalysisAPISession): whole-project external-usage search reusing the same file-iteration strategy as Find Usages (E7)'s KaFindUsagesComputer, since ReferencesSearch/PsiSearchHelper is a no-op standalone. Backs findMoveDeclarationUsages.kt, which reimplements the essential subset of the removed (patch #14, Copy Declaration/E9.19) K2MoveRenameUsageInfo.find().
      • KaMoveDeclarationComputer.move() calls the real, unmodified K2MoveDeclarationsRefactoringProcessor.performRefactoring() — not a hand-rolled reimplementation. Getting there required identifying and fixing several genuine standalone-environment bugs (each a real fix, not a workaround, applied via the same KotlinRefactoring/pom.xml groovy-patch mechanism used for every other era-compatibility issue in this module):
        1. Read-only target directory: this environment's analysis-session KtFiles are in-memory LightVirtualFile-backed; any PsiDirectory/VirtualFile reached via disk (VirtualFileManager/KotlinLocalFileSystem) is read-only for PSI mutation, so K2MoveTargetDescriptor.File's directory-based target resolution (getOrCreateTarget/getTarget, both routed through PsiDirectory.findFile()) can never reach a writable file. Fixed with SessionAwareTargetDirectory (in KaMoveDeclarationComputer.kt) — a PsiDirectory delegate that forwards every member IDEA's conflict-detection code reads (module, FqName, project, ...) to the real disk directory, but overrides findFile() to return the already-writable target KtFile directly (obtained the same way Copy Declaration/E9.19 does: write the file via NetBeans FileObject, refresh KotlinAnalysisAPISession, then getKtFileForPath).
        2. LightVirtualFile doesn't support file deletion: when the source file becomes effectively empty, performRefactoring() deletes it outright; LightVirtualFileBase's VFS doesn't implement deleteFile(). Patched to runCatching { it.delete() } — the move itself already succeeded by this point, so the emptied (package-directive-only) file is left on disk instead of losing that result.
        3. com.intellij.refactoring.rename.RenameUtil not on the standalone classpath: called by retargetUsagesAfterMove for non-code usages, which are always empty here (findNonCodeUsages is patched to emptyList(), no TextOccurrencesUtil standalone) — the call was real dead code at runtime; patched away along with its import.
        4. addElementsToTarget()'s oldToNewMap only mapped nested declarations, never the moved top-level element itself (withChildDeclarations() excludes the receiver). Real IDEA gets away with this because its MoveRenameUsageInfo.referencedElement re-resolves through a document-synced smart pointer that keeps following the element across the move; this plugin's simplified MoveRenameUsageInfo stub (Nbm, no PSI-document sync) resolves it via a plain SmartPsiElementPointer, which doesn't. Patched addElementsToTarget() to also map the moved element itself — a real, general correctness fix for external-usage retargeting of any top-level declaration, not standalone-specific.
        5. Retarget-before-delete reordering: for the same smart-pointer reason as #4, retargeting usages after deleteMovedElement() (IDEA's real order) finds referencedElement == null once the original is deleted. Patched performRefactoring() to call retargetUsagesAfterMove() before deleting the source elements/files.
        6. Import-directive references excluded from KotlinMoveUsageSearchServiceImpl's search: retargeting a reference that's literally part of an existing import statement (as opposed to a code usage) left the KtImportDirective invalidated mid-bindToElement(), standalone — no live-document sync to keep the import list consistent across a K2ReferenceMutateService restructure. Not needed anyway: retargeting the code usage (call site, etc.) to a fully-qualified reference and then shortening it already adds/removes the right import via Kotlin's own shorten-references pass, exactly as it does for Copy Declaration.
      • Retargeting an external (cross-file) usage is exercised for the first time by this refactoring (Copy Declaration only ever retargets same-file/internal usages), and initially hit a "requested stubbed spine during PSI operations" LOG.error() call deep in K2ReferenceMutateService/PsiFileImpl — IntelliJ's DefaultLogger.error() throws an AssertionError unconditionally unless a real Logger.Factory is installed, which this standalone environment never did. Fixed environment-wide (not just for Move) by installing LenientLoggerFactory (Nbm/.../resolve/LenientLogger.kt) — a java.util.logging-backed Logger implementation that logs error() instead of throwing — via Logger.setFactory(...) at the top of KotlinAnalysisAPISession.initApplicationEnvironment(), before any bundled IDEA class can call Logger.getInstance().
      • NetBeans adapter: KaMoveDeclarationComputer (KotlinRefactoring); KotlinMoveDeclarationAction (Refactor menu) / KotlinMoveDeclarationUI (target package + file name fields) / KotlinMoveDeclarationPlugin / KotlinMoveDeclarationRefactoring (Nbm)
      • Source and target mutation is now staged through KotlinRefactoringTransaction: a new target is removed on any conflict/error, an existing target is restored exactly, and Refactor → Undo Last Refactoring restores both documents (or removes the target file if the refactoring created it).
    • F4.1 — Move Kotlin File and Directory (Refactor menu / folder context menu)

      • Ports the Kotlin-specific K2MoveFilesHandler portion of K2MoveFilesOrDirectoriesRefactoringProcessor.kt through KaMoveFileComputer. The generic IDEA processor is intentionally not invoked: it depends on writable IntelliJ VFS, indexed generic-file search, command/listener lifecycle, and modal UI unavailable in standalone K2.
      • Refactor → Move Kotlin File... selects a destination source root and package. NetBeans owns physical movement through KotlinRefactoringTransaction; the K2 adapter updates a package only where source-root-relative package/directory alignment proves it safe, checks portable Kotlin conflicts, and retargets supported Kotlin references.
      • Transactions now record reversible physical file moves and transaction-owned destination folders; failed writes roll back the path and document snapshots, while Undo Last Refactoring restores the original path and text.
      • Folder-node Move Kotlin Directory... recursively moves only Kotlin descendants through one atomic transaction, retaining the selected directory and every nested Kotlin folder below the target package; a single K2 pass uses per-file target packages so inter-file references remain coherent. Non-Kotlin descendants remain at their source paths.
      • Portable coverage includes matching-package update, package/directory mismatch preservation, K2 semantic adapter execution, physical-move rollback, owned-folder cleanup, and undo. The remaining F4.1 scope is generic non-Kotlin content, Java/comment/text/index-only references, and full IDEA project-model conflict behavior.
    • F4.2 — Change Kotlin Package (Refactor menu / folder context menu)

      • Ports real upstream K2ChangePackageDescriptor and K2ChangePackageRefactoringProcessor sources from kotlin.refactorings.move.k2. The copied processor is patched only to remove IDEA's BaseRefactoringProcessor command/progress/dialog/ listener lifecycle; its K2 usage discovery, conflict collection, package-directive rewrite, declaration mapping, and retargeting sequence remain the semantic engine.
      • Refactor → Change Kotlin Package... changes the active Kotlin file's package without moving it. A folder-node invocation recursively changes only Kotlin descendants; direct children use the entered package while nested descendants append their relative folder paths. The selected folder's name is not added because its physical path remains unchanged.
      • Supported Kotlin code references and direct non-aliased imports update atomically through KotlinRefactoringTransaction; Undo Last Refactoring restores every source and usage document. Java/comment/text/index-only references, full IDEA project-model conflicts, and arbitrary multi-selection remain outside the standalone scope.
    • F4.3 — Move Nested Kotlin Member (Refactor menu)

      • Adds Refactor → Move Nested Member... for the portable K2-native subset: a nested named class/object can move to a selected named class/object; a companion-object function/property can move only to a selected target declaring exactly one companion object.
      • KaMoveNestedMemberComputer retains IDEA K2 internal-reference marking, rebinding, and shortening support while the passive NetBeans target chooser receives controller-computed candidates and never invokes K2 directly.
      • KotlinMoveNestedMemberPlugin validates a freshly resolved source/target immediately before mutation, stages every returned changed file through KotlinRefactoringTransaction, rolls back on a persistence failure, and supports Refactor → Undo Last Refactoring for source and target.
      • The intentionally narrow standalone boundary rejects instance members, constructors, enum entries, initializers, alias imports, duplicate targets, Java/non-code/comment/index-only scenarios, and external qualified usages whose rewrite has not been validated.
    • F7 — Rename Kotlin File and Package Directory (Refactor menu / folder context menu)

      • Adds an explicit Refactor → Rename Kotlin File... command for the active .kt file. It uses KotlinRefactoringTransaction to rename only the physical basename and supports Undo Last Refactoring; package declarations and Java file-facade references are deliberately unchanged. The generic file Rename additionally renames a matching top-level Kotlin class and its supported Kotlin references through K2 before renaming the file.
      • Adds folder-node Rename Kotlin Package Directory..., which renames only the physical directory and its descendants while leaving package directives and references unchanged.
      • The generic folder Rename (available for package folders below a conventional source root, not for src/main/kotlin/src/test/kotlin themselves) renames the directory together with its Kotlin packages. Every descendant receives the package derived from its post-rename path (including files whose directive did not match the directory), and KaChangePackageComputer retargets supported Kotlin imports and references. Reference retargeting works on the captured source text: in standalone mode rewriting a package directive invalidates every PSI smart pointer held by K2 UsageInfo, so imports and fully qualified references are rewritten by FQN token and callers that lose an implicit same-package binding receive an explicit import. The semantic pass runs on the original paths first, stages minimal hunk texts through KotlinRefactoringTransaction, and lets the single commit write those documents before renaming the folder, so conflicts are reported before any physical change and Undo Last Refactoring restores paths, texts, and open-editor carets together. Change Kotlin Package... remains the package-only operation.
      • The generic IDEA rename UI/lifecycle remains intentionally unported because it depends on writable IntelliJ VFS, indexed Java/file-facade search, automatic-renamer extensions, and action/command infrastructure unavailable in standalone NetBeans. Unicode/quoted names, Java/comment/text/index-only references, automatic renamers, and full project-model behavior remain outside this portable adapter.
    • E9.8 — Change Signature (Ctrl+F6) — PRs #114, #115

      • IDEA sources: changeSignature/KotlinChangeSignatureUsageSearcher.kt, changeSignature/KotlinChangeInfo.kt, changeSignature/KotlinChangeInfoBase.kt, changeSignature/KotlinParameterInfo.kt, changeSignature/KotlinMethodDescriptor.kt, changeSignature/KotlinChangeSignatureConflictSearcher.kt, all 11 changeSignature/usages/Kotlin*Usage.kt classes (function calls, parameter refs, overrides, callable references, constructor delegation, callers, data-class components/destructuring, enum entries, by-convention calls)
      • All 11 usage types covered: call sites (including through an overriding declaration and by-convention operator calls, box["key"]), in-body parameter references, overrides (project-wide), callable references (::foo), this(...)/super(...) constructor delegation, propagate-to-callers, data-class destructuring (val (a, b) = point, reordered to preserve each variable's binding), enum entries without a super call, and conflict detection (duplicate parameter names rejected)
      • Parameter reordering in the dialog (toolbar buttons + drag-and-drop); real Refactor → Undo Last Refactoring support through KotlinRefactoringTransaction, which commits every touched document or restores all of them after a write failure; a multi-hunk diff (TextRangeDiff) reformats only the actually-changed regions per file, not the whole file
      • Fixed a standalone-environment gap: shortenReferences() throws for any constructor after a structural parameter-list change (K2 can't resolve the constructor's FIR node post-replace, since this plugin's NoOpPomModel never fires a real out-of-block- modification notification) — both call sites now fall back to fully-qualified type names instead of aborting the refactoring
      • Fixed a K2 reference-resolution gap: a data-class destructuring entry's reference (KaFirDestructuringDeclarationReference) doesn't resolve through resolveToSymbol() at all — only through multiResolve(), which returns both the entry's own declaration and the constructor parameter it destructures
      • NetBeans adapter: KaChangeSignatureComputer (KotlinRefactoring); KotlinChangeSignaturePlugin / KotlinChangeSignatureUI (param table with reorder buttons + drag-and-drop) / KotlinChangeSignatureUsageSearchServiceImpl (whole-project usage scan backing the ported engine's ReferencesSearch calls) / TextRangeDiff in Nbm
    • E9.6+ — Enhanced Introduce Variable dialog: KotlinIntroduceVariableUI adds "Replace all occurrences" checkbox (default on), val/var radio, "Specify type explicitly" checkbox; carried on KotlinIntroduceVariableRefactoring (replaceAll, useVar, explicitType) and applied by KotlinIntroduceVariablePlugin.performChange()

    • E9.9 — Introduce Constant (Ctrl+Alt+C) — PR #108

      • IDEA source: introduceConstant/KotlinIntroduceConstantHandler.kt
      • Reuses most of KaIntroduceVariableComputer; only compile-time constant expressions (literals, arithmetic on literals) accepted, validated via K2 evaluate()
      • Inserts into companion object or top-level depending on context
      • Files: KaIntroduceConstantComputer, KotlinIntroduceConstant{Refactoring,Plugin,UI,Action}
    • E9.10 — Introduce Import Alias — PR #108

      • IDEA source: introduceImportAlias/KotlinIntroduceImportAliasHandler.kt
      • Target is a type reference inside an import statement: import pkg.Class → import pkg.Class as Alias, all FQN usages replaced with the alias
      • No IDEA keybinding (Refactor menu / Alt+Enter on import only)
      • Files: KaIntroduceImportAliasComputer, KotlinIntroduceImportAlias{Refactoring,Plugin,UI,Action}
    • E9.11 — Introduce Property (Ctrl+Alt+F) — PR #109

      • IDEA source: introduceProperty/KotlinIntroducePropertyHandler.kt
      • Target: expression → class property (not local val); destination combo (primary constructor param / class body / companion object), initializer vs getter, replace-all-occurrences checkbox
      • Files: KaIntroducePropertyComputer, KotlinIntroduceProperty{Refactoring,Plugin,UI,Action}
    • E9.12 — Introduce Type Alias (Ctrl+Alt+Shift+A) — PR #109

      • IDEA source: introduceTypeAlias/KotlinIntroduceTypeAliasHandler.kt
      • Target: type reference (not expression) → typealias Name = Type; visibility combo, replace-all-occurrences, and K2-backed same-file generic extraction with nested/qualified type-argument substitutions; star projections, local type parameters, class-body targets, expressions, and project-wide duplicate search remain unsupported
      • Files: KaIntroduceTypeAliasComputer, KotlinIntroduceTypeAlias{Refactoring,Plugin,UI,Action}
    • E9.19 — Copy Declaration (F5) — PR #109

      • IDEA source: copy/CopyKotlinDeclarationsHandler.kt
      • Duplicates a declaration into a target file without removing it from the source (simpler than Move — no source-side import/reference updates)
      • Files: KaCopyDeclarationComputer, KotlinCopyDeclaration{Refactoring,Plugin,UI}; hooks into NB's built-in Copy action (F5), no new Action class needed
      • The dialog selects a target source root, existing/new package, and target filename. Target creation/replacement is staged through KotlinRefactoringTransaction: failed copies roll back the target, and Refactor → Undo Last Refactoring removes a newly-created target or restores a pre-existing target's exact original text. Whole-file copies update the selected package and use IDEA's internal-usage retargeting pass before persistence.
    • E9.13 — Introduce Parameter (Ctrl+Alt+P) — PR #119

      • IDEA source ported verbatim: introduceParameter/IntroduceParameterDescriptor.kt (kotlin.refactorings.common) — its valVar/parametersToRemove/newArgumentValue logic is driven as-is, not reimplemented
      • KotlinFirIntroduceParameterHandler.kt (IDE action-system entry point, Editor/dialog/ inplace-introducer) is not ported; KaIntroduceParameterComputer hand-writes the caret/selection resolution and the mutation orchestration instead, reusing E9.8's ported KotlinMethodDescriptor/KotlinChangeInfo/KotlinParameterInfo/ KotlinChangeSignatureUsageProcessor the same way KaChangeSignatureComputer already does standalone
      • Target: expression inside a function/secondary-constructor body (or a class body/property initializer, targeting its primary constructor) → new parameter; every existing call site updated to pass the original expression explicitly; body occurrences (one or all, matched via K2SemanticMatcher) replaced by a reference to the new parameter
      • Dialog: name, type (editable combo pre-filled with the inferred type + supertypes), "replace all N occurrences" checkbox, "use default value" checkbox, target-scope combo when multiple enclosing declarations are available
      • Known simplifications vs. real IDEA (documented in KaIntroduceParameterComputer's class doc): a selection resolving to a local KtProperty is rejected as NotApplicable; a lambda-argument occurrence is always replaced positionally (no named-argument heuristic); context parameters are not tracked by the internal-usage scan (out of scope — this plugin's language version is capped below context parameters, see Key Versions); a KtClass target with no primary constructor yet is out of scope (no "add one from scratch" path)
      • NetBeans adapter: KaIntroduceParameterComputer (KotlinRefactoring); KotlinIntroduceParameter{Refactoring,Plugin,UI,Action} (Nbm). Every changed declaration and caller is staged through KotlinRefactoringTransaction, retaining hunk-only formatting while rolling every file back if any persistence step fails.
    • E9.14 — Introduce Functional Parameter (Ctrl+Alt+Shift+P)

      • Not a flag on E9.13's computer (that description didn't match real IDEA): real IDEA's KotlinFirIntroduceLambdaParameterHandler runs the Extract Function engine (ExtractionDataAnalyzer/Generator.generateDeclaration with ExtractionTarget.FAKE_LAMBDALIKE_FUNCTION) to compute which local variables/receiver the selection captures (these become the lambda's parameters), then drives the same IntroduceParameterDescriptor/KotlinChangeSignatureUsageProcessor pipeline E9.13 already uses. New file KaIntroduceFunctionalParameterComputer (KotlinRefactoring); uses targetParent itself (not an inner block) as ExtractionData.targetSibling — ported verbatim from KotlinFirIntroduceLambdaParameterHandler.invoke() — since the extracted code becomes a lambda literal living at each call site, not a nested local function, so targetParent's own parameters must be captured explicitly rather than closed over
      • Un-stubbed ExtractableCodeDescriptor.duplicates (KotlinRefactoring/pom.xml patch #13, previously emptyList() since E9.5/E9.6) to the real findDuplicates(): it was pure analysis code, stubbed only because it transitively pulled in a few genuinely IDE-heavy functions (highlight/preview/processDuplicates*, need Editor) sharing a file (duplicateUtil.kt) with two pure ones (processWeakMatch/getControlFlowIfMatched) that are needed — the file is now included with the IDE-heavy half stripped by patch #13. Verified no regression to E9.5/E9.6/E9.11 via a new KaExtractFunctionTest fixture (withDuplicate) exercising a previously-impossible duplicate-occurrence path; the one real behavior change (anchor-selection now considers duplicate locations, matching real IDEA) is non-corrupting since computeMinimalDiff's formatEndOffset already covers the shifted region for the existing post-edit reformat pass
      • Known simplifications vs. real IDEA (documented in the class doc): single-expression selection only (not a multi-statement block); an existing lambda-argument occurrence is not given IDEA's double-lambda wrap; the final parameter's type text in the signature may appear fully qualified (kotlin.Int vs Int) — a pre-existing characteristic of the shared E9.8 KotlinChangeSignatureUsageProcessor pipeline, not new to this feature; call-site lambda arguments are inserted positionally, not as an idiomatic trailing lambda
      • NetBeans adapter: KaIntroduceFunctionalParameterComputer (KotlinRefactoring); KotlinIntroduceFunctionalParameter{Refactoring,Plugin,UI,Action} (Nbm). Its declaration and caller writes use the same hunk-preserving transaction and all-or-rollback failure contract as Change Signature and Introduce Parameter.
      • layer.xml position 1175
    • E9.15 — Extract Interface — PR #121

      • IDEA source: extractClass/K2ExtractSuperRefactoring.kt.
      • Creates a new interface from selected members, adds : Interface to the class.
      • NetBeans dialog selects the interface name, members, source root, package, and target Kotlin file; source and target are committed through KotlinRefactoringTransaction, so failed writes roll both back and Undo Last Refactoring restores an existing target or removes a generated one.
    • E9.16 — Extract Superclass — PR #121

      • Reuses the E9.15 K2ExtractSuperRefactoring engine to create an abstract class.
      • Dialog additionally supports making selected members abstract and uses the same transactional source/target persistence and undo behavior as Extract Interface.
    • E9.17 — Pull Members Up (Ctrl+Alt+U)

      • Reuses the copied IDEA K2 PullUpProcessor and registered K2PullUpHelperFactory to move selected Kotlin declarations from a child class into a selected direct Kotlin superclass or interface.
      • Dialog supports cross-file targets, member selection, and a Make Abstract option; Preview Conflicts reports target-member collisions before NetBeans schedules a mutation.
      • The NetBeans apply element snapshots, formats, and restores both source documents for Undo Last Refactoring.
      • Current standalone conflict preview covers direct target-member collisions; IDEA's index-backed inheritor, visibility, and accidental-override checks remain unavailable until their project-search infrastructure is ported.
    • E9.18 — Push Members Down (Ctrl+Alt+O)

      • Reuses the copied IDEA K2 Push Down processor to move selected declarations from a superclass or interface into every direct Kotlin subclass in the related build scope.
      • Dialog supports member selection and a per-member Make Abstract option; the NetBeans apply element snapshots, formats, and restores every changed source/child document for Undo Last Refactoring.
      • Direct inheritors are discovered from writable K2 source files in the standalone session; project-index-only IDEA searches remain bridged by the standalone compatibility layer.

    Common file-layout template for every E9.x refactoring:

    KotlinRefactoring/src/main/kotlin/.../Ka*Computer.kt          — headless K2 analysis, sealed Outcome
    KotlinRefactoring/target/generated-sources/refactoring/       — IDEA sources, copied via pom.xml
    Nbm/src/main/kotlin/.../refactoring/Kotlin*Plugin.kt          — RefactoringPlugin (prepare → bag)
    Nbm/src/main/kotlin/.../refactoring/Kotlin*Refactoring.kt     — AbstractRefactoring carrier
    Nbm/src/main/java/.../refactoring/Kotlin*UI.java              — CustomRefactoringPanel + RefactoringUI
    Nbm/src/main/kotlin/.../refactoring/Kotlin*Action.kt          — BaseAction, opens the dialog
    layer.xml                                                      — Actions, Menu (position), keybindings
    

    Reusable IDEA infrastructure already vendored in generated-sources (no changes needed): K2SemanticMatcher (semantic-duplicate search), KotlinNameSuggester (name generation from type/context), K2ExtractableSubstringInfo (substring extraction), ExtractionData / ExtractionDataAnalyzer / Generator (Extract Function/Property).

    Target Refactor menu layout (layer.xml position, [x] = wired today):

    Rename                      Shift+F6          ~100   [x] E9.1
    Change Signature            Ctrl+F6            150   [x] E9.8
    Move                        F6                ~200   [x] E9.7
    Copy                        F5                ~250   [x] E9.19
    Safely Delete                Alt+Delete       ~500   [x] E9.2
    --- separator ---                              600
    Extract Function            Ctrl+Alt+M         700   [x] E9.5
    Extract Interface                               750   [x] E9.15
    Extract Superclass                              760   [x] E9.16
    --- separator ---                               900
    Introduce Variable          Ctrl+Alt+V        1000   [x] E9.6
    Introduce Constant          Ctrl+Alt+C        1050   [x] E9.9
    Introduce Import Alias                        1075   [x] E9.10
    Introduce Property          Ctrl+Alt+F        1100   [x] E9.11
    Introduce Type Alias        Ctrl+Alt+Shift+A  1125   [x] E9.12
    Introduce Parameter         Ctrl+Alt+P        1150   [x] E9.13
    Introduce Functional Param  Ctrl+Alt+Shift+P  1175   [x] E9.14
    --- separator ---                              1300
    Inline                      Ctrl+Alt+N        1400   [x] E9.3/E9.4
    Pull Members Up             Ctrl+Alt+U        1450   [x] E9.17
    Push Members Down           Ctrl+Alt+O        1500   [x] E9.18
    --- separator ---                              1550
    Undo Last Refactoring                          1600   [x] (Change Signature, Move Declaration, Extract, Introduce, Inline, Pull Up, and Push Down)
    Redo Last Refactoring                          1700
    

    Verification checklist for every E9.x refactoring:

    1. mvn package -DskipTests — builds everything
    2. mvn test -pl Nbm -Dtest=Ka<Feature>Test — unit tests
    3. Manual test in NetBeans: open file → invoke refactoring → check dialog → preview → apply → undo
    4. CHANGELOG bullet updated together with the code

    E9 is complete.

    • F5.1 — Inline Type Alias (Ctrl+Alt+N)

      • Reuses IDEA K2's TypeAliasUsageReplacementStrategy and compiled KotlinInlineTypeAliasProcessor; NetBeans deliberately owns the dialog, preview, transaction, and undo instead of invoking IDEA's processor lifecycle.
      • The unified Inline action resolves a type-alias declaration or usage; its NetBeans panel supports all occurrences, the invocation occurrence only, and retaining the declaration. K2-generated type substitutions/import changes are committed through KotlinRefactoringTransaction so Undo Last Refactoring restores every touched Kotlin document.
      • Portable standalone scope is Kotlin source files registered in the active session; Java, non-code, and project-index-only references remain unavailable.
    • F5.2 — Inline Anonymous Function / Lambda (Ctrl+Alt+N)

      • Reuses IDEA K2's KotlinInlineAnonymousFunctionProcessor for immediate-call recognition, LambdaToAnonymousFunctionUtil for K2-derived lambda signatures, and CodeInliner for the final substitution. NetBeans owns the UI, preview, transaction, and undo.
      • Standalone K2 needs a fresh session after IDEA converts a lambda to an anonymous fun: the new PSI otherwise has no FIR mapping. The adapter commits only the final text through KotlinRefactoringTransaction, so no intermediate source is persisted and Undo Last Refactoring restores the original document.
      • Supports immediately invoked Kotlin lambdas and anonymous functions. Non-invoked functions, Java/non-code/index-only references, and wider IDEA invocation/project-index cases remain unavailable.
    • F8 — Structural conversions (operator/function conversions)

      • Compiles the six IDEA K2 sources for the operator/function conversions into the new KotlinCodeInsightImpl reactor module: ReplaceCallWithBinaryOperatorInspection, ReplaceGetOrSetInspection, ReplaceContainsInspection (inspections-k2), ReplaceInvokeIntention, ReplaceCallWithUnaryOperatorIntention (intentions-k2), and RemoveEmptyParenthesesFromLambdaCallInspection (inspections-shared). The sources are copied from submodules/IntellijCommunity by maven-resources-plugin and compiled unchanged; the only patch is widening the three internal class inspections so the NetBeans layer can construct them.
      • KotlinFixesImpl was extended with the remaining code-insight/api applicable framework (KotlinApplicableInspectionBase, KotlinModCommandQuickFix, KotlinApplicableModCommandAction, ApplicabilityRange, ApplicableRangesProvider, ContextProvider) so those sources have something to compile against.
      • KaIdeaIntentionHint and KaIdeaInspectionHint drive the compiled actions by reflection (their getElementContext/createQuickFix/invoke/applyFix are protected), reusing KaModCommandFix's NoOpModPsiUpdater and PSI→document sync. KaStructuralConversionHints attaches each action to the PSI element the caret refers to, and KotlinHintsProvider.listOfK2Intentions registers them alongside the hand-written hints.
      • Covers a.plus(b) → a + b, a.get(i)/a.set(i, v) → a[i]/a[i] = v, a.contains(b) → b in a, a.invoke(b) → a(b), a.not()/a.unaryPlus() → !a/+a, and f() {} → f {}. The reverse directions (KaOperatorToFunctionIntention, KaConvertLambdaToReferenceIntention) stay hand-written: their IDEA counterparts drag in a much larger slice of code-insight.
  • E10 — J2K (Java→Kotlin) conversion

    • Compiles IDEA's real J2K sources (j2k/shared/src + j2k/k2/src) into the new KotlinJ2K reactor module with standalone stubs, the same pattern as KotlinRefactoring/KotlinFixesImpl. The K2 post-processing subset from code-insight/fixes-k2 was ported into KotlinFixesImpl.
    • Entry point: Refactor → Convert to Kotlin on a Java file. The confirmation dialog runs before anything is touched; the conversion then runs on a background thread as a headless NetBeans refactoring (JavaToKotlinRefactoring + JavaToKotlinPlugin + JavaToKotlinElement), so the sibling .kt creation, its content, and the .java removal are one transaction registered in Undo Last Refactoring. The .kt appears only after the conversion succeeds; a failure rolls everything back and leaves the Java file intact.
    • Conversion itself: NewJavaToKotlinConverter over the analysis session, K2 post-processing, and a final text-based formatting pass.
    • Standalone wiring in KotlinAnalysisAPISession: StandaloneKaModuleProvider (replaces the index-based IDE provider), the org.jetbrains.kotlin.j2kConverterExtension extension point with K2J2KConverterExtension, and the com.intellij.deepestSuperMethodsSearch extension point with a PSI-only executor — without them the engine throws "Missing extension point" on method symbols.
    • J2KTest is re-enabled as Java2KotlinConverterTest over the existing fixtures, now with K2 output (for example System.out.println shortens to println).
    • Unsupported: Java copy/paste conversion, IDEA's project-configuration prompts, unused-import detection during conversion, and editor-level Ctrl+Z of the conversion (use Undo Last Refactoring instead).
  • E11 — New Project with Kotlin group:

    • ProjectWizardPanel integration
    • Variants: Kotlin/JVM application, Kotlin/JVM library, Kotlin Script
  • E12 — Debugger: rewrite via reflection to bypass Friend-module restrictions (lowest priority)


Versioning

  • A1: stays 0.3.x, new Maven coordinates
  • A4 series: 0.4.x → 0.5.x (cleanup of bundled JARs)
  • B2–B6 (Kotlin 1.9.25 + IntelliJ 232 bump, FE1.0 preserved): 0.6.x
  • C1–C10 (K2 Analysis API migration, kotlin-compiler 2.0.21): 0.7.x ✓
  • D1–D7 (kotlin-compiler-ir-for-ide 2.3.21, analysis-api 2.3.21, platform 253): 0.8.x ✓
  • E1–E5 ✓ (hover, diagnostics, parameter info, intentions/quick-fixes, formatter settings UI): 0.9.x → 0.10.x → 0.11.x
  • E6–E12 (New Class wizard, Find Usages, Go to Declaration, Rename, J2K, New Project, Debugger): 0.11.x+
  • Major version 1.0.0: when feature parity with the IDEA plugin reached