diff --git a/ShellCheck/ASTLib.hs b/ShellCheck/ASTLib.hs
index c883fd6..80fad09 100644
--- a/ShellCheck/ASTLib.hs
+++ b/ShellCheck/ASTLib.hs
@@ -308,6 +308,7 @@ isBraceExpansion t = case t of T_BraceExpansion {} -> True; _ -> False
 
 -- Get the lists of commands from tokens that contain them, such as
 -- the body of while loops or branches of if statements.
+getCommandSequences :: Token -> [[Token]]
 getCommandSequences t =
     case t of
         T_Script _ _ cmds -> [cmds]
@@ -318,6 +319,7 @@ getCommandSequences t =
         T_ForIn _ _ _ cmds -> [cmds]
         T_ForArithmetic _ _ _ _ cmds -> [cmds]
         T_IfExpression _ thens elses -> map snd thens ++ [elses]
+        T_Annotation _ _ t -> getCommandSequences t
         _ -> []
 
 -- Get a list of names of associative arrays
diff --git a/ShellCheck/Analytics.hs b/ShellCheck/Analytics.hs
index 909e60f..d153d2b 100644
--- a/ShellCheck/Analytics.hs
+++ b/ShellCheck/Analytics.hs
@@ -63,6 +63,7 @@ treeChecks = [
     ,checkUnassignedReferences
     ,checkUncheckedCdPushdPopd
     ,checkArrayAssignmentIndices
+    ,checkUseBeforeDefinition
     ]
 
 runAnalytics :: AnalysisSpec -> [TokenComment]
@@ -1522,7 +1523,7 @@ prop_subshellAssignmentCheck19 = verifyNotTree subshellAssignmentCheck "#!/bin/b
 subshellAssignmentCheck params t =
     let flow = variableFlow params
         check = findSubshelled flow [("oops",[])] Map.empty
-    in snd $ runWriter check
+    in execWriter check
 
 
 findSubshelled [] _ _ = return ()
@@ -2832,5 +2833,36 @@ checkPipeToNowhere _ t =
             T_FdRedirect _ _ T_HereString {} -> True
             _ -> False
 
+prop_checkUseBeforeDefinition1 = verifyTree checkUseBeforeDefinition "f; f() { true; }"
+prop_checkUseBeforeDefinition2 = verifyNotTree checkUseBeforeDefinition "f() { true; }; f"
+prop_checkUseBeforeDefinition3 = verifyNotTree checkUseBeforeDefinition "if ! mycmd --version; then mycmd() { true; }; fi"
+prop_checkUseBeforeDefinition4 = verifyNotTree checkUseBeforeDefinition "mycmd || mycmd() { f; }"
+checkUseBeforeDefinition _ t =
+    execWriter $ evalStateT (mapM_ examine $ revCommands) Map.empty
+  where
+    examine t = case t of
+        T_Pipeline _ _ [T_Redirecting _ _ (T_Function _ _ _ name _)] ->
+            modify $ Map.insert name t
+        T_Annotation _ _ w -> examine w
+        T_Pipeline _ _ cmds -> do
+            m <- get
+            unless (Map.null m) $
+                mapM_ (checkUsage m) $ concatMap recursiveSequences cmds
+        _ -> return ()
+
+    checkUsage map cmd = potentially $ do
+        name <- getCommandName cmd
+        def <- Map.lookup name map
+        return $
+            err (getId cmd) 2218
+                "This function is only defined later. Move the definition up."
+
+    revCommands = reverse $ concat $ getCommandSequences t
+    recursiveSequences x =
+        let list = concat $ getCommandSequences x in
+            if null list
+            then [x]
+            else concatMap recursiveSequences list
+
 return []
 runTests =  $( [| $(forAllProperties) (quickCheckWithResult (stdArgs { maxSuccess = 1 }) ) |])