CatchMe

Where does this exception
actually get caught?

Editors already highlight try/catch pairs inside one function. CatchMe follows an exception across function boundaries — through every caller — to the handler that really catches it.

Releases

Two questions, answered from the editor

01

Where can this be caught?

Right-click a throw and see every handler it can reach — including handlers in callers, after it escapes the current function.

02

What if I threw one here?

Right-click anywhere, pick an exception type, and see where it would land. No code edits, no debugger, no rebuild.

The whole path, not just the destination

Results group by where the exception ends up, with the call chain that reaches each one underneath. Every hop shows where it was called from and jumps straight there.

▾ 🔥 IOException 2 destinations · 3 paths ▾ ✓ catch (IOException e) Service.java:88 · definite 🔥 throw new IOException(…) Repo.java:42 Repo.load() called at Service.java:71 catch (IOException e) Service.java:88 ▸ ~ catch (Exception e) Api.java:23 · possible ▸ ⛔ uncaught — no caller found 1 path

Chains that converge on one handler collapse into a single destination. Library frames fold away. A search stopped by the depth limit ends in an expand further action rather than pretending it finished.

Honest about what it knows

Static exception analysis cannot be exact in the presence of virtual dispatch, lambdas, reflection or dynamic typing. CatchMe never pretends otherwise — every result is labelled.

definite
The handler certainly applies, proven against a real type hierarchy.
~ possible
Approximate — reached through virtual dispatch, or the language offers no type information.

A chain is rated by its weakest hop: one approximate step makes the whole route possible, even when the final type match is exact. A destination is rated by its best route, because reachability asks whether any chain gets there. A backend without real type information is structurally prevented from ever claiming definite.

How it works

Exception semantics differ enormously between languages, but “who calls this function?” does not. CatchMe splits along exactly that line: a language-agnostic core owns the interprocedural walk — running on standard LSP Call Hierarchy — while pluggable providers own language semantics.

Deep providers

Java runs Eclipse JDT inside the language server, so it has real type bindings: IOException matched by catch (Exception e) resolves as definite.

Generic provider

Any brace-style language gets a syntactic baseline with no extra setup — answering possible, never more.

Adding a language means writing a provider, not touching the core. The contract is published as @leplusorg/catchme-api, with a conformance suite to check an implementation against.

Requirements

Java
Language Support for Java by Red Hat, running in Standard mode.
Other languages
The language's own extension, if it implements LSP Call Hierarchy.

Red Hat's Java extension is deliberately not a hard dependency, so you can install CatchMe without it and still use every other language.

Get involved

CatchMe is Apache-2.0 licensed and developed in the open.

Found a bug?

Open an issue — there are templates for bug reports, feature requests and questions. Existing reports are in the issue tracker.

Want to contribute?

The contributing guide covers the build, the test layers and how changes get reviewed.

Adding a language?

Providers plug in from outside the extension. Start with the provider API and check your implementation against the conformance suite.

Security issue?

Please follow the security policy rather than filing a public issue.