Token: add flag for splitted variable declaration with initialization

This commit is contained in:
Daniel Marjamäki 2020-09-09 16:22:36 +02:00
parent bfe53fce04
commit 687b44dbb7
10 changed files with 60 additions and 28 deletions

View File

@ -137,7 +137,8 @@ class Token:
isUnsigned Is this token a unsigned type isUnsigned Is this token a unsigned type
isSigned Is this token a signed type isSigned Is this token a signed type
isExpandedMacro Is this token a expanded macro token 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 varId varId for token, each variable has a unique non-zero id
variable Variable information for this token. See the Variable class. variable Variable information for this token. See the Variable class.
function If this token points at a function call, this attribute has the Function function If this token points at a function call, this attribute has the Function
@ -186,7 +187,8 @@ class Token:
isUnsigned = False isUnsigned = False
isSigned = False isSigned = False
isExpandedMacro = False isExpandedMacro = False
isSplittedVarDecl = False isSplittedVarDeclComma = False
isSplittedVarDeclEq = False
varId = None varId = None
variableId = None variableId = None
variable = None variable = None
@ -247,8 +249,10 @@ class Token:
self.isLogicalOp = True self.isLogicalOp = True
if element.get('isExpandedMacro'): if element.get('isExpandedMacro'):
self.isExpandedMacro = True self.isExpandedMacro = True
if element.get('isSplittedVarDecl'): if element.get('isSplittedVarDeclComma'):
self.isSplittedVarDecl = True self.isSplittedVarDeclComma = True
if element.get('isSplittedVarDeclEq'):
self.isSplittedVarDeclEq = True
self.linkId = element.get('link') self.linkId = element.get('link')
self.link = None self.link = None
if element.get('varId'): if element.get('varId'):
@ -279,10 +283,10 @@ class Token:
attrs = ["Id", "str", "scopeId", "isName", "isUnsigned", "isSigned", attrs = ["Id", "str", "scopeId", "isName", "isUnsigned", "isSigned",
"isNumber", "isInt", "isFloat", "isString", "strlen", "isNumber", "isInt", "isFloat", "isString", "strlen",
"isChar", "isOp", "isArithmeticalOp", "isComparisonOp", "isChar", "isOp", "isArithmeticalOp", "isComparisonOp",
"isLogicalOp", "isExpandedMacro", "isSplittedVarDecl", "isLogicalOp", "isExpandedMacro", "isSplittedVarDeclComma",
"linkId", "varId", "variableId", "functionId", "valuesId", "isSplittedVarDeclEq","linkId", "varId", "variableId",
"valueType", "typeScopeId", "astParentId", "astOperand1Id", "functionId", "valuesId", "valueType", "typeScopeId",
"file", "linenr", "column"] "astParentId", "astOperand1Id", "file", "linenr", "column"]
return "{}({})".format( return "{}({})".format(
"Token", "Token",
", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs)) ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))

View File

@ -1640,7 +1640,7 @@ class MisraChecker:
def misra_12_3(self, data): def misra_12_3(self, data):
for token in data.tokenlist: 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) self.reportError(token, 12, 3)
if token.str == ',' and token.astParent and token.astParent.str == ';': if token.str == ',' and token.astParent and token.astParent.str == ';':
self.reportError(token, 12, 3) self.reportError(token, 12, 3)

View File

@ -306,7 +306,7 @@ static void uninit(const Token *tok, const ExprEngine::Value &value, ExprEngine:
if (!var->isLocal() || var->isStatic()) if (!var->isLocal() || var->isStatic())
return; 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; return;
if (var && var->nameToken() == tok) if (var && var->nameToken() == tok)
return; return;

View File

@ -111,11 +111,7 @@ void CheckClass::constructors()
if (scope->numConstructors == 0 && printStyle && !usedInUnion) { if (scope->numConstructors == 0 && printStyle && !usedInUnion) {
// If there is a private variable, there should be a constructor.. // If there is a private variable, there should be a constructor..
for (const Variable &var : scope->varlist) { for (const Variable &var : scope->varlist) {
const Token *initTok = var.nameToken(); if (var.isPrivate() && !var.isStatic() && !var.isInit() &&
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%|] {|=") &&
(!var.isClass() || (var.type() && var.type()->needInitialization == Type::NeedInitialization::True))) { (!var.isClass() || (var.type() && var.type()->needInitialization == Type::NeedInitialization::True))) {
noConstructorError(scope->classDef, scope->className, scope->classDef->str() == "struct"); noConstructorError(scope->classDef, scope->className, scope->classDef->str() == "struct");
break; break;

View File

@ -432,7 +432,7 @@ void CheckOther::checkRedundantAssignment()
// Do not warn about redundant initialization when rhs is trivial // Do not warn about redundant initialization when rhs is trivial
// TODO : do not simplify the variable declarations // TODO : do not simplify the variable declarations
bool isInitialization = false; 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; isInitialization = true;
bool trivial = true; bool trivial = true;
visitAstNodes(tok->astOperand2(), visitAstNodes(tok->astOperand2(),

View File

@ -1870,6 +1870,13 @@ Variable::Variable(const Token *name_, const std::string &clangType, const Token
++pos; ++pos;
} while (pos < clangType.size() && clangType[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() Variable::~Variable()
@ -1900,6 +1907,13 @@ const Token * Variable::declEndToken() const
void Variable::evaluate(const Settings* settings) 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) if (!settings)
return; return;

View File

@ -199,6 +199,7 @@ class CPPCHECKLIB Variable {
fIsVolatile = (1 << 13), /** @brief volatile */ fIsVolatile = (1 << 13), /** @brief volatile */
fIsSmartPointer = (1 << 14),/** @brief std::shared_ptr|unique_ptr */ fIsSmartPointer = (1 << 14),/** @brief std::shared_ptr|unique_ptr */
fIsMaybeUnused = (1 << 15), /** @brief marked [[maybe_unused]] */ fIsMaybeUnused = (1 << 15), /** @brief marked [[maybe_unused]] */
fIsInit = (1 << 16), /** @brief Is variable initialized in declaration */
}; };
/** /**
@ -501,6 +502,14 @@ public:
return getFlag(fHasDefault); 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. * Get Type pointer of known type.
* @return pointer to type if known, NULL if not known * @return pointer to type if known, NULL if not known

View File

@ -612,11 +612,18 @@ public:
setFlag(fExternC, b); setFlag(fExternC, b);
} }
bool isSplittedVarDecl() const { bool isSplittedVarDeclComma() const {
return getFlag(fIsSplitVarDecl); return getFlag(fIsSplitVarDeclComma);
} }
void isSplittedVarDecl(bool b) { void isSplittedVarDeclComma(bool b) {
setFlag(fIsSplitVarDecl, b); setFlag(fIsSplitVarDeclComma, b);
}
bool isSplittedVarDeclEq() const {
return getFlag(fIsSplitVarDeclEq);
}
void isSplittedVarDeclEq(bool b) {
setFlag(fIsSplitVarDeclEq, b);
} }
bool isBitfield() const { bool isBitfield() const {
@ -1201,7 +1208,8 @@ private:
fIncompleteVar = (1 << 26), fIncompleteVar = (1 << 26),
fConstexpr = (1 << 27), fConstexpr = (1 << 27),
fExternC = (1 << 28), 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; Token::Type mTokType;

View File

@ -4974,8 +4974,10 @@ void Tokenizer::dump(std::ostream &out) const
} }
if (tok->isExpandedMacro()) if (tok->isExpandedMacro())
out << " isExpandedMacro=\"true\""; out << " isExpandedMacro=\"true\"";
if (tok->isSplittedVarDecl()) if (tok->isSplittedVarDeclComma())
out << " isSplittedVarDecl=\"true\""; out << " isSplittedVarDeclComma=\"true\"";
if (tok->isSplittedVarDeclEq())
out << " isSplittedVarDeclEq=\"true\"";
if (tok->link()) if (tok->link())
out << " link=\"" << tok->link() << '\"'; out << " link=\"" << tok->link() << '\"';
if (tok->varId() > 0) if (tok->varId() > 0)
@ -6859,7 +6861,7 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co
if (tok2->str() == ",") { if (tok2->str() == ",") {
tok2->str(";"); tok2->str(";");
tok2->isSplittedVarDecl(true); tok2->isSplittedVarDeclComma(true);
//TODO: should we have to add also template '<>' links? //TODO: should we have to add also template '<>' links?
TokenList::insertTokens(tok2, type0, typelen); TokenList::insertTokens(tok2, type0, typelen);
} }
@ -6883,11 +6885,12 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co
syntaxError(tok2); // invalid code syntaxError(tok2); // invalid code
TokenList::insertTokens(eq, varTok, 2); TokenList::insertTokens(eq, varTok, 2);
eq->str(";"); eq->str(";");
eq->isSplittedVarDeclEq(true);
// "= x, " => "= x; type " // "= x, " => "= x; type "
if (tok2->str() == ",") { if (tok2->str() == ",") {
tok2->str(";"); tok2->str(";");
tok2->isSplittedVarDecl(true); tok2->isSplittedVarDeclComma(true);
TokenList::insertTokens(tok2, type0, typelen); TokenList::insertTokens(tok2, type0, typelen);
} }
break; break;

View File

@ -5645,10 +5645,8 @@ static void valueFlowUninit(TokenList *tokenlist, SymbolDatabase * /*symbolDatab
// continue; // continue;
if (!Token::Match(vardecl, "%var% ;")) if (!Token::Match(vardecl, "%var% ;"))
continue; continue;
if (Token::Match(vardecl, "%varid% ; %varid% =", vardecl->varId()))
continue;
const Variable *var = vardecl->variable(); const Variable *var = vardecl->variable();
if (!var || var->nameToken() != vardecl) if (!var || var->nameToken() != vardecl || var->isInit())
continue; continue;
if ((!var->isPointer() && var->type() && var->type()->needInitialization != Type::NeedInitialization::True) || if ((!var->isPointer() && var->type() && var->type()->needInitialization != Type::NeedInitialization::True) ||
!var->isLocal() || var->isStatic() || var->isExtern() || var->isReference() || var->isThrow()) !var->isLocal() || var->isStatic() || var->isExtern() || var->isReference() || var->isThrow())