A static analyzer for Java, C, C++, and Objective-C
# AGENTS.md
This file provides guidance to Open Code / Codex / Claude Code (claude.ai/code) when working with code in this repository.
## What is Infer?
Infer is a multi-language static analysis tool developed by Meta. It detects bugs in Java, C, C++, Objective-C, Erlang, Hack, Python, Rust, Swift, and C# code. The primary implementation language is OCaml.
## Build Commands
All build commands run from the repository root. You must have run `./build-infer.sh` and `make devsetup` initially.
| Command | Purpose |
| -------------------------------- | -------------------------------------------------------------------- |
| `make -j` | Full native build (default `dev` mode, warnings are fatal) |
| `make -j BUILD_MODE=dev-noerror` | Build ignoring warnings |
| `make -j -C infer/src check` | Type-check only (fastest iteration cycle, requires prior full build) |
| `make -j -C infer/src byte` | Bytecode build (for testing changes quickly) |
| `make opt` | Optimized build with flambda |
| `make fmt` | Format changed OCaml files with ocamlformat |
| `make fmt_all` | Format all OCaml files |
## Testing
| Command | Purpose |
| ----------------------------------------------------------- | ------------------------------------------------------ |
| `make -j 4 test` | Run all tests (adjust parallelism to your cores) |
| `make -j test_build` | Verify build has no warnings |
| `make test-replace` | Update expected test outputs after intentional changes |
| `make direct_{lang}_{analyzer}_test` | Run a single test suite (rebuilds infer first) |
| `make -C infer/tests/codetoanalyze/{lang}/{analyzer}/ test` | Run a single test suite (assumes infer is up-to-date) |
| `make ocaml_unit_test` | Run OCaml unit tests only |
| `make swift_tests` | Run Swift tests (separate from main `test` target) |
Direct test names follow the pattern `{lang}_{analyzer}`, e.g., `direct_java_pulse_test`, `direct_cpp_pulse_test`, `direct_c_frontend_test`. These are defined in the `DIRECT_TESTS` variable in the root Makefile.
### Test structure
Tests live in `infer/tests/codetoanalyze/{language}/{analyzer}/`. Each test directory has:
- Source files to analyze
- `issues.exp` with expected output (one issue per line)
- `Makefile` that runs infer and diffs output against `issues.exp`
Test procedure naming conventions:
- `*Bad` โ should report an error
- `*Ok` โ should not report an error
- `FP_*` โ false positive (known limitation, include explanatory comment)
- `FN_*` โ false negative (known limitation, include explanatory comment)
### Debugging analysis
```sh
infer --debug -- clang -c examples/hello.c
firefox infer-out/captured/hello.c.*.html
```
## Architecture
### Frontends (language โ SIL translation)
Each supported language has a frontend that translates source code into SIL (Separation Logic Intermediate Language), defined in `infer/src/IR/`:
| Directory | Language | Mechanism |
| ---------- | ----------------- | -------------------------------------------------- |
| `clang/` | C/C++/Objective-C | Custom clang plugin (`facebook-clang-plugins/`) |
| `java/` | Java | javalib/Sawja bytecode parsing |
| `erlang/` | Erlang | Erlang compiler integration |
| `python/` | Python | PyML-based frontend |
| `rust/` | Rust | Charon IR translation |
| `llvm/` | LLVM bitcode | LLVM OCaml bindings (used by Swift) |
| `textual/` | Textual SIL | Text-based SIL representation (Hack, Python, LLVM) |
### Intermediate Representation (`infer/src/IR/`)
Core types: `Sil.ml` (instructions), `Procdesc.ml` (procedure descriptors), `Typ.ml` (types), `Procname.ml` (procedure names), `Tenv.ml` (type environments).
### Analysis engines
- **Pulse** (`pulse/`, ~150+ files) โ The main abstract domain. Handles memory safety, taint tracking, null safety, resource leaks via abductive reasoning.
- **Abstract interpretation framework** (`absint/`) โ `AbstractDomain.ml`, `AbstractInterpreter.ml` define the fixpoint computation infrastructure.
- **Buffer overrun** (`bufferoverrun/`) โ Array bounds analysis.
- **Concurrency** (`concurrency/`) โ Race condition detection (RacerD).
- **Cost** (`cost/`) โ Computational cost analysis.
- **TOPL** (`topl/`) โ Temporal property checking.
- **Checkers** (`checkers/`) โ Miscellaneous checkers (liveness, purity, annotations, etc.).
### Backend (`infer/src/backend/`)
Analysis scheduling (`AnalysisDependencyGraph.ml`), call graph construction (`CallGraph.ml`), checker registration (`callbacks.ml`), reporting.
### Configuration (`infer/src/base/Config.ml`)
Very large file (~189KB) defining all command-line options. Uses `CommandLineOption` module (aliased `CLOpt`).
## OCaml Coding Conventions
- **100-character line limit.** Format with `ocamlformat`.
- **`IStd` is auto-opened** in every file. Always write `open! IStd` explicitly at the top.
- **Polymorphic equality is disabled.** Use type-specific equality (e.g., `Int.equal`, `String.equal`). Use `PolyVariantEqual` only for modules heavy on argument-free polymorphic variants.
- **Standard module aliases** (use consistently, do not alias these names to other modules):
```ocaml
module CLOpt = CommandLineOption
module F = Format
module L = Logging
module MF = MarkupFormatter
```
- **Printf debugging:** Use `Logging.debug_dev` (triggers a warning to prevent accidental commits).
- Use `[@@deriving compare, equal]` for comparison/equality derivations.
- Use named arguments when purpose isn't obvious, especially for bool/int params and function-typed params (conventionally named `f`).
- Avoid globally opening modules other than `IStd` and `PolyVariantEqual`.
- **OCaml debugger:** Module `M` is really `InferModules__M` (or `InferBase__M`, etc.) when setting breakpoints in `ocamldebug`.
## Key Files
- `infer/src/base/Config.ml` โ All CLI options
- `infer/src/IR/Sil.ml` โ SIL instruction definitions
- `infer/src/absint/AbstractInterpreter.ml` โ Fixpoint computation
- `infer/src/pulse/PulseAbductiveDomain.ml` โ Pulse's core abstract state
- `infer/src/dune` โ Main dune build config (generated from `dune.common` + `dune.in`)
- `Makefile` โ Test targets and build orchestration