Skip to content

Don't report SC2218 when another definition's order is unknown - #3520

Open
Eljees wants to merge 1 commit into
koalaman:masterfrom
Eljees:fix/3509-sc2218-unknown-order
Open

Don't report SC2218 when another definition's order is unknown#3520
Eljees wants to merge 1 commit into
koalaman:masterfrom
Eljees:fix/3509-sc2218-unknown-order

Conversation

@Eljees

@Eljees Eljees commented Aug 14, 2026

Copy link
Copy Markdown

Fixes #3509.

Minimal reproduction

The report says the case could not be shrunk below the 1069-line real library. It does reduce, and neither source nor bats is needed:

setup() { f() { true; }; }
f
f() { true; }
In t.sh line 2:
f
^-- SC2218 (error): This function is only defined later. Move the definition up.

The reported shape, with nothing sourced:

#!/usr/bin/env bats
setup() { f() { true; }; }
@test "a" {
  f
}
@test "b" {
  f() { true; }
}

Cause

checkUseBeforeDefinition warns when some definition post-dominates the call and no definition is post-dominated by it. Here there are two definitions: one inside setup's body, one at top level after the call. The top-level one satisfies the first guard; the one in setup satisfies neither relation, because nothing in the script visibly calls setup. So the check concludes "only defined later" while a definition whose order it cannot determine is sitting right there.

That definition may well have run. bats calls setup before every @test, and in an ordinary script a function can be reached through a trap, an indirect call, or a sourcing parent. SC2218 is an error, whereas SC2329 ("This function is never invoked") is only an info, hedged with "or ignored if invoked indirectly", for exactly that reason.

Change

Require every definition to come after the call rather than just one. The second guard stays as it is: inside a loop a definition can both post-dominate the call and be post-dominated by it.

The true positives are unaffected: prop_checkUseBeforeDefinition1 and 5 still fire, 2, 3, 4 and 6 still don't. Two props are added for the two shapes above. Both fail on master and pass with the change, and cabal test is green.

The reporter's original case, with their betteropts.sh, goes from the SC2218 above to exit 0.

checkUseBeforeDefinition warned whenever any definition of a function
post-dominated the call. With two definitions -- one inside a function
body that nothing visibly invokes, one at top level after the call --
the second satisfied that test while the first was ignored, so a call
that may well have been preceded by a definition got reported as being
"only defined later".

That is the shape bats produces: setup() defines helpers, often by
sourcing a library, one @test calls a helper, and a later, unrelated
@test re-sources the same library.

Requiring every definition to come after the call keeps the true
positives and drops this one. A definition whose order we cannot
determine may already have run -- via bats, a trap, an indirect call,
or a sourcing parent -- which is why SC2329 is only an info.

Fixes koalaman#3509
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SC2218 false positive: re-source-ing a library file in a later @test block flags an earlier, correctly-defined function call as "only defined later"

1 participant