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;
|
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 ";
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()); \
|
||||||
|
|
Loading…
Reference in New Issue