Skip to content

ADR-030 — Syntax-only macro analysis

Date: 23/08/2026 Status: Accepted

Context

Codira's C and C++ analyzers already retain preprocessor macro definitions and recognize macro-shaped call evidence without running a preprocessor. The Rust analyzer needs the same useful structural visibility for macro_rules! definitions and path! invocations.

Rust macro expansion is not a local parsing operation. Its result can depend on dependency resolution, procedural macros, Cargo features, build scripts, conditional compilation, and token-tree matching. Treating parser output as if it were expanded compiler output would invent symbols and call edges that the analyzer cannot prove from the repository source alone.

Decision

Adopt one syntax-only macro policy for first-party language analyzers.

Extract stable source evidence

Analyzers may emit macro evidence only when it is syntactically explicit in the source.

For Rust V1:

  • a macro_rules! NAME definition is a macro declaration
  • its stable ID is rust:macro:<repo-relative-source-path>:<name>
  • its source text is retained as a normalized declaration signature; the rule body is not interpreted
  • a SimplePath! invocation within an indexed callable is an unresolved call site with external_target_kind = "rust_macro"
  • the invocation path is retained as the external target name

[plugins.analyzer-rust].emit_macros controls emission of macro declarations. It does not expand macros and does not suppress ordinary syntax analysis or the explicit invocation evidence carried by indexed callables.

Do not emulate compilation

Codira must not, as part of analyzer indexing:

  • expand declarative macros
  • execute or resolve procedural, attribute, or derive macros
  • invoke Cargo or a Rust compiler
  • execute build scripts
  • choose feature sets, target triples, or conditional-compilation branches
  • synthesize declarations, call edges, source spans, or documentation from a potential expansion

This is a fail-closed provenance boundary: unavailable compiler evidence stays unavailable rather than becoming a heuristic fact.

Future expansion-aware analysis

Expansion-aware Rust analysis is a separate capability. It requires a new ADR before implementation that specifies:

  • the compiler/Cargo execution environment and immutable input identity
  • feature, target, lockfile, build-script, and procedural-macro provenance
  • sandboxing and failure behavior
  • truthful source-span policy for generated code
  • cache invalidation and analyzer-version rules

Consequences

Positive

  • Rust macro definitions and invocations are queryable without inventing their expanded behavior.
  • The Rust contract matches the existing C/C++ structural-macro philosophy.
  • Macro bodies remain useful signature evidence while preserving deterministic indexing across machines.
  • Operators can suppress macro declarations when they create unwanted symbol inventory noise.

Negative

  • Symbols and calls generated by macros are intentionally absent.
  • Attribute, derive, and procedural macro behavior is not represented.
  • Queries cannot infer implementation details hidden behind macro expansion.

Execution Rules

  • Keep macro declarations in the normalized declaration model; do not add a parallel parser-specific manifest format.
  • Keep macro invocation call sites unresolved unless another explicit, source-backed resolver can prove a target without expansion.
  • Preserve macro-related configuration, stable-ID, capability, and regression tests whenever the Rust analyzer changes.
  • Do not broaden this boundary silently in language-specific analyzer code.