From a62c932a8f646d85eaf951f891ef5e6b43f9f637 Mon Sep 17 00:00:00 2001 From: IOBYTE Date: Wed, 4 Apr 2018 14:44:01 -0400 Subject: [PATCH] Improve findFunction for function calls with function calls as arguments. (#1147) Duplicate the existing logic for variable to variable type comparisons for function return type to variable type comparisons. --- lib/symboldatabase.cpp | 28 +++++++++++++- test/testsymboldatabase.cpp | 77 +++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 2813c750b..a040601cb 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -4224,7 +4224,33 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const while (argtok->astParent() && argtok->astParent() != tok->next() && argtok->astParent()->str() != ",") { argtok = argtok->astParent(); } - if (argtok && argtok->valueType() && !funcarg->isArrayOrPointer()) { // TODO: Pointers + if (argtok && argtok->valueType() && argtok->previous()->function() && argtok->previous()->function()->retDef) { + const ValueType* valuetype = argtok->valueType(); + const Function* argfunc = argtok->previous()->function(); + const bool isArrayOrPointer = valuetype->pointer; + const bool ptrequals = isArrayOrPointer == funcarg->isArrayOrPointer(); + const bool constEquals = !isArrayOrPointer || ((argfunc->retDef->strAt(-1) == "const") == (funcarg->typeStartToken()->strAt(-1) == "const")); + if (ptrequals && constEquals && + argfunc->retDef->str() == funcarg->typeStartToken()->str() && + argfunc->retDef->isUnsigned() == funcarg->typeStartToken()->isUnsigned() && + argfunc->retDef->isLong() == funcarg->typeStartToken()->isLong()) { + same++; + } else if (isArrayOrPointer) { + if (ptrequals && constEquals && funcarg->typeStartToken()->str() == "void") + fallback1++; + else if (constEquals && funcarg->isStlStringType() && Token::Match(argfunc->retDef, "char|wchar_t")) + fallback2++; + } else if (ptrequals) { + const bool takesInt = Token::Match(funcarg->typeStartToken(), "char|short|int|long"); + const bool takesFloat = Token::Match(funcarg->typeStartToken(), "float|double"); + const bool passesInt = Token::Match(argfunc->retDef, "char|short|int|long"); + const bool passesFloat = Token::Match(argfunc->retDef, "float|double"); + if ((takesInt && passesInt) || (takesFloat && passesFloat)) + fallback1++; + else if ((takesInt && passesFloat) || (takesFloat && passesInt)) + fallback2++; + } + } else if (argtok && argtok->valueType() && !funcarg->isArrayOrPointer()) { // TODO: Pointers if (argtok->valueType()->type == ValueType::BOOL) { if (funcarg->typeStartToken()->str() == "bool") same++; diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 0fd9f3754..efef3df51 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -305,6 +305,7 @@ private: TEST_CASE(findFunction16); TEST_CASE(findFunction17); TEST_CASE(findFunction18); + TEST_CASE(findFunction19); TEST_CASE(noexceptFunction1); TEST_CASE(noexceptFunction2); @@ -3938,6 +3939,82 @@ private: ASSERT_EQUALS(true, f && f->function() && f->function()->tokenDef->linenr() == 3); } + void findFunction19() { + GET_SYMBOL_DB("class Fred {\n" + " enum E1 { e1 };\n" + " enum class E2 : unsigned short { e2 };\n" + " bool get(bool x) { return x; }\n" + " char get(char x) { return x; }\n" + " short get(short x) { return x; }\n" + " int get(int x) { return x; }\n" + " long get(long x) { return x; }\n" + " long long get(long long x) { return x; }\n" + " unsigned char get(unsigned char x) { return x; }\n" + " unsigned short get(unsigned short x) { return x; }\n" + " unsigned int get(unsigned int x) { return x; }\n" + " unsigned long get(unsigned long x) { return x; }\n" + " unsigned long long get(unsigned long long x) { return x; }\n" + " E1 get(E1 x) { return x; }\n" + " E2 get(E2 x) { return x; }\n" + " void foo() {\n" + " bool v1 = true; v1 = get(get(v1));\n" + " char v2 = '1'; v2 = get(get(v2));\n" + " short v3 = 1; v3 = get(get(v3));\n" + " int v4 = 1; v4 = get(get(v4));\n" + " long v5 = 1; v5 = get(get(v5));\n" + " long long v6 = 1; v6 = get(get(v6));\n" + " unsigned char v7 = '1'; v7 = get(get(v7));\n" + " unsigned short v8 = 1; v8 = get(get(v8));\n" + " unsigned int v9 = 1; v9 = get(get(v9));\n" + " unsigned long v10 = 1; v10 = get(get(v10));\n" + " unsigned long long v11 = 1; v11 = get(get(v11));\n" + " E1 v12 = e1; v12 = get(get(v12));\n" + " E2 v13 = E2::e2; v13 = get(get(v13));\n" + " }\n" + "};"); + + ASSERT_EQUALS("", errout.str()); + + const Token *f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v1 ) ) ;"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4); + + f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v2 ) ) ;"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 5); + + f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v3 ) ) ;"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 6); + + f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v4 ) ) ;"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7); + + f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v5 ) ) ;"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 8); + + f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v6 ) ) ;"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 9); + + f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v7 ) ) ;"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 10); + + f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v8 ) ) ;"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 11); + + f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v9 ) ) ;"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 12); + + f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v10 ) ) ;"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 13); + + f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v11 ) ) ;"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 14); + + f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v12 ) ) ;"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 15); + + f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v13 ) ) ;"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 16); + } + #define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \ ASSERT_EQUALS(true, x != nullptr); \ if (x) ASSERT_EQUALS(true, x->isNoExcept());