diff --git a/Makefile b/Makefile index 8381d583b..7954368a6 100644 --- a/Makefile +++ b/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 diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 3ce8d1391..7e2e84ff9 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -17,7 +17,11 @@ */ #include "templatesimplifier.h" +#include "mathlib.h" +#include "errorlogger.h" #include "token.h" +#include "settings.h" +#include "check.h" #include #include #include @@ -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(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::toLongNumber(first) & MathLib::toLongNumber(second)); + else if (op == '|') + result = MathLib::toString(MathLib::toLongNumber(first) | MathLib::toLongNumber(second)); + else if (op == '^') + result = MathLib::toString(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 &files, + const Token *tok, + std::list &templateInstantiations, + std::set &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 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 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::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 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 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 > 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 + 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(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 &_files, + bool &_codeWithTemplates +) +{ + + std::set expandedtemplates(TemplateSimplifier::simplifyTemplatesExpandSpecialized(_tokens)); + + // Locate templates and set member variable _codeWithTemplates if the code has templates. + // this info is used by checks + std::list 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 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::reverse_iterator iter1 = templates.rbegin(); iter1 != templates.rend(); ++iter1) { + TemplateSimplifier::simplifyTemplateInstantions( + _tokens, + _tokensBack, + _errorLogger, + _settings, + _files, + + *iter1, templateInstantiations, expandedtemplates); + } + } + + TemplateSimplifier::removeTemplates(_tokens); +} diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index fcf4a20ce..71f92dbed 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -28,6 +28,8 @@ #include class Token; +class ErrorLogger; +class Settings; /// @addtogroup Core @@ -120,6 +122,41 @@ public: const std::string &newName, std::vector &typesUsedInTemplateInstantion, std::list &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 &files, + const Token *tok, + std::list &templateInstantiations, + std::set &expandedtemplates); + + /** + * Simplify templates + */ + static void simplifyTemplates( + Token *_tokens, + Token **_tokensBack, + ErrorLogger *_errorLogger, + const Settings *_settings, + const std::vector &_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); }; /// @} diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 00f9b0f8c..77f76d7f7 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2742,184 +2742,6 @@ void Tokenizer::simplifyLabelsCaseDefault() -void Tokenizer::simplifyTemplateInstantions(const Token *tok, - std::list &templateInstantiations, - std::set &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 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 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::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 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 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 > 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 - 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(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 expandedtemplates(TemplateSimplifier::simplifyTemplatesExpandSpecialized(_tokens)); - - // Locate templates and set member variable _codeWithTemplates if the code has templates. - // this info is used by checks - std::list 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 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::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(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::toLongNumber(first) & MathLib::toLongNumber(second)); - else if (op == '|') - result = MathLib::toString(MathLib::toLongNumber(first) | MathLib::toLongNumber(second)); - else if (op == '^') - result = MathLib::toString(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); } diff --git a/lib/tokenize.h b/lib/tokenize.h index 03a41f59e..07f0093d5 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -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 &templateInstantiations, - std::set &expandedtemplates); - - /** * Simplify e.g. 'atol("0")' into '0' */