Fixed #8962 ("(debug) Unknown type 'T'" with template typename parame… (#1671)

* Fixed #8962 ("(debug) Unknown type 'T'" with template typename parameter)

Only simple one parameter template functions with one function parameter
are supported.

* Added TODO test case for FIXME.
This commit is contained in:
IOBYTE 2019-02-14 05:48:59 -05:00 committed by amai2012
parent e28367b268
commit 8bd5b3eccf
2 changed files with 197 additions and 1 deletions

View File

@ -28,6 +28,7 @@
#include <algorithm>
#include <cassert>
#include <iostream>
#include <map>
#include <stack>
#include <utility>
@ -649,6 +650,18 @@ bool TemplateSimplifier::getTemplateDeclarations()
void TemplateSimplifier::getTemplateInstantiations()
{
std::multimap<std::string, const TokenAndName *> functionNameMap;
for (const auto & decl : mTemplateDeclarations) {
if (decl.isFunction())
functionNameMap.insert(std::make_pair(decl.name, &decl));
}
for (const auto & decl : mTemplateForwardDeclarations) {
if (decl.isFunction())
functionNameMap.insert(std::make_pair(decl.name, &decl));
}
std::list<ScopeInfo2> scopeList;
const Token *skip = nullptr;
@ -683,7 +696,7 @@ void TemplateSimplifier::getTemplateInstantiations()
else if (!isUsing && tok2 && tok2->str() == ";")
tok = const_cast<Token *>(tok2);
}
} else if (Token::Match(tok->previous(), "(|{|}|;|=|>|<<|:|.|*|& %name% ::|<") ||
} else if (Token::Match(tok->previous(), "(|{|}|;|=|>|<<|:|.|*|& %name% ::|<|(") ||
Token::Match(tok->previous(), "%type% %name% ::|<") ||
Token::Match(tok->tokAt(-2), "[,:] private|protected|public %name% ::|<")) {
std::string scopeName = getScopeName(scopeList);
@ -695,6 +708,75 @@ void TemplateSimplifier::getTemplateInstantiations()
qualification += (qualification.empty() ? "" : " :: ") + tok->str();
tok = tok->tokAt(2);
}
// look for function instantiation with type deduction
// fixme: only single argument functions supported
if (tok->strAt(1) == "(") {
std::string fullName = qualification + (qualification.empty() ? "" : " :: ") + tok->str();
// get all declarations with this name
for (auto pos = functionNameMap.lower_bound(tok->str());
pos != functionNameMap.upper_bound(tok->str()); ++pos) {
// look for declaration with same qualification
if (pos->second->fullName == fullName) {
// make sure it is a single argument function
if (Token::Match(pos->second->token->tokAt(2), "typename|class %name% >") &&
Token::Match(pos->second->nameToken->tokAt(2), "const| %type% &| %name%| )") &&
Token::Match(tok->tokAt(2), "%num%|%str%|%char%|%bool% )")) {
tok->insertToken(">");
switch (tok->tokAt(3)->tokType()) {
case Token::eBoolean:
tok->insertToken("bool");
break;
case Token::eChar:
if (tok->tokAt(3)->isLong())
tok->insertToken("wchar_t");
else
tok->insertToken("char");
break;
case Token::eString:
tok->insertToken("*");
if (tok->tokAt(4)->isLong())
tok->insertToken("wchar_t");
else
tok->insertToken("char");
tok->insertToken("const");
break;
case Token::eNumber: {
MathLib::value num(tok->strAt(3));
if (num.isFloat()) {
// MathLib::getSuffix doesn't work for floating point numbers
char suffix = tok->strAt(3).back();
if (suffix == 'f' || suffix == 'F')
tok->insertToken("float");
else if (suffix == 'l' || suffix == 'L') {
tok->insertToken("double");
tok->insertToken("long");
} else
tok->insertToken("double");
} else if (num.isInt()) {
std::string suffix = MathLib::getSuffix(tok->strAt(3));
if (suffix.find("LL") != std::string::npos) {
tok->insertToken("long");
tok->insertToken("long");
} else if (suffix.find('L') != std::string::npos)
tok->insertToken("long");
else
tok->insertToken("int");
if (suffix.find('U') != std::string::npos)
tok->insertToken("unsigned");
}
break;
}
default:
break;
}
tok->insertToken("<");
break;
}
}
}
}
if (!Token::Match(tok, "%name% <") ||
Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast"))
continue;

View File

@ -179,6 +179,9 @@ private:
// Test TemplateSimplifier::instantiateMatch
TEST_CASE(instantiateMatch);
TEST_CASE(templateParameterWithoutName); // #8602 Template default parameter without name yields syntax error
TEST_CASE(templateTypeDeduction1); // #8962
TEST_CASE(templateTypeDeduction2);
}
std::string tok(const char code[], bool simplify = true, bool debugwarnings = false, Settings::PlatformType type = Settings::Native) {
@ -3106,6 +3109,117 @@ private:
" void g();\n"
"};n"));
}
void templateTypeDeduction1() { // #8962
const char code[] = "template<typename T>\n"
"void f(T n) { (void)n; }\n"
"static void func() {\n"
" f(0);\n"
" f(0u);\n"
" f(0U);\n"
" f(0l);\n"
" f(0L);\n"
" f(0ul);\n"
" f(0UL);\n"
" f(0ll);\n"
" f(0LL);\n"
" f(0ull);\n"
" f(0ULL);\n"
" f(0.0);\n"
" f(0.0f);\n"
" f(0.0F);\n"
" f(0.0l);\n"
" f(0.0L);\n"
" f('c');\n"
" f(L'c');\n"
" f(\"string\");\n"
" f(L\"string\");\n"
" f(true);\n"
" f(false);\n"
"}";
const char expected[] = "void f<int> ( int n ) ; "
"void f<unsignedint> ( unsigned int n ) ; "
"void f<long> ( long n ) ; "
"void f<unsignedlong> ( unsigned long n ) ; "
"void f<longlong> ( long long n ) ; "
"void f<unsignedlonglong> ( unsigned long long n ) ; "
"void f<double> ( double n ) ; "
"void f<float> ( float n ) ; "
"void f<longdouble> ( long double n ) ; "
"void f<char> ( char n ) ; "
"void f<wchar_t> ( wchar_t n ) ; "
"void f<constchar*> ( const char * n ) ; "
"void f<constwchar_t*> ( const wchar_t * n ) ; "
"void f<bool> ( bool n ) ; "
"static void func ( ) { "
"f<int> ( 0 ) ; "
"f<unsignedint> ( 0u ) ; "
"f<unsignedint> ( 0U ) ; "
"f<long> ( 0l ) ; "
"f<long> ( 0L ) ; "
"f<unsignedlong> ( 0ul ) ; "
"f<unsignedlong> ( 0UL ) ; "
"f<longlong> ( 0ll ) ; "
"f<longlong> ( 0LL ) ; "
"f<unsignedlonglong> ( 0ull ) ; "
"f<unsignedlonglong> ( 0ULL ) ; "
"f<double> ( 0.0 ) ; "
"f<float> ( 0.0f ) ; "
"f<float> ( 0.0F ) ; "
"f<longdouble> ( 0.0l ) ; "
"f<longdouble> ( 0.0L ) ; "
"f<char> ( 'c' ) ; "
"f<wchar_t> ( L'c' ) ; "
"f<constchar*> ( \"string\" ) ; "
"f<constwchar_t*> ( L\"string\" ) ; "
"f<bool> ( true ) ; "
"f<bool> ( false ) ; "
"} "
"void f<int> ( int n ) { ( void ) n ; } "
"void f<unsignedint> ( unsigned int n ) { ( void ) n ; } "
"void f<long> ( long n ) { ( void ) n ; } "
"void f<unsignedlong> ( unsigned long n ) { ( void ) n ; } "
"void f<longlong> ( long long n ) { ( void ) n ; } "
"void f<unsignedlonglong> ( unsigned long long n ) { ( void ) n ; } "
"void f<double> ( double n ) { ( void ) n ; } "
"void f<float> ( float n ) { ( void ) n ; } "
"void f<longdouble> ( long double n ) { ( void ) n ; } "
"void f<char> ( char n ) { ( void ) n ; } "
"void f<wchar_t> ( wchar_t n ) { ( void ) n ; } "
"void f<constchar*> ( const char * n ) { ( void ) n ; } "
"void f<constwchar_t*> ( const wchar_t * n ) { ( void ) n ; } "
"void f<bool> ( bool n ) { ( void ) n ; }";
ASSERT_EQUALS(expected, tok(code, false));
ASSERT_EQUALS("", errout.str());
}
void templateTypeDeduction2() {
const char code[] = "template<typename T, typename U>\n"
"void f(T t, U u) { }\n"
"static void func() {\n"
" f(0, 0.0);\n"
" f(0.0, 0);\n"
"}";
const char expected[] = "void f<int,double> ( int t , double u ) ; "
"void f<double,int> ( double t , int u ) ; "
"static void func ( ) { "
"f<int,double> ( 0 , 0.0 ) ; "
"f<double,int> ( 0.0, 0 ) ; "
"void f<int,double> ( int t , double u ) { } "
"void f<double,int> ( double t , int u ) { } ";
const char actual[] = "template < typename T , typename U > "
"void f ( T t , U u ) { } "
"static void func ( ) { "
"f ( 0 , 0.0 ) ; "
"f ( 0.0 , 0 ) ; "
"}";
TODO_ASSERT_EQUALS(expected, actual, tok(code, false));
}
};
REGISTER_TEST(TestSimplifyTemplate)