Fixed #9266 (handle operator() better)

This commit is contained in:
Daniel Marjamäki 2020-09-06 21:02:06 +02:00
parent 4bf411d63d
commit 136ac2c643
4 changed files with 108 additions and 16 deletions

View File

@ -4723,6 +4723,8 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
elseif();
simplifyOverloadedOperators();
validate();
list.front()->assignIndexes();
@ -11210,6 +11212,69 @@ void Tokenizer::simplifyOperatorName()
}
}
void Tokenizer::simplifyOverloadedOperators()
{
if (isC())
return;
std::set<std::string> classNames;
std::set<nonneg int> classVars;
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (!tok->isName())
continue;
// Get classes that have operator() member
if (Token::Match(tok, "class|struct %name% [:{]")) {
int indent = 0;
for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
if (tok2->str() == "}")
break;
else if (indent == 0 && tok2->str() == ";")
break;
else if (tok2->str() == "{") {
if (indent == 0)
++indent;
else
tok2 = tok2->link();
} else if (indent == 1 && Token::simpleMatch(tok2, "operator() (") && isFunctionHead(tok2->next(), ";{")) {
classNames.insert(tok->strAt(1));
}
}
}
// Get variables that have operator() member
if (Token::Match(tok, "%type% &| %var%") && classNames.find(tok->str()) != classNames.end()) {
tok = tok->next();
while (!tok->isName())
tok = tok->next();
classVars.insert(tok->varId());
}
// Simplify operator() calls
if (Token::Match(tok, "%var% (") && classVars.find(tok->varId()) != classVars.end()) {
// constructor init list..
if (Token::Match(tok->previous(), "[:,]")) {
const Token *start = tok->previous();
while (Token::simpleMatch(start, ",")) {
if (Token::simpleMatch(start->previous(), ")"))
start = start->linkAt(-1);
if (Token::Match(start->previous(), "%name%"))
start = start->tokAt(-2);
}
const Token *after = tok->linkAt(1);
while (Token::Match(after, ")|} , %name% (|{"))
after = after->linkAt(3);
// Do not simplify initlist
if (Token::simpleMatch(start, ":") && Token::simpleMatch(after, ") {"))
continue;
}
tok->insertToken("operator()");
tok->insertToken(".");
}
}
}
// remove unnecessary member qualification..
void Tokenizer::removeUnnecessaryQualification()
{

View File

@ -743,6 +743,9 @@ private:
*/
void simplifyOperatorName();
/** simplify overloaded operators: 'obj(123)' => 'obj . operator() ( 123 )' */
void simplifyOverloadedOperators();
/**
* Remove [[attribute]] (C++11 and later) from TokenList
*/

View File

@ -378,6 +378,8 @@ private:
TEST_CASE(findFunctionExternC);
TEST_CASE(findFunctionGlobalScope); // ::foo
TEST_CASE(overloadedFunction1);
TEST_CASE(valueTypeMatchParameter); // ValueType::matchParameter
TEST_CASE(noexceptFunction1);
@ -6178,6 +6180,19 @@ private:
ASSERT(bar->function());
}
void overloadedFunction1() {
GET_SYMBOL_DB("struct S {\n"
" int operator()(int);\n"
"};\n"
"\n"
"void foo(S x) {\n"
" x(123);\n"
"}");
const Token *tok = Token::findsimplematch(tokenizer.tokens(), "x . operator() ( 123 )");
ASSERT(tok);
ASSERT(tok->tokAt(2)->function());
}
void valueTypeMatchParameter() {
ValueType vt_int(ValueType::Sign::SIGNED, ValueType::Type::INT, 0);
ValueType vt_const_int(ValueType::Sign::SIGNED, ValueType::Type::INT, 0, 1);
@ -6291,15 +6306,10 @@ private:
" :a(std::move(b.a)) { }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS(true, db != nullptr); // not null
if (db) {
const Scope *b = db->findScopeByName("B");
ASSERT_EQUALS(true, b != nullptr);
if (b) {
CLASS_FUNC(B, b, true);
}
}
ASSERT(db != nullptr); // not null
const Scope *b = db->findScopeByName("B");
ASSERT(b != nullptr);
CLASS_FUNC(B, b, true);
}
#define FUNC_THROW(x) do { \
@ -6314,14 +6324,12 @@ private:
"void func3() throw(int);\n"
"void func4() throw(int) { }\n");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS(true, db != nullptr); // not null
ASSERT(db != nullptr); // not null
if (db) {
FUNC_THROW(func1);
FUNC_THROW(func2);
FUNC_THROW(func3);
FUNC_THROW(func4);
}
FUNC_THROW(func1);
FUNC_THROW(func2);
FUNC_THROW(func3);
FUNC_THROW(func4);
}
#define CLASS_FUNC_THROW(x, y) do { \

View File

@ -416,6 +416,8 @@ private:
TEST_CASE(simplifyOperatorName26);
TEST_CASE(simplifyOperatorName27);
TEST_CASE(simplifyOverloadedOperators1);
TEST_CASE(simplifyNullArray);
// Some simple cleanups of unhandled macros in the global scope
@ -6636,6 +6638,20 @@ private:
tokenizeAndStringify(code));
}
void simplifyOverloadedOperators1() {
const char code[] = "struct S { void operator()(int); };\n"
"\n"
"void foo(S x) {\n"
" x(123);\n"
"}";
ASSERT_EQUALS("struct S { void operator() ( int ) ; } ;\n"
"\n"
"void foo ( S x ) {\n"
"x . operator() ( 123 ) ;\n"
"}",
tokenizeAndStringify(code));
}
void simplifyNullArray() {
ASSERT_EQUALS("* ( foo . bar [ 5 ] ) = x ;", tokenizeAndStringify("0[foo.bar[5]] = x;"));
}