Skip to content

Blitz Tidy

Narta Xaymar Dirks edited this page Nov 1, 2026 · 7 revisions

Blitz-Tidy

blitz-tidy fixes common mistakes in .bb files. Every rule is one of the Warnings of blitzcc: blitz-tidy compiles the file with all warnings on, and where the compiler says how to fix a warning, it makes the change. It is installed next to blitzcc.

blitz-tidy program.bb lib.bb          # fix the files in place, and print their names
blitz-tidy --diff program.bb          # show what would change, exit code 1 if something would
blitz-tidy -r src/                    # fix every .bb file below a directory
blitz-tidy --check *.bb               # list the files that would change, exit code 1 if there are any
blitz-tidy < program.bb               # standard input to standard output (print the fixed program)

An example

Local ratio# = 2.5
Local count% = ratio
Local label$ = count + 1

Function Sum(limit)
	For i = 1 To limit
		total = total + i
	Next
	Return total
End Function

becomes

Local ratio:Float32 = 2.5
Local count:Int32 = Int(ratio)
Local label:String = Str(count + 1)

Function Sum(limit)
	Local i%
	Local total%
	For i = 1 To limit
		total = total + i
	Next
	Return total
End Function

What it does with a file

  1. The file is compiled (to nothing: no program is made) with every warning on. A file that does not compile is not touched and is reported.
  2. Each warning whose rule is set to fix and that has a fix that is safe becomes a change. Changes that touch each other wait for the next round.
  3. The changed file is compiled again. If it no longer compiles, blitz-tidy finds out which change did it and leaves that one out. Then it starts again at 2, until nothing is left to fix (at most max-passes times).
  4. What is left is printed to the standard error as file:line:column: warning: ... [blitz-tidy:<rule>], with a note why it was not fixed.

A second run over the result changes nothing. The fixes are made so that the program does the same: they only write down what the compiler did anyway. The one exception is that an explicit conversion from a real number to an integer stops at the smallest and largest number of the type (SatInt behavior), while the implicit one is undefined for numbers that do not fit.

Rules

blitz-tidy --rules lists the same.

Rule Default Fix Needs unsafe
implicit-lossy-int-to-int fix Byte(value), UShort(value), UInt(value) ...
implicit-lossy-real-to-int fix Int(value), Byte(value) ...
implicit-lossy-real-to-real fix Float(value), Half(value)
implicit-string-to-number fix Int(value), Float(value) ...
implicit-lossy-int-to-real fix Float(value), Double(value), Half(value)
implicit-number-to-string fix Str(value)
typeless-declaration fix Local x becomes Local x:Int32 (also Global, Const). A Function without a type gets the one its Return statements give: :Int32 if all give an Int (or no value). A function whose Return statements all give a Float or all a String becomes :Float32 or :String. When the Return statements disagree (or give an object, or a type that is not one of these) it is left alone. The function types :Float32 and :String: the function returns an Int now, so the callers get another value once it has the type. :Int32 is safe. :Void is never added: a function that returns no value is only reported, as writing :Void changes what the function is.
one-declare-per-variable off Local a, b = 1 becomes Local a and Local b = 1 on lines of their own (also Global). Const is left alone. Off by default.
parentheses-around-condition off If a = 1 Then b becomes If (a = 1) Then b: the condition of If, ElseIf, While, Until and Select goes in parentheses (also on a line with : and in Else If). A condition that is one parenthesis from start to end is left alone, (a) Or (b) is not. For is not touched. Off by default.
parentheses-around-arguments off Foo 14, 12, 14 + 12 becomes Foo(14, 12, 14 + 12), for a command or function that is called as a statement and has arguments. A parenthesis around only the first argument (Foo (1)+2, 3) is not taken for the parenthesis of the call: it becomes Foo((1)+2, 3). Off by default.
resource-acquisition-is-initialization off A Local or Global gets a value where it is declared, so that there is always a known one: 0, 0.0, "" or Null, by its type. If the statement behind it assigns a value that is free of side effects (numbers, strings, variables and arithmetic, never a call, and not behind a condition) the value moves into the declaration: Local a and a = 5 become Local a = 5. That is not done when something in between mentions the variable or sets what the value reads, and never for a call: Create..., Load... and Copy... stay where they are. Arrays and Const are left alone. Off by default. A Global in a function, in a loop or in code with labels: the declaration then sets it again each time it is passed.
implicit-variable fix Local x:Int32 (or the type the name has) in front of the statement of the function that uses the variable first Variables of the main program, which an Include can declare elsewhere. Not fixed at all in code with labels, as a jump back would run the declaration again.
unreachable-code report None: code after Return, End, Goto or Exit can be there on purpose, for example to debug a problem, so it is only reported.
unused-variable fix Removes a Local of a function that is never mentioned again Local of the main program and Global, which other files can use. A variable that is written to is left alone.
unused-function fix Removes the function, if its name is not mentioned again Always: other files can call it.
unused-result report None: dropping a call can drop what it does.

Settings

A setting is --name=value on the command line, name = value in a .blitz-tidy file, or a key of a flat JSON object in blitz-tidy.json. - and _ are the same in names.

Setting Meaning
<rule> off (ignore), report (print only) or fix. --<rule> alone is fix, --no-<rule> is off.
default The mode of every rule that is not set. A rule that has nothing to fix stays at report.
type-notation How types are written: long (the default) writes x:Int32, x:Float32 and x:String instead of x%, x# and x$ (also x%% is x:Int64 and x## is x:Float64), short does the opposite where a character exists (Int/Int32 is %, Long/Int64 %%, Float/Float32/Real #, Double/Float64 ##, String $; x:Byte stays), and keep leaves it alone. .TypeName is left alone: it has no other form. The long form is the one BlitzLLVM prefers. It is the short-type-notation warning of the compiler, which is unchanged. The rules expand-short-to-long-notation and short-type-notation are the old names of this setting (fix is long, off is keep).
unsafe Also make the fixes of the last column of the table.
max-passes How often the file is fixed and compiled again. Default 20.
userlibs-dir Where the userlibs are, like --userlibs-dir of blitzcc. Defaults to $BLITZLLVM_USERLIBS, then to the userlibs of the installation.

Files are rewritten in place and the only output is the name of each file, one per line, followed by the findings that were left in it (the rules set to report and the fixes that were refused). Without files, or with -, the standard input is fixed and the result written to the standard output. --check and --diff change nothing.

Options: -i (does nothing, files are always rewritten in place), -r/--recursive, --check, --diff, -q, --config=FILE, --no-config, --stdin-filepath=PATH, --print-config, --rules, -h/--help and -v/--version. --help and --version print and stop right away (exit code 0), whatever else is on the command line; --version writes blitz-tidy <version>.

-r replaces every directory in the command line with the .bb files below it (.b3d is a 3D model format as well, so it is not used) (any case of the extension, in sorted order, symbolic links to directories are not followed). Each file is fixed with the configuration file that is closest to it. Files named on the command line are always used, whatever their extension, and a directory without -r is an error.

The configuration is read from .blitz-tidy or blitz-tidy.json in the directory of the file, or in the closest directory above it. The command line wins over the file.

# .blitz-tidy
default = fix
implicit-variable = report
unsafe = false
{
	"default": "report",
	"implicit-lossy-real-to-int": "fix",
	"typeless-declaration": "fix"
}

The file is compiled where it is, so what it includes is found, and a copy of it is written next to it for a moment (.blitz-tidy-*.bb).

Warnings · Installation · Differences

Home · Command Index



Differences
Language Features
BlitzBasic
Blitz3D
BlitzPlus

Clone this wiki locally