@@ -123,6 +123,7 @@ nodeChecks = [
123
123
,checkCaseAgainstGlob
124
124
,checkCommarrays
125
125
,checkOrNeq
126
+ ,checkAndEq
126
127
,checkEchoWc
127
128
,checkConstantIfs
128
129
,checkPipedAssignment
@@ -1631,6 +1632,55 @@ checkOrNeq _ (T_OrIf id lhs rhs) = sequence_ $ do
1631
1632
checkOrNeq _ _ = return ()
1632
1633
1633
1634
1635
+ prop_checkAndEq1 = verify checkAndEq " if [[ $lol -eq cow && $lol -eq foo ]]; then echo foo; fi"
1636
+ prop_checkAndEq2 = verify checkAndEq " (( a==lol && a==foo ))"
1637
+ prop_checkAndEq3 = verify checkAndEq " [ \" $a\" = lol && \" $a\" = foo ]"
1638
+ prop_checkAndEq4 = verifyNot checkAndEq " [ a = $cow && b = $foo ]"
1639
+ prop_checkAndEq5 = verifyNot checkAndEq " [[ $a = /home && $a = */public_html/* ]]"
1640
+ prop_checkAndEq6 = verify checkAndEq " [ $a = a ] && [ $a = b ]"
1641
+ prop_checkAndEq7 = verify checkAndEq " [ $a = a ] && [ $a = b ] || true"
1642
+ prop_checkAndEq8 = verifyNot checkAndEq " [[ $a == x && $a == x ]]"
1643
+ prop_checkAndEq9 = verifyNot checkAndEq " [ 0 -eq $FOO ] && [ 0 -eq $BAR ]"
1644
+
1645
+ -- For test-level "and": [ x = y -a x = z ]
1646
+ checkAndEq _ (TC_And id typ op (TC_Binary _ _ op1 lhs1 rhs1 ) (TC_Binary _ _ op2 lhs2 rhs2))
1647
+ | (op1 == op2 && (op1 == " -eq" || op1 == " =" || op1 == " ==" )) && lhs1 == lhs2 && rhs1 /= rhs2 && not (any isGlob [rhs1,rhs2]) =
1648
+ warn id 2055 $ " You probably wanted " ++ (if typ == SingleBracket then " -o" else " ||" ) ++ " here, otherwise it's always false."
1649
+
1650
+ -- For arithmetic context "and"
1651
+ checkAndEq _ (TA_Binary id " &&" (TA_Binary _ " ==" word1 _) (TA_Binary _ " ==" word2 _))
1652
+ | word1 == word2 =
1653
+ warn id 2056 " You probably wanted || here, otherwise it's always false."
1654
+
1655
+ -- For command level "and": [ x = y ] && [ x = z ]
1656
+ checkAndEq _ (T_AndIf id lhs rhs) = sequence_ $ do
1657
+ (lhs1, op1, rhs1) <- getExpr lhs
1658
+ (lhs2, op2, rhs2) <- getExpr rhs
1659
+ guard $ op1 == op2 && op1 `elem` [" -eq" , " =" , " ==" ]
1660
+ guard $ lhs1 == lhs2 && rhs1 /= rhs2
1661
+ guard . not $ any isGlob [rhs1, rhs2]
1662
+ return $ warn id 2252 " You probably wanted || here, otherwise it's always false."
1663
+ where
1664
+ getExpr x =
1665
+ case x of
1666
+ T_AndIf _ lhs _ -> getExpr lhs -- Fetches x and y in `T_AndIf x (T_AndIf y z)`
1667
+ T_Pipeline _ _ [x] -> getExpr x
1668
+ T_Redirecting _ _ c -> getExpr c
1669
+ T_Condition _ _ c -> getExpr c
1670
+ TC_Binary _ _ op lhs rhs -> orient (lhs, op, rhs)
1671
+ _ -> Nothing
1672
+
1673
+ -- Swap items so that the constant side is rhs (or Nothing if both/neither is constant)
1674
+ orient (lhs, op, rhs) =
1675
+ case (isConstant lhs, isConstant rhs) of
1676
+ (True , False ) -> return (rhs, op, lhs)
1677
+ (False , True ) -> return (lhs, op, rhs)
1678
+ _ -> Nothing
1679
+
1680
+
1681
+ checkAndEq _ _ = return ()
1682
+
1683
+
1634
1684
prop_checkValidCondOps1 = verify checkValidCondOps " [[ a -xz b ]]"
1635
1685
prop_checkValidCondOps2 = verify checkValidCondOps " [ -M a ]"
1636
1686
prop_checkValidCondOps2a = verifyNot checkValidCondOps " [ 3 \\ > 2 ]"
0 commit comments