diff --git a/concepts/analyzers/rust.mdx b/concepts/analyzers/rust.mdx index 7156b01..12e4dc0 100644 --- a/concepts/analyzers/rust.mdx +++ b/concepts/analyzers/rust.mdx @@ -65,6 +65,74 @@ definition selectors. Inspect any rule and its effective settings with: fensu rule FPRSS010 --target rust ``` +## Custom Rust rules + +Custom Rust rules are authored in Python but run over immutable, serialized facts +owned by Fensu. Declare Rust applicability explicitly and use a typed `File` or +`Project` subject; raw `syn` and Cargo metadata objects are never exposed. + +```python +from fensu import ( + AnalyzerId, + Family, + Fault, + File, + RuleContext, + RustItemKind, + rule, +) + + +@rule( + code="XRS001", + family=Family.CUSTOM, + slug="legacy-service", + message="legacy service declaration", + analyzers=(AnalyzerId.RUST,), + cacheable=True, +) +def legacy_service(*, file: File, ctx: RuleContext) -> list[Fault]: + facts = ctx.rust.file(file) + if facts is None: + return [] + return [ + ctx.fault_at(location=item.location) + for item in facts.items + if item.kind is RustItemKind.STRUCT and item.name == "LegacyService" + ] +``` + +Configure it through the standard custom-rule and selector keys: + +```toml +[targets.rust] +analyzer = "rust" +roots = ["src"] +tests = [] +tooling = [] +rule_packs = ["rust"] +rule_modules = ["rules.rust"] +select = ["FPRS", "XRS001"] +``` + +`ctx.rust` includes Cargo workspace crates, targets and dependencies; selected Rust +files and module identities; declarations for functions, structs, enums, traits, +implementations, visibility and derives; parse failures; and statically provable +`use` targets. Resolution remains explicit when a target is external, crate-local +but not attributable to one file, or unresolved. + +Project rules use `Project` and run once for the Rust target. They can combine +`ctx.project.tree` with `ctx.rust.crates` for workspace-wide dependency or layout +policy. Typed `rule_options`, warning tiers, selector ignores, path ignores and exact +exceptions use the same configuration as built-in rules. + +Fensu starts the Python host only when configured custom-rule sources have an active +`X` selector that is not wholly covered by an ignore prefix. A Rust target with only +native selectors remains native and Python-free. Cacheable custom rules retain +separate file or project subjects and replay the tree or Rust-fact queries actually +observed by each invocation. Fact schema, parser contract, runtime, rule package and +typed options all participate in cache identity. + ## Rule options Adjust a rule under the target's standard `rule_options` table: @@ -144,7 +212,8 @@ layout checks for explicit subtrees while preserving per-file checks. ## Cargo metadata and caching Rust sources, Cargo manifests, an existing lockfile, and target configuration are -cache inputs. Fensu uses locked dependency resolution when `Cargo.lock` exists. +cache inputs. Selected custom-rule packages are cache inputs as well. Fensu uses +locked dependency resolution when `Cargo.lock` exists. For a lock-free workspace, it reads declared dependencies without creating a lockfile. diff --git a/reference/rule-context.mdx b/reference/rule-context.mdx index 41e9584..6326de0 100644 --- a/reference/rule-context.mdx +++ b/reference/rule-context.mdx @@ -117,6 +117,28 @@ dynamic imports are not represented. `ImportResolution`, and optional target node. Graph identities include analyzer and source-kind ownership so they remain safe as additional analyzers gain graphs. +## `ctx.rust` + +For Rust targets, a versioned immutable workspace fact view transferred from the +native analyzer. It contains no `syn` or Cargo metadata objects. + +| Call | Returns | Purpose | +| --- | --- | --- | +| `crates` | `tuple[RustCrateFact, ...]` | All Cargo workspace package, target and dependency identities. | +| `files` | `tuple[RustFileFacts, ...]` | All selected Rust file, module, source, item and `use` facts. | +| `crate(identity)` | `RustCrateFact \| None` | One focused crate lookup by stable workspace identity. | +| `file(file_or_path)` | `RustFileFacts \| None` | One focused file lookup by `File` or `ProjectPath`. | + +`RustItemFact` uses `RustItemKind` and `RustVisibility`, preserves derives and +implementation targets, and carries a stable `SourceLocation`. `RustUseFact` +preserves authored parts, source and target modules, optional target file and crate, +and a `RustUseResolution` of `RESOLVED`, `CRATE`, `EXTERNAL`, or `UNRESOLVED`. +`RustFileFacts.parse_error` remains explicit when source cannot be parsed. + +Each broad or focused call records its answer for subject-aware cache replay. Use a +focused `file()` or `crate()` lookup when unrelated source or Cargo changes should +not invalidate a cached result. + ## `ctx.text`, `ctx.syntax`, `ctx.relations` Source text, opaque syntax identities, and syntax relationships for the current @@ -137,6 +159,11 @@ file. The zone protocols are `FactAnalysis`, `ProjectAnalysis`, `TextAnalysis`, `SyntaxAnalysis`, and `RelationAnalysis`, all exported from `fensu`. +The table above describes the Python analysis zones. Serialized Rust rules use +`ctx.rust`, `ctx.project.tree`, `ctx.source`, and stable locations. `ctx.graph`, +`ctx.syntax`, and `ctx.relations` are unavailable because parser implementation +objects are not part of the Rust authoring contract. + ## Fault construction Construct diagnostics through the context so the rule's code, and optionally its @@ -289,6 +316,18 @@ are frozen dataclasses; inspect exact fields with your editor's type information | `ImportEdge` | Authored import plus explicit resolution result. | | `ImportCycle` | One statically proven strongly connected component. | +**Rust facts** + +| Model | Describes | +| --- | --- | +| `RustWorkspaceFacts` | Versioned workspace crates and selected Rust files. | +| `RustCrateFact` | Cargo package identity, manifest, library, targets and dependencies. | +| `RustTargetFact` | Stable Cargo target identity, kinds, source root and entry path. | +| `RustDependencyFact` | Cargo package/source name, dependency kinds and optional local crate. | +| `RustFileFacts` | Source, module identity, parse result, items and authored uses. | +| `RustItemFact` | Function, struct, enum, trait, implementation or module declaration. | +| `RustUseFact` | Authored `use` path and explicit resolution evidence. | + **Test facts** | Model | Describes |