From 26da798bd1af171be429124e9131ab7c9f2fc91f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Sat, 13 Apr 2024 11:33:47 +0200 Subject: [PATCH 01/11] avoid some unchecked pointer dereferences (#6284) --- lib/astutils.cpp | 2 +- lib/checkclass.cpp | 22 +++---- lib/checkclass.h | 4 +- lib/checkcondition.cpp | 4 +- lib/checkio.cpp | 24 +++---- lib/checkother.cpp | 40 ++++++------ lib/checkother.h | 4 +- lib/ctu.cpp | 6 +- lib/programmemory.cpp | 6 +- lib/programmemory.h | 2 +- lib/symboldatabase.cpp | 126 ++++++++++++++++++------------------ lib/symboldatabase.h | 6 +- lib/tokenize.cpp | 96 +++++++++++++-------------- lib/tokenize.h | 2 +- lib/valueflow.cpp | 2 +- test/testsymboldatabase.cpp | 3 +- 16 files changed, 175 insertions(+), 174 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 65180150852..6a99cb2e6b5 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -771,7 +771,7 @@ std::vector getParentValueTypes(const Token* tok, const Settings* set if (Token::simpleMatch(tok->astParent(), "(") && ftok && !tok->astParent()->isCast() && ftok->tokType() != Token::eType) return {}; - if (Token::Match(tok->astParent(), "return|(|{|%assign%") && parent) { + if (parent && Token::Match(tok->astParent(), "return|(|{|%assign%")) { *parent = tok->astParent(); } if (tok->astParent()->valueType()) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 8fadb87e2a2..ab5f9b77a55 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -1740,7 +1740,7 @@ void CheckClass::operatorEqToSelf() // find the parameter name const Token *rhs = func.argumentList.cbegin()->nameToken(); const Token* out_ifStatementScopeStart = nullptr; - if (!hasAssignSelf(&func, rhs, &out_ifStatementScopeStart)) { + if (!hasAssignSelf(&func, rhs, out_ifStatementScopeStart)) { if (hasAllocation(&func, scope)) operatorEqToSelfError(func.token); } else if (out_ifStatementScopeStart != nullptr) { @@ -1859,7 +1859,7 @@ const Token * CheckClass::getIfStmtBodyStart(const Token *tok, const Token *rhs) return nullptr; } -bool CheckClass::hasAssignSelf(const Function *func, const Token *rhs, const Token **out_ifStatementScopeStart) +bool CheckClass::hasAssignSelf(const Function *func, const Token *rhs, const Token *&out_ifStatementScopeStart) { if (!rhs) return false; @@ -1882,7 +1882,7 @@ bool CheckClass::hasAssignSelf(const Function *func, const Token *rhs, const Tok if (tok2 && tok2->isUnaryOp("&") && tok2->astOperand1()->str() == rhs->str()) ret = true; if (ret) { - *out_ifStatementScopeStart = getIfStmtBodyStart(tok2, rhs); + out_ifStatementScopeStart = getIfStmtBodyStart(tok2, rhs); } return ret ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2; }); @@ -3400,13 +3400,13 @@ void CheckClass::checkThisUseAfterFree() const Token * freeToken = nullptr; std::set callstack; - checkThisUseAfterFreeRecursive(classScope, &func, &var, std::move(callstack), &freeToken); + checkThisUseAfterFreeRecursive(classScope, &func, &var, std::move(callstack), freeToken); } } } } -bool CheckClass::checkThisUseAfterFreeRecursive(const Scope *classScope, const Function *func, const Variable *selfPointer, std::set callstack, const Token **freeToken) +bool CheckClass::checkThisUseAfterFreeRecursive(const Scope *classScope, const Function *func, const Variable *selfPointer, std::set callstack, const Token *&freeToken) { if (!func || !func->functionScope) return false; @@ -3419,23 +3419,23 @@ bool CheckClass::checkThisUseAfterFreeRecursive(const Scope *classScope, const F const Token * const bodyStart = func->functionScope->bodyStart; const Token * const bodyEnd = func->functionScope->bodyEnd; for (const Token *tok = bodyStart; tok != bodyEnd; tok = tok->next()) { - const bool isDestroyed = *freeToken != nullptr && !func->isStatic(); + const bool isDestroyed = freeToken != nullptr && !func->isStatic(); if (Token::Match(tok, "delete %var% ;") && selfPointer == tok->next()->variable()) { - *freeToken = tok; + freeToken = tok; tok = tok->tokAt(2); } else if (Token::Match(tok, "%var% . reset ( )") && selfPointer == tok->variable()) - *freeToken = tok; + freeToken = tok; else if (Token::Match(tok->previous(), "!!. %name% (") && tok->function() && tok->function()->nestedIn == classScope) { if (isDestroyed) { - thisUseAfterFree(selfPointer->nameToken(), *freeToken, tok); + thisUseAfterFree(selfPointer->nameToken(), freeToken, tok); return true; } if (checkThisUseAfterFreeRecursive(classScope, tok->function(), selfPointer, callstack, freeToken)) return true; } else if (isDestroyed && Token::Match(tok->previous(), "!!. %name%") && tok->variable() && tok->variable()->scope() == classScope && !tok->variable()->isStatic() && !tok->variable()->isArgument()) { - thisUseAfterFree(selfPointer->nameToken(), *freeToken, tok); + thisUseAfterFree(selfPointer->nameToken(), freeToken, tok); return true; - } else if (*freeToken && Token::Match(tok, "return|throw")) { + } else if (freeToken && Token::Match(tok, "return|throw")) { // TODO return tok->str() == "throw"; } else if (tok->str() == "{" && tok->scope()->type == Scope::ScopeType::eLambda) { diff --git a/lib/checkclass.h b/lib/checkclass.h index bc2a9d5116d..ac81b698a54 100644 --- a/lib/checkclass.h +++ b/lib/checkclass.h @@ -298,7 +298,7 @@ class CPPCHECKLIB CheckClass : public Check { bool hasAllocation(const Function *func, const Scope* scope) const; bool hasAllocation(const Function *func, const Scope* scope, const Token *start, const Token *end) const; bool hasAllocationInIfScope(const Function *func, const Scope* scope, const Token *ifStatementScopeStart) const; - static bool hasAssignSelf(const Function *func, const Token *rhs, const Token **out_ifStatementScopeStart); + static bool hasAssignSelf(const Function *func, const Token *rhs, const Token *&out_ifStatementScopeStart); enum class Bool { TRUE, FALSE, BAILOUT }; static Bool isInverted(const Token *tok, const Token *rhs); static const Token * getIfStmtBodyStart(const Token *tok, const Token *rhs); @@ -411,7 +411,7 @@ class CPPCHECKLIB CheckClass : public Check { /** * @brief Helper for checkThisUseAfterFree */ - bool checkThisUseAfterFreeRecursive(const Scope *classScope, const Function *func, const Variable *selfPointer, std::set callstack, const Token **freeToken); + bool checkThisUseAfterFreeRecursive(const Scope *classScope, const Function *func, const Variable *selfPointer, std::set callstack, const Token *&freeToken); }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp index f5e250a0cd8..3203bef3986 100644 --- a/lib/checkcondition.cpp +++ b/lib/checkcondition.cpp @@ -1573,8 +1573,8 @@ void CheckCondition::alwaysTrueFalse() { const ValueFlow::Value *zeroValue = nullptr; const Token *nonZeroExpr = nullptr; - if (CheckOther::comparisonNonZeroExpressionLessThanZero(tok, &zeroValue, &nonZeroExpr, /*suppress*/ true) || - CheckOther::testIfNonZeroExpressionIsPositive(tok, &zeroValue, &nonZeroExpr)) + if (CheckOther::comparisonNonZeroExpressionLessThanZero(tok, zeroValue, nonZeroExpr, /*suppress*/ true) || + CheckOther::testIfNonZeroExpressionIsPositive(tok, zeroValue, nonZeroExpr)) continue; } diff --git a/lib/checkio.cpp b/lib/checkio.cpp index b4fc0a4abb6..cd919537b75 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -487,7 +487,7 @@ void CheckIO::invalidScanfError(const Token *tok) //--------------------------------------------------------------------------- static bool findFormat(nonneg int arg, const Token *firstArg, - const Token **formatStringTok, const Token **formatArgTok) + const Token *&formatStringTok, const Token *&formatArgTok) { const Token* argTok = firstArg; @@ -495,8 +495,8 @@ static bool findFormat(nonneg int arg, const Token *firstArg, argTok = argTok->nextArgument(); if (Token::Match(argTok, "%str% [,)]")) { - *formatArgTok = argTok->nextArgument(); - *formatStringTok = argTok; + formatArgTok = argTok->nextArgument(); + formatStringTok = argTok; return true; } if (Token::Match(argTok, "%var% [,)]") && @@ -506,13 +506,13 @@ static bool findFormat(nonneg int arg, const Token *firstArg, (argTok->variable()->dimensions().size() == 1 && argTok->variable()->dimensionKnown(0) && argTok->variable()->dimension(0) != 0))) { - *formatArgTok = argTok->nextArgument(); + formatArgTok = argTok->nextArgument(); if (!argTok->values().empty()) { const std::list::const_iterator value = std::find_if( argTok->values().cbegin(), argTok->values().cend(), std::mem_fn(&ValueFlow::Value::isTokValue)); if (value != argTok->values().cend() && value->isTokValue() && value->tokvalue && value->tokvalue->tokType() == Token::eString) { - *formatStringTok = value->tokvalue; + formatStringTok = value->tokvalue; } } return true; @@ -552,37 +552,37 @@ void CheckIO::checkWrongPrintfScanfArguments() if (formatStringArgNo >= 0) { // formatstring found in library. Find format string and first argument belonging to format string. - if (!findFormat(formatStringArgNo, tok->tokAt(2), &formatStringTok, &argListTok)) + if (!findFormat(formatStringArgNo, tok->tokAt(2), formatStringTok, argListTok)) continue; } else if (Token::simpleMatch(tok, "swprintf (")) { if (Token::Match(tok->tokAt(2)->nextArgument(), "%str%")) { // Find third parameter and format string - if (!findFormat(1, tok->tokAt(2), &formatStringTok, &argListTok)) + if (!findFormat(1, tok->tokAt(2), formatStringTok, argListTok)) continue; } else { // Find fourth parameter and format string - if (!findFormat(2, tok->tokAt(2), &formatStringTok, &argListTok)) + if (!findFormat(2, tok->tokAt(2), formatStringTok, argListTok)) continue; } } else if (isWindows && Token::Match(tok, "sprintf_s|swprintf_s (")) { // template int sprintf_s(char (&buffer)[size], const char *format, ...); - if (findFormat(1, tok->tokAt(2), &formatStringTok, &argListTok)) { + if (findFormat(1, tok->tokAt(2), formatStringTok, argListTok)) { if (!formatStringTok) continue; } // int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...); - else if (findFormat(2, tok->tokAt(2), &formatStringTok, &argListTok)) { + else if (findFormat(2, tok->tokAt(2), formatStringTok, argListTok)) { if (!formatStringTok) continue; } } else if (isWindows && Token::Match(tok, "_snprintf_s|_snwprintf_s (")) { // template int _snprintf_s(char (&buffer)[size], size_t count, const char *format, ...); - if (findFormat(2, tok->tokAt(2), &formatStringTok, &argListTok)) { + if (findFormat(2, tok->tokAt(2), formatStringTok, argListTok)) { if (!formatStringTok) continue; } // int _snprintf_s(char *buffer, size_t sizeOfBuffer, size_t count, const char *format, ...); - else if (findFormat(3, tok->tokAt(2), &formatStringTok, &argListTok)) { + else if (findFormat(3, tok->tokAt(2), formatStringTok, argListTok)) { if (!formatStringTok) continue; } diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 0f9f90415d4..e4fcfa73c16 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2713,13 +2713,13 @@ void CheckOther::checkSignOfUnsignedVariable() for (const Token *tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) { const ValueFlow::Value *zeroValue = nullptr; const Token *nonZeroExpr = nullptr; - if (comparisonNonZeroExpressionLessThanZero(tok, &zeroValue, &nonZeroExpr)) { + if (comparisonNonZeroExpressionLessThanZero(tok, zeroValue, nonZeroExpr)) { const ValueType* vt = nonZeroExpr->valueType(); if (vt->pointer) pointerLessThanZeroError(tok, zeroValue); else unsignedLessThanZeroError(tok, zeroValue, nonZeroExpr->expressionString()); - } else if (testIfNonZeroExpressionIsPositive(tok, &zeroValue, &nonZeroExpr)) { + } else if (testIfNonZeroExpressionIsPositive(tok, zeroValue, nonZeroExpr)) { const ValueType* vt = nonZeroExpr->valueType(); if (vt->pointer) pointerPositiveError(tok, zeroValue); @@ -2730,7 +2730,7 @@ void CheckOther::checkSignOfUnsignedVariable() } } -bool CheckOther::comparisonNonZeroExpressionLessThanZero(const Token *tok, const ValueFlow::Value **zeroValue, const Token **nonZeroExpr, bool suppress) +bool CheckOther::comparisonNonZeroExpressionLessThanZero(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr, bool suppress) { if (!tok->isComparisonOp() || !tok->astOperand1() || !tok->astOperand2()) return false; @@ -2739,24 +2739,24 @@ bool CheckOther::comparisonNonZeroExpressionLessThanZero(const Token *tok, const const ValueFlow::Value *v2 = tok->astOperand2()->getValue(0); if (Token::Match(tok, "<|<=") && v2 && v2->isKnown()) { - *zeroValue = v2; - *nonZeroExpr = tok->astOperand1(); + zeroValue = v2; + nonZeroExpr = tok->astOperand1(); } else if (Token::Match(tok, ">|>=") && v1 && v1->isKnown()) { - *zeroValue = v1; - *nonZeroExpr = tok->astOperand2(); + zeroValue = v1; + nonZeroExpr = tok->astOperand2(); } else { return false; } - if (const Variable* var = (*nonZeroExpr)->variable()) + if (const Variable* var = nonZeroExpr->variable()) if (var->typeStartToken()->isTemplateArg()) return suppress; - const ValueType* vt = (*nonZeroExpr)->valueType(); + const ValueType* vt = nonZeroExpr->valueType(); return vt && (vt->pointer || vt->sign == ValueType::UNSIGNED); } -bool CheckOther::testIfNonZeroExpressionIsPositive(const Token *tok, const ValueFlow::Value **zeroValue, const Token **nonZeroExpr) +bool CheckOther::testIfNonZeroExpressionIsPositive(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr) { if (!tok->isComparisonOp() || !tok->astOperand1() || !tok->astOperand2()) return false; @@ -2765,16 +2765,16 @@ bool CheckOther::testIfNonZeroExpressionIsPositive(const Token *tok, const Value const ValueFlow::Value *v2 = tok->astOperand2()->getValue(0); if (Token::simpleMatch(tok, ">=") && v2 && v2->isKnown()) { - *zeroValue = v2; - *nonZeroExpr = tok->astOperand1(); + zeroValue = v2; + nonZeroExpr = tok->astOperand1(); } else if (Token::simpleMatch(tok, "<=") && v1 && v1->isKnown()) { - *zeroValue = v1; - *nonZeroExpr = tok->astOperand2(); + zeroValue = v1; + nonZeroExpr = tok->astOperand2(); } else { return false; } - const ValueType* vt = (*nonZeroExpr)->valueType(); + const ValueType* vt = nonZeroExpr->valueType(); return vt && (vt->pointer || vt->sign == ValueType::UNSIGNED); } @@ -3863,7 +3863,7 @@ void CheckOther::checkModuloOfOneError(const Token *tok) //----------------------------------------------------------------------------- // Overlapping write (undefined behavior) //----------------------------------------------------------------------------- -static bool getBufAndOffset(const Token *expr, const Token **buf, MathLib::bigint *offset) +static bool getBufAndOffset(const Token *expr, const Token *&buf, MathLib::bigint *offset) { if (!expr) return false; @@ -3884,7 +3884,7 @@ static bool getBufAndOffset(const Token *expr, const Token **buf, MathLib::bigin return false; } } else if (expr->valueType() && expr->valueType()->pointer > 0) { - *buf = expr; + buf = expr; *offset = 0; return true; } else { @@ -3894,7 +3894,7 @@ static bool getBufAndOffset(const Token *expr, const Token **buf, MathLib::bigin return false; if (!offsetToken->hasKnownIntValue()) return false; - *buf = bufToken; + buf = bufToken; *offset = offsetToken->getKnownIntValue(); return true; } @@ -3973,9 +3973,9 @@ void CheckOther::checkOverlappingWrite() const MathLib::bigint sizeValue = args[nonOverlappingData->sizeArg-1]->getKnownIntValue(); const Token *buf1, *buf2; MathLib::bigint offset1, offset2; - if (!getBufAndOffset(ptr1, &buf1, &offset1)) + if (!getBufAndOffset(ptr1, buf1, &offset1)) continue; - if (!getBufAndOffset(ptr2, &buf2, &offset2)) + if (!getBufAndOffset(ptr2, buf2, &offset2)) continue; if (offset1 < offset2 && offset1 + sizeValue <= offset2) diff --git a/lib/checkother.h b/lib/checkother.h index 1b7d080e7e5..b64281d46de 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -56,10 +56,10 @@ class CPPCHECKLIB CheckOther : public Check { CheckOther() : Check(myName()) {} /** Is expression a comparison that checks if a nonzero (unsigned/pointer) expression is less than zero? */ - static bool comparisonNonZeroExpressionLessThanZero(const Token *tok, const ValueFlow::Value **zeroValue, const Token **nonZeroExpr, bool suppress = false); + static bool comparisonNonZeroExpressionLessThanZero(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr, bool suppress = false); /** Is expression a comparison that checks if a nonzero (unsigned/pointer) expression is positive? */ - static bool testIfNonZeroExpressionIsPositive(const Token *tok, const ValueFlow::Value **zeroValue, const Token **nonZeroExpr); + static bool testIfNonZeroExpressionIsPositive(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr); private: /** @brief This constructor is used when running checks. */ diff --git a/lib/ctu.cpp b/lib/ctu.cpp index 19a0e834136..789d0c675c8 100644 --- a/lib/ctu.cpp +++ b/lib/ctu.cpp @@ -276,7 +276,7 @@ std::list CTU::loadUnsafeUsageListFromXml(const tiny return ret; } -static int isCallFunction(const Scope *scope, int argnr, const Token **tok) +static int isCallFunction(const Scope *scope, int argnr, const Token *&tok) { const Variable * const argvar = scope->function->getArgumentVar(argnr); if (!argvar->isPointer()) @@ -299,7 +299,7 @@ static int isCallFunction(const Scope *scope, int argnr, const Token **tok) break; if (!prev->astOperand1() || !prev->astOperand1()->function()) break; - *tok = prev->previous(); + tok = prev->previous(); return argnr2; } return -1; @@ -424,7 +424,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer) // Nested function calls for (int argnr = 0; argnr < scopeFunction->argCount(); ++argnr) { const Token *tok; - const int argnr2 = isCallFunction(&scope, argnr, &tok); + const int argnr2 = isCallFunction(&scope, argnr, tok); if (argnr2 > 0) { FileInfo::NestedCall nestedCall(tokenizer, scopeFunction, tok); nestedCall.myArgNr = argnr + 1; diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 532da5ed879..62a1c2b2a2b 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -97,11 +97,11 @@ void ProgramMemory::setIntValue(const Token* expr, MathLib::bigint value, bool i setValue(expr, v); } -bool ProgramMemory::getTokValue(nonneg int exprid, const Token** result) const +bool ProgramMemory::getTokValue(nonneg int exprid, const Token*& result) const { const ValueFlow::Value* value = getValue(exprid); if (value && value->isTokValue()) { - *result = value->tokvalue; + result = value->tokvalue; return true; } return false; @@ -1469,7 +1469,7 @@ namespace { return lhs; } else if (expr->str() == "[" && expr->astOperand1() && expr->astOperand2()) { const Token* tokvalue = nullptr; - if (!pm->getTokValue(expr->astOperand1()->exprId(), &tokvalue)) { + if (!pm->getTokValue(expr->astOperand1()->exprId(), tokvalue)) { auto tokvalue_it = std::find_if(expr->astOperand1()->values().cbegin(), expr->astOperand1()->values().cend(), std::mem_fn(&ValueFlow::Value::isTokValue)); diff --git a/lib/programmemory.h b/lib/programmemory.h index 717284efb24..b746e2e8dd7 100644 --- a/lib/programmemory.h +++ b/lib/programmemory.h @@ -115,7 +115,7 @@ struct ProgramMemory { void setUnknown(const Token* expr); - bool getTokValue(nonneg int exprid, const Token** result) const; + bool getTokValue(nonneg int exprid, const Token*& result) const; bool hasValue(nonneg int exprid); const ValueFlow::Value& at(nonneg int exprid) const; diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 4f86497551c..4a883977ee2 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -542,7 +542,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() } // class function? - else if (isFunction(tok, scope, &funcStart, &argStart, &declEnd)) { + else if (isFunction(tok, scope, funcStart, argStart, declEnd)) { if (tok->previous()->str() != "::" || tok->strAt(-2) == scope->className) { Function function(tok, scope, funcStart, argStart); @@ -591,7 +591,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() Function* funcptr = &scope->functionList.back(); const Token *tok2 = funcStart; - addNewFunction(&scope, &tok2); + addNewFunction(scope, tok2); if (scope) { scope->functionOf = function.nestedIn; scope->function = funcptr; @@ -608,7 +608,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() const Scope * const nested = scope->findInNestedListRecursive(tok->strAt(-2)); if (nested) - addClassFunction(&scope, &tok, argStart); + addClassFunction(scope, tok, argStart); else { /** @todo handle friend functions */ } @@ -645,20 +645,20 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() const Token *declEnd = nullptr; // function? - if (isFunction(tok, scope, &funcStart, &argStart, &declEnd)) { + if (isFunction(tok, scope, funcStart, argStart, declEnd)) { // has body? if (declEnd && declEnd->str() == "{") { tok = funcStart; // class function if (tok->previous() && tok->previous()->str() == "::") - addClassFunction(&scope, &tok, argStart); + addClassFunction(scope, tok, argStart); // class destructor else if (tok->previous() && tok->previous()->str() == "~" && tok->strAt(-2) == "::") - addClassFunction(&scope, &tok, argStart); + addClassFunction(scope, tok, argStart); // regular function else { @@ -676,7 +676,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() else if (declEnd && declEnd->str() == ";") { if (tok->astParent() && tok->astParent()->str() == "::" && Token::Match(declEnd->previous(), "default|delete")) { - addClassFunction(&scope, &tok, argStart); + addClassFunction(scope, tok, argStart); continue; } @@ -761,7 +761,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() const Token *funcStart = nullptr; const Token *argStart = nullptr; const Token *declEnd = nullptr; - if (isFunction(ftok, scope, &funcStart, &argStart, &declEnd)) { + if (isFunction(ftok, scope, funcStart, argStart, declEnd)) { if (declEnd && declEnd->str() == ";") { bool newFunc = true; // Is this function already in the database? auto range = scope->functionMap.equal_range(ftok->str()); @@ -1886,7 +1886,7 @@ SymbolDatabase::~SymbolDatabase() } } -bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const Token **funcStart, const Token **argStart, const Token** declEnd) const +bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const Token *&funcStart, const Token *&argStart, const Token*& declEnd) const { if (tok->varId()) return false; @@ -1903,9 +1903,9 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const argStartTok = tok->link()->linkAt(-2); else argStartTok = tok->link()->linkAt(-1); - *funcStart = argStartTok->previous(); - *argStart = argStartTok; - *declEnd = Token::findmatch(tok2->link()->next(), "{|;"); + funcStart = argStartTok->previous(); + argStart = argStartTok; + declEnd = Token::findmatch(tok2->link()->next(), "{|;"); return true; } if (tok2 && tok2->str() == "[") { @@ -1917,9 +1917,9 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const argStartTok = tok->link()->linkAt(-2); else argStartTok = tok->link()->linkAt(-1); - *funcStart = argStartTok->previous(); - *argStart = argStartTok; - *declEnd = Token::findmatch(tok2, "{|;"); + funcStart = argStartTok->previous(); + argStart = argStartTok; + declEnd = Token::findmatch(tok2, "{|;"); return true; } } @@ -2031,9 +2031,9 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const Token::Match(tok2, ": ::| %name% (|::|<|{") || Token::Match(tok2, "&|&&| ;|{") || Token::Match(tok2, "= delete|default ;"))) { - *funcStart = tok; - *argStart = tok->next(); - *declEnd = Token::findmatch(tok2, "{|;"); + funcStart = tok; + argStart = tok->next(); + declEnd = Token::findmatch(tok2, "{|;"); return true; } } @@ -2044,9 +2044,9 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const tok->isUpperCaseName() && Token::simpleMatch(tok->linkAt(1), ") {") && (!tok->previous() || Token::Match(tok->previous(), "[;{}]"))) { - *funcStart = tok; - *argStart = tok->next(); - *declEnd = tok->linkAt(1)->next(); + funcStart = tok; + argStart = tok->next(); + declEnd = tok->linkAt(1)->next(); return true; } @@ -2056,9 +2056,9 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const if (Token::Match(tok2, ") const| ;|{|=") || Token::Match(tok2, ") : ::| %name% (|::|<|{") || Token::Match(tok2, ") const| noexcept {|;|(")) { - *funcStart = tok; - *argStart = tok2->link(); - *declEnd = Token::findmatch(tok2->next(), "{|;"); + funcStart = tok; + argStart = tok2->link(); + declEnd = Token::findmatch(tok2->next(), "{|;"); return true; } } @@ -2069,9 +2069,9 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const (!tok->previous() || Token::Match(tok->previous(), ";|}"))) { if (tok->isC()) { returnImplicitIntError(tok); - *funcStart = tok; - *argStart = tok->next(); - *declEnd = tok->linkAt(1)->next(); + funcStart = tok; + argStart = tok->next(); + declEnd = tok->linkAt(1)->next(); return true; } mTokenizer.syntaxError(tok); @@ -2763,8 +2763,8 @@ static bool typesMatch( const Token *first_token, const Scope *second_scope, const Token *second_token, - const Token **new_first, - const Token **new_second) + const Token *&new_first, + const Token *&new_second) { // get first type const Type* first_type = first_scope->check->findType(first_token, first_scope, /*lookOutside*/ true); @@ -2781,8 +2781,8 @@ static bool typesMatch( tok2 = tok2->next(); // update parser token positions if (tok1 && tok2) { - *new_first = tok1->previous(); - *new_second = tok2->previous(); + new_first = tok1->previous(); + new_second = tok2->previous(); return true; } } @@ -2958,7 +2958,7 @@ bool Function::argsMatch(const Scope *scope, const Token *first, const Token *se first = first->tokAt(offset); // same type with different qualification - else if (typesMatch(scope, first->next(), nestedIn, second->next(), &first, &second)) + else if (typesMatch(scope, first->next(), nestedIn, second->next(), first, second)) ; // variable with class path @@ -3225,7 +3225,7 @@ Function* SymbolDatabase::addGlobalFunction(Scope*& scope, const Token*& tok, co function->token = funcStart; function->hasBody(true); - addNewFunction(&scope, &tok); + addNewFunction(scope, tok); if (scope) { scope->function = function; @@ -3242,16 +3242,16 @@ Function* SymbolDatabase::addGlobalFunctionDecl(Scope*& scope, const Token *tok, return &scope->functionList.back(); } -void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const Token *argStart) +void SymbolDatabase::addClassFunction(Scope *&scope, const Token *&tok, const Token *argStart) { - const bool destructor((*tok)->previous()->str() == "~"); + const bool destructor(tok->previous()->str() == "~"); const bool has_const(argStart->link()->strAt(1) == "const"); const bool lval(argStart->link()->strAt(has_const ? 2 : 1) == "&"); const bool rval(argStart->link()->strAt(has_const ? 2 : 1) == "&&"); int count = 0; std::string path; unsigned int path_length = 0; - const Token *tok1 = (*tok); + const Token *tok1 = tok; if (destructor) tok1 = tok1->previous(); @@ -3292,14 +3292,14 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To bool match = false; // check in namespace if using found - if (*scope == scope1 && !scope1->usingList.empty()) { + if (scope == scope1 && !scope1->usingList.empty()) { std::vector::const_iterator it2; for (it2 = scope1->usingList.cbegin(); it2 != scope1->usingList.cend(); ++it2) { if (it2->scope) { Function * func = findFunctionInScope(tok1, it2->scope, path, path_length); if (func) { if (!func->hasBody()) { - const Token *closeParen = (*tok)->next()->link(); + const Token *closeParen = tok->next()->link(); if (closeParen) { const Token *eq = Tokenizer::isFunctionHead(closeParen, ";"); if (eq && Token::simpleMatch(eq->tokAt(-2), "= default ;")) { @@ -3308,13 +3308,13 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To } } func->hasBody(true); - func->token = *tok; + func->token = tok; func->arg = argStart; addNewFunction(scope, tok); - if (*scope) { - (*scope)->functionOf = func->nestedIn; - (*scope)->function = func; - (*scope)->function->functionScope = *scope; + if (scope) { + scope->functionOf = func->nestedIn; + scope->function = func; + scope->function->functionScope = scope; } return; } @@ -3326,14 +3326,14 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To const bool isAnonymousNamespace = (scope1->type == Scope::eNamespace && scope1->className.empty()); if ((scope1->className == tok1->str() && (scope1->type != Scope::eFunction)) || isAnonymousNamespace) { // do the scopes match (same scope) or do their names match (multiple namespaces) - if ((*scope == scope1->nestedIn) || (*scope && - (*scope)->className == scope1->nestedIn->className && - !(*scope)->className.empty() && - (*scope)->type == scope1->nestedIn->type)) { + if ((scope == scope1->nestedIn) || (scope && + scope->className == scope1->nestedIn->className && + !scope->className.empty() && + scope->type == scope1->nestedIn->type)) { // nested scopes => check that they match { - const Scope *s1 = *scope; + const Scope *s1 = scope; const Scope *s2 = scope1->nestedIn; while (s1 && s2) { if (s1->className != s2->className) @@ -3367,12 +3367,12 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To } if (match) { - auto range = scope1->functionMap.equal_range((*tok)->str()); + auto range = scope1->functionMap.equal_range(tok->str()); for (std::multimap::const_iterator it = range.first; it != range.second; ++it) { auto * func = const_cast(it->second); if (!func->hasBody()) { - if (func->argsMatch(scope1, func->argDef, (*tok)->next(), path, path_length)) { - const Token *closeParen = (*tok)->next()->link(); + if (func->argsMatch(scope1, func->argDef, tok->next(), path, path_length)) { + const Token *closeParen = tok->next()->link(); if (closeParen) { const Token *eq = Tokenizer::isFunctionHead(closeParen, ";"); if (eq && Token::simpleMatch(eq->tokAt(-2), "= default ;")) { @@ -3393,13 +3393,13 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To } if (func->hasBody()) { - func->token = *tok; + func->token = tok; func->arg = argStart; addNewFunction(scope, tok); - if (*scope) { - (*scope)->functionOf = scope1; - (*scope)->function = func; - (*scope)->function->functionScope = *scope; + if (scope) { + scope->functionOf = scope1; + scope->function = func; + scope->function->functionScope = scope; } return; } @@ -3413,10 +3413,10 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To addNewFunction(scope, tok); } -void SymbolDatabase::addNewFunction(Scope **scope, const Token **tok) +void SymbolDatabase::addNewFunction(Scope *&scope, const Token *&tok) { - const Token *tok1 = *tok; - scopeList.emplace_back(this, tok1, *scope); + const Token *tok1 = tok; + scopeList.emplace_back(this, tok1, scope); Scope *newScope = &scopeList.back(); // find start of function '{' @@ -3440,15 +3440,15 @@ void SymbolDatabase::addNewFunction(Scope **scope, const Token **tok) if (!newScope->bodyEnd) { mTokenizer.unmatchedToken(tok1); } else { - (*scope)->nestedList.push_back(newScope); - *scope = newScope; + scope->nestedList.push_back(newScope); + scope = newScope; } } else if (tok1 && Token::Match(tok1->tokAt(-2), "= default|delete ;")) { scopeList.pop_back(); } else { - throw InternalError(*tok, "Analysis failed (function not recognized). If the code is valid then please report this failure."); + throw InternalError(tok, "Analysis failed (function not recognized). If the code is valid then please report this failure."); } - *tok = tok1; + tok = tok1; } bool Type::isClassType() const diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 901991313d4..0dfebdbedb6 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1435,11 +1435,11 @@ class CPPCHECKLIB SymbolDatabase { void debugSymbolDatabase() const; - void addClassFunction(Scope **scope, const Token **tok, const Token *argStart); + void addClassFunction(Scope *&scope, const Token *&tok, const Token *argStart); static Function *addGlobalFunctionDecl(Scope*& scope, const Token* tok, const Token *argStart, const Token* funcStart); Function *addGlobalFunction(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart); - void addNewFunction(Scope **scope, const Token **tok); - bool isFunction(const Token *tok, const Scope* outerScope, const Token **funcStart, const Token **argStart, const Token** declEnd) const; + void addNewFunction(Scope *&scope, const Token *&tok); + bool isFunction(const Token *tok, const Scope* outerScope, const Token *&funcStart, const Token *&argStart, const Token*& declEnd) const; const Type *findTypeInNested(const Token *startTok, const Scope *startScope) const; const Scope *findNamespace(const Token * tok, const Scope * scope) const; static Function *findFunctionInScope(const Token *func, const Scope *ns, const std::string & path, nonneg int path_length); diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 25317d38de2..b3b5378bbad 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -84,13 +84,13 @@ static bool isEnumStart(const Token* tok) } template -static void skipEnumBody(T **tok) +static void skipEnumBody(T *&tok) { - T *defStart = *tok; + T *defStart = tok; while (Token::Match(defStart, "%name%|::|:")) defStart = defStart->next(); if (defStart && defStart->str() == "{") - *tok = defStart->link()->next(); + tok = defStart->link()->next(); } const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &endsWith) @@ -211,10 +211,10 @@ nonneg int Tokenizer::sizeOfType(const Token *type) const //--------------------------------------------------------------------------- // check if this statement is a duplicate definition -bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name, const Token *typeDef) const +bool Tokenizer::duplicateTypedef(Token *&tokPtr, const Token *name, const Token *typeDef) const { // check for an end of definition - Token * tok = *tokPtr; + Token * tok = tokPtr; if (tok && Token::Match(tok->next(), ";|,|[|=|)|>|(|{")) { Token * end = tok->next(); @@ -252,7 +252,7 @@ bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name, const Token if (!Token::Match(tok->tokAt(-3), ",|<")) return false; - *tokPtr = end->link(); + tokPtr = end->link(); return true; } } @@ -263,7 +263,7 @@ bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name, const Token if (Token::Match(tok->previous(), "%type%") && !Token::Match(tok->previous(), "return|new|const|struct")) { // duplicate definition so skip entire function - *tokPtr = end->next()->link(); + tokPtr = end->next()->link(); return true; } } else if (end->str() == ">") { // template parameter ? @@ -274,7 +274,7 @@ bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name, const Token while (end && end->str() != "{") end = end->next(); if (end) { - *tokPtr = end->link(); + tokPtr = end->link(); return true; } } @@ -319,7 +319,7 @@ bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name, const Token tok = tok->previous(); } - if ((*tokPtr)->strAt(1) != "(" || !Token::Match((*tokPtr)->linkAt(1), ") .|(|[")) + if (tokPtr->strAt(1) != "(" || !Token::Match(tokPtr->linkAt(1), ") .|(|[")) return true; } } @@ -1843,7 +1843,7 @@ void Tokenizer::simplifyTypedefCpp() } } else if (Token::Match(tok2->previous(), "case|;|{|} %type% :")) { tok2 = tok2->next(); - } else if (duplicateTypedef(&tok2, typeName, typeDef)) { + } else if (duplicateTypedef(tok2, typeName, typeDef)) { // skip to end of scope if not already there if (tok2->str() != "}") { while (tok2->next()) { @@ -2491,22 +2491,22 @@ namespace { } }; - void setScopeInfo(Token *tok, ScopeInfo3 **scopeInfo, bool debug=false) + void setScopeInfo(Token *tok, ScopeInfo3 *&scopeInfo, bool debug=false) { if (!tok) return; - if (tok->str() == "{" && (*scopeInfo)->parent && tok == (*scopeInfo)->bodyStart) + if (tok->str() == "{" && scopeInfo->parent && tok == scopeInfo->bodyStart) return; if (tok->str() == "}") { - if ((*scopeInfo)->parent && tok == (*scopeInfo)->bodyEnd) - *scopeInfo = (*scopeInfo)->parent; + if (scopeInfo->parent && tok == scopeInfo->bodyEnd) + scopeInfo = scopeInfo->parent; else { // Try to find parent scope - ScopeInfo3 *parent = (*scopeInfo)->parent; + ScopeInfo3 *parent = scopeInfo->parent; while (parent && parent->bodyEnd != tok) parent = parent->parent; if (parent) { - *scopeInfo = parent; + scopeInfo = parent; if (debug) throw std::runtime_error("Internal error: unmatched }"); } @@ -2524,7 +2524,7 @@ namespace { nameSpace += tok1->str(); tok1 = tok1->next(); } - (*scopeInfo)->usingNamespaces.insert(std::move(nameSpace)); + scopeInfo->usingNamespaces.insert(std::move(nameSpace)); } // check for member function else if (tok->str() == "{") { @@ -2561,13 +2561,13 @@ namespace { scope = tok1->strAt(-3) + " :: " + scope; tok1 = tok1->tokAt(-2); } - *scopeInfo = (*scopeInfo)->addChild(ScopeInfo3::MemberFunction, scope, tok, tok->link()); + scopeInfo = scopeInfo->addChild(ScopeInfo3::MemberFunction, scope, tok, tok->link()); added = true; } } if (!added) - *scopeInfo = (*scopeInfo)->addChild(ScopeInfo3::Other, emptyString, tok, tok->link()); + scopeInfo = scopeInfo->addChild(ScopeInfo3::Other, emptyString, tok, tok->link()); } return; } @@ -2582,7 +2582,7 @@ namespace { // add record type to scope info if (record) - (*scopeInfo)->recordTypes.insert(classname); + scopeInfo->recordTypes.insert(classname); tok = tok->next(); // skip template parameters @@ -2622,8 +2622,8 @@ namespace { } if (tok && tok->str() == "{") { - *scopeInfo = (*scopeInfo)->addChild(record ? ScopeInfo3::Record : ScopeInfo3::Namespace, classname, tok, tok->link()); - (*scopeInfo)->baseTypes = std::move(baseTypes); + scopeInfo = scopeInfo->addChild(record ? ScopeInfo3::Record : ScopeInfo3::Namespace, classname, tok, tok->link()); + scopeInfo->baseTypes = std::move(baseTypes); } } @@ -2644,19 +2644,19 @@ namespace { bool usingMatch( const Token *nameToken, const std::string &scope, - Token **tok, + Token *&tok, const std::string &scope1, const ScopeInfo3 *currentScope, const ScopeInfo3 *memberClassScope) { - Token *tok1 = *tok; + Token *tok1 = tok; if (tok1 && tok1->str() != nameToken->str()) return false; // skip this using if (tok1 == nameToken) { - *tok = findSemicolon(tok1); + tok = findSemicolon(tok1); return false; } @@ -2665,7 +2665,7 @@ namespace { // fixme: this is wrong // skip to end of scope if (currentScope->bodyEnd) - *tok = const_cast(currentScope->bodyEnd->previous()); + tok = const_cast(currentScope->bodyEnd->previous()); return false; } @@ -2897,7 +2897,7 @@ bool Tokenizer::simplifyUsing() if (Token::Match(tok, "{|}|namespace|class|struct|union") || Token::Match(tok, "using namespace %name% ;|::")) { try { - setScopeInfo(tok, ¤tScope, mSettings.debugwarnings); + setScopeInfo(tok, currentScope, mSettings.debugwarnings); } catch (const std::runtime_error &) { reportError(tok, Severity::debug, "simplifyUsingUnmatchedBodyEnd", "simplifyUsing: unmatched body end"); @@ -3054,7 +3054,7 @@ bool Tokenizer::simplifyUsing() if ((Token::Match(tok1, "{|}|namespace|class|struct|union") && tok1->strAt(-1) != "using") || Token::Match(tok1, "using namespace %name% ;|::")) { try { - setScopeInfo(tok1, ¤tScope1, mSettings.debugwarnings); + setScopeInfo(tok1, currentScope1, mSettings.debugwarnings); } catch (const std::runtime_error &) { reportError(tok1, Severity::debug, "simplifyUsingUnmatchedBodyEnd", "simplifyUsing: unmatched body end"); @@ -3105,9 +3105,9 @@ bool Tokenizer::simplifyUsing() continue; } if (inMemberFunc && memberFuncScope) { - if (!usingMatch(nameToken, scope, &tok1, scope1, currentScope1, memberFuncScope)) + if (!usingMatch(nameToken, scope, tok1, scope1, currentScope1, memberFuncScope)) continue; - } else if (!usingMatch(nameToken, scope, &tok1, scope1, currentScope1, nullptr)) + } else if (!usingMatch(nameToken, scope, tok1, scope1, currentScope1, nullptr)) continue; const auto nReplace = tokDistance(start, usingEnd); @@ -3748,9 +3748,9 @@ void Tokenizer::simplifyDoublePlusAndDoubleMinus() void Tokenizer::arraySize() { - auto getStrTok = [](Token* tok, bool addLength, Token** endStmt) -> Token* { + auto getStrTok = [](Token* tok, bool addLength, Token*& endStmt) -> Token* { if (addLength) { - *endStmt = tok->tokAt(5); + endStmt = tok->tokAt(5); return tok->tokAt(4); } if (Token::Match(tok, "%var% [ ] =")) { @@ -3761,7 +3761,7 @@ void Tokenizer::arraySize() tok = tok->next(); } if (Token::Match(tok, "%str%")) { - *endStmt = tok->tokAt(parCount + 1); + endStmt = tok->tokAt(parCount + 1); return tok; } } @@ -3780,7 +3780,7 @@ void Tokenizer::arraySize() } Token* endStmt{}; - if (const Token* strTok = getStrTok(tok, addlength, &endStmt)) { + if (const Token* strTok = getStrTok(tok, addlength, endStmt)) { const int sz = Token::getStrArraySize(strTok); tok->next()->insertToken(std::to_string(sz)); tok = endStmt; @@ -4161,10 +4161,10 @@ void VariableMap::addVariable(const std::string& varname, bool globalNamespace) it->second = ++mVarId; } -static bool setVarIdParseDeclaration(Token** tok, const VariableMap& variableMap, bool executableScope) +static bool setVarIdParseDeclaration(Token*& tok, const VariableMap& variableMap, bool executableScope) { - const Token* const tok1 = *tok; - Token* tok2 = *tok; + const Token* const tok1 = tok; + Token* tok2 = tok; if (!tok2->isName()) return false; @@ -4204,7 +4204,7 @@ static bool setVarIdParseDeclaration(Token** tok, const VariableMap& variableMap } } else if (tok2->isCpp() && ((TemplateSimplifier::templateParameters(tok2) > 0) || Token::simpleMatch(tok2, "< >") /* Ticket #4764 */)) { - const Token *start = *tok; + const Token *start = tok; if (Token::Match(start->previous(), "%or%|%oror%|&&|&|^|+|-|*|/")) return false; Token* const closingBracket = tok2->findClosingBracket(); @@ -4248,7 +4248,7 @@ static bool setVarIdParseDeclaration(Token** tok, const VariableMap& variableMap if (tok2) { bool isLambdaArg = false; { - const Token *tok3 = (*tok)->previous(); + const Token *tok3 = tok->previous(); if (tok3 && tok3->str() == ",") { while (tok3 && !Token::Match(tok3,";|(|[|{")) { if (Token::Match(tok3, ")|]")) @@ -4274,7 +4274,7 @@ static bool setVarIdParseDeclaration(Token** tok, const VariableMap& variableMap } - *tok = tok2; + tok = tok2; // In executable scopes, references must be assigned // Catching by reference is an exception @@ -4303,11 +4303,11 @@ static bool setVarIdParseDeclaration(Token** tok, const VariableMap& variableMap } -static void setVarIdStructMembers(Token **tok1, +static void setVarIdStructMembers(Token *&tok1, std::map>& structMembers, nonneg int &varId) { - Token *tok = *tok1; + Token *tok = tok1; if (Token::Match(tok, "%name% = { . %name% =|{")) { const nonneg int struct_varid = tok->varId(); @@ -4365,7 +4365,7 @@ static void setVarIdStructMembers(Token **tok1, } } // tok can't be null - *tok1 = tok; + tok1 = tok; } static bool setVarIdClassDeclaration(Token* const startToken, @@ -4433,7 +4433,7 @@ static bool setVarIdClassDeclaration(Token* const startToken, const std::unordered_map::const_iterator it = variableMap.map(false).find(tok->str()); if (it != variableMap.map(false).end()) { tok->varId(it->second); - setVarIdStructMembers(&tok, structMembers, variableMap.getVarId()); + setVarIdStructMembers(tok, structMembers, variableMap.getVarId()); } } } @@ -4471,7 +4471,7 @@ void Tokenizer::setVarIdClassFunction(const std::string &classname, const std::map::const_iterator it = varlist.find(tok2->str()); if (it != varlist.end()) { tok2->varId(it->second); - setVarIdStructMembers(&tok2, structMembers, varId_); + setVarIdStructMembers(tok2, structMembers, varId_); } } } @@ -4688,7 +4688,7 @@ void Tokenizer::setVarIdPass1() } try { /* Ticket #8151 */ - decl = setVarIdParseDeclaration(&tok2, variableMap, scopeStack.top().isExecutable); + decl = setVarIdParseDeclaration(tok2, variableMap, scopeStack.top().isExecutable); } catch (const Token * errTok) { syntaxError(errTok); } @@ -4851,7 +4851,7 @@ void Tokenizer::setVarIdPass1() const std::unordered_map::const_iterator it = variableMap.map(globalNamespace).find(tok->str()); if (it != variableMap.map(globalNamespace).end()) { tok->varId(it->second); - setVarIdStructMembers(&tok, structMembers, variableMap.getVarId()); + setVarIdStructMembers(tok, structMembers, variableMap.getVarId()); } } } else if (Token::Match(tok, "::|. %name%") && Token::Match(tok->previous(), ")|]|>|%name%")) { @@ -9759,7 +9759,7 @@ void Tokenizer::simplifyNamespaceStd() for (Token* tok = Token::findsimplematch(list.front(), "using namespace std ;"); tok; tok = tok->next()) { bool insert = false; if (Token::Match(tok, "enum class|struct| %name%| :|{")) { // Don't replace within enum definitions - skipEnumBody(&tok); + skipEnumBody(tok); } if (!tok->isName() || tok->isKeyword() || tok->isStandardType() || tok->varId()) continue; diff --git a/lib/tokenize.h b/lib/tokenize.h index a7bbbe32a25..556eb18f253 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -538,7 +538,7 @@ class CPPCHECKLIB Tokenizer { void reportError(const Token* tok, const Severity severity, const std::string& id, const std::string& msg, bool inconclusive = false) const; void reportError(const std::list& callstack, Severity severity, const std::string& id, const std::string& msg, bool inconclusive = false) const; - bool duplicateTypedef(Token **tokPtr, const Token *name, const Token *typeDef) const; + bool duplicateTypedef(Token *&tokPtr, const Token *name, const Token *typeDef) const; void unsupportedTypedef(const Token *tok) const; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index dcb0eb710bc..dc826e60290 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -8561,7 +8561,7 @@ static void valueFlowSmartPointer(TokenList &tokenlist, ErrorLogger & errorLogge static Library::Container::Yield findIteratorYield(Token* tok, const Token** ftok, const Settings &settings) { auto yield = astContainerYield(tok, ftok); - if (*ftok) + if (ftok && *ftok) return yield; if (!tok->astParent()) diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index d56db42fef9..7e44bf56a21 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -6568,7 +6568,8 @@ class TestSymbolDatabase : public TestFixture { " *PTRRELOC(&x) = &y;\n" "}"); ASSERT(db != nullptr); - ASSERT(db && !db->isFunction(Token::findsimplematch(tokenizer.tokens(), "PTRRELOC ( &"), &db->scopeList.back(), nullptr, nullptr, nullptr)); + const Token *funcStart, *argStart, *declEnd; + ASSERT(db && !db->isFunction(Token::findsimplematch(tokenizer.tokens(), "PTRRELOC ( &"), &db->scopeList.back(), funcStart, argStart, declEnd)); ASSERT(db->findScopeByName("set_cur_cpu_spec") != nullptr); ASSERT(db->findScopeByName("setup_cpu_spec") != nullptr); ASSERT(db->findScopeByName("PTRRELOC") == nullptr); From fe3bf914e5f6fbfe34f7053982cdf16a0efcb706 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sat, 13 Apr 2024 15:32:21 +0200 Subject: [PATCH 02/11] Add test for #12401 (#6289) --- test/testuninitvar.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 08b1a0908d3..ade4a61cbd6 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -7502,6 +7502,16 @@ class TestUninitVar : public TestFixture { " int len = strlen(arr);\n" "}\n"); ASSERT_EQUALS("[test.cpp:8]: (error) Uninitialized variable: arr\n", errout_str()); + + valueFlowUninit("struct S1 { int x; };\n" // #12401 + "struct S2 { struct S1 s1; };\n" + "struct S2 f() {\n" + " struct S2 s2;\n" + " struct S1* s1 = &s2.s1;\n" + " s1->x = 0;\n" + " return s2;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void uninitvar_memberfunction() { From 01c049d822e606dc3d2c8f1f45dd28a7cd172cff Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sat, 13 Apr 2024 21:28:19 +0200 Subject: [PATCH 03/11] Fix #12597 syntaxError with array typedef in namespace (#6287) --- lib/tokenize.cpp | 2 ++ test/testsimplifytypedef.cpp | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index b3b5378bbad..77d797eb0a4 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2249,6 +2249,8 @@ void Tokenizer::simplifyTypedefCpp() tok2 = tok3->tokAt(3); else if (Token::Match(tok2->tokAt(3), "[(),;]")) tok2 = tok2->tokAt(2); + else if (Token::simpleMatch(tok2->tokAt(3), ">")) + tok2 = tok2->tokAt(2); else tok2 = tok2->tokAt(3); if (!tok2) diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 3118afa31ce..4970e863c5d 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -214,6 +214,7 @@ class TestSimplifyTypedef : public TestFixture { TEST_CASE(simplifyTypedef148); TEST_CASE(simplifyTypedef149); TEST_CASE(simplifyTypedef150); + TEST_CASE(simplifyTypedef151); TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction2); // ticket #1685 @@ -3530,6 +3531,18 @@ class TestSimplifyTypedef : public TestFixture { ASSERT_EQUALS(exp, tok(code)); } + void simplifyTypedef151() { + const char* code{}, *exp{}; + code = "namespace N {\n" // #12597 + " typedef int T[10];\n" + " const T* f() { return static_cast(nullptr); }\n" + "}\n"; + exp = "namespace N { " + "const int ( * f ( ) ) [ 10 ] { return static_cast < const int ( * ) [ 10 ] > ( nullptr ) ; } " + "}"; + ASSERT_EQUALS(exp, tok(code)); + } + void simplifyTypedefFunction1() { { const char code[] = "typedef void (*my_func)();\n" From 068b0b8f0ae9ccd07e2ccae0b85af653f2e9a716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Mon, 15 Apr 2024 13:45:55 +0200 Subject: [PATCH 04/11] iwyu.yml: use Qt 6 for `clang-include-cleaner` and include the GUI sources in its analysis (#6291) --- .github/workflows/iwyu.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/iwyu.yml b/.github/workflows/iwyu.yml index 1a8fcafdd5d..2c7b402d74a 100644 --- a/.github/workflows/iwyu.yml +++ b/.github/workflows/iwyu.yml @@ -122,7 +122,7 @@ jobs: if: ${{ github.repository_owner == 'danmar' }} env: - QT_VERSION: 5.15.2 + QT_VERSION: 6.7.0 steps: - uses: actions/checkout@v3 @@ -151,7 +151,7 @@ jobs: - name: Prepare CMake run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DBUILD_GUI=On -DWITH_QCHART=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On + cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DUSE_QT6=On -DWITH_QCHART=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On env: CC: clang-18 CXX: clang++-18 @@ -171,7 +171,7 @@ jobs: - name: clang-include-cleaner run: | # TODO: run multi-threaded - find $PWD/cli $PWD/lib $PWD/test -maxdepth 1 -name "*.cpp" | xargs -t -n 1 clang-include-cleaner-18 --print=changes --extra-arg=-w -p cmake.output > clang-include-cleaner.log 2>&1 + find $PWD/cli $PWD/lib $PWD/test $PWD/gui -maxdepth 1 -name "*.cpp" | xargs -t -n 1 clang-include-cleaner-18 --print=changes --extra-arg=-w -p cmake.output > clang-include-cleaner.log 2>&1 - uses: actions/upload-artifact@v3 with: From 040b7822374cc5662bae1187f571e1f4cfd79076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Mon, 15 Apr 2024 16:14:48 +0200 Subject: [PATCH 05/11] updated Qt in CI to 6.7.0 (#6290) --- .github/workflows/CI-windows.yml | 2 +- .github/workflows/asan.yml | 4 ++-- .github/workflows/clang-tidy.yml | 2 +- .github/workflows/selfcheck.yml | 8 ++++---- .github/workflows/tsan.yml | 4 ++-- .github/workflows/ubsan.yml | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml index 5ed1648e770..19bcaf0047f 100644 --- a/.github/workflows/CI-windows.yml +++ b/.github/workflows/CI-windows.yml @@ -26,7 +26,7 @@ jobs: strategy: matrix: os: [windows-2019, windows-2022] - qt_ver: [5.15.2, 6.6.0] + qt_ver: [5.15.2, 6.7.0] fail-fast: false runs-on: ${{ matrix.os }} diff --git a/.github/workflows/asan.yml b/.github/workflows/asan.yml index bc0aa9468b0..e223952fc34 100644 --- a/.github/workflows/asan.yml +++ b/.github/workflows/asan.yml @@ -134,7 +134,7 @@ jobs: ec=0 ./cmake.output/bin/cppcheck $selfcheck_options externals/simplecpp || ec=1 ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json cli lib || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB --library=qt --addon=naming.json -Icmake.output/gui -Igui gui/*.cpp cmake.output/gui/*.cpp || ec=1 + ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt --addon=naming.json -Icmake.output/gui -Igui gui/*.cpp cmake.output/gui/*.cpp || ec=1 ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli test/*.cpp tools/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB --library=qt -Icmake.output/tools/triage -Igui tools/triage/*.cpp cmake.output/tools/triage/*.cpp || ec=1 + ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt -Icmake.output/tools/triage -Igui tools/triage/*.cpp cmake.output/tools/triage/*.cpp || ec=1 exit $ec diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 90d04acd10f..29cf0ecbf67 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-22.04 env: - QT_VERSION: 6.6.0 + QT_VERSION: 6.7.0 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index ce7110c73f2..f76cb978cf0 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-22.04 env: - QT_VERSION: 6.6.0 + QT_VERSION: 6.7.0 steps: - uses: actions/checkout@v3 @@ -75,7 +75,7 @@ jobs: - name: Self check (unusedFunction) if: false # TODO: fails with preprocessorErrorDirective - see #10667 run: | - ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__CPPCHECK__ -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB --enable=unusedFunction --exception-handling -rp=. --project=cmake.output/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr + ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__CPPCHECK__ -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --enable=unusedFunction --exception-handling -rp=. --project=cmake.output/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr env: DISABLE_VALUEFLOW: 1 UNUSEDFUNCTION_ONLY: 1 @@ -96,7 +96,7 @@ jobs: # TODO: find a way to report unmatched suppressions without need to add information checks - name: Self check (unusedFunction / no test) run: | - ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__CPPCHECK__ -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB --enable=unusedFunction --exception-handling -rp=. --project=cmake.output.notest/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr + ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__CPPCHECK__ -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --enable=unusedFunction --exception-handling -rp=. --project=cmake.output.notest/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr env: DISABLE_VALUEFLOW: 1 UNUSEDFUNCTION_ONLY: 1 @@ -122,7 +122,7 @@ jobs: - name: Self check (unusedFunction / corpus / no test / callgrind) run: | # TODO: fix -rp so the suppressions actually work - valgrind --tool=callgrind ./cppcheck --template=selfcheck --error-exitcode=0 --library=cppcheck-lib --library=qt -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB --enable=unusedFunction --exception-handling -rp=. --project=cmake.output.corpus/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr 2>callgrind.log || (cat callgrind.log && false) + valgrind --tool=callgrind ./cppcheck --template=selfcheck --error-exitcode=0 --library=cppcheck-lib --library=qt -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --enable=unusedFunction --exception-handling -rp=. --project=cmake.output.corpus/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr 2>callgrind.log || (cat callgrind.log && false) cat callgrind.log callgrind_annotate --auto=no > callgrind.annotated.log head -50 callgrind.annotated.log diff --git a/.github/workflows/tsan.yml b/.github/workflows/tsan.yml index 0cabb7b2271..28f508fdbd0 100644 --- a/.github/workflows/tsan.yml +++ b/.github/workflows/tsan.yml @@ -136,7 +136,7 @@ jobs: ec=0 ./cmake.output/bin/cppcheck $selfcheck_options externals/simplecpp || ec=1 ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json -DCHECK_INTERNAL cli lib || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB --library=qt --addon=naming.json -Icmake.output/gui -Igui gui/*.cpp cmake.output/gui/*.cpp || ec=1 + ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt --addon=naming.json -Icmake.output/gui -Igui gui/*.cpp cmake.output/gui/*.cpp || ec=1 ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli test/*.cpp tools/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB --library=qt -Icmake.output/tools/triage -Igui tools/triage/*.cpp cmake.output/tools/triage/*.cpp || ec=1 + ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt -Icmake.output/tools/triage -Igui tools/triage/*.cpp cmake.output/tools/triage/*.cpp || ec=1 exit $ec diff --git a/.github/workflows/ubsan.yml b/.github/workflows/ubsan.yml index a1951adc406..31701b1bbd4 100644 --- a/.github/workflows/ubsan.yml +++ b/.github/workflows/ubsan.yml @@ -130,7 +130,7 @@ jobs: ec=0 ./cmake.output/bin/cppcheck $selfcheck_options externals/simplecpp || ec=1 ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json cli lib || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB --library=qt --addon=naming.json -Icmake.output/gui -Igui gui/*.cpp cmake.output/gui/*.cpp || ec=1 + ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt --addon=naming.json -Icmake.output/gui -Igui gui/*.cpp cmake.output/gui/*.cpp || ec=1 ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli test/*.cpp tools/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB --library=qt -Icmake.output/tools/triage -Igui tools/triage/*.cpp cmake.output/tools/triage/*.cpp || ec=1 + ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt -Icmake.output/tools/triage -Igui tools/triage/*.cpp cmake.output/tools/triage/*.cpp || ec=1 exit $ec From f79424b0ac2ac3e6b5183ba7a8bd88693b83ed73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Mon, 15 Apr 2024 16:17:40 +0200 Subject: [PATCH 06/11] avoid more unchecked pointer dereferences (#6293) --- lib/astutils.cpp | 10 ++++----- lib/astutils.h | 2 +- lib/check.h | 4 +--- lib/checkbufferoverrun.cpp | 12 +++++----- lib/checkbufferoverrun.h | 8 +++---- lib/checkclass.cpp | 10 ++++----- lib/checkclass.h | 2 +- lib/checkleakautovar.cpp | 2 +- lib/checknullpointer.cpp | 46 ++++++++++++++++++-------------------- lib/checknullpointer.h | 6 ++--- lib/checkother.cpp | 2 +- lib/checkstl.cpp | 2 +- lib/checkuninitvar.cpp | 10 ++++----- lib/checkuninitvar.h | 2 +- lib/cppcheck.cpp | 4 ++-- lib/ctu.cpp | 30 ++++++++++++------------- lib/ctu.h | 12 +++++----- lib/summaries.cpp | 8 +++---- lib/summaries.h | 2 +- lib/tokenize.cpp | 14 ++++++------ test/testbufferoverrun.cpp | 4 ++-- test/testclass.cpp | 4 ++-- test/testnullpointer.cpp | 8 +++---- test/testsummaries.cpp | 2 +- test/testuninitvar.cpp | 4 ++-- 25 files changed, 103 insertions(+), 107 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 6a99cb2e6b5..bd832a8b852 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -3286,7 +3286,7 @@ bool isConstVarExpression(const Token *tok, const std::functionastParent() && tok->astParent()->isUnaryOp("&"); @@ -3326,11 +3326,11 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings if (ftok->variable()->isStlType() || (ftok->variable()->valueType() && ftok->variable()->valueType()->container)) // STL types or containers don't initialize external variables return ExprUsage::Used; } else { - const bool isnullbad = settings->library.isnullargbad(ftok, argnr + 1); + const bool isnullbad = settings.library.isnullargbad(ftok, argnr + 1); if (indirect == 0 && astIsPointer(tok) && !addressOf && isnullbad) return ExprUsage::Used; bool hasIndirect = false; - const bool isuninitbad = settings->library.isuninitargbad(ftok, argnr + 1, indirect, &hasIndirect); + const bool isuninitbad = settings.library.isuninitargbad(ftok, argnr + 1, indirect, &hasIndirect); if (isuninitbad && (!addressOf || isnullbad)) return ExprUsage::Used; } @@ -3349,7 +3349,7 @@ bool isLeafDot(const Token* tok) return isLeafDot(parent); } -ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings) +ExprUsage getExprUsage(const Token* tok, int indirect, const Settings& settings) { const Token* parent = tok->astParent(); if (indirect > 0 && parent) { @@ -3365,7 +3365,7 @@ ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings) return ExprUsage::NotUsed; if (Token::simpleMatch(parent, ":") && Token::simpleMatch(parent->astParent(), "?")) return getExprUsage(parent->astParent(), indirect, settings); - if (isUsedAsBool(tok, settings)) + if (isUsedAsBool(tok, &settings)) return ExprUsage::NotUsed; } if (indirect == 0) { diff --git a/lib/astutils.h b/lib/astutils.h index 1526d00a7d7..6c296b4e9ee 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -439,7 +439,7 @@ bool isLeafDot(const Token* tok); enum class ExprUsage { None, NotUsed, PassedByReference, Used, Inconclusive }; -ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings); +ExprUsage getExprUsage(const Token* tok, int indirect, const Settings& settings); const Variable *getLHSVariable(const Token *tok); diff --git a/lib/check.h b/lib/check.h index 91930a37450..ab7f3ccad13 100644 --- a/lib/check.h +++ b/lib/check.h @@ -109,9 +109,7 @@ class CPPCHECKLIB Check { } }; - virtual FileInfo * getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const { - (void)tokenizer; - (void)settings; + virtual FileInfo * getFileInfo(const Tokenizer& /*tokenizer*/, const Settings& /*settings*/) const { return nullptr; } diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 5c5cc5e0c81..884ca51f2f3 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -915,11 +915,11 @@ namespace }; } -bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Settings *settings, const Token *argtok, MathLib::bigint *offset, int type) +bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Settings &settings, const Token *argtok, MathLib::bigint *offset, int type) { if (!offset) return false; - if (!argtok->valueType() || argtok->valueType()->typeSize(settings->platform) == 0) + if (!argtok->valueType() || argtok->valueType()->typeSize(settings.platform) == 0) return false; const Token *indexTok = nullptr; if (type == 1 && Token::Match(argtok, "%name% [") && argtok->astParent() == argtok->next() && !Token::simpleMatch(argtok->linkAt(1), "] [")) @@ -932,22 +932,22 @@ bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Settings *settings, const return false; if (!indexTok->hasKnownIntValue()) return false; - *offset = indexTok->getKnownIntValue() * argtok->valueType()->typeSize(settings->platform); + *offset = indexTok->getKnownIntValue() * argtok->valueType()->typeSize(settings.platform); return true; } -bool CheckBufferOverrun::isCtuUnsafeArrayIndex(const Settings *settings, const Token *argtok, MathLib::bigint *offset) +bool CheckBufferOverrun::isCtuUnsafeArrayIndex(const Settings &settings, const Token *argtok, MathLib::bigint *offset) { return isCtuUnsafeBufferUsage(settings, argtok, offset, 1); } -bool CheckBufferOverrun::isCtuUnsafePointerArith(const Settings *settings, const Token *argtok, MathLib::bigint *offset) +bool CheckBufferOverrun::isCtuUnsafePointerArith(const Settings &settings, const Token *argtok, MathLib::bigint *offset) { return isCtuUnsafeBufferUsage(settings, argtok, offset, 2); } /** @brief Parse current TU and extract file info */ -Check::FileInfo *CheckBufferOverrun::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const +Check::FileInfo *CheckBufferOverrun::getFileInfo(const Tokenizer &tokenizer, const Settings &settings) const { const std::list &unsafeArrayIndex = CTU::getUnsafeUsage(tokenizer, settings, isCtuUnsafeArrayIndex); const std::list &unsafePointerArith = CTU::getUnsafeUsage(tokenizer, settings, isCtuUnsafePointerArith); diff --git a/lib/checkbufferoverrun.h b/lib/checkbufferoverrun.h index e97cf518848..b993dafdfbb 100644 --- a/lib/checkbufferoverrun.h +++ b/lib/checkbufferoverrun.h @@ -92,7 +92,7 @@ class CPPCHECKLIB CheckBufferOverrun : public Check { } /** @brief Parse current TU and extract file info */ - Check::FileInfo *getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const override; + Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings) const override; /** @brief Analyse all file infos for all TU */ bool analyseWholeProgram(const CTU::FileInfo *ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override; @@ -130,9 +130,9 @@ class CPPCHECKLIB CheckBufferOverrun : public Check { ValueFlow::Value getBufferSize(const Token *bufTok) const; // CTU - static bool isCtuUnsafeBufferUsage(const Settings *settings, const Token *argtok, MathLib::bigint *offset, int type); - static bool isCtuUnsafeArrayIndex(const Settings *settings, const Token *argtok, MathLib::bigint *offset); - static bool isCtuUnsafePointerArith(const Settings *settings, const Token *argtok, MathLib::bigint *offset); + static bool isCtuUnsafeBufferUsage(const Settings &settings, const Token *argtok, MathLib::bigint *offset, int type); + static bool isCtuUnsafeArrayIndex(const Settings &settings, const Token *argtok, MathLib::bigint *offset); + static bool isCtuUnsafePointerArith(const Settings &settings, const Token *argtok, MathLib::bigint *offset); Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override; static bool analyseWholeProgram1(const std::map> &callsMap, const CTU::FileInfo::UnsafeUsage &unsafeUsage, int type, ErrorLogger &errorLogger); diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index ab5f9b77a55..7dc6c3f1468 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -3533,14 +3533,14 @@ namespace }; } -Check::FileInfo *CheckClass::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const +Check::FileInfo *CheckClass::getFileInfo(const Tokenizer &tokenizer, const Settings& /*settings*/) const { - if (!tokenizer->isCPP()) + if (!tokenizer.isCPP()) return nullptr; - (void)settings; + // One definition rule std::vector classDefinitions; - for (const Scope * classScope : tokenizer->getSymbolDatabase()->classAndStructScopes) { + for (const Scope * classScope : tokenizer.getSymbolDatabase()->classAndStructScopes) { if (classScope->isAnonymous()) continue; @@ -3575,7 +3575,7 @@ Check::FileInfo *CheckClass::getFileInfo(const Tokenizer *tokenizer, const Setti MyFileInfo::NameLoc nameLoc; nameLoc.className = std::move(name); - nameLoc.fileName = tokenizer->list.file(classScope->classDef); + nameLoc.fileName = tokenizer.list.file(classScope->classDef); nameLoc.lineNumber = classScope->classDef->linenr(); nameLoc.column = classScope->classDef->column(); diff --git a/lib/checkclass.h b/lib/checkclass.h index ac81b698a54..820b14ab858 100644 --- a/lib/checkclass.h +++ b/lib/checkclass.h @@ -168,7 +168,7 @@ class CPPCHECKLIB CheckClass : public Check { void checkUnsafeClassRefMember(); /** @brief Parse current TU and extract file info */ - Check::FileInfo *getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const override; + Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings) const override; Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override; diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 266da5c50b7..de06c9f28aa 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -834,7 +834,7 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t const std::map::const_iterator var = varInfo.alloctype.find(tok->varId()); if (var != varInfo.alloctype.end()) { bool unknown = false; - if (var->second.status == VarInfo::DEALLOC && CheckNullPointer::isPointerDeRef(tok, unknown, mSettings) && !unknown) { + if (var->second.status == VarInfo::DEALLOC && CheckNullPointer::isPointerDeRef(tok, unknown, *mSettings) && !unknown) { deallocUseError(tok, tok->str()); } else if (Token::simpleMatch(tok->tokAt(-2), "= &")) { varInfo.erase(tok->varId()); diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index cec36ee06dd..12c8b5ea4b1 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -62,28 +62,26 @@ static bool checkNullpointerFunctionCallPlausibility(const Function* func, unsig * @param var variables that the function read / write. * @param library --library files data */ -void CheckNullPointer::parseFunctionCall(const Token &tok, std::list &var, const Library *library) +void CheckNullPointer::parseFunctionCall(const Token &tok, std::list &var, const Library &library) { if (Token::Match(&tok, "%name% ( )") || !tok.tokAt(2)) return; const std::vector args = getArguments(&tok); - if (library || tok.function() != nullptr) { - for (int argnr = 1; argnr <= args.size(); ++argnr) { - const Token *param = args[argnr - 1]; - if (library && library->isnullargbad(&tok, argnr) && checkNullpointerFunctionCallPlausibility(tok.function(), argnr)) + for (int argnr = 1; argnr <= args.size(); ++argnr) { + const Token *param = args[argnr - 1]; + if (library.isnullargbad(&tok, argnr) && checkNullpointerFunctionCallPlausibility(tok.function(), argnr)) + var.push_back(param); + else if (tok.function()) { + const Variable* argVar = tok.function()->getArgumentVar(argnr-1); + if (argVar && argVar->isStlStringType() && !argVar->isArrayOrPointer()) var.push_back(param); - else if (tok.function()) { - const Variable* argVar = tok.function()->getArgumentVar(argnr-1); - if (argVar && argVar->isStlStringType() && !argVar->isArrayOrPointer()) - var.push_back(param); - } } } - if (library && library->formatstr_function(&tok)) { - const int formatStringArgNr = library->formatstr_argno(&tok); + if (library.formatstr_function(&tok)) { + const int formatStringArgNr = library.formatstr_argno(&tok); if (formatStringArgNr < 0 || formatStringArgNr >= args.size()) return; @@ -95,7 +93,7 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::liststrValue(); int argnr = formatStringArgNr + 1; - const bool scan = library->formatstr_scan(&tok); + const bool scan = library.formatstr_scan(&tok); bool percent = false; for (std::string::const_iterator i = formatString.cbegin(); i != formatString.cend(); ++i) { @@ -148,15 +146,15 @@ namespace { */ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown) const { - return isPointerDeRef(tok, unknown, mSettings); + return isPointerDeRef(tok, unknown, *mSettings); } -bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Settings *settings) +bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Settings &settings) { unknown = false; // Is pointer used as function parameter? - if (Token::Match(tok->previous(), "[(,] %name% [,)]") && settings) { + if (Token::Match(tok->previous(), "[(,] %name% [,)]")) { const Token *ftok = tok->previous(); while (ftok && ftok->str() != "(") { if (ftok->str() == ")") @@ -165,7 +163,7 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Set } if (ftok && ftok->previous()) { std::list varlist; - parseFunctionCall(*ftok->previous(), varlist, &settings->library); + parseFunctionCall(*ftok->previous(), varlist, settings.library); if (std::find(varlist.cbegin(), varlist.cend(), tok) != varlist.cend()) { return true; } @@ -263,7 +261,7 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Set } -static bool isNullablePointer(const Token* tok, const Settings* settings) +static bool isNullablePointer(const Token* tok) { if (!tok) return false; @@ -274,7 +272,7 @@ static bool isNullablePointer(const Token* tok, const Settings* settings) if (astIsSmartPointer(tok)) return true; if (Token::simpleMatch(tok, ".")) - return isNullablePointer(tok->astOperand2(), settings); + return isNullablePointer(tok->astOperand2()); if (const Variable* var = tok->variable()) { return (var->isPointer() || var->isSmartPointer()); } @@ -294,8 +292,8 @@ void CheckNullPointer::nullPointerByDeRefAndChec() if (Token::Match(tok, "%num%|%char%|%str%")) continue; - if (!isNullablePointer(tok, mSettings) || - (tok->str() == "." && isNullablePointer(tok->astOperand2(), mSettings) && tok->astOperand2()->getValue(0))) // avoid duplicate warning + if (!isNullablePointer(tok) || + (tok->str() == "." && isNullablePointer(tok->astOperand2()) && tok->astOperand2()->getValue(0))) // avoid duplicate warning continue; // Can pointer be NULL? @@ -367,7 +365,7 @@ void CheckNullPointer::nullConstantDereference() nullPointerError(tok); } else { // function call std::list var; - parseFunctionCall(*tok, var, &mSettings->library); + parseFunctionCall(*tok, var, mSettings->library); // is one of the var items a NULL pointer? for (const Token *vartok : var) { @@ -551,7 +549,7 @@ void CheckNullPointer::redundantConditionWarning(const Token* tok, const ValueFl } // NOLINTNEXTLINE(readability-non-const-parameter) - used as callback so we need to preserve the signature -static bool isUnsafeUsage(const Settings *settings, const Token *vartok, MathLib::bigint *value) +static bool isUnsafeUsage(const Settings &settings, const Token *vartok, MathLib::bigint *value) { (void)value; bool unknown = false; @@ -580,7 +578,7 @@ namespace }; } -Check::FileInfo *CheckNullPointer::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const +Check::FileInfo *CheckNullPointer::getFileInfo(const Tokenizer &tokenizer, const Settings &settings) const { const std::list &unsafeUsage = CTU::getUnsafeUsage(tokenizer, settings, isUnsafeUsage); if (unsafeUsage.empty()) diff --git a/lib/checknullpointer.h b/lib/checknullpointer.h index 19171e337eb..53e3c98f26a 100644 --- a/lib/checknullpointer.h +++ b/lib/checknullpointer.h @@ -67,7 +67,7 @@ class CPPCHECKLIB CheckNullPointer : public Check { */ bool isPointerDeRef(const Token *tok, bool &unknown) const; - static bool isPointerDeRef(const Token *tok, bool &unknown, const Settings *settings); + static bool isPointerDeRef(const Token *tok, bool &unknown, const Settings &settings); private: /** @@ -78,7 +78,7 @@ class CPPCHECKLIB CheckNullPointer : public Check { */ static void parseFunctionCall(const Token &tok, std::list &var, - const Library *library); + const Library &library); /** @brief This constructor is used when running checks. */ CheckNullPointer(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) @@ -106,7 +106,7 @@ class CPPCHECKLIB CheckNullPointer : public Check { void nullPointerError(const Token *tok, const std::string &varname, const ValueFlow::Value* value, bool inconclusive); /** @brief Parse current TU and extract file info */ - Check::FileInfo *getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const override; + Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings) const override; Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override; diff --git a/lib/checkother.cpp b/lib/checkother.cpp index e4fcfa73c16..9823957e525 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -3363,7 +3363,7 @@ void CheckOther::checkAccessOfMovedVariable() else inconclusive = true; } else { - const ExprUsage usage = getExprUsage(tok, 0, mSettings); + const ExprUsage usage = getExprUsage(tok, 0, *mSettings); if (usage == ExprUsage::Used) accessOfMoved = true; if (usage == ExprUsage::PassedByReference) diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 5eca694028f..35218e43a06 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -2479,7 +2479,7 @@ void CheckStl::checkDereferenceInvalidIterator2() emptyAdvance = tok->astParent(); } } - if (!CheckNullPointer::isPointerDeRef(tok, unknown, mSettings) && !isInvalidIterator && !emptyAdvance) { + if (!CheckNullPointer::isPointerDeRef(tok, unknown, *mSettings) && !isInvalidIterator && !emptyAdvance) { if (!unknown) continue; inconclusive = true; diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 6e58f0acd54..2b8e566305b 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1641,13 +1641,13 @@ void CheckUninitVar::valueFlowUninit() const bool isarray = tok->variable()->isArray(); if (isarray && tok->variable()->isMember()) continue; // Todo: this is a bailout - const bool deref = CheckNullPointer::isPointerDeRef(tok, unknown, mSettings); + const bool deref = CheckNullPointer::isPointerDeRef(tok, unknown, *mSettings); uninitderef = deref && v->indirect == 0; const bool isleaf = isLeafDot(tok) || uninitderef; if (!isleaf && Token::Match(tok->astParent(), ". %name%") && (tok->astParent()->next()->varId() || tok->astParent()->next()->isEnumerator())) continue; } - const ExprUsage usage = getExprUsage(tok, v->indirect, mSettings); + const ExprUsage usage = getExprUsage(tok, v->indirect, *mSettings); if (usage == ExprUsage::NotUsed || usage == ExprUsage::Inconclusive) continue; if (!v->subexpressions.empty() && usage == ExprUsage::PassedByReference) @@ -1670,10 +1670,10 @@ void CheckUninitVar::valueFlowUninit() } // NOLINTNEXTLINE(readability-non-const-parameter) - used as callback so we need to preserve the signature -static bool isVariableUsage(const Settings *settings, const Token *vartok, MathLib::bigint *value) +static bool isVariableUsage(const Settings &settings, const Token *vartok, MathLib::bigint *value) { (void)value; - return CheckUninitVar::isVariableUsage(vartok, settings->library, true, CheckUninitVar::Alloc::ARRAY); + return CheckUninitVar::isVariableUsage(vartok, settings.library, true, CheckUninitVar::Alloc::ARRAY); } // a Clang-built executable will crash when using the anonymous MyFileInfo later on - so put it in a unique namespace for now @@ -1698,7 +1698,7 @@ namespace }; } -Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const +Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer &tokenizer, const Settings &settings) const { const std::list &unsafeUsage = CTU::getUnsafeUsage(tokenizer, settings, ::isVariableUsage); if (unsafeUsage.empty()) diff --git a/lib/checkuninitvar.h b/lib/checkuninitvar.h index 025cc9f119f..d715b5352a7 100644 --- a/lib/checkuninitvar.h +++ b/lib/checkuninitvar.h @@ -106,7 +106,7 @@ class CPPCHECKLIB CheckUninitVar : public Check { void valueFlowUninit(); /** @brief Parse current TU and extract file info */ - Check::FileInfo *getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const override; + Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings) const override; Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override; diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index db1df11cd54..cfe7b624fbe 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1090,7 +1090,7 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer) if (mSettings.useSingleJob() || !mSettings.buildDir.empty()) { // Analyse the tokens.. - if (CTU::FileInfo * const fi1 = CTU::getFileInfo(&tokenizer)) { + if (CTU::FileInfo * const fi1 = CTU::getFileInfo(tokenizer)) { if (!mSettings.buildDir.empty()) mAnalyzerInformation.setFileInfo("ctu", fi1->toString()); if (mSettings.useSingleJob()) @@ -1102,7 +1102,7 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer) if (!doUnusedFunctionOnly) { // cppcheck-suppress shadowFunction - TODO: fix this for (const Check *check : Check::instances()) { - if (Check::FileInfo * const fi = check->getFileInfo(&tokenizer, &mSettings)) { + if (Check::FileInfo * const fi = check->getFileInfo(tokenizer, mSettings)) { if (!mSettings.buildDir.empty()) mAnalyzerInformation.setFileInfo(check->name(), fi->toString()); if (mSettings.useSingleJob()) diff --git a/lib/ctu.cpp b/lib/ctu.cpp index 789d0c675c8..41e8a5aa0ed 100644 --- a/lib/ctu.cpp +++ b/lib/ctu.cpp @@ -57,13 +57,13 @@ static constexpr char ATTR_VALUE[] = "value"; int CTU::maxCtuDepth = 2; -std::string CTU::getFunctionId(const Tokenizer *tokenizer, const Function *function) +std::string CTU::getFunctionId(const Tokenizer &tokenizer, const Function *function) { - return tokenizer->list.file(function->tokenDef) + ':' + std::to_string(function->tokenDef->linenr()) + ':' + std::to_string(function->tokenDef->column()); + return tokenizer.list.file(function->tokenDef) + ':' + std::to_string(function->tokenDef->linenr()) + ':' + std::to_string(function->tokenDef->column()); } -CTU::FileInfo::Location::Location(const Tokenizer *tokenizer, const Token *tok) - : fileName(tokenizer->list.file(tok)) +CTU::FileInfo::Location::Location(const Tokenizer &tokenizer, const Token *tok) + : fileName(tokenizer.list.file(tok)) , lineNumber(tok->linenr()) , column(tok->column()) {} @@ -156,13 +156,13 @@ std::string CTU::toString(const std::list &unsafeUsa return ret.str(); } -CTU::FileInfo::CallBase::CallBase(const Tokenizer *tokenizer, const Token *callToken) +CTU::FileInfo::CallBase::CallBase(const Tokenizer &tokenizer, const Token *callToken) : callId(getFunctionId(tokenizer, callToken->function())) , callFunctionName(callToken->next()->astOperand1()->expressionString()) , location(CTU::FileInfo::Location(tokenizer, callToken)) {} -CTU::FileInfo::NestedCall::NestedCall(const Tokenizer *tokenizer, const Function *myFunction, const Token *callToken) +CTU::FileInfo::NestedCall::NestedCall(const Tokenizer &tokenizer, const Function *myFunction, const Token *callToken) : CallBase(tokenizer, callToken) , myId(getFunctionId(tokenizer, myFunction)) {} @@ -306,9 +306,9 @@ static int isCallFunction(const Scope *scope, int argnr, const Token *&tok) } -CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer) +CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer) { - const SymbolDatabase * const symbolDatabase = tokenizer->getSymbolDatabase(); + const SymbolDatabase * const symbolDatabase = tokenizer.getSymbolDatabase(); auto *fileInfo = new FileInfo; @@ -346,7 +346,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer) functionCall.callArgValue = value.intvalue; functionCall.warning = !value.errorSeverity(); for (const ErrorPathItem &i : value.errorPath) { - const std::string& file = tokenizer->list.file(i.first); + const std::string& file = tokenizer.list.file(i.first); const std::string& info = i.second; const int line = i.first->linenr(); const int column = i.first->column(); @@ -364,7 +364,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer) functionCall.location = FileInfo::Location(tokenizer, tok); functionCall.callArgNr = argnr + 1; functionCall.callArgumentExpression = argtok->expressionString(); - const auto typeSize = argtok->valueType()->typeSize(tokenizer->getSettings().platform); + const auto typeSize = argtok->valueType()->typeSize(tokenizer.getSettings().platform); functionCall.callArgValue = typeSize > 0 ? argtok->variable()->dimension(0) * typeSize : -1; functionCall.warning = false; fileInfo->functionCalls.push_back(std::move(functionCall)); @@ -378,7 +378,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer) functionCall.location = FileInfo::Location(tokenizer, tok); functionCall.callArgNr = argnr + 1; functionCall.callArgumentExpression = argtok->expressionString(); - functionCall.callArgValue = argtok->astOperand1()->valueType()->typeSize(tokenizer->getSettings().platform); + functionCall.callArgValue = argtok->astOperand1()->valueType()->typeSize(tokenizer.getSettings().platform); functionCall.warning = false; fileInfo->functionCalls.push_back(std::move(functionCall)); } @@ -437,7 +437,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer) return fileInfo; } -static std::list> getUnsafeFunction(const Settings *settings, const Scope *scope, int argnr, bool (*isUnsafeUsage)(const Settings *settings, const Token *argtok, MathLib::bigint *value)) +static std::list> getUnsafeFunction(const Settings &settings, const Scope *scope, int argnr, bool (*isUnsafeUsage)(const Settings &settings, const Token *argtok, MathLib::bigint *value)) { std::list> ret; const Variable * const argvar = scope->function->getArgumentVar(argnr); @@ -451,7 +451,7 @@ static std::list> getUnsafeFunction(co int indirect = 0; if (argvar->valueType()) indirect = argvar->valueType()->pointer; - if (isVariableChanged(tok2->link(), tok2, indirect, argvar->declarationId(), false, settings)) + if (isVariableChanged(tok2->link(), tok2, indirect, argvar->declarationId(), false, &settings)) return ret; } if (Token::Match(tok2, "%oror%|&&|?")) { @@ -469,12 +469,12 @@ static std::list> getUnsafeFunction(co return ret; } -std::list CTU::getUnsafeUsage(const Tokenizer *tokenizer, const Settings *settings, bool (*isUnsafeUsage)(const Settings *settings, const Token *argtok, MathLib::bigint *value)) +std::list CTU::getUnsafeUsage(const Tokenizer &tokenizer, const Settings &settings, bool (*isUnsafeUsage)(const Settings &settings, const Token *argtok, MathLib::bigint *value)) { std::list unsafeUsage; // Parse all functions in TU - const SymbolDatabase * const symbolDatabase = tokenizer->getSymbolDatabase(); + const SymbolDatabase * const symbolDatabase = tokenizer.getSymbolDatabase(); for (const Scope &scope : symbolDatabase->scopeList) { if (!scope.isExecutable() || scope.type != Scope::eFunction || !scope.function) diff --git a/lib/ctu.h b/lib/ctu.h index 28e4421871c..af2cd6b07f0 100644 --- a/lib/ctu.h +++ b/lib/ctu.h @@ -57,7 +57,7 @@ namespace CTU { struct Location { Location() = default; - Location(const Tokenizer *tokenizer, const Token *tok); + Location(const Tokenizer &tokenizer, const Token *tok); Location(std::string fileName, nonneg int lineNumber, nonneg int column) : fileName(std::move(fileName)), lineNumber(lineNumber), column(column) {} std::string fileName; nonneg int lineNumber{}; @@ -81,7 +81,7 @@ namespace CTU { CallBase(std::string callId, int callArgNr, std::string callFunctionName, Location loc) : callId(std::move(callId)), callArgNr(callArgNr), callFunctionName(std::move(callFunctionName)), location(std::move(loc)) {} - CallBase(const Tokenizer *tokenizer, const Token *callToken); + CallBase(const Tokenizer &tokenizer, const Token *callToken); virtual ~CallBase() = default; CallBase(const CallBase&) = default; std::string callId; @@ -114,7 +114,7 @@ namespace CTU { myId(std::move(myId)), myArgNr(myArgNr) {} - NestedCall(const Tokenizer *tokenizer, const Function *myFunction, const Token *callToken); + NestedCall(const Tokenizer &tokenizer, const Function *myFunction, const Token *callToken); std::string toXmlString() const; bool loadFromXml(const tinyxml2::XMLElement *xmlElement); @@ -141,12 +141,12 @@ namespace CTU { CPPCHECKLIB std::string toString(const std::list &unsafeUsage); - CPPCHECKLIB std::string getFunctionId(const Tokenizer *tokenizer, const Function *function); + CPPCHECKLIB std::string getFunctionId(const Tokenizer &tokenizer, const Function *function); /** @brief Parse current TU and extract file info */ - CPPCHECKLIB FileInfo *getFileInfo(const Tokenizer *tokenizer); + CPPCHECKLIB FileInfo *getFileInfo(const Tokenizer &tokenizer); - CPPCHECKLIB std::list getUnsafeUsage(const Tokenizer *tokenizer, const Settings *settings, bool (*isUnsafeUsage)(const Settings *settings, const Token *argtok, MathLib::bigint *value)); + CPPCHECKLIB std::list getUnsafeUsage(const Tokenizer &tokenizer, const Settings &settings, bool (*isUnsafeUsage)(const Settings &settings, const Token *argtok, MathLib::bigint *value)); CPPCHECKLIB std::list loadUnsafeUsageListFromXml(const tinyxml2::XMLElement *xmlElement); } diff --git a/lib/summaries.cpp b/lib/summaries.cpp index c35f66f8f49..e4dddc1e365 100644 --- a/lib/summaries.cpp +++ b/lib/summaries.cpp @@ -34,10 +34,10 @@ -std::string Summaries::create(const Tokenizer *tokenizer, const std::string &cfg) +std::string Summaries::create(const Tokenizer &tokenizer, const std::string &cfg) { - const SymbolDatabase *symbolDatabase = tokenizer->getSymbolDatabase(); - const Settings &settings = tokenizer->getSettings(); + const SymbolDatabase *symbolDatabase = tokenizer.getSymbolDatabase(); + const Settings &settings = tokenizer.getSettings(); std::ostringstream ostr; for (const Scope *scope : symbolDatabase->functionScopes) { @@ -82,7 +82,7 @@ std::string Summaries::create(const Tokenizer *tokenizer, const std::string &cfg } if (!settings.buildDir.empty()) { - std::string filename = AnalyzerInformation::getAnalyzerInfoFile(settings.buildDir, tokenizer->list.getSourceFilePath(), cfg); + std::string filename = AnalyzerInformation::getAnalyzerInfoFile(settings.buildDir, tokenizer.list.getSourceFilePath(), cfg); const std::string::size_type pos = filename.rfind(".a"); if (pos != std::string::npos) { filename[pos+1] = 's'; diff --git a/lib/summaries.h b/lib/summaries.h index 0d9bd1da8b7..11a370c0f5f 100644 --- a/lib/summaries.h +++ b/lib/summaries.h @@ -29,7 +29,7 @@ class Tokenizer; namespace Summaries { - CPPCHECKLIB std::string create(const Tokenizer *tokenizer, const std::string &cfg); + CPPCHECKLIB std::string create(const Tokenizer &tokenizer, const std::string &cfg); CPPCHECKLIB void loadReturn(const std::string &buildDir, std::set &summaryReturn); } diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 77d797eb0a4..007ab36e3fd 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3400,7 +3400,7 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration) } if (!mSettings.buildDir.empty()) - Summaries::create(this, configuration); + Summaries::create(*this, configuration); // TODO: do not run valueflow if no checks are being performed at all - e.g. unusedFunctions only const char* disableValueflowEnv = std::getenv("DISABLE_VALUEFLOW"); @@ -5232,7 +5232,7 @@ void Tokenizer::setVarIdPass2() } } -static void linkBrackets(const Tokenizer * const tokenizer, std::stack& type, std::stack& links, Token * const token, const char open, const char close) +static void linkBrackets(const Tokenizer & tokenizer, std::stack& type, std::stack& links, Token * const token, const char open, const char close) { if (token->str()[0] == open) { links.push(token); @@ -5240,10 +5240,10 @@ static void linkBrackets(const Tokenizer * const tokenizer, std::stackstr()[0] == close) { if (links.empty()) { // Error, { and } don't match. - tokenizer->unmatchedToken(token); + tokenizer.unmatchedToken(token); } if (type.top()->str()[0] != open) { - tokenizer->unmatchedToken(type.top()); + tokenizer.unmatchedToken(type.top()); } type.pop(); @@ -5263,11 +5263,11 @@ void Tokenizer::createLinks() token->link(nullptr); } - linkBrackets(this, type, links1, token, '{', '}'); + linkBrackets(*this, type, links1, token, '{', '}'); - linkBrackets(this, type, links2, token, '(', ')'); + linkBrackets(*this, type, links2, token, '(', ')'); - linkBrackets(this, type, links3, token, '[', ']'); + linkBrackets(*this, type, links3, token, '[', ']'); } if (!links1.empty()) { diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 7c845c82722..82471879321 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -5163,12 +5163,12 @@ class TestBufferOverrun : public TestFixture { SimpleTokenizer tokenizer(settings0, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - CTU::FileInfo *ctu = CTU::getFileInfo(&tokenizer); + CTU::FileInfo *ctu = CTU::getFileInfo(tokenizer); // Check code.. std::list fileInfo; Check& c = getCheck(); - fileInfo.push_back(c.getFileInfo(&tokenizer, &settings0)); + fileInfo.push_back(c.getFileInfo(tokenizer, settings0)); c.analyseWholeProgram(ctu, fileInfo, settings0, *this); while (!fileInfo.empty()) { delete fileInfo.back(); diff --git a/test/testclass.cpp b/test/testclass.cpp index a6ba8a202b1..c9dde77fae5 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -8854,7 +8854,7 @@ class TestClass : public TestFixture { const std::string filename = std::to_string(fileInfo.size()) + ".cpp"; ASSERT(tokenizer.list.createTokens(istr, filename)); ASSERT(tokenizer.simplifyTokens1("")); - fileInfo.push_back(check.getFileInfo(&tokenizer, &settingsDefault)); + fileInfo.push_back(check.getFileInfo(tokenizer, settingsDefault)); } // Check code.. @@ -8898,7 +8898,7 @@ class TestClass : public TestFixture { // Check.. const Check& c = getCheck(); - Check::FileInfo * fileInfo = (c.getFileInfo)(&tokenizer, &settings1); + Check::FileInfo * fileInfo = (c.getFileInfo)(tokenizer, settings1); delete fileInfo; } diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 3dfaefb06c5..fadc729caf6 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -4153,7 +4153,7 @@ class TestNullPointer : public TestFixture { library.functions["x"].argumentChecks[3] = arg; std::list null; - CheckNullPointer::parseFunctionCall(*xtok, null, &library); + CheckNullPointer::parseFunctionCall(*xtok, null, library); ASSERT_EQUALS(0U, null.size()); } @@ -4167,7 +4167,7 @@ class TestNullPointer : public TestFixture { library.functions["x"].argumentChecks[1].notnull = true; std::list null; - CheckNullPointer::parseFunctionCall(*xtok, null, &library); + CheckNullPointer::parseFunctionCall(*xtok, null, library); ASSERT_EQUALS(1U, null.size()); ASSERT_EQUALS("a", null.front()->str()); } @@ -4483,12 +4483,12 @@ class TestNullPointer : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - CTU::FileInfo *ctu = CTU::getFileInfo(&tokenizer); + CTU::FileInfo *ctu = CTU::getFileInfo(tokenizer); // Check code.. std::list fileInfo; Check& c = getCheck(); - fileInfo.push_back(c.getFileInfo(&tokenizer, &settings)); + fileInfo.push_back(c.getFileInfo(tokenizer, settings)); c.analyseWholeProgram(ctu, fileInfo, settings, *this); while (!fileInfo.empty()) { delete fileInfo.back(); diff --git a/test/testsummaries.cpp b/test/testsummaries.cpp index a133d3eab38..6f5b198e255 100644 --- a/test/testsummaries.cpp +++ b/test/testsummaries.cpp @@ -39,7 +39,7 @@ class TestSummaries : public TestFixture { // tokenize.. SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT_LOC(tokenizer.tokenize(code, cpp), file, line); - return Summaries::create(&tokenizer, ""); + return Summaries::create(tokenizer, ""); } void createSummaries1() { diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index ade4a61cbd6..f86f0acc0ce 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -7763,12 +7763,12 @@ class TestUninitVar : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - CTU::FileInfo *ctu = CTU::getFileInfo(&tokenizer); + CTU::FileInfo *ctu = CTU::getFileInfo(tokenizer); // Check code.. std::list fileInfo; Check& c = getCheck(); - fileInfo.push_back(c.getFileInfo(&tokenizer, &settings)); + fileInfo.push_back(c.getFileInfo(tokenizer, settings)); c.analyseWholeProgram(ctu, fileInfo, settings, *this); while (!fileInfo.empty()) { delete fileInfo.back(); From 7e6062478a4d06f6a0baf7c3dfe4baa3fc89a817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Mon, 15 Apr 2024 17:28:15 +0200 Subject: [PATCH 07/11] iwyu.yml: use Qt6 for `include-what-you-use` (#6292) - updated all package dependencies for Qt6 - switched to clang as compiler as it is installed as a dependency anyways - fixed Qt mappings generation for Debian and ArchLinux --- .github/workflows/iwyu.yml | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/.github/workflows/iwyu.yml b/.github/workflows/iwyu.yml index 2c7b402d74a..9ef6f6fb03c 100644 --- a/.github/workflows/iwyu.yml +++ b/.github/workflows/iwyu.yml @@ -15,7 +15,7 @@ jobs: strategy: matrix: - image: ["opensuse/tumbleweed:latest"] # "fedora:latest" / "debian:unstable" / "archlinux:latest" + image: ["opensuse/tumbleweed:latest"] # "opensuse/tumbleweed:latest" / "fedora:latest" / "debian:unstable" / "archlinux:latest" runs-on: ubuntu-22.04 if: ${{ github.repository_owner == 'danmar' }} @@ -26,22 +26,24 @@ jobs: steps: - uses: actions/checkout@v3 - # TODO: the necessary packages are excessive - mostly because of Qt - use a pre-built image - name: Install missing software on debian/ubuntu if: contains(matrix.image, 'debian') run: | apt-get update - apt-get install -y cmake g++ make libpcre3-dev - apt-get install -y qtbase5-dev qttools5-dev libqt5charts5-dev + apt-get install -y cmake clang make libpcre3-dev + apt-get install -y qt6-base-dev qt6-tools-dev qt6-charts-dev apt-get install -y wget iwyu - ln -s ../x86_64-linux-gnu/qt5 /usr/include/qt + ln -s x86_64-linux-gnu/qt6 /usr/include/qt + # TODO: fails with /usr/lib/qt6/bin/lupdate: symbol lookup error: /usr/lib/libproxy/libpxbackend-1.0.so: undefined symbol: g_once_init_leave_pointer - name: Install missing software on archlinux if: contains(matrix.image, 'archlinux') run: | set -x pacman -Sy - pacman -S cmake make gcc qt5-base qt5-tools qt5-charts pcre wget --noconfirm + pacman -S cmake make clang pcre --noconfirm + pacman -S qt6-base qt6-tools qt6-charts --noconfirm + pacman -S wget --noconfirm pacman-key --init pacman-key --recv-key 3056513887B78AEB --keyserver keyserver.ubuntu.com pacman-key --lsign-key 3056513887B78AEB @@ -51,28 +53,32 @@ jobs: pacman -Sy pacman -S include-what-you-use --noconfirm ln -s iwyu-tool /usr/sbin/iwyu_tool + ln -s qt6 /usr/include/qt - # TODO: the necessary packages are excessive - mostly because of Qt - use a pre-built image - name: Install missing software on Fedora if: contains(matrix.image, 'fedora') run: | - dnf install -y cmake gcc-c++ qt5-qtbase-devel qt5-linguist qt5-qttools-devel qt5-qtcharts-devel pcre-devel + dnf install -y cmake clang pcre-devel + dnf install -y qt6-qtbase-devel qt6-qttools-devel qt6-qtcharts-devel dnf install -y wget iwyu ln -s iwyu_tool.py /usr/bin/iwyu_tool - ln -s qt5 /usr/include/qt + ln -s qt6 /usr/include/qt - name: Install missing software on OpenSUSE if: contains(matrix.image, 'opensuse') run: | - zypper install -y cmake gcc-c++ pcre-devel libQt5Core-devel libQt5Gui-devel libQt5Widgets-devel libQt5PrintSupport-devel libqt5-linguist-devel libqt5-qttools-devel libQt5Network-devel libQt5Charts5-devel libQt5Test-devel + zypper install -y cmake clang pcre-devel + zypper install -y qt6-base-common-devel qt6-core-devel qt6-gui-devel qt6-widgets-devel qt6-printsupport-devel qt6-linguist-devel qt6-help-devel qt6-charts-devel qt6-test-devel zypper install -y wget include-what-you-use-tools ln -s iwyu_tool.py /usr/bin/iwyu_tool - ln -s qt5 /usr/include/qt + ln -s qt6 /usr/include/qt - # TODO: switch to Qt 6 after we enabled the Qt mappings again - name: Prepare CMake run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On + cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DUSE_QT6=On -DWITH_QCHART=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On + env: + CC: clang + CXX: clang++ - name: Prepare CMake dependencies run: | @@ -90,13 +96,13 @@ jobs: - name: Build Qt mappings run: | wget https://raw.githubusercontent.com/include-what-you-use/include-what-you-use/master/mapgen/iwyu-mapgen-qt.py - python3 iwyu-mapgen-qt.py /usr/include/qt/ > qt5.imp + python3 iwyu-mapgen-qt.py /usr/include/qt/ > qt.imp - name: iwyu_tool run: | PWD=$(pwd) # -isystem/usr/lib/clang/17/include - iwyu_tool -p cmake.output -j $(nproc) -- -w -Xiwyu --max_line_length=1024 -Xiwyu --comment_style=long -Xiwyu --quoted_includes_first -Xiwyu --update_comments -Xiwyu --mapping_file=$PWD/qt5.imp > iwyu.log + iwyu_tool -p cmake.output -j $(nproc) -- -w -Xiwyu --max_line_length=1024 -Xiwyu --comment_style=long -Xiwyu --quoted_includes_first -Xiwyu --update_comments -Xiwyu --mapping_file=$PWD/qt.imp > iwyu.log - uses: actions/upload-artifact@v3 if: success() || failure() @@ -108,7 +114,7 @@ jobs: if: success() || failure() with: name: Qt Mappings - path: ./qt5.imp + path: ./qt.imp - uses: actions/upload-artifact@v3 if: success() || failure() From 65f571f5a9d007f9f882dc56883ad14dd9cb6c9b Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 15 Apr 2024 19:16:24 +0200 Subject: [PATCH 08/11] Fix #12615 FP syntaxError with operator= (#6295) --- lib/tokenize.cpp | 2 +- test/testgarbage.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 007ab36e3fd..f28f16e0105 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8636,7 +8636,7 @@ void Tokenizer::findGarbageCode() const syntaxError(tok); if (Token::Match(tok, "%assign% typename|class %assign%")) syntaxError(tok); - if (Token::Match(tok, "%assign% [;)}]") && (!isCPP() || !Token::Match(tok->previous(), "operator %assign% ;"))) + if (Token::Match(tok, "%assign% [;)}]") && (!isCPP() || !Token::simpleMatch(tok->previous(), "operator"))) syntaxError(tok); if (Token::Match(tok, "%cop%|=|,|[ %or%|%oror%|/|%")) syntaxError(tok); diff --git a/test/testgarbage.cpp b/test/testgarbage.cpp index 3726a3d2602..86e7c6c58e5 100644 --- a/test/testgarbage.cpp +++ b/test/testgarbage.cpp @@ -252,6 +252,7 @@ class TestGarbage : public TestFixture { TEST_CASE(garbageCode224); TEST_CASE(garbageCode225); TEST_CASE(garbageCode226); + TEST_CASE(garbageCode227); TEST_CASE(garbageCodeFuzzerClientMode1); // test cases created with the fuzzer client, mode 1 @@ -1753,6 +1754,9 @@ class TestGarbage : public TestFixture { ASSERT_THROW_INTERNAL(checkCode("int a() { (b((c)\\)) } {}"), SYNTAX); ASSERT_THROW_INTERNAL(checkCode("int a() { (b((c)@)) } {}"), SYNTAX); } + void garbageCode227() { // #12615 + ASSERT_NO_THROW(checkCode("f(&S::operator=);")); + } void syntaxErrorFirstToken() { ASSERT_THROW_INTERNAL(checkCode("&operator(){[]};"), SYNTAX); // #7818 From 087fd7911a5c40a3a887daa7ce2d4a363b45d0d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Mon, 15 Apr 2024 20:21:32 +0200 Subject: [PATCH 09/11] avoid even more unchecked pointer dereferences / changed some pointers to references (#6296) --- gui/mainwindow.cpp | 22 +++++++++---------- gui/mainwindow.h | 4 ++-- lib/astutils.cpp | 33 +++++++++++++--------------- lib/astutils.h | 6 +++--- lib/checkautovariables.cpp | 2 +- lib/checkother.cpp | 4 ++-- lib/checkstl.cpp | 2 +- lib/findtoken.h | 10 ++++----- lib/forwardanalyzer.cpp | 4 ++-- lib/fwdanalysis.cpp | 2 +- lib/programmemory.cpp | 18 ++++++++-------- lib/programmemory.h | 8 +++---- lib/symboldatabase.cpp | 10 ++++----- lib/valueflow.cpp | 44 +++++++++++++++++++------------------- test/testastutils.cpp | 2 +- 15 files changed, 83 insertions(+), 88 deletions(-) diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 5d79794784c..eb2905d3475 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -823,24 +823,24 @@ void MainWindow::addIncludeDirs(const QStringList &includeDirs, Settings &result } } -Library::Error MainWindow::loadLibrary(Library *library, const QString &filename) +Library::Error MainWindow::loadLibrary(Library &library, const QString &filename) { Library::Error ret; // Try to load the library from the project folder.. if (mProjectFile) { QString path = QFileInfo(mProjectFile->getFilename()).canonicalPath(); - ret = library->load(nullptr, (path+"/"+filename).toLatin1()); + ret = library.load(nullptr, (path+"/"+filename).toLatin1()); if (ret.errorcode != Library::ErrorCode::FILE_NOT_FOUND) return ret; } // Try to load the library from the application folder.. const QString appPath = QFileInfo(QCoreApplication::applicationFilePath()).canonicalPath(); - ret = library->load(nullptr, (appPath+"/"+filename).toLatin1()); + ret = library.load(nullptr, (appPath+"/"+filename).toLatin1()); if (ret.errorcode != Library::ErrorCode::FILE_NOT_FOUND) return ret; - ret = library->load(nullptr, (appPath+"/cfg/"+filename).toLatin1()); + ret = library.load(nullptr, (appPath+"/cfg/"+filename).toLatin1()); if (ret.errorcode != Library::ErrorCode::FILE_NOT_FOUND) return ret; @@ -848,10 +848,10 @@ Library::Error MainWindow::loadLibrary(Library *library, const QString &filename // Try to load the library from FILESDIR/cfg.. const QString filesdir = FILESDIR; if (!filesdir.isEmpty()) { - ret = library->load(nullptr, (filesdir+"/cfg/"+filename).toLatin1()); + ret = library.load(nullptr, (filesdir+"/cfg/"+filename).toLatin1()); if (ret.errorcode != Library::ErrorCode::FILE_NOT_FOUND) return ret; - ret = library->load(nullptr, (filesdir+filename).toLatin1()); + ret = library.load(nullptr, (filesdir+filename).toLatin1()); if (ret.errorcode != Library::ErrorCode::FILE_NOT_FOUND) return ret; } @@ -860,10 +860,10 @@ Library::Error MainWindow::loadLibrary(Library *library, const QString &filename // Try to load the library from the cfg subfolder.. const QString datadir = getDataDir(); if (!datadir.isEmpty()) { - ret = library->load(nullptr, (datadir+"/"+filename).toLatin1()); + ret = library.load(nullptr, (datadir+"/"+filename).toLatin1()); if (ret.errorcode != Library::ErrorCode::FILE_NOT_FOUND) return ret; - ret = library->load(nullptr, (datadir+"/cfg/"+filename).toLatin1()); + ret = library.load(nullptr, (datadir+"/cfg/"+filename).toLatin1()); if (ret.errorcode != Library::ErrorCode::FILE_NOT_FOUND) return ret; } @@ -871,7 +871,7 @@ Library::Error MainWindow::loadLibrary(Library *library, const QString &filename return ret; } -bool MainWindow::tryLoadLibrary(Library *library, const QString& filename) +bool MainWindow::tryLoadLibrary(Library &library, const QString& filename) { const Library::Error error = loadLibrary(library, filename); if (error.errorcode != Library::ErrorCode::OK) { @@ -972,7 +972,7 @@ QPair MainWindow::getCppcheckSettings() // default to --check-level=normal for GUI for now result.setCheckLevel(Settings::CheckLevel::normal); - const bool std = tryLoadLibrary(&result.library, "std.cfg"); + const bool std = tryLoadLibrary(result.library, "std.cfg"); if (!std) { QMessageBox::critical(this, tr("Error"), tr("Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir= at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured.\n\nAnalysis is aborted.").arg("std.cfg")); return {false, {}}; @@ -1022,7 +1022,7 @@ QPair MainWindow::getCppcheckSettings() for (const QString& library : libraries) { result.libraries.emplace_back(library.toStdString()); const QString filename = library + ".cfg"; - tryLoadLibrary(&result.library, filename); + tryLoadLibrary(result.library, filename); } for (const SuppressionList::Suppression &suppression : mProjectFile->getCheckingSuppressions()) { diff --git a/gui/mainwindow.h b/gui/mainwindow.h index 5214b690ddc..b0721213545 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -392,7 +392,7 @@ private slots: * @param filename filename (no path) * @return error code */ - Library::Error loadLibrary(Library *library, const QString &filename); + Library::Error loadLibrary(Library &library, const QString &filename); /** * @brief Tries to load library file, prints message on error @@ -400,7 +400,7 @@ private slots: * @param filename filename (no path) * @return True if no error */ - bool tryLoadLibrary(Library *library, const QString& filename); + bool tryLoadLibrary(Library &library, const QString& filename); QString loadAddon(Settings &settings, const QString &filesDir, const QString &pythonCmd, const QString& addon); diff --git a/lib/astutils.cpp b/lib/astutils.cpp index bd832a8b852..105d780fd88 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -304,15 +304,12 @@ Library::Container::Yield astContainerYield(const Token* tok, const Token** ftok return tok->valueType()->container->getYield(ftok2->str()); } -Library::Container::Yield astFunctionYield(const Token* tok, const Settings* settings, const Token** ftok) +Library::Container::Yield astFunctionYield(const Token* tok, const Settings& settings, const Token** ftok) { if (!tok) return Library::Container::Yield::NO_YIELD; - if (!settings) - return Library::Container::Yield::NO_YIELD; - - const auto* function = settings->library.getFunction(tok); + const auto* function = settings.library.getFunction(tok); if (!function) return Library::Container::Yield::NO_YIELD; @@ -635,7 +632,7 @@ static std::vector getParentMembers(const Token* tok) return result; } -const Token* getParentLifetime(const Token* tok, const Library* library) +const Token* getParentLifetime(const Token* tok, const Library& library) { std::vector members = getParentMembers(tok); if (members.size() < 2) @@ -647,7 +644,7 @@ const Token* getParentLifetime(const Token* tok, const Library* library) return var->isLocal() || var->isArgument(); if (Token::simpleMatch(tok2, "[")) return true; - return isTemporary(tok2, library); + return isTemporary(tok2, &library); }); if (it == members.rend()) return tok; @@ -2127,18 +2124,18 @@ bool isUniqueExpression(const Token* tok) return isUniqueExpression(tok->astOperand2()); } -static bool isEscaped(const Token* tok, bool functionsScope, const Library* library) +static bool isEscaped(const Token* tok, bool functionsScope, const Library& library) { - if (library && library->isnoreturn(tok)) + if (library.isnoreturn(tok)) return true; if (functionsScope) return Token::simpleMatch(tok, "throw"); return Token::Match(tok, "return|throw"); } -static bool isEscapedOrJump(const Token* tok, bool functionsScope, const Library* library) +static bool isEscapedOrJump(const Token* tok, bool functionsScope, const Library& library) { - if (library && library->isnoreturn(tok)) + if (library.isnoreturn(tok)) return true; if (functionsScope) return Token::simpleMatch(tok, "throw"); @@ -2162,7 +2159,7 @@ bool isEscapeFunction(const Token* ftok, const Library* library) return false; } -static bool hasNoreturnFunction(const Token* tok, const Library* library, const Token** unknownFunc) +static bool hasNoreturnFunction(const Token* tok, const Library& library, const Token** unknownFunc) { if (!tok) return false; @@ -2176,12 +2173,12 @@ static bool hasNoreturnFunction(const Token* tok, const Library* library, const return true; if (function->isAttributeNoreturn()) return true; - } else if (library && library->isnoreturn(ftok)) { + } else if (library.isnoreturn(ftok)) { return true; } else if (Token::Match(ftok, "exit|abort")) { return true; } - if (unknownFunc && !function && library && library->functions.count(library->getFunctionName(ftok)) == 0) + if (unknownFunc && !function && library.functions.count(library.getFunctionName(ftok)) == 0) *unknownFunc = ftok; return false; } @@ -2192,7 +2189,7 @@ static bool hasNoreturnFunction(const Token* tok, const Library* library, const return false; } -bool isReturnScope(const Token* const endToken, const Library* library, const Token** unknownFunc, bool functionScope) +bool isReturnScope(const Token* const endToken, const Library& library, const Token** unknownFunc, bool functionScope) { if (!endToken || endToken->str() != "}") return false; @@ -3005,9 +3002,9 @@ namespace { }; struct ExpressionChangedSkipDeadCode { - const Library* library; + const Library& library; const std::function(const Token* tok)>* evaluate; - ExpressionChangedSkipDeadCode(const Library* library, + ExpressionChangedSkipDeadCode(const Library& library, const std::function(const Token* tok)>& evaluate) : library(library), evaluate(&evaluate) {} @@ -3036,7 +3033,7 @@ const Token* findExpressionChangedSkipDeadCode(const Token* expr, int depth) { return findExpressionChangedImpl( - expr, start, end, settings, depth, ExpressionChangedSkipDeadCode{&settings->library, evaluate}); + expr, start, end, settings, depth, ExpressionChangedSkipDeadCode{settings->library, evaluate}); } const Token* getArgumentStart(const Token* ftok) diff --git a/lib/astutils.h b/lib/astutils.h index 6c296b4e9ee..6426225253e 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -173,7 +173,7 @@ bool astIsContainerString(const Token* tok); Library::Container::Action astContainerAction(const Token* tok, const Token** ftok = nullptr); Library::Container::Yield astContainerYield(const Token* tok, const Token** ftok = nullptr); -Library::Container::Yield astFunctionYield(const Token* tok, const Settings* settings, const Token** ftok = nullptr); +Library::Container::Yield astFunctionYield(const Token* tok, const Settings& settings, const Token** ftok = nullptr); /** Is given token a range-declaration in a range-based for loop */ bool astIsRangeBasedForDecl(const Token* tok); @@ -209,7 +209,7 @@ const Token* astParentSkipParens(const Token* tok); const Token* getParentMember(const Token * tok); const Token* getParentLifetime(const Token* tok); -const Token* getParentLifetime(const Token* tok, const Library* library); +const Token* getParentLifetime(const Token* tok, const Library& library); std::vector getParentValueTypes(const Token* tok, const Settings* settings = nullptr, @@ -304,7 +304,7 @@ bool isEscapeFunction(const Token* ftok, const Library* library); /** Is scope a return scope (scope will unconditionally return) */ CPPCHECKLIB bool isReturnScope(const Token* const endToken, - const Library* library = nullptr, + const Library& library, const Token** unknownFunc = nullptr, bool functionScope = false); diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index 7434fb3be3a..17242326490 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -598,7 +598,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token continue; if (!printInconclusive && val.isInconclusive()) continue; - const Token* parent = getParentLifetime(val.tokvalue, &mSettings->library); + const Token* parent = getParentLifetime(val.tokvalue, mSettings->library); if (!exprs.insert(parent).second) continue; for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(parent, escape || isAssignedToNonLocal(tok))) { diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 9823957e525..453495af520 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -3802,10 +3802,10 @@ void CheckOther::checkComparePointers() continue; if (var1->isRValueReference() || var2->isRValueReference()) continue; - if (const Token* parent2 = getParentLifetime(v2.tokvalue, &mSettings->library)) + if (const Token* parent2 = getParentLifetime(v2.tokvalue, mSettings->library)) if (var1 == parent2->variable()) continue; - if (const Token* parent1 = getParentLifetime(v1.tokvalue, &mSettings->library)) + if (const Token* parent1 = getParentLifetime(v1.tokvalue, mSettings->library)) if (var2 == parent1->variable()) continue; comparePointersError(tok, &v1, &v2); diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 35218e43a06..e581a36fc47 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -1121,7 +1121,7 @@ void CheckStl::invalidContainer() const Scope* s = tok2->scope(); if (!s) continue; - if (isReturnScope(s->bodyEnd, &mSettings->library)) + if (isReturnScope(s->bodyEnd, mSettings->library)) continue; invalidContainerLoopError(r.ftok, tok, r.errorPath); bail = true; diff --git a/lib/findtoken.h b/lib/findtoken.h index d3404758b16..f75845fd813 100644 --- a/lib/findtoken.h +++ b/lib/findtoken.h @@ -79,7 +79,7 @@ template )> -bool findTokensSkipDeadCodeImpl(const Library* library, +bool findTokensSkipDeadCodeImpl(const Library& library, T* start, const Token* end, const Predicate& pred, @@ -169,7 +169,7 @@ bool findTokensSkipDeadCodeImpl(const Library* library, } template )> -std::vector findTokensSkipDeadCode(const Library* library, +std::vector findTokensSkipDeadCode(const Library& library, T* start, const Token* end, const Predicate& pred, @@ -190,13 +190,13 @@ std::vector findTokensSkipDeadCode(const Library* library, } template )> -std::vector findTokensSkipDeadCode(const Library* library, T* start, const Token* end, const Predicate& pred) +std::vector findTokensSkipDeadCode(const Library& library, T* start, const Token* end, const Predicate& pred) { return findTokensSkipDeadCode(library, start, end, pred, &evaluateKnownValues); } template )> -T* findTokenSkipDeadCode(const Library* library, T* start, const Token* end, const Predicate& pred, const Evaluate& evaluate) +T* findTokenSkipDeadCode(const Library& library, T* start, const Token* end, const Predicate& pred, const Evaluate& evaluate) { T* result = nullptr; (void)findTokensSkipDeadCodeImpl( @@ -213,7 +213,7 @@ T* findTokenSkipDeadCode(const Library* library, T* start, const Token* end, con } template )> -T* findTokenSkipDeadCode(const Library* library, T* start, const Token* end, const Predicate& pred) +T* findTokenSkipDeadCode(const Library& library, T* start, const Token* end, const Predicate& pred) { return findTokenSkipDeadCode(library, start, end, pred, &evaluateKnownValues); } diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index c5cb8eaf3ee..2572ccc0613 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -311,7 +311,7 @@ namespace { for (const Token* tok=start; tok != end; tok = tok->previous()) { if (Token::simpleMatch(tok, "}")) { const Token* ftok = nullptr; - const bool r = isReturnScope(tok, &settings.library, &ftok); + const bool r = isReturnScope(tok, settings.library, &ftok); if (r) return true; } @@ -321,7 +321,7 @@ namespace { bool isEscapeScope(const Token* endBlock, bool& unknown) const { const Token* ftok = nullptr; - const bool r = isReturnScope(endBlock, &settings.library, &ftok); + const bool r = isReturnScope(endBlock, settings.library, &ftok); if (!r && ftok) unknown = true; return r; diff --git a/lib/fwdanalysis.cpp b/lib/fwdanalysis.cpp index 264153d1fd0..c261b39ea96 100644 --- a/lib/fwdanalysis.cpp +++ b/lib/fwdanalysis.cpp @@ -236,7 +236,7 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * } } tok = bodyStart->link(); - if (isReturnScope(tok, &mLibrary)) + if (isReturnScope(tok, mLibrary)) return Result(Result::Type::BAILOUT); if (Token::simpleMatch(tok, "} else {")) tok = tok->linkAt(2); diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 62a1c2b2a2b..49b11310104 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -271,7 +271,7 @@ static bool isBasicForLoop(const Token* tok) return true; } -void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Token* endTok, const Settings* settings, bool then) +static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Token* endTok, const Settings* settings, bool then) { auto eval = [&](const Token* t) -> std::vector { if (!t) @@ -427,14 +427,14 @@ static void removeModifiedVars(ProgramMemory& pm, const Token* tok, const Token* static ProgramMemory getInitialProgramState(const Token* tok, const Token* origin, - const Settings* settings, + const Settings& settings, const ProgramMemory::Map& vars = ProgramMemory::Map {}) { ProgramMemory pm; if (origin) { fillProgramMemoryFromConditions(pm, origin, nullptr); const ProgramMemory state = pm; - fillProgramMemoryFromAssignments(pm, tok, settings, state, vars); + fillProgramMemoryFromAssignments(pm, tok, &settings, state, vars); removeModifiedVars(pm, tok, origin); } return pm; @@ -534,15 +534,15 @@ ProgramMemory ProgramMemoryState::get(const Token* tok, const Token* ctx, const return local.state; } -ProgramMemory getProgramMemory(const Token* tok, const Token* expr, const ValueFlow::Value& value, const Settings* settings) +ProgramMemory getProgramMemory(const Token* tok, const Token* expr, const ValueFlow::Value& value, const Settings& settings) { ProgramMemory programMemory; programMemory.replace(getInitialProgramState(tok, value.tokvalue, settings)); programMemory.replace(getInitialProgramState(tok, value.condition, settings)); - fillProgramMemoryFromConditions(programMemory, tok, settings); + fillProgramMemoryFromConditions(programMemory, tok, &settings); programMemory.setValue(expr, value); const ProgramMemory state = programMemory; - fillProgramMemoryFromAssignments(programMemory, tok, settings, state, {{expr, value}}); + fillProgramMemoryFromAssignments(programMemory, tok, &settings, state, {{expr, value}}); return programMemory; } @@ -1257,7 +1257,7 @@ namespace { int fdepth = 4; int depth = 10; - explicit Executor(ProgramMemory* pm = nullptr, const Settings* settings = nullptr) : pm(pm), settings(settings) {} + Executor(ProgramMemory* pm, const Settings* settings) : pm(pm), settings(settings) {} static ValueFlow::Value unknown() { return ValueFlow::Value::unknown(); @@ -1748,9 +1748,9 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Sett return ex.execute(expr); } -std::vector execute(const Scope* scope, ProgramMemory& pm, const Settings* settings) +std::vector execute(const Scope* scope, ProgramMemory& pm, const Settings& settings) { - Executor ex{&pm, settings}; + Executor ex{&pm, &settings}; return ex.execute(scope); } diff --git a/lib/programmemory.h b/lib/programmemory.h index b746e2e8dd7..85703455b5f 100644 --- a/lib/programmemory.h +++ b/lib/programmemory.h @@ -161,8 +161,6 @@ struct ProgramMemory { Map mValues; }; -void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Token* endTok, const Settings* settings, bool then); - struct ProgramMemoryState { ProgramMemory state; std::map origins; @@ -182,13 +180,13 @@ struct ProgramMemoryState { ProgramMemory get(const Token* tok, const Token* ctx, const ProgramMemory::Map& vars) const; }; -std::vector execute(const Scope* scope, ProgramMemory& pm, const Settings* settings); +std::vector execute(const Scope* scope, ProgramMemory& pm, const Settings& settings); void execute(const Token* expr, ProgramMemory& programMemory, MathLib::bigint* result, bool* error, - const Settings* settings = nullptr); + const Settings* settings); /** * Is condition always false when variable has given value? @@ -207,7 +205,7 @@ bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings* s /** * Get program memory by looking backwards from given token. */ -ProgramMemory getProgramMemory(const Token* tok, const Token* expr, const ValueFlow::Value& value, const Settings* settings); +ProgramMemory getProgramMemory(const Token* tok, const Token* expr, const ValueFlow::Value& value, const Settings& settings); ValueFlow::Value evaluateLibraryFunction(const std::unordered_map& args, const std::string& returnValue, diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 4a883977ee2..b2d3605f409 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1522,7 +1522,7 @@ void SymbolDatabase::createSymbolDatabaseEscapeFunctions() continue; if (Token::findsimplematch(scope.bodyStart, "return", scope.bodyEnd)) continue; - function->isEscapeFunction(isReturnScope(scope.bodyEnd, &mSettings.library, nullptr, true)); + function->isEscapeFunction(isReturnScope(scope.bodyEnd, mSettings.library, nullptr, true)); } } @@ -2306,7 +2306,7 @@ void Variable::evaluate(const Settings* settings) if (!settings) return; - const Library * const lib = &settings->library; + const Library & lib = settings->library; // TODO: ValueType::parseDecl() is also performing a container lookup bool isContainer = false; @@ -2367,10 +2367,10 @@ void Variable::evaluate(const Settings* settings) std::string strtype = mTypeStartToken->str(); for (const Token *typeToken = mTypeStartToken; Token::Match(typeToken, "%type% :: %type%"); typeToken = typeToken->tokAt(2)) strtype += "::" + typeToken->strAt(2); - setFlag(fIsClass, !lib->podtype(strtype) && !mTypeStartToken->isStandardType() && !isEnumType() && !isPointer() && strtype != "..."); + setFlag(fIsClass, !lib.podtype(strtype) && !mTypeStartToken->isStandardType() && !isEnumType() && !isPointer() && strtype != "..."); setFlag(fIsStlType, Token::simpleMatch(mTypeStartToken, "std ::")); setFlag(fIsStlString, ::isStlStringType(mTypeStartToken)); - setFlag(fIsSmartPointer, mTypeStartToken->isCpp() && lib->isSmartPointer(mTypeStartToken)); + setFlag(fIsSmartPointer, mTypeStartToken->isCpp() && lib.isSmartPointer(mTypeStartToken)); } if (mAccess == AccessControl::Argument) { tok = mNameToken; @@ -7599,7 +7599,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to continue; } - const auto yield = astFunctionYield(tok->previous(), &mSettings); + const auto yield = astFunctionYield(tok->previous(), mSettings); if (yield == Library::Container::Yield::START_ITERATOR || yield == Library::Container::Yield::END_ITERATOR || yield == Library::Container::Yield::ITERATOR) { diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index dc826e60290..6e7e79c4c1b 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -4040,7 +4040,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList &tokenlist, ErrorLog // TODO: handle `[` if (Token::simpleMatch(parent->astOperand1(), ".")) { const Token* parentLifetime = - getParentLifetime(parent->astOperand1()->astOperand2(), &settings.library); + getParentLifetime(parent->astOperand1()->astOperand2(), settings.library); if (parentLifetime && parentLifetime->exprId() > 0) { valueFlowForward(nextExpression, endOfVarScope, parentLifetime, std::move(values), tokenlist, errorLogger, settings); } @@ -5049,7 +5049,7 @@ static void valueFlowLifetime(TokenList &tokenlist, ErrorLogger &errorLogger, co // Skip if its a free function that doesnt yield an iterator to the container if (Token::Match(parent->previous(), "%name% (") && !contains({Library::Container::Yield::START_ITERATOR, Library::Container::Yield::END_ITERATOR}, - astFunctionYield(parent->previous(), &settings))) + astFunctionYield(parent->previous(), settings))) continue; ValueFlow::Value master; @@ -5061,7 +5061,7 @@ static void valueFlowLifetime(TokenList &tokenlist, ErrorLogger &errorLogger, co master.lifetimeKind = ValueFlow::Value::LifetimeKind::Iterator; } else if (astIsIterator(parent) && Token::Match(parent->previous(), "%name% (") && contains({Library::Container::Yield::START_ITERATOR, Library::Container::Yield::END_ITERATOR}, - astFunctionYield(parent->previous(), &settings))) { + astFunctionYield(parent->previous(), settings))) { master.errorPath.emplace_back(parent, "Iterator to container is created here."); master.lifetimeKind = ValueFlow::Value::LifetimeKind::Iterator; } else if ((astIsPointer(parent->tokAt(2)) && @@ -5820,12 +5820,12 @@ static void valueFlowForwardConst(Token* start, static ValueFlow::Value::Bound findVarBound(const Variable* var, const Token* start, const Token* end, - const Settings* settings) + const Settings& settings) { ValueFlow::Value::Bound result = ValueFlow::Value::Bound::Point; const Token* next = start; while ((next = findExpressionChangedSkipDeadCode( - var->nameToken(), next->next(), end, settings, &evaluateKnownValues))) { + var->nameToken(), next->next(), end, &settings, &evaluateKnownValues))) { ValueFlow::Value::Bound b = ValueFlow::Value::Bound::Point; if (next->varId() != var->declarationId()) return ValueFlow::Value::Bound::Point; @@ -5948,7 +5948,7 @@ static void valueFlowForwardAssign(Token* const tok, } if (isInitialVarAssign(expr)) { // Check if variable is only incremented or decremented - ValueFlow::Value::Bound b = findVarBound(expr->variable(), nextExpression, endOfVarScope, &settings); + ValueFlow::Value::Bound b = findVarBound(expr->variable(), nextExpression, endOfVarScope, settings); if (b != ValueFlow::Value::Bound::Point) { auto knownValueIt = std::find_if(values.begin(), values.end(), [](const ValueFlow::Value& value) { if (!value.isKnown()) @@ -6713,9 +6713,9 @@ struct ConditionHandler { ProgramMemory pm; fillFromPath(pm, initTok, path); fillFromPath(pm, condTok, path); - execute(initTok, pm, nullptr, nullptr); + execute(initTok, pm, nullptr, nullptr, nullptr); MathLib::bigint result = 1; - execute(condTok, pm, &result, nullptr); + execute(condTok, pm, &result, nullptr, nullptr); if (result == 0) return; // Remove condition since for condition is not redundant @@ -6783,7 +6783,7 @@ struct ConditionHandler { if (condTok->astParent() && Token::Match(top->previous(), "while|for (")) dead_if = !isBreakScope(after); else if (!dead_if) - dead_if = isReturnScope(after, &settings.library, &unknownFunction); + dead_if = isReturnScope(after, settings.library, &unknownFunction); if (!dead_if && unknownFunction) { if (settings.debugwarnings) @@ -6795,7 +6795,7 @@ struct ConditionHandler { after = after->linkAt(2); unknownFunction = nullptr; if (!dead_else) - dead_else = isReturnScope(after, &settings.library, &unknownFunction); + dead_else = isReturnScope(after, settings.library, &unknownFunction); if (!dead_else && unknownFunction) { if (settings.debugwarnings) bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope"); @@ -7132,10 +7132,10 @@ static bool valueFlowForLoop2(const Token *tok, ProgramMemory programMemory; MathLib::bigint result(0); bool error = false; - execute(firstExpression, programMemory, &result, &error); + execute(firstExpression, programMemory, &result, &error, nullptr); if (error) return false; - execute(secondExpression, programMemory, &result, &error); + execute(secondExpression, programMemory, &result, &error, nullptr); if (result == 0) // 2nd expression is false => no looping return false; if (error) { @@ -7158,9 +7158,9 @@ static bool valueFlowForLoop2(const Token *tok, int maxcount = 10000; while (result != 0 && !error && --maxcount > 0) { endMemory = programMemory; - execute(thirdExpression, programMemory, &result, &error); + execute(thirdExpression, programMemory, &result, &error, nullptr); if (!error) - execute(secondExpression, programMemory, &result, &error); + execute(secondExpression, programMemory, &result, &error, nullptr); } if (memory1) @@ -7217,7 +7217,7 @@ static void valueFlowForLoopSimplify(Token* const bodyStart, } if (Token::Match(tok2, "%oror%|&&")) { - const ProgramMemory programMemory(getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), &settings)); + const ProgramMemory programMemory(getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), settings)); if ((tok2->str() == "&&" && !conditionIsTrue(tok2->astOperand1(), programMemory, &settings)) || (tok2->str() == "||" && !conditionIsFalse(tok2->astOperand1(), programMemory, &settings))) { // Skip second expression.. @@ -7242,11 +7242,11 @@ static void valueFlowForLoopSimplify(Token* const bodyStart, if ((tok2->str() == "&&" && conditionIsFalse(tok2->astOperand1(), - getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), &settings), + getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), settings), &settings)) || (tok2->str() == "||" && conditionIsTrue(tok2->astOperand1(), - getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), &settings), + getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), settings), &settings))) break; @@ -7965,7 +7965,7 @@ static void valueFlowFunctionReturn(TokenList &tokenlist, ErrorLogger &errorLogg } if (programMemory.empty() && !arguments.empty()) continue; - std::vector values = execute(function->functionScope, programMemory, &settings); + std::vector values = execute(function->functionScope, programMemory, settings); for (const ValueFlow::Value& v : values) { if (v.isUninitValue()) continue; @@ -8020,7 +8020,7 @@ static void addToErrorPath(ValueFlow::Value& value, const ValueFlow::Value& from static std::vector findAllUsages(const Variable* var, Token* start, // cppcheck-suppress constParameterPointer // FP - const Library* library) + const Library& library) { // std::vector result; const Scope* scope = var->scope(); @@ -8031,7 +8031,7 @@ static std::vector findAllUsages(const Variable* var, }); } -static Token* findStartToken(const Variable* var, Token* start, const Library* library) +static Token* findStartToken(const Variable* var, Token* start, const Library& library) { std::vector uses = findAllUsages(var, start, library); if (uses.empty()) @@ -8111,7 +8111,7 @@ static void valueFlowUninit(TokenList& tokenlist, ErrorLogger& errorLogger, cons bool partial = false; - Token* start = findStartToken(var, tok->next(), &settings.library); + Token* start = findStartToken(var, tok->next(), settings.library); std::map partialReads; if (const Scope* scope = var->typeScope()) { @@ -8568,7 +8568,7 @@ static Library::Container::Yield findIteratorYield(Token* tok, const Token** fto return yield; //begin/end free functions - return astFunctionYield(tok->astParent()->previous(), &settings, ftok); + return astFunctionYield(tok->astParent()->previous(), settings, ftok); } static void valueFlowIterators(TokenList &tokenlist, const Settings &settings) diff --git a/test/testastutils.cpp b/test/testastutils.cpp index baa8357d09c..869e991ed54 100644 --- a/test/testastutils.cpp +++ b/test/testastutils.cpp @@ -145,7 +145,7 @@ class TestAstUtils : public TestFixture { const Token * const tok = (offset < 0) ? tokenizer.list.back()->tokAt(1+offset) : tokenizer.tokens()->tokAt(offset); - return (isReturnScope)(tok); + return (isReturnScope)(tok, settingsDefault.library); } void isReturnScopeTest() { From 82fcffa1a8b9b8c5f107aeddcc60b553b01c187f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Mon, 15 Apr 2024 22:42:45 +0200 Subject: [PATCH 10/11] iwyu.yml: use Qt 6.7.0 for `include-what-you-use` (#6218) Starting with Qt 6.7.0 we no longer require the Qt mappings because IWYU annotations have been added to the headers upstream (see https://bugreports.qt.io/browse/QTBUG-119505). --- .github/workflows/iwyu.yml | 60 ++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/.github/workflows/iwyu.yml b/.github/workflows/iwyu.yml index 9ef6f6fb03c..738d0d1489e 100644 --- a/.github/workflows/iwyu.yml +++ b/.github/workflows/iwyu.yml @@ -15,7 +15,7 @@ jobs: strategy: matrix: - image: ["opensuse/tumbleweed:latest"] # "opensuse/tumbleweed:latest" / "fedora:latest" / "debian:unstable" / "archlinux:latest" + image: ["archlinux:latest"] # "opensuse/tumbleweed:latest" / "fedora:latest" / "debian:unstable" / "archlinux:latest" runs-on: ubuntu-22.04 if: ${{ github.repository_owner == 'danmar' }} @@ -23,6 +23,9 @@ jobs: container: image: ${{ matrix.image }} + env: + QT_VERSION: 6.7.0 + steps: - uses: actions/checkout@v3 @@ -31,19 +34,16 @@ jobs: run: | apt-get update apt-get install -y cmake clang make libpcre3-dev - apt-get install -y qt6-base-dev qt6-tools-dev qt6-charts-dev - apt-get install -y wget iwyu - ln -s x86_64-linux-gnu/qt6 /usr/include/qt + apt-get install -y libgl-dev # fixes missing dependency for Qt in CMake + apt-get install -y iwyu - # TODO: fails with /usr/lib/qt6/bin/lupdate: symbol lookup error: /usr/lib/libproxy/libpxbackend-1.0.so: undefined symbol: g_once_init_leave_pointer - name: Install missing software on archlinux if: contains(matrix.image, 'archlinux') run: | set -x pacman -Sy pacman -S cmake make clang pcre --noconfirm - pacman -S qt6-base qt6-tools qt6-charts --noconfirm - pacman -S wget --noconfirm + pacman -S libglvnd --noconfirm # fixes missing dependency for Qt in CMake pacman-key --init pacman-key --recv-key 3056513887B78AEB --keyserver keyserver.ubuntu.com pacman-key --lsign-key 3056513887B78AEB @@ -53,25 +53,36 @@ jobs: pacman -Sy pacman -S include-what-you-use --noconfirm ln -s iwyu-tool /usr/sbin/iwyu_tool - ln -s qt6 /usr/include/qt - name: Install missing software on Fedora if: contains(matrix.image, 'fedora') run: | dnf install -y cmake clang pcre-devel - dnf install -y qt6-qtbase-devel qt6-qttools-devel qt6-qtcharts-devel - dnf install -y wget iwyu + dnf install -y libglvnd-devel # fixes missing dependency for Qt in CMake + dnf install -y iwyu ln -s iwyu_tool.py /usr/bin/iwyu_tool - ln -s qt6 /usr/include/qt - name: Install missing software on OpenSUSE if: contains(matrix.image, 'opensuse') run: | zypper install -y cmake clang pcre-devel - zypper install -y qt6-base-common-devel qt6-core-devel qt6-gui-devel qt6-widgets-devel qt6-printsupport-devel qt6-linguist-devel qt6-help-devel qt6-charts-devel qt6-test-devel - zypper install -y wget include-what-you-use-tools + zypper install -y include-what-you-use-tools + # fixes error during Qt installation + # /__w/cppcheck/Qt/6.7.0/gcc_64/bin/qmake: error while loading shared libraries: libgthread-2.0.so.0: cannot open shared object file: No such file or directory + zypper install -y libgthread-2_0-0 ln -s iwyu_tool.py /usr/bin/iwyu_tool - ln -s qt6 /usr/include/qt + + # Fails on OpenSUSE: + # Warning: Failed to restore: Tar failed with error: Unable to locate executable file: tar. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also check the file mode to verify the file is executable. + # Also the shell is broken afterwards: + # OCI runtime exec failed: exec failed: unable to start container process: exec: "sh": executable file not found in $PATH: unknown + - name: Install Qt ${{ env.QT_VERSION }} + uses: jurplel/install-qt-action@v3 + with: + version: ${{ env.QT_VERSION }} + modules: 'qtcharts' + install-deps: false + cache: true - name: Prepare CMake run: | @@ -80,6 +91,8 @@ jobs: CC: clang CXX: clang++ + # Fails on Debian: + # /__w/cppcheck/Qt/6.7.0/gcc_64/libexec/rcc: error while loading shared libraries: libglib-2.0.so.0: cannot open shared object file: No such file or directory - name: Prepare CMake dependencies run: | # make sure the precompiled headers exist @@ -93,16 +106,11 @@ jobs: make -C cmake.output gui-build-deps make -C cmake.output triage-build-ui-deps - - name: Build Qt mappings - run: | - wget https://raw.githubusercontent.com/include-what-you-use/include-what-you-use/master/mapgen/iwyu-mapgen-qt.py - python3 iwyu-mapgen-qt.py /usr/include/qt/ > qt.imp - - name: iwyu_tool run: | PWD=$(pwd) # -isystem/usr/lib/clang/17/include - iwyu_tool -p cmake.output -j $(nproc) -- -w -Xiwyu --max_line_length=1024 -Xiwyu --comment_style=long -Xiwyu --quoted_includes_first -Xiwyu --update_comments -Xiwyu --mapping_file=$PWD/qt.imp > iwyu.log + iwyu_tool -p cmake.output -j $(nproc) -- -w -Xiwyu --max_line_length=1024 -Xiwyu --comment_style=long -Xiwyu --quoted_includes_first -Xiwyu --update_comments > iwyu.log - uses: actions/upload-artifact@v3 if: success() || failure() @@ -110,12 +118,6 @@ jobs: name: Compilation Database path: ./cmake.output/compile_commands.json - - uses: actions/upload-artifact@v3 - if: success() || failure() - with: - name: Qt Mappings - path: ./qt.imp - - uses: actions/upload-artifact@v3 if: success() || failure() with: @@ -136,9 +138,8 @@ jobs: - name: Install missing software run: | sudo apt-get update - sudo apt-get install -y cmake make - sudo apt-get install -y libpcre3-dev - sudo apt-get install -y libffi7 # work around missing dependency for Qt install step + sudo apt-get install -y cmake make libpcre3-dev + sudo apt-get install -y libgl-dev # missing dependency for using Qt in CMake - name: Install clang run: | @@ -153,6 +154,7 @@ jobs: with: version: ${{ env.QT_VERSION }} modules: 'qtcharts' + install-deps: false cache: true - name: Prepare CMake From 8cd680bba26dc917db4177f7ba533e6c576ff8e0 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 15 Apr 2024 22:43:04 +0200 Subject: [PATCH 11/11] Fix #8862 Enhancement: false negative: variablescope (#6294) --- lib/checkother.cpp | 4 ++++ test/testother.cpp | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 453495af520..171437a20db 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -915,6 +915,10 @@ static bool isSimpleExpr(const Token* tok, const Variable* var, const Settings* if (Token::Match(ftok, "%name% (") && ((ftok->function() && ftok->function()->isConst()) || settings->library.isFunctionConst(ftok->str(), /*pure*/ true))) needsCheck = true; + if (tok->isArithmeticalOp() && + (!tok->astOperand1() || isSimpleExpr(tok->astOperand1(), var, settings)) && + (!tok->astOperand2() || isSimpleExpr(tok->astOperand2(), var, settings))) + return true; } return (needsCheck && !findExpressionChanged(tok, tok->astParent(), var->scope()->bodyEnd, settings)); } diff --git a/test/testother.cpp b/test/testother.cpp index 4d4286ce1d5..85ee90f7ff6 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -100,6 +100,7 @@ class TestOther : public TestFixture { TEST_CASE(varScope37); // #12158 TEST_CASE(varScope38); TEST_CASE(varScope39); + TEST_CASE(varScope40); TEST_CASE(oldStylePointerCast); TEST_CASE(invalidPointerCast); @@ -1710,6 +1711,28 @@ class TestOther : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void varScope40() { + checkP("#define NUM (-999.9)\n" + "double f(int i) {\n" + " double a = NUM;\n" + " double b = -NUM;\n" + " double c = -1.0 * NUM;\n" + " if (i == 1) {\n" + " return a;\n" + " }\n" + " if (i == 2) {\n" + " return b;\n" + " }\n" + " if (i == 3) {\n" + " return c;\n" + " }\n" + " return 0.0;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (style) The scope of the variable 'a' can be reduced.\n" + "[test.cpp:4]: (style) The scope of the variable 'b' can be reduced.\n" + "[test.cpp:5]: (style) The scope of the variable 'c' can be reduced.\n", + errout_str()); + } #define checkOldStylePointerCast(code) checkOldStylePointerCast_(code, __FILE__, __LINE__) void checkOldStylePointerCast_(const char code[], const char* file, int line) {