async-rust-lsp 0.2.2

LSP server that detects tokio::sync::Mutex guards held across .await points — a pattern clippy misses
Documentation
# async-rust-lsp

A standalone LSP server that provides real-time diagnostics for async Rust antipatterns — focusing on patterns that clippy and rust-analyzer miss.

## Problem

Existing Rust tooling has a blind spot for tokio-specific async antipatterns:

- **clippy** only checks `std::sync::Mutex` across `.await`, not `tokio::sync::Mutex`
- **rust-analyzer** has no plugin system for custom diagnostics
- **Runtime tools** (tokio-console) only help during execution, not during editing

This LSP fills the gap with real-time editor feedback for async lock patterns.

## Current rules

### `async-rust/mutex-across-await`

Warns when `tokio::sync::Mutex` or `RwLock` guards are held across `.await` points — a pattern that can deadlock under tokio's cooperative scheduling.

```rust
// BAD — guard lives across the await
let guard = mutex.lock().await;
do_something(&guard);
some_future.await; // WARNING: deadlock risk

// OK — guard scoped before the await
let value = {
    let guard = mutex.lock().await;
    guard.clone()
};
some_future.await; // fine
```

The rule tracks guard liveness through:
- `drop(guard)` calls (including inside conditional branches)
- `let` shadowing that kills the guard binding
- Block scoping (guard dropped at end of block)

## Installation

```bash
cargo install --git https://github.com/rgbkrk/async-rust-lsp
```

Or build from source:

```bash
git clone https://github.com/rgbkrk/async-rust-lsp
cd async-rust-lsp
cargo build --release
# binary at ./target/release/async-rust-lsp
```

## Editor setup

### Neovim (nvim-lspconfig)

```lua
local lspconfig = require('lspconfig')
local configs = require('lspconfig.configs')

if not configs.async_rust_lsp then
  configs.async_rust_lsp = {
    default_config = {
      cmd = { 'async-rust-lsp' },
      filetypes = { 'rust' },
      root_dir = lspconfig.util.root_pattern('Cargo.toml'),
    },
  }
end

lspconfig.async_rust_lsp.setup {}
```

### VS Code

Use a generic LSP client extension and add to `.vscode/settings.json`:

```json
{
  "lsp-client.servers": [
    {
      "name": "async-rust-lsp",
      "command": "async-rust-lsp",
      "filetypes": ["rust"]
    }
  ]
}
```

### Zed

Add to `~/.config/zed/settings.json`:

```json
{
  "lsp": {
    "async-rust-lsp": {
      "binary": {
        "path": "async-rust-lsp"
      }
    }
  }
}
```

### Claude Code

```bash
claude lsp add --name async-rust-lsp --command async-rust-lsp
```

Diagnostics appear automatically in Claude's context when editing `.rs` files.

## Logging

The server logs to `$TMPDIR/async-rust-lsp.log` (never stdout/stderr, which are reserved for LSP stdio protocol).

```bash
tail -f "$TMPDIR/async-rust-lsp.log"
RUST_LOG=debug async-rust-lsp  # verbose logging
```

## Architecture

```
┌─────────────┐    LSP/stdio    ┌──────────────────┐
│   Editor    │ <─────────────> │  async-rust-lsp  │
│ (or Claude) │                 │                  │
└─────────────┘                 │  tree-sitter-rust│
                                │  + custom rules  │
                                └──────────────────┘
```

Built with:
- [`tower-lsp`]https://github.com/ebkalderon/tower-lsp — async LSP framework
- [`tree-sitter-rust`]https://github.com/tree-sitter/tree-sitter-rust — incremental Rust parser

## Origin

Born from a real deadlock in the [nteract desktop](https://github.com/nteract/desktop) daemon. See [nteract/desktop#1614](https://github.com/nteract/desktop/pull/1614). The gap in static analysis for tokio async patterns is well-known but no one has filled it with an LSP yet.

## License

MIT