diff --git a/addons/cppcheckdata.py b/addons/cppcheckdata.py
index efbe86a41..55c27c448 100755
--- a/addons/cppcheckdata.py
+++ b/addons/cppcheckdata.py
@@ -137,7 +137,8 @@ class Token:
isUnsigned Is this token a unsigned type
isSigned Is this token a signed type
isExpandedMacro Is this token a expanded macro token
- isSplittedVarDecl Is this token a splitted variable declaration. "int a,b; => int a; int b;"
+ isSplittedVarDeclComma Is this a comma changed to semicolon in a splitted variable declaration ('int a,b;' => 'int a; int b;')
+ isSplittedVarDeclEq Is this a '=' changed to semicolon in a splitted variable declaration ('int a=5;' => 'int a; a=5;')
varId varId for token, each variable has a unique non-zero id
variable Variable information for this token. See the Variable class.
function If this token points at a function call, this attribute has the Function
@@ -186,7 +187,8 @@ class Token:
isUnsigned = False
isSigned = False
isExpandedMacro = False
- isSplittedVarDecl = False
+ isSplittedVarDeclComma = False
+ isSplittedVarDeclEq = False
varId = None
variableId = None
variable = None
@@ -247,8 +249,10 @@ class Token:
self.isLogicalOp = True
if element.get('isExpandedMacro'):
self.isExpandedMacro = True
- if element.get('isSplittedVarDecl'):
- self.isSplittedVarDecl = True
+ if element.get('isSplittedVarDeclComma'):
+ self.isSplittedVarDeclComma = True
+ if element.get('isSplittedVarDeclEq'):
+ self.isSplittedVarDeclEq = True
self.linkId = element.get('link')
self.link = None
if element.get('varId'):
@@ -279,10 +283,10 @@ class Token:
attrs = ["Id", "str", "scopeId", "isName", "isUnsigned", "isSigned",
"isNumber", "isInt", "isFloat", "isString", "strlen",
"isChar", "isOp", "isArithmeticalOp", "isComparisonOp",
- "isLogicalOp", "isExpandedMacro", "isSplittedVarDecl",
- "linkId", "varId", "variableId", "functionId", "valuesId",
- "valueType", "typeScopeId", "astParentId", "astOperand1Id",
- "file", "linenr", "column"]
+ "isLogicalOp", "isExpandedMacro", "isSplittedVarDeclComma",
+ "isSplittedVarDeclEq","linkId", "varId", "variableId",
+ "functionId", "valuesId", "valueType", "typeScopeId",
+ "astParentId", "astOperand1Id", "file", "linenr", "column"]
return "{}({})".format(
"Token",
", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
diff --git a/addons/misra.py b/addons/misra.py
index bb8274368..4ee33b739 100755
--- a/addons/misra.py
+++ b/addons/misra.py
@@ -1640,7 +1640,7 @@ class MisraChecker:
def misra_12_3(self, data):
for token in data.tokenlist:
- if token.str == ';' and (token.isSplittedVarDecl is True):
+ if token.str == ';' and (token.isSplittedVarDeclComma is True):
self.reportError(token, 12, 3)
if token.str == ',' and token.astParent and token.astParent.str == ';':
self.reportError(token, 12, 3)
diff --git a/cfg/wxwidgets.cfg b/cfg/wxwidgets.cfg
index 883be5969..c860016d4 100644
--- a/cfg/wxwidgets.cfg
+++ b/cfg/wxwidgets.cfg
@@ -14381,4 +14381,17 @@ wxItemKind kind = wxITEM_NORMAL) -->
+
+
+ false
+
+
+
+
+
+
+ false
+
+
+
diff --git a/lib/astutils.cpp b/lib/astutils.cpp
index 1f75dd775..80dde21d6 100644
--- a/lib/astutils.cpp
+++ b/lib/astutils.cpp
@@ -248,6 +248,9 @@ bool isTemporary(bool cpp, const Token* tok, const Library* library, bool unknow
if (Token::Match(tok, "&|<<|>>") && isLikelyStream(cpp, tok->astOperand1()))
return false;
if (Token::Match(tok->previous(), ">|%name% (")) {
+ if (tok->valueType()) {
+ return tok->valueType()->reference == Reference::None;
+ }
const Token* ftok = nullptr;
if (tok->previous()->link())
ftok = tok->previous()->link()->previous();
@@ -956,7 +959,7 @@ bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token
if (!cond1 || !cond2)
return false;
- if (cond1->str() == "&&" && cond2->str() == "&&") {
+ if (!isNot && cond1->str() == "&&" && cond2->str() == "&&") {
for (const Token* tok1: {
cond1->astOperand1(), cond1->astOperand2()
}) {
diff --git a/lib/bughuntingchecks.cpp b/lib/bughuntingchecks.cpp
index ba78a4cfc..85e3eec24 100644
--- a/lib/bughuntingchecks.cpp
+++ b/lib/bughuntingchecks.cpp
@@ -306,7 +306,7 @@ static void uninit(const Token *tok, const ExprEngine::Value &value, ExprEngine:
if (!var->isLocal() || var->isStatic())
return;
}
- if (var && (Token::Match(var->nameToken(), "%name% [=:({)]") || Token::Match(var->nameToken(), "%varid% ; %varid% =", var->declarationId())))
+ if (var && (Token::Match(var->nameToken(), "%name% [=:({)]") || var->isInit()))
return;
if (var && var->nameToken() == tok)
return;
diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp
index 9402faaf3..a1d99f1d7 100644
--- a/lib/checkautovariables.cpp
+++ b/lib/checkautovariables.cpp
@@ -528,6 +528,16 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token
errorDanglingReference(tok, var, errorPath);
continue;
}
+ // Reference to temporary
+ } else if (tok->variable() && (tok->variable()->isReference() || tok->variable()->isRValueReference())) {
+ for (const LifetimeToken& lt : getLifetimeTokens(getParentLifetime(tok))) {
+ const Token * tokvalue = lt.token;
+ if (isDeadTemporary(mTokenizer->isCPP(), tokvalue, tok, &mSettings->library)) {
+ errorDanglingTempReference(tok, lt.errorPath, lt.inconclusive);
+ break;
+ }
+ }
+
}
for (const ValueFlow::Value& val:tok->values()) {
if (!val.isLocalLifetimeValue() && !val.isSubFunctionLifetimeValue())
@@ -644,6 +654,13 @@ void CheckAutoVariables::errorDanglngLifetime(const Token *tok, const ValueFlow:
reportError(errorPath, Severity::error, "danglingLifetime", msg + ".", CWE562, inconclusive);
}
+void CheckAutoVariables::errorDanglingTempReference(const Token* tok, ErrorPath errorPath, bool inconclusive)
+{
+ errorPath.emplace_back(tok, "");
+ reportError(
+ errorPath, Severity::error, "danglingTempReference", "Using reference to dangling temporary.", CWE562, inconclusive);
+}
+
void CheckAutoVariables::errorReturnReference(const Token* tok, ErrorPath errorPath, bool inconclusive)
{
errorPath.emplace_back(tok, "");
diff --git a/lib/checkautovariables.h b/lib/checkautovariables.h
index 7087aacef..99356ca56 100644
--- a/lib/checkautovariables.h
+++ b/lib/checkautovariables.h
@@ -79,6 +79,7 @@ private:
void errorDanglingTemporaryLifetime(const Token* tok, const ValueFlow::Value* val);
void errorReturnReference(const Token* tok, ErrorPath errorPath, bool inconclusive);
void errorDanglingReference(const Token *tok, const Variable *var, ErrorPath errorPath);
+ void errorDanglingTempReference(const Token* tok, ErrorPath errorPath, bool inconclusive);
void errorReturnTempReference(const Token* tok, ErrorPath errorPath, bool inconclusive);
void errorInvalidDeallocation(const Token *tok, const ValueFlow::Value *val);
void errorReturnAddressOfFunctionParameter(const Token *tok, const std::string &varname);
@@ -94,6 +95,7 @@ private:
c.errorReturnReference(nullptr, errorPath, false);
c.errorDanglingReference(nullptr, nullptr, errorPath);
c.errorReturnTempReference(nullptr, errorPath, false);
+ c.errorDanglingTempReference(nullptr, errorPath, false);
c.errorInvalidDeallocation(nullptr, nullptr);
c.errorReturnAddressOfFunctionParameter(nullptr, "parameter");
c.errorUselessAssignmentArg(nullptr);
diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp
index f513a3285..2c45f8e9a 100644
--- a/lib/checkclass.cpp
+++ b/lib/checkclass.cpp
@@ -111,11 +111,7 @@ void CheckClass::constructors()
if (scope->numConstructors == 0 && printStyle && !usedInUnion) {
// If there is a private variable, there should be a constructor..
for (const Variable &var : scope->varlist) {
- const Token *initTok = var.nameToken();
- while (Token::simpleMatch(initTok->next(), "["))
- initTok = initTok->linkAt(1);
- if (var.isPrivate() && !var.isStatic() && !Token::Match(var.nameToken(), "%varid% ; %varid% =", var.declarationId()) &&
- !Token::Match(initTok, "%var%|] {|=") &&
+ if (var.isPrivate() && !var.isStatic() && !var.isInit() &&
(!var.isClass() || (var.type() && var.type()->needInitialization == Type::NeedInitialization::True))) {
noConstructorError(scope->classDef, scope->className, scope->classDef->str() == "struct");
break;
@@ -947,9 +943,15 @@ void CheckClass::initializationListUsage()
for (const Scope *scope : mSymbolDatabase->functionScopes) {
// Check every constructor
- if (!scope->function || (!scope->function->isConstructor()))
+ if (!scope->function || !scope->function->isConstructor())
continue;
+ // Do not warn when a delegate constructor is called
+ if (const Token *initList = scope->function->constructorMemberInitialization()) {
+ if (Token::Match(initList, ": %name% {|(") && initList->strAt(1) == scope->className)
+ continue;
+ }
+
const Scope* owner = scope->functionOf;
for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
if (Token::Match(tok, "%name% (")) // Assignments might depend on this function call or if/for/while/switch statement from now on.
diff --git a/lib/checkother.cpp b/lib/checkother.cpp
index 5d395ccd7..89ba23d8c 100644
--- a/lib/checkother.cpp
+++ b/lib/checkother.cpp
@@ -432,7 +432,7 @@ void CheckOther::checkRedundantAssignment()
// Do not warn about redundant initialization when rhs is trivial
// TODO : do not simplify the variable declarations
bool isInitialization = false;
- if (Token::Match(tok->tokAt(-3), "%var% ; %var% =") && tok->previous()->variable() && tok->previous()->variable()->nameToken() == tok->tokAt(-3) && tok->tokAt(-3)->linenr() == tok->previous()->linenr()) {
+ if (Token::Match(tok->tokAt(-2), "; %var% =") && tok->tokAt(-2)->isSplittedVarDeclEq()) {
isInitialization = true;
bool trivial = true;
visitAstNodes(tok->astOperand2(),
diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp
index 9787d203c..914753f6a 100644
--- a/lib/checkstl.cpp
+++ b/lib/checkstl.cpp
@@ -59,6 +59,11 @@ static const struct CWE CWE825(825U); // Expired Pointer Dereference
static const struct CWE CWE833(833U); // Deadlock
static const struct CWE CWE834(834U); // Excessive Iteration
+static bool isElementAccessYield(const Library::Container::Yield& yield)
+{
+ return yield == Library::Container::Yield::ITEM || yield == Library::Container::Yield::AT_INDEX;
+}
+
void CheckStl::outOfBounds()
{
for (const Scope *function : mTokenizer->getSymbolDatabase()->functionScopes) {
@@ -76,9 +81,28 @@ void CheckStl::outOfBounds()
continue;
if (!value.errorSeverity() && !mSettings->isEnabled(Settings::WARNING))
continue;
- if (value.intvalue == 0 && Token::Match(parent, ". %name% (") && container->getYield(parent->strAt(1)) == Library::Container::Yield::ITEM) {
- outOfBoundsError(parent->tokAt(2), tok->expressionString(), &value, parent->strAt(1), nullptr);
- continue;
+ if (Token::Match(parent, ". %name% (") && isElementAccessYield(container->getYield(parent->strAt(1)))) {
+ if (value.intvalue == 0) {
+ outOfBoundsError(parent->tokAt(2), tok->expressionString(), &value, parent->strAt(1), nullptr);
+ continue;
+ }
+ const Token* indexTok = parent->tokAt(2)->astOperand2();
+ if (!indexTok)
+ continue;
+ const ValueFlow::Value* indexValue = indexTok->getMaxValue(false);
+ if (indexValue && indexValue->intvalue >= value.intvalue) {
+ outOfBoundsError(
+ parent, tok->expressionString(), &value, indexTok->expressionString(), indexValue);
+ continue;
+ }
+ if (mSettings->isEnabled(Settings::WARNING)) {
+ indexValue = indexTok->getMaxValue(true);
+ if (indexValue && indexValue->intvalue >= value.intvalue) {
+ outOfBoundsError(
+ parent, tok->expressionString(), &value, indexTok->expressionString(), indexValue);
+ continue;
+ }
+ }
}
if (Token::Match(tok, "%name% . %name% (") && container->getYield(tok->strAt(2)) == Library::Container::Yield::START_ITERATOR) {
const Token *fparent = tok->tokAt(3)->astParent();
diff --git a/lib/exprengine.cpp b/lib/exprengine.cpp
index 9050c2c1a..a624a124d 100644
--- a/lib/exprengine.cpp
+++ b/lib/exprengine.cpp
@@ -2512,7 +2512,7 @@ static ExprEngine::ValuePtr createStructVal(const Scope *structScope, bool unini
std::shared_ptr structValue = std::make_shared(data.getNewSymbolName());
auto uninitValue = std::make_shared();
for (const Variable &member : structScope->varlist) {
- if (uninitData) {
+ if (uninitData && !member.isInit()) {
if (member.isPointer()) {
structValue->member[member.name()] = uninitValue;
continue;
diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp
index 5f4c5b900..8b6e5219a 100644
--- a/lib/symboldatabase.cpp
+++ b/lib/symboldatabase.cpp
@@ -21,6 +21,7 @@
#include "astutils.h"
#include "errorlogger.h"
+#include "library.h"
#include "mathlib.h"
#include "platform.h"
#include "settings.h"
@@ -1869,6 +1870,13 @@ Variable::Variable(const Token *name_, const std::string &clangType, const Token
++pos;
} while (pos < clangType.size() && clangType[pos] == '[');
}
+
+ // Is there initialization in variable declaration
+ const Token *initTok = mNameToken ? mNameToken->next() : nullptr;
+ while (initTok && initTok->str() == "[")
+ initTok = initTok->link()->next();
+ if (Token::Match(initTok, "=|{") || (initTok && initTok->isSplittedVarDeclEq()))
+ setFlag(fIsInit, true);
}
Variable::~Variable()
@@ -1899,6 +1907,13 @@ const Token * Variable::declEndToken() const
void Variable::evaluate(const Settings* settings)
{
+ // Is there initialization in variable declaration
+ const Token *initTok = mNameToken ? mNameToken->next() : nullptr;
+ while (initTok && initTok->str() == "[")
+ initTok = initTok->link()->next();
+ if (Token::Match(initTok, "=|{") || (initTok && initTok->isSplittedVarDeclEq()))
+ setFlag(fIsInit, true);
+
if (!settings)
return;
@@ -5968,7 +5983,8 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
valuetype.sign = ValueType::Sign::SIGNED;
}
setValueType(tok, valuetype);
- } else if (tok->link() && tok->str() == "(") {
+ } else if (tok->link() && Token::Match(tok, "(|{")) {
+ const Token* start = tok->astOperand1() ? tok->astOperand1()->findExpressionStartEndTokens().first : nullptr;
// cast
if (tok->isCast() && !tok->astOperand2() && Token::Match(tok, "( %name%")) {
ValueType valuetype;
@@ -5983,6 +5999,16 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
setValueType(tok, valuetype);
}
+ // Construct smart pointer
+ else if (mSettings->library.isSmartPointer(start)) {
+ ValueType valuetype;
+ if (parsedecl(start, &valuetype, mDefaultSignedness, mSettings)) {
+ setValueType(tok, valuetype);
+ setValueType(tok->astOperand1(), valuetype);
+ }
+
+ }
+
// function
else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->retDef) {
ValueType valuetype;
diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h
index 7485883ac..df9f1aab9 100644
--- a/lib/symboldatabase.h
+++ b/lib/symboldatabase.h
@@ -199,6 +199,7 @@ class CPPCHECKLIB Variable {
fIsVolatile = (1 << 13), /** @brief volatile */
fIsSmartPointer = (1 << 14),/** @brief std::shared_ptr|unique_ptr */
fIsMaybeUnused = (1 << 15), /** @brief marked [[maybe_unused]] */
+ fIsInit = (1 << 16), /** @brief Is variable initialized in declaration */
};
/**
@@ -501,6 +502,14 @@ public:
return getFlag(fHasDefault);
}
+ /**
+ * Is variable initialized in its declaration
+ * @return true if variable declaration contains initialization
+ */
+ bool isInit() const {
+ return getFlag(fIsInit);
+ }
+
/**
* Get Type pointer of known type.
* @return pointer to type if known, NULL if not known
diff --git a/lib/token.h b/lib/token.h
index 981f49e4a..a93e67258 100644
--- a/lib/token.h
+++ b/lib/token.h
@@ -612,11 +612,18 @@ public:
setFlag(fExternC, b);
}
- bool isSplittedVarDecl() const {
- return getFlag(fIsSplitVarDecl);
+ bool isSplittedVarDeclComma() const {
+ return getFlag(fIsSplitVarDeclComma);
}
- void isSplittedVarDecl(bool b) {
- setFlag(fIsSplitVarDecl, b);
+ void isSplittedVarDeclComma(bool b) {
+ setFlag(fIsSplitVarDeclComma, b);
+ }
+
+ bool isSplittedVarDeclEq() const {
+ return getFlag(fIsSplitVarDeclEq);
+ }
+ void isSplittedVarDeclEq(bool b) {
+ setFlag(fIsSplitVarDeclEq, b);
}
bool isBitfield() const {
@@ -1201,7 +1208,8 @@ private:
fIncompleteVar = (1 << 26),
fConstexpr = (1 << 27),
fExternC = (1 << 28),
- fIsSplitVarDecl = (1 << 29), // int a,b; <-- vardecl is split up
+ fIsSplitVarDeclComma = (1 << 29), // set to true when variable declarations are split up ('int a,b;' => 'int a; int b;')
+ fIsSplitVarDeclEq = (1 << 30) // set to true when variable declaration with initialization is split up ('int a=5;' => 'int a; a=5;')
};
Token::Type mTokType;
diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp
index fd9c7e2b5..7c73e6331 100644
--- a/lib/tokenize.cpp
+++ b/lib/tokenize.cpp
@@ -4974,8 +4974,10 @@ void Tokenizer::dump(std::ostream &out) const
}
if (tok->isExpandedMacro())
out << " isExpandedMacro=\"true\"";
- if (tok->isSplittedVarDecl())
- out << " isSplittedVarDecl=\"true\"";
+ if (tok->isSplittedVarDeclComma())
+ out << " isSplittedVarDeclComma=\"true\"";
+ if (tok->isSplittedVarDeclEq())
+ out << " isSplittedVarDeclEq=\"true\"";
if (tok->link())
out << " link=\"" << tok->link() << '\"';
if (tok->varId() > 0)
@@ -6859,7 +6861,7 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co
if (tok2->str() == ",") {
tok2->str(";");
- tok2->isSplittedVarDecl(true);
+ tok2->isSplittedVarDeclComma(true);
//TODO: should we have to add also template '<>' links?
TokenList::insertTokens(tok2, type0, typelen);
}
@@ -6883,11 +6885,12 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co
syntaxError(tok2); // invalid code
TokenList::insertTokens(eq, varTok, 2);
eq->str(";");
+ eq->isSplittedVarDeclEq(true);
// "= x, " => "= x; type "
if (tok2->str() == ",") {
tok2->str(";");
- tok2->isSplittedVarDecl(true);
+ tok2->isSplittedVarDeclComma(true);
TokenList::insertTokens(tok2, type0, typelen);
}
break;
diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp
index c48410770..a030003aa 100644
--- a/lib/valueflow.cpp
+++ b/lib/valueflow.cpp
@@ -3062,7 +3062,7 @@ std::vector getLifetimeTokens(const Token* tok, bool escape, Valu
return std::vector {};
const Token* argTok = args[n];
lt.errorPath.emplace_back(returnTok, "Return reference.");
- lt.errorPath.emplace_back(tok->previous(), "Called function passing '" + argTok->str() + "'.");
+ lt.errorPath.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
std::vector arglts = LifetimeToken::setInconclusive(
getLifetimeTokens(argTok, escape, std::move(lt.errorPath), depth - 1), returns.size() > 1);
result.insert(result.end(), arglts.begin(), arglts.end());
@@ -3422,7 +3422,7 @@ struct LifetimeStore {
return LifetimeStore{};
}
const Token *argtok2 = args[n];
- return LifetimeStore{argtok2, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Object};
+ return LifetimeStore{argtok2, "Passed to '" + tok->expressionString() + "'.", ValueFlow::Value::LifetimeKind::Object};
}
template
@@ -5650,10 +5650,8 @@ static void valueFlowUninit(TokenList *tokenlist, SymbolDatabase * /*symbolDatab
// continue;
if (!Token::Match(vardecl, "%var% ;"))
continue;
- if (Token::Match(vardecl, "%varid% ; %varid% =", vardecl->varId()))
- continue;
const Variable *var = vardecl->variable();
- if (!var || var->nameToken() != vardecl)
+ if (!var || var->nameToken() != vardecl || var->isInit())
continue;
if ((!var->isPointer() && var->type() && var->type()->needInitialization != Type::NeedInitialization::True) ||
!var->isLocal() || var->isStatic() || var->isExtern() || var->isReference() || var->isThrow())
@@ -5957,47 +5955,55 @@ static void valueFlowSmartPointer(TokenList *tokenlist, ErrorLogger * errorLogge
continue;
if (!tok->scope()->isExecutable())
continue;
- if (!tok->variable())
- continue;
- const Variable * var = tok->variable();
- if (!var->isSmartPointer())
- continue;
- if (var->nameToken() == tok) {
- if (Token::Match(tok, "%var% (|{") && tok->next()->astOperand2() && tok->next()->astOperand2()->str() != ",") {
- Token * inTok = tok->next()->astOperand2();
- std::list values = inTok->values();
- const bool constValue = inTok->isNumber();
- valueFlowForwardAssign(inTok, var, values, constValue, true, tokenlist, errorLogger, settings);
+ if (tok->variable()) {
+ const Variable* var = tok->variable();
+ if (!var->isSmartPointer())
+ continue;
+ if (var->nameToken() == tok) {
+ if (Token::Match(tok, "%var% (|{") && tok->next()->astOperand2() &&
+ tok->next()->astOperand2()->str() != ",") {
+ Token* inTok = tok->next()->astOperand2();
+ std::list values = inTok->values();
+ const bool constValue = inTok->isNumber();
+ valueFlowForwardAssign(inTok, var, values, constValue, true, tokenlist, errorLogger, settings);
- } else if (Token::Match(tok, "%var% ;")) {
- std::list values;
- ValueFlow::Value v(0);
- v.setKnown();
- values.push_back(v);
- valueFlowForwardAssign(tok, var, values, false, true, tokenlist, errorLogger, settings);
- }
- } else if (Token::Match(tok, "%var% . reset (") && tok->next()->originalName() != "->") {
- if (Token::simpleMatch(tok->tokAt(3), "( )")) {
+ } else if (Token::Match(tok, "%var% ;")) {
+ std::list values;
+ ValueFlow::Value v(0);
+ v.setKnown();
+ values.push_back(v);
+ valueFlowForwardAssign(tok, var, values, false, true, tokenlist, errorLogger, settings);
+ }
+ } else if (Token::Match(tok, "%var% . reset (") && tok->next()->originalName() != "->") {
+ if (Token::simpleMatch(tok->tokAt(3), "( )")) {
+ std::list values;
+ ValueFlow::Value v(0);
+ v.setKnown();
+ values.push_back(v);
+ valueFlowForwardAssign(tok->tokAt(4), var, values, false, false, tokenlist, errorLogger, settings);
+ } else {
+ tok->removeValues(std::mem_fn(&ValueFlow::Value::isIntValue));
+ Token* inTok = tok->tokAt(3)->astOperand2();
+ if (!inTok)
+ continue;
+ std::list values = inTok->values();
+ const bool constValue = inTok->isNumber();
+ valueFlowForwardAssign(inTok, var, values, constValue, false, tokenlist, errorLogger, settings);
+ }
+ } else if (Token::Match(tok, "%var% . release ( )") && tok->next()->originalName() != "->") {
std::list values;
ValueFlow::Value v(0);
v.setKnown();
values.push_back(v);
valueFlowForwardAssign(tok->tokAt(4), var, values, false, false, tokenlist, errorLogger, settings);
- } else {
- tok->removeValues(std::mem_fn(&ValueFlow::Value::isIntValue));
- Token * inTok = tok->tokAt(3)->astOperand2();
- if (!inTok)
- continue;
- std::list values = inTok->values();
- const bool constValue = inTok->isNumber();
- valueFlowForwardAssign(inTok, var, values, constValue, false, tokenlist, errorLogger, settings);
}
- } else if (Token::Match(tok, "%var% . release ( )") && tok->next()->originalName() != "->") {
- std::list values;
- ValueFlow::Value v(0);
- v.setKnown();
- values.push_back(v);
- valueFlowForwardAssign(tok->tokAt(4), var, values, false, false, tokenlist, errorLogger, settings);
+ } else if (Token::Match(tok->previous(), "%name%|> (|{") && astIsSmartPointer(tok) &&
+ astIsSmartPointer(tok->astOperand1())) {
+ std::vector args = getArguments(tok);
+ if (args.empty())
+ continue;
+ for (const ValueFlow::Value& v : args.front()->values())
+ setTokenValue(tok, v, settings);
}
}
}
@@ -6686,7 +6692,6 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
valueFlowGlobalStaticVar(tokenlist, settings);
valueFlowPointerAlias(tokenlist);
valueFlowLifetime(tokenlist, symboldatabase, errorLogger, settings);
- valueFlowFunctionReturn(tokenlist, errorLogger);
valueFlowBitAnd(tokenlist);
valueFlowSameExpressions(tokenlist);
valueFlowFwdAnalysis(tokenlist, settings);
@@ -6708,6 +6713,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings);
valueFlowForLoop(tokenlist, symboldatabase, errorLogger, settings);
valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings);
+ valueFlowFunctionReturn(tokenlist, errorLogger);
valueFlowLifetime(tokenlist, symboldatabase, errorLogger, settings);
valueFlowFunctionDefaultParameter(tokenlist, symboldatabase, errorLogger, settings);
valueFlowUninit(tokenlist, symboldatabase, errorLogger, settings);
diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp
index 6841f5f51..2b5668ff0 100644
--- a/test/testautovariables.cpp
+++ b/test/testautovariables.cpp
@@ -1442,7 +1442,7 @@ private:
check("auto& f() {\n"
" return std::vector{1}.front();\n"
"}\n");
- TODO_ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:3]: (error) Reference to temporary returned.\n", "", errout.str());
+ ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:2]: (error) Reference to temporary returned.\n", errout.str());
check("struct A { int foo; };\n"
"int& f(std::vector v) {\n"
@@ -1638,7 +1638,8 @@ private:
" int& x = h();\n"
" g(&x);\n"
"}\n");
- ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:5] -> [test.cpp:5]: (error) Using pointer to temporary.\n", errout.str());
+ ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:5] -> [test.cpp:5]: (error) Using pointer to temporary.\n"
+ "[test.cpp:4] -> [test.cpp:5]: (error) Using reference to dangling temporary.\n", errout.str());
check("void g(int*);\n"
"int h();\n"
@@ -1675,6 +1676,27 @@ private:
ASSERT_EQUALS("", errout.str());
}
+ void danglingTempReference() {
+ check("const std::string& g(const std::string& str_cref) {\n"
+ " return str_cref;\n"
+ "}\n"
+ "void f() {\n"
+ " const auto& str_cref2 = g(std::string(\"hello\"));\n"
+ " std::cout << str_cref2 << std::endl;\n"
+ "}\n");
+ ASSERT_EQUALS("error", errout.str());
+
+ // Lifetime extended
+ check("std::string g(const std::string& str_cref) {\n"
+ " return str_cref;\n"
+ "}\n"
+ "void f() {\n"
+ " const auto& str_cref2 = g(std::string(\"hello\"));\n"
+ " std::cout << str_cref2 << std::endl;\n"
+ "}\n");
+ ASSERT_EQUALS("", errout.str());
+ }
+
void testglobalnamespace() {
check("class SharedPtrHolder\n"
"{\n"
diff --git a/test/testbughuntingchecks.cpp b/test/testbughuntingchecks.cpp
index f4aba5233..5229224b4 100644
--- a/test/testbughuntingchecks.cpp
+++ b/test/testbughuntingchecks.cpp
@@ -44,6 +44,7 @@ private:
TEST_CASE(uninit_bailout);
TEST_CASE(uninit_fp_smartptr);
TEST_CASE(uninit_fp_struct);
+ TEST_CASE(uninit_fp_struct_member_init_2);
TEST_CASE(uninit_fp_template_var);
TEST_CASE(ctu);
#endif
@@ -202,6 +203,16 @@ private:
ASSERT_EQUALS("", errout.str());
}
+ void uninit_fp_struct_member_init_2() {
+ check("struct A {\n"
+ " int x {0}; int y {0};\n"
+ "};\n"
+ "void foo(const A& a) {\n"
+ " bar(a);\n"
+ "}");
+ ASSERT_EQUALS("", errout.str());
+ }
+
void uninit_fp_template_var() {
check("void foo() {\n"
" X*x = DYNAMIC_CAST(X, p);\n"
diff --git a/test/testclass.cpp b/test/testclass.cpp
index eaa197725..34a1d6104 100644
--- a/test/testclass.cpp
+++ b/test/testclass.cpp
@@ -6567,6 +6567,19 @@ private:
" Foo m_i;\n"
"};");
ASSERT_EQUALS("", errout.str());
+
+ checkInitializationListUsage("class A {\n" // #9821 - delegate constructor
+ "public:\n"
+ " A() : st{} {}\n"
+ "\n"
+ " explicit A(const std::string &input): A() {\n"
+ " st = input;\n"
+ " }\n"
+ "\n"
+ "private:\n"
+ " std::string st;\n"
+ "};");
+ ASSERT_EQUALS("", errout.str());
}
diff --git a/test/testcondition.cpp b/test/testcondition.cpp
index 823947033..5b41aa0e9 100644
--- a/test/testcondition.cpp
+++ b/test/testcondition.cpp
@@ -3658,6 +3658,15 @@ private:
" if(b[1] == 2) {}\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (style) Condition 'b[1]==2' is always false\n", errout.str());
+
+ // #9878
+ check("void f(bool a, bool b) {\n"
+ " if (a && b){;}\n"
+ " else if (!a && b){;}\n"
+ " else if (!a && !b){;}\n"
+ " else {;}\n"
+ "}\n");
+ ASSERT_EQUALS("", errout.str());
}
void duplicateCondition() {
diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp
index 3c7c1421e..11b77f6b0 100644
--- a/test/testnullpointer.cpp
+++ b/test/testnullpointer.cpp
@@ -2859,6 +2859,16 @@ private:
" return x.release();\n"
"}\n", true);
ASSERT_EQUALS("", errout.str());
+
+ // #9496
+ check("std::shared_ptr f() {\n"
+ " return std::shared_ptr(nullptr);\n"
+ "}\n"
+ "void g() {\n"
+ " int a = *f();\n"
+ "}\n",
+ true);
+ ASSERT_EQUALS("[test.cpp:5]: (error) Null pointer dereference: f()\n", errout.str());
}
void functioncall() { // #3443 - function calls
diff --git a/test/testother.cpp b/test/testother.cpp
index 99f688320..22b5f7c76 100644
--- a/test/testother.cpp
+++ b/test/testother.cpp
@@ -5310,7 +5310,7 @@ private:
check("void f(int* x, bool b) {\n"
" if ((!x && b) || (x != 0 && b)) {}\n"
"}\n");
- ASSERT_EQUALS("[test.cpp:2]: (style) Opposite expression on both sides of '||'.\n", errout.str());
+ ASSERT_EQUALS("", errout.str());
}
void oppositeExpression() {
diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp
index 2e4984f56..1a177dc68 100644
--- a/test/testsimplifytypedef.cpp
+++ b/test/testsimplifytypedef.cpp
@@ -1152,8 +1152,9 @@ private:
ASSERT_EQUALS(expected, tok(code, false));
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
- "[test.cpp:28]: (debug) valueflow.cpp:3109:valueFlowFunctionReturn bailout: function return; nontrivial function body\n"
- , errout.str());
+ "[test.cpp:31]: (debug) valueflow.cpp:3109:valueFlowFunctionReturn bailout: function return; nontrivial function body\n"
+ "[test.cpp:28]: (debug) valueflow.cpp:3109:valueFlowFunctionReturn bailout: function return; nontrivial function body\n",
+ errout.str());
}
void simplifyTypedef36() {
diff --git a/test/teststl.cpp b/test/teststl.cpp
index 4fc0226d1..af953104f 100644
--- a/test/teststl.cpp
+++ b/test/teststl.cpp
@@ -347,6 +347,24 @@ private:
" x[0] = 2;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
+
+ checkNormal("void f(bool b) {\n"
+ " std::vector v;\n"
+ " if(v.at(b?42:0)) {}\n"
+ "}\n");
+ ASSERT_EQUALS(
+ "test.cpp:3:error:Out of bounds access in expression 'v.at(b?42:0)' because 'v' is empty and 'at' may be non-zero.\n",
+ errout.str());
+
+ checkNormal("void f(std::vector v, bool b){\n"
+ " if (v.size() == 1)\n"
+ " if(v.at(b?42:0)) {}\n"
+ "}\n");
+ ASSERT_EQUALS(
+ "test.cpp:3:warning:Either the condition 'v.size()==1' is redundant or v size can be 1. Expression 'v.at' cause access out of bounds.\n"
+ "test.cpp:2:note:condition 'v.size()==1'\n"
+ "test.cpp:3:note:Access out of bounds\n",
+ errout.str());
}
void outOfBoundsIndexExpression() {