Skip to content

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" #3509

Description

@jakub-bochenski

ShellCheck version: 0.11.0 (shellcheck --version)

Summary

In a .bats test file, setup() sources a library file once, defining (among others) a function _bo_parse. The very first @test block calls _bo_parse — at that point it has unambiguously already been defined, by setup(), which bats runs before every test. A later, separate @test block re-sources the same library file mid-body (e.g. to layer extra fixture state on top of setup()'s). That later, unrelated re-source makes ShellCheck retroactively flag the earlier test's call to _bo_parse as SC2218 ("This function is only defined later. Move the definition up."), even though nothing about that earlier test changed.

Removing the later re-source call makes the false positive disappear without changing the flagged test at all.

Reproduction

This is a real project's library (betteropts.sh, ~1069 lines, plain bash, no bashisms beyond ordinary functions/arrays), sourced as-is. I was not able to shrink it down to a small synthetic stand-in — a small hand-written library with the same shape (a handful of functions, one defined well after the others, sourced twice across two @test blocks) did not reproduce this, so whatever triggers it seems tied to some property of a larger/more complex sourced file, not just "any function sourced twice." I'm filing the observed case as-is rather than guessing at that mechanism.

Library: https://raw.githubusercontent.com/VirtusLab/betteropts/5be1b58f92287045f6d61d817f22b4f564ecd302/betteropts.sh
(save as betteropts.sh next to the test file below)

t.bats:

#!/usr/bin/env bats

setup() {
  # shellcheck source=./betteropts.sh
  source "$BATS_TEST_DIRNAME/betteropts.sh"
  flag verbose -v --verbose
}

@test "long flag is marked provided" {
  _bo_parse --verbose
}

@test "a later test re-sources betteropts.sh mid-body" {
  # shellcheck source=./betteropts.sh
  source "$BATS_TEST_DIRNAME/betteropts.sh"
  argument files variadic
}

Run: shellcheck -x t.bats

In t.bats line 10:
  _bo_parse --verbose
  ^-----------------^ SC2218 (error): This function is only defined later. Move the definition up.

Expected

No warning. _bo_parse is defined in setup(), which runs before every @test block including the first one; nothing about the second, unrelated @test block's re-source should retroactively affect analysis of the first.

What makes it go away

Deleting the second @test block's source line entirely (or deleting the whole second @test block) makes the warning disappear with nothing else changed:

#!/usr/bin/env bats

setup() {
  # shellcheck source=./betteropts.sh
  source "$BATS_TEST_DIRNAME/betteropts.sh"
  flag verbose -v --verbose
}

@test "long flag is marked provided" {
  _bo_parse --verbose
}

shellcheck -x t.bats → clean, exit 0.

Notes

  • Found via bisection on a real ~250-line .bats file where 15 call sites across many @test blocks were all flagged as SC2218 for functions (_bo_parse, _bo_assign_positionals) that are unambiguously defined by a source in setup(). Removing 11 mid-body re-source calls scattered through later tests (added to layer extra fixture state onto the shared setup()) dropped the count from 15 to 0 with no other change.
  • This may be related to the general class of bug in Exporting the same variable with bats causes spurious SC2030 SC2031 warnings #3263 and Bogus SC2030/SC2031 (regression in 0.8.0?) #2431 (both about SC2030/2031 false positives from something being repeated across @test blocks in a .bats file), but the reported check here is SC2218, a different check with presumably different internal logic, so I'm filing it separately rather than assuming it shares a fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions