Fixed #9266 (handle operator() better)
This commit is contained in:
parent
4bf411d63d
commit
136ac2c643
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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); \
|
||||||
|
|
|
@ -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;"));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue