Skip to content

undeclared-reference misses never-created resources in field values and command targets #60

Description

@djankov

Summary

The undeclared-reference rule does not flag a reference to a resource that is never created anywhere in the script when that reference appears as:

  • a resource-field object value — e.g. Prop.FM = FM where no Create ... FM exists; or
  • a mission-sequence command target — e.g. Maneuver ghostBurn(Sat) where no Create ... ghostBurn exists.

Both lint clean, even though both are genuine errors (GMAT rejects them at load). A hallucinated or typo'd resource name is one of the most common defects in machine-generated scripts, and undeclared-reference is the natural guard for it, so this gap matters when using the linter as a static, GMAT-free pre-flight gate.

Reproduction (gmat-script 0.3.0)

from gmat_script import lint

# A — undeclared resource in a field value
lint("Create Spacecraft Sat;\nCreate Propagator Prop;\nProp.FM = FM;\n"
     "BeginMissionSequence;\nPropagate Prop(Sat) {Sat.ElapsedSecs = 60};\n")
# -> []   (expected: undeclared-reference ERROR on FM)

# B — undeclared resource as a command target
lint("Create Spacecraft Sat;\nBeginMissionSequence;\nManeuver ghostBurn(Sat);\n")
# -> []   (expected: undeclared-reference ERROR on ghostBurn)

Not a catalogue / resolution problem

The related ref-target-mismatch rule resolves resource types correctly, so the type information is available:

lint("Create Spacecraft Sat;\nCreate Propagator Prop;\nSat.Tanks = {Prop};\n"
     "BeginMissionSequence;\nPropagate Prop(Sat) {Sat.ElapsedSecs=60};\n")
# -> [('ref-target-mismatch', 'WARNING')]   # fires as expected

So the gap is in undeclared-reference's scoping, not in reference resolution generally.

Why it's conservative today, and the distinction that fixes it

The rule appears to deliberately avoid false positives on forward references (a resource referenced before its own Create, which is legal in GMAT) and on builtin/plugin names — and as a result it does not flag references in these positions at all.

The distinguishing test is whole-file, not positional:

  • a name created somewhere in the file (before or after the reference) → legal forward reference, do not flag;
  • a name never created anywhere (and not a builtin / plugin / allow-listed name) → genuine undeclared reference, flag.

A two-pass approach — collect every Created name across the whole script, then flag object references (field values and command targets) whose name is in neither that set nor the builtin/plugin allow-lists — would catch the never-created case without regressing the legitimate forward-reference allowance.

Impact

Low severity in isolation — a downstream dynamic check (a GMAT load / dry-run) still catches these — but it's a hole in the one rule meant to catch hallucinated or typo'd resource names, which is the highest-value class for static, GMAT-free validation of generated scripts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions