Skip to content

5 REQ lang

Manuel Hatzl edited this page Nov 23, 2025 · 7 revisions

lang: Conventions for integrated programming languages

Sub-requirements of lang define conventions and syntax constructs that must be followed by users that want to use mantra's built-in automatic trace, test, and coverage collection for supported programming languages.

lang.rust: Conventions for Rust

Contains conventions for Rust code to allow automated collection of traceability information by mantra.

lang.rust.tracing: Rules to detect traces in Rust code

  • Parents: [lang.rust, trace.collect.auto.ast, trace.collect.auto.pattern, trace.kind]

Sub-requirements describe patterns that must be recognized as requirements traces in Rust code.

Note: <requirement IDs> is used in this section as placeholder for the pattern or parts of the pattern defined in [req("trace.collect.auto.pattern")].

lang.rust.tracing.attribute_macros: Detectable attribute macros

These traces have an associated line span of the element the attribute macro is set on.

The module path must be irrelevant for the detection to allow different macro implementations.

mantra must be able to detect the attribute macro inside a cfg_attr attribute macro independent of the currently active features.

  • Clarify Requirement Macro:

    The attribute macro #[req_note()] may be used to mark code that adds clarification for one or more requirements. Therefore, mantra must detect this macro as a trace of kind clarify.

    Examples:

    #[req_note(<requirement IDs>)]
    fn foo() {}
  • Satisfy Requirement Macro:

    The attribute macro #[req()] may be used to mark code that satisfies one or more requirements. Therefore, mantra must detect this macro as a trace of kind satisfy.

    Examples:

    #[req(<requirement IDs>)]
    fn foo() {}
    #[mod_path::req(<requirement IDs>)]
    fn foo() {}
    #[cfg_attr(<some condition>, mod_path::req(<requirement IDs>))]
    fn foo() {}

    Note: The <some condition> must be added as trace property under the field cfg-attr.

    #[req(<requirement IDs>; { prop_key: "custom-prop-1" }, "custom-prop-2")]
    fn foo() {}
  • Verify Requirement Macro:

    The attribute macro #[req_test()] may be used to mark code that verifies one or more requirements. Therefore, mantra must detect this macro as a trace of kind verify.

    Examples:

    #[req_test(<requirement IDs>)]
    fn foo() {}
  • Link Requirement Macro:

    The attribute macro #[req_link()] may be used to mark code that links to one or more requirements. Therefore, mantra must detect this macro as a trace of kind links.

    Examples:

    #[req_link(<requirement IDs>)]
    fn foo() {}

lang.rust.tracing.fn_macros: Detectable function-like macros

These traces only link to the lines the function-like macro itself spans. Therefore, these macros must allow to wrap/surround code that is kept through as is. One : colon must be used after the requirement IDs and optional trace properties to separate them from the wrapped code.

The module path must be irrelevant for the detection to allow different macro implementations.

  • Satisfy Requirement Macro:

    The function-like macro satisfy_req!() may be used to mark code that satisfies one or more requirements. Therefore, mantra must detect this macro as a trace of kind satisfy.

    Examples:

    fn foo() {
        satisfy_req!(<requirement IDs>: <some code that satisfies the requirements>);
        mod_path::satisfy_req!(<requirement IDs>; { some_key: "custom-prop" }: <some code that satisfies the requirements>);
    }
  • Verify Requirement Macro:

    The function-like macros assert_req!(), assert_eq!(), and assert_ne!() may be used to mark code that verifies one or more requirements. Therefore, mantra must detect those macros as traces of kind verify.

    These macros must behave like the equivalent assertions of Rust's std library.

    Examples:

    fn foo() {
        assert_req!(<requirement IDs>; { some_key: "custom-prop" }: <some boolean expression that must evaluate to "true">, <some optional message explaining the assertion>);
        assert_req_eq!(<requirement IDs>: <left side>, <right side>, <some optional message explaining the assertion>);
        assert_req_ne!(<requirement IDs>: <left side>, <right side>, <some optional message explaining the assertion>);
    }

lang.rust.tracing.comments: Detectable traces in comments

These traces have an associated line span of the element the comment is referred to. The trace syntax is similar to the one for attribute macros except the missing # at the start.

Note: Traces in block comments are not supported to reduce the potential of false trace detection.

  • Doc-Comments:

    /// [req(<requirement IDs>)]
    fn foo() {}
    
    /// [req_test(<requirement IDs>)]
    fn test_foo() {}
  • Line Comments:

    For traces in regular line comments, several restrictions apply to prevent false detection:

    • Traces must be on a separate commented line without any other content except whitespace
    • The line directly below a trace must contain a non-commented element to which the trace is linked to
    • The affected line span depends on the non-commented element the trace is linked to
    • For conditional if blocks, only line comments directly above the starting if block must be searched for traces, and the span must include all lines up to the end of the last else block.
    fn foo(y: isize) {
        // [req(<requirement IDs>)] <- trace span starts at this line
        let x = 5; // <- trace span goes until this line
    
        // Some comment above the if block <- trace span starts at this line
        // [req(<requirement IDs>)]
        if x == y {
            // do something ...
        } else if x < y {
            // do something else ...
        } else {
            // do something else ...
        } // <- trace span goes until this line
    }

lang.rust.tracing.span: Line span of elements and code blocks in Rust code

Line spans of elements in Rust code must include the element header, element body, doc comments, and attribute macros set on an element, because code generated by attribute macros has the line the macro is set at. To properly map covered statements to traces, the line span of elements must therefore cover more lines than just the body.

e.g. all lines of the example below are part of the element span

/// Some doc comment for the function.
#[req(<requirement IDs>)]
fn foo() { // <- element header up until `{`
    // some body content
}

Line spans of code blocks must include the span of the code block and the optional line comments directly above a code block if no blank line is between the last line comment and the code block start.

Clone this wiki locally