This commit is contained in:
parent
8903f0e4b1
commit
c21166565f
|
@ -2633,6 +2633,7 @@ namespace { // avoid one-definition-rule violation
|
|||
|
||||
const Variable *var;
|
||||
const Token *tok;
|
||||
std::vector<const Variable*> initArgs;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -2663,25 +2664,38 @@ void CheckClass::initializerListOrder()
|
|||
tok = tok->next();
|
||||
|
||||
// find all variable initializations in list
|
||||
while (tok && tok != func->functionScope->bodyStart) {
|
||||
for (; tok && tok != func->functionScope->bodyStart; tok = tok->next()) {
|
||||
if (Token::Match(tok, "%name% (|{")) {
|
||||
const Variable *var = scope->getVariable(tok->str());
|
||||
if (var)
|
||||
vars.emplace_back(var, tok);
|
||||
else
|
||||
continue;
|
||||
|
||||
if (Token::Match(tok->tokAt(2), "%name% =")) {
|
||||
var = scope->getVariable(tok->strAt(2));
|
||||
|
||||
if (var)
|
||||
vars.emplace_back(var, tok->tokAt(2));
|
||||
const Token* const end = tok->next()->link();
|
||||
for (; tok != end; tok = tok->next()) {
|
||||
if (const Variable* argVar = scope->getVariable(tok->str())) {
|
||||
if (var->isPointer() && (argVar->isArray() || Token::simpleMatch(tok->astParent(), "&")))
|
||||
continue;
|
||||
if (var->isReference())
|
||||
continue;
|
||||
if (Token::simpleMatch(tok->astParent(), "="))
|
||||
continue;
|
||||
vars.back().initArgs.emplace_back(argVar);
|
||||
}
|
||||
}
|
||||
tok = tok->next()->link()->next();
|
||||
} else
|
||||
tok = tok->next();
|
||||
}
|
||||
}
|
||||
|
||||
// need at least 2 members to have out of order initialization
|
||||
for (int j = 1; j < vars.size(); j++) {
|
||||
for (int j = 0; j < vars.size(); j++) {
|
||||
// check for use of uninitialized arguments
|
||||
for (const auto& arg : vars[j].initArgs)
|
||||
if (vars[j].var->index() < arg->index())
|
||||
initializerListError(vars[j].tok, vars[j].var->nameToken(), scope->className, vars[j].var->name(), /*isArgument*/ true);
|
||||
|
||||
// need at least 2 members to have out of order initialization
|
||||
if (j == 0)
|
||||
continue;
|
||||
// check for out of order initialization
|
||||
if (vars[j].var->index() < vars[j - 1].var->index())
|
||||
initializerListError(vars[j].tok,vars[j].var->nameToken(), scope->className, vars[j].var->name());
|
||||
|
@ -2692,15 +2706,18 @@ void CheckClass::initializerListOrder()
|
|||
}
|
||||
}
|
||||
|
||||
void CheckClass::initializerListError(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &varname)
|
||||
void CheckClass::initializerListError(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &varname, bool isArgument)
|
||||
{
|
||||
std::list<const Token *> toks = { tok1, tok2 };
|
||||
const std::string msg = isArgument ?
|
||||
"Member variable '$symbol' uses an uninitialized argument due to the order of declarations." :
|
||||
"Member variable '$symbol' is in the wrong place in the initializer list.";
|
||||
reportError(toks, Severity::style, "initializerList",
|
||||
"$symbol:" + classname + "::" + varname +"\n"
|
||||
"Member variable '$symbol' is in the wrong place in the initializer list.\n"
|
||||
"Member variable '$symbol' is in the wrong place in the initializer list. "
|
||||
"$symbol:" + classname + "::" + varname + '\n' +
|
||||
msg + '\n' +
|
||||
msg + ' ' +
|
||||
"Members are initialized in the order they are declared, not in the "
|
||||
"order they are in the initializer list. Keeping the initializer list "
|
||||
"order they are in the initializer list. Keeping the initializer list "
|
||||
"in the same order that the members were declared prevents order dependent "
|
||||
"initialization errors.", CWE398, Certainty::inconclusive);
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ private:
|
|||
void operatorEqToSelfError(const Token *tok);
|
||||
void checkConstError(const Token *tok, const std::string &classname, const std::string &funcname, bool suggestStatic);
|
||||
void checkConstError2(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &funcname, bool suggestStatic);
|
||||
void initializerListError(const Token *tok1,const Token *tok2, const std::string & classname, const std::string &varname);
|
||||
void initializerListError(const Token *tok1,const Token *tok2, const std::string & classname, const std::string &varname, bool isArgument = false);
|
||||
void suggestInitializationList(const Token *tok, const std::string& varname);
|
||||
void selfInitializationError(const Token* tok, const std::string& varname);
|
||||
void pureVirtualFunctionCallInConstructorError(const Function * scopeFunction, const std::list<const Token *> & tokStack, const std::string &purefuncname);
|
||||
|
|
|
@ -215,6 +215,7 @@ private:
|
|||
TEST_CASE(qualifiedNameMember); // #10872
|
||||
|
||||
TEST_CASE(initializerListOrder);
|
||||
TEST_CASE(initializerListArgument);
|
||||
TEST_CASE(initializerListUsage);
|
||||
TEST_CASE(selfInitialization);
|
||||
|
||||
|
@ -7571,6 +7572,57 @@ private:
|
|||
"};");
|
||||
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:2]: (style, inconclusive) Member variable 'Fred::b' is in the wrong place in the initializer list.\n"
|
||||
"[test.cpp:4] -> [test.cpp:2]: (style, inconclusive) Member variable 'Fred::a' is in the wrong place in the initializer list.\n", errout.str());
|
||||
|
||||
checkInitializerListOrder("struct S {\n"
|
||||
" S() : b(a = 1) {}\n"
|
||||
" int a, b;\n"
|
||||
"};");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void initializerListArgument() {
|
||||
checkInitializerListOrder("struct A { A(); };\n" // #12322
|
||||
"struct B { explicit B(const A* a); };\n"
|
||||
"struct C {\n"
|
||||
" C() : b(&a) {}\n"
|
||||
" B b;\n"
|
||||
" const A a;\n"
|
||||
"};");
|
||||
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:5]: (style, inconclusive) Member variable 'C::b' uses an uninitialized argument due to the order of declarations.\n",
|
||||
errout.str());
|
||||
|
||||
checkInitializerListOrder("struct S {\n"
|
||||
" S(const std::string& f, std::string i, int b, int c) : a(0), b(b), c(c) {}\n"
|
||||
" int a, b, c;\n"
|
||||
"};");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
checkInitializerListOrder("struct S {\n"
|
||||
" S() : p(a) {}\n"
|
||||
" int* p;\n"
|
||||
" int a[1];\n"
|
||||
"};");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
checkInitializerListOrder("struct S {\n"
|
||||
" S() : p(&i) {}\n"
|
||||
" int* p;\n"
|
||||
" int i;\n"
|
||||
"};");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
checkInitializerListOrder("struct S {\n"
|
||||
" S() : a(b = 1) {}\n"
|
||||
" int a, b;\n"
|
||||
"};");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
checkInitializerListOrder("struct S {\n"
|
||||
" S() : r(i) {}\n"
|
||||
" int& r;\n"
|
||||
" int i{};\n"
|
||||
"};");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
#define checkInitializationListUsage(code) checkInitializationListUsage_(code, __FILE__, __LINE__)
|
||||
|
|
Loading…
Reference in New Issue