Cppcheck
templatesimplifier.cpp
Go to the documentation of this file.
00001 /*
00002  * Cppcheck - A tool for static C/C++ code analysis
00003  * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation, either version 3 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include "templatesimplifier.h"
00020 #include "mathlib.h"
00021 #include "token.h"
00022 #include "tokenlist.h"
00023 #include "errorlogger.h"
00024 #include "settings.h"
00025 #include <algorithm>
00026 #include <sstream>
00027 #include <list>
00028 #include <set>
00029 #include <stack>
00030 #include <vector>
00031 #include <string>
00032 #include <cassert>
00033 
00034 //---------------------------------------------------------------------------
00035 
00036 void TemplateSimplifier::cleanupAfterSimplify(Token *tokens)
00037 {
00038     bool goback = false;
00039     for (Token *tok = tokens; tok; tok = tok->next()) {
00040         if (goback) {
00041             tok = tok->previous();
00042             goback = false;
00043         }
00044         if (tok->str() == "(")
00045             tok = tok->link();
00046 
00047         else if (Token::Match(tok, "%type% <") &&
00048                  (!tok->previous() || tok->previous()->str() == ";")) {
00049             const Token *tok2 = tok->tokAt(2);
00050             std::string type;
00051             while (Token::Match(tok2, "%type% ,") || Token::Match(tok2, "%num% ,")) {
00052                 type += tok2->str() + ",";
00053                 tok2 = tok2->tokAt(2);
00054             }
00055             if (Token::Match(tok2, "%type% > (") || Token::Match(tok2, "%num% > (")) {
00056                 type += tok2->str();
00057                 tok->str(tok->str() + "<" + type + ">");
00058                 Token::eraseTokens(tok, tok2->tokAt(2));
00059                 if (tok == tokens)
00060                     goback = true;
00061             }
00062         }
00063     }
00064 }
00065 
00066 
00067 const Token* TemplateSimplifier::hasComplicatedSyntaxErrorsInTemplates(Token *tokens)
00068 {
00069     // check for more complicated syntax errors when using templates..
00070     for (const Token *tok = tokens; tok; tok = tok->next()) {
00071         // skip executing scopes (ticket #3183)..
00072         if (Token::simpleMatch(tok, "( {"))
00073             tok = tok->link();
00074 
00075         // skip executing scopes..
00076         if (Token::simpleMatch(tok, ") {") || Token::Match(tok, ") %var% {") || Token::Match(tok, "[;,=] {")) {
00077             while (tok->str() != "{")
00078                 tok = tok->next();
00079             tok = tok->link();
00080         }
00081 
00082         // skip executing scopes (ticket #1985)..
00083         else if (Token::simpleMatch(tok, "try {")) {
00084             tok = tok->next()->link();
00085             while (Token::simpleMatch(tok, "} catch (")) {
00086                 tok = tok->linkAt(2);
00087                 if (Token::simpleMatch(tok, ") {"))
00088                     tok = tok->next()->link();
00089             }
00090         }
00091 
00092         // not start of statement?
00093         if (tok->previous() && !Token::Match(tok, "[;{}]"))
00094             continue;
00095 
00096         // skip starting tokens.. ;;; typedef typename foo::bar::..
00097         while (Token::Match(tok, "[;{}]"))
00098             tok = tok->next();
00099         while (Token::Match(tok, "typedef|typename"))
00100             tok = tok->next();
00101         while (Token::Match(tok, "%type% ::"))
00102             tok = tok->tokAt(2);
00103         if (!tok)
00104             break;
00105 
00106         // template variable or type..
00107         if (Token::Match(tok, "%type% <")) {
00108             // these are used types..
00109             std::set<std::string> usedtypes;
00110 
00111             // parse this statement and see if the '<' and '>' are matching
00112             unsigned int level = 0;
00113             for (const Token *tok2 = tok; tok2 && !Token::Match(tok2, "[;{}]"); tok2 = tok2->next()) {
00114                 if (tok2->str() == "(")
00115                     tok2 = tok2->link();
00116                 else if (tok2->str() == "<") {
00117                     bool inclevel = false;
00118                     if (Token::simpleMatch(tok2->previous(), "operator <"))
00119                         ;
00120                     else if (level == 0)
00121                         inclevel = true;
00122                     else if (tok2->next() && tok2->next()->isStandardType())
00123                         inclevel = true;
00124                     else if (Token::simpleMatch(tok2, "< typename"))
00125                         inclevel = true;
00126                     else if (Token::Match(tok2->tokAt(-2), "<|, %type% <") && usedtypes.find(tok2->previous()->str()) != usedtypes.end())
00127                         inclevel = true;
00128                     else if (Token::Match(tok2, "< %type%") && usedtypes.find(tok2->next()->str()) != usedtypes.end())
00129                         inclevel = true;
00130                     else if (Token::Match(tok2, "< %type%")) {
00131                         // is the next token a type and not a variable/constant?
00132                         // assume it's a type if there comes another "<"
00133                         const Token *tok3 = tok2->next();
00134                         while (Token::Match(tok3, "%type% ::"))
00135                             tok3 = tok3->tokAt(2);
00136                         if (Token::Match(tok3, "%type% <"))
00137                             inclevel = true;
00138                     }
00139 
00140                     if (inclevel) {
00141                         ++level;
00142                         if (Token::Match(tok2->tokAt(-2), "<|, %type% <"))
00143                             usedtypes.insert(tok2->previous()->str());
00144                     }
00145                 } else if (tok2->str() == ">") {
00146                     if (level > 0)
00147                         --level;
00148                 } else if (tok2->str() == ">>") {
00149                     if (level > 0)
00150                         --level;
00151                     if (level > 0)
00152                         --level;
00153                 }
00154             }
00155             if (level > 0) {
00156 //                syntaxError(tok);
00157                 return tok;
00158             }
00159         }
00160     }
00161 
00162     return 0;
00163 }
00164 
00165 unsigned int TemplateSimplifier::templateParameters(const Token *tok)
00166 {
00167     unsigned int numberOfParameters = 1;
00168 
00169     if (!tok)
00170         return 0;
00171     if (tok->str() != "<")
00172         return 0;
00173     tok = tok->next();
00174 
00175     unsigned int level = 0;
00176 
00177     while (tok) {
00178         // skip const
00179         if (tok->str() == "const")
00180             tok = tok->next();
00181 
00182         // skip struct/union
00183         if (Token::Match(tok, "struct|union"))
00184             tok = tok->next();
00185 
00186         // Skip '&'
00187         if (Token::Match(tok, "& ::| %var%"))
00188             tok = tok->next();
00189 
00190         // skip std::
00191         if (tok && tok->str() == "::")
00192             tok = tok->next();
00193         while (Token::Match(tok, "%var% ::"))
00194             tok = tok->tokAt(2);
00195         if (!tok)
00196             return 0;
00197 
00198         // num/type ..
00199         if (!tok->isNumber() && tok->type() != Token::eChar && !tok->isName())
00200             return 0;
00201         tok = tok->next();
00202         if (!tok)
00203             return 0;
00204 
00205         // * / const
00206         while (Token::Match(tok, "*|&|const"))
00207             tok = tok->next();
00208 
00209         if (!tok)
00210             return 0;
00211 
00212         // Function pointer or prototype..
00213         while (tok && tok->str() == "(")
00214             tok = tok->link()->next();
00215         if (!tok)
00216             return 0;
00217 
00218         // inner template
00219         if (tok->str() == "<") {
00220             ++level;
00221             tok = tok->next();
00222         }
00223 
00224         if (!tok)
00225             return 0;
00226 
00227         // ,/>
00228         while (tok->str() == ">" || tok->str() == ">>") {
00229             if (level == 0)
00230                 return numberOfParameters;
00231             --level;
00232             if (tok->str() == ">>") {
00233                 if (level == 0)
00234                     return numberOfParameters;
00235                 --level;
00236             }
00237             tok = tok->next();
00238 
00239             // * / &
00240             while (Token::Match(tok, "[*&]"))
00241                 tok = tok->next();
00242 
00243             if (!tok)
00244                 return 0;
00245         }
00246 
00247         if (tok->str() != ",")
00248             continue;
00249         if (level == 0)
00250             ++numberOfParameters;
00251         tok = tok->next();
00252     }
00253     return 0;
00254 }
00255 
00256 bool TemplateSimplifier::removeTemplate(Token *tok)
00257 {
00258     if (!Token::simpleMatch(tok, "template <"))
00259         return false;
00260 
00261     int indentlevel = 0;
00262     unsigned int countgt = 0;   // Counter for ">"
00263     for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
00264 
00265         if (tok2->str() == "(") {
00266             tok2 = tok2->link();
00267         } else if (tok2->str() == ")") {  // garbage code! (#3504)
00268             Token::eraseTokens(tok,tok2);
00269             tok->deleteThis();
00270             return false;
00271         }
00272 
00273         else if (tok2->str() == "{") {
00274             tok2 = tok2->link()->next();
00275             Token::eraseTokens(tok, tok2);
00276             if (tok2 && tok2->str() == ";" && tok2->next())
00277                 tok->deleteNext();
00278             tok->deleteThis();
00279             return true;
00280         } else if (tok2->str() == "}") {  // garbage code! (#3449)
00281             Token::eraseTokens(tok,tok2);
00282             tok->deleteThis();
00283             return false;
00284         }
00285 
00286         // Count ">"
00287         if (tok2->str() == ">")
00288             countgt++;
00289 
00290         // don't remove constructor
00291         if (tok2->str() == "explicit" ||
00292             (countgt == 1 && Token::Match(tok2->previous(), "> %type% (") && Token::simpleMatch(tok2->next()->link(), ") {"))) {
00293             Token::eraseTokens(tok, tok2);
00294             tok->deleteThis();
00295             return true;
00296         }
00297 
00298         if (tok2->str() == ";") {
00299             tok2 = tok2->next();
00300             Token::eraseTokens(tok, tok2);
00301             tok->deleteThis();
00302             return true;
00303         }
00304 
00305         if (tok2->str() == "<")
00306             ++indentlevel;
00307 
00308         else if (indentlevel >= 2 && tok2->str() == ">")
00309             --indentlevel;
00310 
00311         else if (Token::Match(tok2, "> class|struct %var% [,)]")) {
00312             tok2 = tok2->next();
00313             Token::eraseTokens(tok, tok2);
00314             tok->deleteThis();
00315             return true;
00316         }
00317     }
00318 
00319     return false;
00320 }
00321 
00322 std::set<std::string> TemplateSimplifier::expandSpecialized(Token *tokens)
00323 {
00324     std::set<std::string> expandedtemplates;
00325 
00326     // Locate specialized templates..
00327     for (Token *tok = tokens; tok; tok = tok->next()) {
00328         if (!Token::simpleMatch(tok, "template < >"))
00329             continue;
00330 
00331         // what kind of template is this?
00332         Token *tok2 = tok->tokAt(3);
00333         while (tok2 && (tok2->isName() || tok2->str() == "*"))
00334             tok2 = tok2->next();
00335 
00336         if (!TemplateSimplifier::templateParameters(tok2))
00337             continue;
00338 
00339         // unknown template.. bail out
00340         if (!tok2->previous()->isName())
00341             continue;
00342 
00343         tok2 = tok2->previous();
00344         std::string s;
00345         {
00346             std::ostringstream ostr;
00347             const Token *tok3 = tok2;
00348             for (; tok3 && tok3->str() != ">"; tok3 = tok3->next()) {
00349                 if (tok3 != tok2)
00350                     ostr << " ";
00351                 ostr << tok3->str();
00352             }
00353             if (!Token::simpleMatch(tok3, "> ("))
00354                 continue;
00355             s = ostr.str();
00356         }
00357 
00358         // save search pattern..
00359         const std::string pattern(s + " > (");
00360 
00361         // remove spaces to create new name
00362         s.erase(std::remove(s.begin(), s.end(), ' '), s.end());
00363         const std::string name(s + ">");
00364         expandedtemplates.insert(name);
00365 
00366         // Rename template..
00367         Token::eraseTokens(tok2, Token::findsimplematch(tok2, "("));
00368         tok2->str(name);
00369 
00370         // delete the "template < >"
00371         tok->deleteNext(2);
00372         tok->deleteThis();
00373 
00374         // Use this special template in the code..
00375         while (NULL != (tok2 = const_cast<Token *>(Token::findmatch(tok2, pattern.c_str())))) {
00376             Token::eraseTokens(tok2, Token::findsimplematch(tok2, "("));
00377             tok2->str(name);
00378         }
00379     }
00380 
00381     return expandedtemplates;
00382 }
00383 
00384 std::list<Token *> TemplateSimplifier::getTemplateDeclarations(Token *tokens, bool &codeWithTemplates)
00385 {
00386     std::list<Token *> templates;
00387     for (Token *tok = tokens; tok; tok = tok->next()) {
00388         // TODO: handle namespaces. Right now we don't instantiate templates that are defined in namespaces.
00389         if (Token::Match(tok, "namespace %type% {"))
00390             tok = tok->linkAt(2);
00391 
00392         if (Token::simpleMatch(tok, "template <")) {
00393             codeWithTemplates = true;
00394 
00395             for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) {
00396                 // Just a declaration => ignore this
00397                 if (tok2->str() == ";")
00398                     break;
00399 
00400                 // Implementation => add to "templates"
00401                 if (tok2->str() == "{") {
00402                     templates.push_back(tok);
00403                     break;
00404                 }
00405             }
00406         }
00407     }
00408     return templates;
00409 }
00410 
00411 
00412 std::list<Token *> TemplateSimplifier::getTemplateInstantiations(Token *tokens)
00413 {
00414     std::list<Token *> used;
00415 
00416     for (Token *tok = tokens; tok; tok = tok->next()) {
00417         // template definition.. skip it
00418         if (Token::simpleMatch(tok, "template <")) {
00419             tok->next()->findClosingBracket(tok);
00420             if (!tok)
00421                 break;
00422         } else if (Token::Match(tok->previous(), "[({};=] %var% <") ||
00423                    Token::Match(tok->tokAt(-2), "[,:] private|protected|public %var% <")) {
00424 
00425             // Add inner template instantiations first => go to the ">"
00426             // and then parse backwards, adding all seen instantiations
00427             const Token *tok2;
00428             tok->next()->findClosingBracket(tok2);
00429 
00430             // parse backwards and add template instantiations
00431             for (; tok2 && tok2 != tok; tok2 = tok2->previous()) {
00432                 if (Token::Match(tok2, ", %var% <") &&
00433                     TemplateSimplifier::templateParameters(tok2->tokAt(2))) {
00434                     used.push_back(tok2->next());
00435                 }
00436             }
00437 
00438             // Add outer template..
00439             if (TemplateSimplifier::templateParameters(tok->next()))
00440                 used.push_back(tok);
00441         }
00442     }
00443 
00444     return used;
00445 }
00446 
00447 
00448 void TemplateSimplifier::useDefaultArgumentValues(const std::list<Token *> &templates,
00449         const std::list<Token *> &templateInstantiations)
00450 {
00451     for (std::list<Token *>::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) {
00452         // template parameters with default value has syntax such as:
00453         //     x = y
00454         // this list will contain all the '=' tokens for such arguments
00455         std::list<Token *> eq;
00456 
00457         // parameter number. 1,2,3,..
00458         std::size_t templatepar = 1;
00459 
00460         // the template classname. This will be empty for template functions
00461         std::string classname;
00462 
00463         // Scan template declaration..
00464         for (Token *tok = *iter1; tok; tok = tok->next()) {
00465             // end of template parameters?
00466             if (tok->str() == ">") {
00467                 if (Token::Match(tok, "> class|struct %var%"))
00468                     classname = tok->strAt(2);
00469                 break;
00470             }
00471 
00472             // next template parameter
00473             if (tok->str() == ",")
00474                 ++templatepar;
00475 
00476             // default parameter value
00477             else if (tok->str() == "=")
00478                 eq.push_back(tok);
00479         }
00480         if (eq.empty() || classname.empty())
00481             continue;
00482 
00483         // iterate through all template instantiations
00484         for (std::list<Token *>::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) {
00485             Token *tok = *iter2;
00486 
00487             if (!Token::Match(tok, (classname + " < %any%").c_str()))
00488                 continue;
00489 
00490             // count the parameters..
00491             unsigned int usedpar = 1;
00492             for (tok = tok->tokAt(3); tok; tok = tok->tokAt(2)) {
00493                 if (tok->str() == ">")
00494                     break;
00495 
00496                 if (tok->str() == ",")
00497                     ++usedpar;
00498 
00499                 else
00500                     break;
00501             }
00502             if (tok && tok->str() == ">") {
00503                 tok = tok->previous();
00504                 std::list<Token *>::const_iterator it = eq.begin();
00505                 for (std::size_t i = (templatepar - eq.size()); it != eq.end() && i < usedpar; ++i)
00506                     ++it;
00507                 while (it != eq.end()) {
00508                     tok->insertToken(",");
00509                     tok = tok->next();
00510                     const Token *from = (*it)->next();
00511                     std::stack<Token *> links;
00512                     while (from && (!links.empty() || (from->str() != "," && from->str() != ">"))) {
00513                         tok->insertToken(from->str());
00514                         tok = tok->next();
00515                         if (Token::Match(tok, "(|["))
00516                             links.push(tok);
00517                         else if (!links.empty() && Token::Match(tok, ")|]")) {
00518                             Token::createMutualLinks(links.top(), tok);
00519                             links.pop();
00520                         }
00521                         from = from->next();
00522                     }
00523                     ++it;
00524                 }
00525             }
00526         }
00527 
00528         for (std::list<Token *>::iterator it = eq.begin(); it != eq.end(); ++it) {
00529             Token * const eqtok = *it;
00530             const Token *tok2;
00531             for (tok2 = eqtok->next(); tok2; tok2 = tok2->next()) {
00532                 if (tok2->str() == "(")
00533                     tok2 = tok2->link();
00534                 else if (tok2->str() == "," || tok2->str() == ">")
00535                     break;
00536             }
00537             Token::eraseTokens(eqtok, tok2);
00538             eqtok->deleteThis();
00539         }
00540     }
00541 }
00542 
00543 bool TemplateSimplifier::instantiateMatch(const Token *instance, const std::string &name, std::size_t numberOfArguments, const char patternAfter[])
00544 {
00545     if (!Token::simpleMatch(instance, (name + " <").c_str()))
00546         return false;
00547 
00548     if (numberOfArguments != TemplateSimplifier::templateParameters(instance->next()))
00549         return false;
00550 
00551     if (patternAfter) {
00552         const Token *tok = Token::findsimplematch(instance, ">");
00553         if (!tok || !Token::Match(tok->next(), patternAfter))
00554             return false;
00555     }
00556 
00557     // nothing mismatching was found..
00558     return true;
00559 }
00560 
00561 int TemplateSimplifier::getTemplateNamePosition(const Token *tok)
00562 {
00563     // get the position of the template name
00564     int namepos = 0;
00565     if (Token::Match(tok, "> class|struct %type% {|:"))
00566         namepos = 2;
00567     else if (Token::Match(tok, "> %type% *|&| %type% ("))
00568         namepos = 2;
00569     else if (Token::Match(tok, "> %type% %type% *|&| %type% ("))
00570         namepos = 3;
00571     else {
00572         // Name not found
00573         return -1;
00574     }
00575     if ((tok->strAt(namepos) == "*" || tok->strAt(namepos) == "&"))
00576         ++namepos;
00577 
00578     return namepos;
00579 }
00580 
00581 
00582 void TemplateSimplifier::expandTemplate(
00583     TokenList& tokenlist,
00584     const Token *tok,
00585     const std::string &name,
00586     std::vector<const Token *> &typeParametersInDeclaration,
00587     const std::string &newName,
00588     std::vector<const Token *> &typesUsedInTemplateInstantiation,
00589     std::list<Token *> &templateInstantiations)
00590 {
00591     for (const Token *tok3 = tokenlist.front(); tok3; tok3 = tok3->next()) {
00592         if (tok3->str() == "{" || tok3->str() == "(")
00593             tok3 = tok3->link();
00594 
00595         // Start of template..
00596         if (tok3 == tok) {
00597             tok3 = tok3->next();
00598         }
00599 
00600         // member function implemented outside class definition
00601         else if (TemplateSimplifier::instantiateMatch(tok3, name, typeParametersInDeclaration.size(), ":: ~| %var% (")) {
00602             tokenlist.addtoken(newName.c_str(), tok3->linenr(), tok3->fileIndex());
00603             while (tok3->str() != "::")
00604                 tok3 = tok3->next();
00605         }
00606 
00607         // not part of template.. go on to next token
00608         else
00609             continue;
00610 
00611         int indentlevel = 0;
00612         std::stack<Token *> brackets; // holds "(", "[" and "{" tokens
00613 
00614         for (; tok3; tok3 = tok3->next()) {
00615             if (tok3->isName()) {
00616                 // search for this token in the type vector
00617                 unsigned int itype = 0;
00618                 while (itype < typeParametersInDeclaration.size() && typeParametersInDeclaration[itype]->str() != tok3->str())
00619                     ++itype;
00620 
00621                 // replace type with given type..
00622                 if (itype < typeParametersInDeclaration.size()) {
00623                     for (const Token *typetok = typesUsedInTemplateInstantiation[itype];
00624                          typetok && !Token::Match(typetok, "[,>]");
00625                          typetok = typetok->next()) {
00626                         tokenlist.addtoken(typetok, tok3->linenr(), tok3->fileIndex());
00627                     }
00628                     continue;
00629                 }
00630             }
00631 
00632             // replace name..
00633             if (Token::Match(tok3, (name + " !!<").c_str())) {
00634                 tokenlist.addtoken(newName.c_str(), tok3->linenr(), tok3->fileIndex());
00635                 continue;
00636             }
00637 
00638             // copy
00639             tokenlist.addtoken(tok3, tok3->linenr(), tok3->fileIndex());
00640             if (Token::Match(tok3, "%type% <")) {
00641                 //if (!Token::simpleMatch(tok3, (name + " <").c_str()))
00642                 //done = false;
00643                 templateInstantiations.push_back(tokenlist.back());
00644             }
00645 
00646             // link() newly tokens manually
00647             else if (tok3->str() == "{") {
00648                 brackets.push(tokenlist.back());
00649                 indentlevel++;
00650             } else if (tok3->str() == "(") {
00651                 brackets.push(tokenlist.back());
00652             } else if (tok3->str() == "[") {
00653                 brackets.push(tokenlist.back());
00654             } else if (tok3->str() == "}") {
00655                 assert(brackets.empty() == false && brackets.top()->str() == "{");
00656                 Token::createMutualLinks(brackets.top(), tokenlist.back());
00657                 brackets.pop();
00658                 if (indentlevel <= 1 && brackets.empty()) {
00659                     // there is a bug if indentlevel is 0
00660                     // the "}" token should only be added if indentlevel is 1 but I add it always intentionally
00661                     // if indentlevel ever becomes 0, cppcheck will write:
00662                     // ### Error: Invalid number of character {
00663                     break;
00664                 }
00665                 --indentlevel;
00666             } else if (tok3->str() == ")") {
00667                 assert(brackets.empty() == false && brackets.top()->str() == "(");
00668                 Token::createMutualLinks(brackets.top(), tokenlist.back());
00669                 brackets.pop();
00670             } else if (tok3->str() == "]") {
00671                 assert(brackets.empty() == false && brackets.top()->str() == "[");
00672                 Token::createMutualLinks(brackets.top(), tokenlist.back());
00673                 brackets.pop();
00674             }
00675         }
00676 
00677         assert(brackets.empty());
00678     }
00679 }
00680 
00681 static bool isLowerThanOr(const Token* lower)
00682 {
00683     return lower->isAssignmentOp() || Token::Match(lower, "}|;|(|[|]|)|,|?|:|%oror%|&&|return|throw|case");
00684 }
00685 static bool isLowerThanXor(const Token* lower)
00686 {
00687     return isLowerThanOr(lower) || lower->str() == "|";
00688 }
00689 static bool isLowerThanAnd(const Token* lower)
00690 {
00691     return isLowerThanXor(lower) || lower->str() == "^";
00692 }
00693 static bool isLowerThanShift(const Token* lower)
00694 {
00695     return isLowerThanAnd(lower) || Token::Match(lower, "%comp%|&");
00696 }
00697 static bool isLowerThanPlusMinus(const Token* lower)
00698 {
00699     return isLowerThanShift(lower) || lower->str() == "<<" || lower->str() == ">>";
00700 }
00701 static bool isLowerThanMulDiv(const Token* lower)
00702 {
00703     return isLowerThanPlusMinus(lower) || lower->str() == "+" || lower->str() == "-";
00704 }
00705 static bool isLowerEqualThanMulDiv(const Token* lower)
00706 {
00707     return isLowerThanMulDiv(lower) || Token::Match(lower, "[*/%]");
00708 }
00709 
00710 
00711 bool TemplateSimplifier::simplifyNumericCalculations(Token *tok)
00712 {
00713     bool ret = false;
00714     // (1-2)
00715     while (tok->tokAt(4) && tok->next()->isNumber() && tok->tokAt(3)->isNumber()) { // %any% %num% %any% %num% %any%
00716         const Token* op = tok->tokAt(2);
00717         const Token* after = tok->tokAt(4);
00718         if (Token::Match(tok, "* %num% /") && tok->next()->str() == MathLib::multiply(tok->strAt(3), MathLib::divide(tok->next()->str(), tok->strAt(3)))) {
00719             // Division where result is a whole number
00720         } else if (!((op->str() == "*" && (isLowerThanMulDiv(tok) || tok->str() == "*") && isLowerEqualThanMulDiv(after)) || // associative
00721                      (Token::Match(op, "[/%]") && isLowerThanMulDiv(tok) && isLowerEqualThanMulDiv(after)) || // NOT associative
00722                      (Token::Match(op, "[+-]") && isLowerThanMulDiv(tok) && isLowerThanMulDiv(after)) || // Only partially (+) associative, but handled later
00723                      (Token::Match(op, ">>|<<") && isLowerThanShift(tok) && isLowerThanPlusMinus(after)) || // NOT associative
00724                      (op->str() == "&" && isLowerThanShift(tok) && isLowerThanShift(after)) || // associative
00725                      (op->str() == "^" && isLowerThanAnd(tok) && isLowerThanAnd(after)) || // associative
00726                      (op->str() == "|" && isLowerThanXor(tok) && isLowerThanXor(after)))) // associative
00727             break;
00728 
00729         tok = tok->next();
00730 
00731         // Don't simplify "%num% / 0"
00732         if (Token::Match(op, "[/%] 0"))
00733             continue;
00734 
00735         // Integer operations
00736         if (Token::Match(op, ">>|<<|&|^|%or%")) {
00737             const char cop = op->str()[0];
00738             const MathLib::bigint leftInt(MathLib::toLongNumber(tok->str()));
00739             const MathLib::bigint rightInt(MathLib::toLongNumber(tok->strAt(2)));
00740             std::string result;
00741 
00742             if (cop == '&' || cop == '|' || cop == '^')
00743                 result = MathLib::calculate(tok->str(), tok->strAt(2), cop);
00744             else if (cop == '<') {
00745                 if (tok->previous()->str() != "<<" && rightInt > 0) // Ensure that its not a shift operator as used for streams
00746                     result = MathLib::longToString(leftInt << rightInt);
00747             } else if (rightInt > 0)
00748                 result = MathLib::longToString(leftInt >> rightInt);
00749 
00750             if (!result.empty()) {
00751                 ret = true;
00752                 tok->str(result);
00753                 tok->deleteNext(2);
00754                 continue;
00755             }
00756         }
00757 
00758         else if (Token::Match(tok->previous(), "- %num% - %num%"))
00759             tok->str(MathLib::add(tok->str(), tok->strAt(2)));
00760         else if (Token::Match(tok->previous(), "- %num% + %num%"))
00761             tok->str(MathLib::subtract(tok->str(), tok->strAt(2)));
00762         else {
00763             try {
00764                 tok->str(MathLib::calculate(tok->str(), tok->strAt(2), op->str()[0]));
00765             } catch (InternalError &e) {
00766                 e.token = tok;
00767                 throw;
00768             }
00769         }
00770 
00771         tok->deleteNext(2);
00772 
00773         ret = true;
00774     }
00775     return ret;
00776 }
00777 
00778 // TODO: This is not the correct class for simplifyCalculations(), so it
00779 // should be moved away.
00780 bool TemplateSimplifier::simplifyCalculations(Token *_tokens)
00781 {
00782     bool ret = false;
00783     for (Token *tok = _tokens; tok; tok = tok->next()) {
00784         // Remove parentheses around variable..
00785         // keep parentheses here: dynamic_cast<Fred *>(p);
00786         // keep parentheses here: A operator * (int);
00787         // keep parentheses here: int ( * ( * f ) ( ... ) ) (int) ;
00788         // keep parentheses here: int ( * * ( * compilerHookVector ) (void) ) ( ) ;
00789         // keep parentheses here: operator new [] (size_t);
00790         // keep parentheses here: Functor()(a ... )
00791         // keep parentheses here: ) ( var ) ;
00792         if ((Token::Match(tok->next(), "( %var% ) ;|)|,|]") ||
00793              (Token::Match(tok->next(), "( %var% ) %cop%") && (tok->tokAt(2)->varId()>0 || !Token::Match(tok->tokAt(4), "[*&]")))) &&
00794             !tok->isName() &&
00795             tok->str() != ">" &&
00796             tok->str() != "]" &&
00797             tok->strAt(-1) != "operator" &&
00798             !Token::simpleMatch(tok->previous(), "* )") &&
00799             !Token::simpleMatch(tok->previous(), ") )") &&
00800             !Token::Match(tok->tokAt(-2), "* %var% )") &&
00801             !Token::Match(tok->tokAt(-2), "%type% ( ) ( %var%") &&
00802             !Token::Match(tok, ") ( %var% ) ;")
00803            ) {
00804             tok->deleteNext();
00805             tok = tok->next();
00806             tok->deleteNext();
00807             ret = true;
00808         }
00809 
00810         if (Token::Match(tok->previous(), "(|&&|%oror% %char% %comp% %num% &&|%oror%|)")) {
00811             tok->str(MathLib::longToString(tok->str()[1] & 0xff));
00812         }
00813 
00814         if (tok->isNumber()) {
00815             // Remove redundant conditions (0&&x) (1||x)
00816             if (Token::Match(tok->previous(), "[(=,] 0 &&") ||
00817                 Token::Match(tok->previous(), "[(=,] 1 ||")) {
00818                 unsigned int par = 0;
00819                 const Token *tok2 = tok;
00820                 for (; tok2; tok2 = tok2->next()) {
00821                     if (tok2->str() == "(")
00822                         ++par;
00823                     else if (tok2->str() == ")") {
00824                         if (par == 0)
00825                             break;
00826                         --par;
00827                     } else if (par == 0 && (Token::Match(tok2, "[,;]")))
00828                         break;
00829                 }
00830                 if (Token::Match(tok2, "[);,]"))
00831                     Token::eraseTokens(tok, tok2);
00832                 continue;
00833             }
00834 
00835             if (tok->str() == "0") {
00836                 if (Token::Match(tok->previous(), "[+-|] 0")) {
00837                     tok = tok->previous();
00838                     if (Token::Match(tok->tokAt(-4), "[;{}] %var% = %var% [+-|] 0 ;") &&
00839                         tok->strAt(-3) == tok->previous()->str()) {
00840                         tok = tok->tokAt(-3);
00841                         tok->deleteNext(2);
00842                         tok->deleteThis();
00843                     }
00844                     tok->deleteNext();
00845                     tok->deleteThis();
00846                     ret = true;
00847                 } else if (Token::Match(tok->previous(), "[=([,] 0 [+|]") ||
00848                            Token::Match(tok->previous(), "return|case 0 [+|]")) {
00849                     tok->deleteNext();
00850                     tok->deleteThis();
00851                     ret = true;
00852                 } else if (Token::Match(tok->previous(), "[=[(,] 0 * %var% ,|]|)|;|=|%cop%") ||
00853                            Token::Match(tok->previous(), "[=[(,] 0 * %num% ,|]|)|;|%op%") ||
00854                            Token::Match(tok->previous(), "[=[(,] 0 * (") ||
00855                            Token::Match(tok->previous(), "return|case 0 *|&& %var% ,|:|;|=|%cop%") ||
00856                            Token::Match(tok->previous(), "return|case 0 *|&& %num% ,|:|;|%op%") ||
00857                            Token::Match(tok->previous(), "return|case 0 *|&& (")) {
00858                     tok->deleteNext();
00859                     if (tok->next()->str() == "(")
00860                         Token::eraseTokens(tok, tok->next()->link());
00861                     tok->deleteNext();
00862                     ret = true;
00863                 } else if (Token::Match(tok->previous(), "[=[(,] 0 && *|& %any% ,|]|)|;|=|%cop%") ||
00864                            Token::Match(tok->previous(), "return|case 0 && *|& %any% ,|:|;|=|%cop%")) {
00865                     tok->deleteNext();
00866                     tok->deleteNext();
00867                     if (tok->next()->str() == "(")
00868                         Token::eraseTokens(tok, tok->next()->link());
00869                     tok->deleteNext();
00870                     ret = true;
00871                 }
00872             }
00873 
00874             if (tok->str() == "1") {
00875                 if (Token::Match(tok->previous(), "[=[(,] 1 %oror% %any% ,|]|)|;|=|%cop%") ||
00876                     Token::Match(tok->previous(), "return|case 1 %oror% %any% ,|:|;|=|%cop%")) {
00877                     tok->deleteNext();
00878                     if (tok->next()->str() == "(")
00879                         Token::eraseTokens(tok, tok->next()->link());
00880                     tok->deleteNext();
00881                     ret = true;
00882                 } else if (Token::Match(tok->previous(), "[=[(,] 1 %oror% *|& %any% ,|]|)|;|=|%cop%") ||
00883                            Token::Match(tok->previous(), "return|case 1 %oror% *|& %any% ,|:|;|=|%cop%")) {
00884                     tok->deleteNext();
00885                     tok->deleteNext();
00886                     if (tok->next()->str() == "(")
00887                         Token::eraseTokens(tok, tok->next()->link());
00888                     tok->deleteNext();
00889                     ret = true;
00890                 }
00891             }
00892 
00893             if (Token::simpleMatch(tok->previous(), "* 1") || Token::simpleMatch(tok, "1 *")) {
00894                 if (tok->previous() && tok->previous()->isConstOp())
00895                     tok = tok->previous();
00896                 tok->deleteNext();
00897                 tok->deleteThis();
00898                 ret = true;
00899             }
00900 
00901             // Remove parentheses around number..
00902             if (Token::Match(tok->tokAt(-2), "%any% ( %num% )") && !tok->tokAt(-2)->isName() && tok->strAt(-2) != ">") {
00903                 tok = tok->previous();
00904                 tok->deleteThis();
00905                 tok->deleteNext();
00906                 ret = true;
00907             }
00908 
00909             if (Token::simpleMatch(tok->previous(), "( 0 ||") ||
00910                 Token::simpleMatch(tok->previous(), "|| 0 )") ||
00911                 Token::simpleMatch(tok->previous(), "( 0 |") ||
00912                 Token::simpleMatch(tok->previous(), "| 0 )") ||
00913                 Token::simpleMatch(tok->previous(), "( 1 &&") ||
00914                 Token::simpleMatch(tok->previous(), "&& 1 )")) {
00915                 if (tok->previous()->isConstOp())
00916                     tok = tok->previous();
00917                 tok->deleteNext();
00918                 tok->deleteThis();
00919                 ret = true;
00920             }
00921 
00922             if (Token::Match(tok, "%num% %comp% %num%") &&
00923                 MathLib::isInt(tok->str()) &&
00924                 MathLib::isInt(tok->strAt(2))) {
00925                 if (Token::Match(tok->previous(), "(|&&|%oror%") && Token::Match(tok->tokAt(3), ")|&&|%oror%")) {
00926                     const MathLib::bigint op1(MathLib::toLongNumber(tok->str()));
00927                     const std::string &cmp(tok->next()->str());
00928                     const MathLib::bigint op2(MathLib::toLongNumber(tok->strAt(2)));
00929 
00930                     std::string result;
00931 
00932                     if (cmp == "==")
00933                         result = (op1 == op2) ? "1" : "0";
00934                     else if (cmp == "!=")
00935                         result = (op1 != op2) ? "1" : "0";
00936                     else if (cmp == "<=")
00937                         result = (op1 <= op2) ? "1" : "0";
00938                     else if (cmp == ">=")
00939                         result = (op1 >= op2) ? "1" : "0";
00940                     else if (cmp == "<")
00941                         result = (op1 < op2) ? "1" : "0";
00942                     else if (cmp == ">")
00943                         result = (op1 > op2) ? "1" : "0";
00944 
00945                     tok->str(result);
00946                     tok->deleteNext(2);
00947                     ret = true;
00948                 }
00949             }
00950         }
00951         // Division where result is a whole number
00952         else if (Token::Match(tok->previous(), "* %num% /") &&
00953                  tok->str() == MathLib::multiply(tok->strAt(2), MathLib::divide(tok->str(), tok->strAt(2)))) {
00954             tok->deleteNext(2);
00955         }
00956 
00957         else {
00958             ret |= simplifyNumericCalculations(tok);
00959         }
00960     }
00961     return ret;
00962 }
00963 
00964 
00965 bool TemplateSimplifier::simplifyTemplateInstantiations(
00966     TokenList& tokenlist,
00967     ErrorLogger& errorlogger,
00968     const Settings *_settings,
00969     const Token *tok,
00970     std::list<Token *> &templateInstantiations,
00971     std::set<std::string> &expandedtemplates)
00972 {
00973     // this variable is not used at the moment. The intention was to
00974     // allow continuous instantiations until all templates has been expanded
00975     //bool done = false;
00976 
00977     // Contains tokens such as "T"
00978     std::vector<const Token *> typeParametersInDeclaration;
00979     for (tok = tok->tokAt(2); tok && tok->str() != ">"; tok = tok->next()) {
00980         if (Token::Match(tok, "%var% ,|>"))
00981             typeParametersInDeclaration.push_back(tok);
00982     }
00983 
00984     // bail out if the end of the file was reached
00985     if (!tok)
00986         return false;
00987 
00988     // get the position of the template name
00989     int namepos = TemplateSimplifier::getTemplateNamePosition(tok);
00990     if (namepos == -1) {
00991         // debug message that we bail out..
00992         if (_settings->debugwarnings) {
00993             std::list<const Token *> callstack(1, tok);
00994             errorlogger.reportErr(ErrorLogger::ErrorMessage(callstack, &tokenlist, Severity::debug, "debug", "simplifyTemplates: bailing out", false));
00995         }
00996         return false;
00997     }
00998 
00999     // name of template function/class..
01000     const std::string name(tok->strAt(namepos));
01001 
01002     const bool isfunc(tok->strAt(namepos + 1) == "(");
01003 
01004     // locate template usage..
01005     std::string::size_type amountOftemplateInstantiations = templateInstantiations.size();
01006     unsigned int recursiveCount = 0;
01007 
01008     bool instantiated = false;
01009 
01010     for (std::list<Token *>::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) {
01011         if (amountOftemplateInstantiations != templateInstantiations.size()) {
01012             amountOftemplateInstantiations = templateInstantiations.size();
01013             simplifyCalculations(tokenlist.front());
01014             ++recursiveCount;
01015             if (recursiveCount > 100) {
01016                 // bail out..
01017                 break;
01018             }
01019         }
01020 
01021         Token * const tok2 = *iter2;
01022         if (tok2->str() != name)
01023             continue;
01024 
01025         if (Token::Match(tok2->previous(), "[;{}=]") &&
01026             !TemplateSimplifier::instantiateMatch(*iter2, name, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %var%"))
01027             continue;
01028 
01029         // New type..
01030         std::vector<const Token *> typesUsedInTemplateInstantiation;
01031         std::string typeForNewNameStr;
01032         std::string templateMatchPattern(name + " < ");
01033         unsigned int indentlevel = 0;
01034         for (const Token *tok3 = tok2->tokAt(2); tok3 && (indentlevel > 0 || tok3->str() != ">"); tok3 = tok3->next()) {
01035             // #2648 - unhandled parentheses => bail out
01036             // #2721 - unhandled [ => bail out
01037             if (tok3->str() == "(" || tok3->str() == "[") {
01038                 typeForNewNameStr.clear();
01039                 break;
01040             }
01041             if (!tok3->next()) {
01042                 typeForNewNameStr.clear();
01043                 break;
01044             }
01045             if (tok3->str() == "<" && templateParameters(tok3) > 0)
01046                 ++indentlevel;
01047             else if (indentlevel > 0 && Token::Match(tok3, "> [,>]"))
01048                 --indentlevel;
01049             templateMatchPattern += tok3->str();
01050             templateMatchPattern += " ";
01051             if (indentlevel == 0 && Token::Match(tok3->previous(), "[<,]"))
01052                 typesUsedInTemplateInstantiation.push_back(tok3);
01053             // add additional type information
01054             if (tok3->isUnsigned())
01055                 typeForNewNameStr += "unsigned";
01056             else if (tok3->isSigned())
01057                 typeForNewNameStr += "signed";
01058             if (tok3->isLong())
01059                 typeForNewNameStr += "long";
01060             typeForNewNameStr += tok3->str();
01061         }
01062         templateMatchPattern += ">";
01063         const std::string typeForNewName(typeForNewNameStr);
01064 
01065         if (typeForNewName.empty() || typeParametersInDeclaration.size() != typesUsedInTemplateInstantiation.size()) {
01066             if (_settings->debugwarnings) {
01067                 std::list<const Token *> callstack(1, tok);
01068                 errorlogger.reportErr(ErrorLogger::ErrorMessage(callstack, &tokenlist, Severity::debug, "debg",
01069                                       "Failed to instantiate template. The checking continues anyway.", false));
01070             }
01071             if (typeForNewName.empty())
01072                 continue;
01073             break;
01074         }
01075 
01076         // New classname/funcname..
01077         const std::string newName(name + "<" + typeForNewName + ">");
01078 
01079         if (expandedtemplates.find(newName) == expandedtemplates.end()) {
01080             expandedtemplates.insert(newName);
01081             TemplateSimplifier::expandTemplate(tokenlist, tok,name,typeParametersInDeclaration,newName,typesUsedInTemplateInstantiation,templateInstantiations);
01082             instantiated = true;
01083         }
01084 
01085         // Replace all these template usages..
01086         std::list< std::pair<Token *, Token *> > removeTokens;
01087         for (Token *tok4 = tok2; tok4; tok4 = tok4->next()) {
01088             if (Token::simpleMatch(tok4, templateMatchPattern.c_str())) {
01089                 Token * tok5 = tok4->tokAt(2);
01090                 unsigned int typeCountInInstantiation = 1U; // There is always at least one type
01091                 const Token *typetok = (!typesUsedInTemplateInstantiation.empty()) ? typesUsedInTemplateInstantiation[0] : 0;
01092                 unsigned int indentlevel5 = 0;  // indentlevel for tok5
01093                 while (tok5 && (indentlevel5 > 0 || tok5->str() != ">")) {
01094                     if (tok5->str() == "<" && templateParameters(tok5) > 0)
01095                         ++indentlevel5;
01096                     else if (indentlevel5 > 0 && Token::Match(tok5, "> [,>]"))
01097                         --indentlevel5;
01098                     else if (indentlevel5 == 0) {
01099                         if (tok5->str() != ",") {
01100                             if (!typetok ||
01101                                 tok5->isUnsigned() != typetok->isUnsigned() ||
01102                                 tok5->isSigned() != typetok->isSigned() ||
01103                                 tok5->isLong() != typetok->isLong()) {
01104                                 break;
01105                             }
01106 
01107                             typetok = typetok ? typetok->next() : 0;
01108                         } else {
01109                             typetok = (typeCountInInstantiation < typesUsedInTemplateInstantiation.size()) ? typesUsedInTemplateInstantiation[typeCountInInstantiation] : 0;
01110                             ++typeCountInInstantiation;
01111                         }
01112                     }
01113                     tok5 = tok5->next();
01114                 }
01115 
01116                 // matching template usage => replace tokens..
01117                 // Foo < int >  =>  Foo<int>
01118                 if (tok5 && tok5->str() == ">" && typeCountInInstantiation == typesUsedInTemplateInstantiation.size()) {
01119                     tok4->str(newName);
01120                     for (Token *tok6 = tok4->next(); tok6 != tok5; tok6 = tok6->next()) {
01121                         if (tok6->isName())
01122                             templateInstantiations.remove(tok6);
01123                     }
01124                     removeTokens.push_back(std::pair<Token*,Token*>(tok4, tok5->next()));
01125                 }
01126 
01127                 tok4 = tok5;
01128                 if (!tok4)
01129                     break;
01130             }
01131         }
01132         while (!removeTokens.empty()) {
01133             Token::eraseTokens(removeTokens.back().first, removeTokens.back().second);
01134             removeTokens.pop_back();
01135         }
01136     }
01137 
01138     // Template has been instantiated .. then remove the template declaration
01139     return instantiated;
01140 }
01141 
01142 
01143 void TemplateSimplifier::simplifyTemplates(
01144     TokenList& tokenlist,
01145     ErrorLogger& errorlogger,
01146     const Settings *_settings,
01147     bool &_codeWithTemplates
01148 )
01149 {
01150 
01151     std::set<std::string> expandedtemplates(TemplateSimplifier::expandSpecialized(tokenlist.front()));
01152 
01153     // Locate templates and set member variable _codeWithTemplates if the code has templates.
01154     // this info is used by checks
01155     std::list<Token *> templates(TemplateSimplifier::getTemplateDeclarations(tokenlist.front(), _codeWithTemplates));
01156 
01157     if (templates.empty())
01158         return;
01159 
01160     // There are templates..
01161     // Remove "typename" unless used in template arguments..
01162     for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
01163         if (tok->str() == "typename")
01164             tok->deleteThis();
01165 
01166         if (Token::simpleMatch(tok, "template <")) {
01167             while (tok && tok->str() != ">")
01168                 tok = tok->next();
01169             if (!tok)
01170                 break;
01171         }
01172     }
01173 
01174     // Locate possible instantiations of templates..
01175     std::list<Token *> templateInstantiations(TemplateSimplifier::getTemplateInstantiations(tokenlist.front()));
01176 
01177     // No template instantiations? Then return.
01178     if (templateInstantiations.empty())
01179         return;
01180 
01181     // Template arguments with default values
01182     TemplateSimplifier::useDefaultArgumentValues(templates, templateInstantiations);
01183 
01184     // expand templates
01185     //bool done = false;
01186     //while (!done)
01187     {
01188         //done = true;
01189         std::list<Token *> templates2;
01190         for (std::list<Token *>::reverse_iterator iter1 = templates.rbegin(); iter1 != templates.rend(); ++iter1) {
01191             bool instantiated = TemplateSimplifier::simplifyTemplateInstantiations(tokenlist,
01192                                 errorlogger,
01193                                 _settings,
01194                                 *iter1,
01195                                 templateInstantiations,
01196                                 expandedtemplates);
01197             if (instantiated)
01198                 templates2.push_back(*iter1);
01199         }
01200 
01201         for (std::list<Token *>::iterator it = templates2.begin(); it != templates2.end(); ++it) {
01202             std::list<Token *>::iterator it1 = std::find(templates.begin(), templates.end(), *it);
01203             if (it1 != templates.end()) {
01204                 templates.erase(it1);
01205                 removeTemplate(*it);
01206             }
01207         }
01208     }
01209 }