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;
// out of line function
if (Token::simpleMatch(end, ") ;")) {
if (Token::Match(end, ") const| &|&&| ;")) {
// find the function implementation later
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);
}
@ -575,6 +584,16 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
function.throwArg = end->tokAt(arg);
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 '{'
@ -670,7 +689,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
}
// has body?
if (Token::Match(scopeBegin, "{|:")) {
if (Token::Match(scopeBegin, "&|&&| {|:")) {
tok = funcStart;
// 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->next()->link()->strAt(1) == "{") ||
Token::Match(tok2, ": ::| %name% (|::|<|{") ||
Token::Match(tok2, "const| &|&&| ;|{") ||
Token::Match(tok2, "= delete|default ;") ||
Token::Match(tok2, "const| noexcept {|:|;|=") ||
(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)
{
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;
// skip class/struct name
if (destructor)
@ -1888,8 +1911,9 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To
// normal function?
if ((*tok)->next()->link()) {
const bool hasConstKeyword = (*tok)->next()->link()->next()->str() == "const";
if ((func->isConst() && hasConstKeyword) ||
(!func->isConst() && !hasConstKeyword)) {
if ((func->isConst() == hasConstKeyword) &&
(func->hasLvalRefQualifier() == lval) &&
(func->hasRvalRefQualifier() == rval)) {
func->hasBody(true);
}
}
@ -2303,6 +2327,8 @@ void SymbolDatabase::printOut(const char *title) const
std::cout << " isNoExcept: " << func->isNoExcept() << std::endl;
std::cout << " isThrow: " << func->isThrow() << 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:";
if (func->isAttributeConst())
std::cout << " const ";

View File

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

View File

@ -249,6 +249,7 @@ private:
TEST_CASE(findFunction5); // #6230
TEST_CASE(findFunction6);
TEST_CASE(findFunction7); // #6700
TEST_CASE(findFunction8);
TEST_CASE(noexceptFunction1);
TEST_CASE(noexceptFunction2);
@ -2606,6 +2607,83 @@ private:
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()); \