diff --git a/CHANGELOG.md b/CHANGELOG.md index fb76d126..473f2625 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ Status of the `main` branch. Changes prior to the next official version change w * Language Servers: - Elixir (`elixir-tools/next-ls`): Fix deadlock in monorepo projects where `mix.exs` lives in a subdirectory. The server now searches immediate subdirectories when no `mix.exs` is found at the repository root. #1444 - Java (`eclipse.jdt.ls`): Add upstream JDTLS mode for offline / restricted-network use. Setting both `jdtls_path` and `lombok_path` in `ls_specific_settings.java` makes Serena use an existing upstream JDTLS installation (e.g. `brew install jdtls`) and the system JDK 21+, skipping the ~500 MB vscode-java VSIX, Gradle, and IntelliCode downloads. New related setting `java_home` lets the user override the JDK used to launch JDTLS. Default behavior unchanged — the JDTLS workspace hash is preserved bit-for-bit for users on the default route, so existing project caches are reused without a one-time reindex; the launcher path is mixed into the hash only when `jdtls_path` is set, isolating upstream installations from the default workspace. #1415 + - Java (eclipse.jdt.ls): Lombok-generated methods (getters/setters, builder(), equals/hashCode/toString, etc.) are now included in symbol-based tools (find_symbol, get_symbols_overview, edits). Added lombok_show_generated setting (default: on) to toggle this. Updated bundled vscode-java to 1.54.0-923. Issue #1432. - Add **Angular** (experimental) via a dual-server architecture: `@angular/language-server` (ngserver) handles standalone `.html` template files, while a companion `typescript-language-server` with `@angular/language-service` loaded as a tsserver plugin handles all `.ts` operations including inline templates. Provides type-aware navigation between templates and component classes. Requires Node.js, npm, and `@angular/core` installed in the project (`npm install` in the project root). Subsumes `typescript`+`html` for `.ts`/`.html` files when active; SCSS is not subsumed. - Add **HTML** (experimental) using `vscode-html-language-server` from the `vscode-langservers-extracted` npm package. Provides in-file element/id symbols via documentSymbol; cross-file references are not meaningful for HTML. Also used as a companion server by the Angular LS for plain HTML documentSymbol support. - Add **SCSS / Sass / CSS** (experimental) using [some-sass-language-server](https://github.com/wkillerud/some-sass). Handles `.scss`, `.sass`, and `.css` through one server, with full `@use`/`@forward` workspace-wide go-to-definition and find-references for variables, mixins, and functions across Sass files. The `.css` path uses the same `vscode-css-languageservice` engine that powers the standalone CSS LS; CSS feature toggles default off upstream and are flipped on at startup so symbols, hover, completion, and syntax-level diagnostics work for plain CSS as well. diff --git a/docs/02-usage/050_configuration.md b/docs/02-usage/050_configuration.md index 99388485..c1183b05 100644 --- a/docs/02-usage/050_configuration.md +++ b/docs/02-usage/050_configuration.md @@ -589,8 +589,9 @@ The following settings are supported for the Java language server: | `gradle_java_home` | `null` | Path to the JDK used by Gradle. When unset, Gradle uses the bundled JRE. | | `use_system_java_home` | `false` | Use the system's `JAVA_HOME` environment variable for JDTLS itself. Enable this if your project requires a specific JDK vendor or version for Gradle's JDK checks. | | `gradle_version` | `8.14.2` | (vscode-java mode only) Override the Gradle distribution version Serena downloads by default. | -| `vscode_java_version` | `1.42.0-561` | (vscode-java mode only) Override the bundled `vscode-java` runtime bundle version Serena downloads by default. | +| `vscode_java_version` | `1.54.0-923` | (vscode-java mode only) Override the bundled `vscode-java` runtime bundle version Serena downloads by default. | | `intellicode_version` | `1.2.30` | (vscode-java mode only) Override the IntelliCode VSIX version Serena downloads by default. | +| `lombok_show_generated` | `true` | Show Lombok-generated methods (`getX/setX`, `builder()`, `equals/hashCode/toString`, `withX`, fluent accessors) in `find_symbol`, `get_symbols_overview` and the symbol-edit tools. Set to `false` to restore the previous JDTLS default and hide the synthetic methods (e.g. when `@Data` classes pollute the outline with too many getters/setters). Requires JDTLS commit `b2d8952` / `vscode-java >= 1.53.0`; the bundled default already meets this. | | `jdtls_xmx` | `3G` | Maximum heap size for the JDTLS server JVM. | | `jdtls_xms` | `100m` | Initial heap size for the JDTLS server JVM. | | `intellicode_xmx` | `1G` | (vscode-java mode only) Maximum heap size for the IntelliCode embedded JVM. | @@ -613,7 +614,7 @@ Example: upstream-jdtls mode (offline / corporate network): ls_specific_settings: java: jdtls_path: "/opt/homebrew/Cellar/jdtls/1.50.0/libexec" - lombok_path: "/Users/me/.m2/repository/org/projectlombok/lombok/1.18.36/lombok-1.18.36.jar" + lombok_path: "/Users/me/.m2/repository/org/projectlombok/lombok/1.18.38/lombok-1.18.38.jar" # java_home: "/opt/homebrew/opt/openjdk@21" # optional ``` diff --git a/src/solidlsp/language_servers/eclipse_jdtls.py b/src/solidlsp/language_servers/eclipse_jdtls.py index 646174a5..5ab570a8 100644 --- a/src/solidlsp/language_servers/eclipse_jdtls.py +++ b/src/solidlsp/language_servers/eclipse_jdtls.py @@ -38,6 +38,7 @@ INTELLICODE_ALLOWED_HOSTS = ( "download.visualstudio.microsoft.com", ) + # Version pinning convention (read this before bumping anything below): # # INITIAL_* — the very first version we shipped runtime-dependency support for, paired with @@ -62,6 +63,22 @@ INTELLICODE_ALLOWED_HOSTS = ( # custom_settings and the matching cached subdir is picked up without re-downloading. # - INITIAL_* and DEFAULT_* hold identical literals when first introduced; they diverge on # the first DEFAULT_* bump and stay independent thereafter. +@dataclasses.dataclass(frozen=True) +class VsixResourcePaths: + """ + Paths to resources inside the vscode-java VSIX archive. These vary between vscode-java + releases (JRE bundle, Lombok jar, Equinox launcher all have versioned filenames inside + the VSIX), so we pin them per-version alongside SHA256 — bumping the VSIX version means + bumping these too. Without this, a user requesting a non-DEFAULT pinned version would + extract the right archive but then crash on FileNotFoundError trying to find the wrong + JRE / Lombok / launcher inside it. + """ + + jre_version: str # e.g. "21.0.7"; expanded to extension/jre/{jre_version}-{platform-suffix} + lombok_jar_basename: str # e.g. "lombok-1.18.36.jar" + equinox_launcher_basename: str # e.g. "org.eclipse.equinox.launcher_1.7.0.v20250424-1814.jar" + + INITIAL_VSCODE_JAVA_VERSION = "1.42.0-561" INITIAL_VSCODE_JAVA_SHA256_BY_PLATFORM = { "osx-arm64": "bc00c2699d4b8d478eb9a1621db9d6d3a12ea0dcc247a9cd8040e8ac19c03933", @@ -70,14 +87,26 @@ INITIAL_VSCODE_JAVA_SHA256_BY_PLATFORM = { "linux-x64": "7660b7b527be6fda46a917966b34d828e7416d5cc84287b29b88e7b99c1737f9", "win-x64": "ef195b45bd260976ad2e84618f4044b5d7248deed41d647573f0ee22c4233df3", } -DEFAULT_VSCODE_JAVA_VERSION = "1.42.0-561" +INITIAL_VSCODE_JAVA_PATHS = VsixResourcePaths( + jre_version="21.0.7", + lombok_jar_basename="lombok-1.18.36.jar", + equinox_launcher_basename="org.eclipse.equinox.launcher_1.7.0.v20250424-1814.jar", +) +# Bumped from 1.42.0-561 to surface Lombok-generated methods (#1432); brings JDTLS commit b2d8952 +# (java.symbols.includeGeneratedCode), JRE 21.0.10, Lombok 1.18.39 and Equinox launcher 1.7.100. +DEFAULT_VSCODE_JAVA_VERSION = "1.54.0-923" DEFAULT_VSCODE_JAVA_SHA256_BY_PLATFORM = { - "osx-arm64": "bc00c2699d4b8d478eb9a1621db9d6d3a12ea0dcc247a9cd8040e8ac19c03933", - "osx-x64": "03ae1db1a22c15561a620f1b722d6797d35d4faaa7c4666dbe6ca2715089852f", - "linux-arm64": "e15bc9b2a665d3453203402621b5441062aa41b0ec2d140661f439326fd248c1", - "linux-x64": "7660b7b527be6fda46a917966b34d828e7416d5cc84287b29b88e7b99c1737f9", - "win-x64": "ef195b45bd260976ad2e84618f4044b5d7248deed41d647573f0ee22c4233df3", + "osx-arm64": "c54c45cb0d2579d8e0a4ddeb24d4a9dd0b460d07d9366adea2b38a1da22a463c", + "osx-x64": "dfc98abc4e54165a78372e280242a039671729b1b03420608df3b10c6b629fb6", + "linux-arm64": "e2bb22c427d90da8dbb1afff72ff1e2dce38d50b76deb02d7bc313a330a1330c", + "linux-x64": "9d4b15da54e25a0192f9bac073f086c015397d3676623b68dbf83a5dbaf5132b", + "win-x64": "66f3914987edeccfee8a2558470e0fde4f8c4154232ff4baa5d73373ebc819d4", } +DEFAULT_VSCODE_JAVA_PATHS = VsixResourcePaths( + jre_version="21.0.10", + lombok_jar_basename="lombok-1.18.39-4050.jar", + equinox_launcher_basename="org.eclipse.equinox.launcher_1.7.100.v20251111-0406.jar", +) INITIAL_INTELLICODE_VERSION = "1.2.30" INITIAL_INTELLICODE_SHA256 = "7f61a7f96d101cdf230f96821be3fddd8f890ebfefb3695d18beee43004ae251" @@ -156,8 +185,16 @@ class EclipseJDTLS(SolidLanguageServer): - jdtls_xms: Initial heap size for the JDTLS server JVM (default: "100m") - intellicode_xmx: Maximum heap size for the IntelliCode embedded JVM (default: "1G") - intellicode_xms: Initial heap size for the IntelliCode embedded JVM (default: "100m") + - lombok_show_generated: Show Lombok-generated methods (getX/setX/builder()/...) in document + symbols by sending java.symbols.includeGeneratedCode=true to JDTLS (default: true). + Set to false for @Data-heavy projects where the extra getters/setters are noise. + Requires JDTLS commit b2d8952+ (vscode-java >= 1.53.0); older servers ignore the + key silently. See eclipse-jdtls/eclipse.jdt.ls#3706 and serena #1432. - gradle_version: Override the pinned Gradle distribution version downloaded by Serena - - vscode_java_version: Override the pinned vscode-java runtime bundle version downloaded by Serena + - vscode_java_version: Override the pinned vscode-java runtime bundle version downloaded by Serena. + Pinned versions: "1.54.0-923" (default) and "1.42.0-561" (legacy / initial). Other versions + are not supported in default VSIX mode (the resource paths inside the archive change between + releases); use upstream-jdtls mode for arbitrary versions. - intellicode_version: Override the pinned IntelliCode VSIX version downloaded by Serena Example configuration for upstream JDTLS mode (no downloads, suitable for offline/corporate): @@ -184,8 +221,9 @@ class EclipseJDTLS(SolidLanguageServer): jdtls_xms: "100m" # initial heap size for the JDTLS server JVM intellicode_xmx: "1G" # maximum heap size for the IntelliCode embedded JVM intellicode_xms: "100m" # initial heap size for the IntelliCode embedded JVM + lombok_show_generated: true # show Lombok-generated methods in document symbols (default true) gradle_version: "8.14.2" - vscode_java_version: "1.42.0-561" + vscode_java_version: "1.54.0-923" # also accepts pinned legacy "1.42.0-561" intellicode_version: "1.2.30" ``` """ @@ -305,6 +343,23 @@ class EclipseJDTLS(SolidLanguageServer): return DEFAULT_INTELLICODE_SHA256 return None + # Resolve internal VSIX paths (JRE / Lombok / launcher filenames). For pinned versions + # these are known; for any other user-supplied version we bail out — guessing would + # silently produce broken paths at JDTLS launch time, which is a worse UX than failing + # fast here with a pointer to upstream-JDTLS mode (which doesn't need pinned paths). + if vscode_java_version == INITIAL_VSCODE_JAVA_VERSION: + vsix_paths = INITIAL_VSCODE_JAVA_PATHS + elif vscode_java_version == DEFAULT_VSCODE_JAVA_VERSION: + vsix_paths = DEFAULT_VSCODE_JAVA_PATHS + else: + raise SolidLSPException( + f"Resource paths inside the vscode-java {vscode_java_version} VSIX are not pinned in serena " + f"(known: {INITIAL_VSCODE_JAVA_VERSION}, {DEFAULT_VSCODE_JAVA_VERSION}). " + f"Either remove the 'vscode_java_version' override (defaults to {DEFAULT_VSCODE_JAVA_VERSION}), " + f"or use upstream JDTLS mode by setting both 'jdtls_path' and 'lombok_path' in " + f"ls_specific_settings.java (no pinning required)." + ) + runtime_dependencies: dict[str, dict[str, dict[str, object]]] = { "gradle": { "platform-agnostic": { @@ -329,10 +384,10 @@ class EclipseJDTLS(SolidLanguageServer): "relative_extraction_path": vscode_java_dirname, "sha256": vscode_java_sha("osx-arm64"), "allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS, - "jre_home_path": "extension/jre/21.0.7-macosx-aarch64", - "jre_path": "extension/jre/21.0.7-macosx-aarch64/bin/java", - "lombok_jar_path": "extension/lombok/lombok-1.18.36.jar", - "jdtls_launcher_jar_path": "extension/server/plugins/org.eclipse.equinox.launcher_1.7.0.v20250424-1814.jar", + "jre_home_path": f"extension/jre/{vsix_paths.jre_version}-macosx-aarch64", + "jre_path": f"extension/jre/{vsix_paths.jre_version}-macosx-aarch64/bin/java", + "lombok_jar_path": f"extension/lombok/{vsix_paths.lombok_jar_basename}", + "jdtls_launcher_jar_path": f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}", "jdtls_readonly_config_path": "extension/server/config_mac_arm", }, "osx-x64": { @@ -341,10 +396,10 @@ class EclipseJDTLS(SolidLanguageServer): "relative_extraction_path": vscode_java_dirname, "sha256": vscode_java_sha("osx-x64"), "allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS, - "jre_home_path": "extension/jre/21.0.7-macosx-x86_64", - "jre_path": "extension/jre/21.0.7-macosx-x86_64/bin/java", - "lombok_jar_path": "extension/lombok/lombok-1.18.36.jar", - "jdtls_launcher_jar_path": "extension/server/plugins/org.eclipse.equinox.launcher_1.7.0.v20250424-1814.jar", + "jre_home_path": f"extension/jre/{vsix_paths.jre_version}-macosx-x86_64", + "jre_path": f"extension/jre/{vsix_paths.jre_version}-macosx-x86_64/bin/java", + "lombok_jar_path": f"extension/lombok/{vsix_paths.lombok_jar_basename}", + "jdtls_launcher_jar_path": f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}", "jdtls_readonly_config_path": "extension/server/config_mac", }, "linux-arm64": { @@ -353,10 +408,10 @@ class EclipseJDTLS(SolidLanguageServer): "relative_extraction_path": vscode_java_dirname, "sha256": vscode_java_sha("linux-arm64"), "allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS, - "jre_home_path": "extension/jre/21.0.7-linux-aarch64", - "jre_path": "extension/jre/21.0.7-linux-aarch64/bin/java", - "lombok_jar_path": "extension/lombok/lombok-1.18.36.jar", - "jdtls_launcher_jar_path": "extension/server/plugins/org.eclipse.equinox.launcher_1.7.0.v20250424-1814.jar", + "jre_home_path": f"extension/jre/{vsix_paths.jre_version}-linux-aarch64", + "jre_path": f"extension/jre/{vsix_paths.jre_version}-linux-aarch64/bin/java", + "lombok_jar_path": f"extension/lombok/{vsix_paths.lombok_jar_basename}", + "jdtls_launcher_jar_path": f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}", "jdtls_readonly_config_path": "extension/server/config_linux_arm", }, "linux-x64": { @@ -365,10 +420,10 @@ class EclipseJDTLS(SolidLanguageServer): "relative_extraction_path": vscode_java_dirname, "sha256": vscode_java_sha("linux-x64"), "allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS, - "jre_home_path": "extension/jre/21.0.7-linux-x86_64", - "jre_path": "extension/jre/21.0.7-linux-x86_64/bin/java", - "lombok_jar_path": "extension/lombok/lombok-1.18.36.jar", - "jdtls_launcher_jar_path": "extension/server/plugins/org.eclipse.equinox.launcher_1.7.0.v20250424-1814.jar", + "jre_home_path": f"extension/jre/{vsix_paths.jre_version}-linux-x86_64", + "jre_path": f"extension/jre/{vsix_paths.jre_version}-linux-x86_64/bin/java", + "lombok_jar_path": f"extension/lombok/{vsix_paths.lombok_jar_basename}", + "jdtls_launcher_jar_path": f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}", "jdtls_readonly_config_path": "extension/server/config_linux", }, "win-x64": { @@ -377,10 +432,10 @@ class EclipseJDTLS(SolidLanguageServer): "relative_extraction_path": vscode_java_dirname, "sha256": vscode_java_sha("win-x64"), "allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS, - "jre_home_path": "extension/jre/21.0.7-win32-x86_64", - "jre_path": "extension/jre/21.0.7-win32-x86_64/bin/java.exe", - "lombok_jar_path": "extension/lombok/lombok-1.18.36.jar", - "jdtls_launcher_jar_path": "extension/server/plugins/org.eclipse.equinox.launcher_1.7.0.v20250424-1814.jar", + "jre_home_path": f"extension/jre/{vsix_paths.jre_version}-win32-x86_64", + "jre_path": f"extension/jre/{vsix_paths.jre_version}-win32-x86_64/bin/java.exe", + "lombok_jar_path": f"extension/lombok/{vsix_paths.lombok_jar_basename}", + "jdtls_launcher_jar_path": f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}", "jdtls_readonly_config_path": "extension/server/config_win", }, }, @@ -883,6 +938,15 @@ class EclipseJDTLS(SolidLanguageServer): intellicode_xmx = self._custom_settings.get("intellicode_xmx", "1G") intellicode_xms = self._custom_settings.get("intellicode_xms", "100m") + # Lombok-generated symbols (getX/setX/builder()/equals/hashCode/toString/...): JDTLS filters + # these out of documentSymbol results by default. Without them, find_symbol/get_symbols_overview + # return only user-written sources, which breaks navigation around @Data/@Builder/@Getter/@Setter + # classes. Default to True so agentic workflows can find_symbol -> replace_symbol_body on generated + # members. Requires JDTLS commit b2d8952 or newer (vscode-java >= 1.53.0, or upstream JDTLS + # snapshot after 2026-02-24); older servers ignore the unknown preference key silently. + # See eclipse-jdtls/eclipse.jdt.ls#3706. + lombok_show_generated = self._custom_settings.get("lombok_show_generated", True) + # Gradle wrapper: default to False to preserve existing behaviour gradle_wrapper_enabled = self._custom_settings.get("gradle_wrapper_enabled", False) log.info( @@ -1096,9 +1160,10 @@ class EclipseJDTLS(SolidLanguageServer): "defaultMojoExecutionAction": "ignore", }, "workspaceCacheLimit": 90, - "runtimes": [ - {"name": "JavaSE-21", "path": "static/vscode-java/extension/jre/21.0.7-linux-x86_64", "default": True} - ], + # Placeholder; the real `runtimes` array is overwritten below from + # self.runtime_dependency_paths.jre_home_path (works for both default + # VSIX mode and upstream-jdtls mode, which uses the system JDK). + "runtimes": [], }, "trace": {"server": "verbose"}, "import": { @@ -1162,7 +1227,11 @@ class EclipseJDTLS(SolidLanguageServer): "references": {"includeAccessors": True, "includeDecompiledSources": True}, "typeHierarchy": {"lazyLoad": False}, "settings": {"url": None}, - "symbols": {"includeSourceMethodDeclarations": False}, + "symbols": { + "includeSourceMethodDeclarations": False, + # Surface Lombok-generated methods in document symbols (#1432). + "includeGeneratedCode": lombok_show_generated, + }, "inlayHints": {"parameterNames": {"enabled": "literals", "exclusions": []}}, "codeAction": {"sortMembers": {"avoidVolatileChanges": True}}, "compile": { diff --git a/test/resources/repos/java/test_repo/pom.xml b/test/resources/repos/java/test_repo/pom.xml index 672f990e..facb5368 100644 --- a/test/resources/repos/java/test_repo/pom.xml +++ b/test/resources/repos/java/test_repo/pom.xml @@ -11,8 +11,18 @@ 21 21 3.13.0 + 1.18.38 - + + + + org.projectlombok + lombok + ${lombok.version} + provided + + + @@ -22,6 +32,13 @@ 21 21 + + + org.projectlombok + lombok + ${lombok.version} + + diff --git a/test/resources/repos/java/test_repo/src/main/java/test_repo/DefaultGreeter.java b/test/resources/repos/java/test_repo/src/main/java/test_repo/DefaultGreeter.java new file mode 100644 index 00000000..8ed25b1a --- /dev/null +++ b/test/resources/repos/java/test_repo/src/main/java/test_repo/DefaultGreeter.java @@ -0,0 +1,13 @@ +package test_repo; + +class DefaultGreeter implements LombokModel.Greeter { + @Override + public String greet() { + return "hi"; + } + + @Override + public String farewell() { + return "bye"; + } +} diff --git a/test/resources/repos/java/test_repo/src/main/java/test_repo/FluentLombokModel.java b/test/resources/repos/java/test_repo/src/main/java/test_repo/FluentLombokModel.java new file mode 100644 index 00000000..8b448707 --- /dev/null +++ b/test/resources/repos/java/test_repo/src/main/java/test_repo/FluentLombokModel.java @@ -0,0 +1,14 @@ +package test_repo; + +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +/** Verifies prefix-stripped fluent accessors generated by @Accessors(fluent=true). */ +@Getter +@Setter +@Accessors(fluent = true) +public class FluentLombokModel { + private String host; + private String tag; +} diff --git a/test/resources/repos/java/test_repo/src/main/java/test_repo/LombokModel.java b/test/resources/repos/java/test_repo/src/main/java/test_repo/LombokModel.java new file mode 100644 index 00000000..f003d51a --- /dev/null +++ b/test/resources/repos/java/test_repo/src/main/java/test_repo/LombokModel.java @@ -0,0 +1,27 @@ +package test_repo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.With; +import lombok.experimental.Delegate; + +@Data +@Builder(toBuilder = true) +@With +@AllArgsConstructor +@NoArgsConstructor +public class LombokModel { + private String name; + private int age; + + /** Lombok @Delegate forwards every method of Greeter to delegate.* (covers @Delegate generation). */ + public interface Greeter { + String greet(); + String farewell(); + } + + @Delegate + private final Greeter delegate = new DefaultGreeter(); +} diff --git a/test/solidlsp/java/test_java_basic.py b/test/solidlsp/java/test_java_basic.py index 4c50c3c4..b9b78d84 100644 --- a/test/solidlsp/java/test_java_basic.py +++ b/test/solidlsp/java/test_java_basic.py @@ -96,3 +96,55 @@ class TestJavaLanguageServer: f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}", pytrace=False, ) + + @pytest.mark.parametrize("language_server", [Language.JAVA], indirect=True) + def test_lombok_generated_methods_visible_by_default(self, language_server: SolidLanguageServer) -> None: + """Generated Lombok methods must appear in document symbols across the common annotations. + + Default `lombok_show_generated=True` sends `java.symbols.includeGeneratedCode=true` to JDTLS, + which disables the SourceMethod-isGenerated filter in DocumentSymbolHandler. Without it, + find_symbol/get_symbols_overview cannot reach Lombok-synthesised methods at all (#1432). + Covers @Data, @Builder(toBuilder=true), @With, @AllArgsConstructor, @NoArgsConstructor, + @Delegate and @Accessors(fluent=true) — every method-generating annotation listed in the + issue plus fluent prefix-stripped accessors and @Delegate forwarders. + """ + + def _names_by_kind(doc, kind: int) -> set[str]: + return {sym.get("name") for sym in doc.get_all_symbols_and_roots()[0] if sym.get("kind") == kind} + + SYMBOL_KIND_CLASS = 5 + SYMBOL_KIND_METHOD = 6 + SYMBOL_KIND_CONSTRUCTOR = 9 + + # ---- LombokModel: @Data + @Builder(toBuilder=true) + @With + ctors + @Delegate ------- + lombok_path = os.path.join("src", "main", "java", "test_repo", "LombokModel.java") + lombok_doc = language_server.request_document_symbols(lombok_path) + + lombok_methods = _names_by_kind(lombok_doc, SYMBOL_KIND_METHOD) + # @Data getters/setters (prefixed) + canonical Object overrides + for expected in ("getName", "getAge", "setName", "setAge", "equals", "hashCode", "toString"): + assert expected in lombok_methods, f"@Data did not surface {expected!r}; got: {sorted(lombok_methods)}" + # @Builder(toBuilder=true): static factory + instance toBuilder + inner build() + for expected in ("builder", "toBuilder", "build"): + assert expected in lombok_methods, f"@Builder did not surface {expected!r}; got: {sorted(lombok_methods)}" + # @With: copy-with methods + for expected in ("withName", "withAge"): + assert expected in lombok_methods, f"@With did not surface {expected!r}; got: {sorted(lombok_methods)}" + # @Delegate: forwarder methods for every method of the delegate target + for expected in ("greet", "farewell"): + assert expected in lombok_methods, f"@Delegate did not surface forwarder {expected!r}; got: {sorted(lombok_methods)}" + + # @Builder generates an inner builder class + lombok_classes = _names_by_kind(lombok_doc, SYMBOL_KIND_CLASS) + assert "LombokModelBuilder" in lombok_classes, f"@Builder inner class missing; got: {sorted(lombok_classes)}" + + # @AllArgsConstructor + @NoArgsConstructor surface as ctor symbols (kind=9) + lombok_ctors = _names_by_kind(lombok_doc, SYMBOL_KIND_CONSTRUCTOR) + assert "LombokModel" in lombok_ctors, f"Lombok ctors missing; got ctors {sorted(lombok_ctors)}" + + # ---- FluentLombokModel: @Accessors(fluent=true) - prefix-stripped accessors --------- + fluent_path = os.path.join("src", "main", "java", "test_repo", "FluentLombokModel.java") + fluent_doc = language_server.request_document_symbols(fluent_path) + fluent_methods = _names_by_kind(fluent_doc, SYMBOL_KIND_METHOD) + for expected in ("host", "tag"): + assert expected in fluent_methods, f"@Accessors(fluent=true) did not surface {expected!r}; got: {sorted(fluent_methods)}"