Skip to content

3. Linter

Pawel Lampe edited this page Nov 18, 2023 · 3 revisions

gdlint is a static code analysis tool used to find potential problems in GDScript code.

For each provided file, this tool executes two phases in order:

  1. It parses the file thus checking if the code conforms to GDScript syntax
  2. It runs various predefined checks against the code

Linting with gdlint

To run a linter, just execute the gdlint command with some files as arguments e.g.:

$ gdlint misc/MarkovianPCG.gd

The command's exit code is 0 if both - parsing succeeded and checks were successful. Any lines in stdout mean that there were some problems found like e.g.:

misc/MarkovianPCG.gd:96: Error: Function argument name "aOrigin" is not valid (function-argument-name)
misc/MarkovianPCG.gd:96: Error: Function argument name "aPos" is not valid (function-argument-name)

Disabling checks on demand

In case of gdlint bugs or work-in-progress code it may be necessary to disable some checks. Each check can be disabled single time using gdlint:ignore comment:

# gdlint:ignore = function-name , function-argument-name
func SomeWrongName(someArg):
    assert(someArg > 0)

In case some checks must be disabled in larger file area, the gdlint: disable (with optional gdlint: enable) comment may be used:

# gdlint: disable=function-name
func SomeWrongName():
    pass
# gdlint: enable=function-name

Tweaking default check settings

To tweak the default check settings, you can dump the default config to a file:

$ gdlint -d
$ cat gdlintrc
class-load-variable-name: (([A-Z][a-z0-9]*)+|_?[a-z][a-z0-9]*(_[a-z0-9]+)*)
class-name: ([A-Z][a-z0-9]*)+
class-variable-name: _?[a-z][a-z0-9]*(_[a-z0-9]+)*
constant-name: '[A-Z][A-Z0-9]*(_[A-Z0-9]+)*'
disable: []
enum-element-name: '[A-Z][A-Z0-9]*(_[A-Z0-9]+)*'
enum-name: ([A-Z][a-z0-9]*)+
function-argument-name: _?[a-z][a-z0-9]*(_[a-z0-9]+)*
function-arguments-number: 10
function-preload-variable-name: ([A-Z][a-z0-9]*)+
function-name: (_on_([A-Z][a-z0-9]*)+(_[a-z0-9]+)*|_?[a-z][a-z0-9]*(_[a-z0-9]+)*)
function-variable-name: '[a-z][a-z0-9]*(_[a-z0-9]+)*'
load-constant-name: (([A-Z][a-z0-9]*)+|[A-Z][A-Z0-9]*(_[A-Z0-9]+)*)
loop-variable-name: _?[a-z][a-z0-9]*(_[a-z0-9]+)*
signal-name: '[a-z][a-z0-9]*(_[a-z0-9]+)*'
sub-class-name: _?([A-Z][a-z0-9]*)+

Once the dump is performed, you can modify the gdlintrc file and optionally rename it to .gdlintrc. From now on, linter will use this config file to override the default config.

Checks

The linter checks are divided into categories:

  • name checks - the checks which are checking the naming conventions as per GDScript style guide
  • basic checks - checks for very basic problems
  • class checks - checks for problems related to classes
  • design checks - checks for problems related to classes/functions design
  • format checks - checks for file structure problems
  • misc checks - other checks

Name checks

  • function-name - validates if function name conforms to snake_case, _private_snake_case, or _on_PascalCase_snake_case.
  • class-name - validates if class name conforms to PascalCase.
  • sub-class-name - validates if class name conforms to _PrivatePascalCase.
  • signal-name - validates if signal name conforms to PascalCase.
  • class-variable-name - validates if class variable name conforms to snake_case or _private_snake_case.
  • class-load-variable-name - validates if class load variable (var variable = load(...)) name conforms to PascalCase, snake_case or private_snake_case.
  • function-variable-name - validates if function variable name conforms to snake_case.
  • function-preload-variable-name - validates if function preload variable (var Variable = preload(...)) name conforms to PascalCase.
  • function-argument-name - validates if function argument (formal parameter) name conforms to snake_case or _private_snake_case.
  • loop-variable-name - validates if loop variable name conforms to snake_case or _private_snake_case.
  • enum-name - validates if enum name conforms to PascalCase.
  • enum-element-name - validates if enum element name conforms to UPPER_SNAKE_CASE.
  • constant-name- validates if constant name conforms to UPPER_SNAKE_CASE.
  • load-constant-name - validates if load constant (const constant = load(...)) name conforms to PascalCase, snake_case or private_snake_case.

Basic checks

  • duplicated-load - copy-pasted load(...) for the same path e.g. load("res://asdf.tscn") in multiple places. To fix, simply extract string to constant.
  • expression-not-assigned - standalone expression like 1 + 1 which is not used in any way. To fix, simply remove that expression.
  • unnecessary-pass - pass which is not the only expression on class or function body. To fix, simple remove that pass statement.
  • unused-argument - unused funtion argument. To fix, simply remove it or mark as explicitly unused by prefixing with underscore _ e.g. _unused_arg.
  • comparison-with-itself - redundant comparison like e.g. x == x which is always true. To fix, simply remove that expression.

Class checks

  • private-method-call - private (prefixed with underscore _) function was called. E.g. player._private_func(). To fix, redesign your approach so that private function is not being called.
  • class-definitions-order - class statements are not in order. The order should be:
    • tool
    • classname
    • extends
    • signals
    • enums
    • constants
    • exports
    • public variables
    • private variables (prefixed with underscore _)
    • onready public variables
    • onready private variables (prefixed with underscore _)
    • other statements

Design checks

  • max-public-methods - validates maximum number of public methods (class-level functions).
  • function-arguments-number - validates number of function arguments.

Format checks

  • max-file-lines - validates maximum number of file lines.
  • trailing-whitespace - validates if any trailing whitespaces are present.
  • max-line-length - validates maxium line length for each line.
  • mixed-tabs-and-spaces - validates if either only tabs or only spaces are used for indentation.

Misc checks

  • no-elif-return - validates if unnecessary elif is present in case if body was ended with return.
  • no-else-return - validates if unnecessary else is present in case if (and each elif) body was ended with return.