Tokenizer::simplifyTemplates: Broke out the functionality that instantiates a template
This commit is contained in:
parent
9021f0f180
commit
4d1aae5859
630
lib/tokenize.cpp
630
lib/tokenize.cpp
|
@ -2791,6 +2791,325 @@ void Tokenizer::simplifyTemplatesUseDefaultArgumentValues(const std::list<Token
|
|||
}
|
||||
}
|
||||
|
||||
void Tokenizer::simplifyTemplatesInstantiate(std::list<Token *> &used,
|
||||
const Token *tok,
|
||||
std::set<std::string> &expandedtemplates)
|
||||
{
|
||||
// this variable is not used at the moment. the intention was to
|
||||
// allow continous instantiations until all templates has been expanded
|
||||
bool done = false;
|
||||
|
||||
std::vector<const Token *> type;
|
||||
for (tok = tok->tokAt(2); tok && tok->str() != ">"; tok = tok->next())
|
||||
{
|
||||
if (Token::Match(tok, "%var% ,|>"))
|
||||
type.push_back(tok);
|
||||
}
|
||||
// bail out if the end of the file was reached
|
||||
if (!tok)
|
||||
return;
|
||||
|
||||
// get the position of the template name
|
||||
unsigned char namepos = 0;
|
||||
if (Token::Match(tok, "> class|struct %type% {|:"))
|
||||
namepos = 2;
|
||||
else if (Token::Match(tok, "> %type% *|&| %type% ("))
|
||||
namepos = 2;
|
||||
else if (Token::Match(tok, "> %type% %type% *|&| %type% ("))
|
||||
namepos = 3;
|
||||
else
|
||||
{
|
||||
// debug message that we bail out..
|
||||
if (_settings->debugwarnings)
|
||||
{
|
||||
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
||||
ErrorLogger::ErrorMessage::FileLocation loc;
|
||||
loc.line = tok->linenr();
|
||||
loc.setfile(file(tok));
|
||||
locationList.push_back(loc);
|
||||
|
||||
const ErrorLogger::ErrorMessage errmsg(locationList,
|
||||
Severity::debug,
|
||||
"simplifyTemplates: bailing out",
|
||||
"debug");
|
||||
|
||||
if (_errorLogger)
|
||||
_errorLogger->reportErr(errmsg);
|
||||
else
|
||||
Check::reportError(errmsg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ((tok->tokAt(namepos)->str() == "*" || tok->tokAt(namepos)->str() == "&"))
|
||||
++namepos;
|
||||
|
||||
// name of template function/class..
|
||||
const std::string name(tok->strAt(namepos));
|
||||
|
||||
const bool isfunc(tok->strAt(namepos + 1) == "(");
|
||||
|
||||
// locate template usage..
|
||||
|
||||
std::string s(name + " <");
|
||||
for (unsigned int i = 0; i < type.size(); ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
s += ",";
|
||||
s += " %any% ";
|
||||
}
|
||||
const std::string pattern(s + "> ");
|
||||
|
||||
std::string::size_type sz1 = used.size();
|
||||
unsigned int recursiveCount = 0;
|
||||
|
||||
for (std::list<Token *>::const_iterator iter2 = used.begin(); iter2 != used.end(); ++iter2)
|
||||
{
|
||||
// If the size of "used" has changed, simplify calculations
|
||||
if (sz1 != used.size())
|
||||
{
|
||||
sz1 = used.size();
|
||||
simplifyCalculations();
|
||||
recursiveCount++;
|
||||
if (recursiveCount > 100)
|
||||
{
|
||||
// bail out..
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Token * const tok2 = *iter2;
|
||||
|
||||
if (tok2->str() != name)
|
||||
continue;
|
||||
|
||||
if (Token::Match(tok2->previous(), "[;{}=]") &&
|
||||
!Token::Match(tok2, (pattern + (isfunc ? "(" : "*| %var%")).c_str()))
|
||||
continue;
|
||||
|
||||
// New type..
|
||||
std::vector<Token> types2;
|
||||
s = "";
|
||||
std::string s1(name + " < ");
|
||||
for (const Token *tok3 = tok2->tokAt(2); tok3 && tok3->str() != ">"; tok3 = tok3->next())
|
||||
{
|
||||
if (!tok3->next())
|
||||
{
|
||||
s.clear();
|
||||
break;
|
||||
}
|
||||
s1 += tok3->str();
|
||||
s1 += " ";
|
||||
if (tok3->str() != ",")
|
||||
types2.push_back(*tok3);
|
||||
// add additional type information
|
||||
if (tok3->isUnsigned())
|
||||
s += "unsigned";
|
||||
else if (tok3->isSigned())
|
||||
s += "signed";
|
||||
if (tok3->isLong())
|
||||
s += "long";
|
||||
s += tok3->str();
|
||||
}
|
||||
s1 += ">";
|
||||
const std::string type2(s);
|
||||
|
||||
if (type2.empty() || type.size() != types2.size())
|
||||
{
|
||||
if (_settings->debugwarnings)
|
||||
{
|
||||
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
||||
ErrorLogger::ErrorMessage::FileLocation loc;
|
||||
loc.line = tok2->linenr();
|
||||
loc.setfile(file(tok2));
|
||||
locationList.push_back(loc);
|
||||
|
||||
const ErrorLogger::ErrorMessage errmsg(locationList,
|
||||
Severity::debug,
|
||||
"Failed to instantiate template. The checking continues anyway.",
|
||||
"debug");
|
||||
|
||||
_errorLogger->reportErr(errmsg);
|
||||
}
|
||||
if (type2.empty())
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
// New classname/funcname..
|
||||
const std::string name2(name + "<" + type2 + ">");
|
||||
|
||||
if (expandedtemplates.find(name2) == expandedtemplates.end())
|
||||
{
|
||||
expandedtemplates.insert(name2);
|
||||
// Copy template..
|
||||
int _indentlevel = 0;
|
||||
int _parlevel = 0;
|
||||
for (const Token *tok3 = _tokens; tok3; tok3 = tok3->next())
|
||||
{
|
||||
if (tok3->str() == "{")
|
||||
++_indentlevel;
|
||||
else if (tok3->str() == "}")
|
||||
--_indentlevel;
|
||||
else if (tok3->str() == "(")
|
||||
++_parlevel;
|
||||
else if (tok3->str() == ")")
|
||||
--_parlevel;
|
||||
|
||||
// Start of template..
|
||||
if (tok3 == tok)
|
||||
{
|
||||
tok3 = tok3->next();
|
||||
}
|
||||
|
||||
// member function implemented outside class definition
|
||||
else if (_indentlevel == 0 && _parlevel == 0 && Token::Match(tok3, (pattern + " :: ~| %var% (").c_str()))
|
||||
{
|
||||
addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex());
|
||||
while (tok3->str() != "::")
|
||||
tok3 = tok3->next();
|
||||
}
|
||||
|
||||
// not part of template.. go on to next token
|
||||
else
|
||||
continue;
|
||||
|
||||
int indentlevel = 0;
|
||||
std::stack<Token *> braces; // holds "{" tokens
|
||||
std::stack<Token *> brackets; // holds "(" tokens
|
||||
std::stack<Token *> brackets2; // holds "[" tokens
|
||||
|
||||
for (; tok3; tok3 = tok3->next())
|
||||
{
|
||||
if (tok3->str() == "{")
|
||||
++indentlevel;
|
||||
|
||||
else if (tok3->str() == "}")
|
||||
{
|
||||
if (indentlevel <= 1 && brackets.empty() && brackets2.empty())
|
||||
{
|
||||
// there is a bug if indentlevel is 0
|
||||
// the "}" token should only be added if indentlevel is 1 but I add it always intentionally
|
||||
// if indentlevel ever becomes 0, cppcheck will write:
|
||||
// ### Error: Invalid number of character {
|
||||
addtoken("}", tok3->linenr(), tok3->fileIndex());
|
||||
Token::createMutualLinks(braces.top(), _tokensBack);
|
||||
braces.pop();
|
||||
break;
|
||||
}
|
||||
--indentlevel;
|
||||
}
|
||||
|
||||
|
||||
if (tok3->isName())
|
||||
{
|
||||
// search for this token in the type vector
|
||||
unsigned int itype = 0;
|
||||
while (itype < type.size() && type[itype]->str() != tok3->str())
|
||||
++itype;
|
||||
|
||||
// replace type with given type..
|
||||
if (itype < type.size())
|
||||
{
|
||||
addtoken(&types2[itype], tok3->linenr(), tok3->fileIndex());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// replace name..
|
||||
if (Token::Match(tok3, (name + " !!<").c_str()))
|
||||
{
|
||||
addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex());
|
||||
continue;
|
||||
}
|
||||
|
||||
// copy
|
||||
addtoken(tok3, tok3->linenr(), tok3->fileIndex());
|
||||
if (Token::Match(tok3, "%type% <"))
|
||||
{
|
||||
if (!Token::Match(tok3, (name + " <").c_str()))
|
||||
done = false;
|
||||
used.push_back(_tokensBack);
|
||||
}
|
||||
|
||||
// link() newly tokens manually
|
||||
if (tok3->str() == "{")
|
||||
{
|
||||
braces.push(_tokensBack);
|
||||
}
|
||||
else if (tok3->str() == "}")
|
||||
{
|
||||
assert(braces.empty() == false);
|
||||
Token::createMutualLinks(braces.top(), _tokensBack);
|
||||
braces.pop();
|
||||
}
|
||||
else if (tok3->str() == "(")
|
||||
{
|
||||
brackets.push(_tokensBack);
|
||||
}
|
||||
else if (tok3->str() == "[")
|
||||
{
|
||||
brackets2.push(_tokensBack);
|
||||
}
|
||||
else if (tok3->str() == ")")
|
||||
{
|
||||
assert(brackets.empty() == false);
|
||||
Token::createMutualLinks(brackets.top(), _tokensBack);
|
||||
brackets.pop();
|
||||
}
|
||||
else if (tok3->str() == "]")
|
||||
{
|
||||
assert(brackets2.empty() == false);
|
||||
Token::createMutualLinks(brackets2.top(), _tokensBack);
|
||||
brackets2.pop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
assert(braces.empty());
|
||||
assert(brackets.empty());
|
||||
}
|
||||
}
|
||||
|
||||
// Replace all these template usages..
|
||||
for (Token *tok4 = tok2; tok4; tok4 = tok4->next())
|
||||
{
|
||||
if (Token::simpleMatch(tok4, s1.c_str()))
|
||||
{
|
||||
bool match = true;
|
||||
Token * tok5 = tok4->tokAt(2);
|
||||
unsigned int count = 0;
|
||||
while (tok5->str() != ">")
|
||||
{
|
||||
if (tok5->str() != ",")
|
||||
{
|
||||
if (tok5->isUnsigned() != types2[count].isUnsigned() ||
|
||||
tok5->isSigned() != types2[count].isSigned() ||
|
||||
tok5->isLong() != types2[count].isLong())
|
||||
{
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
tok5 = tok5->next();
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
tok4->str(name2);
|
||||
while (tok4->next()->str() != ">")
|
||||
{
|
||||
used.remove(tok4->next());
|
||||
tok4->deleteNext();
|
||||
}
|
||||
used.remove(tok4->next());
|
||||
tok4->deleteNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Tokenizer::simplifyTemplates()
|
||||
{
|
||||
std::set<std::string> expandedtemplates(simplifyTemplatesExpandSpecialized());
|
||||
|
@ -2840,316 +3159,7 @@ void Tokenizer::simplifyTemplates()
|
|||
done = true;
|
||||
for (std::list<Token *>::iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1)
|
||||
{
|
||||
Token *tok = *iter1;
|
||||
std::vector<const Token *> type;
|
||||
for (tok = tok->tokAt(2); tok && tok->str() != ">"; tok = tok->next())
|
||||
{
|
||||
if (Token::Match(tok, "%var% ,|>"))
|
||||
type.push_back(tok);
|
||||
}
|
||||
// bail out if the end of the file was reached
|
||||
if (!tok)
|
||||
break;
|
||||
|
||||
// get the position of the template name
|
||||
unsigned char namepos = 0;
|
||||
if (Token::Match(tok, "> class|struct %type% {|:"))
|
||||
namepos = 2;
|
||||
else if (Token::Match(tok, "> %type% *|&| %type% ("))
|
||||
namepos = 2;
|
||||
else if (Token::Match(tok, "> %type% %type% *|&| %type% ("))
|
||||
namepos = 3;
|
||||
else
|
||||
{
|
||||
// debug message that we bail out..
|
||||
if (_settings->debugwarnings)
|
||||
{
|
||||
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
||||
ErrorLogger::ErrorMessage::FileLocation loc;
|
||||
loc.line = tok->linenr();
|
||||
loc.setfile(file(tok));
|
||||
locationList.push_back(loc);
|
||||
|
||||
const ErrorLogger::ErrorMessage errmsg(locationList,
|
||||
Severity::debug,
|
||||
"simplifyTemplates: bailing out",
|
||||
"debug");
|
||||
|
||||
if (_errorLogger)
|
||||
_errorLogger->reportErr(errmsg);
|
||||
else
|
||||
Check::reportError(errmsg);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ((tok->tokAt(namepos)->str() == "*" || tok->tokAt(namepos)->str() == "&"))
|
||||
++namepos;
|
||||
|
||||
// name of template function/class..
|
||||
const std::string name(tok->strAt(namepos));
|
||||
|
||||
const bool isfunc(tok->strAt(namepos + 1) == "(");
|
||||
|
||||
// locate template usage..
|
||||
|
||||
std::string s(name + " <");
|
||||
for (unsigned int i = 0; i < type.size(); ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
s += ",";
|
||||
s += " %any% ";
|
||||
}
|
||||
const std::string pattern(s + "> ");
|
||||
|
||||
std::string::size_type sz1 = used.size();
|
||||
unsigned int recursiveCount = 0;
|
||||
|
||||
for (std::list<Token *>::iterator iter2 = used.begin(); iter2 != used.end(); ++iter2)
|
||||
{
|
||||
// If the size of "used" has changed, simplify calculations
|
||||
if (sz1 != used.size())
|
||||
{
|
||||
sz1 = used.size();
|
||||
simplifyCalculations();
|
||||
recursiveCount++;
|
||||
if (recursiveCount > 100)
|
||||
{
|
||||
// bail out..
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Token * const tok2 = *iter2;
|
||||
|
||||
if (tok2->str() != name)
|
||||
continue;
|
||||
|
||||
if (Token::Match(tok2->previous(), "[;{}=]") &&
|
||||
!Token::Match(tok2, (pattern + (isfunc ? "(" : "*| %var%")).c_str()))
|
||||
continue;
|
||||
|
||||
// New type..
|
||||
std::vector<Token> types2;
|
||||
s = "";
|
||||
std::string s1(name + " < ");
|
||||
for (const Token *tok3 = tok2->tokAt(2); tok3 && tok3->str() != ">"; tok3 = tok3->next())
|
||||
{
|
||||
if (!tok3->next())
|
||||
{
|
||||
s.clear();
|
||||
break;
|
||||
}
|
||||
s1 += tok3->str();
|
||||
s1 += " ";
|
||||
if (tok3->str() != ",")
|
||||
types2.push_back(*tok3);
|
||||
// add additional type information
|
||||
if (tok3->isUnsigned())
|
||||
s += "unsigned";
|
||||
else if (tok3->isSigned())
|
||||
s += "signed";
|
||||
if (tok3->isLong())
|
||||
s += "long";
|
||||
s += tok3->str();
|
||||
}
|
||||
s1 += ">";
|
||||
const std::string type2(s);
|
||||
|
||||
if (type2.empty() || type.size() != types2.size())
|
||||
{
|
||||
if (_settings->debugwarnings)
|
||||
{
|
||||
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
||||
ErrorLogger::ErrorMessage::FileLocation loc;
|
||||
loc.line = tok2->linenr();
|
||||
loc.setfile(file(tok2));
|
||||
locationList.push_back(loc);
|
||||
|
||||
const ErrorLogger::ErrorMessage errmsg(locationList,
|
||||
Severity::debug,
|
||||
"Failed to instantiate template. The checking continues anyway.",
|
||||
"debug");
|
||||
|
||||
_errorLogger->reportErr(errmsg);
|
||||
}
|
||||
if (type2.empty())
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
// New classname/funcname..
|
||||
const std::string name2(name + "<" + type2 + ">");
|
||||
|
||||
if (expandedtemplates.find(name2) == expandedtemplates.end())
|
||||
{
|
||||
expandedtemplates.insert(name2);
|
||||
// Copy template..
|
||||
int _indentlevel = 0;
|
||||
int _parlevel = 0;
|
||||
for (const Token *tok3 = _tokens; tok3; tok3 = tok3->next())
|
||||
{
|
||||
if (tok3->str() == "{")
|
||||
++_indentlevel;
|
||||
else if (tok3->str() == "}")
|
||||
--_indentlevel;
|
||||
else if (tok3->str() == "(")
|
||||
++_parlevel;
|
||||
else if (tok3->str() == ")")
|
||||
--_parlevel;
|
||||
|
||||
// Start of template..
|
||||
if (tok3 == tok)
|
||||
{
|
||||
tok3 = tok3->next();
|
||||
}
|
||||
|
||||
// member function implemented outside class definition
|
||||
else if (_indentlevel == 0 && _parlevel == 0 && Token::Match(tok3, (pattern + " :: ~| %var% (").c_str()))
|
||||
{
|
||||
addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex());
|
||||
while (tok3->str() != "::")
|
||||
tok3 = tok3->next();
|
||||
}
|
||||
|
||||
// not part of template.. go on to next token
|
||||
else
|
||||
continue;
|
||||
|
||||
int indentlevel = 0;
|
||||
std::stack<Token *> braces; // holds "{" tokens
|
||||
std::stack<Token *> brackets; // holds "(" tokens
|
||||
std::stack<Token *> brackets2; // holds "[" tokens
|
||||
|
||||
for (; tok3; tok3 = tok3->next())
|
||||
{
|
||||
if (tok3->str() == "{")
|
||||
++indentlevel;
|
||||
|
||||
else if (tok3->str() == "}")
|
||||
{
|
||||
if (indentlevel <= 1 && brackets.empty() && brackets2.empty())
|
||||
{
|
||||
// there is a bug if indentlevel is 0
|
||||
// the "}" token should only be added if indentlevel is 1 but I add it always intentionally
|
||||
// if indentlevel ever becomes 0, cppcheck will write:
|
||||
// ### Error: Invalid number of character {
|
||||
addtoken("}", tok3->linenr(), tok3->fileIndex());
|
||||
Token::createMutualLinks(braces.top(), _tokensBack);
|
||||
braces.pop();
|
||||
break;
|
||||
}
|
||||
--indentlevel;
|
||||
}
|
||||
|
||||
|
||||
if (tok3->isName())
|
||||
{
|
||||
// search for this token in the type vector
|
||||
unsigned int itype = 0;
|
||||
while (itype < type.size() && type[itype]->str() != tok3->str())
|
||||
++itype;
|
||||
|
||||
// replace type with given type..
|
||||
if (itype < type.size())
|
||||
{
|
||||
addtoken(&types2[itype], tok3->linenr(), tok3->fileIndex());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// replace name..
|
||||
if (Token::Match(tok3, (name + " !!<").c_str()))
|
||||
{
|
||||
addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex());
|
||||
continue;
|
||||
}
|
||||
|
||||
// copy
|
||||
addtoken(tok3, tok3->linenr(), tok3->fileIndex());
|
||||
if (Token::Match(tok3, "%type% <"))
|
||||
{
|
||||
if (!Token::Match(tok3, (name + " <").c_str()))
|
||||
done = false;
|
||||
used.push_back(_tokensBack);
|
||||
}
|
||||
|
||||
// link() newly tokens manually
|
||||
if (tok3->str() == "{")
|
||||
{
|
||||
braces.push(_tokensBack);
|
||||
}
|
||||
else if (tok3->str() == "}")
|
||||
{
|
||||
assert(braces.empty() == false);
|
||||
Token::createMutualLinks(braces.top(), _tokensBack);
|
||||
braces.pop();
|
||||
}
|
||||
else if (tok3->str() == "(")
|
||||
{
|
||||
brackets.push(_tokensBack);
|
||||
}
|
||||
else if (tok3->str() == "[")
|
||||
{
|
||||
brackets2.push(_tokensBack);
|
||||
}
|
||||
else if (tok3->str() == ")")
|
||||
{
|
||||
assert(brackets.empty() == false);
|
||||
Token::createMutualLinks(brackets.top(), _tokensBack);
|
||||
brackets.pop();
|
||||
}
|
||||
else if (tok3->str() == "]")
|
||||
{
|
||||
assert(brackets2.empty() == false);
|
||||
Token::createMutualLinks(brackets2.top(), _tokensBack);
|
||||
brackets2.pop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
assert(braces.empty());
|
||||
assert(brackets.empty());
|
||||
}
|
||||
}
|
||||
|
||||
// Replace all these template usages..
|
||||
for (Token *tok4 = tok2; tok4; tok4 = tok4->next())
|
||||
{
|
||||
if (Token::simpleMatch(tok4, s1.c_str()))
|
||||
{
|
||||
bool match = true;
|
||||
Token * tok5 = tok4->tokAt(2);
|
||||
unsigned int count = 0;
|
||||
while (tok5->str() != ">")
|
||||
{
|
||||
if (tok5->str() != ",")
|
||||
{
|
||||
if (tok5->isUnsigned() != types2[count].isUnsigned() ||
|
||||
tok5->isSigned() != types2[count].isSigned() ||
|
||||
tok5->isLong() != types2[count].isLong())
|
||||
{
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
tok5 = tok5->next();
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
tok4->str(name2);
|
||||
while (tok4->next()->str() != ">")
|
||||
{
|
||||
used.remove(tok4->next());
|
||||
tok4->deleteNext();
|
||||
}
|
||||
used.remove(tok4->next());
|
||||
tok4->deleteNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
simplifyTemplatesInstantiate(used, *iter1, expandedtemplates);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -423,6 +423,13 @@ public:
|
|||
void simplifyTemplatesUseDefaultArgumentValues(const std::list<Token *> &templates,
|
||||
const std::list<Token *> &instantiations);
|
||||
|
||||
/**
|
||||
* Simplify templates : expand all instantiatiations for a template
|
||||
*/
|
||||
void simplifyTemplatesInstantiate(std::list<Token *> &used,
|
||||
const Token *tok,
|
||||
std::set<std::string> &expandedtemplates);
|
||||
|
||||
/**
|
||||
* Used after simplifyTemplates to perform a little cleanup.
|
||||
* Sometimes the simplifyTemplates isn't fully successful and then
|
||||
|
|
Loading…
Reference in New Issue