Commit graph Crafter.Build/tests/Lint
Author SHA1 Message Date
04bc58b2fa refactor(lint): derive CommentStripped from tokens, drop the char scanner
StripComments hand-scanned five states over raw characters and could not see
a raw string literal, which was documented as a v1 limitation. It was worse
than "does not recognise them": an odd number of quotes inside a raw string
desynchronised the scanner for the rest of the file. Simulated on the new
fixture, the old output was

    auto banner = R"         "hi)" \n                 \n ...  "MARKER text"

— the code after the raw string blanked away, and the *contents* of a later
string literal left standing as if it were code. Every rule reading
CommentStripped() saw that. There are 33 raw strings across 6 files here,
including the two largest.

The replacement projects the token stream onto a copy of the buffer, blanking
comment tokens whole and the bodies of string/character literals. Editing a
copy in place makes the length-preserving contract structural rather than
something each branch has to remember, and the token extents make raw
strings, escapes, encoding prefixes and '"' all fall out for free. A raw
string reduces to R"…" so rules that bracket a literal by counting quotes
keep working. Digit separators (1'000) are excluded by requiring the text
before the quote to be an encoding prefix.

The public contract is unchanged, so no rule needed editing, and `lint` over
this repo produces byte-identical output to the previous implementation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 02:59:11 +02:00
5888af29ed feat(lint): libclang-backed token layer
Adds LintContext::Tokens() and friends, backed by clang_tokenize, as the
substrate the rules will move onto. Nothing consumes it yet.

libclang is dlopen'd rather than linked: -lclang would break the mingw and
MSVC cross-builds at link time and would put a libclang.so.NN runtime
dependency into the otherwise self-contained release tarballs. The clang-c
header is used for its declarations only, and the function-pointer table is
typed with decltype so the signatures cannot drift from the real API.

Three properties this buys that the hand-rolled scanners could not have:

  - a raw string literal or block comment is ONE token, so the documented
    "raw string literals are not recognized" limitation goes away;
  - `//` inside a literal is not a comment, so LineHasComment() replaces the
    Line(n).contains("//") probes that false-positive on it;
  - tokens cover preprocessor branches that are inactive for the host, since
    clang_tokenize lexes rather than evaluates #if. Token rules therefore
    keep seeing every platform's code, which an AST could not offer.

The parse backing the tokenizer is expected to fail on module units — no
PCMs, no build flags — and that is fine, because lexing has no semantic
prerequisites. Verified in the new tests.

LintSummary::Clean() now counts `errors`. It previously ignored them, so an
infrastructure failure that produced no findings reported clean and exited
0; a missing libclang would have been exactly that.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 02:54:38 +02:00
8892154b28 linting
Some checks failed
CI / build-test-release (push) Failing after 7m15s
2026-07-23 01:24:42 +02:00