smith check, fmt, lint and lsp
smith fmt, smith lint and smith lsp are clang-format, clang-tidy and clangd, linked into smith from the same LLVM as the compiler, so every machine formats and lints alike.
On the project: no arguments
The verbs mean the same in every project and read what its build.c declares; a project writes no task for them.
smith fmtrewrites every C, C++, Objective-C and.smithfile git sees (tracked, and untracked but not ignored;.c .h .m .mm .cpp .cc .cxx .hpp .hh .smith .metal) to.clang-format(a.metalfile is formatted as C++, the language clang-format gives an extension it does not know).smith fmt --dry-run(or-n, with--Werroror-i) andsmith lint --quietare the project forms too: options alone, no file names, so they never wait for standard input; any other option, or a file name, makes them the tools (smith fmt --assume-filename=x.creads standard input). A file named in.clang-format-ignore(clang-format reads it itself: a generatedparser.c, a fixture) is left alone. Outside a git repository it says to name the files (smith fmt -i <files>).smith lintbuilds what the compiles read (generated headers), then runs clang-tidy with.clang-tidyon the project's own sources among the build's compiles (smith_object, andsmith_compile_commandfor sources the build never compiles), side by side. Not.smith/,build/outputs or packages. Every.smithsource is linted assmith lint x.smith -- <flags>does: the build's own with their compile's command, and each other.smithfile git sees with the nearest compile's command, except what.clang-format-ignorenames (the one list of files that are not ordinary source: test inputs, deliberately wrong fixtures, generated and copied files;smith fmtreads it too, so there is no second list). A finding fails the lint; its last line sayslinted N files(smith check:lint ok: N files), and a project with.smithsources that lints none fails. A.clang-tidyin a folder (such asInheritParentConfig: truewith other checks) applies there.smith lintis incremental: clang-tidy's result for a file is cached under~/.cache/smith/lintand replayed while the file, what it includes (for a.smithfile, also the generated headers of the modules it imports), its.clang-tidyand smith are unchanged, so the last line readssmith lint: linted 180 files (3 run, 177 cached, 1.2 s)and an unchanged tree runs clang-tidy on no file.SMITH_LINT_CACHE=0turns it off,SMITH_LINT_CACHE=whysays why a file ran,smith cache clean lintempties it. A file whose clang-tidy fails is named in the last lines (smith lint: c.c: exited with status 1, orwas killed by signal 9, which prints nothing of its own) and at the end of its own output.smith lint --changed[=<ref>]lints only the files changed since the merge-base with<ref>(default: the branch's upstream, elseorigin/HEAD's branch ororigin/main, never a localmain; none of them is an error naming--changed=<ref>; the line it prints names the base; edits and untracked files count) and the files that include or import them; a changed.clang-tidy, build file,shim/orpatches/selects every file, and nothing affected says so and succeeds. It also builds only what those files wait for. Plainsmith lintlints everything (CI). A file that waits for a package the network does not give (the tree-sitter parser in a cloud sandbox) is skipped by name (smith lint: skipped runtime/tree_sitter_data.c: the tree-sitter parser it embeds cannot be fetched (<url>)) and the rest is linted; CI (CIorSMITH_PRIORITY=ci) fails instead.smith lint FILEin a project not built yet (nocompile_commands.json) stops and says to runsmith build smith_needsonce, rather than report the missing generated headers as errors.smith docschecksknowledge/and the skills (smith-docs).smith checkruns fmt (clang-format's dry run), docs, lint, test and prove, in that order, and does not stop at a failure: each part prints one line,smith check: <part> ok: <detail> (<n> s wall, <n> s cpu)orFAILED (status N)with a bounded excerpt of the failure and the path of the full log (.smith/log/<part>.log; the output of a passing part is there too;smith check -vprints everything as it happens), thensmith check: promises: N(what smith trusts, from a default build it makes if needed), and the last line issmith check: okorsmith check: failed: <parts>; the exit status is 1 when any failed. The prove line says the coverage,smith check: prove ok (4 of 23 functions): ...(functions with a contract of their own, of the project's;0 of N functionswhen there is nothing to prove, which is a success; nothing fails on low coverage). Each part's line ends with its wall and CPU time ((91.2 s wall, 480.1 s cpu): CPU is user plus system, of the part and the processes it waited for). It takes no arguments but-Doptions and-v. On a host that is not macOS it runs the tests with--skip-macosand says so (the macOS-only tests do not run on this host).smith testends with a table of the build's tasks (.smith/task/<name>steps, as smith's owntest-<name>), slowest first: wall, CPU and system seconds and the number of smith processes each started (SMITH_START_LOG, which smith appends to asmainbegins; a task that clears the environment is not counted); the slowest eight, every task withsmith check -vorSMITH_ACCOUNT=all, none withSMITH_ACCOUNT=no. The tasks run throughsmith --smith-account <file> <name> <command...>, which writes the line..smithfiles in the new syntax are not clang-format's (#1890, #1886, #2040):smith fmtsends a.smithfile to smith's own formatter (front::format) unless it is in today's syntax (a line starts with a form only today's syntax or C has, today's parser reads it without an error, or its first error in the new syntax has a fix, like a//comment) or has a parse error and no line only the new syntax has (fn,let,pub,#): one style and no.clang-formatfor it (any consistent indentation comes out at 4 spaces, one statement a line,#comments kept). A new-syntax file with a parse error is reported aspath:line:column: message, left byte for byte as it was (with--dry-runtoo) and makessmith fmtexit 1: it is never sent to clang-format, which would mangle it. It is idempotent, honours.clang-format-ignore, and--dry-run/-nnames the files that would change (path: would be formatted) without writing. A.smithfile in today's syntax (and every.c) stays clang-format's until the switch-over (#1631) removes that fall-back. Tested bytests/fmt_smith_test.smith.smith fmt FILErefuses a file whose extension is not one of those (a.sh, a.md), with an error that names the file and writes nothing, since clang-format would read it as C and corrupt it;--assume-filename=x.csays what it is.- Before committing:
smith fmt, thensmith check. - A task of your own (a custom check, a generator) is
smith_taskin build.c and runs withsmith build <task>; no task or alias may be namedfmt,lint,docs,prove,check,runortest.smith build checkand the other verb names are refused: use the verb.
On files: with arguments
smith lint DIR (a folder among the arguments) lints the C, C++, Objective-C and .smith sources under it that git sees and .clang-format-ignore does not name, like the project lint (no headers, which are read through their sources); smith lint front -- <flags> and smith lint front/ main.c mix with files. A folder with no such source is an error.
clang-tidy's analyzer (clang-analyzer-*) reads smith_requires, smith_ensures, smith_invariant and smith_assert of <smith/contract.h> as assumptions (target::static_analyzer), so an index a contract bounds is not reported by clang-analyzer-security.ArrayBound.
smith's default .clang-tidy turns off two analyzer checks that were noise (on game, learner and smith: 546 of 616 findings): clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling (every memcpy) and clang-analyzer-optin.performance.Padding. Turn one back on in the project's own .clang-tidy (smith lint --dump-config > .clang-tidy writes the effective file) by deleting its -clang-analyzer-... line.
smith lint --fix FILE.smith... (no --) applies the fixes that smith's own front end carries in its parse errors (an old or C-style form with its smith spelling: the edits of one fix are applied together or not at all, an overlapping fix is skipped, and a file is parsed again until nothing applies, at most 16 passes) and prints path: N fixes applied; a second run prints 0 fixes applied. It reads .smith files only and needs the full smith. With -- <flags> it is clang-tidy's --fix, above. No parse error carries a fix yet: the old forms get theirs ticket by ticket (#1428).
smith lint FILE adds --extra-arg=-I for build/<os>/front-project/.smith/include when that folder exists (front modules import each other through it), and on a host that is not macOS prints one line: CI lints on a Mac, where u64 is unsigned long long and usize is unsigned long, so (U64)(i + 1) with a usize is a bugprone-misplaced-widening-cast finding there only; fix such a cast by writing (U64)i + 1.
With arguments they are the tools: smith fmt main.c rewrites the file in place (clang-format would print it; smith adds -i when you name files and no option chooses another mode: -n, --dry-run, --lines, --assume-filename keep clang-format's meaning, and smith fmt --assume-filename=x.c < x.c prints the result), smith fmt --dry-run --Werror main.c, smith fmt --dry-run --Werror main.c, smith lint --quiet main.c -- <flags>, smith lsp --check=main.c. A project's .clang-format and .clang-tidy apply. A stage0 smith runs Homebrew's tools, or $SMITH_CLANG_FORMAT, $SMITH_CLANG_TIDY, $SMITH_CLANGD.
smith's defaults, where a project has no file (issue #43). A project with no .clang-format (or _clang-format) and no .clang-tidy, looked up from each file's folder and up as clang-format and clang-tidy do, is formatted and linted with smith's own, embedded in smith (the files smith new writes today); there is nothing to write. A file in the project replaces smith's whole, never merged, and an explicit --style (or --fallback-style), --config or --config-file wins. With standard input, --assume-filename names where to look. Naming files with and without a project file in one command works (smith runs the second kind as another process). smith fmt --dump-config > .clang-format and smith lint --dump-config > .clang-tidy print the effective one (the project's, else smith's), so a project takes the defaults over by dumping them and edits what it wants; the defaults change rarely and on purpose, so a project that wants them fixed dumps them. smith writes its copy to $XDG_DATA_HOME/smith/defaults/ (else ~/.local/share/...). smith cc is never affected: it stays a pure passthrough.
.smith files
smith fmt x.smith (and -i, --dry-run, standard input with --assume-filename=x.smith) formats a .smith file as C, with its :: paths, module a::b; and import a::b as x; lines and import <sys/wait.h>; kept whole; smith fmt with no arguments formats the project's .smith files too (git sees them). import and module inside a function are names, as in C. Needs a smith whose clang-format has the .smith patch (a stage0 runs Homebrew's, which reads .smith as C++ and so misreads C names that are C++ keywords, such as throw). clangd formats .smith files the same way.
smith lint x.smith -- <flags> (clang-tidy, with the project's .clang-tidy) lints a .smith file as smith cc reads it (-x c, and -std=gnu2y unless you name a standard; a compile database's own command is used as it is) and reports as the source is written: findings, notes and fix-its at the lines and columns of the .smith text, with the names as written (area and Box in the module, box::area where it is imported, never geometry_box_area). readability-identifier-naming judges the written name of a module's file-scope names, so the template's rules (snake_case functions and variables, PascalCase types) apply to area and Box, and --fix rewrites the token in the source; the sized types (U32, I32), the lowering's copies of prototypes and the headers smith build writes are never reported. A finding about an export is reported in the module's file, not in each importer, and a fix there does not rename the importers. Other checks show the written names in their messages, but a check that compares the name itself (a length or a reserved-name check, say) still reads the lowered one. Needs a smith whose clang has the token hook (smith cc --smith-which x.smith says token-hook yes); a stage0 runs Homebrew's clang-tidy, which cannot read .smith.
Also in this family: smith-check-lints.