From 687b44dbb7c1c30de16b638e12ff9c1f5476de57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 9 Sep 2020 16:22:36 +0200 Subject: [PATCH] Token: add flag for splitted variable declaration with initialization --- addons/cppcheckdata.py | 20 ++++++++++++-------- addons/misra.py | 2 +- lib/bughuntingchecks.cpp | 2 +- lib/checkclass.cpp | 6 +----- lib/checkother.cpp | 2 +- lib/symboldatabase.cpp | 14 ++++++++++++++ lib/symboldatabase.h | 9 +++++++++ lib/token.h | 18 +++++++++++++----- lib/tokenize.cpp | 11 +++++++---- lib/valueflow.cpp | 4 +--- 10 files changed, 60 insertions(+), 28 deletions(-) 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/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/checkclass.cpp b/lib/checkclass.cpp index f513a3285..f893e2ede 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; 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/symboldatabase.cpp b/lib/symboldatabase.cpp index d9706da16..8b6e5219a 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1870,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() @@ -1900,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; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 4d13d9293..52781a1e0 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 9c2c33f96..c77c5ba21 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -5645,10 +5645,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())