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
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))

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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(),

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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())