* Fixed #8693 (Template specialization: Constructor detected as normal function (functionStatic error)) Refactor template simplifier to remove the existing full specialization function expandSpecialized and allow full specializations to use the existing function expandTemplate. The function expandTemplate was modified to either expand the template like it originally did by copying it or to modify the template in place. Both instantiated and uninstantiated full specializations are modified in place. This also fixes #8692 and probably other related tickets as well. The function simplifyTemplates now tries twice to simplify templates so more templates can be simplified. We should try as many times as necessary to find all possible templates. We can't do that now because uninstantiated templates are left unchanged. It is relatively straight forward to have the new code also expand in place uninstantiated templates with their symbolic types but namespaces are not handled properly (ticket #8671) and it would introduce regressions. * Fix travis warnings.
This commit is contained in:
parent
12c81ac0bf
commit
0a30768b59
|
@ -352,6 +352,20 @@ void TemplateSimplifier::eraseTokens(Token *begin, const Token *end)
|
||||||
it->token->hasTemplateSimplifierPointer(false);
|
it->token->hasTemplateSimplifierPointer(false);
|
||||||
it->token = nullptr;
|
it->token = nullptr;
|
||||||
}
|
}
|
||||||
|
const std::list<TokenAndName>::iterator it2 = std::find_if(mTemplateDeclarations.begin(),
|
||||||
|
mTemplateDeclarations.end(),
|
||||||
|
FindToken(begin->next()));
|
||||||
|
if (it2 != mTemplateDeclarations.end()) {
|
||||||
|
// remove the pointer flag and prevent the deleted pointer from being used
|
||||||
|
it2->token->hasTemplateSimplifierPointer(false);
|
||||||
|
it2->token = nullptr;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < mTypesUsedInTemplateInstantiation.size(); ++i) {
|
||||||
|
if (mTypesUsedInTemplateInstantiation[i] == begin->next()) {
|
||||||
|
mTypesUsedInTemplateInstantiation[i]->hasTemplateSimplifierPointer(false);
|
||||||
|
mTypesUsedInTemplateInstantiation[i] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
begin->deleteNext();
|
begin->deleteNext();
|
||||||
}
|
}
|
||||||
|
@ -377,20 +391,20 @@ bool TemplateSimplifier::removeTemplate(Token *tok)
|
||||||
if (tok2->str() == "(") {
|
if (tok2->str() == "(") {
|
||||||
tok2 = tok2->link();
|
tok2 = tok2->link();
|
||||||
} else if (tok2->str() == ")") { // garbage code! (#3504)
|
} else if (tok2->str() == ")") { // garbage code! (#3504)
|
||||||
Token::eraseTokens(tok,tok2);
|
eraseTokens(tok,tok2);
|
||||||
deleteToken(tok);
|
deleteToken(tok);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (tok2->str() == "{") {
|
else if (tok2->str() == "{") {
|
||||||
tok2 = tok2->link()->next();
|
tok2 = tok2->link()->next();
|
||||||
Token::eraseTokens(tok, tok2);
|
eraseTokens(tok, tok2);
|
||||||
if (tok2 && tok2->str() == ";" && tok2->next())
|
if (tok2 && tok2->str() == ";" && tok2->next())
|
||||||
tok->deleteNext();
|
deleteToken(tok->next());
|
||||||
deleteToken(tok);
|
deleteToken(tok);
|
||||||
return true;
|
return true;
|
||||||
} else if (tok2->str() == "}") { // garbage code! (#3449)
|
} else if (tok2->str() == "}") { // garbage code! (#3449)
|
||||||
Token::eraseTokens(tok,tok2);
|
eraseTokens(tok,tok2);
|
||||||
deleteToken(tok);
|
deleteToken(tok);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -403,14 +417,14 @@ bool TemplateSimplifier::removeTemplate(Token *tok)
|
||||||
if (tok2->str() == "explicit" ||
|
if (tok2->str() == "explicit" ||
|
||||||
(countgt == 1 && Token::Match(tok2->previous(), "> %type% (") &&
|
(countgt == 1 && Token::Match(tok2->previous(), "> %type% (") &&
|
||||||
Tokenizer::startOfExecutableScope(tok2->linkAt(1)))) {
|
Tokenizer::startOfExecutableScope(tok2->linkAt(1)))) {
|
||||||
Token::eraseTokens(tok, tok2);
|
eraseTokens(tok, tok2);
|
||||||
deleteToken(tok);
|
deleteToken(tok);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok2->str() == ";") {
|
if (tok2->str() == ";") {
|
||||||
tok2 = tok2->next();
|
tok2 = tok2->next();
|
||||||
Token::eraseTokens(tok, tok2);
|
eraseTokens(tok, tok2);
|
||||||
deleteToken(tok);
|
deleteToken(tok);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -423,7 +437,7 @@ bool TemplateSimplifier::removeTemplate(Token *tok)
|
||||||
|
|
||||||
else if (Token::Match(tok2, "> class|struct|union %name% [,)]")) {
|
else if (Token::Match(tok2, "> class|struct|union %name% [,)]")) {
|
||||||
tok2 = tok2->next();
|
tok2 = tok2->next();
|
||||||
Token::eraseTokens(tok, tok2);
|
eraseTokens(tok, tok2);
|
||||||
deleteToken(tok);
|
deleteToken(tok);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -432,64 +446,6 @@ bool TemplateSimplifier::removeTemplate(Token *tok)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::string> TemplateSimplifier::expandSpecialized()
|
|
||||||
{
|
|
||||||
std::set<std::string> expandedtemplates;
|
|
||||||
|
|
||||||
// Locate specialized templates..
|
|
||||||
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
|
|
||||||
if (!Token::simpleMatch(tok, "template < >"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// what kind of template is this?
|
|
||||||
Token *tok2 = tok->tokAt(3);
|
|
||||||
while (tok2 && (tok2->isName() || tok2->str() == "*"))
|
|
||||||
tok2 = tok2->next();
|
|
||||||
|
|
||||||
if (!templateParameters(tok2))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// unknown template.. bail out
|
|
||||||
if (!tok2->previous()->isName())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
tok2 = tok2->previous();
|
|
||||||
std::string s;
|
|
||||||
{
|
|
||||||
std::ostringstream ostr;
|
|
||||||
const Token *tok3 = tok2;
|
|
||||||
for (; tok3 && tok3->str() != ">"; tok3 = tok3->next()) {
|
|
||||||
if (tok3 != tok2)
|
|
||||||
ostr << " ";
|
|
||||||
ostr << tok3->str();
|
|
||||||
}
|
|
||||||
if (!Token::Match(tok3, "> (|{|:"))
|
|
||||||
continue;
|
|
||||||
s = ostr.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove spaces to create new name
|
|
||||||
const std::string name(s + " >");
|
|
||||||
expandedtemplates.insert(name);
|
|
||||||
|
|
||||||
// Rename template..
|
|
||||||
Token::eraseTokens(tok2, Token::findsimplematch(tok2, "<")->findClosingBracket()->next());
|
|
||||||
tok2->str(name);
|
|
||||||
|
|
||||||
// delete the "template < >"
|
|
||||||
tok->deleteNext(2);
|
|
||||||
tok->deleteThis();
|
|
||||||
|
|
||||||
// Use this special template in the code..
|
|
||||||
while (nullptr != (tok2 = const_cast<Token *>(Token::findsimplematch(tok2, name.c_str())))) {
|
|
||||||
Token::eraseTokens(tok2, Token::findsimplematch(tok2, "<")->findClosingBracket()->next());
|
|
||||||
tok2->str(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return expandedtemplates;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// TODO: This is copy pasted from Tokenizer. We should reuse this code.
|
/// TODO: This is copy pasted from Tokenizer. We should reuse this code.
|
||||||
namespace {
|
namespace {
|
||||||
struct ScopeInfo2 {
|
struct ScopeInfo2 {
|
||||||
|
@ -777,7 +733,15 @@ void TemplateSimplifier::useDefaultArgumentValues()
|
||||||
if (!tok2)
|
if (!tok2)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Token::eraseTokens(eqtok, tok2);
|
// don't strip args from uninstantiated templates
|
||||||
|
std::list<TokenAndName>::iterator ti2 = std::find_if(mTemplateInstantiations.begin(),
|
||||||
|
mTemplateInstantiations.end(),
|
||||||
|
FindName(template1.name));
|
||||||
|
|
||||||
|
if (ti2 == mTemplateInstantiations.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
eraseTokens(eqtok, tok2);
|
||||||
eqtok->deleteThis();
|
eqtok->deleteThis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -959,6 +923,9 @@ int TemplateSimplifier::getTemplateNamePosition(const Token *tok)
|
||||||
namepos = 2;
|
namepos = 2;
|
||||||
else if (Token::Match(tok, "> %type% *|&| %type% ("))
|
else if (Token::Match(tok, "> %type% *|&| %type% ("))
|
||||||
namepos = 2;
|
namepos = 2;
|
||||||
|
else if (Token::Match(tok, "> %type% %type% <") &&
|
||||||
|
Token::simpleMatch(tok->tokAt(3)->findClosingBracket(), "> ("))
|
||||||
|
namepos = 2;
|
||||||
else if (Token::Match(tok, "> %type% %type% *|&| %type% ("))
|
else if (Token::Match(tok, "> %type% %type% *|&| %type% ("))
|
||||||
namepos = 3;
|
namepos = 3;
|
||||||
else if (getTemplateNamePositionTemplateMember(tok, namepos))
|
else if (getTemplateNamePositionTemplateMember(tok, namepos))
|
||||||
|
@ -985,14 +952,14 @@ void TemplateSimplifier::expandTemplate(
|
||||||
const std::string &fullName,
|
const std::string &fullName,
|
||||||
const std::vector<const Token *> &typeParametersInDeclaration,
|
const std::vector<const Token *> &typeParametersInDeclaration,
|
||||||
const std::string &newName,
|
const std::string &newName,
|
||||||
const std::vector<const Token *> &typesUsedInTemplateInstantiation)
|
bool copy)
|
||||||
{
|
{
|
||||||
std::list<ScopeInfo2> scopeInfo;
|
std::list<ScopeInfo2> scopeInfo;
|
||||||
bool inTemplateDefinition = false;
|
bool inTemplateDefinition = false;
|
||||||
const Token *startOfTemplateDeclaration = nullptr;
|
const Token *startOfTemplateDeclaration = nullptr;
|
||||||
const Token *endOfTemplateDefinition = nullptr;
|
const Token *endOfTemplateDefinition = nullptr;
|
||||||
const Token * const templateDeclarationNameToken = templateDeclarationToken->tokAt(getTemplateNamePosition(templateDeclarationToken));
|
const Token * const templateDeclarationNameToken = templateDeclarationToken->tokAt(getTemplateNamePosition(templateDeclarationToken));
|
||||||
for (const Token *tok3 = mTokenList.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) {
|
for (Token *tok3 = mTokenList.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) {
|
||||||
if (Token::Match(tok3, "}|namespace|class|struct|union")) {
|
if (Token::Match(tok3, "}|namespace|class|struct|union")) {
|
||||||
setScopeInfo(tok3, &scopeInfo);
|
setScopeInfo(tok3, &scopeInfo);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1034,8 +1001,8 @@ void TemplateSimplifier::expandTemplate(
|
||||||
instantiateMatch(tok3, typeParametersInDeclaration.size(), ":: ~| %name% (")) {
|
instantiateMatch(tok3, typeParametersInDeclaration.size(), ":: ~| %name% (")) {
|
||||||
// there must be template..
|
// there must be template..
|
||||||
bool istemplate = false;
|
bool istemplate = false;
|
||||||
const Token * tok5 = nullptr; // start of function return type
|
Token * tok5 = nullptr; // start of function return type
|
||||||
for (const Token *prev = tok3; prev && !Token::Match(prev, "[;{}]"); prev = prev->previous()) {
|
for (Token *prev = tok3; prev && !Token::Match(prev, "[;{}]"); prev = prev->previous()) {
|
||||||
if (prev->str() == "template") {
|
if (prev->str() == "template") {
|
||||||
istemplate = true;
|
istemplate = true;
|
||||||
tok5 = prev;
|
tok5 = prev;
|
||||||
|
@ -1058,12 +1025,19 @@ void TemplateSimplifier::expandTemplate(
|
||||||
while (tok5 && tok5 != tok3) {
|
while (tok5 && tok5 != tok3) {
|
||||||
// replace name if found
|
// replace name if found
|
||||||
if (Token::Match(tok5, "%name% <") && tok5->str() == fullName) {
|
if (Token::Match(tok5, "%name% <") && tok5->str() == fullName) {
|
||||||
|
if (copy) {
|
||||||
mTokenList.addtoken(newName, tok5->linenr(), tok5->fileIndex());
|
mTokenList.addtoken(newName, tok5->linenr(), tok5->fileIndex());
|
||||||
tok5 = tok5->next()->findClosingBracket();
|
tok5 = tok5->next()->findClosingBracket();
|
||||||
} else
|
} else {
|
||||||
|
tok5->str(newName);
|
||||||
|
eraseTokens(tok5, tok5->next()->findClosingBracket()->next());
|
||||||
|
}
|
||||||
|
} else if (copy)
|
||||||
mTokenList.addtoken(tok5, tok5->linenr(), tok5->fileIndex());
|
mTokenList.addtoken(tok5, tok5->linenr(), tok5->fileIndex());
|
||||||
|
|
||||||
tok5 = tok5->next();
|
tok5 = tok5->next();
|
||||||
}
|
}
|
||||||
|
if (copy)
|
||||||
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
|
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
|
||||||
while (tok3 && tok3->str() != "::")
|
while (tok3 && tok3->str() != "::")
|
||||||
tok3 = tok3->next();
|
tok3 = tok3->next();
|
||||||
|
@ -1094,7 +1068,7 @@ void TemplateSimplifier::expandTemplate(
|
||||||
// replace type with given type..
|
// replace type with given type..
|
||||||
if (itype < typeParametersInDeclaration.size()) {
|
if (itype < typeParametersInDeclaration.size()) {
|
||||||
unsigned int typeindentlevel = 0;
|
unsigned int typeindentlevel = 0;
|
||||||
for (const Token *typetok = typesUsedInTemplateInstantiation[itype];
|
for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype];
|
||||||
typetok && (typeindentlevel>0 || !Token::Match(typetok, ",|>"));
|
typetok && (typeindentlevel>0 || !Token::Match(typetok, ",|>"));
|
||||||
typetok = typetok->next()) {
|
typetok = typetok->next()) {
|
||||||
if (Token::simpleMatch(typetok, ". . .")) {
|
if (Token::simpleMatch(typetok, ". . .")) {
|
||||||
|
@ -1105,9 +1079,11 @@ void TemplateSimplifier::expandTemplate(
|
||||||
++typeindentlevel;
|
++typeindentlevel;
|
||||||
else if (typeindentlevel > 0 && typetok->str() == ">")
|
else if (typeindentlevel > 0 && typetok->str() == ">")
|
||||||
--typeindentlevel;
|
--typeindentlevel;
|
||||||
|
if (copy) {
|
||||||
mTokenList.addtoken(typetok, tok3->linenr(), tok3->fileIndex());
|
mTokenList.addtoken(typetok, tok3->linenr(), tok3->fileIndex());
|
||||||
mTokenList.back()->isTemplateArg(true);
|
mTokenList.back()->isTemplateArg(true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1115,17 +1091,29 @@ void TemplateSimplifier::expandTemplate(
|
||||||
// replace name..
|
// replace name..
|
||||||
if (tok3->str() == lastName) {
|
if (tok3->str() == lastName) {
|
||||||
if (!Token::simpleMatch(tok3->next(), "<")) {
|
if (!Token::simpleMatch(tok3->next(), "<")) {
|
||||||
|
if (copy)
|
||||||
|
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
|
||||||
|
else if (tok3->strAt(1) != ":")
|
||||||
|
tok3->str(newName);
|
||||||
|
else
|
||||||
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
|
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
|
||||||
continue;
|
continue;
|
||||||
} else if (tok3 == templateDeclarationNameToken) {
|
} else if (tok3 == templateDeclarationNameToken) {
|
||||||
|
if (copy) {
|
||||||
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
|
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
|
||||||
tok3 = tok3->next()->findClosingBracket();
|
tok3 = tok3->next()->findClosingBracket();
|
||||||
|
} else {
|
||||||
|
tok3->str(newName);
|
||||||
|
eraseTokens(tok3, tok3->next()->findClosingBracket()->next());
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy
|
// copy
|
||||||
|
if (copy)
|
||||||
mTokenList.addtoken(tok3, tok3->linenr(), tok3->fileIndex());
|
mTokenList.addtoken(tok3, tok3->linenr(), tok3->fileIndex());
|
||||||
|
|
||||||
if (Token::Match(tok3, "%type% <") && Token::Match(tok3->next()->findClosingBracket(), ">|>>")) {
|
if (Token::Match(tok3, "%type% <") && Token::Match(tok3->next()->findClosingBracket(), ">|>>")) {
|
||||||
const Token *closingBracket = tok3->next()->findClosingBracket();
|
const Token *closingBracket = tok3->next()->findClosingBracket();
|
||||||
if (Token::simpleMatch(closingBracket->next(), "&")) {
|
if (Token::simpleMatch(closingBracket->next(), "&")) {
|
||||||
|
@ -1149,7 +1137,8 @@ void TemplateSimplifier::expandTemplate(
|
||||||
}
|
}
|
||||||
|
|
||||||
// link() newly tokens manually
|
// link() newly tokens manually
|
||||||
else if (tok3->str() == "{") {
|
else if (copy) {
|
||||||
|
if (tok3->str() == "{") {
|
||||||
brackets.push(mTokenList.back());
|
brackets.push(mTokenList.back());
|
||||||
} else if (tok3->str() == "(") {
|
} else if (tok3->str() == "(") {
|
||||||
brackets.push(mTokenList.back());
|
brackets.push(mTokenList.back());
|
||||||
|
@ -1177,6 +1166,7 @@ void TemplateSimplifier::expandTemplate(
|
||||||
brackets.pop();
|
brackets.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert(brackets.empty());
|
assert(brackets.empty());
|
||||||
}
|
}
|
||||||
|
@ -1541,6 +1531,52 @@ bool TemplateSimplifier::matchSpecialization(
|
||||||
return Token::Match(templateDeclarationNameToken, "%name% !!<");
|
return Token::Match(templateDeclarationNameToken, "%name% !!<");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string TemplateSimplifier::getNewName(
|
||||||
|
Token *tok2,
|
||||||
|
std::list<std::string> &typeStringsUsedInTemplateInstantiation)
|
||||||
|
{
|
||||||
|
std::string typeForNewName;
|
||||||
|
unsigned int indentlevel = 0;
|
||||||
|
for (Token *tok3 = tok2->tokAt(2); tok3 && (indentlevel > 0 || tok3->str() != ">"); tok3 = tok3->next()) {
|
||||||
|
// #2648 - unhandled parentheses => bail out
|
||||||
|
// #2721 - unhandled [ => bail out
|
||||||
|
if (Token::Match(tok3, "(|[")) {
|
||||||
|
typeForNewName.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!tok3->next()) {
|
||||||
|
typeForNewName.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (Token::Match(tok3->tokAt(-2), "<|,|:: %name% <") && templateParameters(tok3) > 0)
|
||||||
|
++indentlevel;
|
||||||
|
else if (indentlevel > 0 && Token::Match(tok3, "> [,>]"))
|
||||||
|
--indentlevel;
|
||||||
|
if (indentlevel == 0 && Token::Match(tok3->previous(), "[<,]")) {
|
||||||
|
tok3->hasTemplateSimplifierPointer(true);
|
||||||
|
mTypesUsedInTemplateInstantiation.push_back(tok3);
|
||||||
|
}
|
||||||
|
const bool constconst = tok3->str() == "const" && tok3->strAt(1) == "const";
|
||||||
|
if (!constconst) {
|
||||||
|
typeStringsUsedInTemplateInstantiation.push_back(tok3->str());
|
||||||
|
}
|
||||||
|
// add additional type information
|
||||||
|
if (!constconst && !Token::Match(tok3, "class|struct|enum")) {
|
||||||
|
if (tok3->isUnsigned())
|
||||||
|
typeForNewName += "unsigned";
|
||||||
|
else if (tok3->isSigned())
|
||||||
|
typeForNewName += "signed";
|
||||||
|
if (tok3->isLong())
|
||||||
|
typeForNewName += "long";
|
||||||
|
if (!typeForNewName.empty())
|
||||||
|
typeForNewName += ' ';
|
||||||
|
typeForNewName += tok3->str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeForNewName;
|
||||||
|
}
|
||||||
|
|
||||||
bool TemplateSimplifier::simplifyTemplateInstantiations(
|
bool TemplateSimplifier::simplifyTemplateInstantiations(
|
||||||
const TokenAndName &templateDeclaration,
|
const TokenAndName &templateDeclaration,
|
||||||
const std::list<const Token *> &specializations,
|
const std::list<const Token *> &specializations,
|
||||||
|
@ -1572,7 +1608,16 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool isfunc(tok->strAt(namepos + 1) == "(");
|
const bool specialized = Token::simpleMatch(templateDeclaration.token, "template < >");
|
||||||
|
bool isfunc = false;
|
||||||
|
|
||||||
|
if (tok->strAt(namepos + 1) == "(")
|
||||||
|
isfunc = true;
|
||||||
|
else if (tok->strAt(namepos + 1) == "<") {
|
||||||
|
const Token *tok1 = tok->tokAt(namepos + 1)->findClosingBracket();
|
||||||
|
if (tok1 && tok1->strAt(1) == "(")
|
||||||
|
isfunc = true;
|
||||||
|
}
|
||||||
|
|
||||||
// locate template usage..
|
// locate template usage..
|
||||||
std::string::size_type numberOfTemplateInstantiations = mTemplateInstantiations.size();
|
std::string::size_type numberOfTemplateInstantiations = mTemplateInstantiations.size();
|
||||||
|
@ -1613,54 +1658,28 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
|
||||||
assert(mTokenList.validateToken(tok2)); // that assertion fails on examples from #6021
|
assert(mTokenList.validateToken(tok2)); // that assertion fails on examples from #6021
|
||||||
|
|
||||||
const Token *startToken = tok2;
|
const Token *startToken = tok2;
|
||||||
while (Token::Match(startToken->tokAt(-2), "%name% :: %name%"))
|
while (Token::Match(startToken->tokAt(-2), "%name% :: %name%") ||
|
||||||
|
Token::Match(startToken->tokAt(-2), "> :: %name%")) {
|
||||||
|
if (startToken->strAt(-2) == ">") {
|
||||||
|
const Token * tok3 = startToken->tokAt(-2)->findOpeningBracket();
|
||||||
|
if (tok3)
|
||||||
|
startToken = tok3->previous();
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
} else
|
||||||
startToken = startToken->tokAt(-2);
|
startToken = startToken->tokAt(-2);
|
||||||
|
}
|
||||||
|
|
||||||
if (Token::Match(startToken->previous(), "[;{}=]") &&
|
if (Token::Match(startToken->previous(), "[;{}=]") &&
|
||||||
!instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %name%"))
|
(!specialized && !instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %name%")))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// New type..
|
// New type..
|
||||||
std::vector<const Token *> typesUsedInTemplateInstantiation;
|
mTypesUsedInTemplateInstantiation.clear();
|
||||||
std::string typeForNewName;
|
|
||||||
std::list<std::string> typeStringsUsedInTemplateInstantiation;
|
std::list<std::string> typeStringsUsedInTemplateInstantiation;
|
||||||
unsigned int indentlevel = 0;
|
std::string typeForNewName = getNewName(tok2, typeStringsUsedInTemplateInstantiation);
|
||||||
for (const Token *tok3 = tok2->tokAt(2); tok3 && (indentlevel > 0 || tok3->str() != ">"); tok3 = tok3->next()) {
|
|
||||||
// #2648 - unhandled parentheses => bail out
|
|
||||||
// #2721 - unhandled [ => bail out
|
|
||||||
if (Token::Match(tok3, "(|[")) {
|
|
||||||
typeForNewName.clear();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!tok3->next()) {
|
|
||||||
typeForNewName.clear();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (Token::Match(tok3->tokAt(-2), "<|,|:: %name% <") && templateParameters(tok3) > 0)
|
|
||||||
++indentlevel;
|
|
||||||
else if (indentlevel > 0 && Token::Match(tok3, "> [,>]"))
|
|
||||||
--indentlevel;
|
|
||||||
if (indentlevel == 0 && Token::Match(tok3->previous(), "[<,]"))
|
|
||||||
typesUsedInTemplateInstantiation.push_back(tok3);
|
|
||||||
const bool constconst = tok3->str() == "const" && tok3->strAt(1) == "const";
|
|
||||||
if (!constconst) {
|
|
||||||
typeStringsUsedInTemplateInstantiation.push_back(tok3->str());
|
|
||||||
}
|
|
||||||
// add additional type information
|
|
||||||
if (!constconst && !Token::Match(tok3, "class|struct|union|enum")) {
|
|
||||||
if (tok3->isUnsigned())
|
|
||||||
typeForNewName += "unsigned";
|
|
||||||
else if (tok3->isSigned())
|
|
||||||
typeForNewName += "signed";
|
|
||||||
if (tok3->isLong())
|
|
||||||
typeForNewName += "long";
|
|
||||||
if (!typeForNewName.empty())
|
|
||||||
typeForNewName += ' ';
|
|
||||||
typeForNewName += tok3->str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeForNewName.empty() || typeParametersInDeclaration.size() != typesUsedInTemplateInstantiation.size()) {
|
if (typeForNewName.empty() || (!typeParametersInDeclaration.empty() && typeParametersInDeclaration.size() != mTypesUsedInTemplateInstantiation.size())) {
|
||||||
if (printDebug && mErrorLogger) {
|
if (printDebug && mErrorLogger) {
|
||||||
std::list<const Token *> callstack(1, tok2);
|
std::list<const Token *> callstack(1, tok2);
|
||||||
mErrorLogger->reportErr(ErrorLogger::ErrorMessage(callstack, &mTokenList, Severity::debug, "debug",
|
mErrorLogger->reportErr(ErrorLogger::ErrorMessage(callstack, &mTokenList, Severity::debug, "debug",
|
||||||
|
@ -1676,12 +1695,89 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
|
||||||
|
|
||||||
if (expandedtemplates.find(newName) == expandedtemplates.end()) {
|
if (expandedtemplates.find(newName) == expandedtemplates.end()) {
|
||||||
expandedtemplates.insert(newName);
|
expandedtemplates.insert(newName);
|
||||||
expandTemplate(tok, instantiation.name, typeParametersInDeclaration, newName, typesUsedInTemplateInstantiation);
|
expandTemplate(tok, instantiation.name, typeParametersInDeclaration, newName, !specialized);
|
||||||
instantiated = true;
|
instantiated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace all these template usages..
|
// Replace all these template usages..
|
||||||
replaceTemplateUsage(tok2, instantiation.name, typeStringsUsedInTemplateInstantiation, newName, typesUsedInTemplateInstantiation);
|
replaceTemplateUsage(tok2, instantiation.name, typeStringsUsedInTemplateInstantiation, newName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// process uninstantiated templates
|
||||||
|
// TODO: remove the specialized check and handle all uninstantiated templates someday.
|
||||||
|
if (mTemplateInstantiations.empty() && specialized) {
|
||||||
|
simplifyCalculations();
|
||||||
|
|
||||||
|
Token * tok2 = const_cast<Token *>(tok->tokAt(namepos));
|
||||||
|
if (mErrorLogger && !mTokenList.getFiles().empty())
|
||||||
|
mErrorLogger->reportProgress(mTokenList.getFiles()[0], "TemplateSimplifier::simplifyTemplateInstantiations()", tok2->progressValue());
|
||||||
|
#ifdef MAXTIME
|
||||||
|
if (std::time(0) > maxtime)
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
(void)maxtime;
|
||||||
|
#endif
|
||||||
|
assert(mTokenList.validateToken(tok2)); // that assertion fails on examples from #6021
|
||||||
|
|
||||||
|
Token *startToken = tok2;
|
||||||
|
while (Token::Match(startToken->tokAt(-2), "%name% :: %name%") ||
|
||||||
|
Token::Match(startToken->tokAt(-2), "> :: %name%")) {
|
||||||
|
if (startToken->strAt(-2) == ">") {
|
||||||
|
const Token * tok3 = startToken->tokAt(-2)->findOpeningBracket();
|
||||||
|
if (tok3)
|
||||||
|
startToken = tok3->previous();
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
startToken = startToken->tokAt(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Token::Match(startToken->previous(), "[;{}=]") &&
|
||||||
|
(!specialized && !instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %name%")))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// already simplified
|
||||||
|
if (!Token::Match(startToken, "%name% <"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (templateDeclaration.scope.empty()) {
|
||||||
|
if (startToken->str() != templateDeclaration.name)
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
std::string name = templateDeclaration.scope + " :: " + startToken->str();
|
||||||
|
if (name != templateDeclaration.name)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matchSpecialization(tok->tokAt(namepos), startToken, specializations))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
tok2 = startToken;
|
||||||
|
|
||||||
|
// New type..
|
||||||
|
mTypesUsedInTemplateInstantiation.clear();
|
||||||
|
std::list<std::string> typeStringsUsedInTemplateInstantiation;
|
||||||
|
std::string typeForNewName = getNewName(tok2, typeStringsUsedInTemplateInstantiation);
|
||||||
|
|
||||||
|
if (typeForNewName.empty()) {
|
||||||
|
if (printDebug && mErrorLogger) {
|
||||||
|
std::list<const Token *> callstack(1, tok2);
|
||||||
|
mErrorLogger->reportErr(ErrorLogger::ErrorMessage(callstack, &mTokenList, Severity::debug, "debug",
|
||||||
|
"Failed to instantiate template \"" + templateDeclaration.name + "\". The checking continues anyway.", false));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// New classname/funcname..
|
||||||
|
const std::string newName(templateDeclaration.name + " < " + typeForNewName + " >");
|
||||||
|
if (expandedtemplates.find(newName) == expandedtemplates.end()) {
|
||||||
|
expandedtemplates.insert(newName);
|
||||||
|
expandTemplate(tok, templateDeclaration.name, typeParametersInDeclaration, newName, !specialized);
|
||||||
|
instantiated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace all these template usages..
|
||||||
|
replaceTemplateUsage(startToken, templateDeclaration.name, typeStringsUsedInTemplateInstantiation, newName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Template has been instantiated .. then remove the template declaration
|
// Template has been instantiated .. then remove the template declaration
|
||||||
|
@ -1702,8 +1798,7 @@ static bool matchTemplateParameters(const Token *nameTok, const std::list<std::s
|
||||||
void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
|
void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
|
||||||
const std::string &templateName,
|
const std::string &templateName,
|
||||||
const std::list<std::string> &typeStringsUsedInTemplateInstantiation,
|
const std::list<std::string> &typeStringsUsedInTemplateInstantiation,
|
||||||
const std::string &newName,
|
const std::string &newName)
|
||||||
const std::vector<const Token *> &typesUsedInTemplateInstantiation)
|
|
||||||
{
|
{
|
||||||
std::list<ScopeInfo2> scopeInfo;
|
std::list<ScopeInfo2> scopeInfo;
|
||||||
std::list< std::pair<Token *, Token *> > removeTokens;
|
std::list< std::pair<Token *, Token *> > removeTokens;
|
||||||
|
@ -1725,7 +1820,7 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
|
||||||
// match parameters
|
// match parameters
|
||||||
Token * tok2 = nameTok->tokAt(2);
|
Token * tok2 = nameTok->tokAt(2);
|
||||||
unsigned int typeCountInInstantiation = 1U; // There is always at least one type
|
unsigned int typeCountInInstantiation = 1U; // There is always at least one type
|
||||||
const Token *typetok = (!typesUsedInTemplateInstantiation.empty()) ? typesUsedInTemplateInstantiation[0] : nullptr;
|
const Token *typetok = (!mTypesUsedInTemplateInstantiation.empty()) ? mTypesUsedInTemplateInstantiation[0] : nullptr;
|
||||||
unsigned int indentlevel2 = 0; // indentlevel for tokgt
|
unsigned int indentlevel2 = 0; // indentlevel for tokgt
|
||||||
while (tok2 && (indentlevel2 > 0 || tok2->str() != ">")) {
|
while (tok2 && (indentlevel2 > 0 || tok2->str() != ">")) {
|
||||||
if (tok2->str() == "<" && templateParameters(tok2) > 0)
|
if (tok2->str() == "<" && templateParameters(tok2) > 0)
|
||||||
|
@ -1743,8 +1838,8 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
|
||||||
|
|
||||||
typetok = typetok->next();
|
typetok = typetok->next();
|
||||||
} else {
|
} else {
|
||||||
if (typeCountInInstantiation < typesUsedInTemplateInstantiation.size())
|
if (typeCountInInstantiation < mTypesUsedInTemplateInstantiation.size())
|
||||||
typetok = typesUsedInTemplateInstantiation[typeCountInInstantiation++];
|
typetok = mTypesUsedInTemplateInstantiation[typeCountInInstantiation++];
|
||||||
else
|
else
|
||||||
typetok = nullptr;
|
typetok = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -1757,7 +1852,7 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
|
||||||
|
|
||||||
// matching template usage => replace tokens..
|
// matching template usage => replace tokens..
|
||||||
// Foo < int > => Foo<int>
|
// Foo < int > => Foo<int>
|
||||||
if (tok2->str() == ">" && typeCountInInstantiation == typesUsedInTemplateInstantiation.size()) {
|
if (tok2->str() == ">" && typeCountInInstantiation == mTypesUsedInTemplateInstantiation.size()) {
|
||||||
const Token * const nameTok1 = nameTok;
|
const Token * const nameTok1 = nameTok;
|
||||||
while (Token::Match(nameTok->tokAt(-2), "%name% :: %name%"))
|
while (Token::Match(nameTok->tokAt(-2), "%name% :: %name%"))
|
||||||
nameTok = nameTok->tokAt(-2);
|
nameTok = nameTok->tokAt(-2);
|
||||||
|
@ -1794,7 +1889,7 @@ void TemplateSimplifier::simplifyTemplates(
|
||||||
bool &codeWithTemplates
|
bool &codeWithTemplates
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
std::set<std::string> expandedtemplates(expandSpecialized());
|
std::set<std::string> expandedtemplates;
|
||||||
|
|
||||||
if (getTemplateDeclarations(codeWithTemplates).empty())
|
if (getTemplateDeclarations(codeWithTemplates).empty())
|
||||||
return;
|
return;
|
||||||
|
@ -1813,25 +1908,31 @@ void TemplateSimplifier::simplifyTemplates(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// expand templates
|
||||||
|
// TODO: 2 is not the ideal number of loops.
|
||||||
|
// We should loop until the number of declarations is 0 but we can't
|
||||||
|
// do that until we instantiate unintstantiated templates with their symbolic types.
|
||||||
|
// That will allow the uninstantiated template code to be removed from the symbol database.
|
||||||
|
// Unfortunately the template simplifier doesn't handle namespaces properly so
|
||||||
|
// the uninstantiated template code in the symbol database can't be removed until #8768
|
||||||
|
// is fixed.
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
if (i) {
|
||||||
|
expandedtemplates.clear();
|
||||||
|
mTemplateInstantiations.clear();
|
||||||
|
mInstantiatedTemplates.clear();
|
||||||
|
}
|
||||||
|
|
||||||
mTemplateDeclarations = getTemplateDeclarations(codeWithTemplates);
|
mTemplateDeclarations = getTemplateDeclarations(codeWithTemplates);
|
||||||
|
|
||||||
// Locate possible instantiations of templates..
|
// Locate possible instantiations of templates..
|
||||||
getTemplateInstantiations();
|
getTemplateInstantiations();
|
||||||
|
|
||||||
// No template instantiations? Then return.
|
|
||||||
if (mTemplateInstantiations.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Template arguments with default values
|
// Template arguments with default values
|
||||||
useDefaultArgumentValues();
|
useDefaultArgumentValues();
|
||||||
|
|
||||||
simplifyTemplateAliases();
|
simplifyTemplateAliases();
|
||||||
|
|
||||||
// expand templates
|
|
||||||
//bool done = false;
|
|
||||||
//while (!done)
|
|
||||||
{
|
|
||||||
//done = true;
|
|
||||||
for (std::list<TokenAndName>::reverse_iterator iter1 = mTemplateDeclarations.rbegin(); iter1 != mTemplateDeclarations.rend(); ++iter1) {
|
for (std::list<TokenAndName>::reverse_iterator iter1 = mTemplateDeclarations.rbegin(); iter1 != mTemplateDeclarations.rend(); ++iter1) {
|
||||||
// get specializations..
|
// get specializations..
|
||||||
std::list<const Token *> specializations;
|
std::list<const Token *> specializations;
|
||||||
|
@ -1860,8 +1961,14 @@ void TemplateSimplifier::simplifyTemplates(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (decl != mTemplateDeclarations.end()) {
|
if (decl != mTemplateDeclarations.end()) {
|
||||||
mTemplateDeclarations.erase(decl);
|
if (Token::simpleMatch(it->token, "template < >")) {
|
||||||
|
// delete the "template < >"
|
||||||
|
Token * tok = it->token;
|
||||||
|
tok->deleteNext(2);
|
||||||
|
tok->deleteThis();
|
||||||
|
} else
|
||||||
removeTemplate(it->token);
|
removeTemplate(it->token);
|
||||||
|
mTemplateDeclarations.erase(decl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ public:
|
||||||
* @return true if modifications to token-list are done.
|
* @return true if modifications to token-list are done.
|
||||||
* false if no modifications are done.
|
* false if no modifications are done.
|
||||||
*/
|
*/
|
||||||
bool simplifyNumericCalculations(Token *tok);
|
static bool simplifyNumericCalculations(Token *tok);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simplify constant calculations such as "1+2" => "3".
|
* Simplify constant calculations such as "1+2" => "3".
|
||||||
|
@ -161,14 +161,14 @@ private:
|
||||||
* @param fullName Full name of template
|
* @param fullName Full name of template
|
||||||
* @param typeParametersInDeclaration The type parameters of the template
|
* @param typeParametersInDeclaration The type parameters of the template
|
||||||
* @param newName New name of class/function.
|
* @param newName New name of class/function.
|
||||||
* @param typesUsedInTemplateInstantiation Type parameters in instantiation
|
* @param copy copy or expand in place
|
||||||
*/
|
*/
|
||||||
void expandTemplate(
|
void expandTemplate(
|
||||||
const Token *templateDeclarationToken,
|
const Token *templateDeclarationToken,
|
||||||
const std::string &fullName,
|
const std::string &fullName,
|
||||||
const std::vector<const Token *> &typeParametersInDeclaration,
|
const std::vector<const Token *> &typeParametersInDeclaration,
|
||||||
const std::string &newName,
|
const std::string &newName,
|
||||||
const std::vector<const Token *> &typesUsedInTemplateInstantiation);
|
bool copy);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace all matching template usages 'Foo < int >' => 'Foo<int>'
|
* Replace all matching template usages 'Foo < int >' => 'Foo<int>'
|
||||||
|
@ -176,19 +176,11 @@ private:
|
||||||
* @param templateName full template name with scope info
|
* @param templateName full template name with scope info
|
||||||
* @param typeStringsUsedInTemplateInstantiation template parameters. list of token strings.
|
* @param typeStringsUsedInTemplateInstantiation template parameters. list of token strings.
|
||||||
* @param newName The new type name
|
* @param newName The new type name
|
||||||
* @param typesUsedInTemplateInstantiation template instantiation parameters
|
|
||||||
*/
|
*/
|
||||||
void replaceTemplateUsage(Token *const instantiationToken,
|
void replaceTemplateUsage(Token *const instantiationToken,
|
||||||
const std::string &templateName,
|
const std::string &templateName,
|
||||||
const std::list<std::string> &typeStringsUsedInTemplateInstantiation,
|
const std::list<std::string> &typeStringsUsedInTemplateInstantiation,
|
||||||
const std::string &newName,
|
const std::string &newName);
|
||||||
const std::vector<const Token *> &typesUsedInTemplateInstantiation);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expand specialized templates : "template<>.."
|
|
||||||
* @return names of expanded templates
|
|
||||||
*/
|
|
||||||
std::set<std::string> expandSpecialized();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief TemplateParametersInDeclaration
|
* @brief TemplateParametersInDeclaration
|
||||||
|
@ -199,7 +191,7 @@ private:
|
||||||
* @return template < typename T, typename S >
|
* @return template < typename T, typename S >
|
||||||
* ^ return
|
* ^ return
|
||||||
*/
|
*/
|
||||||
const Token * getTemplateParametersInDeclaration(
|
static const Token * getTemplateParametersInDeclaration(
|
||||||
const Token * tok,
|
const Token * tok,
|
||||||
std::vector<const Token *> & typeParametersInDeclaration);
|
std::vector<const Token *> & typeParametersInDeclaration);
|
||||||
|
|
||||||
|
@ -211,7 +203,7 @@ private:
|
||||||
/** Syntax error */
|
/** Syntax error */
|
||||||
static void syntaxError(const Token *tok);
|
static void syntaxError(const Token *tok);
|
||||||
|
|
||||||
bool matchSpecialization(
|
static bool matchSpecialization(
|
||||||
const Token *templateDeclarationNameToken,
|
const Token *templateDeclarationNameToken,
|
||||||
const Token *templateInstantiationNameToken,
|
const Token *templateInstantiationNameToken,
|
||||||
const std::list<const Token *> & specializations);
|
const std::list<const Token *> & specializations);
|
||||||
|
@ -228,7 +220,17 @@ private:
|
||||||
* tok will be invalidated.
|
* tok will be invalidated.
|
||||||
* @param tok token to delete
|
* @param tok token to delete
|
||||||
*/
|
*/
|
||||||
void deleteToken(Token *tok);
|
static void deleteToken(Token *tok);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the new token name.
|
||||||
|
* @param tok name token
|
||||||
|
* @param &typeStringsUsedInTemplateInstantiation type strings use in template instantiation
|
||||||
|
* @return new token name
|
||||||
|
*/
|
||||||
|
std::string getNewName(
|
||||||
|
Token *tok2,
|
||||||
|
std::list<std::string> &typeStringsUsedInTemplateInstantiation);
|
||||||
|
|
||||||
TokenList &mTokenList;
|
TokenList &mTokenList;
|
||||||
const Settings *mSettings;
|
const Settings *mSettings;
|
||||||
|
@ -238,6 +240,7 @@ private:
|
||||||
std::list<TokenAndName> mTemplateInstantiations;
|
std::list<TokenAndName> mTemplateInstantiations;
|
||||||
std::list<TokenAndName> mInstantiatedTemplates;
|
std::list<TokenAndName> mInstantiatedTemplates;
|
||||||
std::list<TokenAndName> mMemberFunctionsToDelete;
|
std::list<TokenAndName> mMemberFunctionsToDelete;
|
||||||
|
std::vector<Token *> mTypesUsedInTemplateInstantiation;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
|
@ -878,6 +878,38 @@ Token * Token::findClosingBracket()
|
||||||
return const_cast<Token*>(const_cast<const Token*>(this)->findClosingBracket());
|
return const_cast<Token*>(const_cast<const Token*>(this)->findClosingBracket());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Token * Token::findOpeningBracket() const
|
||||||
|
{
|
||||||
|
if (mStr != ">")
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
const Token *opening = nullptr;
|
||||||
|
|
||||||
|
unsigned int depth = 0;
|
||||||
|
for (opening = this; opening != nullptr; opening = opening->previous()) {
|
||||||
|
if (Token::Match(opening, "}|]|)")) {
|
||||||
|
opening = opening->link();
|
||||||
|
if (!opening)
|
||||||
|
return nullptr;
|
||||||
|
} else if (Token::Match(opening, "{|{|(|;"))
|
||||||
|
return nullptr;
|
||||||
|
else if (opening->str() == ">")
|
||||||
|
++depth;
|
||||||
|
else if (opening->str() == "<") {
|
||||||
|
if (--depth == 0)
|
||||||
|
return opening;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return opening;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token * Token::findOpeningBracket()
|
||||||
|
{
|
||||||
|
// return value of const function
|
||||||
|
return const_cast<Token*>(const_cast<const Token*>(this)->findOpeningBracket());
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
const Token *Token::findsimplematch(const Token * const startTok, const char pattern[])
|
const Token *Token::findsimplematch(const Token * const startTok, const char pattern[])
|
||||||
|
|
|
@ -812,6 +812,9 @@ public:
|
||||||
const Token* findClosingBracket() const;
|
const Token* findClosingBracket() const;
|
||||||
Token* findClosingBracket();
|
Token* findClosingBracket();
|
||||||
|
|
||||||
|
const Token* findOpeningBracket() const;
|
||||||
|
Token* findOpeningBracket();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the original name.
|
* @return the original name.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -171,6 +171,7 @@ private:
|
||||||
TEST_CASE(const62); // ticket #5701
|
TEST_CASE(const62); // ticket #5701
|
||||||
TEST_CASE(const63); // ticket #5983
|
TEST_CASE(const63); // ticket #5983
|
||||||
TEST_CASE(const64); // ticket #6268
|
TEST_CASE(const64); // ticket #6268
|
||||||
|
TEST_CASE(const65); // ticket #8693
|
||||||
TEST_CASE(const_handleDefaultParameters);
|
TEST_CASE(const_handleDefaultParameters);
|
||||||
TEST_CASE(const_passThisToMemberOfOtherClass);
|
TEST_CASE(const_passThisToMemberOfOtherClass);
|
||||||
TEST_CASE(assigningPointerToPointerIsNotAConstOperation);
|
TEST_CASE(assigningPointerToPointerIsNotAConstOperation);
|
||||||
|
@ -5444,6 +5445,25 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void const65() {
|
||||||
|
checkConst("template <typename T>\n"
|
||||||
|
"class TemplateClass {\n"
|
||||||
|
"public:\n"
|
||||||
|
" TemplateClass() { }\n"
|
||||||
|
"};\n"
|
||||||
|
"template <>\n"
|
||||||
|
"class TemplateClass<float> {\n"
|
||||||
|
"public:\n"
|
||||||
|
" TemplateClass() { }\n"
|
||||||
|
"};\n"
|
||||||
|
"int main() {\n"
|
||||||
|
" TemplateClass<int> a;\n"
|
||||||
|
" TemplateClass<float> b;\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void const_handleDefaultParameters() {
|
void const_handleDefaultParameters() {
|
||||||
checkConst("struct Foo {\n"
|
checkConst("struct Foo {\n"
|
||||||
" void foo1(int i, int j = 0) {\n"
|
" void foo1(int i, int j = 0) {\n"
|
||||||
|
|
|
@ -127,7 +127,9 @@ private:
|
||||||
|
|
||||||
TEST_CASE(templateNamePosition);
|
TEST_CASE(templateNamePosition);
|
||||||
|
|
||||||
TEST_CASE(expandSpecialized);
|
TEST_CASE(expandSpecialized1);
|
||||||
|
TEST_CASE(expandSpecialized2);
|
||||||
|
TEST_CASE(expandSpecialized3); // #8671
|
||||||
|
|
||||||
TEST_CASE(templateAlias1);
|
TEST_CASE(templateAlias1);
|
||||||
TEST_CASE(templateAlias2);
|
TEST_CASE(templateAlias2);
|
||||||
|
@ -1694,9 +1696,126 @@ private:
|
||||||
"template<> unsigned A<int, v<char> >::foo() { return 0; }", 30, /*onlyCreateTokens=*/true));
|
"template<> unsigned A<int, v<char> >::foo() { return 0; }", 30, /*onlyCreateTokens=*/true));
|
||||||
}
|
}
|
||||||
|
|
||||||
void expandSpecialized() {
|
void expandSpecialized1() {
|
||||||
ASSERT_EQUALS("class A<int> { } ;", tok("template<> class A<int> {};"));
|
ASSERT_EQUALS("class A<int> { } ;", tok("template<> class A<int> {};"));
|
||||||
ASSERT_EQUALS("class A<int> : public B { } ;", tok("template<> class A<int> : public B {};"));
|
ASSERT_EQUALS("class A<int> : public B { } ;", tok("template<> class A<int> : public B {};"));
|
||||||
|
ASSERT_EQUALS("class A<int> { A<int> ( ) ; ~ A<int> ( ) ; } ;", tok("template<> class A<int> { A(); ~A(); };"));
|
||||||
|
ASSERT_EQUALS("class A<int> { A<int> ( ) { } ~ A<int> ( ) { } } ;", tok("template<> class A<int> { A() {} ~A() {} };"));
|
||||||
|
ASSERT_EQUALS("class A<int> { A<int> ( ) ; ~ A<int> ( ) ; } ; A<int> :: A<int> ( ) { } ~ A<int> :: A<int> ( ) { }",
|
||||||
|
tok("template<> class A<int> { A(); ~A(); }; A<int>::A() { } ~A<int>::A() {}"));
|
||||||
|
ASSERT_EQUALS("class A<int> { A<int> ( ) ; A<int> ( const A<int> & ) ; A<int> foo ( ) ; } ; A<int> :: A<int> ( ) { } A<int> :: A<int> ( const A<int> & ) { } A<int> A<int> :: foo ( ) { A<int> a ; return a ; }",
|
||||||
|
tok("template<> class A<int> { A(); A(const A &) ; A foo(); }; A<int>::A() { } A<int>::A(const A &) { } A<int> A<int>::foo() { A a; return a; }"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void expandSpecialized2() {
|
||||||
|
{
|
||||||
|
const char code[] = "template <>\n"
|
||||||
|
"class C<float> {\n"
|
||||||
|
"public:\n"
|
||||||
|
" C() { }\n"
|
||||||
|
" C(const C &) { }\n"
|
||||||
|
" ~C() { }\n"
|
||||||
|
" C & operator=(const C &) { return *this; }\n"
|
||||||
|
"};\n"
|
||||||
|
"C<float> b;\n";
|
||||||
|
const char expected[] = "class C<float> { "
|
||||||
|
"public: "
|
||||||
|
"C<float> ( ) { } "
|
||||||
|
"C<float> ( const C<float> & ) { } "
|
||||||
|
"~ C<float> ( ) { } "
|
||||||
|
"C<float> & operator= ( const C<float> & ) { return * this ; } "
|
||||||
|
"} ; "
|
||||||
|
"C<float> b ;";
|
||||||
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const char code[] = "template <>\n"
|
||||||
|
"class C<float> {\n"
|
||||||
|
"public:\n"
|
||||||
|
" C() { }\n"
|
||||||
|
" C(const C &) { }\n"
|
||||||
|
" ~C() { }\n"
|
||||||
|
" C & operator=(const C &) { return *this; }\n"
|
||||||
|
"};";
|
||||||
|
const char expected[] = "class C<float> { "
|
||||||
|
"public: "
|
||||||
|
"C<float> ( ) { } "
|
||||||
|
"C<float> ( const C<float> & ) { } "
|
||||||
|
"~ C<float> ( ) { } "
|
||||||
|
"C<float> & operator= ( const C<float> & ) { return * this ; } "
|
||||||
|
"} ;";
|
||||||
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const char code[] = "template <>\n"
|
||||||
|
"class C<float> {\n"
|
||||||
|
"public:\n"
|
||||||
|
" C();\n"
|
||||||
|
" C(const C &);\n"
|
||||||
|
" ~C();\n"
|
||||||
|
" C & operator=(const C &);\n"
|
||||||
|
"};\n"
|
||||||
|
"C::C() { }\n"
|
||||||
|
"C::C(const C &) { }\n"
|
||||||
|
"C::~C() { }\n"
|
||||||
|
"C & C::operator=(const C &) { return *this; }\n"
|
||||||
|
"C<float> b;\n";
|
||||||
|
const char expected[] = "class C<float> { "
|
||||||
|
"public: "
|
||||||
|
"C<float> ( ) ; "
|
||||||
|
"C<float> ( const C<float> & ) ; "
|
||||||
|
"~ C<float> ( ) ; "
|
||||||
|
"C<float> & operator= ( const C<float> & ) ; "
|
||||||
|
"} ; "
|
||||||
|
"C<float> :: C<float> ( ) { } "
|
||||||
|
"C<float> :: C<float> ( const C<float> & ) { } "
|
||||||
|
"C<float> :: ~ C<float> ( ) { } "
|
||||||
|
"C<float> & C<float> :: operator= ( const C<float> & ) { return * this ; } "
|
||||||
|
"C<float> b ;";
|
||||||
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const char code[] = "template <>\n"
|
||||||
|
"class C<float> {\n"
|
||||||
|
"public:\n"
|
||||||
|
" C();\n"
|
||||||
|
" C(const C &);\n"
|
||||||
|
" ~C();\n"
|
||||||
|
" C & operator=(const C &);\n"
|
||||||
|
"};\n"
|
||||||
|
"C::C() { }\n"
|
||||||
|
"C::C(const C &) { }\n"
|
||||||
|
"C::~C() { }\n"
|
||||||
|
"C & C::operator=(const C &) { return *this; }";
|
||||||
|
const char expected[] = "class C<float> { "
|
||||||
|
"public: "
|
||||||
|
"C<float> ( ) ; "
|
||||||
|
"C<float> ( const C<float> & ) ; "
|
||||||
|
"~ C<float> ( ) ; "
|
||||||
|
"C<float> & operator= ( const C<float> & ) ; "
|
||||||
|
"} ; "
|
||||||
|
"C<float> :: C<float> ( ) { } "
|
||||||
|
"C<float> :: C<float> ( const C<float> & ) { } "
|
||||||
|
"C<float> :: ~ C<float> ( ) { } "
|
||||||
|
"C<float> & C<float> :: operator= ( const C<float> & ) { return * this ; }";
|
||||||
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void expandSpecialized3() { // #8671
|
||||||
|
const char code[] = "template <> struct OutputU16<unsigned char> final {\n"
|
||||||
|
" explicit OutputU16(std::basic_ostream<unsigned char> &t) : outputStream_(t) {}\n"
|
||||||
|
" void operator()(unsigned short) const;\n"
|
||||||
|
"private:\n"
|
||||||
|
" std::basic_ostream<unsigned char> &outputStream_;\n"
|
||||||
|
"};";
|
||||||
|
const char expected[] = "struct OutputU16<unsignedchar> final { "
|
||||||
|
"explicit OutputU16<unsignedchar> ( std :: basic_ostream < char > & t ) : outputStream_ ( t ) { } "
|
||||||
|
"void operator() ( short ) const ; "
|
||||||
|
"private: "
|
||||||
|
"std :: basic_ostream < char > & outputStream_ ; "
|
||||||
|
"} ;";
|
||||||
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
void templateAlias1() {
|
void templateAlias1() {
|
||||||
|
|
Loading…
Reference in New Issue