Skip to content

--reorder-code detaches per-function @warning_ignore(...) from its function in scripts without a class_name/extends header #242

@minami110

Description

@minami110

Summary

When a script has no class_name and no extends header (an implicit RefCounted script that begins directly with members), --reorder-code treats a per-function @warning_ignore("...") decorator as a standalone/script-level annotation and detaches it from its function. The function silently loses its warning suppression, and with multiple functions the annotations pile up at the top of the file.

Adding any class header (extends RefCounted, extends Node, or class_name Foo) makes the problem disappear. The output also passes --safe (exit 0), so safe mode does not catch it.

Version

  • gdscript-formatter 0.20.1

Minimal reproduction

A. Single function — annotation separated from its function

Input:

@warning_ignore("unused_parameter")
func do_thing(value: int) -> void:
      pass

gdscript-formatter --reorder-code output:

@warning_ignore("unused_parameter")


func do_thing(value: int) -> void:
      pass

The annotation is pushed two blank lines away from do_thing, i.e. parsed as a top-level annotation instead of a decorator on the function.

B. Two functions — a function silently loses its suppression

Input:

@warning_ignore("unused_parameter")
func _helper(value: int) -> void:
      pass


@warning_ignore("unused_parameter")
func do_thing(value: int) -> void:
      pass

gdscript-formatter --reorder-code output:

@warning_ignore("unused_parameter")
@warning_ignore("unused_parameter")


func do_thing(value: int) -> void:
      pass


func _helper(value: int) -> void:
      pass

Both annotations are hoisted and stacked at the top of the file, detached from their functions. _helper now has no @warning_ignore (lost its suppression); do_thing effectively receives both. The more annotated functions a script has, the more annotations accumulate at the top.

Expected

The @warning_ignore("...") decorator should move with its function during reordering and stay directly attached to it — exactly as it does when the script has a header. Adding extends RefCounted produces the correct result:

Input:

extends RefCounted

@warning_ignore("unused_parameter")
func _helper(value: int) -> void:
      pass


@warning_ignore("unused_parameter")
func do_thing(value: int) -> void:
      pass

Output (correct — each annotation stays on its function):

extends RefCounted


@warning_ignore("unused_parameter")
func do_thing(value: int) -> void:
      pass


@warning_ignore("unused_parameter")
func _helper(value: int) -> void:
      pass

Trigger condition (isolated)

Header Result
no class_name, no extends bug reproduces
extends RefCounted / extends Node / … OK
class_name Foo only OK
class_name Foo + extends … OK

The trigger is specifically a header-less script. It does not depend on the warning name or the parameter name, and it reproduces even with a single function (no actual reordering required, as in example A).

Notes / related

  • --safe does not reject this; the buggy output passes --reorder-code --safe.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions