Merge branch 'main' of https://github.com/danmar/cppcheck into main

This commit is contained in:
orbitcowboy 2021-06-03 07:33:47 +02:00
commit 601ca6b3c5
8 changed files with 201 additions and 20 deletions

View File

@ -1668,7 +1668,8 @@ const Token * getTokenArgumentFunction(const Token * tok, int& argn)
return nullptr; return nullptr;
if (!Token::Match(tok, "{|(")) if (!Token::Match(tok, "{|("))
return nullptr; return nullptr;
tok = tok->astOperand1(); if (tok->astOperand2())
tok = tok->astOperand1();
while (tok && (tok->isUnaryOp("*") || tok->str() == "[")) while (tok && (tok->isUnaryOp("*") || tok->str() == "["))
tok = tok->astOperand1(); tok = tok->astOperand1();
while (Token::simpleMatch(tok, ".")) while (Token::simpleMatch(tok, "."))
@ -1690,21 +1691,31 @@ const Token * getTokenArgumentFunction(const Token * tok, int& argn)
return tok; return tok;
} }
static std::vector<const Variable*> getArgumentVars(const Token* tok, int argnr) std::vector<const Variable*> getArgumentVars(const Token* tok, int argnr)
{ {
std::vector<const Variable*> result; std::vector<const Variable*> result;
if (!tok) if (!tok)
return result; return result;
if (tok->function()) if (tok->function()) {
return {tok->function()->getArgumentVar(argnr)}; const Variable* argvar = tok->function()->getArgumentVar(argnr);
if (Token::Match(tok->previous(), "%type% (|{") || tok->variable()) { if (argvar)
const bool constructor = tok->variable() && tok->variable()->nameToken() == tok; return {argvar};
else
return result;
}
if (Token::Match(tok->previous(), "%type% (|{") || Token::simpleMatch(tok, "{") || tok->variable()) {
const bool constructor = Token::simpleMatch(tok, "{") || (tok->variable() && tok->variable()->nameToken() == tok);
const Type* type = Token::typeOf(tok); const Type* type = Token::typeOf(tok);
if (!type) if (!type)
return result; return result;
const Scope* typeScope = type->classScope; const Scope* typeScope = type->classScope;
if (!typeScope) if (!typeScope)
return result; return result;
// Aggregate constructor
if (Token::simpleMatch(tok, "{") && typeScope->numConstructors == 0 && argnr < typeScope->varlist.size()) {
auto it = std::next(typeScope->varlist.begin(), argnr);
return {&*it};
}
const int argCount = numberOfArguments(tok); const int argCount = numberOfArguments(tok);
for (const Function &function : typeScope->functionList) { for (const Function &function : typeScope->functionList) {
if (function.argCount() < argCount) if (function.argCount() < argCount)
@ -1713,7 +1724,9 @@ static std::vector<const Variable*> getArgumentVars(const Token* tok, int argnr)
continue; continue;
if (!constructor && !Token::simpleMatch(function.token, "operator()")) if (!constructor && !Token::simpleMatch(function.token, "operator()"))
continue; continue;
result.push_back(function.getArgumentVar(argnr)); const Variable* argvar = function.getArgumentVar(argnr);
if (argvar)
result.push_back(argvar);
} }
} }
return result; return result;
@ -1726,6 +1739,17 @@ static bool isCPPCastKeyword(const Token* tok)
return endsWith(tok->str(), "_cast", 5); return endsWith(tok->str(), "_cast", 5);
} }
static bool isTrivialConstructor(const Token* tok)
{
const Token* typeTok = nullptr;
const Type* t = Token::typeOf(tok, &typeTok);
if (t)
return false;
if (typeTok->valueType() && typeTok->valueType()->isPrimitive())
return true;
return false;
}
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Settings *settings, bool *inconclusive) bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Settings *settings, bool *inconclusive)
{ {
if (!tok) if (!tok)
@ -1743,6 +1767,8 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
tok = getTokenArgumentFunction(tok, argnr); tok = getTokenArgumentFunction(tok, argnr);
if (!tok) if (!tok)
return false; // not a function => variable not changed return false; // not a function => variable not changed
if (Token::simpleMatch(tok, "{") && isTrivialConstructor(tok))
return false;
if (tok->isKeyword() && !isCPPCastKeyword(tok)) if (tok->isKeyword() && !isCPPCastKeyword(tok))
return false; return false;
const Token * parenTok = tok->next(); const Token * parenTok = tok->next();
@ -2303,19 +2329,19 @@ std::vector<const Variable*> getLHSVariables(const Token* tok)
return result; return result;
} }
static const Variable *getLHSVariableRecursive(const Token *tok) static const Token* getLHSVariableRecursive(const Token* tok)
{ {
if (!tok) if (!tok)
return nullptr; return nullptr;
if (Token::Match(tok, "*|&|&&|[")) { if (Token::Match(tok, "*|&|&&|[")) {
const Variable *var = getLHSVariableRecursive(tok->astOperand1()); const Token* vartok = getLHSVariableRecursive(tok->astOperand1());
if (var || Token::simpleMatch(tok, "[")) if ((vartok && vartok->variable()) || Token::simpleMatch(tok, "["))
return var; return vartok;
return getLHSVariableRecursive(tok->astOperand2()); return getLHSVariableRecursive(tok->astOperand2());
} }
if (Token::Match(tok->previous(), "this . %var%")) if (Token::Match(tok->previous(), "this . %var%"))
return tok->next()->variable(); return tok->next();
return tok->variable(); return tok;
} }
const Variable *getLHSVariable(const Token *tok) const Variable *getLHSVariable(const Token *tok)
@ -2326,7 +2352,24 @@ const Variable *getLHSVariable(const Token *tok)
return nullptr; return nullptr;
if (tok->astOperand1()->varId() > 0 && tok->astOperand1()->variable()) if (tok->astOperand1()->varId() > 0 && tok->astOperand1()->variable())
return tok->astOperand1()->variable(); return tok->astOperand1()->variable();
return getLHSVariableRecursive(tok->astOperand1()); const Token* vartok = getLHSVariableRecursive(tok->astOperand1());
if (!vartok)
return nullptr;
return vartok->variable();
}
const Token* getLHSVariableToken(const Token* tok)
{
if (!Token::Match(tok, "%assign%"))
return nullptr;
if (!tok->astOperand1())
return nullptr;
if (tok->astOperand1()->varId() > 0)
return tok->astOperand1();
const Token* vartok = getLHSVariableRecursive(tok->astOperand1());
if (!vartok)
return tok->astOperand1();
return vartok;
} }
const Token* findAllocFuncCallToken(const Token *expr, const Library &library) const Token* findAllocFuncCallToken(const Token *expr, const Library &library)

View File

@ -188,6 +188,8 @@ bool isReturnScope(const Token* const endToken,
/// Return the token to the function and the argument number /// Return the token to the function and the argument number
const Token * getTokenArgumentFunction(const Token * tok, int& argn); const Token * getTokenArgumentFunction(const Token * tok, int& argn);
std::vector<const Variable*> getArgumentVars(const Token* tok, int argnr);
/** Is variable changed by function call? /** Is variable changed by function call?
* In case the answer of the question is inconclusive, e.g. because the function declaration is not known * In case the answer of the question is inconclusive, e.g. because the function declaration is not known
* the return value is false and the output parameter inconclusive is set to true * the return value is false and the output parameter inconclusive is set to true
@ -279,6 +281,8 @@ bool isConstVarExpression(const Token *tok, const char * skipMatch = nullptr);
const Variable *getLHSVariable(const Token *tok); const Variable *getLHSVariable(const Token *tok);
const Token* getLHSVariableToken(const Token* tok);
std::vector<const Variable*> getLHSVariables(const Token* tok); std::vector<const Variable*> getLHSVariables(const Token* tok);
/** Find a allocation function call in expression, so result of expression is allocated memory/resource. */ /** Find a allocation function call in expression, so result of expression is allocated memory/resource. */

View File

@ -1273,6 +1273,8 @@ public:
static MatchResult matchParameter(const ValueType *call, const ValueType *func); static MatchResult matchParameter(const ValueType *call, const ValueType *func);
static MatchResult matchParameter(const ValueType *call, const Variable *callVar, const Variable *funcVar); static MatchResult matchParameter(const ValueType *call, const Variable *callVar, const Variable *funcVar);
bool isPrimitive() const { return (type >= ValueType::Type::BOOL); }
bool isIntegral() const { bool isIntegral() const {
return (type >= ValueType::Type::BOOL && type <= ValueType::Type::UNKNOWN_INT); return (type >= ValueType::Type::BOOL && type <= ValueType::Type::UNKNOWN_INT);
} }

View File

@ -2257,10 +2257,12 @@ void Token::type(const ::Type *t)
tokType(eName); tokType(eName);
} }
const ::Type *Token::typeOf(const Token *tok) const ::Type* Token::typeOf(const Token* tok, const Token** typeTok)
{ {
if (!tok) if (!tok)
return nullptr; return nullptr;
if (typeTok != nullptr)
*typeTok = tok;
if (Token::simpleMatch(tok, "return")) { if (Token::simpleMatch(tok, "return")) {
const Scope *scope = tok->scope(); const Scope *scope = tok->scope();
if (!scope) if (!scope)
@ -2282,14 +2284,30 @@ const ::Type *Token::typeOf(const Token *tok)
return nullptr; return nullptr;
return function->retType; return function->retType;
} else if (Token::Match(tok->previous(), "%type%|= (|{")) { } else if (Token::Match(tok->previous(), "%type%|= (|{")) {
return typeOf(tok->previous()); return typeOf(tok->previous(), typeTok);
} else if (Token::simpleMatch(tok, "=")) { } else if (Token::simpleMatch(tok, "=")) {
return Token::typeOf(tok->astOperand1()); return Token::typeOf(getLHSVariableToken(tok), typeTok);
} else if (Token::simpleMatch(tok, ".")) { } else if (Token::simpleMatch(tok, ".")) {
return Token::typeOf(tok->astOperand2()); return Token::typeOf(tok->astOperand2(), typeTok);
} else if (Token::simpleMatch(tok, "[")) { } else if (Token::simpleMatch(tok, "[")) {
return Token::typeOf(tok->astOperand1()); return Token::typeOf(tok->astOperand1(), typeTok);
} else if (Token::simpleMatch(tok, "{")) {
int argnr;
const Token* ftok = getTokenArgumentFunction(tok, argnr);
if (argnr < 0)
return nullptr;
if (!ftok)
return nullptr;
if (ftok == tok)
return nullptr;
std::vector<const Variable*> vars = getArgumentVars(ftok, argnr);
if (vars.empty())
return nullptr;
if (std::all_of(
vars.begin(), vars.end(), [&](const Variable* var) { return var->type() == vars.front()->type(); }))
return vars.front()->type();
} }
return nullptr; return nullptr;
} }

View File

@ -1010,7 +1010,7 @@ public:
return mTokType == eType ? mImpl->mType : nullptr; return mTokType == eType ? mImpl->mType : nullptr;
} }
static const ::Type *typeOf(const Token *tok); static const ::Type* typeOf(const Token* tok, const Token** typeTok = nullptr);
static std::pair<const Token*, const Token*> typeDecl(const Token * tok); static std::pair<const Token*, const Token*> typeDecl(const Token * tok);

View File

@ -723,6 +723,8 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti
for (const ValueFlow::Value &val : tok->values()) { for (const ValueFlow::Value &val : tok->values()) {
if (!val.isIntValue()) if (!val.isIntValue())
continue; continue;
if (val.isImpossible() && val.intvalue != 0)
continue;
ValueFlow::Value v(val); ValueFlow::Value v(val);
v.intvalue = !v.intvalue; v.intvalue = !v.intvalue;
setTokenValue(parent, v, settings); setTokenValue(parent, v, settings);

View File

@ -381,6 +381,86 @@ private:
"}\n", true); "}\n", true);
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("struct T {\n"
" std::vector<int>* v;\n"
"};\n"
"struct S {\n"
" std::vector<T> t;\n"
"};\n"
"long g(S& s);\n"
"int f() {\n"
" std::vector<int> ArrS;\n"
" S s = { { { &ArrS } } };\n"
" g(s);\n"
" return ArrS[0];\n"
"}\n",
true);
ASSERT_EQUALS("", errout.str());
check("struct T {\n"
" std::vector<int>* v;\n"
"};\n"
"struct S {\n"
" std::vector<std::vector<T>> t;\n"
"};\n"
"long g(S& s);\n"
"int f() {\n"
" std::vector<int> ArrS;\n"
" S s = { { { { &ArrS } } } };\n"
" g(s);\n"
" return ArrS[0];\n"
"}\n",
true);
ASSERT_EQUALS("", errout.str());
check("struct T {\n"
" std::vector<int>* v;\n"
"};\n"
"struct S {\n"
" T t;\n"
"};\n"
"long g(S& s);\n"
"int f() {\n"
" std::vector<int> ArrS;\n"
" S s { { &ArrS } };\n"
" g(s);\n"
" return ArrS[0];\n"
"}\n",
true);
ASSERT_EQUALS("", errout.str());
check("struct T {\n"
" std::vector<int>* v;\n"
"};\n"
"struct S {\n"
" std::vector<T> t;\n"
"};\n"
"long g(S& s);\n"
"int f() {\n"
" std::vector<int> ArrS;\n"
" S s { { { &ArrS } } };\n"
" g(s);\n"
" return ArrS[0];\n"
"}\n",
true);
ASSERT_EQUALS("", errout.str());
check("struct T {\n"
" std::vector<int>* v;\n"
"};\n"
"struct S {\n"
" std::vector<std::vector<T>> t;\n"
"};\n"
"long g(S& s);\n"
"int f() {\n"
" std::vector<int> ArrS;\n"
" S s { { { { &ArrS } } } };\n"
" g(s);\n"
" return ArrS[0];\n"
"}\n",
true);
ASSERT_EQUALS("", errout.str());
checkNormal("extern void Bar(const double, const double);\n" checkNormal("extern void Bar(const double, const double);\n"
"void f(std::vector<double> &r, const double ) {\n" "void f(std::vector<double> &r, const double ) {\n"
" std::vector<double> result;\n" " std::vector<double> result;\n"

View File

@ -141,6 +141,7 @@ private:
TEST_CASE(valueFlowUnknownMixedOperators); TEST_CASE(valueFlowUnknownMixedOperators);
TEST_CASE(valueFlowIdempotent); TEST_CASE(valueFlowIdempotent);
TEST_CASE(valueFlowUnsigned); TEST_CASE(valueFlowUnsigned);
TEST_CASE(valueFlowMod);
} }
static bool isNotTokValue(const ValueFlow::Value &val) { static bool isNotTokValue(const ValueFlow::Value &val) {
@ -2643,6 +2644,20 @@ private:
ASSERT_EQUALS(false, testValueOfXKnown(code, 5U, 1)); ASSERT_EQUALS(false, testValueOfXKnown(code, 5U, 1));
ASSERT_EQUALS(false, testValueOfXImpossible(code, 5U, 0)); ASSERT_EQUALS(false, testValueOfXImpossible(code, 5U, 0));
ASSERT_EQUALS(false, testValueOfXImpossible(code, 5U, 1)); ASSERT_EQUALS(false, testValueOfXImpossible(code, 5U, 1));
code = "auto f(int i) {\n"
" if (i == 0) return;\n"
" auto x = !i;\n"
" return x;\n"
"}\n";
ASSERT_EQUALS(true, testValueOfXImpossible(code, 4U, 1));
code = "auto f(int i) {\n"
" if (i == 1) return;\n"
" auto x = !i;\n"
" return x;\n"
"}\n";
ASSERT_EQUALS(false, testValueOfXImpossible(code, 4U, 0));
} }
void valueFlowAfterConditionExpr() { void valueFlowAfterConditionExpr() {
@ -5638,6 +5653,23 @@ private:
ASSERT_EQUALS(false, testValueOfXImpossible(code, 4U, 0)); ASSERT_EQUALS(false, testValueOfXImpossible(code, 4U, 0));
ASSERT_EQUALS(true, testValueOfXImpossible(code, 4U, -1)); ASSERT_EQUALS(true, testValueOfXImpossible(code, 4U, -1));
} }
void valueFlowMod() {
const char *code;
code = "auto f(int i) {\n"
" auto x = i % 2;\n"
" return x;\n"
"}\n";
ASSERT_EQUALS(true, testValueOfXImpossible(code, 3U, 2));
code = "auto f(int i) {\n"
" auto x = !(i % 2);\n"
" return x;\n"
"}\n";
ASSERT_EQUALS(false, testValueOfXImpossible(code, 3U, 0));
ASSERT_EQUALS(false, testValueOfXImpossible(code, 3U, 1));
}
}; };
REGISTER_TEST(TestValueFlow) REGISTER_TEST(TestValueFlow)