| 1838 | } |
| 1839 | |
| 1840 | void CheckConditionImpl::checkDuplicateConditionalAssign() |
| 1841 | { |
| 1842 | if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("duplicateConditionalAssign")) |
| 1843 | return; |
| 1844 | |
| 1845 | logChecker("CheckCondition::checkDuplicateConditionalAssign"); // style |
| 1846 | |
| 1847 | const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); |
| 1848 | for (const Scope *scope : symbolDatabase->functionScopes) { |
| 1849 | for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { |
| 1850 | if (!Token::simpleMatch(tok, "if (")) |
| 1851 | continue; |
| 1852 | if (!Token::simpleMatch(tok->linkAt(1), ") {")) |
| 1853 | continue; |
| 1854 | const Token *blockTok = tok->linkAt(1)->next(); |
| 1855 | const Token *condTok = tok->next()->astOperand2(); |
| 1856 | const bool isBoolVar = Token::Match(condTok, "!| %var%"); |
| 1857 | if (!isBoolVar && !Token::Match(condTok, "==|!=")) |
| 1858 | continue; |
| 1859 | if ((isBoolVar || condTok->str() == "!=") && Token::simpleMatch(blockTok->link(), "} else {")) |
| 1860 | continue; |
| 1861 | if (!blockTok->next()) |
| 1862 | continue; |
| 1863 | const Token *assignTok = blockTok->next()->astTop(); |
| 1864 | if (!Token::simpleMatch(assignTok, "=")) |
| 1865 | continue; |
| 1866 | if (nextAfterAstRightmostLeaf(assignTok) != blockTok->link()->previous()) |
| 1867 | continue; |
| 1868 | bool isRedundant = false; |
| 1869 | if (isBoolVar) { |
| 1870 | const bool isNegation = condTok->str() == "!"; |
| 1871 | const Token* const varTok = isNegation ? condTok->next() : condTok; |
| 1872 | const ValueType* vt = varTok->variable() ? varTok->variable()->valueType() : nullptr; |
| 1873 | if (!(vt && vt->type == ValueType::Type::BOOL && !vt->pointer)) |
| 1874 | continue; |
| 1875 | |
| 1876 | if (!(assignTok->astOperand1() && assignTok->astOperand1()->varId() == varTok->varId())) |
| 1877 | continue; |
| 1878 | if (!(assignTok->astOperand2() && assignTok->astOperand2()->hasKnownIntValue())) |
| 1879 | continue; |
| 1880 | const MathLib::bigint val = assignTok->astOperand2()->getKnownIntValue(); |
| 1881 | if (val < 0 || val > 1) |
| 1882 | continue; |
| 1883 | isRedundant = (isNegation && val == 0) || (!isNegation && val == 1); |
| 1884 | } else { // comparison |
| 1885 | if (!isSameExpression( |
| 1886 | true, condTok->astOperand1(), assignTok->astOperand1(), mSettings, true, true)) |
| 1887 | continue; |
| 1888 | if (!isSameExpression( |
| 1889 | true, condTok->astOperand2(), assignTok->astOperand2(), mSettings, true, true)) |
| 1890 | continue; |
| 1891 | } |
| 1892 | duplicateConditionalAssignError(condTok, assignTok, isRedundant); |
| 1893 | } |
| 1894 | } |
| 1895 | } |
| 1896 | |
| 1897 | void CheckConditionImpl::duplicateConditionalAssignError(const Token *condTok, const Token* assignTok, bool isRedundant) |
no test coverage detected