Refactoring: Move rest of the template simplification into TemplateSimplifier
simplifyCalculations() was temporarily moved into TemplateSimplifier also, it should be moved to a better place.
This commit is contained in:
parent
756b8762ab
commit
be7691c7b4
2
Makefile
2
Makefile
|
@ -287,7 +287,7 @@ lib/suppressions.o: lib/suppressions.cpp lib/suppressions.h lib/settings.h lib/s
|
|||
lib/symboldatabase.o: lib/symboldatabase.cpp lib/symboldatabase.h lib/token.h lib/mathlib.h lib/tokenize.h lib/path.h lib/settings.h lib/suppressions.h lib/standards.h lib/errorlogger.h lib/check.h
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_LIB} -c -o lib/symboldatabase.o lib/symboldatabase.cpp
|
||||
|
||||
lib/templatesimplifier.o: lib/templatesimplifier.cpp lib/templatesimplifier.h lib/token.h
|
||||
lib/templatesimplifier.o: lib/templatesimplifier.cpp lib/templatesimplifier.h lib/mathlib.h lib/errorlogger.h lib/suppressions.h lib/token.h lib/settings.h lib/standards.h lib/check.h lib/tokenize.h lib/path.h
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_LIB} -c -o lib/templatesimplifier.o lib/templatesimplifier.cpp
|
||||
|
||||
lib/timer.o: lib/timer.cpp lib/timer.h
|
||||
|
|
|
@ -17,7 +17,11 @@
|
|||
*/
|
||||
|
||||
#include "templatesimplifier.h"
|
||||
#include "mathlib.h"
|
||||
#include "errorlogger.h"
|
||||
#include "token.h"
|
||||
#include "settings.h"
|
||||
#include "check.h"
|
||||
#include <sstream>
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
@ -702,3 +706,476 @@ void TemplateSimplifier::simplifyTemplatesExpandTemplate(
|
|||
assert(brackets.empty());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This is not the correct class for simplifyCalculations(), so it
|
||||
// should be moved away.
|
||||
bool TemplateSimplifier::simplifyCalculations(Token *_tokens)
|
||||
{
|
||||
bool ret = false;
|
||||
for (Token *tok = _tokens; tok; tok = tok->next()) {
|
||||
// Remove parentheses around variable..
|
||||
// keep parentheses here: dynamic_cast<Fred *>(p);
|
||||
// keep parentheses here: A operator * (int);
|
||||
// keep parentheses here: int ( * ( * f ) ( ... ) ) (int) ;
|
||||
// keep parentheses here: int ( * * ( * compilerHookVector ) (void) ) ( ) ;
|
||||
// keep parentheses here: operator new [] (size_t);
|
||||
// keep parentheses here: Functor()(a ... )
|
||||
// keep parentheses here: ) ( var ) ;
|
||||
if (Token::Match(tok->next(), "( %var% ) ;|)|,|]|%op%") &&
|
||||
!tok->isName() &&
|
||||
tok->str() != ">" &&
|
||||
tok->str() != "]" &&
|
||||
!Token::simpleMatch(tok->previous(), "operator") &&
|
||||
!Token::simpleMatch(tok->previous(), "* )") &&
|
||||
!Token::simpleMatch(tok->previous(), ") )") &&
|
||||
!Token::Match(tok->tokAt(-2), "* %var% )") &&
|
||||
!Token::Match(tok->tokAt(-2), "%type% ( ) ( %var%") &&
|
||||
!Token::Match(tok, ") ( %var% ) ;")
|
||||
) {
|
||||
tok->deleteNext();
|
||||
tok = tok->next();
|
||||
tok->deleteNext();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (tok->str()[0] == '\'' && tok->str().size() == 3 &&
|
||||
Token::Match(tok->previous(), "(|&&|%oror% %any% ==|!=|<=|<|>=|> %num% &&|%oror%|)")) {
|
||||
tok->str(MathLib::toString(tok->str()[1] & 0xff));
|
||||
}
|
||||
|
||||
if (tok->isNumber()) {
|
||||
if (tok->str() == "0") {
|
||||
if (Token::Match(tok->previous(), "[+-|] 0")) {
|
||||
tok = tok->previous();
|
||||
if (Token::Match(tok->tokAt(-4), "[;{}] %var% = %var% [+-|] 0 ;") &&
|
||||
tok->strAt(-3) == tok->previous()->str()) {
|
||||
tok = tok->tokAt(-3);
|
||||
tok->deleteNext(2);
|
||||
tok->deleteThis();
|
||||
}
|
||||
tok->deleteNext();
|
||||
tok->deleteThis();
|
||||
ret = true;
|
||||
} else if (Token::Match(tok->previous(), "[=([,] 0 [+|]") ||
|
||||
Token::Match(tok->previous(), "return|case 0 [+|]")) {
|
||||
tok->deleteNext();
|
||||
tok->deleteThis();
|
||||
ret = true;
|
||||
} else if (Token::Match(tok->previous(), "[=[(,] 0 * %any% ,|]|)|;|=|%op%") ||
|
||||
Token::Match(tok->previous(), "return|case 0 * %any% ,|:|;|=|%op%")) {
|
||||
tok->deleteNext();
|
||||
if (tok->next()->str() == "(")
|
||||
Token::eraseTokens(tok, tok->next()->link());
|
||||
tok->deleteNext();
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Token::simpleMatch(tok->previous(), "* 1") || Token::simpleMatch(tok, "1 *")) {
|
||||
if (tok->previous()->isOp())
|
||||
tok = tok->previous();
|
||||
tok->deleteNext();
|
||||
tok->deleteThis();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
// Remove parentheses around number..
|
||||
if (Token::Match(tok->tokAt(-2), "%any% ( %num% )") && !tok->tokAt(-2)->isName() && tok->strAt(-2) != ">") {
|
||||
tok = tok->previous();
|
||||
tok->deleteThis();
|
||||
tok->deleteNext();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (Token::simpleMatch(tok->previous(), "( 0 ||") ||
|
||||
Token::simpleMatch(tok->previous(), "|| 0 )") ||
|
||||
Token::simpleMatch(tok->previous(), "( 0 |") ||
|
||||
Token::simpleMatch(tok->previous(), "| 0 )") ||
|
||||
Token::simpleMatch(tok->previous(), "( 1 &&") ||
|
||||
Token::simpleMatch(tok->previous(), "&& 1 )")) {
|
||||
if (tok->previous()->isOp())
|
||||
tok = tok->previous();
|
||||
tok->deleteNext();
|
||||
tok->deleteThis();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (Token::Match(tok, "%num% ==|!=|<=|>=|<|> %num%") &&
|
||||
MathLib::isInt(tok->str()) &&
|
||||
MathLib::isInt(tok->strAt(2))) {
|
||||
if (Token::Match(tok->previous(), "(|&&|%oror%") && Token::Match(tok->tokAt(3), ")|&&|%oror%")) {
|
||||
const MathLib::bigint op1(MathLib::toLongNumber(tok->str()));
|
||||
const std::string &cmp(tok->next()->str());
|
||||
const MathLib::bigint op2(MathLib::toLongNumber(tok->strAt(2)));
|
||||
|
||||
std::string result;
|
||||
|
||||
if (cmp == "==")
|
||||
result = (op1 == op2) ? "1" : "0";
|
||||
else if (cmp == "!=")
|
||||
result = (op1 != op2) ? "1" : "0";
|
||||
else if (cmp == "<=")
|
||||
result = (op1 <= op2) ? "1" : "0";
|
||||
else if (cmp == ">=")
|
||||
result = (op1 >= op2) ? "1" : "0";
|
||||
else if (cmp == "<")
|
||||
result = (op1 < op2) ? "1" : "0";
|
||||
else if (cmp == ">")
|
||||
result = (op1 > op2) ? "1" : "0";
|
||||
|
||||
tok->str(result);
|
||||
tok->deleteNext(2);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Token::Match(tok->previous(), "[([,=] %num% <<|>> %num%")) {
|
||||
const MathLib::bigint op1(MathLib::toLongNumber(tok->str()));
|
||||
const MathLib::bigint op2(MathLib::toLongNumber(tok->strAt(2)));
|
||||
MathLib::bigint result;
|
||||
|
||||
if (tok->next()->str() == "<<")
|
||||
result = op1 << op2;
|
||||
else
|
||||
result = op1 >> op2;
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << result;
|
||||
|
||||
tok->str(ss.str());
|
||||
tok->deleteNext(2);
|
||||
}
|
||||
}
|
||||
|
||||
else if (tok->next() && tok->next()->isNumber()) {
|
||||
// (1-2)
|
||||
while (Token::Match(tok, "[[,(=<>+-*|&^] %num% [+-*/] %num% ]|,|)|;|=|%op%") ||
|
||||
Token::Match(tok, "<< %num% [+-*/] %num% ]|,|)|;|=|%op%") ||
|
||||
Token::Match(tok, "[[,(=<>+-*|&^] %num% [+-*/] %num% <<|>>") ||
|
||||
Token::Match(tok, "<< %num% [+-*/] %num% <<") ||
|
||||
Token::Match(tok, "[(,[] %num% [|&^] %num% [];,);]") ||
|
||||
Token::Match(tok, "(|%op% %num% [+-*/] %num% )|%op%") ||
|
||||
Token::Match(tok,"return|case %num% [+-*/] %num% ;|,|=|:|%op%")) {
|
||||
tok = tok->next();
|
||||
|
||||
// Don't simplify "%num% / 0"
|
||||
if (Token::simpleMatch(tok->next(), "/ 0"))
|
||||
continue;
|
||||
|
||||
// & | ^
|
||||
if (Token::Match(tok->next(), "[&|^]")) {
|
||||
std::string result;
|
||||
const std::string first(tok->str());
|
||||
const std::string second(tok->strAt(2));
|
||||
const char op = tok->next()->str()[0];
|
||||
if (op == '&')
|
||||
result = MathLib::toString<MathLib::bigint>(MathLib::toLongNumber(first) & MathLib::toLongNumber(second));
|
||||
else if (op == '|')
|
||||
result = MathLib::toString<MathLib::bigint>(MathLib::toLongNumber(first) | MathLib::toLongNumber(second));
|
||||
else if (op == '^')
|
||||
result = MathLib::toString<MathLib::bigint>(MathLib::toLongNumber(first) ^ MathLib::toLongNumber(second));
|
||||
|
||||
if (!result.empty()) {
|
||||
ret = true;
|
||||
tok->str(result);
|
||||
tok->deleteNext(2);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Division where result is a whole number
|
||||
if (Token::Match(tok->previous(), "* %num% /") &&
|
||||
tok->str() == MathLib::multiply(tok->strAt(2), MathLib::divide(tok->str(), tok->strAt(2)))) {
|
||||
}
|
||||
|
||||
// + and - are calculated after * and /
|
||||
else if (Token::Match(tok->next(), "[+-/]")) {
|
||||
if (Token::Match(tok->previous(), "[*/%]"))
|
||||
continue;
|
||||
if (Token::Match(tok->tokAt(3), "[*/%]"))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Token::Match(tok->previous(), "- %num% - %num%"))
|
||||
tok->str(MathLib::add(tok->str(), tok->strAt(2)));
|
||||
else if (Token::Match(tok->previous(), "- %num% + %num%"))
|
||||
tok->str(MathLib::subtract(tok->str(), tok->strAt(2)));
|
||||
else {
|
||||
try {
|
||||
tok->str(MathLib::calculate(tok->str(), tok->strAt(2), tok->next()->str()[0]));
|
||||
} catch (InternalError &e) {
|
||||
e.token = tok;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
tok->deleteNext(2);
|
||||
|
||||
// evaluate "2 + 2 - 2 - 2"
|
||||
// as (((2 + 2) - 2) - 2) = 0
|
||||
// instead of ((2 + 2) - (2 - 2)) = 4
|
||||
if (Token::Match(tok->next(), "[+-*/]")) {
|
||||
tok = tok->previous();
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void TemplateSimplifier::simplifyTemplateInstantions(
|
||||
Token *_tokens,
|
||||
Token **_tokensBack,
|
||||
ErrorLogger *_errorLogger,
|
||||
const Settings *_settings,
|
||||
const std::vector<std::string> &files,
|
||||
const Token *tok,
|
||||
std::list<Token *> &templateInstantiations,
|
||||
std::set<std::string> &expandedtemplates)
|
||||
{
|
||||
// this variable is not used at the moment. The intention was to
|
||||
// allow continuous instantiations until all templates has been expanded
|
||||
//bool done = false;
|
||||
|
||||
// Contains tokens such as "T"
|
||||
std::vector<const Token *> typeParametersInDeclaration;
|
||||
for (tok = tok->tokAt(2); tok && tok->str() != ">"; tok = tok->next()) {
|
||||
if (Token::Match(tok, "%var% ,|>"))
|
||||
typeParametersInDeclaration.push_back(tok);
|
||||
}
|
||||
|
||||
// bail out if the end of the file was reached
|
||||
if (!tok)
|
||||
return;
|
||||
|
||||
// get the position of the template name
|
||||
int namepos = TemplateSimplifier::simplifyTemplatesGetTemplateNamePosition(tok);
|
||||
if (namepos == -1) {
|
||||
// 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(files[tok->fileIndex()]);
|
||||
locationList.push_back(loc);
|
||||
|
||||
const ErrorLogger::ErrorMessage errmsg(locationList,
|
||||
Severity::debug,
|
||||
"simplifyTemplates: bailing out",
|
||||
"debug",
|
||||
false);
|
||||
|
||||
if (_errorLogger)
|
||||
_errorLogger->reportErr(errmsg);
|
||||
else
|
||||
Check::reportError(errmsg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// name of template function/class..
|
||||
const std::string name(tok->strAt(namepos));
|
||||
|
||||
const bool isfunc(tok->strAt(namepos + 1) == "(");
|
||||
|
||||
// locate template usage..
|
||||
std::string::size_type amountOftemplateInstantiations = templateInstantiations.size();
|
||||
unsigned int recursiveCount = 0;
|
||||
|
||||
for (std::list<Token *>::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) {
|
||||
if (amountOftemplateInstantiations != templateInstantiations.size()) {
|
||||
amountOftemplateInstantiations = templateInstantiations.size();
|
||||
simplifyCalculations(_tokens);
|
||||
++recursiveCount;
|
||||
if (recursiveCount > 100) {
|
||||
// bail out..
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Token * const tok2 = *iter2;
|
||||
if (tok2->str() != name)
|
||||
continue;
|
||||
|
||||
if (Token::Match(tok2->previous(), "[;{}=]") &&
|
||||
!TemplateSimplifier::simplifyTemplatesInstantiateMatch(*iter2, name, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %var%"))
|
||||
continue;
|
||||
|
||||
// New type..
|
||||
std::vector<const Token *> typesUsedInTemplateInstantion;
|
||||
std::string typeForNewNameStr;
|
||||
std::string templateMatchPattern(name + " < ");
|
||||
for (const Token *tok3 = tok2->tokAt(2); tok3 && tok3->str() != ">"; tok3 = tok3->next()) {
|
||||
// #2648 - unhandled parenthesis => bail out
|
||||
// #2721 - unhandled [ => bail out
|
||||
if (tok3->str() == "(" || tok3->str() == "[") {
|
||||
typeForNewNameStr.clear();
|
||||
break;
|
||||
}
|
||||
if (!tok3->next()) {
|
||||
typeForNewNameStr.clear();
|
||||
break;
|
||||
}
|
||||
templateMatchPattern += tok3->str();
|
||||
templateMatchPattern += " ";
|
||||
if (Token::Match(tok3->previous(), "[<,]"))
|
||||
typesUsedInTemplateInstantion.push_back(tok3);
|
||||
// add additional type information
|
||||
if (tok3->isUnsigned())
|
||||
typeForNewNameStr += "unsigned";
|
||||
else if (tok3->isSigned())
|
||||
typeForNewNameStr += "signed";
|
||||
if (tok3->isLong())
|
||||
typeForNewNameStr += "long";
|
||||
typeForNewNameStr += tok3->str();
|
||||
}
|
||||
templateMatchPattern += ">";
|
||||
const std::string typeForNewName(typeForNewNameStr);
|
||||
|
||||
if (typeForNewName.empty() || typeParametersInDeclaration.size() != typesUsedInTemplateInstantion.size()) {
|
||||
if (_settings->debugwarnings) {
|
||||
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
||||
ErrorLogger::ErrorMessage::FileLocation loc;
|
||||
loc.line = tok2->linenr();
|
||||
loc.setfile(files[tok2->fileIndex()]);
|
||||
locationList.push_back(loc);
|
||||
|
||||
const ErrorLogger::ErrorMessage errmsg(locationList,
|
||||
Severity::debug,
|
||||
"Failed to instantiate template. The checking continues anyway.",
|
||||
"debug",
|
||||
false);
|
||||
|
||||
_errorLogger->reportErr(errmsg);
|
||||
}
|
||||
if (typeForNewName.empty())
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
// New classname/funcname..
|
||||
const std::string newName(name + "<" + typeForNewName + ">");
|
||||
|
||||
if (expandedtemplates.find(newName) == expandedtemplates.end()) {
|
||||
expandedtemplates.insert(newName);
|
||||
TemplateSimplifier::simplifyTemplatesExpandTemplate(_tokens,_tokensBack, tok,name,typeParametersInDeclaration,newName,typesUsedInTemplateInstantion,templateInstantiations);
|
||||
}
|
||||
|
||||
// Replace all these template usages..
|
||||
std::list< std::pair<Token *, Token *> > removeTokens;
|
||||
for (Token *tok4 = tok2; tok4; tok4 = tok4->next()) {
|
||||
if (Token::simpleMatch(tok4, templateMatchPattern.c_str())) {
|
||||
Token * tok5 = tok4->tokAt(2);
|
||||
unsigned int typeCountInInstantion = 1U; // There is always atleast one type
|
||||
const Token *typetok = (!typesUsedInTemplateInstantion.empty()) ? typesUsedInTemplateInstantion[0] : 0;
|
||||
while (tok5 && tok5->str() != ">") {
|
||||
if (tok5->str() != ",") {
|
||||
if (!typetok ||
|
||||
tok5->isUnsigned() != typetok->isUnsigned() ||
|
||||
tok5->isSigned() != typetok->isSigned() ||
|
||||
tok5->isLong() != typetok->isLong()) {
|
||||
break;
|
||||
}
|
||||
|
||||
typetok = typetok ? typetok->next() : 0;
|
||||
} else {
|
||||
typetok = (typeCountInInstantion < typesUsedInTemplateInstantion.size()) ? typesUsedInTemplateInstantion[typeCountInInstantion] : 0;
|
||||
++typeCountInInstantion;
|
||||
}
|
||||
tok5 = tok5->next();
|
||||
}
|
||||
|
||||
// matching template usage => replace tokens..
|
||||
// Foo < int > => Foo<int>
|
||||
if (tok5 && tok5->str() == ">" && typeCountInInstantion == typesUsedInTemplateInstantion.size()) {
|
||||
tok4->str(newName);
|
||||
for (Token *tok6 = tok4->next(); tok6 != tok5; tok6 = tok6->next()) {
|
||||
if (tok6->isName())
|
||||
templateInstantiations.remove(tok6);
|
||||
}
|
||||
removeTokens.push_back(std::pair<Token*,Token*>(tok4, tok5->next()));
|
||||
}
|
||||
|
||||
tok4 = tok5;
|
||||
if (!tok4)
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (!removeTokens.empty()) {
|
||||
Token::eraseTokens(removeTokens.back().first, removeTokens.back().second);
|
||||
removeTokens.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TemplateSimplifier::simplifyTemplates(
|
||||
Token *_tokens,
|
||||
Token **_tokensBack,
|
||||
ErrorLogger *_errorLogger,
|
||||
const Settings *_settings,
|
||||
const std::vector<std::string> &_files,
|
||||
bool &_codeWithTemplates
|
||||
)
|
||||
{
|
||||
|
||||
std::set<std::string> expandedtemplates(TemplateSimplifier::simplifyTemplatesExpandSpecialized(_tokens));
|
||||
|
||||
// Locate templates and set member variable _codeWithTemplates if the code has templates.
|
||||
// this info is used by checks
|
||||
std::list<Token *> templates(TemplateSimplifier::simplifyTemplatesGetTemplateDeclarations(_tokens,_codeWithTemplates));
|
||||
|
||||
if (templates.empty()) {
|
||||
TemplateSimplifier::removeTemplates(_tokens);
|
||||
return;
|
||||
}
|
||||
|
||||
// There are templates..
|
||||
// Remove "typename" unless used in template arguments..
|
||||
for (Token *tok = _tokens; tok; tok = tok->next()) {
|
||||
if (tok->str() == "typename")
|
||||
tok->deleteThis();
|
||||
|
||||
if (Token::simpleMatch(tok, "template <")) {
|
||||
while (tok && tok->str() != ">")
|
||||
tok = tok->next();
|
||||
if (!tok)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Locate possible instantiations of templates..
|
||||
std::list<Token *> templateInstantiations(TemplateSimplifier::simplifyTemplatesGetTemplateInstantiations(_tokens));
|
||||
|
||||
// No template instantiations? Then remove all templates.
|
||||
if (templateInstantiations.empty()) {
|
||||
TemplateSimplifier::removeTemplates(_tokens);
|
||||
return;
|
||||
}
|
||||
|
||||
// Template arguments with default values
|
||||
TemplateSimplifier::simplifyTemplatesUseDefaultArgumentValues(templates, templateInstantiations);
|
||||
|
||||
// expand templates
|
||||
//bool done = false;
|
||||
//while (!done)
|
||||
{
|
||||
//done = true;
|
||||
for (std::list<Token *>::reverse_iterator iter1 = templates.rbegin(); iter1 != templates.rend(); ++iter1) {
|
||||
TemplateSimplifier::simplifyTemplateInstantions(
|
||||
_tokens,
|
||||
_tokensBack,
|
||||
_errorLogger,
|
||||
_settings,
|
||||
_files,
|
||||
|
||||
*iter1, templateInstantiations, expandedtemplates);
|
||||
}
|
||||
}
|
||||
|
||||
TemplateSimplifier::removeTemplates(_tokens);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <vector>
|
||||
|
||||
class Token;
|
||||
class ErrorLogger;
|
||||
class Settings;
|
||||
|
||||
|
||||
/// @addtogroup Core
|
||||
|
@ -120,6 +122,41 @@ public:
|
|||
const std::string &newName,
|
||||
std::vector<const Token *> &typesUsedInTemplateInstantion,
|
||||
std::list<Token *> &templateInstantiations);
|
||||
|
||||
/**
|
||||
* Simplify templates : expand all instantiatiations for a template
|
||||
* @todo It seems that inner templates should be instantiated recursively
|
||||
* @param tok token where the template declaration begins
|
||||
* @param templateInstantiations a list of template usages (not necessarily just for this template)
|
||||
* @param expandedtemplates all templates that has been expanded so far. The full names are stored.
|
||||
*/
|
||||
static void simplifyTemplateInstantions(
|
||||
Token *_tokens,
|
||||
Token **_tokensBack,
|
||||
ErrorLogger *_errorLogger,
|
||||
const Settings *_settings,
|
||||
const std::vector<std::string> &files,
|
||||
const Token *tok,
|
||||
std::list<Token *> &templateInstantiations,
|
||||
std::set<std::string> &expandedtemplates);
|
||||
|
||||
/**
|
||||
* Simplify templates
|
||||
*/
|
||||
static void simplifyTemplates(
|
||||
Token *_tokens,
|
||||
Token **_tokensBack,
|
||||
ErrorLogger *_errorLogger,
|
||||
const Settings *_settings,
|
||||
const std::vector<std::string> &_files,
|
||||
bool &_codeWithTemplates);
|
||||
|
||||
/**
|
||||
* Simplify constant calculations such as "1+2" => "3"
|
||||
* @return true if modifications to token-list are done.
|
||||
* false if no modifications are done.
|
||||
*/
|
||||
static bool simplifyCalculations(Token *_tokens);
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
|
447
lib/tokenize.cpp
447
lib/tokenize.cpp
|
@ -2742,184 +2742,6 @@ void Tokenizer::simplifyLabelsCaseDefault()
|
|||
|
||||
|
||||
|
||||
void Tokenizer::simplifyTemplateInstantions(const Token *tok,
|
||||
std::list<Token *> &templateInstantiations,
|
||||
std::set<std::string> &expandedtemplates)
|
||||
{
|
||||
// this variable is not used at the moment. The intention was to
|
||||
// allow continuous instantiations until all templates has been expanded
|
||||
//bool done = false;
|
||||
|
||||
// Contains tokens such as "T"
|
||||
std::vector<const Token *> typeParametersInDeclaration;
|
||||
for (tok = tok->tokAt(2); tok && tok->str() != ">"; tok = tok->next()) {
|
||||
if (Token::Match(tok, "%var% ,|>"))
|
||||
typeParametersInDeclaration.push_back(tok);
|
||||
}
|
||||
|
||||
// bail out if the end of the file was reached
|
||||
if (!tok)
|
||||
return;
|
||||
|
||||
// get the position of the template name
|
||||
int namepos = TemplateSimplifier::simplifyTemplatesGetTemplateNamePosition(tok);
|
||||
if (namepos == -1) {
|
||||
// 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",
|
||||
false);
|
||||
|
||||
if (_errorLogger)
|
||||
_errorLogger->reportErr(errmsg);
|
||||
else
|
||||
Check::reportError(errmsg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// name of template function/class..
|
||||
const std::string name(tok->strAt(namepos));
|
||||
|
||||
const bool isfunc(tok->strAt(namepos + 1) == "(");
|
||||
|
||||
// locate template usage..
|
||||
std::string::size_type amountOftemplateInstantiations = templateInstantiations.size();
|
||||
unsigned int recursiveCount = 0;
|
||||
|
||||
for (std::list<Token *>::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) {
|
||||
if (amountOftemplateInstantiations != templateInstantiations.size()) {
|
||||
amountOftemplateInstantiations = templateInstantiations.size();
|
||||
simplifyCalculations();
|
||||
++recursiveCount;
|
||||
if (recursiveCount > 100) {
|
||||
// bail out..
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Token * const tok2 = *iter2;
|
||||
if (tok2->str() != name)
|
||||
continue;
|
||||
|
||||
if (Token::Match(tok2->previous(), "[;{}=]") &&
|
||||
!TemplateSimplifier::simplifyTemplatesInstantiateMatch(*iter2, name, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %var%"))
|
||||
continue;
|
||||
|
||||
// New type..
|
||||
std::vector<const Token *> typesUsedInTemplateInstantion;
|
||||
std::string typeForNewNameStr;
|
||||
std::string templateMatchPattern(name + " < ");
|
||||
for (const Token *tok3 = tok2->tokAt(2); tok3 && tok3->str() != ">"; tok3 = tok3->next()) {
|
||||
// #2648 - unhandled parenthesis => bail out
|
||||
// #2721 - unhandled [ => bail out
|
||||
if (tok3->str() == "(" || tok3->str() == "[") {
|
||||
typeForNewNameStr.clear();
|
||||
break;
|
||||
}
|
||||
if (!tok3->next()) {
|
||||
typeForNewNameStr.clear();
|
||||
break;
|
||||
}
|
||||
templateMatchPattern += tok3->str();
|
||||
templateMatchPattern += " ";
|
||||
if (Token::Match(tok3->previous(), "[<,]"))
|
||||
typesUsedInTemplateInstantion.push_back(tok3);
|
||||
// add additional type information
|
||||
if (tok3->isUnsigned())
|
||||
typeForNewNameStr += "unsigned";
|
||||
else if (tok3->isSigned())
|
||||
typeForNewNameStr += "signed";
|
||||
if (tok3->isLong())
|
||||
typeForNewNameStr += "long";
|
||||
typeForNewNameStr += tok3->str();
|
||||
}
|
||||
templateMatchPattern += ">";
|
||||
const std::string typeForNewName(typeForNewNameStr);
|
||||
|
||||
if (typeForNewName.empty() || typeParametersInDeclaration.size() != typesUsedInTemplateInstantion.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",
|
||||
false);
|
||||
|
||||
_errorLogger->reportErr(errmsg);
|
||||
}
|
||||
if (typeForNewName.empty())
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
// New classname/funcname..
|
||||
const std::string newName(name + "<" + typeForNewName + ">");
|
||||
|
||||
if (expandedtemplates.find(newName) == expandedtemplates.end()) {
|
||||
expandedtemplates.insert(newName);
|
||||
TemplateSimplifier::simplifyTemplatesExpandTemplate(_tokens,&_tokensBack, tok,name,typeParametersInDeclaration,newName,typesUsedInTemplateInstantion,templateInstantiations);
|
||||
}
|
||||
|
||||
// Replace all these template usages..
|
||||
std::list< std::pair<Token *, Token *> > removeTokens;
|
||||
for (Token *tok4 = tok2; tok4; tok4 = tok4->next()) {
|
||||
if (Token::simpleMatch(tok4, templateMatchPattern.c_str())) {
|
||||
Token * tok5 = tok4->tokAt(2);
|
||||
unsigned int typeCountInInstantion = 1U; // There is always atleast one type
|
||||
const Token *typetok = (!typesUsedInTemplateInstantion.empty()) ? typesUsedInTemplateInstantion[0] : 0;
|
||||
while (tok5 && tok5->str() != ">") {
|
||||
if (tok5->str() != ",") {
|
||||
if (!typetok ||
|
||||
tok5->isUnsigned() != typetok->isUnsigned() ||
|
||||
tok5->isSigned() != typetok->isSigned() ||
|
||||
tok5->isLong() != typetok->isLong()) {
|
||||
break;
|
||||
}
|
||||
|
||||
typetok = typetok ? typetok->next() : 0;
|
||||
} else {
|
||||
typetok = (typeCountInInstantion < typesUsedInTemplateInstantion.size()) ? typesUsedInTemplateInstantion[typeCountInInstantion] : 0;
|
||||
++typeCountInInstantion;
|
||||
}
|
||||
tok5 = tok5->next();
|
||||
}
|
||||
|
||||
// matching template usage => replace tokens..
|
||||
// Foo < int > => Foo<int>
|
||||
if (tok5 && tok5->str() == ">" && typeCountInInstantion == typesUsedInTemplateInstantion.size()) {
|
||||
tok4->str(newName);
|
||||
for (Token *tok6 = tok4->next(); tok6 != tok5; tok6 = tok6->next()) {
|
||||
if (tok6->isName())
|
||||
templateInstantiations.remove(tok6);
|
||||
}
|
||||
removeTokens.push_back(std::pair<Token*,Token*>(tok4, tok5->next()));
|
||||
}
|
||||
|
||||
tok4 = tok5;
|
||||
if (!tok4)
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (!removeTokens.empty()) {
|
||||
Token::eraseTokens(removeTokens.back().first, removeTokens.back().second);
|
||||
removeTokens.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Tokenizer::simplifyTemplates()
|
||||
{
|
||||
|
@ -2934,54 +2756,13 @@ void Tokenizer::simplifyTemplates()
|
|||
}
|
||||
}
|
||||
|
||||
std::set<std::string> expandedtemplates(TemplateSimplifier::simplifyTemplatesExpandSpecialized(_tokens));
|
||||
|
||||
// Locate templates and set member variable _codeWithTemplates if the code has templates.
|
||||
// this info is used by checks
|
||||
std::list<Token *> templates(TemplateSimplifier::simplifyTemplatesGetTemplateDeclarations(_tokens,_codeWithTemplates));
|
||||
|
||||
if (templates.empty()) {
|
||||
TemplateSimplifier::removeTemplates(_tokens);
|
||||
return;
|
||||
}
|
||||
|
||||
// There are templates..
|
||||
// Remove "typename" unless used in template arguments..
|
||||
for (Token *tok = _tokens; tok; tok = tok->next()) {
|
||||
if (tok->str() == "typename")
|
||||
tok->deleteThis();
|
||||
|
||||
if (Token::simpleMatch(tok, "template <")) {
|
||||
while (tok && tok->str() != ">")
|
||||
tok = tok->next();
|
||||
if (!tok)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Locate possible instantiations of templates..
|
||||
std::list<Token *> templateInstantiations(TemplateSimplifier::simplifyTemplatesGetTemplateInstantiations(_tokens));
|
||||
|
||||
// No template instantiations? Then remove all templates.
|
||||
if (templateInstantiations.empty()) {
|
||||
TemplateSimplifier::removeTemplates(_tokens);
|
||||
return;
|
||||
}
|
||||
|
||||
// Template arguments with default values
|
||||
TemplateSimplifier::simplifyTemplatesUseDefaultArgumentValues(templates, templateInstantiations);
|
||||
|
||||
// expand templates
|
||||
//bool done = false;
|
||||
//while (!done)
|
||||
{
|
||||
//done = true;
|
||||
for (std::list<Token *>::reverse_iterator iter1 = templates.rbegin(); iter1 != templates.rend(); ++iter1) {
|
||||
simplifyTemplateInstantions(*iter1, templateInstantiations, expandedtemplates);
|
||||
}
|
||||
}
|
||||
|
||||
TemplateSimplifier::removeTemplates(_tokens);
|
||||
TemplateSimplifier::simplifyTemplates(
|
||||
_tokens,
|
||||
&_tokensBack,
|
||||
_errorLogger,
|
||||
_settings,
|
||||
_files,
|
||||
_codeWithTemplates);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
@ -6868,219 +6649,7 @@ void Tokenizer::simplifyReference()
|
|||
|
||||
bool Tokenizer::simplifyCalculations()
|
||||
{
|
||||
bool ret = false;
|
||||
for (Token *tok = _tokens; tok; tok = tok->next()) {
|
||||
// Remove parentheses around variable..
|
||||
// keep parentheses here: dynamic_cast<Fred *>(p);
|
||||
// keep parentheses here: A operator * (int);
|
||||
// keep parentheses here: int ( * ( * f ) ( ... ) ) (int) ;
|
||||
// keep parentheses here: int ( * * ( * compilerHookVector ) (void) ) ( ) ;
|
||||
// keep parentheses here: operator new [] (size_t);
|
||||
// keep parentheses here: Functor()(a ... )
|
||||
// keep parentheses here: ) ( var ) ;
|
||||
if (Token::Match(tok->next(), "( %var% ) ;|)|,|]|%op%") &&
|
||||
!tok->isName() &&
|
||||
tok->str() != ">" &&
|
||||
tok->str() != "]" &&
|
||||
!Token::simpleMatch(tok->previous(), "operator") &&
|
||||
!Token::simpleMatch(tok->previous(), "* )") &&
|
||||
!Token::simpleMatch(tok->previous(), ") )") &&
|
||||
!Token::Match(tok->tokAt(-2), "* %var% )") &&
|
||||
!Token::Match(tok->tokAt(-2), "%type% ( ) ( %var%") &&
|
||||
!Token::Match(tok, ") ( %var% ) ;")
|
||||
) {
|
||||
tok->deleteNext();
|
||||
tok = tok->next();
|
||||
tok->deleteNext();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (tok->str()[0] == '\'' && tok->str().size() == 3 &&
|
||||
Token::Match(tok->previous(), "(|&&|%oror% %any% ==|!=|<=|<|>=|> %num% &&|%oror%|)")) {
|
||||
tok->str(MathLib::toString(tok->str()[1] & 0xff));
|
||||
}
|
||||
|
||||
if (tok->isNumber()) {
|
||||
if (tok->str() == "0") {
|
||||
if (Token::Match(tok->previous(), "[+-|] 0")) {
|
||||
tok = tok->previous();
|
||||
if (Token::Match(tok->tokAt(-4), "[;{}] %var% = %var% [+-|] 0 ;") &&
|
||||
tok->strAt(-3) == tok->previous()->str()) {
|
||||
tok = tok->tokAt(-3);
|
||||
tok->deleteNext(2);
|
||||
tok->deleteThis();
|
||||
}
|
||||
tok->deleteNext();
|
||||
tok->deleteThis();
|
||||
ret = true;
|
||||
} else if (Token::Match(tok->previous(), "[=([,] 0 [+|]") ||
|
||||
Token::Match(tok->previous(), "return|case 0 [+|]")) {
|
||||
tok->deleteNext();
|
||||
tok->deleteThis();
|
||||
ret = true;
|
||||
} else if (Token::Match(tok->previous(), "[=[(,] 0 * %any% ,|]|)|;|=|%op%") ||
|
||||
Token::Match(tok->previous(), "return|case 0 * %any% ,|:|;|=|%op%")) {
|
||||
tok->deleteNext();
|
||||
if (tok->next()->str() == "(")
|
||||
Token::eraseTokens(tok, tok->next()->link());
|
||||
tok->deleteNext();
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Token::simpleMatch(tok->previous(), "* 1") || Token::simpleMatch(tok, "1 *")) {
|
||||
if (tok->previous()->isOp())
|
||||
tok = tok->previous();
|
||||
tok->deleteNext();
|
||||
tok->deleteThis();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
// Remove parentheses around number..
|
||||
if (Token::Match(tok->tokAt(-2), "%any% ( %num% )") && !tok->tokAt(-2)->isName() && tok->strAt(-2) != ">") {
|
||||
tok = tok->previous();
|
||||
tok->deleteThis();
|
||||
tok->deleteNext();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (Token::simpleMatch(tok->previous(), "( 0 ||") ||
|
||||
Token::simpleMatch(tok->previous(), "|| 0 )") ||
|
||||
Token::simpleMatch(tok->previous(), "( 0 |") ||
|
||||
Token::simpleMatch(tok->previous(), "| 0 )") ||
|
||||
Token::simpleMatch(tok->previous(), "( 1 &&") ||
|
||||
Token::simpleMatch(tok->previous(), "&& 1 )")) {
|
||||
if (tok->previous()->isOp())
|
||||
tok = tok->previous();
|
||||
tok->deleteNext();
|
||||
tok->deleteThis();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (Token::Match(tok, "%num% ==|!=|<=|>=|<|> %num%") &&
|
||||
MathLib::isInt(tok->str()) &&
|
||||
MathLib::isInt(tok->strAt(2))) {
|
||||
if (Token::Match(tok->previous(), "(|&&|%oror%") && Token::Match(tok->tokAt(3), ")|&&|%oror%")) {
|
||||
const MathLib::bigint op1(MathLib::toLongNumber(tok->str()));
|
||||
const std::string &cmp(tok->next()->str());
|
||||
const MathLib::bigint op2(MathLib::toLongNumber(tok->strAt(2)));
|
||||
|
||||
std::string result;
|
||||
|
||||
if (cmp == "==")
|
||||
result = (op1 == op2) ? "1" : "0";
|
||||
else if (cmp == "!=")
|
||||
result = (op1 != op2) ? "1" : "0";
|
||||
else if (cmp == "<=")
|
||||
result = (op1 <= op2) ? "1" : "0";
|
||||
else if (cmp == ">=")
|
||||
result = (op1 >= op2) ? "1" : "0";
|
||||
else if (cmp == "<")
|
||||
result = (op1 < op2) ? "1" : "0";
|
||||
else if (cmp == ">")
|
||||
result = (op1 > op2) ? "1" : "0";
|
||||
|
||||
tok->str(result);
|
||||
tok->deleteNext(2);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Token::Match(tok->previous(), "[([,=] %num% <<|>> %num%")) {
|
||||
const MathLib::bigint op1(MathLib::toLongNumber(tok->str()));
|
||||
const MathLib::bigint op2(MathLib::toLongNumber(tok->strAt(2)));
|
||||
MathLib::bigint result;
|
||||
|
||||
if (tok->next()->str() == "<<")
|
||||
result = op1 << op2;
|
||||
else
|
||||
result = op1 >> op2;
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << result;
|
||||
|
||||
tok->str(ss.str());
|
||||
tok->deleteNext(2);
|
||||
}
|
||||
}
|
||||
|
||||
else if (tok->next() && tok->next()->isNumber()) {
|
||||
// (1-2)
|
||||
while (Token::Match(tok, "[[,(=<>+-*|&^] %num% [+-*/] %num% ]|,|)|;|=|%op%") ||
|
||||
Token::Match(tok, "<< %num% [+-*/] %num% ]|,|)|;|=|%op%") ||
|
||||
Token::Match(tok, "[[,(=<>+-*|&^] %num% [+-*/] %num% <<|>>") ||
|
||||
Token::Match(tok, "<< %num% [+-*/] %num% <<") ||
|
||||
Token::Match(tok, "[(,[] %num% [|&^] %num% [];,);]") ||
|
||||
Token::Match(tok, "(|%op% %num% [+-*/] %num% )|%op%") ||
|
||||
Token::Match(tok,"return|case %num% [+-*/] %num% ;|,|=|:|%op%")) {
|
||||
tok = tok->next();
|
||||
|
||||
// Don't simplify "%num% / 0"
|
||||
if (Token::simpleMatch(tok->next(), "/ 0"))
|
||||
continue;
|
||||
|
||||
// & | ^
|
||||
if (Token::Match(tok->next(), "[&|^]")) {
|
||||
std::string result;
|
||||
const std::string first(tok->str());
|
||||
const std::string second(tok->strAt(2));
|
||||
const char op = tok->next()->str()[0];
|
||||
if (op == '&')
|
||||
result = MathLib::toString<MathLib::bigint>(MathLib::toLongNumber(first) & MathLib::toLongNumber(second));
|
||||
else if (op == '|')
|
||||
result = MathLib::toString<MathLib::bigint>(MathLib::toLongNumber(first) | MathLib::toLongNumber(second));
|
||||
else if (op == '^')
|
||||
result = MathLib::toString<MathLib::bigint>(MathLib::toLongNumber(first) ^ MathLib::toLongNumber(second));
|
||||
|
||||
if (!result.empty()) {
|
||||
ret = true;
|
||||
tok->str(result);
|
||||
tok->deleteNext(2);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Division where result is a whole number
|
||||
if (Token::Match(tok->previous(), "* %num% /") &&
|
||||
tok->str() == MathLib::multiply(tok->strAt(2), MathLib::divide(tok->str(), tok->strAt(2)))) {
|
||||
}
|
||||
|
||||
// + and - are calculated after * and /
|
||||
else if (Token::Match(tok->next(), "[+-/]")) {
|
||||
if (Token::Match(tok->previous(), "[*/%]"))
|
||||
continue;
|
||||
if (Token::Match(tok->tokAt(3), "[*/%]"))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Token::Match(tok->previous(), "- %num% - %num%"))
|
||||
tok->str(MathLib::add(tok->str(), tok->strAt(2)));
|
||||
else if (Token::Match(tok->previous(), "- %num% + %num%"))
|
||||
tok->str(MathLib::subtract(tok->str(), tok->strAt(2)));
|
||||
else {
|
||||
try {
|
||||
tok->str(MathLib::calculate(tok->str(), tok->strAt(2), tok->next()->str()[0]));
|
||||
} catch (InternalError &e) {
|
||||
e.token = tok;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
tok->deleteNext(2);
|
||||
|
||||
// evaluate "2 + 2 - 2 - 2"
|
||||
// as (((2 + 2) - 2) - 2) = 0
|
||||
// instead of ((2 + 2) - (2 - 2)) = 4
|
||||
if (Token::Match(tok->next(), "[+-*/]")) {
|
||||
tok = tok->previous();
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
return TemplateSimplifier::simplifyCalculations(_tokens);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -487,18 +487,6 @@ public:
|
|||
|
||||
void simplifyReservedWordNullptr();
|
||||
|
||||
/**
|
||||
* Simplify templates : expand all instantiatiations for a template
|
||||
* @todo It seems that inner templates should be instantiated recursively
|
||||
* @param tok token where the template declaration begins
|
||||
* @param templateInstantiations a list of template usages (not necessarily just for this template)
|
||||
* @param expandedtemplates all templates that has been expanded so far. The full names are stored.
|
||||
*/
|
||||
void simplifyTemplateInstantions(const Token *tok,
|
||||
std::list<Token *> &templateInstantiations,
|
||||
std::set<std::string> &expandedtemplates);
|
||||
|
||||
|
||||
/**
|
||||
* Simplify e.g. 'atol("0")' into '0'
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue