v0.2.5-pre.010.fix.003

This commit is contained in:
2026-08-20 12:15:36 +02:00
parent 08c8046262
commit cb142b1cb8
5 changed files with 156 additions and 25 deletions

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# file: scripts/audit_rust_general_rules.py
# version: 4
# version: 5
"""Audit mechanically verifiable Rust normalization rules used by KSP."""
@@ -186,13 +186,6 @@ def preceding_doc_line(lines: list[str], index: int) -> bool:
return cursor >= 0 and lines[cursor].lstrip().startswith("///")
def export_symbol(line: str) -> str:
"""Return the re-exported symbol name from one ungrouped re-export."""
path = line.split(" use ", 1)[1].split(";", 1)[0].strip()
return path.rsplit("::", 1)[-1]
def natural_key(value: str) -> tuple[tuple[int, object], ...]:
"""Return a natural case-sensitive ordering key."""
@@ -523,12 +516,12 @@ def audit_file(root: pathlib.Path, path: pathlib.Path) -> list[Violation]:
for attribute in ("#![warn(missing_docs)]", "#![deny(unreachable_pub)]", "#![forbid(unsafe_code)]"):
if attribute not in lines[:24]:
violations.append(Violation("RUST-BASE-103", relative, 1, f"missing `{attribute}`"))
exports: list[tuple[int, str, str]] = []
exports: list[tuple[int, str]] = []
for idx, line in enumerate(lines, 1):
stripped = line.strip()
if stripped.startswith("pub use ") or stripped.startswith("pub(crate) use "):
visibility = "pub(crate)" if stripped.startswith("pub(crate) use ") else "pub"
exports.append((idx, visibility, export_symbol(stripped)))
exports.append((idx, visibility))
if not preceding_doc_line(lines, idx):
violations.append(Violation("RUST-DOC-102", relative, idx, "crate-root re-export requires adjacent rustdoc"))
source_match = re.match(r"^pub(?:\(crate\))?\s+use\s+(?:self::)?([A-Za-z_][A-Za-z0-9_]*)::", stripped)
@@ -544,22 +537,21 @@ def audit_file(root: pathlib.Path, path: pathlib.Path) -> list[Violation]:
if blank_count != 1:
violations.append(Violation("RUST-FMT-113", relative, crate_start, f"pub use and pub(crate) use blocks require exactly one blank line; found {blank_count}"))
crate_seen = False
previous_by_visibility: dict[str, tuple[int, str]] = {}
for idx, visibility, symbol in exports:
previous_by_visibility: dict[str, int] = {}
for idx, visibility in exports:
if visibility == "pub(crate)":
crate_seen = True
elif crate_seen:
violations.append(Violation("RUST-FMT-105", relative, idx, "pub use block must precede pub(crate) use block"))
previous = previous_by_visibility.get(visibility)
if previous is not None:
previous_idx, previous_symbol = previous
previous_idx = previous_by_visibility.get(visibility)
if previous_idx is not None:
# One homogeneous block may contain rustdocs but no blank line.
# rustfmt is authoritative for intra-block re-export ordering;
# this audit must not impose a competing exported-symbol sort.
between = lines[previous_idx:idx - 1]
if any(not candidate.strip() for candidate in between):
violations.append(Violation("RUST-FMT-106", relative, idx, f"{visibility} use block contains an empty line"))
if natural_key(symbol) < natural_key(previous_symbol):
violations.append(Violation("RUST-FMT-107", relative, idx, f"{visibility} use block is not alphabetically ordered by exported symbol"))
previous_by_visibility[visibility] = (idx, symbol)
previous_by_visibility[visibility] = idx
violations.extend(audit_blank_lines_in_bodies(relative, lines, masked_lines, depths))
violations.extend(audit_item_spacing_and_nesting(relative, lines, masked_lines, depths))
violations.extend(audit_module_order(relative, lines, depths))