Fixed #7195 (crash: valueFlowSwitchVariable())
This commit is contained in:
parent
599327bfb1
commit
db6dfa2d22
|
@ -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 ";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()); \
|
||||
|
|
Loading…
Reference in New Issue