Godot · GDScript

Dead code, found and gone.

gdlint reads every script in your Godot project — and every scene and autoload entry that could be pointing at one — then tells you what nothing references. Leftover prints, orphaned .gd.uid files and dynamic has_method() calls too. Run it with -fix and it takes them out.

go install github.com/aviorstudio/gdlint@latest

Go · one static binary · Linux, macOS and Windows

gdlint / godot_client
$ gdlint
=== ERRORS (will be removed with -fix) ===

Unused files: 3
  • addon/autoload.gd
  • addon/plugin.gd
  • addon/src/core/router.gd

Print statements: 1
  • addon/plugin.gd:59: print("GD Router: Created route map at %s." % RouteMapGenera...

Orphaned UID files: 2
  • addon/src/route_transition_util.gd.uid
  • addon/src/router_service.gd.uid

❌ has_method() calls (ALWAYS ERRORS): 2
  • addon/src/core/router.gd:121: if not route.guard.has_method("can_enter"):
  • addon/src/core/router.gd:131: if not host.has_method("mount_route"):

Explicit Variant usages (disallowed once enabled): 1
  • addon/src/core/router.gd:99: func get_param(key: String, default: Variant = null) -> Vari...

=== SUMMARY ===
❌ 9 errors found
   Run with -fix to remove all errors
exit 1 errors block-warn adds the warnings-fix removes the errors
01

It knows what it is not

gdlint has no opinion on your directory names, your required sibling files, which layer may import which, or who owns an autoload. Those rules are yours and they change per project — a hygiene checker that guessed at them would be wrong in every repo but the one it was written in.

02

Unused means nothing points at it

Before a script is called dead, gdlint follows preload, load and file-path extends through every .gd, the ext_resource and script paths inside every .tscn, and the autoload list in project.godot. A scene referencing a script counts, even when no code does.

03

Four rules on, the rest asked for

A project with no config gets prints, stray pass, orphaned .gd.uid files and tab indentation. Everything else stays quiet until gdlint.json switches it on, because the rest is house style and gdlint does not know yours yet.

gdlint init

Every rule, and what it ships as.

gdlint init writes this list into gdlint.json with the defaults below. Errors block and exit non-zero; warnings only appear under -warn. Files can be excluded wholesale, or only from the unused-code rules, or only from the Variant rule.

-fix acts on the errors — it deletes functions, signals, constants and whole files that static analysis believes are unused. Reflection, a string-built call() or a resource path assembled at runtime is invisible to it. Turn the unused rules on, read what they report, and keep the change reviewable.

Rule Catches Default
print_statements print() and debug output left behind on
pass_statements pass in a body that already has statements on
orphaned_uids a .gd.uid whose script is gone on
indentation spaces where GDScript indents with tabs on
unused_functions functions nothing calls off
unused_signals signals nothing connects or emits off
unused_constants constants nothing reads off
unused_enums enums and enum values nothing reads off
unused_class_names class_name nothing refers to off
unused_files scripts no script, scene or autoload points at off
comments comments outside the allowed prefixes off
has_method dynamic dispatch instead of a typed call off
variant_usage explicit Variant in a signature off
missing_return_types public functions with no return annotation off
single_use_functions warning functions with exactly one caller off
empty_functions warning functions with nothing in them off

Ship what you use.
Not what you wrote.

PROJECT.GODOTEVERY .GD AND .TSCNWHAT NOTHING NEEDS