From 9329e4d0159a141b33c2c38aae3b76eb2df8c1dd Mon Sep 17 00:00:00 2001 From: Eljees <3.14hell@gmail.com> Date: Fri, 14 Aug 2026 06:45:19 +0000 Subject: [PATCH] Don't report SC2218 when another definition's order is unknown 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 #3509 --- src/ShellCheck/Analytics.hs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ShellCheck/Analytics.hs b/src/ShellCheck/Analytics.hs index f6208e72b..effe7e728 100644 --- a/src/ShellCheck/Analytics.hs +++ b/src/ShellCheck/Analytics.hs @@ -3901,6 +3901,8 @@ prop_checkUseBeforeDefinition3 = verifyNotTree checkUseBeforeDefinition "if ! my prop_checkUseBeforeDefinition4 = verifyNotTree checkUseBeforeDefinition "mycmd || mycmd() { f; }" prop_checkUseBeforeDefinition5 = verifyTree checkUseBeforeDefinition "false || mycmd; mycmd() { f; }" prop_checkUseBeforeDefinition6 = verifyNotTree checkUseBeforeDefinition "f() { one; }; f; f() { two; }; f" +prop_checkUseBeforeDefinition7 = verifyNotTree checkUseBeforeDefinition "setup() { f() { true; }; }; f; f() { true; }" +prop_checkUseBeforeDefinition8 = verifyNotTree checkUseBeforeDefinition "#!/usr/bin/env bats\nsetup() { f() { true; }; }\n@test \"a\" {\n f\n}\n@test \"b\" {\n f() { true; }\n}" checkUseBeforeDefinition :: Parameters -> Token -> [TokenComment] checkUseBeforeDefinition params t = fromMaybe [] $ do cfga <- cfgAnalysis params @@ -3920,7 +3922,10 @@ checkUseBeforeDefinition params t = fromMaybe [] $ do name <- getLiteralString cmd invocations <- Map.lookup name funcs -- Is the function definitely being defined later? - guard $ any (\c -> CF.doesPostDominate cfga c id) invocations + -- Every definition has to be later: one whose order we can't + -- determine, such as in a function nothing visibly invokes, + -- may already have run. + guard $ all (\c -> CF.doesPostDominate cfga c id) invocations -- Was one already defined, so it's actually a re-definition? guard . not $ any (\c -> CF.doesPostDominate cfga id c) invocations return $ err id 2218 "This function is only defined later. Move the definition up."