Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ Status of the `main` branch. Changes prior to the next official version change w
- Fix: Host validation required a local host regardless of the listen address (regression introduced in v1.5.2),
preventing remote connections

* JetBrains:
- Add new tool `jet_brains_find_unused_code`: reports code symbols (classes, methods, fields, ...) declared in a
file that have no references in the project — likely-dead code (usage-based heuristic via the IDE's reference
search). Requires Serena JetBrains plugin version 2023.2.17+.

# v1.5.3 (2026-05-26)

Add meta-data for the GitHub MCP registry
Expand Down
14 changes: 14 additions & 0 deletions src/serena/jetbrains/jetbrains_plugin_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,20 @@ def find_implementations(self, relative_path: str, name_path: str, include_quick
self._postprocess_symbol_collection_response(symbol_collection)
return symbol_collection

def find_unused_code(self, relative_path: str, include_quick_info: bool = False) -> jb.SymbolCollectionResponse:
"""
Finds code symbols (classes, methods, fields, ...) declared in the given file that have no references
anywhere in the project, i.e. code that is likely unused.

:param relative_path: the relative path to the file to analyze for unused code
:param include_quick_info: whether to include quick info (typically the signature) for each unused symbol
"""
self._require_version_at_least(2023, 2, 17)
request_data = {"relativePath": relative_path, "includeQuickInfo": include_quick_info}
symbol_collection = cast(jb.SymbolCollectionResponse, self._make_request("POST", "/findUnusedCode", request_data))
self._postprocess_symbol_collection_response(symbol_collection)
return symbol_collection

def debug_eval(self, repl_key: str, expression: str) -> dict[str, Any]:
"""
Evaluates a Groovy expression in the persistent debug REPL.
Expand Down
3 changes: 3 additions & 0 deletions src/serena/resources/config/internal_modes/jetbrains.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ prompt: |
* `jet_brains_find_referencing_symbols` replaces `find_referencing_symbols`
* `jet_brains_get_symbols_overview` replaces `get_symbols_overview`
* `jet_brains_rename` replaces `rename_symbol`
In addition, `jet_brains_find_unused_code` reports code symbols in a file that have no references in the
project (a usage-based heuristic for finding likely-dead code).
excluded_tools:
- find_symbol
- find_referencing_symbols
Expand All @@ -32,3 +34,4 @@ included_optional_tools:
- serena_info
- jet_brains_run_inspections
- jet_brains_list_inspections
- jet_brains_find_unused_code
42 changes: 42 additions & 0 deletions src/serena/tools/jetbrains_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -668,3 +668,45 @@ def apply(
)
result = self._to_json(response_dict)
return self._limit_length(result, max_answer_chars)


class JetBrainsFindUnusedCodeTool(Tool, ToolMarkerSymbolicRead, ToolMarkerOptional, ToolMarkerBeta):
"""
Finds likely-unused code symbols (classes, methods, fields, ...) in a file using the JetBrains backend
"""

symbol_dict_grouper = JetBrainsSymbolDictGrouper(["relative_path", "type"], ["type"], collapse_singleton=True)

def apply(
self,
relative_path: str,
include_quick_info: bool = False,
max_answer_chars: int = -1,
) -> str:
"""
Finds code symbols (classes, methods, fields, etc.) declared in the given file that have no references
anywhere in the project, i.e. code that is likely unused and may be safe to remove.
This is a usage-based heuristic computed via the IDE's reference search: entry points (e.g. main methods,
public API that is consumed outside the project) and reflective/framework usages are NOT accounted for, and
transitively dead code (a private member used only by other dead code) is not reported. Review results
before deleting anything.

:param relative_path: the relative path to the file to analyze for unused code.
:param include_quick_info: whether to include quick info (typically the signature) for each unused symbol.
:param max_answer_chars: max characters for the result (-1 for default). If exceeded, no content/a shortened
result is returned.
:return: the unused symbols grouped by file and type; a message stating that none were found if the file has
no unused symbols.
"""
relative_path = self._sanitize_input_param(relative_path)
with JetBrainsPluginClient.from_project(self.project) as client:
response_dict = client.find_unused_code(
relative_path=relative_path,
include_quick_info=include_quick_info,
)
symbols = response_dict["symbols"]
if not symbols:
return f"No unused code symbols found in {relative_path}."
grouped = self.symbol_dict_grouper.group(symbols)
result = self._to_json(grouped)
return self._limit_length(result, max_answer_chars)
Loading