Fix 11721: False positive: constParameterReference with overloaded template function (#5151)
This commit is contained in:
parent
7075b6e61d
commit
d6e3182441
|
@ -726,21 +726,28 @@ void TemplateSimplifier::addInstantiation(Token *token, const std::string &scope
|
|||
mTemplateInstantiations.emplace_back(std::move(instantiation));
|
||||
}
|
||||
|
||||
static void getFunctionArguments(const Token *nameToken, std::vector<const Token *> &args)
|
||||
static const Token* getFunctionToken(const Token* nameToken)
|
||||
{
|
||||
const Token *argToken;
|
||||
if (Token::Match(nameToken, "%name% ("))
|
||||
return nameToken->next();
|
||||
|
||||
if (nameToken->strAt(1) == "(")
|
||||
argToken = nameToken->tokAt(2);
|
||||
else if (nameToken->strAt(1) == "<") {
|
||||
const Token *end = nameToken->next()->findClosingBracket();
|
||||
if (end)
|
||||
argToken = end->tokAt(2);
|
||||
else
|
||||
return;
|
||||
} else
|
||||
if (Token::Match(nameToken, "%name% <")) {
|
||||
const Token* end = nameToken->next()->findClosingBracket();
|
||||
if (Token::simpleMatch(end, "> ("))
|
||||
return end->next();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void getFunctionArguments(const Token* nameToken, std::vector<const Token*>& args)
|
||||
{
|
||||
const Token* functionToken = getFunctionToken(nameToken);
|
||||
if (!functionToken)
|
||||
return;
|
||||
|
||||
const Token* argToken = functionToken->next();
|
||||
|
||||
if (argToken->str() == ")")
|
||||
return;
|
||||
|
||||
|
@ -750,6 +757,15 @@ static void getFunctionArguments(const Token *nameToken, std::vector<const Token
|
|||
args.push_back(argToken);
|
||||
}
|
||||
|
||||
static bool isConstMethod(const Token* nameToken)
|
||||
{
|
||||
const Token* functionToken = getFunctionToken(nameToken);
|
||||
if (!functionToken)
|
||||
return false;
|
||||
const Token* endToken = functionToken->link();
|
||||
return Token::simpleMatch(endToken, ") const");
|
||||
}
|
||||
|
||||
static bool areAllParamsTypes(const std::vector<const Token *> ¶ms)
|
||||
{
|
||||
if (params.empty())
|
||||
|
@ -3826,6 +3842,57 @@ void TemplateSimplifier::simplifyTemplates(
|
|||
if (mSettings.debugtemplate)
|
||||
printOut("### Template Simplifier pass " + std::to_string(passCount + 1) + " ###");
|
||||
|
||||
// Keep track of the order the names appear so sort can preserve that order
|
||||
std::unordered_map<std::string, int> nameOrdinal;
|
||||
int ordinal = 0;
|
||||
for (const auto& decl : mTemplateDeclarations) {
|
||||
nameOrdinal.emplace(decl.fullName(), ordinal++);
|
||||
}
|
||||
|
||||
auto score = [&](const Token* arg) {
|
||||
int i = 0;
|
||||
for (const Token* tok = arg; tok; tok = tok->next()) {
|
||||
if (tok->str() == ",")
|
||||
return i;
|
||||
else if (tok->link() && Token::Match(tok, "(|{|["))
|
||||
tok = tok->link();
|
||||
else if (tok->str() == "<") {
|
||||
const Token* temp = tok->findClosingBracket();
|
||||
if (temp)
|
||||
tok = temp;
|
||||
} else if (Token::Match(tok, ")|;"))
|
||||
return i;
|
||||
else if (Token::simpleMatch(tok, "const"))
|
||||
i--;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
// Sort so const parameters come first in the list
|
||||
mTemplateDeclarations.sort([&](const TokenAndName& x, const TokenAndName& y) {
|
||||
if (x.fullName() != y.fullName())
|
||||
return nameOrdinal.at(x.fullName()) < nameOrdinal.at(y.fullName());
|
||||
if (x.isFunction() && y.isFunction()) {
|
||||
std::vector<const Token*> xargs;
|
||||
getFunctionArguments(x.nameToken(), xargs);
|
||||
std::vector<const Token*> yargs;
|
||||
getFunctionArguments(y.nameToken(), yargs);
|
||||
if (xargs.size() != yargs.size())
|
||||
return xargs.size() < yargs.size();
|
||||
if (isConstMethod(x.nameToken()) != isConstMethod(y.nameToken()))
|
||||
return isConstMethod(x.nameToken());
|
||||
return std::lexicographical_compare(xargs.begin(),
|
||||
xargs.end(),
|
||||
yargs.begin(),
|
||||
yargs.end(),
|
||||
[&](const Token* xarg, const Token* yarg) {
|
||||
if (xarg != yarg)
|
||||
return score(xarg) < score(yarg);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
std::set<std::string> expandedtemplates;
|
||||
|
||||
for (std::list<TokenAndName>::const_reverse_iterator iter1 = mTemplateDeclarations.crbegin(); iter1 != mTemplateDeclarations.crend(); ++iter1) {
|
||||
|
|
|
@ -3219,6 +3219,37 @@ private:
|
|||
"[test.cpp:6]: (style) Parameter 'a' can be declared as pointer to const\n"
|
||||
"[test.cpp:9]: (style) Parameter 'a' can be declared as pointer to const\n",
|
||||
errout.str());
|
||||
|
||||
check("struct a {\n"
|
||||
" template <class T>\n"
|
||||
" void mutate();\n"
|
||||
"};\n"
|
||||
"struct b {};\n"
|
||||
"template <class T>\n"
|
||||
"void f(a& x) {\n"
|
||||
" x.mutate<T>();\n"
|
||||
"}\n"
|
||||
"template <class T>\n"
|
||||
"void f(const b&)\n"
|
||||
"{}\n"
|
||||
"void g(a& c) { f<int>(c); }\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("struct S {\n"
|
||||
" template <typename T>\n"
|
||||
" T* g() {\n"
|
||||
" return reinterpret_cast<T*>(m);\n"
|
||||
" }\n"
|
||||
" template <typename T>\n"
|
||||
" const T* g() const {\n"
|
||||
" return reinterpret_cast<const T*>(m);\n"
|
||||
" }\n"
|
||||
" char* m;\n"
|
||||
"};\n"
|
||||
"void f(S& s) {\n"
|
||||
" const int* p = s.g<int>();\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void constParameterCallback() {
|
||||
|
|
|
@ -4064,11 +4064,11 @@ private:
|
|||
" f<T>(0);\n"
|
||||
"}\n";
|
||||
const char exp2[] = "template < typename T > void f ( ) ; "
|
||||
"void f<int> ( int ) ; "
|
||||
"void f<char> ( int ) ; "
|
||||
"void f<int> ( int ) ; "
|
||||
"void g ( ) { f<int> ( ) ; f<char> ( 1 ) ; } "
|
||||
"void f<int> ( ) { f<int> ( 0 ) ; } "
|
||||
"void f<char> ( int ) { }";
|
||||
"void f<char> ( int ) { } "
|
||||
"void f<int> ( ) { f<int> ( 0 ) ; }";
|
||||
ASSERT_EQUALS(exp2, tok(code2));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue