class

Analyzer::Rust::RustEngine

Inherits FileScanEngine < Analyzer < FileHelper < Reference < Object

Constants

CARGO_KEY_RE = /^\s*(name|path)\s*=\s*"([^"]+)"/
CARGO_PACKAGE_RE = /(?m)^\s*\[package\]/
CARGO_SECTION_RE = /^\s*\[([^\]]+)\]/
CARGO_WORKSPACE_RE = /(?m)^\s*\[workspace\]/
EXTRACTOR_KINDS = {"Query" => {"query", "query"}, "Json" => {"json", "body"}, "Form" => {"form", "form"}}

Extractor => {param location, name used when its type's fields are unknown}.

EXTRACTOR_TARGET_RES = EXTRACTOR_KINDS.keys.to_h do |kind| {kind, /(?<!\w)(?:Aweb)?#{kind}(?:Parameter)?\s*<\s*(?:(?:(?:std::)?vec::)?Vec\s*<\s*)?((?:[A-Za-z_]\w*::)*[A-Za-z_]\w*)\s*[<>,]/} end

The type an extractor decodes into, when it is a plain (possibly module-qualified, possibly generic) name: Json<CreatePost>, web::Query<api::Params>, Json<Record<Data>>, deserr's AwebJson<T, E> / AwebQueryParameter<T, E>. Json<Vec<T>> is a JSON array of T, so its params are T's fields.

FLATTEN_TYPE_RE = /\A(?:Option\s*<\s*)?((?:[A-Za-z_]\w*::)*[A-Za-z_]\w*)\s*(?:[<>]|\z)/
HTTP_VERBS = Set {"get", "post", "put", "delete", "patch", "head", "options"}

Lower-case verb names the route macros and builders are spelled with.

MAX_FLATTEN_DEPTH = 4
RUST_PATH_ROOTS = {"crate", "self", "super"}
RUST_RESOLVE_MAX_STEPS = 512

Bound on the (file, name) steps one resolution may take; a cyclic re-export graph (pub use super::* both ways) visits each step once.

STRUCT_DECL_RE = /\bstruct\s+([A-Za-z_]\w*)/
TEST_CRATE_DIR_RE = /\/(?:[\w.-]+[-_])?tests(?:[-_][\w.-]+)?\/|\/(?:e2e|playwright)(?:[-_]tests?)?\//

Workspace test crates are named after the convention without being the literal tests/ segment: rwf-tests, tests-fuzz, playwright-tests, suspense_tests. Plural tests needs a -/_ delimiter so contests/ and latest/ stay out; singular test-app / test_only are deliberately not matched. e2e / playwright count only as the whole segment, optionally with a -test(s) / _test(s) suffix: e2e-encryption/ and api/e2e_keys/ are Matrix-style end-to-end encryption code and serve real routes. Applied to the rooted scan-base-relative path, like the /tests/ check.

Class methods

collect_cfg_test_regions(source : String) : Array(Tuple(Int32, Int32))

Scan the source for #[cfg(test)] annotations, then capture the byte range of the following mod/fn/impl block via simple brace counting. String/char literals are skipped so a { inside "foo {" doesn't shift the depth. Rust lifetimes like 'a look like char literals to a naive quote scanner and would otherwise drop the close-brace search into oblivion — see skip_char_or_lifetime.

Shared with all Rust analyzers: axum's extract/path/mod.rs, salvo's crates/core/src/routing.rs, and similar framework source files mix production routes with #[cfg(test)] mod tests { ... } blocks. Each analyzer that uses tree-sitter can call this once per file, then drop any route call whose ts_node_start_byte falls in one of the returned ranges.

Source
fan_out_verbs(verb : String) : Array(String)

Expand any / all (case-insensitive) into the seven canonical HTTP methods. Anything else passes through as a single-element list.

Source
inside_test_region?(node : LibTreeSitter::TSNode, regions : Array(Tuple(Int32, Int32))) : Bool
Source
test_path?(relative_path : String) : Bool

Cargo convention: every .rs immediately under a crate's tests/ directory is an integration-test binary, never a production endpoint. The _test.rs / _tests.rs suffix is equally rigid for unit tests in sibling files. Framework repos (rocket/Rocket's core/codegen/tests/, actix-web's actix-web-codegen/tests/, poem's poem-openapi/tests/) all park hundreds of route registrations under one of these patterns. Promoted from axum.cr#test_only_path? (#1569) to the shared engine so the rest of the Rust family benefits.

Takes the scan-base-relative path (Analyzer#base_relative_path), never the absolute one. Cargo's conventions are relative to the crate, so matching the absolute path let a directory above the scan base decide the answer: the same tree cloned into ~/work/tests/myapp reported 0 endpoints instead of 220.

Source

Nested types