|
Cppcheck
|
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 }
1.7.6.1