Lints - SQF


required_version

Code: L-S01
Default Severity: Error
Minimum Severity: Error

Checks for command usage that requires a newer version than specified in CfgPatches

Example

Incorrect

class CfgPatches {
    class MyAddon {
        units[] = {};
        weapons[] = {};
        requiredVersion = 2.00;
    };
};
private _leaky = getWaterLeakiness vehicle player; // getWaterLeakiness requires 2.16

Check the wiki to see what in version commands were introduced.


event_insufficient_version

Code: L-S02IV
Default Severity: Error
Minimum Severity: Error

Checks for event handlers that require a newer version than specified in CfgPatches

Example

Incorrect

class CfgPatches {
    class MyAddon {
        units[] = {};
        weapons[] = {};
        requiredVersion = 2.00;
    };
};
_this addEventHandler ["OpticsModeChanged", { // Requires 2.10
    hint 'Optics mode changed';
}];

Check the wiki to see what in version events were introduced.


event_unknown

Code: L-S02UE
Default Severity: Warning
Minimum Severity: Warning

Checks for unknown event used in event handlers

Configuration

  • ignore: List of unknown event names to ignore
[lints.sqf.event_unknown]
options.ignore = [
    "HealingReceived",
]

Example

Incorrect

_this addEventHandler ["HealingReceived", { // HealingReceived is not a valid event
    hint 'Healing received';
}];

Check the wiki to see what events are available.


event_incorrect_command

Code: L-S02IC
Default Severity: Error
Minimum Severity: Error

Checks for event handlers used with incorrect commands

Example

Incorrect

_this addEventHandler ["MPHit", {
    hint 'Hit';
}];

Correct

_this addMPEventHandler ["MPHit", {
    hint 'Hit';
}];

static_typename

Code: L-S03
Default Severity: Help
Minimum Severity: Help

Checks for typeName on static values, which can be replaced with the string type directly

Example

Incorrect

if (typeName _myVar == typeName "") then {
    hint "String";
};

Correct

if (typeName _myVar == "STRING") then {
    hint "String";
};

Explanation

typeName is a command that returns the type of a variable. When used on a constant value, it is slower than using the type directly.


command_case

Code: L-S04
Default Severity: Help
Minimum Severity: Help

Checks command usage for casing that matches the wiki

Configuration

  • ignore: An array of commands to ignore
[lints.sqf.command_case]
options.ignore = [
    "ASLtoAGL",
    "AGLtoASL",
]

Example

Incorrect

private _leaky = getwaterleakiness vehicle player;

Correct

private _leaky = getWaterLeakiness vehicle player;

if_assign

Code: L-S05
Default Severity: Help
Minimum Severity: Help

Checks if statements that are used as assignments when select or parseNumber would be more appropriate

Example

Incorrect

private _x = if (_myVar) then {1} else {0};

Correct

private _x = parseNumber _myVar;

Incorrect

private _x = if (_myVar) then {"apple"} else {"orange"};

Correct

private _x = ["orange", "apple"] select _myVar;

Explanation

if statements that are used as assignments and only return a static value can be replaced with the faster select or parseNumber commands.


find_in_str

Code: L-S06
Default Severity: Help
Minimum Severity: Help

Checks for find commands that can be replaced with in

Example

Incorrect

if (_haystack find _needle > -1) ...

Correct

if (_needle in _haystack) ...

Explanation

The in command is faster than find when searching for a substring in a string.


select_parse_number

Code: L-S07
Default Severity: Help
Minimum Severity: Help

Checks for select commands that can be replaced with parseNumber

Example

Incorrect

private _isWater = [0, 1] select (surfaceIsWater getPos player);

Correct

private _isWater = parseNumber (surfaceIsWater getPos player);

Incorrect

private _isLand = [1, 0] select (surfaceIsWater getPos player);

Correct

private _isLand = parseNumber !(surfaceIsWater getPos player);

Explanation

Using select on an array with 0 and 1 can be replaced with parseNumber for better performance.


format_args

Code: L-S08
Default Severity: Error
Minimum Severity: Warning

Checks for format commands with incorrect argument counts

Example

Incorrect

private _text = format ["%1", "Hello", "World"];

Correct

private _text = format ["%1", "Hello World"];

Incorrect

private _text = format ["%1 %2", "Hello World"];

Correct

private _text = format ["%1 %2", "Hello", "World"];

Explanation

The format and formatText commands requires the correct number of arguments to match the format string.


banned_commands

Code: L-S09
Default Severity: Error
Minimum Severity: Warning

Checks for broken or banned commands.

Configuration

  • banned: Additional commands to check for
  • ignore: An array of commands to ignore
[lints.sqf.banned_commands]
options.banned = [
    "execVM",
]
options.ignore = [
    "echo",
]

Example

Incorrect

echo "Hello World"; // Doesn't exist in the retail game

Explanation

Checks for usage of broken or banned commands.


if_not_else

Code: L-S11
Default Severity: Help (Disabled)
Minimum Severity: Help

Checks for unneeded not

Example

Incorrect

if (!alive player) then { player } else { objNull };

Correct

if (alive player) then { objNull } else { player };

! can be removed and else order swapped


var_all_caps

Code: L-S17
Default Severity: Help
Minimum Severity: Help

Checks for global variables that are ALL_CAPS and may actually be a undefined macro

Configuration

  • ignore: An array of vars to ignore
[lints.sqf.var_all_caps]
options.ignore = [
    "XMOD_TEST", "MYMOD_*",
]

Example

Incorrect

private _z = _y + DO_NOT_EXIST;

Explanation

Variables that are all caps are usually reserved for macros. This should should help prevent any accidental typos or uses before definitions when using macros. .


in_vehicle_check

Code: L-S18
Default Severity: Help
Minimum Severity: Help

Recommends using isNull objectParent X instead of vehicle X == X

Example

Incorrect

if (vehicle player == player) then { ... };

Correct

if (isNull objectParent player) then { ... };

Explanation

Using isNull objectParent x is faster and more reliable than vehicle x == x for checking if a unit is currently in a vehicle.


bool_static_comparison

Code: L-S20
Default Severity: Help
Minimum Severity: Help

Checks for a variable being compared to true or false

Example

Incorrect

if (_x == true) then {};
if (_y == false) then {};

Correct

if (_x) then {};
if (!_y) then {};

invalid_comparisons

Code: L-S21
Default Severity: Help
Minimum Severity: Help

Checks for if statements with impossible or overlapping conditions

Example

Incorrect

// This will never be true
if (_x < 20 && _x > 30) then { ... };
// If _x is less than 20, it will also be less than 10
if (_x < 20 && _x < 10) then { ... };

Explanation

This lint checks for if statements with impossible or overlapping conditions. This can be caused by typos or incorrect logic. HEMTT is not able to determine the intent of the code, so it is up to the developer to fix the condition.


this_call

Code: L-S22
Default Severity: Help (Disabled)
Minimum Severity: Help

Checks for usage of _this call, where _this is not necessary

Example

Incorrect

_this call _my_function;

Correct

call _my_function;

Explanation

When using call, the called code will inherit _this from the calling scope. This means that _this is not necessary in the call, and can be omitted for better performance.


reasign_reserved_variable

Code: L-S23
Default Severity: Error
Minimum Severity: Error

Prevents reassigning reserved variables

Example

Incorrect

call {
    _this = 1;
};
{
    private _forEachIndex = random 5;
} forEach allUnits;

Explanation

Reassigning reserved variables can lead to unintentional behavior.


marker_update_spam

Code: L-S24
Default Severity: Help
Minimum Severity: Help

Checks for repeated calls to global marker updates

Example

Incorrect

"my_marker" setMarkerAlpha 0.5;
"my_marker" setMarkerDir 90;
"my_marker" setMarkerSize [100, 200];
"my_marker" setMarkerShape "RECTANGLE";

Correct

"my_marker" setMarkerAlphaLocal 0.5;
"my_marker" setMarkerDirLocal 90;
"my_marker" setMarkerSizeLocal [100, 200];
"my_marker" setMarkerShape "RECTANGLE";

Explanation

The setMarker* commands send the entire state of the marker to all clients. This can be very expensive if done repeatedly.
Using the setMarker*Local on all calls except the last one will reduce the amount of data sent over the network.