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(); elseif();
simplifyOverloadedOperators();
validate(); validate();
list.front()->assignIndexes(); 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.. // remove unnecessary member qualification..
void Tokenizer::removeUnnecessaryQualification() void Tokenizer::removeUnnecessaryQualification()
{ {

View File

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

View File

@ -378,6 +378,8 @@ private:
TEST_CASE(findFunctionExternC); TEST_CASE(findFunctionExternC);
TEST_CASE(findFunctionGlobalScope); // ::foo TEST_CASE(findFunctionGlobalScope); // ::foo
TEST_CASE(overloadedFunction1);
TEST_CASE(valueTypeMatchParameter); // ValueType::matchParameter TEST_CASE(valueTypeMatchParameter); // ValueType::matchParameter
TEST_CASE(noexceptFunction1); TEST_CASE(noexceptFunction1);
@ -6178,6 +6180,19 @@ private:
ASSERT(bar->function()); 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() { void valueTypeMatchParameter() {
ValueType vt_int(ValueType::Sign::SIGNED, ValueType::Type::INT, 0); ValueType vt_int(ValueType::Sign::SIGNED, ValueType::Type::INT, 0);
ValueType vt_const_int(ValueType::Sign::SIGNED, ValueType::Type::INT, 0, 1); ValueType vt_const_int(ValueType::Sign::SIGNED, ValueType::Type::INT, 0, 1);
@ -6291,16 +6306,11 @@ private:
" :a(std::move(b.a)) { }\n" " :a(std::move(b.a)) { }\n"
"};\n"); "};\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS(true, db != nullptr); // not null ASSERT(db != nullptr); // not null
if (db) {
const Scope *b = db->findScopeByName("B"); const Scope *b = db->findScopeByName("B");
ASSERT_EQUALS(true, b != nullptr); ASSERT(b != nullptr);
if (b) {
CLASS_FUNC(B, b, true); CLASS_FUNC(B, b, true);
} }
}
}
#define FUNC_THROW(x) do { \ #define FUNC_THROW(x) do { \
const Function *x = findFunctionByName(#x, &db->scopeList.front()); \ const Function *x = findFunctionByName(#x, &db->scopeList.front()); \
@ -6314,15 +6324,13 @@ private:
"void func3() throw(int);\n" "void func3() throw(int);\n"
"void func4() throw(int) { }\n"); "void func4() throw(int) { }\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS(true, db != nullptr); // not null ASSERT(db != nullptr); // not null
if (db) {
FUNC_THROW(func1); FUNC_THROW(func1);
FUNC_THROW(func2); FUNC_THROW(func2);
FUNC_THROW(func3); FUNC_THROW(func3);
FUNC_THROW(func4); FUNC_THROW(func4);
} }
}
#define CLASS_FUNC_THROW(x, y) do { \ #define CLASS_FUNC_THROW(x, y) do { \
const Function *x = findFunctionByName(#x, y); \ const Function *x = findFunctionByName(#x, y); \

View File

@ -416,6 +416,8 @@ private:
TEST_CASE(simplifyOperatorName26); TEST_CASE(simplifyOperatorName26);
TEST_CASE(simplifyOperatorName27); TEST_CASE(simplifyOperatorName27);
TEST_CASE(simplifyOverloadedOperators1);
TEST_CASE(simplifyNullArray); TEST_CASE(simplifyNullArray);
// Some simple cleanups of unhandled macros in the global scope // Some simple cleanups of unhandled macros in the global scope
@ -6636,6 +6638,20 @@ private:
tokenizeAndStringify(code)); 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() { void simplifyNullArray() {
ASSERT_EQUALS("* ( foo . bar [ 5 ] ) = x ;", tokenizeAndStringify("0[foo.bar[5]] = x;")); ASSERT_EQUALS("* ( foo . bar [ 5 ] ) = x ;", tokenizeAndStringify("0[foo.bar[5]] = x;"));
} }