@@ -123,6 +123,7 @@ nodeChecks = [
123123 ,checkCaseAgainstGlob
124124 ,checkCommarrays
125125 ,checkOrNeq
126+ ,checkAndEq
126127 ,checkEchoWc
127128 ,checkConstantIfs
128129 ,checkPipedAssignment
@@ -1634,6 +1635,64 @@ checkOrNeq _ (T_OrIf id lhs rhs) = sequence_ $ do
16341635checkOrNeq _ _ = return ()
16351636
16361637
1638+ prop_checkAndEq1 = verifyNot checkAndEq " cow=0; foo=0; if [[ $lol -eq cow && $lol -eq foo ]]; then echo foo; fi"
1639+ prop_checkAndEq2 = verifyNot checkAndEq " lol=0 foo=0; (( a==lol && a==foo ))"
1640+ prop_checkAndEq3 = verify checkAndEq " [ \" $a\" = lol && \" $a\" = foo ]"
1641+ prop_checkAndEq4 = verifyNot checkAndEq " [ a = $cow && b = $foo ]"
1642+ prop_checkAndEq5 = verifyNot checkAndEq " [[ $a = /home && $a = */public_html/* ]]"
1643+ prop_checkAndEq6 = verify checkAndEq " [ $a = a ] && [ $a = b ]"
1644+ prop_checkAndEq7 = verify checkAndEq " [ $a = a ] && [ $a = b ] || true"
1645+ prop_checkAndEq8 = verifyNot checkAndEq " [[ $a == x && $a == x ]]"
1646+ prop_checkAndEq9 = verifyNot checkAndEq " [ 0 -eq $FOO ] && [ 0 -eq $BAR ]"
1647+ prop_checkAndEq10 = verify checkAndEq " (( a == 1 && a == 2 ))"
1648+ prop_checkAndEq11 = verify checkAndEq " [ $x -eq 1 ] && [ $x -eq 2 ]"
1649+ prop_checkAndEq12 = verify checkAndEq " [ 1 -eq $x ] && [ $x -eq 2 ]"
1650+ prop_checkAndEq13 = verifyNot checkAndEq " [ 1 -eq $x ] && [ $x -eq 1 ]"
1651+ prop_checkAndEq14 = verifyNot checkAndEq " [ $a = $b ] && [ $a = $c ]"
1652+
1653+ checkAndEqOperands " -eq" rhs1 rhs2 = isLiteralNumber rhs1 && isLiteralNumber rhs2
1654+ checkAndEqOperands op rhs1 rhs2 | op == " =" || op == " ==" = isLiteral rhs1 && isLiteral rhs2
1655+ checkAndEqOperands _ _ _ = False
1656+
1657+ -- For test-level "and": [ x = y -a x = z ]
1658+ checkAndEq _ (TC_And id typ op (TC_Binary _ _ op1 lhs1 rhs1 ) (TC_Binary _ _ op2 lhs2 rhs2))
1659+ | op1 == op2 && lhs1 == lhs2 && rhs1 /= rhs2 && checkAndEqOperands op1 rhs1 rhs2 =
1660+ warn id 2333 $ " You probably wanted " ++ (if typ == SingleBracket then " -o" else " ||" ) ++ " here, otherwise it's always false."
1661+
1662+ -- For arithmetic context "and"
1663+ checkAndEq _ (TA_Binary id " &&" (TA_Binary _ " ==" lhs1 rhs1) (TA_Binary _ " ==" lhs2 rhs2))
1664+ | lhs1 == lhs2 && isLiteralNumber rhs1 && isLiteralNumber rhs2 =
1665+ warn id 2334 " You probably wanted || here, otherwise it's always false."
1666+
1667+ -- For command level "and": [ x = y ] && [ x = z ]
1668+ checkAndEq _ (T_AndIf id lhs rhs) = sequence_ $ do
1669+ (lhs1, op1, rhs1) <- getExpr lhs
1670+ (lhs2, op2, rhs2) <- getExpr rhs
1671+ guard $ op1 == op2
1672+ guard $ lhs1 == lhs2 && rhs1 /= rhs2
1673+ guard $ checkAndEqOperands op1 rhs1 rhs2
1674+ return $ warn id 2333 " You probably wanted || here, otherwise it's always false."
1675+ where
1676+ getExpr x =
1677+ case x of
1678+ T_AndIf _ lhs _ -> getExpr lhs -- Fetches x and y in `T_AndIf x (T_AndIf y z)`
1679+ T_Pipeline _ _ [x] -> getExpr x
1680+ T_Redirecting _ _ c -> getExpr c
1681+ T_Condition _ _ c -> getExpr c
1682+ TC_Binary _ _ op lhs rhs -> orient (lhs, op, rhs)
1683+ _ -> Nothing
1684+
1685+ -- Swap items so that the constant side is rhs (or Nothing if both/neither is constant)
1686+ orient (lhs, op, rhs) =
1687+ case (isConstant lhs, isConstant rhs) of
1688+ (True , False ) -> return (rhs, op, lhs)
1689+ (False , True ) -> return (lhs, op, rhs)
1690+ _ -> Nothing
1691+
1692+
1693+ checkAndEq _ _ = return ()
1694+
1695+
16371696prop_checkValidCondOps1 = verify checkValidCondOps " [[ a -xz b ]]"
16381697prop_checkValidCondOps2 = verify checkValidCondOps " [ -M a ]"
16391698prop_checkValidCondOps2a = verifyNot checkValidCondOps " [ 3 \\ > 2 ]"
0 commit comments