# mojolint.rules

> A module of lint's API.

The rules. Each is one function over a file's logical lines and its recovered structure, returning `Finding`s. `RULES` is the table the CLI and the corpus harness read; add an entry and a branch in `run_rule` for L004.

## Structs

### `Finding`

```mojo
struct Finding
```

Implements: `Copyable`, `Movable`, `Writable`

Fields:

- `path: String`
- `line: Int`
- `col: Int`
- `rule: String`
- `message: String`

#### `write_to`

```mojo
def write_to(self, mut writer: T)
```

### `Rule`

```mojo
struct Rule
```

Implements: `Copyable`, `Movable`

Fields:

- `id: String`
- `name: String`
- `summary: String`

## Functions

### `rules`

```mojo
def rules() -> List[Rule]
```

Every rule, in the order they run.

### `check_l001`

```mojo
def check_l001(path: String, lines: List[Line], mod: Module, facts: Facts) -> List[Finding]
```

`Pointer(to=x)` erased to an untracked or opaque pointer, where either

- the line is a `return`: the untracked pointer leaves the function while
  `x` (a parameter or local) does not; or
- `x` is a `var` local of this function and is never mentioned again:
  Mojo destroys `x` at that last use, before anything reads the pointer.

An erased pointer passed as an argument to a call, from a parameter, is
fine — a parameter is alive for the whole call, joins included — which is
how the library's own typed `parallel_for` looks, and why it is silent.

With facts, the second case is decided by the compiler: the last
name-resolved use of `x`, and whether the line binds a value whose
resolved type is an untracked pointer or a struct wrapping one — so
`var ctx = Ctx.to(x)` is caught at the call, not inside the helper.

### `check_l002`

```mojo
def check_l002(path: String, lines: List[Line], mod: Module, facts: Facts) -> List[Finding]
```

A struct with `__deinit__`/`__del__` and an untracked pointer field, dereferenced as `local.field[]` from outside its methods.

`local.field[]` copies the pointer out and, if that is `local`'s last
use, the destructor runs between the copy and the deref. A method borrows
the whole struct for the call; so does `OwnedPointer.__getitem__`.

With facts, the field's type is the resolved one, the owners are every
local whose resolved type is the struct (however it was built), and the
deref must sit on the owner's last use.

### `check_l003`

```mojo
def check_l003(path: String, lines: List[Line], mod: Module, facts: Facts) -> List[Finding]
```

A plain store to shared state inside a task-shaped function.

Fires on `t.field = …` (typed shape) and `p[].field = …` (any shape). A
subscripted target such as `s.cells[i] = …` is taken to be a per-task
slot and left alone; atomics never appear on the left of `=`.

### `run_rule`

```mojo
def run_rule(id: String, path: String, lines: List[Line], mod: Module, facts: Facts) -> List[Finding]
```

### `lint_source`

```mojo
def lint_source(path: String, source: String) -> List[Finding]
```

Every finding for one file, sorted by line — text only, no compiler.

### `lint_with_facts`

```mojo
def lint_with_facts(path: String, source: String, facts: Facts) -> List[Finding]
```

Every finding for one file, sorted by line, using `facts` where the rules have a use for them (`collect_facts` fills them from the LSP).
