Refactorized Library

This commit is contained in:
PKEuS 2016-12-06 12:31:16 +01:00 committed by PKEuS
parent af1398900c
commit 2f6350a0d0
16 changed files with 207 additions and 188 deletions

View File

@ -128,7 +128,7 @@ const Token * astIsVariableComparison(const Token *tok, const std::string &comp,
return ret;
}
bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const std::set<std::string> &constFunctions)
bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const Library& library, bool pure)
{
if (tok1 == nullptr && tok2 == nullptr)
return true;
@ -143,15 +143,15 @@ bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2
if (tok1->varId() != tok2->varId() || tok1->str() != tok2->str() || tok1->originalName() != tok2->originalName()) {
if ((Token::Match(tok1,"<|>") && Token::Match(tok2,"<|>")) ||
(Token::Match(tok1,"<=|>=") && Token::Match(tok2,"<=|>="))) {
return isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand2(), constFunctions) &&
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand1(), constFunctions);
return isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand2(), library, pure) &&
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand1(), library, pure);
}
return false;
}
if (macro && (tok1->isExpandedMacro() || tok2->isExpandedMacro()))
return false;
if (tok1->isName() && tok1->next()->str() == "(" && tok1->str() != "sizeof") {
if (!tok1->function() && !Token::Match(tok1->previous(), ".|::") && constFunctions.find(tok1->str()) == constFunctions.end() && !tok1->isAttributeConst() && !tok1->isAttributePure())
if (!tok1->function() && !Token::Match(tok1->previous(), ".|::") && pure && !library.isFunctionConst(tok1->str(), true) && !tok1->isAttributeConst() && !tok1->isAttributePure())
return false;
else if (tok1->function() && !tok1->function()->isConst() && !tok1->function()->isAttributeConst() && !tok1->function()->isAttributePure())
return false;
@ -201,18 +201,18 @@ bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2
return false;
}
bool noncommutativeEquals =
isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand1(), constFunctions);
isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand1(), library, pure);
noncommutativeEquals = noncommutativeEquals &&
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand2(), constFunctions);
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand2(), library, pure);
if (noncommutativeEquals)
return true;
const bool commutative = tok1->astOperand1() && tok1->astOperand2() && Token::Match(tok1, "%or%|%oror%|+|*|&|&&|^|==|!=");
bool commutativeEquals = commutative &&
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand1(), constFunctions);
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand1(), library, pure);
commutativeEquals = commutativeEquals &&
isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand2(), constFunctions);
isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand2(), library, pure);
// in c++, "a"+b might be different to b+"a"
if (cpp && commutativeEquals && tok1->str() == "+" &&
@ -224,7 +224,7 @@ bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2
return commutativeEquals;
}
bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions)
bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const Library& library, bool pure)
{
if (!cond1 || !cond2)
return false;
@ -232,15 +232,15 @@ bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token
if (cond1->str() == "!") {
if (cond2->str() == "!=") {
if (cond2->astOperand1() && cond2->astOperand1()->str() == "0")
return isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand2(), constFunctions);
return isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand2(), library, pure);
if (cond2->astOperand2() && cond2->astOperand2()->str() == "0")
return isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand1(), constFunctions);
return isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand1(), library, pure);
}
return isSameExpression(cpp, true, cond1->astOperand1(), cond2, constFunctions);
return isSameExpression(cpp, true, cond1->astOperand1(), cond2, library, pure);
}
if (cond2->str() == "!")
return isOppositeCond(isNot, cpp, cond2, cond1, constFunctions);
return isOppositeCond(isNot, cpp, cond2, cond1, library, pure);
if (!cond1->isComparisonOp() || !cond2->isComparisonOp())
return false;
@ -249,11 +249,11 @@ bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token
// condition found .. get comparator
std::string comp2;
if (isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand1(), constFunctions) &&
isSameExpression(cpp, true, cond1->astOperand2(), cond2->astOperand2(), constFunctions)) {
if (isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand1(), library, pure) &&
isSameExpression(cpp, true, cond1->astOperand2(), cond2->astOperand2(), library, pure)) {
comp2 = cond2->str();
} else if (isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand2(), constFunctions) &&
isSameExpression(cpp, true, cond1->astOperand2(), cond2->astOperand1(), constFunctions)) {
} else if (isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand2(), library, pure) &&
isSameExpression(cpp, true, cond1->astOperand2(), cond2->astOperand1(), library, pure)) {
comp2 = cond2->str();
if (comp2[0] == '>')
comp2[0] = '<';
@ -272,12 +272,12 @@ bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token
(comp1 == ">" && comp2 == "<"))));
}
bool isConstExpression(const Token *tok, const std::set<std::string> &constFunctions)
bool isConstExpression(const Token *tok, const Library& library, bool pure)
{
if (!tok)
return true;
if (tok->isName() && tok->next()->str() == "(") {
if (!tok->function() && !Token::Match(tok->previous(), ".|::") && constFunctions.find(tok->str()) == constFunctions.end())
if (!tok->function() && !Token::Match(tok->previous(), ".|::") && !library.isFunctionConst(tok->str(), pure))
return false;
else if (tok->function() && !tok->function()->isConst())
return false;
@ -287,7 +287,7 @@ bool isConstExpression(const Token *tok, const std::set<std::string> &constFunct
// bailout when we see ({..})
if (tok->str() == "{")
return false;
return isConstExpression(tok->astOperand1(),constFunctions) && isConstExpression(tok->astOperand2(),constFunctions);
return isConstExpression(tok->astOperand1(), library, pure) && isConstExpression(tok->astOperand2(), library, pure);
}
bool isWithoutSideEffects(bool cpp, const Token* tok)

View File

@ -22,10 +22,10 @@
#define astutilsH
//---------------------------------------------------------------------------
#include <set>
#include <string>
class Settings;
class Library;
class Token;
/** Is expression a 'signed char' if no promotion is used */
@ -53,7 +53,7 @@ std::string astCanonicalType(const Token *expr);
/** Is given syntax tree a variable comparison against value */
const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok=nullptr);
bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const std::set<std::string> &constFunctions);
bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const Library& library, bool pure);
/**
* Are two conditions opposite
@ -63,9 +63,9 @@ bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2
* @param cond2 condition2
* @param constFunctions constFunctions
*/
bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions);
bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const Library& library, bool pure);
bool isConstExpression(const Token *tok, const std::set<std::string> &constFunctions);
bool isConstExpression(const Token *tok, const Library& library, bool pure);
bool isWithoutSideEffects(bool cpp, const Token* tok);

View File

@ -351,13 +351,13 @@ void CheckCondition::comparisonError(const Token *tok, const std::string &bitop,
reportError(tok, Severity::style, "comparisonError", errmsg, CWE398, false);
}
bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions) const
bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token * const cond2, bool pure) const
{
if (!cond1 || !cond2)
return false;
// same expressions
if (isSameExpression(_tokenizer->isCPP(), true, cond1, cond2, constFunctions))
if (isSameExpression(_tokenizer->isCPP(), true, cond1, cond2, _settings->library, pure))
return true;
// bitwise overlap for example 'x&7' and 'x==1'
@ -380,7 +380,7 @@ bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token *
if (!num2->isNumber() || MathLib::isNegative(num2->str()))
return false;
if (!isSameExpression(_tokenizer->isCPP(), true, expr1, expr2, constFunctions))
if (!isSameExpression(_tokenizer->isCPP(), true, expr1, expr2, _settings->library, pure))
return false;
const MathLib::bigint value1 = MathLib::toLongNumber(num1->str());
@ -414,7 +414,7 @@ void CheckCondition::multiCondition()
break;
tok2 = tok2->tokAt(4);
if (isOverlappingCond(cond1, tok2->astOperand2(), _settings->library.functionpure))
if (isOverlappingCond(cond1, tok2->astOperand2(), true))
multiConditionError(tok2, cond1->linenr());
}
}
@ -502,7 +502,7 @@ void CheckCondition::oppositeInnerCondition()
const Token *cond1 = scope->classDef->next()->astOperand2();
const Token *cond2 = ifToken->next()->astOperand2();
if (isOppositeCond(false, _tokenizer->isCPP(), cond1, cond2, _settings->library.functionpure))
if (isOppositeCond(false, _tokenizer->isCPP(), cond1, cond2, _settings->library, true))
oppositeInnerConditionError(scope->classDef, cond2);
}
}
@ -677,7 +677,7 @@ void CheckCondition::checkIncorrectLogicOperator()
// Opposite comparisons around || or && => always true or always false
if ((tok->astOperand1()->isName() || tok->astOperand2()->isName()) &&
isOppositeCond(true, _tokenizer->isCPP(), tok->astOperand1(), tok->astOperand2(), _settings->library.functionpure)) {
isOppositeCond(true, _tokenizer->isCPP(), tok->astOperand1(), tok->astOperand2(), _settings->library, true)) {
const bool alwaysTrue(tok->str() == "||");
incorrectLogicOperatorError(tok, tok->expressionString(), alwaysTrue, false);
@ -691,7 +691,7 @@ void CheckCondition::checkIncorrectLogicOperator()
((tok->str() == "||" && tok->astOperand2()->str() == "&&") ||
(tok->str() == "&&" && tok->astOperand2()->str() == "||"))) {
const Token* tok2 = tok->astOperand2()->astOperand1();
if (isOppositeCond(true, _tokenizer->isCPP(), tok->astOperand1(), tok2, _settings->library.functionpure)) {
if (isOppositeCond(true, _tokenizer->isCPP(), tok->astOperand1(), tok2, _settings->library, true)) {
std::string expr1(tok->astOperand1()->expressionString());
std::string expr2(tok->astOperand2()->astOperand1()->expressionString());
std::string expr3(tok->astOperand2()->astOperand2()->expressionString());
@ -752,9 +752,9 @@ void CheckCondition::checkIncorrectLogicOperator()
if (inconclusive && !printInconclusive)
continue;
if (isSameExpression(_tokenizer->isCPP(), true, comp1, comp2, _settings->library.functionpure))
if (isSameExpression(_tokenizer->isCPP(), true, comp1, comp2, _settings->library, true))
continue; // same expressions => only report that there are same expressions
if (!isSameExpression(_tokenizer->isCPP(), true, expr1, expr2, _settings->library.functionpure))
if (!isSameExpression(_tokenizer->isCPP(), true, expr1, expr2, _settings->library, true))
continue;
const bool isfloat = astIsFloat(expr1, true) || MathLib::isFloat(value1) || astIsFloat(expr2, true) || MathLib::isFloat(value2);
@ -1082,9 +1082,9 @@ void CheckCondition::checkInvalidTestForOverflow()
continue;
const Token *termToken;
if (isSameExpression(_tokenizer->isCPP(), true, exprToken, calcToken->astOperand1(), _settings->library.functionpure))
if (isSameExpression(_tokenizer->isCPP(), true, exprToken, calcToken->astOperand1(), _settings->library, true))
termToken = calcToken->astOperand2();
else if (isSameExpression(_tokenizer->isCPP(), true, exprToken, calcToken->astOperand2(), _settings->library.functionpure))
else if (isSameExpression(_tokenizer->isCPP(), true, exprToken, calcToken->astOperand2(), _settings->library, true))
termToken = calcToken->astOperand1();
else
continue;

View File

@ -103,7 +103,7 @@ public:
private:
bool isOverlappingCond(const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions) const;
bool isOverlappingCond(const Token * const cond1, const Token * const cond2, bool pure) const;
void assignIfError(const Token *tok1, const Token *tok2, const std::string &condition, bool result);
void mismatchingBitAndError(const Token *tok1, const MathLib::bigint num1, const Token *tok2, const MathLib::bigint num2);
void badBitmaskCheckError(const Token *tok);

View File

@ -233,7 +233,7 @@ void CheckIO::checkFileUsage()
if ((tok->str() == "ungetc" || tok->str() == "ungetwc") && fileTok)
fileTok = fileTok->nextArgument();
operation = Filepointer::UNIMPORTANT;
} else if (!Token::Match(tok, "if|for|while|catch|switch") && _settings->library.functionpure.find(tok->str()) == _settings->library.functionpure.end()) {
} else if (!Token::Match(tok, "if|for|while|catch|switch") && !_settings->library.isFunctionConst(tok->str(), true)) {
const Token* const end2 = tok->linkAt(1);
if (scope->functionOf && scope->functionOf->isClassOrStruct() && !scope->function->isStatic() && ((tok->strAt(-1) != "::" && tok->strAt(-1) != ".") || tok->strAt(-2) == "this")) {
if (!tok->function() || (tok->function()->nestedIn && tok->function()->nestedIn->isClassOrStruct())) {

View File

@ -460,8 +460,7 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
if (_tokenizer->IsScopeNoReturn(tok->tokAt(2), &unknown)) {
if (!unknown)
varInfo->clear();
else if (_settings->library.leakignore.find(functionName) == _settings->library.leakignore.end() &&
_settings->library.use.find(functionName) == _settings->library.use.end())
else if (!_settings->library.isLeakIgnore(functionName) && !_settings->library.isUse(functionName))
varInfo->possibleUsageAll(functionName);
}
}
@ -526,8 +525,7 @@ void CheckLeakAutoVar::changeAllocStatus(VarInfo *varInfo, const VarInfo::AllocI
void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af)
{
// Ignore function call?
const bool ignore = bool(_settings->library.leakignore.find(tok->str()) != _settings->library.leakignore.end());
if (ignore)
if (_settings->library.isLeakIgnore(tok->str()))
return;
int argNr = 1;

View File

@ -494,7 +494,7 @@ static bool alwaysTrue(const Token *tok)
bool CheckMemoryLeakInFunction::test_white_list(const std::string &funcname, const Settings *settings, bool cpp)
{
return ((call_func_white_list.find(funcname)!=call_func_white_list.end()) || (settings->library.leakignore.find(funcname) != settings->library.leakignore.end()) || (cpp && funcname == "delete"));
return ((call_func_white_list.find(funcname)!=call_func_white_list.end()) || settings->library.isLeakIgnore(funcname) || (cpp && funcname == "delete"));
}
namespace {
@ -1318,7 +1318,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
parent = parent->astParent();
if (parent && parent->astOperand1() && parent->astOperand1()->isName()) {
const std::string &functionName = parent->astOperand1()->str();
if (_settings->library.leakignore.find(functionName) != _settings->library.leakignore.end())
if (_settings->library.isLeakIgnore(functionName))
leakignore = true;
}
}

View File

@ -574,7 +574,7 @@ void CheckOther::checkRedundantAssignment()
}
// Ensure that LHS in assignments are the same
bool error = oldeq && eq->astOperand1() && isSameExpression(_tokenizer->isCPP(), true, eq->astOperand1(), oldeq->astOperand1(), _settings->library.functionpure);
bool error = oldeq && eq->astOperand1() && isSameExpression(_tokenizer->isCPP(), true, eq->astOperand1(), oldeq->astOperand1(), _settings->library, true);
// Ensure that variable is not used on right side
std::stack<const Token *> tokens;
@ -635,7 +635,7 @@ void CheckOther::checkRedundantAssignment()
if (!writtenArgumentsEnd) // Indicates that we are in the first argument of strcpy/memcpy/... function
memAssignments.erase(tok->varId());
}
} else if (Token::Match(tok, "%name% (") && _settings->library.functionpure.find(tok->str()) == _settings->library.functionpure.end()) { // Function call. Global variables might be used. Reset their status
} else if (Token::Match(tok, "%name% (") && !_settings->library.isFunctionConst(tok->str(), true)) { // Function call. Global variables might be used. Reset their status
const bool memfunc = Token::Match(tok, "memcpy|memmove|memset|strcpy|strncpy|sprintf|snprintf|strcat|strncat|wcscpy|wcsncpy|swprintf|wcscat|wcsncat");
if (tok->varId()) // operator() or function pointer
varAssignments.erase(tok->varId());
@ -1936,7 +1936,7 @@ void CheckOther::checkInvalidFree()
// If the previously-allocated variable is passed in to another function
// as a parameter, it might be modified, so we shouldn't report an error
// if it is later used to free memory
else if (Token::Match(tok, "%name% (") && _settings->library.functionpure.find(tok->str()) == _settings->library.functionpure.end()) {
else if (Token::Match(tok, "%name% (") && !_settings->library.isFunctionConst(tok->str(), true)) {
const Token* tok2 = Token::findmatch(tok->next(), "%var%", tok->linkAt(1));
while (tok2 != nullptr) {
allocatedVariables.erase(tok2->varId());
@ -2001,7 +2001,6 @@ void CheckOther::checkDuplicateExpression()
std::list<Scope>::const_iterator scope;
std::list<const Function*> constFunctions;
const std::set<std::string> temp; // Can be used as dummy for isSameExpression()
getConstFunctions(symbolDatabase, constFunctions);
for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
@ -2013,7 +2012,7 @@ void CheckOther::checkDuplicateExpression()
if (tok->isOp() && tok->astOperand1() && !Token::Match(tok, "+|*|<<|>>|+=|*=|<<=|>>=")) {
if (Token::Match(tok, "==|!=|-") && astIsFloat(tok->astOperand1(), true))
continue;
if (isSameExpression(_tokenizer->isCPP(), true, tok->astOperand1(), tok->astOperand2(), _settings->library.functionpure)) {
if (isSameExpression(_tokenizer->isCPP(), true, tok->astOperand1(), tok->astOperand2(), _settings->library, true)) {
if (isWithoutSideEffects(_tokenizer->isCPP(), tok->astOperand1())) {
const bool assignment = tok->str() == "=";
if (assignment && warningEnabled)
@ -2033,25 +2032,25 @@ void CheckOther::checkDuplicateExpression()
}
}
} else if (!Token::Match(tok, "[-/%]")) { // These operators are not associative
if (styleEnabled && tok->astOperand2() && tok->str() == tok->astOperand1()->str() && isSameExpression(_tokenizer->isCPP(), true, tok->astOperand2(), tok->astOperand1()->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer->isCPP(), tok->astOperand2()))
if (styleEnabled && tok->astOperand2() && tok->str() == tok->astOperand1()->str() && isSameExpression(_tokenizer->isCPP(), true, tok->astOperand2(), tok->astOperand1()->astOperand2(), _settings->library, true) && isWithoutSideEffects(_tokenizer->isCPP(), tok->astOperand2()))
duplicateExpressionError(tok->astOperand2(), tok->astOperand2(), tok->str());
else if (tok->astOperand2()) {
const Token *ast1 = tok->astOperand1();
while (ast1 && tok->str() == ast1->str()) {
if (isSameExpression(_tokenizer->isCPP(), true, ast1->astOperand1(), tok->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer->isCPP(), ast1->astOperand1()))
if (isSameExpression(_tokenizer->isCPP(), true, ast1->astOperand1(), tok->astOperand2(), _settings->library, true) && isWithoutSideEffects(_tokenizer->isCPP(), ast1->astOperand1()))
// TODO: warn if variables are unchanged. See #5683
// Probably the message should be changed to 'duplicate expressions X in condition or something like that'.
;//duplicateExpressionError(ast1->astOperand1(), tok->astOperand2(), tok->str());
else if (styleEnabled && isSameExpression(_tokenizer->isCPP(), true, ast1->astOperand2(), tok->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer->isCPP(), ast1->astOperand2()))
else if (styleEnabled && isSameExpression(_tokenizer->isCPP(), true, ast1->astOperand2(), tok->astOperand2(), _settings->library, true) && isWithoutSideEffects(_tokenizer->isCPP(), ast1->astOperand2()))
duplicateExpressionError(ast1->astOperand2(), tok->astOperand2(), tok->str());
if (!isConstExpression(ast1->astOperand2(), _settings->library.functionpure))
if (!isConstExpression(ast1->astOperand2(), _settings->library, true))
break;
ast1 = ast1->astOperand1();
}
}
}
} else if (styleEnabled && tok->astOperand1() && tok->astOperand2() && tok->str() == ":" && tok->astParent() && tok->astParent()->str() == "?") {
if (isSameExpression(_tokenizer->isCPP(), true, tok->astOperand1(), tok->astOperand2(), temp))
if (isSameExpression(_tokenizer->isCPP(), true, tok->astOperand1(), tok->astOperand2(), _settings->library, false))
duplicateExpressionTernaryError(tok);
}
}
@ -2655,9 +2654,9 @@ void CheckOther::checkEvaluationOrder()
if (tok2 == tok &&
tok->str() == "=" &&
parent->str() == "=" &&
isSameExpression(_tokenizer->isCPP(), false, tok->astOperand1(), parent->astOperand1(), _settings->library.functionpure)) {
isSameExpression(_tokenizer->isCPP(), false, tok->astOperand1(), parent->astOperand1(), _settings->library, true)) {
if (_settings->isEnabled("warning") &&
isSameExpression(_tokenizer->isCPP(), true, tok->astOperand1(), parent->astOperand1(), _settings->library.functionpure))
isSameExpression(_tokenizer->isCPP(), true, tok->astOperand1(), parent->astOperand1(), _settings->library, true))
selfAssignmentError(parent, tok->astOperand1()->expressionString());
break;
}
@ -2677,7 +2676,7 @@ void CheckOther::checkEvaluationOrder()
continue; // don't care about sizeof usage
tokens.push(tok3->astOperand1());
tokens.push(tok3->astOperand2());
if (isSameExpression(_tokenizer->isCPP(), false, tok->astOperand1(), tok3, _settings->library.functionpure)) {
if (isSameExpression(_tokenizer->isCPP(), false, tok->astOperand1(), tok3, _settings->library, true)) {
foundError = true;
}
}

View File

@ -888,7 +888,7 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc al
break;
}
if (alloc != NO_ALLOC && parent->str() == "(") {
if (_settings->library.functionpure.find(parent->strAt(-1)) == _settings->library.functionpure.end()) {
if (!_settings->library.isFunctionConst(parent->strAt(-1), true)) {
assignment = true;
break;
}

View File

@ -187,7 +187,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
temp.arg = 1;
_dealloc[memorynode->GetText()] = temp;
} else if (memorynodename == "use")
use.insert(memorynode->GetText());
functions[memorynode->GetText()].use = true;
else
unknown_elements.insert(memorynodename);
}
@ -537,14 +537,14 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
if (functionnodename == "noreturn")
_noreturn[name] = (strcmp(functionnode->GetText(), "true") == 0);
else if (functionnodename == "pure")
functionpure.insert(name);
functions[name].ispure = true;
else if (functionnodename == "const") {
functionconst.insert(name);
functionpure.insert(name); // a constant function is pure
functions[name].ispure = true;
functions[name].isconst = true; // a constant function is pure
} else if (functionnodename == "leak-ignore")
leakignore.insert(name);
functions[name].leakignore = true;
else if (functionnodename == "use-retval")
_useretval.insert(name);
functions[name].useretval = true;
else if (functionnodename == "returnValue") {
if (const char *expr = functionnode->GetText())
_returnValue[name] = expr;
@ -558,7 +558,7 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
return Error(MISSING_ATTRIBUTE, "nr");
const bool bAnyArg = strcmp(argNrString, "any")==0;
const int nr = bAnyArg ? -1 : std::atoi(argNrString);
ArgumentChecks &ac = argumentChecks[name][nr];
ArgumentChecks &ac = functions[name].argumentChecks[nr];
ac.optional = functionnode->Attribute("default") != nullptr;
for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) {
const std::string argnodename = argnode->Name();
@ -633,19 +633,25 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
}
else if (argnodename == "iterator") {
ac.iteratorInfo.setType(argnode->Attribute("type"));
ac.iteratorInfo.setContainer(argnode->Attribute("container"));
ac.iteratorInfo.it = true;
const char* str = argnode->Attribute("type");
ac.iteratorInfo.first = str ? (std::strcmp(str, "first") == 0) : false;
ac.iteratorInfo.last = str ? (std::strcmp(str, "last") == 0) : false;
str = argnode->Attribute("container");
ac.iteratorInfo.container = str ? std::atoi(str) : 0;
}
else
unknown_elements.insert(argnodename);
}
} else if (functionnodename == "ignorefunction") {
_ignorefunction.insert(name);
functions[name].ignore = true;
} else if (functionnodename == "formatstr") {
functions[name].formatstr = true;
const tinyxml2::XMLAttribute* scan = functionnode->FindAttribute("scan");
const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute("secure");
_formatstr[name] = std::make_pair(scan && scan->BoolValue(), secure && secure->BoolValue());
functions[name].formatstr_scan = scan && scan->BoolValue();
functions[name].formatstr_secure = secure && secure->BoolValue();
} else if (functionnodename == "warn") {
WarnInfo wi;
const char* const severity = functionnode->Attribute("severity");
@ -788,8 +794,8 @@ bool Library::isnullargbad(const Token *ftok, int argnr) const
if (!arg) {
// scan format string argument should not be null
const std::string funcname = getFunctionName(ftok);
std::map<std::string, std::pair<bool, bool> >::const_iterator it = _formatstr.find(funcname);
if (it != _formatstr.end() && it->second.first)
std::map<std::string, Function>::const_iterator it = functions.find(funcname);
if (it != functions.cend() && it->second.formatstr && it->second.formatstr_scan)
return true;
}
return arg && arg->notnull;
@ -801,8 +807,8 @@ bool Library::isuninitargbad(const Token *ftok, int argnr) const
if (!arg) {
// non-scan format string argument should not be uninitialized
const std::string funcname = getFunctionName(ftok);
std::map<std::string, std::pair<bool, bool> >::const_iterator it = _formatstr.find(funcname);
if (it != _formatstr.end() && !it->second.first)
std::map<std::string, Function>::const_iterator it = functions.find(funcname);
if (it != functions.cend() && it->second.formatstr && !it->second.formatstr_scan)
return true;
}
return arg && arg->notuninit;
@ -813,14 +819,14 @@ bool Library::isuninitargbad(const Token *ftok, int argnr) const
const Library::AllocFunc* Library::alloc(const Token *tok) const
{
const std::string funcname = getFunctionName(tok);
return isNotLibraryFunction(tok) && argumentChecks.find(funcname) != argumentChecks.end() ? 0 : getAllocDealloc(_alloc, funcname);
return isNotLibraryFunction(tok) && functions.find(funcname) != functions.end() ? 0 : getAllocDealloc(_alloc, funcname);
}
/** get deallocation info for function */
const Library::AllocFunc* Library::dealloc(const Token *tok) const
{
const std::string funcname = getFunctionName(tok);
return isNotLibraryFunction(tok) && argumentChecks.find(funcname) != argumentChecks.end() ? 0 : getAllocDealloc(_dealloc, funcname);
return isNotLibraryFunction(tok) && functions.find(funcname) != functions.end() ? 0 : getAllocDealloc(_dealloc, funcname);
}
/** get allocation id for function */
@ -842,15 +848,14 @@ const Library::ArgumentChecks * Library::getarg(const Token *ftok, int argnr) co
{
if (isNotLibraryFunction(ftok))
return nullptr;
std::map<std::string, std::map<int, ArgumentChecks> >::const_iterator it1;
it1 = argumentChecks.find(getFunctionName(ftok));
if (it1 == argumentChecks.end())
std::map<std::string, Function>::const_iterator it1 = functions.find(getFunctionName(ftok));
if (it1 == functions.cend())
return nullptr;
const std::map<int,ArgumentChecks>::const_iterator it2 = it1->second.find(argnr);
if (it2 != it1->second.end())
const std::map<int,ArgumentChecks>::const_iterator it2 = it1->second.argumentChecks.find(argnr);
if (it2 != it1->second.argumentChecks.cend())
return &it2->second;
const std::map<int,ArgumentChecks>::const_iterator it3 = it1->second.find(-1);
if (it3 != it1->second.end())
const std::map<int,ArgumentChecks>::const_iterator it3 = it1->second.argumentChecks.find(-1);
if (it3 != it1->second.argumentChecks.cend())
return &it3->second;
return nullptr;
}
@ -926,12 +931,12 @@ bool Library::isNotLibraryFunction(const Token *ftok) const
bool Library::matchArguments(const Token *ftok, const std::string &functionName) const
{
int callargs = numberOfArguments(ftok);
const std::map<std::string, std::map<int, ArgumentChecks> >::const_iterator it = argumentChecks.find(functionName);
if (it == argumentChecks.end())
const std::map<std::string, Function>::const_iterator it = functions.find(functionName);
if (it == functions.cend())
return (callargs == 0);
int args = 0;
int firstOptionalArg = -1;
for (std::map<int, ArgumentChecks>::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
for (std::map<int, ArgumentChecks>::const_iterator it2 = it->second.argumentChecks.cbegin(); it2 != it->second.argumentChecks.cend(); ++it2) {
if (it2->first > args)
args = it2->first;
if (it2->second.optional && (firstOptionalArg == -1 || firstOptionalArg > it2->first))
@ -955,13 +960,18 @@ const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const
bool Library::formatstr_function(const Token* ftok) const
{
return (!isNotLibraryFunction(ftok) &&
_formatstr.find(getFunctionName(ftok)) != _formatstr.cend());
if (isNotLibraryFunction(ftok))
return false;
std::map<std::string, Library::Function>::const_iterator it = functions.find(getFunctionName(ftok));
if (it != functions.cend())
return it->second.formatstr;
return false;
}
int Library::formatstr_argno(const Token* ftok) const
{
const std::map<int, Library::ArgumentChecks>& argumentChecksFunc = argumentChecks.at(getFunctionName(ftok));
const std::map<int, Library::ArgumentChecks>& argumentChecksFunc = functions.at(getFunctionName(ftok)).argumentChecks;
for (std::map<int, Library::ArgumentChecks>::const_iterator i = argumentChecksFunc.cbegin(); i != argumentChecksFunc.cend(); ++i) {
if (i->second.formatstr) {
return i->first - 1;
@ -972,18 +982,22 @@ int Library::formatstr_argno(const Token* ftok) const
bool Library::formatstr_scan(const Token* ftok) const
{
return _formatstr.at(getFunctionName(ftok)).first;
return functions.at(getFunctionName(ftok)).formatstr_scan;
}
bool Library::formatstr_secure(const Token* ftok) const
{
return _formatstr.at(getFunctionName(ftok)).second;
return functions.at(getFunctionName(ftok)).formatstr_secure;
}
bool Library::isUseRetVal(const Token* ftok) const
{
return (!isNotLibraryFunction(ftok) &&
_useretval.find(getFunctionName(ftok)) != _useretval.end());
if (isNotLibraryFunction(ftok))
return false;
std::map<std::string, Library::Function>::const_iterator it = functions.find(getFunctionName(ftok));
if (it != functions.cend())
return it->second.useretval;
return false;
}
const std::string& Library::returnValue(const Token *ftok) const
@ -1010,6 +1024,47 @@ int Library::returnValueContainer(const Token *ftok) const
return it != _returnValueContainer.end() ? it->second : -1;
}
bool Library::hasminsize(const std::string &functionName) const
{
std::map<std::string, Function>::const_iterator it1 = functions.find(functionName);
if (it1 == functions.cend())
return false;
for (std::map<int, ArgumentChecks>::const_iterator it2 = it1->second.argumentChecks.cbegin(); it2 != it1->second.argumentChecks.cend(); ++it2) {
if (!it2->second.minsizes.empty())
return true;
}
return false;
}
bool Library::ignorefunction(const std::string& functionName) const
{
std::map<std::string, Library::Function>::const_iterator it = functions.find(functionName);
if (it != functions.cend())
return it->second.ignore;
return false;
}
bool Library::isUse(const std::string& functionName) const
{
std::map<std::string, Library::Function>::const_iterator it = functions.find(functionName);
if (it != functions.cend())
return it->second.use;
return false;
}
bool Library::isLeakIgnore(const std::string& functionName) const
{
std::map<std::string, Library::Function>::const_iterator it = functions.find(functionName);
if (it != functions.cend())
return it->second.leakignore;
return false;
}
bool Library::isFunctionConst(const std::string& functionName, bool pure) const
{
std::map<std::string, Library::Function>::const_iterator it = functions.find(functionName);
if (it != functions.cend())
return pure ? it->second.ispure : it->second.isconst;
return false;
}
bool Library::isnoreturn(const Token *ftok) const
{
if (ftok->function() && ftok->function()->isAttributeNoreturn())

View File

@ -31,7 +31,6 @@
#include <string>
#include <list>
#include <vector>
#include <cstring>
namespace tinyxml2 {
class XMLDocument;
@ -54,9 +53,10 @@ public:
class Error {
public:
Error() : errorcode(OK) , reason("") {}
explicit Error(ErrorCode e) : errorcode(e) , reason("") {}
Error(ErrorCode e, const std::string &r) : errorcode(e), reason(r) {}
Error() : errorcode(OK) {}
explicit Error(ErrorCode e) : errorcode(e) {}
template<typename T>
Error(ErrorCode e, T&& r) : errorcode(e), reason(r) {}
ErrorCode errorcode;
std::string reason;
};
@ -139,18 +139,10 @@ public:
}
bool formatstr_function(const Token* ftok) const;
int formatstr_argno(const Token* ftok) const;
bool formatstr_scan(const Token* ftok) const;
bool formatstr_secure(const Token* ftok) const;
std::set<std::string> use;
std::set<std::string> leakignore;
std::set<std::string> functionconst;
std::set<std::string> functionpure;
struct WarnInfo {
std::string message;
Standards standards;
@ -245,15 +237,6 @@ public:
class IteratorInfo {
public:
IteratorInfo() : it(false), container(0), first(false), last(false) {}
void setContainer(const char *str) {
it = true;
container = str ? std::atoi(str) : 0;
}
void setType(const char *str) {
it = true;
first = str ? (std::strcmp(str,"first") == 0) : false;
last = str ? (std::strcmp(str,"last") == 0) : false;
}
bool it;
int container;
@ -264,7 +247,7 @@ public:
class MinSize {
public:
enum Type {NONE,STRLEN,ARGVALUE,SIZEOF,MUL};
enum Type { NONE, STRLEN, ARGVALUE, SIZEOF, MUL };
MinSize(Type t, int a) : type(t), arg(a), arg2(0) {}
Type type;
int arg;
@ -273,8 +256,25 @@ public:
std::list<MinSize> minsizes;
};
// function name, argument nr => argument data
std::map<std::string, std::map<int, ArgumentChecks> > argumentChecks;
struct Function {
std::map<int, ArgumentChecks> argumentChecks; // argument nr => argument data
bool use;
bool leakignore;
bool isconst;
bool ispure;
bool useretval;
bool ignore; // ignore functions/macros from a library (gtk, qt etc)
bool formatstr;
bool formatstr_scan;
bool formatstr_secure;
Function() : use(false), leakignore(false), isconst(false), ispure(false), useretval(false), ignore(false), formatstr(false), formatstr_scan(false), formatstr_secure(false) {}
};
std::map<std::string, Function> functions;
bool isUse(const std::string& functionName) const;
bool isLeakIgnore(const std::string& functionName) const;
bool isFunctionConst(const std::string& functionName, bool pure) const;
bool isboolargbad(const Token *ftok, int argnr) const {
const ArgumentChecks *arg = getarg(ftok, argnr);
@ -306,18 +306,7 @@ public:
return arg && arg->iteratorInfo.it ? &arg->iteratorInfo : nullptr;
}
bool hasminsize(const std::string &functionName) const {
std::map<std::string, std::map<int, ArgumentChecks> >::const_iterator it1;
it1 = argumentChecks.find(functionName);
if (it1 == argumentChecks.end())
return false;
std::map<int,ArgumentChecks>::const_iterator it2;
for (it2 = it1->second.begin(); it2 != it1->second.end(); ++it2) {
if (!it2->second.minsizes.empty())
return true;
}
return false;
}
bool hasminsize(const std::string &functionName) const;
const std::list<ArgumentChecks::MinSize> *argminsizes(const Token *ftok, int argnr) const {
const ArgumentChecks *arg = getarg(ftok, argnr);
@ -334,9 +323,7 @@ public:
bool reportErrors(const std::string &path) const;
bool ignorefunction(const std::string &function) const {
return (_ignorefunction.find(function) != _ignorefunction.end());
}
bool ignorefunction(const std::string &function) const;
bool isexecutableblock(const std::string &file, const std::string &token) const;
@ -401,13 +388,13 @@ public:
, _const_ptr(false) {
}
bool operator == (const PlatformType & type) const {
return (_type == type._type &&
_signed == type._signed &&
return (_signed == type._signed &&
_unsigned == type._unsigned &&
_long == type._long &&
_pointer == type._pointer &&
_ptr_ptr == type._ptr_ptr &&
_const_ptr == type._const_ptr);
_const_ptr == type._const_ptr &&
_type == type._type);
}
bool operator != (const PlatformType & type) const {
return !(*this == type);
@ -431,16 +418,13 @@ public:
const PlatformType *platform_type(const std::string &name, const std::string & platform) const {
const std::map<std::string, Platform>::const_iterator it = platforms.find(platform);
if (it != platforms.end()) {
const PlatformType * const type = it->second.platform_type(name);
if (type)
return type;
}
const std::map<std::string, PlatformType>::const_iterator it2 = platform_types.find(name);
return (it2 != platform_types.end()) ? &(it2->second) : nullptr;
}
@ -504,7 +488,6 @@ private:
};
int allocid;
std::set<std::string> _files;
std::set<std::string> _useretval;
std::map<std::string, AllocFunc> _alloc; // allocation functions
std::map<std::string, AllocFunc> _dealloc; // deallocation functions
std::set<std::string> _functions;
@ -512,7 +495,6 @@ private:
std::map<std::string, std::string> _returnValue;
std::map<std::string, std::string> _returnValueType;
std::map<std::string, int> _returnValueContainer;
std::set<std::string> _ignorefunction; // ignore functions/macros from a library (gtk, qt etc)
std::map<std::string, bool> _reporterrors;
std::map<std::string, bool> _processAfterCode;
std::set<std::string> _markupExtensions; // file extensions of markup files
@ -520,8 +502,7 @@ private:
std::map<std::string, CodeBlock> _executableblocks; // keywords for blocks of executable code
std::map<std::string, ExportedFunctions> _exporters; // keywords that export variables/functions to libraries (meta-code/macros)
std::map<std::string, std::set<std::string> > _importers; // keywords that import variables/functions
std::map<std::string,int> _reflection; // invocation of reflection
std::map<std::string, std::pair<bool, bool> > _formatstr; // Parameters for format string checking
std::map<std::string, int> _reflection; // invocation of reflection
std::map<std::string, struct PodType> podtypes; // pod types
std::map<std::string, PlatformType> platform_types; // platform independent typedefs
std::map<std::string, Platform> platforms; // platform dependent typedefs

View File

@ -8420,9 +8420,9 @@ void Tokenizer::simplifyAttribute()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "%type% (") && !_settings->library.isNotLibraryFunction(tok)) {
if (_settings->library.functionpure.find(tok->str()) != _settings->library.functionpure.end())
if (_settings->library.isFunctionConst(tok->str(), true))
tok->isAttributePure(true);
if (_settings->library.functionconst.find(tok->str()) != _settings->library.functionconst.end())
if (_settings->library.isFunctionConst(tok->str(), false))
tok->isAttributeConst(true);
}
while (Token::Match(tok, "__attribute__|__attribute (") && tok->next()->link() && tok->next()->link()->next()) {

View File

@ -856,7 +856,7 @@ static void valueFlowOppositeCondition(SymbolDatabase *symboldatabase, const Set
const Token *cond2 = tok2->tokAt(4)->astOperand2();
if (!cond2 || !cond2->isComparisonOp())
continue;
if (isOppositeCond(true, cpp, cond1, cond2, settings->library.functionpure)) {
if (isOppositeCond(true, cpp, cond1, cond2, settings->library, true)) {
ValueFlow::Value value(1);
value.setKnown();
setTokenValue(const_cast<Token*>(cond2), value, settings);

View File

@ -66,9 +66,7 @@ private:
Library library;
readLibrary(library, xmldata);
ASSERT(library.use.empty());
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
ASSERT(library.functions.empty());
}
void function() const {
@ -86,9 +84,7 @@ private:
Library library;
readLibrary(library, xmldata);
ASSERT(library.use.empty());
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
ASSERT(library.functions.empty());
ASSERT(library.isnotnoreturn(tokenList.front()));
}
@ -222,13 +218,13 @@ private:
Library library;
readLibrary(library, xmldata);
ASSERT_EQUALS(true, library.argumentChecks["foo"][1].notuninit);
ASSERT_EQUALS(true, library.argumentChecks["foo"][2].notnull);
ASSERT_EQUALS(true, library.argumentChecks["foo"][3].formatstr);
ASSERT_EQUALS(true, library.argumentChecks["foo"][4].strz);
ASSERT_EQUALS(false, library.argumentChecks["foo"][4].optional);
ASSERT_EQUALS(true, library.argumentChecks["foo"][5].notbool);
ASSERT_EQUALS(true, library.argumentChecks["foo"][5].optional);
ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[1].notuninit);
ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[2].notnull);
ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[3].formatstr);
ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[4].strz);
ASSERT_EQUALS(false, library.functions["foo"].argumentChecks[4].optional);
ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[5].notbool);
ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[5].optional);
}
void function_arg_any() const {
@ -241,7 +237,7 @@ private:
Library library;
readLibrary(library, xmldata);
ASSERT_EQUALS(true, library.argumentChecks["foo"][-1].notuninit);
ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[-1].notuninit);
}
void function_arg_valid() const {
@ -346,9 +342,7 @@ private:
Library library;
readLibrary(library, xmldata);
ASSERT(library.use.empty());
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
ASSERT(library.functions.empty());
{
TokenList tokenList(nullptr);
@ -375,9 +369,7 @@ private:
Library library;
readLibrary(library, xmldata);
ASSERT(library.use.empty());
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
ASSERT(library.functions.empty());
{
Settings settings;
@ -471,9 +463,7 @@ private:
Library library;
readLibrary(library, xmldata);
ASSERT(library.use.empty());
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
ASSERT(library.functions.empty());
ASSERT(Library::ismemory(library.alloc("CreateX")));
ASSERT_EQUALS(library.allocId("CreateX"), library.deallocId("DeleteX"));
@ -516,9 +506,7 @@ private:
Library library;
readLibrary(library, xmldata);
ASSERT(library.use.empty());
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
ASSERT(library.functions.empty());
const Library::AllocFunc* af = library.alloc("CreateX");
ASSERT(af && af->arg == 5);
@ -539,9 +527,7 @@ private:
Library library;
readLibrary(library, xmldata);
ASSERT(library.use.empty());
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
ASSERT(library.functions.empty());
ASSERT(Library::isresource(library.allocId("CreateX")));
ASSERT_EQUALS(library.allocId("CreateX"), library.deallocId("DeleteX"));

View File

@ -2254,9 +2254,9 @@ private:
{
Library library;
Library::ArgumentChecks arg;
library.argumentChecks["x"][1] = arg;
library.argumentChecks["x"][2] = arg;
library.argumentChecks["x"][3] = arg;
library.functions["x"].argumentChecks[1] = arg;
library.functions["x"].argumentChecks[2] = arg;
library.functions["x"].argumentChecks[3] = arg;
std::list<const Token *> null, uninit;
CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U);
@ -2269,10 +2269,10 @@ private:
{
Library library;
Library::ArgumentChecks arg;
library.argumentChecks["x"][1] = arg;
library.argumentChecks["x"][2] = arg;
library.argumentChecks["x"][3] = arg;
library.argumentChecks["x"][1].notnull = true;
library.functions["x"].argumentChecks[1] = arg;
library.functions["x"].argumentChecks[2] = arg;
library.functions["x"].argumentChecks[3] = arg;
library.functions["x"].argumentChecks[1].notnull = true;
std::list<const Token *> null,uninit;
CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U);
@ -2286,10 +2286,10 @@ private:
{
Library library;
Library::ArgumentChecks arg;
library.argumentChecks["x"][1] = arg;
library.argumentChecks["x"][2] = arg;
library.argumentChecks["x"][3] = arg;
library.argumentChecks["x"][2].notuninit = true;
library.functions["x"].argumentChecks[1] = arg;
library.functions["x"].argumentChecks[2] = arg;
library.functions["x"].argumentChecks[3] = arg;
library.functions["x"].argumentChecks[2].notuninit = true;
std::list<const Token *> null,uninit;
CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U);
@ -2303,10 +2303,10 @@ private:
{
Library library;
Library::ArgumentChecks arg;
library.argumentChecks["x"][1] = arg;
library.argumentChecks["x"][2] = arg;
library.argumentChecks["x"][3] = arg;
library.argumentChecks["x"][3].notuninit = true;
library.functions["x"].argumentChecks[1] = arg;
library.functions["x"].argumentChecks[2] = arg;
library.functions["x"].argumentChecks[3] = arg;
library.functions["x"].argumentChecks[3].notuninit = true;
std::list<const Token *> null,uninit;
CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U);

View File

@ -2291,7 +2291,7 @@ private:
Settings settings;
settings.library.setnoreturn("exit", true);
settings.library.argumentChecks["exit"][1] = Library::ArgumentChecks();
settings.library.functions["exit"].argumentChecks[1] = Library::ArgumentChecks();
check("void foo() {\n"
" exit(0);\n"
" break;\n"