> ## Documentation Index
> Fetch the complete documentation index at: https://roe.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Entry points and roots

> How roe decides what code is reachable.

`roe dead-code` reports code that's unreachable from your solution's entry
points. Entry points are never flagged themselves, and reachability is
traced outward from them.

## What counts as an entry point

* `static Main` and top-level-statement files
* ASP.NET controllers (`*Controller` / `ControllerBase`) and their actions,
  `Startup` conventions
* Test methods and fixtures (`[Fact]`, `[Theory]`, `[Test]`, `[TestMethod]`, …)
* Any declaration carrying a non-inert attribute (`[HttpGet]`,
  `[JsonProperty]`, `[UsedImplicitly]`, custom markers — everything except
  `[Obsolete]`-class metadata)
* Reflection-scan contracts: implementations of a type used as a lone
  generic argument in a call (`GetExports<IImageProvider>()`,
  `AddHostedService<W>()`)
* Public API surface of NuGet-packable projects, of every non-test project
  when the workspace has no executable ("library mode"), and of any project
  named with `--library`/`libraryProjects` (a project consumed outside the
  workspace, e.g. a Unity project referencing the built DLL, regardless of
  what executables live alongside it)
* Declarations in generated files (`*.g.cs`, `*.Designer.cs`,
  `<auto-generated>` headers, `obj/`) — reference-only, never flagged

## Adding your own roots

When code is only reached in ways roe can't see — string-based reflection,
an external plugin host — declare it as a root with the `--root` flag or the
`roots` config field, using the symbol's fully-qualified name:

```bash theme={null}
roe dead-code --root App.Jobs.NightlyCleanupJob
```

```json roe.json theme={null}
{
  "roots": ["App.Jobs.NightlyCleanupJob"]
}
```

When a whole file is consumed in ways roe can't see — a plugin host loading
it by path, an external tool reading it directly — name the file with the
`entryPoints` config field instead of listing every symbol in it. Patterns
are globs resolved relative to the config file's directory (a trailing `/`
matches the whole directory); every declaration in a matching file becomes
a root, so the file and everything it references count as used:

```json roe.json theme={null}
{
  "entryPoints": ["Plugins/", "Jobs/**/*.cs"]
}
```

A pattern that matches no file at all is reported as a note, so a stale
path can't silently drop the protection it promised. See
[Configuration](/configuration#entry-point-files) for the full rules.

## How detection works

Under the hood, `roe dead-code` runs a five-step pipeline:

1. **Discover** — parses `.sln` and `.csproj` files and walks the source
   tree, gitignore-aware, harvesting `obj/` generated sources as
   reference-only inputs.
2. **Extract** — parses every `.cs` file in parallel with tree-sitter,
   collecting declarations and references.
3. **Resolve** — merges partial types and overloads into one symbol table;
   references resolve by namespace-aware, conservative name matching.
4. **Mark and sweep** — walks the reference graph outward from the entry
   points. A member only counts as used when its name is referenced from
   reachable code *and* its containing type is reachable.
5. **Report** — unreachable symbols become findings; a file whose every
   declaration is dead is reported once as a dead file.

The whole tool is tuned so that when in doubt, code is marked used — a
missed finding is cheap, a wrong one is a bug. See
[Known limitations](/limitations) for the cases that name-based, static
analysis can't see.
