Fixed #7195 (crash: valueFlowSwitchVariable())

This commit is contained in:
Robert Reif 2016-01-02 18:53:51 +01:00 committed by Daniel Marjamäki
parent 599327bfb1
commit db6dfa2d22
3 changed files with 137 additions and 19 deletions

View File

@ -443,9 +443,18 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
function.arg = function.argDef; function.arg = function.argDef;
// out of line function // out of line function
if (Token::simpleMatch(end, ") ;")) { if (Token::Match(end, ") const| &|&&| ;")) {
// find the function implementation later // find the function implementation later
tok = end->next(); tok = end->next();
if (tok->str() == "const")
tok = tok->next();
if (tok->str() == "&") {
function.hasLvalRefQualifier(true);
tok = tok->next();
} else if (tok->str() == "&&") {
function.hasRvalRefQualifier(true);
tok = tok->next();
}
scope->addFunction(function); scope->addFunction(function);
} }
@ -575,6 +584,16 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
function.throwArg = end->tokAt(arg); function.throwArg = end->tokAt(arg);
function.isThrow(true); function.isThrow(true);
} else if (Token::Match(end, ") const| &|&&|")) {
int arg = 1;
if (end->strAt(arg) == "const")
arg++;
if (end->strAt(arg) == "&")
function.hasLvalRefQualifier(true);
else if (end->strAt(arg) == "&&")
function.hasRvalRefQualifier(true);
} }
// find start of function '{' // find start of function '{'
@ -670,7 +689,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
} }
// has body? // has body?
if (Token::Match(scopeBegin, "{|:")) { if (Token::Match(scopeBegin, "&|&&| {|:")) {
tok = funcStart; tok = funcStart;
// class function // class function
@ -1388,6 +1407,7 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
(tok2->isUpperCaseName() && Token::Match(tok2, "%name% ;|{")) || (tok2->isUpperCaseName() && Token::Match(tok2, "%name% ;|{")) ||
(tok2->isUpperCaseName() && Token::Match(tok2, "%name% (") && tok2->next()->link()->strAt(1) == "{") || (tok2->isUpperCaseName() && Token::Match(tok2, "%name% (") && tok2->next()->link()->strAt(1) == "{") ||
Token::Match(tok2, ": ::| %name% (|::|<|{") || Token::Match(tok2, ": ::| %name% (|::|<|{") ||
Token::Match(tok2, "const| &|&&| ;|{") ||
Token::Match(tok2, "= delete|default ;") || Token::Match(tok2, "= delete|default ;") ||
Token::Match(tok2, "const| noexcept {|:|;|=") || Token::Match(tok2, "const| noexcept {|:|;|=") ||
(Token::Match(tok2, "const| noexcept|throw (") && (Token::Match(tok2, "const| noexcept|throw (") &&
@ -1763,6 +1783,9 @@ Function* SymbolDatabase::addGlobalFunctionDecl(Scope*& scope, const Token *tok,
void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const Token *argStart) void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const Token *argStart)
{ {
const bool destructor((*tok)->previous()->str() == "~"); const bool destructor((*tok)->previous()->str() == "~");
const bool has_const(argStart->link()->strAt(1) == "const");
const bool lval(argStart->link()->strAt(has_const ? 2 : 1) == "&");
const bool rval(argStart->link()->strAt(has_const ? 2 : 1) == "&&");
const Token *tok1; const Token *tok1;
// skip class/struct name // skip class/struct name
if (destructor) if (destructor)
@ -1888,8 +1911,9 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To
// normal function? // normal function?
if ((*tok)->next()->link()) { if ((*tok)->next()->link()) {
const bool hasConstKeyword = (*tok)->next()->link()->next()->str() == "const"; const bool hasConstKeyword = (*tok)->next()->link()->next()->str() == "const";
if ((func->isConst() && hasConstKeyword) || if ((func->isConst() == hasConstKeyword) &&
(!func->isConst() && !hasConstKeyword)) { (func->hasLvalRefQualifier() == lval) &&
(func->hasRvalRefQualifier() == rval)) {
func->hasBody(true); func->hasBody(true);
} }
} }
@ -2303,6 +2327,8 @@ void SymbolDatabase::printOut(const char *title) const
std::cout << " isNoExcept: " << func->isNoExcept() << std::endl; std::cout << " isNoExcept: " << func->isNoExcept() << std::endl;
std::cout << " isThrow: " << func->isThrow() << std::endl; std::cout << " isThrow: " << func->isThrow() << std::endl;
std::cout << " isOperator: " << func->isOperator() << std::endl; std::cout << " isOperator: " << func->isOperator() << std::endl;
std::cout << " hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl;
std::cout << " hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl;
std::cout << " attributes:"; std::cout << " attributes:";
if (func->isAttributeConst()) if (func->isAttributeConst())
std::cout << " const "; std::cout << " const ";

View File

@ -593,21 +593,23 @@ private:
class CPPCHECKLIB Function { class CPPCHECKLIB Function {
/** @brief flags mask used to access specific bit. */ /** @brief flags mask used to access specific bit. */
enum { enum {
fHasBody = (1 << 0), /** @brief has implementation */ fHasBody = (1 << 0), /** @brief has implementation */
fIsInline = (1 << 1), /** @brief implementation in class definition */ fIsInline = (1 << 1), /** @brief implementation in class definition */
fIsConst = (1 << 2), /** @brief is const */ fIsConst = (1 << 2), /** @brief is const */
fIsVirtual = (1 << 3), /** @brief is virtual */ fIsVirtual = (1 << 3), /** @brief is virtual */
fIsPure = (1 << 4), /** @brief is pure virtual */ fIsPure = (1 << 4), /** @brief is pure virtual */
fIsStatic = (1 << 5), /** @brief is static */ fIsStatic = (1 << 5), /** @brief is static */
fIsStaticLocal = (1 << 6), /** @brief is static local */ fIsStaticLocal = (1 << 6), /** @brief is static local */
fIsExtern = (1 << 7), /** @brief is extern */ fIsExtern = (1 << 7), /** @brief is extern */
fIsFriend = (1 << 8), /** @brief is friend */ fIsFriend = (1 << 8), /** @brief is friend */
fIsExplicit = (1 << 9), /** @brief is explicit */ fIsExplicit = (1 << 9), /** @brief is explicit */
fIsDefault = (1 << 10), /** @brief is default */ fIsDefault = (1 << 10), /** @brief is default */
fIsDelete = (1 << 11), /** @brief is delete */ fIsDelete = (1 << 11), /** @brief is delete */
fIsNoExcept = (1 << 12), /** @brief is noexcept */ fIsNoExcept = (1 << 12), /** @brief is noexcept */
fIsThrow = (1 << 13), /** @brief is throw */ fIsThrow = (1 << 13), /** @brief is throw */
fIsOperator = (1 << 14) /** @brief is operator */ fIsOperator = (1 << 14), /** @brief is operator */
fHasLvalRefQual = (1 << 15), /** @brief has & lvalue ref-qualifier */
fHasRvalRefQual = (1 << 16) /** @brief has && rvalue ref-qualifier */
}; };
/** /**
@ -739,6 +741,12 @@ public:
bool isOperator() const { bool isOperator() const {
return getFlag(fIsOperator); return getFlag(fIsOperator);
} }
bool hasLvalRefQualifier() const {
return getFlag(fHasLvalRefQual);
}
bool hasRvalRefQualifier() const {
return getFlag(fHasRvalRefQual);
}
void hasBody(bool state) { void hasBody(bool state) {
setFlag(fHasBody, state); setFlag(fHasBody, state);
@ -785,6 +793,12 @@ public:
void isOperator(bool state) { void isOperator(bool state) {
setFlag(fIsOperator, state); setFlag(fIsOperator, state);
} }
void hasLvalRefQualifier(bool state) {
setFlag(fHasLvalRefQual, state);
}
void hasRvalRefQualifier(bool state) {
setFlag(fHasRvalRefQual, state);
}
const Token *tokenDef; // function name token in class definition const Token *tokenDef; // function name token in class definition
const Token *argDef; // function argument start '(' in class definition const Token *argDef; // function argument start '(' in class definition

View File

@ -249,6 +249,7 @@ private:
TEST_CASE(findFunction5); // #6230 TEST_CASE(findFunction5); // #6230
TEST_CASE(findFunction6); TEST_CASE(findFunction6);
TEST_CASE(findFunction7); // #6700 TEST_CASE(findFunction7); // #6700
TEST_CASE(findFunction8);
TEST_CASE(noexceptFunction1); TEST_CASE(noexceptFunction1);
TEST_CASE(noexceptFunction2); TEST_CASE(noexceptFunction2);
@ -2606,6 +2607,83 @@ private:
ASSERT_EQUALS(true, callfunc && callfunc->tokAt(2)->function() && callfunc->tokAt(2)->function()->tokenDef->linenr() == 3); ASSERT_EQUALS(true, callfunc && callfunc->tokAt(2)->function() && callfunc->tokAt(2)->function()->tokenDef->linenr() == 3);
} }
void findFunction8() {
GET_SYMBOL_DB("struct S {\n"
" void f() { }\n"
" void f() & { }\n"
" void f() &&{ }\n"
" void f() const { }\n"
" void f() const & { }\n"
" void f() const &&{ }\n"
" void g() ;\n"
" void g() & ;\n"
" void g() &&;\n"
" void g() const ;\n"
" void g() const & ;\n"
" void g() const &&;\n"
"};\n"
"void S::g() { }\n"
"void S::g() & { }\n"
"void S::g() &&{ }\n"
"void S::g() const { }\n"
"void S::g() const & { }\n"
"void S::g() const &&{ }\n");
ASSERT_EQUALS("", errout.str());
const Token *f = Token::findsimplematch(tokenizer.tokens(), "f ( ) {");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2);
f = Token::findsimplematch(tokenizer.tokens(), "f ( ) & {");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3);
f = Token::findsimplematch(tokenizer.tokens(), "f ( ) && {");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4);
f = Token::findsimplematch(tokenizer.tokens(), "f ( ) const {");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 5);
f = Token::findsimplematch(tokenizer.tokens(), "f ( ) const & {");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 6);
f = Token::findsimplematch(tokenizer.tokens(), "f ( ) const && {");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7);
f = Token::findsimplematch(tokenizer.tokens(), "g ( ) {");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 8 && f->function()->token->linenr() == 15);
f = Token::findsimplematch(tokenizer.tokens(), "g ( ) & {");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 9 && f->function()->token->linenr() == 16);
f = Token::findsimplematch(tokenizer.tokens(), "g ( ) && {");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 10 && f->function()->token->linenr() == 17);
f = Token::findsimplematch(tokenizer.tokens(), "g ( ) const {");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 11 && f->function()->token->linenr() == 18);
f = Token::findsimplematch(tokenizer.tokens(), "g ( ) const & {");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 12 && f->function()->token->linenr() == 19);
f = Token::findsimplematch(tokenizer.tokens(), "g ( ) const && {");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 13 && f->function()->token->linenr() == 20);
f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) {");
ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 8 && f->tokAt(2)->function()->token->linenr() == 15);
f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) & {");
ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 9 && f->tokAt(2)->function()->token->linenr() == 16);
f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) && {");
ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 10 && f->tokAt(2)->function()->token->linenr() == 17);
f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) const {");
ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 11 && f->tokAt(2)->function()->token->linenr() == 18);
f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) const & {");
ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 12 && f->tokAt(2)->function()->token->linenr() == 19);
f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) const && {");
ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 13 && f->tokAt(2)->function()->token->linenr() == 20);
}
#define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \ #define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \