Skip to content

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

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

Labels

No labels
No labels

Type

Fields

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions