Improve valueflow after pushing to container (#4803)
This commit is contained in:
parent
91d2526c41
commit
346ecdb53a
|
@ -587,7 +587,7 @@ QString ProjectFileDialog::getImportProject() const
|
||||||
|
|
||||||
void ProjectFileDialog::addIncludeDir(const QString &dir)
|
void ProjectFileDialog::addIncludeDir(const QString &dir)
|
||||||
{
|
{
|
||||||
if (dir.isNull() || dir.isEmpty())
|
if (dir.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QString newdir = QDir::toNativeSeparators(dir);
|
const QString newdir = QDir::toNativeSeparators(dir);
|
||||||
|
@ -598,7 +598,7 @@ void ProjectFileDialog::addIncludeDir(const QString &dir)
|
||||||
|
|
||||||
void ProjectFileDialog::addCheckPath(const QString &path)
|
void ProjectFileDialog::addCheckPath(const QString &path)
|
||||||
{
|
{
|
||||||
if (path.isNull() || path.isEmpty())
|
if (path.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QString newpath = QDir::toNativeSeparators(path);
|
const QString newpath = QDir::toNativeSeparators(path);
|
||||||
|
@ -609,7 +609,7 @@ void ProjectFileDialog::addCheckPath(const QString &path)
|
||||||
|
|
||||||
void ProjectFileDialog::addExcludePath(const QString &path)
|
void ProjectFileDialog::addExcludePath(const QString &path)
|
||||||
{
|
{
|
||||||
if (path.isNull() || path.isEmpty())
|
if (path.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QString newpath = QDir::toNativeSeparators(path);
|
const QString newpath = QDir::toNativeSeparators(path);
|
||||||
|
|
|
@ -2863,10 +2863,52 @@ int getArgumentPos(const Variable* var, const Function* f)
|
||||||
return std::distance(f->argumentList.cbegin(), arg_it);
|
return std::distance(f->argumentList.cbegin(), arg_it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Token* getIteratorExpression(const Token* tok)
|
||||||
|
{
|
||||||
|
if (!tok)
|
||||||
|
return nullptr;
|
||||||
|
if (tok->isUnaryOp("*"))
|
||||||
|
return nullptr;
|
||||||
|
if (!tok->isName()) {
|
||||||
|
const Token* iter1 = getIteratorExpression(tok->astOperand1());
|
||||||
|
if (iter1)
|
||||||
|
return iter1;
|
||||||
|
if (tok->str() == "(")
|
||||||
|
return nullptr;
|
||||||
|
const Token* iter2 = getIteratorExpression(tok->astOperand2());
|
||||||
|
if (iter2)
|
||||||
|
return iter2;
|
||||||
|
} else if (Token::Match(tok, "begin|cbegin|rbegin|crbegin|end|cend|rend|crend (")) {
|
||||||
|
if (Token::Match(tok->previous(), ". %name% ( ) !!."))
|
||||||
|
return tok->previous()->astOperand1();
|
||||||
|
if (!Token::simpleMatch(tok->previous(), ".") && Token::Match(tok, "%name% ( !!)") &&
|
||||||
|
!Token::simpleMatch(tok->linkAt(1), ") ."))
|
||||||
|
return tok->next()->astOperand2();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool isIteratorPair(std::vector<const Token*> args)
|
bool isIteratorPair(std::vector<const Token*> args)
|
||||||
{
|
{
|
||||||
return args.size() == 2 &&
|
if (args.size() != 2)
|
||||||
((astIsIterator(args[0]) && astIsIterator(args[1])) || (astIsPointer(args[0]) && astIsPointer(args[1])));
|
return false;
|
||||||
|
if (astIsPointer(args[0]) && astIsPointer(args[1]))
|
||||||
|
return true;
|
||||||
|
// Check if iterator is from same container
|
||||||
|
const Token* tok1 = nullptr;
|
||||||
|
const Token* tok2 = nullptr;
|
||||||
|
if (astIsIterator(args[0]) && astIsIterator(args[1])) {
|
||||||
|
tok1 = ValueFlow::getLifetimeObjValue(args[0]).tokvalue;
|
||||||
|
tok2 = ValueFlow::getLifetimeObjValue(args[1]).tokvalue;
|
||||||
|
if (!tok1 || !tok2)
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
tok1 = getIteratorExpression(args[0]);
|
||||||
|
tok2 = getIteratorExpression(args[1]);
|
||||||
|
}
|
||||||
|
if (tok1 && tok2)
|
||||||
|
return tok1->exprId() == tok2->exprId();
|
||||||
|
return tok1 || tok2;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Token *findLambdaStartToken(const Token *last)
|
const Token *findLambdaStartToken(const Token *last)
|
||||||
|
|
|
@ -375,6 +375,8 @@ std::vector<const Token *> getArguments(const Token *ftok);
|
||||||
|
|
||||||
int getArgumentPos(const Variable* var, const Function* f);
|
int getArgumentPos(const Variable* var, const Function* f);
|
||||||
|
|
||||||
|
const Token* getIteratorExpression(const Token* tok);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Are the arguments a pair of iterators/pointers?
|
* Are the arguments a pair of iterators/pointers?
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -678,30 +678,6 @@ void CheckStl::sameIteratorExpressionError(const Token *tok)
|
||||||
reportError(tok, Severity::style, "sameIteratorExpression", "Same iterators expression are used for algorithm.", CWE664, Certainty::normal);
|
reportError(tok, Severity::style, "sameIteratorExpression", "Same iterators expression are used for algorithm.", CWE664, Certainty::normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Token * getIteratorExpression(const Token * tok)
|
|
||||||
{
|
|
||||||
if (!tok)
|
|
||||||
return nullptr;
|
|
||||||
if (tok->isUnaryOp("*"))
|
|
||||||
return nullptr;
|
|
||||||
if (!tok->isName()) {
|
|
||||||
const Token *iter1 = getIteratorExpression(tok->astOperand1());
|
|
||||||
if (iter1)
|
|
||||||
return iter1;
|
|
||||||
if (tok->str() == "(")
|
|
||||||
return nullptr;
|
|
||||||
const Token *iter2 = getIteratorExpression(tok->astOperand2());
|
|
||||||
if (iter2)
|
|
||||||
return iter2;
|
|
||||||
} else if (Token::Match(tok, "begin|cbegin|rbegin|crbegin|end|cend|rend|crend (")) {
|
|
||||||
if (Token::Match(tok->previous(), ". %name% ( ) !!."))
|
|
||||||
return tok->previous()->astOperand1();
|
|
||||||
if (!Token::simpleMatch(tok->previous(), ".") && Token::Match(tok, "%name% ( !!)") && !Token::simpleMatch(tok->linkAt(1), ") ."))
|
|
||||||
return tok->next()->astOperand2();
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const Token* getAddressContainer(const Token* tok)
|
static const Token* getAddressContainer(const Token* tok)
|
||||||
{
|
{
|
||||||
if (Token::simpleMatch(tok, "[") && tok->astOperand1())
|
if (Token::simpleMatch(tok, "[") && tok->astOperand1())
|
||||||
|
|
|
@ -498,7 +498,7 @@ static void getConfigs(const simplecpp::TokenList &tokens, std::set<std::string>
|
||||||
if (c.find(configs_ifndef.back()) != std::string::npos)
|
if (c.find(configs_ifndef.back()) != std::string::npos)
|
||||||
ret.insert(c);
|
ret.insert(c);
|
||||||
else if (c.empty())
|
else if (c.empty())
|
||||||
ret.insert(configs.empty() ? configs_ifndef.back() : "");
|
ret.insert("");
|
||||||
else
|
else
|
||||||
ret.insert(c + ";" + configs_ifndef.back());
|
ret.insert(c + ";" + configs_ifndef.back());
|
||||||
}
|
}
|
||||||
|
|
|
@ -665,8 +665,11 @@ static void setTokenValue(Token* tok,
|
||||||
setTokenValue(parent->astParent(), v, settings);
|
setTokenValue(parent->astParent(), v, settings);
|
||||||
} else if (yields == Library::Container::Yield::EMPTY) {
|
} else if (yields == Library::Container::Yield::EMPTY) {
|
||||||
ValueFlow::Value v(value);
|
ValueFlow::Value v(value);
|
||||||
v.intvalue = !v.intvalue;
|
|
||||||
v.valueType = ValueFlow::Value::ValueType::INT;
|
v.valueType = ValueFlow::Value::ValueType::INT;
|
||||||
|
if (value.isImpossible() && value.intvalue == 0)
|
||||||
|
v.setKnown();
|
||||||
|
else
|
||||||
|
v.intvalue = !v.intvalue;
|
||||||
setTokenValue(parent->astParent(), v, settings);
|
setTokenValue(parent->astParent(), v, settings);
|
||||||
}
|
}
|
||||||
} else if (Token::Match(parent->previous(), "%name% (")) {
|
} else if (Token::Match(parent->previous(), "%name% (")) {
|
||||||
|
@ -8431,6 +8434,11 @@ static void valueFlowContainerSize(TokenList* tokenlist,
|
||||||
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||||
value.setKnown();
|
value.setKnown();
|
||||||
valueFlowForward(tok->linkAt(2), containerTok, value, tokenlist);
|
valueFlowForward(tok->linkAt(2), containerTok, value, tokenlist);
|
||||||
|
} else if (action == Library::Container::Action::PUSH && !isIteratorPair(getArguments(tok->tokAt(2)))) {
|
||||||
|
ValueFlow::Value value(0);
|
||||||
|
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||||
|
value.setImpossible();
|
||||||
|
valueFlowForward(tok->linkAt(2), containerTok, value, tokenlist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2585,7 +2585,7 @@ private:
|
||||||
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str());
|
||||||
|
|
||||||
check("void f1(const std::string &s) { if(s.size() < 0) if(s.empty()) {}} "); // <- CheckOther reports: checking if unsigned expression is less than zero
|
check("void f1(const std::string &s) { if(s.size() < 0) if(s.empty()) {}} "); // <- CheckOther reports: checking if unsigned expression is less than zero
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (style) Condition 's.empty()' is always false\n", errout.str());
|
||||||
|
|
||||||
check("void f1(const std::string &s) { if(s.empty()) if(s.size() > 42) {}}");
|
check("void f1(const std::string &s) { if(s.empty()) if(s.size() > 42) {}}");
|
||||||
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str());
|
||||||
|
@ -4971,6 +4971,22 @@ private:
|
||||||
" return a.empty() || (b.empty() && a.empty());\n"
|
" return a.empty() || (b.empty() && a.empty());\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:2]: (style) Return value 'a.empty()' is always false\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:2]: (style) Return value 'a.empty()' is always false\n", errout.str());
|
||||||
|
|
||||||
|
check("struct A {\n"
|
||||||
|
" struct iterator;\n"
|
||||||
|
" iterator begin() const;\n"
|
||||||
|
" iterator end() const;\n"
|
||||||
|
"};\n"
|
||||||
|
"A g();\n"
|
||||||
|
"void f(bool b) {\n"
|
||||||
|
" std::set<int> s;\n"
|
||||||
|
" auto v = g();\n"
|
||||||
|
" s.insert(v.begin(), v.end());\n"
|
||||||
|
" if(!b && s.size() != 1)\n"
|
||||||
|
" return;\n"
|
||||||
|
" if(!s.empty()) {}\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void alwaysTrueLoop()
|
void alwaysTrueLoop()
|
||||||
|
|
|
@ -6378,6 +6378,13 @@ private:
|
||||||
" else if (a.empty() == false && b.empty() == false) {}\n"
|
" else if (a.empty() == false && b.empty() == false) {}\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
ASSERT("" != isImpossibleContainerSizeValue(tokenValues(code, "a . empty ( ) == false"), 0));
|
ASSERT("" != isImpossibleContainerSizeValue(tokenValues(code, "a . empty ( ) == false"), 0));
|
||||||
|
|
||||||
|
code = "bool g(std::vector<int>& v) {\n"
|
||||||
|
" v.push_back(1);\n"
|
||||||
|
" int x = v.empty();\n"
|
||||||
|
" return x;\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(true, testValueOfXKnown(code, 4U, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueFlowContainerElement()
|
void valueFlowContainerElement()
|
||||||
|
|
Loading…
Reference in New Issue