* 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 = 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();
|
||||
}
|
||||
|
@ -377,20 +391,20 @@ bool TemplateSimplifier::removeTemplate(Token *tok)
|
|||
if (tok2->str() == "(") {
|
||||
tok2 = tok2->link();
|
||||
} else if (tok2->str() == ")") { // garbage code! (#3504)
|
||||
Token::eraseTokens(tok,tok2);
|
||||
eraseTokens(tok,tok2);
|
||||
deleteToken(tok);
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (tok2->str() == "{") {
|
||||
tok2 = tok2->link()->next();
|
||||
Token::eraseTokens(tok, tok2);
|
||||
eraseTokens(tok, tok2);
|
||||
if (tok2 && tok2->str() == ";" && tok2->next())
|
||||
tok->deleteNext();
|
||||
deleteToken(tok->next());
|
||||
deleteToken(tok);
|
||||
return true;
|
||||
} else if (tok2->str() == "}") { // garbage code! (#3449)
|
||||
Token::eraseTokens(tok,tok2);
|
||||
eraseTokens(tok,tok2);
|
||||
deleteToken(tok);
|
||||
return false;
|
||||
}
|
||||
|
@ -403,14 +417,14 @@ bool TemplateSimplifier::removeTemplate(Token *tok)
|
|||
if (tok2->str() == "explicit" ||
|
||||
(countgt == 1 && Token::Match(tok2->previous(), "> %type% (") &&
|
||||
Tokenizer::startOfExecutableScope(tok2->linkAt(1)))) {
|
||||
Token::eraseTokens(tok, tok2);
|
||||
eraseTokens(tok, tok2);
|
||||
deleteToken(tok);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tok2->str() == ";") {
|
||||
tok2 = tok2->next();
|
||||
Token::eraseTokens(tok, tok2);
|
||||
eraseTokens(tok, tok2);
|
||||
deleteToken(tok);
|
||||
return true;
|
||||
}
|
||||
|
@ -423,7 +437,7 @@ bool TemplateSimplifier::removeTemplate(Token *tok)
|
|||
|
||||
else if (Token::Match(tok2, "> class|struct|union %name% [,)]")) {
|
||||
tok2 = tok2->next();
|
||||
Token::eraseTokens(tok, tok2);
|
||||
eraseTokens(tok, tok2);
|
||||
deleteToken(tok);
|
||||
return true;
|
||||
}
|
||||
|
@ -432,64 +446,6 @@ bool TemplateSimplifier::removeTemplate(Token *tok)
|
|||
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.
|
||||
namespace {
|
||||
struct ScopeInfo2 {
|
||||
|
@ -777,7 +733,15 @@ void TemplateSimplifier::useDefaultArgumentValues()
|
|||
if (!tok2)
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -959,6 +923,9 @@ int TemplateSimplifier::getTemplateNamePosition(const Token *tok)
|
|||
namepos = 2;
|
||||
else if (Token::Match(tok, "> %type% *|&| %type% ("))
|
||||
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% ("))
|
||||
namepos = 3;
|
||||
else if (getTemplateNamePositionTemplateMember(tok, namepos))
|
||||
|
@ -985,14 +952,14 @@ void TemplateSimplifier::expandTemplate(
|
|||
const std::string &fullName,
|
||||
const std::vector<const Token *> &typeParametersInDeclaration,
|
||||
const std::string &newName,
|
||||
const std::vector<const Token *> &typesUsedInTemplateInstantiation)
|
||||
bool copy)
|
||||
{
|
||||
std::list<ScopeInfo2> scopeInfo;
|
||||
bool inTemplateDefinition = false;
|
||||
const Token *startOfTemplateDeclaration = nullptr;
|
||||
const Token *endOfTemplateDefinition = nullptr;
|
||||
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")) {
|
||||
setScopeInfo(tok3, &scopeInfo);
|
||||
continue;
|
||||
|
@ -1034,8 +1001,8 @@ void TemplateSimplifier::expandTemplate(
|
|||
instantiateMatch(tok3, typeParametersInDeclaration.size(), ":: ~| %name% (")) {
|
||||
// there must be template..
|
||||
bool istemplate = false;
|
||||
const Token * tok5 = nullptr; // start of function return type
|
||||
for (const Token *prev = tok3; prev && !Token::Match(prev, "[;{}]"); prev = prev->previous()) {
|
||||
Token * tok5 = nullptr; // start of function return type
|
||||
for (Token *prev = tok3; prev && !Token::Match(prev, "[;{}]"); prev = prev->previous()) {
|
||||
if (prev->str() == "template") {
|
||||
istemplate = true;
|
||||
tok5 = prev;
|
||||
|
@ -1058,13 +1025,20 @@ void TemplateSimplifier::expandTemplate(
|
|||
while (tok5 && tok5 != tok3) {
|
||||
// replace name if found
|
||||
if (Token::Match(tok5, "%name% <") && tok5->str() == fullName) {
|
||||
mTokenList.addtoken(newName, tok5->linenr(), tok5->fileIndex());
|
||||
tok5 = tok5->next()->findClosingBracket();
|
||||
} else
|
||||
if (copy) {
|
||||
mTokenList.addtoken(newName, tok5->linenr(), tok5->fileIndex());
|
||||
tok5 = tok5->next()->findClosingBracket();
|
||||
} else {
|
||||
tok5->str(newName);
|
||||
eraseTokens(tok5, tok5->next()->findClosingBracket()->next());
|
||||
}
|
||||
} else if (copy)
|
||||
mTokenList.addtoken(tok5, tok5->linenr(), tok5->fileIndex());
|
||||
|
||||
tok5 = tok5->next();
|
||||
}
|
||||
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
|
||||
if (copy)
|
||||
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
|
||||
while (tok3 && tok3->str() != "::")
|
||||
tok3 = tok3->next();
|
||||
|
||||
|
@ -1094,7 +1068,7 @@ void TemplateSimplifier::expandTemplate(
|
|||
// replace type with given type..
|
||||
if (itype < typeParametersInDeclaration.size()) {
|
||||
unsigned int typeindentlevel = 0;
|
||||
for (const Token *typetok = typesUsedInTemplateInstantiation[itype];
|
||||
for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype];
|
||||
typetok && (typeindentlevel>0 || !Token::Match(typetok, ",|>"));
|
||||
typetok = typetok->next()) {
|
||||
if (Token::simpleMatch(typetok, ". . .")) {
|
||||
|
@ -1105,8 +1079,10 @@ void TemplateSimplifier::expandTemplate(
|
|||
++typeindentlevel;
|
||||
else if (typeindentlevel > 0 && typetok->str() == ">")
|
||||
--typeindentlevel;
|
||||
mTokenList.addtoken(typetok, tok3->linenr(), tok3->fileIndex());
|
||||
mTokenList.back()->isTemplateArg(true);
|
||||
if (copy) {
|
||||
mTokenList.addtoken(typetok, tok3->linenr(), tok3->fileIndex());
|
||||
mTokenList.back()->isTemplateArg(true);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -1115,17 +1091,29 @@ void TemplateSimplifier::expandTemplate(
|
|||
// replace name..
|
||||
if (tok3->str() == lastName) {
|
||||
if (!Token::simpleMatch(tok3->next(), "<")) {
|
||||
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
|
||||
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());
|
||||
continue;
|
||||
} else if (tok3 == templateDeclarationNameToken) {
|
||||
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
|
||||
tok3 = tok3->next()->findClosingBracket();
|
||||
if (copy) {
|
||||
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
|
||||
tok3 = tok3->next()->findClosingBracket();
|
||||
} else {
|
||||
tok3->str(newName);
|
||||
eraseTokens(tok3, tok3->next()->findClosingBracket()->next());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// copy
|
||||
mTokenList.addtoken(tok3, tok3->linenr(), tok3->fileIndex());
|
||||
if (copy)
|
||||
mTokenList.addtoken(tok3, tok3->linenr(), tok3->fileIndex());
|
||||
|
||||
if (Token::Match(tok3, "%type% <") && Token::Match(tok3->next()->findClosingBracket(), ">|>>")) {
|
||||
const Token *closingBracket = tok3->next()->findClosingBracket();
|
||||
if (Token::simpleMatch(closingBracket->next(), "&")) {
|
||||
|
@ -1149,32 +1137,34 @@ void TemplateSimplifier::expandTemplate(
|
|||
}
|
||||
|
||||
// link() newly tokens manually
|
||||
else if (tok3->str() == "{") {
|
||||
brackets.push(mTokenList.back());
|
||||
} else if (tok3->str() == "(") {
|
||||
brackets.push(mTokenList.back());
|
||||
} else if (tok3->str() == "[") {
|
||||
brackets.push(mTokenList.back());
|
||||
} else if (tok3->str() == "}") {
|
||||
assert(brackets.empty() == false && brackets.top()->str() == "{");
|
||||
Token::createMutualLinks(brackets.top(), mTokenList.back());
|
||||
if (tok3->strAt(1) == ";") {
|
||||
const Token * tokSemicolon = tok3->next();
|
||||
mTokenList.addtoken(tokSemicolon, tokSemicolon->linenr(), tokSemicolon->fileIndex());
|
||||
else if (copy) {
|
||||
if (tok3->str() == "{") {
|
||||
brackets.push(mTokenList.back());
|
||||
} else if (tok3->str() == "(") {
|
||||
brackets.push(mTokenList.back());
|
||||
} else if (tok3->str() == "[") {
|
||||
brackets.push(mTokenList.back());
|
||||
} else if (tok3->str() == "}") {
|
||||
assert(brackets.empty() == false && brackets.top()->str() == "{");
|
||||
Token::createMutualLinks(brackets.top(), mTokenList.back());
|
||||
if (tok3->strAt(1) == ";") {
|
||||
const Token * tokSemicolon = tok3->next();
|
||||
mTokenList.addtoken(tokSemicolon, tokSemicolon->linenr(), tokSemicolon->fileIndex());
|
||||
}
|
||||
brackets.pop();
|
||||
if (brackets.empty()) {
|
||||
inTemplateDefinition = false;
|
||||
break;
|
||||
}
|
||||
} else if (tok3->str() == ")") {
|
||||
assert(brackets.empty() == false && brackets.top()->str() == "(");
|
||||
Token::createMutualLinks(brackets.top(), mTokenList.back());
|
||||
brackets.pop();
|
||||
} else if (tok3->str() == "]") {
|
||||
assert(brackets.empty() == false && brackets.top()->str() == "[");
|
||||
Token::createMutualLinks(brackets.top(), mTokenList.back());
|
||||
brackets.pop();
|
||||
}
|
||||
brackets.pop();
|
||||
if (brackets.empty()) {
|
||||
inTemplateDefinition = false;
|
||||
break;
|
||||
}
|
||||
} else if (tok3->str() == ")") {
|
||||
assert(brackets.empty() == false && brackets.top()->str() == "(");
|
||||
Token::createMutualLinks(brackets.top(), mTokenList.back());
|
||||
brackets.pop();
|
||||
} else if (tok3->str() == "]") {
|
||||
assert(brackets.empty() == false && brackets.top()->str() == "[");
|
||||
Token::createMutualLinks(brackets.top(), mTokenList.back());
|
||||
brackets.pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1541,6 +1531,52 @@ bool TemplateSimplifier::matchSpecialization(
|
|||
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(
|
||||
const TokenAndName &templateDeclaration,
|
||||
const std::list<const Token *> &specializations,
|
||||
|
@ -1572,7 +1608,16 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
|
|||
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..
|
||||
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
|
||||
|
||||
const Token *startToken = tok2;
|
||||
while (Token::Match(startToken->tokAt(-2), "%name% :: %name%"))
|
||||
startToken = startToken->tokAt(-2);
|
||||
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(), "[;{}=]") &&
|
||||
!instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %name%"))
|
||||
(!specialized && !instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %name%")))
|
||||
continue;
|
||||
|
||||
// New type..
|
||||
std::vector<const Token *> typesUsedInTemplateInstantiation;
|
||||
std::string typeForNewName;
|
||||
mTypesUsedInTemplateInstantiation.clear();
|
||||
std::list<std::string> typeStringsUsedInTemplateInstantiation;
|
||||
unsigned int indentlevel = 0;
|
||||
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();
|
||||
}
|
||||
}
|
||||
std::string typeForNewName = getNewName(tok2, typeStringsUsedInTemplateInstantiation);
|
||||
|
||||
if (typeForNewName.empty() || typeParametersInDeclaration.size() != typesUsedInTemplateInstantiation.size()) {
|
||||
if (typeForNewName.empty() || (!typeParametersInDeclaration.empty() && typeParametersInDeclaration.size() != mTypesUsedInTemplateInstantiation.size())) {
|
||||
if (printDebug && mErrorLogger) {
|
||||
std::list<const Token *> callstack(1, tok2);
|
||||
mErrorLogger->reportErr(ErrorLogger::ErrorMessage(callstack, &mTokenList, Severity::debug, "debug",
|
||||
|
@ -1676,12 +1695,89 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
|
|||
|
||||
if (expandedtemplates.find(newName) == expandedtemplates.end()) {
|
||||
expandedtemplates.insert(newName);
|
||||
expandTemplate(tok, instantiation.name, typeParametersInDeclaration, newName, typesUsedInTemplateInstantiation);
|
||||
expandTemplate(tok, instantiation.name, typeParametersInDeclaration, newName, !specialized);
|
||||
instantiated = true;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -1702,8 +1798,7 @@ static bool matchTemplateParameters(const Token *nameTok, const std::list<std::s
|
|||
void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
|
||||
const std::string &templateName,
|
||||
const std::list<std::string> &typeStringsUsedInTemplateInstantiation,
|
||||
const std::string &newName,
|
||||
const std::vector<const Token *> &typesUsedInTemplateInstantiation)
|
||||
const std::string &newName)
|
||||
{
|
||||
std::list<ScopeInfo2> scopeInfo;
|
||||
std::list< std::pair<Token *, Token *> > removeTokens;
|
||||
|
@ -1725,7 +1820,7 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
|
|||
// match parameters
|
||||
Token * tok2 = nameTok->tokAt(2);
|
||||
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
|
||||
while (tok2 && (indentlevel2 > 0 || tok2->str() != ">")) {
|
||||
if (tok2->str() == "<" && templateParameters(tok2) > 0)
|
||||
|
@ -1743,8 +1838,8 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
|
|||
|
||||
typetok = typetok->next();
|
||||
} else {
|
||||
if (typeCountInInstantiation < typesUsedInTemplateInstantiation.size())
|
||||
typetok = typesUsedInTemplateInstantiation[typeCountInInstantiation++];
|
||||
if (typeCountInInstantiation < mTypesUsedInTemplateInstantiation.size())
|
||||
typetok = mTypesUsedInTemplateInstantiation[typeCountInInstantiation++];
|
||||
else
|
||||
typetok = nullptr;
|
||||
}
|
||||
|
@ -1757,7 +1852,7 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
|
|||
|
||||
// matching template usage => replace tokens..
|
||||
// Foo < int > => Foo<int>
|
||||
if (tok2->str() == ">" && typeCountInInstantiation == typesUsedInTemplateInstantiation.size()) {
|
||||
if (tok2->str() == ">" && typeCountInInstantiation == mTypesUsedInTemplateInstantiation.size()) {
|
||||
const Token * const nameTok1 = nameTok;
|
||||
while (Token::Match(nameTok->tokAt(-2), "%name% :: %name%"))
|
||||
nameTok = nameTok->tokAt(-2);
|
||||
|
@ -1794,7 +1889,7 @@ void TemplateSimplifier::simplifyTemplates(
|
|||
bool &codeWithTemplates
|
||||
)
|
||||
{
|
||||
std::set<std::string> expandedtemplates(expandSpecialized());
|
||||
std::set<std::string> expandedtemplates;
|
||||
|
||||
if (getTemplateDeclarations(codeWithTemplates).empty())
|
||||
return;
|
||||
|
@ -1813,25 +1908,31 @@ void TemplateSimplifier::simplifyTemplates(
|
|||
}
|
||||
}
|
||||
|
||||
mTemplateDeclarations = getTemplateDeclarations(codeWithTemplates);
|
||||
|
||||
// Locate possible instantiations of templates..
|
||||
getTemplateInstantiations();
|
||||
|
||||
// No template instantiations? Then return.
|
||||
if (mTemplateInstantiations.empty())
|
||||
return;
|
||||
|
||||
// Template arguments with default values
|
||||
useDefaultArgumentValues();
|
||||
|
||||
simplifyTemplateAliases();
|
||||
|
||||
// expand templates
|
||||
//bool done = false;
|
||||
//while (!done)
|
||||
{
|
||||
//done = true;
|
||||
// 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);
|
||||
|
||||
// Locate possible instantiations of templates..
|
||||
getTemplateInstantiations();
|
||||
|
||||
// Template arguments with default values
|
||||
useDefaultArgumentValues();
|
||||
|
||||
simplifyTemplateAliases();
|
||||
|
||||
for (std::list<TokenAndName>::reverse_iterator iter1 = mTemplateDeclarations.rbegin(); iter1 != mTemplateDeclarations.rend(); ++iter1) {
|
||||
// get specializations..
|
||||
std::list<const Token *> specializations;
|
||||
|
@ -1860,8 +1961,14 @@ void TemplateSimplifier::simplifyTemplates(
|
|||
break;
|
||||
}
|
||||
if (decl != mTemplateDeclarations.end()) {
|
||||
if (Token::simpleMatch(it->token, "template < >")) {
|
||||
// delete the "template < >"
|
||||
Token * tok = it->token;
|
||||
tok->deleteNext(2);
|
||||
tok->deleteThis();
|
||||
} else
|
||||
removeTemplate(it->token);
|
||||
mTemplateDeclarations.erase(decl);
|
||||
removeTemplate(it->token);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ public:
|
|||
* @return true if modifications to token-list 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".
|
||||
|
@ -161,14 +161,14 @@ private:
|
|||
* @param fullName Full name of template
|
||||
* @param typeParametersInDeclaration The type parameters of the template
|
||||
* @param newName New name of class/function.
|
||||
* @param typesUsedInTemplateInstantiation Type parameters in instantiation
|
||||
* @param copy copy or expand in place
|
||||
*/
|
||||
void expandTemplate(
|
||||
const Token *templateDeclarationToken,
|
||||
const std::string &fullName,
|
||||
const std::vector<const Token *> &typeParametersInDeclaration,
|
||||
const std::string &newName,
|
||||
const std::vector<const Token *> &typesUsedInTemplateInstantiation);
|
||||
bool copy);
|
||||
|
||||
/**
|
||||
* Replace all matching template usages 'Foo < int >' => 'Foo<int>'
|
||||
|
@ -176,19 +176,11 @@ private:
|
|||
* @param templateName full template name with scope info
|
||||
* @param typeStringsUsedInTemplateInstantiation template parameters. list of token strings.
|
||||
* @param newName The new type name
|
||||
* @param typesUsedInTemplateInstantiation template instantiation parameters
|
||||
*/
|
||||
void replaceTemplateUsage(Token *const instantiationToken,
|
||||
const std::string &templateName,
|
||||
const std::list<std::string> &typeStringsUsedInTemplateInstantiation,
|
||||
const std::string &newName,
|
||||
const std::vector<const Token *> &typesUsedInTemplateInstantiation);
|
||||
|
||||
/**
|
||||
* Expand specialized templates : "template<>.."
|
||||
* @return names of expanded templates
|
||||
*/
|
||||
std::set<std::string> expandSpecialized();
|
||||
const std::string &newName);
|
||||
|
||||
/**
|
||||
* @brief TemplateParametersInDeclaration
|
||||
|
@ -199,7 +191,7 @@ private:
|
|||
* @return template < typename T, typename S >
|
||||
* ^ return
|
||||
*/
|
||||
const Token * getTemplateParametersInDeclaration(
|
||||
static const Token * getTemplateParametersInDeclaration(
|
||||
const Token * tok,
|
||||
std::vector<const Token *> & typeParametersInDeclaration);
|
||||
|
||||
|
@ -211,7 +203,7 @@ private:
|
|||
/** Syntax error */
|
||||
static void syntaxError(const Token *tok);
|
||||
|
||||
bool matchSpecialization(
|
||||
static bool matchSpecialization(
|
||||
const Token *templateDeclarationNameToken,
|
||||
const Token *templateInstantiationNameToken,
|
||||
const std::list<const Token *> & specializations);
|
||||
|
@ -228,7 +220,17 @@ private:
|
|||
* tok will be invalidated.
|
||||
* @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;
|
||||
const Settings *mSettings;
|
||||
|
@ -238,6 +240,7 @@ private:
|
|||
std::list<TokenAndName> mTemplateInstantiations;
|
||||
std::list<TokenAndName> mInstantiatedTemplates;
|
||||
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());
|
||||
}
|
||||
|
||||
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[])
|
||||
|
|
|
@ -812,6 +812,9 @@ public:
|
|||
const Token* findClosingBracket() const;
|
||||
Token* findClosingBracket();
|
||||
|
||||
const Token* findOpeningBracket() const;
|
||||
Token* findOpeningBracket();
|
||||
|
||||
/**
|
||||
* @return the original name.
|
||||
*/
|
||||
|
|
|
@ -171,6 +171,7 @@ private:
|
|||
TEST_CASE(const62); // ticket #5701
|
||||
TEST_CASE(const63); // ticket #5983
|
||||
TEST_CASE(const64); // ticket #6268
|
||||
TEST_CASE(const65); // ticket #8693
|
||||
TEST_CASE(const_handleDefaultParameters);
|
||||
TEST_CASE(const_passThisToMemberOfOtherClass);
|
||||
TEST_CASE(assigningPointerToPointerIsNotAConstOperation);
|
||||
|
@ -5444,6 +5445,25 @@ private:
|
|||
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() {
|
||||
checkConst("struct Foo {\n"
|
||||
" void foo1(int i, int j = 0) {\n"
|
||||
|
|
|
@ -127,7 +127,9 @@ private:
|
|||
|
||||
TEST_CASE(templateNamePosition);
|
||||
|
||||
TEST_CASE(expandSpecialized);
|
||||
TEST_CASE(expandSpecialized1);
|
||||
TEST_CASE(expandSpecialized2);
|
||||
TEST_CASE(expandSpecialized3); // #8671
|
||||
|
||||
TEST_CASE(templateAlias1);
|
||||
TEST_CASE(templateAlias2);
|
||||
|
@ -1100,7 +1102,7 @@ private:
|
|||
"struct Factorial<4> { enum FacHelper { value = 4 * Factorial<3> :: value } ; } ; "
|
||||
"struct Factorial<3> { enum FacHelper { value = 3 * Factorial<2> :: value } ; } ; "
|
||||
"struct Factorial<2> { enum FacHelper { value = 2 * Factorial<1> :: value } ; } ; "
|
||||
"struct Factorial<1> { enum FacHelper { value = Factorial < 0 > :: value } ; } ;";
|
||||
"struct Factorial<1> { enum FacHelper { value = Factorial<0> :: value } ; } ;";
|
||||
ASSERT_EQUALS(exp, tok(code));
|
||||
}
|
||||
|
||||
|
@ -1694,9 +1696,126 @@ private:
|
|||
"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> : 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() {
|
||||
|
|
Loading…
Reference in New Issue