|
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 00020 //--------------------------------------------------------------------------- 00021 #include "tokenize.h" 00022 #include "mathlib.h" 00023 #include "settings.h" 00024 #include "check.h" 00025 #include "path.h" 00026 #include "symboldatabase.h" 00027 #include "templatesimplifier.h" 00028 #include "timer.h" 00029 00030 #include <cstring> 00031 #include <sstream> 00032 #include <cassert> 00033 #include <cctype> 00034 #include <stack> 00035 00036 //--------------------------------------------------------------------------- 00037 00038 Tokenizer::Tokenizer() : 00039 list(0), 00040 _settings(0), 00041 _errorLogger(0), 00042 _symbolDatabase(0), 00043 _varId(0), 00044 _codeWithTemplates(false), //is there any templates? 00045 m_timerResults(NULL) 00046 { 00047 } 00048 00049 Tokenizer::Tokenizer(const Settings *settings, ErrorLogger *errorLogger) : 00050 list(settings), 00051 _settings(settings), 00052 _errorLogger(errorLogger), 00053 _symbolDatabase(0), 00054 _varId(0), 00055 _codeWithTemplates(false), //is there any templates? 00056 m_timerResults(NULL) 00057 { 00058 // make sure settings are specified 00059 assert(_settings); 00060 } 00061 00062 Tokenizer::~Tokenizer() 00063 { 00064 delete _symbolDatabase; 00065 } 00066 00067 00068 //--------------------------------------------------------------------------- 00069 // SizeOfType - gives the size of a type 00070 //--------------------------------------------------------------------------- 00071 00072 unsigned int Tokenizer::sizeOfType(const Token *type) const 00073 { 00074 if (!type || type->str().empty()) 00075 return 0; 00076 00077 if (type->type() == Token::eString) 00078 return static_cast<unsigned int>(Token::getStrLength(type) + 1); 00079 00080 std::map<std::string, unsigned int>::const_iterator it = _typeSize.find(type->str()); 00081 if (it == _typeSize.end()) 00082 return 0; 00083 else if (type->isLong()) { 00084 if (type->str() == "double") 00085 return _settings->sizeof_long_double; 00086 else if (type->str() == "long") 00087 return _settings->sizeof_long_long; 00088 } 00089 00090 return it->second; 00091 } 00092 00093 //--------------------------------------------------------------------------- 00094 00095 Token *Tokenizer::copyTokens(Token *dest, const Token *first, const Token *last, bool one_line) 00096 { 00097 std::stack<Token *> links; 00098 Token *tok2 = dest; 00099 unsigned int linenrs = dest->linenr(); 00100 unsigned int commonFileIndex = dest->fileIndex(); 00101 for (const Token *tok = first; tok != last->next(); tok = tok->next()) { 00102 tok2->insertToken(tok->str()); 00103 tok2 = tok2->next(); 00104 tok2->fileIndex(commonFileIndex); 00105 tok2->linenr(linenrs); 00106 tok2->type(tok->type()); 00107 tok2->isUnsigned(tok->isUnsigned()); 00108 tok2->isSigned(tok->isSigned()); 00109 tok2->isPointerCompare(tok->isPointerCompare()); 00110 tok2->isLong(tok->isLong()); 00111 tok2->isUnused(tok->isUnused()); 00112 tok2->setExpandedMacro(tok->isExpandedMacro()); 00113 tok2->varId(tok->varId()); 00114 00115 // Check for links and fix them up 00116 if (tok2->str() == "(" || tok2->str() == "[" || tok2->str() == "{") 00117 links.push(tok2); 00118 else if (tok2->str() == ")" || tok2->str() == "]" || tok2->str() == "}") { 00119 if (links.empty()) 00120 return tok2; 00121 00122 Token * link = links.top(); 00123 00124 tok2->link(link); 00125 link->link(tok2); 00126 00127 links.pop(); 00128 } 00129 if (!one_line && tok->next()) 00130 linenrs += tok->next()->linenr() - tok->linenr(); 00131 } 00132 return tok2; 00133 } 00134 00135 //--------------------------------------------------------------------------- 00136 00137 void Tokenizer::duplicateTypedefError(const Token *tok1, const Token *tok2, const std::string &type) const 00138 { 00139 if (tok1 && !(_settings->isEnabled("style") && _settings->inconclusive)) 00140 return; 00141 00142 std::list<const Token*> locationList; 00143 locationList.push_back(tok1); 00144 locationList.push_back(tok2); 00145 const std::string tok2_str = tok2 ? tok2->str() : std::string("name"); 00146 00147 reportError(locationList, Severity::style, "variableHidingTypedef", 00148 std::string("The " + type + " '" + tok2_str + "' hides a typedef with the same name."), true); 00149 } 00150 00151 void Tokenizer::duplicateDeclarationError(const Token *tok1, const Token *tok2, const std::string &type) const 00152 { 00153 if (tok1 && !(_settings->isEnabled("style"))) 00154 return; 00155 00156 std::list<const Token*> locationList; 00157 locationList.push_back(tok1); 00158 locationList.push_back(tok2); 00159 const std::string tok2_str = tok2 ? tok2->str() : std::string("name"); 00160 00161 reportError(locationList, Severity::style, "unnecessaryForwardDeclaration", 00162 std::string("The " + type + " '" + tok2_str + "' forward declaration is unnecessary. Type " + type + " is already declared earlier.")); 00163 } 00164 00165 // check if this statement is a duplicate definition 00166 bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name, const Token *typeDef, bool undefinedStruct) const 00167 { 00168 // check for an end of definition 00169 const Token * tok = *tokPtr; 00170 if (tok && Token::Match(tok->next(), ";|,|[|=|)|>|(|{")) { 00171 const Token * end = tok->next(); 00172 00173 if (end->str() == "[") { 00174 end = end->link()->next(); 00175 } else if (end->str() == ",") { 00176 // check for derived class 00177 if (Token::Match(tok->previous(), "public|private|protected")) 00178 return false; 00179 00180 // find end of definition 00181 while (end && end->next() && !Token::Match(end->next(), ";|)|>")) { 00182 if (end->next()->str() == "(") 00183 end = end->linkAt(1); 00184 00185 end = end->next(); 00186 } 00187 if (end) 00188 end = end->next(); 00189 } else if (end->str() == "(") { 00190 if (tok->previous()->str().find("operator") == 0) { 00191 // conversion operator 00192 return false; 00193 } else if (tok->previous()->str() == "typedef") { 00194 // typedef of function returning this type 00195 return false; 00196 } else if (Token::Match(tok->previous(), "public:|private:|protected:")) { 00197 return false; 00198 } else if (tok->previous()->str() == ">") { 00199 if (!Token::Match(tok->tokAt(-2), "%type%")) 00200 return false; 00201 00202 if (!Token::Match(tok->tokAt(-3), ",|<")) 00203 return false; 00204 00205 duplicateTypedefError(*tokPtr, name, "template instantiation"); 00206 *tokPtr = end->link(); 00207 return true; 00208 } 00209 } 00210 00211 if (end) { 00212 if (Token::simpleMatch(end, ") {")) { // function parameter ? 00213 // look backwards 00214 if (Token::Match(tok->previous(), "%type%") && 00215 !Token::Match(tok->previous(), "return|new|const")) { 00216 duplicateTypedefError(*tokPtr, name, "function parameter"); 00217 // duplicate definition so skip entire function 00218 *tokPtr = end->next()->link(); 00219 return true; 00220 } 00221 } else if (end->str() == ">") { // template parameter ? 00222 // look backwards 00223 if (Token::Match(tok->previous(), "%type%") && 00224 !Token::Match(tok->previous(), "return|new|const|volatile")) { 00225 // duplicate definition so skip entire template 00226 while (end && end->str() != "{") 00227 end = end->next(); 00228 if (end) { 00229 duplicateTypedefError(*tokPtr, name, "template parameter"); 00230 *tokPtr = end->link(); 00231 return true; 00232 } 00233 } 00234 } else { 00235 // look backwards 00236 if (Token::Match(tok->previous(), "typedef|}|>") || 00237 (tok->previous()->str() == "*" && tok->next()->str() != "(") || 00238 (Token::Match(tok->previous(), "%type%") && 00239 (!Token::Match(tok->previous(), "return|new|const|friend|public|private|protected|throw|extern") && 00240 !Token::simpleMatch(tok->tokAt(-2), "friend class")))) { 00241 // scan backwards for the end of the previous statement 00242 while (tok && tok->previous() && !Token::Match(tok->previous(), ";|{")) { 00243 if (tok->previous()->str() == "}") { 00244 tok = tok->previous()->link(); 00245 } else if (tok->previous()->str() == "typedef") { 00246 duplicateTypedefError(*tokPtr, name, "typedef"); 00247 return true; 00248 } else if (tok->previous()->str() == "enum") { 00249 duplicateTypedefError(*tokPtr, name, "enum"); 00250 return true; 00251 } else if (tok->previous()->str() == "struct") { 00252 if (tok->strAt(-2) == "typedef" && 00253 tok->next()->str() == "{" && 00254 typeDef->strAt(3) != "{") { 00255 // declaration after forward declaration 00256 return true; 00257 } else if (tok->next()->str() == "{") { 00258 if (!undefinedStruct) 00259 duplicateTypedefError(*tokPtr, name, "struct"); 00260 return true; 00261 } else if (Token::Match(tok->next(), ")|*")) { 00262 return true; 00263 } else if (tok->next()->str() == name->str()) { 00264 return true; 00265 } else if (tok->next()->str() != ";") { 00266 duplicateTypedefError(*tokPtr, name, "struct"); 00267 return true; 00268 } else { 00269 // forward declaration after declaration 00270 duplicateDeclarationError(*tokPtr, name, "struct"); 00271 return false; 00272 } 00273 } else if (tok->previous()->str() == "union") { 00274 if (tok->next()->str() != ";") { 00275 duplicateTypedefError(*tokPtr, name, "union"); 00276 return true; 00277 } else { 00278 // forward declaration after declaration 00279 duplicateDeclarationError(*tokPtr, name, "union"); 00280 return false; 00281 } 00282 } else if (tok->previous()->str() == "class") { 00283 if (tok->next()->str() != ";") { 00284 duplicateTypedefError(*tokPtr, name, "class"); 00285 return true; 00286 } else { 00287 // forward declaration after declaration 00288 duplicateDeclarationError(*tokPtr, name, "class"); 00289 return false; 00290 } 00291 } 00292 00293 tok = tok->previous(); 00294 } 00295 00296 duplicateTypedefError(*tokPtr, name, "variable"); 00297 return true; 00298 } 00299 } 00300 } 00301 } 00302 00303 return false; 00304 } 00305 00306 void Tokenizer::unsupportedTypedef(const Token *tok) const 00307 { 00308 if (!_settings->debugwarnings) 00309 return; 00310 00311 std::ostringstream str; 00312 const Token *tok1 = tok; 00313 unsigned int level = 0; 00314 while (tok) { 00315 if (level == 0 && tok->str() == ";") 00316 break; 00317 else if (tok->str() == "{") 00318 ++level; 00319 else if (tok->str() == "}") { 00320 if (!level) 00321 break; 00322 --level; 00323 } 00324 00325 if (tok != tok1) 00326 str << " "; 00327 str << tok->str(); 00328 tok = tok->next(); 00329 } 00330 if (tok) 00331 str << " ;"; 00332 00333 reportError(tok1, Severity::debug, "debug", 00334 "Failed to parse \'" + str.str() + "\'. The checking continues anyway."); 00335 } 00336 00337 Token * Tokenizer::deleteInvalidTypedef(Token *typeDef) 00338 { 00339 Token *tok = NULL; 00340 00341 // remove typedef but leave ; 00342 while (typeDef->next()) { 00343 if (typeDef->next()->str() == ";") { 00344 typeDef->deleteNext(); 00345 break; 00346 } else if (typeDef->next()->str() == "{") 00347 Token::eraseTokens(typeDef, typeDef->linkAt(1)); 00348 else if (typeDef->next()->str() == "}") 00349 break; 00350 typeDef->deleteNext(); 00351 } 00352 00353 if (typeDef != list.front()) { 00354 tok = typeDef->previous(); 00355 tok->deleteNext(); 00356 } else { 00357 list.front()->deleteThis(); 00358 tok = list.front(); 00359 } 00360 00361 return tok; 00362 } 00363 00364 struct Space { 00365 std::string className; 00366 const Token * classEnd; 00367 bool isNamespace; 00368 }; 00369 00370 static Token *splitDefinitionFromTypedef(Token *tok) 00371 { 00372 Token *tok1; 00373 std::string name; 00374 bool isConst = false; 00375 00376 if (tok->next()->str() == "const") { 00377 tok->deleteNext(); 00378 isConst = true; 00379 } 00380 00381 if (tok->strAt(2) == "{") { // unnamed 00382 tok1 = tok->linkAt(2); 00383 00384 if (tok1 && tok1->next()) { 00385 // use typedef name if available 00386 if (Token::Match(tok1->next(), "%type%")) 00387 name = tok1->next()->str(); 00388 else { // create a unique name 00389 static unsigned int count = 0; 00390 name = "Unnamed" + MathLib::longToString(count++); 00391 } 00392 tok->next()->insertToken(name); 00393 } else 00394 return NULL; 00395 } else if (tok->strAt(3) == ":") { 00396 tok1 = tok->tokAt(4); 00397 while (tok1 && tok1->str() != "{") 00398 tok1 = tok1->next(); 00399 if (!tok1) 00400 return NULL; 00401 00402 tok1 = tok1->link(); 00403 00404 name = tok->strAt(2); 00405 } else { // has a name 00406 tok1 = tok->linkAt(3); 00407 00408 if (!tok1) 00409 return NULL; 00410 00411 name = tok->strAt(2); 00412 } 00413 00414 tok1->insertToken(";"); 00415 tok1 = tok1->next(); 00416 00417 if (tok1->next() && tok1->next()->str() == ";" && tok1->previous()->str() == "}") { 00418 tok->deleteThis(); 00419 tok1->deleteThis(); 00420 return NULL; 00421 } else { 00422 tok1->insertToken("typedef"); 00423 tok1 = tok1->next(); 00424 Token * tok3 = tok1; 00425 if (isConst) { 00426 tok1->insertToken("const"); 00427 tok1 = tok1->next(); 00428 } 00429 tok1->insertToken(tok->next()->str()); // struct, union or enum 00430 tok1 = tok1->next(); 00431 tok1->insertToken(name); 00432 tok->deleteThis(); 00433 tok = tok3; 00434 } 00435 00436 return tok; 00437 } 00438 00439 /* This function is called when processing function related typedefs. 00440 * If simplifyTypedef generates an "Internal Error" message and the 00441 * code that generated it deals in some way with functions, then this 00442 * function will probably need to be extended to handle a new function 00443 * related pattern */ 00444 static Token *processFunc(Token *tok2, bool inOperator) 00445 { 00446 if (tok2->next() && tok2->next()->str() != ")" && 00447 tok2->next()->str() != ",") { 00448 // skip over tokens for some types of canonicalization 00449 if (Token::Match(tok2->next(), "( * %type% ) (")) 00450 tok2 = tok2->linkAt(5); 00451 else if (Token::Match(tok2->next(), "* ( * %type% ) (")) 00452 tok2 = tok2->linkAt(6); 00453 else if (Token::Match(tok2->next(), "* ( * %type% ) ;")) 00454 tok2 = tok2->tokAt(5); 00455 else if (Token::Match(tok2->next(), "* ( %type% [") && 00456 Token::Match(tok2->linkAt(4), "] ) ;|=")) 00457 tok2 = tok2->linkAt(4)->next(); 00458 else if (Token::Match(tok2->next(), "* ( * %type% (")) 00459 tok2 = tok2->linkAt(5)->next(); 00460 else if (Token::simpleMatch(tok2->next(), "* [") && 00461 Token::simpleMatch(tok2->linkAt(2), "] ;")) 00462 tok2 = tok2->next(); 00463 else { 00464 if (tok2->next()->str() == "(") 00465 tok2 = tok2->next()->link(); 00466 else if (!inOperator && !Token::Match(tok2->next(), "[|>|;")) { 00467 tok2 = tok2->next(); 00468 00469 while (Token::Match(tok2, "*|&") && 00470 !Token::Match(tok2->next(), ")|>")) 00471 tok2 = tok2->next(); 00472 00473 // skip over namespace 00474 while (Token::Match(tok2, "%var% ::")) 00475 tok2 = tok2->tokAt(2); 00476 00477 if (!tok2) 00478 return NULL; 00479 00480 if (tok2->str() == "(" && 00481 tok2->link()->next()->str() == "(") { 00482 tok2 = tok2->link(); 00483 00484 if (tok2->next()->str() == "(") 00485 tok2 = tok2->next()->link(); 00486 } 00487 00488 // skip over typedef parameter 00489 if (tok2->next() && tok2->next()->str() == "(") { 00490 tok2 = tok2->next()->link(); 00491 00492 if (tok2->next()->str() == "(") 00493 tok2 = tok2->next()->link(); 00494 } 00495 } 00496 } 00497 } 00498 return tok2; 00499 } 00500 00501 void Tokenizer::simplifyTypedef() 00502 { 00503 std::vector<Space> spaceInfo; 00504 bool isNamespace = false; 00505 std::string className; 00506 bool hasClass = false; 00507 bool goback = false; 00508 for (Token *tok = list.front(); tok; tok = tok->next()) { 00509 if (_errorLogger && !list.getFiles().empty()) 00510 _errorLogger->reportProgress(list.getFiles()[0], "Tokenize (typedef)", tok->progressValue()); 00511 00512 if (goback) { 00513 //jump back once, see the comment at the end of the function 00514 goback = false; 00515 tok = tok->previous(); 00516 } 00517 00518 // Skip typedefs inside parentheses (#2453 and #4002) 00519 if (tok->str() == "(" && tok->strAt(1) == "typedef") { 00520 tok = tok->next(); 00521 continue; 00522 } 00523 00524 if (Token::Match(tok, "class|struct|namespace %any%") && 00525 (!tok->previous() || (tok->previous() && tok->previous()->str() != "enum"))) { 00526 isNamespace = (tok->str() == "namespace"); 00527 hasClass = true; 00528 className = tok->next()->str(); 00529 continue; 00530 } else if (hasClass && tok->str() == ";") { 00531 hasClass = false; 00532 continue; 00533 } else if (hasClass && tok->str() == "{") { 00534 Space info; 00535 info.isNamespace = isNamespace; 00536 info.className = className; 00537 info.classEnd = tok->link(); 00538 spaceInfo.push_back(info); 00539 00540 hasClass = false; 00541 continue; 00542 } else if (!spaceInfo.empty() && tok->str() == "}" && spaceInfo.back().classEnd == tok) { 00543 spaceInfo.pop_back(); 00544 continue; 00545 } else if (tok->str() != "typedef") 00546 continue; 00547 00548 // pull struct, union, enum or class definition out of typedef 00549 // use typedef name for unnamed struct, union, enum or class 00550 if (Token::Match(tok->next(), "const| struct|enum|union|class %type% {") || 00551 Token::Match(tok->next(), "const| struct|enum|union|class {")) { 00552 Token *tok1 = splitDefinitionFromTypedef(tok); 00553 if (!tok1) 00554 continue; 00555 tok = tok1; 00556 } else if (Token::Match(tok->next(), "const| struct|class %type% :")) { 00557 Token *tok1 = tok; 00558 while (tok1 && tok1->str() != ";" && tok1->str() != "{") 00559 tok1 = tok1->next(); 00560 if (tok1 && tok1->str() == "{") { 00561 tok1 = splitDefinitionFromTypedef(tok); 00562 if (!tok1) 00563 continue; 00564 tok = tok1; 00565 } 00566 } 00567 00568 /** @todo add support for union */ 00569 bool undefinedStruct = false; 00570 if (Token::Match(tok, "typedef enum|struct %type% %type% ;") && tok->strAt(2) == tok->strAt(3)) { 00571 if (tok->next()->str() == "enum") { 00572 tok->deleteNext(3); 00573 tok->deleteThis(); 00574 if (tok->next()) 00575 tok->deleteThis(); 00576 //now the next token to process is 'tok', not 'tok->next()'; 00577 goback = true; 00578 continue; 00579 } else { 00580 const std::string pattern("struct " + tok->strAt(2) + " {|:"); 00581 const Token *tok2 = Token::findmatch(list.front(), pattern.c_str(), tok); 00582 if (!tok2) 00583 undefinedStruct = true; 00584 } 00585 } 00586 00587 Token *typeName; 00588 std::list<std::string> pointers; 00589 Token *typeStart = 0; 00590 Token *typeEnd = 0; 00591 Token *argStart = 0; 00592 Token *argEnd = 0; 00593 Token *arrayStart = 0; 00594 Token *arrayEnd = 0; 00595 Token *specStart = 0; 00596 Token *specEnd = 0; 00597 Token *typeDef = tok; 00598 Token *argFuncRetStart = 0; 00599 Token *argFuncRetEnd = 0; 00600 Token *funcStart = 0; 00601 Token *funcEnd = 0; 00602 Token *tokOffset = tok->next(); 00603 bool function = false; 00604 bool functionPtr = false; 00605 bool functionRef = false; 00606 bool functionRetFuncPtr = false; 00607 bool functionPtrRetFuncPtr = false; 00608 bool ptrToArray = false; 00609 bool refToArray = false; 00610 bool ptrMember = false; 00611 bool typeOf = false; 00612 Token *namespaceStart = 0; 00613 Token *namespaceEnd = 0; 00614 00615 // check for invalid input 00616 if (!tok->next()) { 00617 syntaxError(tok); 00618 return; 00619 } 00620 00621 if (tok->next()->str() == "::" || Token::Match(tok->next(), "%type%")) { 00622 typeStart = tok->next(); 00623 00624 while (Token::Match(tokOffset, "const|signed|unsigned|struct|enum %type%") || 00625 (tokOffset->next() && tokOffset->next()->isStandardType())) 00626 tokOffset = tokOffset->next(); 00627 00628 typeEnd = tokOffset; 00629 tokOffset = tokOffset->next(); 00630 00631 bool atEnd = false; 00632 while (!atEnd) { 00633 if (tokOffset && tokOffset->str() == "::") { 00634 typeEnd = tokOffset; 00635 tokOffset = tokOffset->next(); 00636 } 00637 00638 if (Token::Match(tokOffset, "%type%") && 00639 tokOffset->next() && !Token::Match(tokOffset->next(), "[|;|,|(")) { 00640 typeEnd = tokOffset; 00641 tokOffset = tokOffset->next(); 00642 } else if (Token::simpleMatch(tokOffset, "const (")) { 00643 typeEnd = tokOffset; 00644 tokOffset = tokOffset->next(); 00645 atEnd = true; 00646 } else 00647 atEnd = true; 00648 } 00649 } else 00650 continue; // invalid input 00651 00652 // check for invalid input 00653 if (!tokOffset) { 00654 syntaxError(tok); 00655 return; 00656 } 00657 00658 // check for template 00659 if (tokOffset->str() == "<") { 00660 tokOffset->findClosingBracket(typeEnd); 00661 00662 while (typeEnd && Token::Match(typeEnd->next(), ":: %type%")) 00663 typeEnd = typeEnd->tokAt(2); 00664 00665 if (!typeEnd) { 00666 // internal error 00667 return; 00668 } 00669 00670 while (Token::Match(typeEnd->next(), "const|volatile")) 00671 typeEnd = typeEnd->next(); 00672 00673 tok = typeEnd; 00674 tokOffset = tok->next(); 00675 } 00676 00677 // check for pointers and references 00678 while (Token::Match(tokOffset, "*|&|const")) { 00679 pointers.push_back(tokOffset->str()); 00680 tokOffset = tokOffset->next(); 00681 } 00682 00683 // check for invalid input 00684 if (!tokOffset) { 00685 syntaxError(tok); 00686 return; 00687 } 00688 00689 if (Token::Match(tokOffset, "%type%")) { 00690 // found the type name 00691 typeName = tokOffset; 00692 tokOffset = tokOffset->next(); 00693 00694 // check for array 00695 if (tokOffset && tokOffset->str() == "[") { 00696 arrayStart = tokOffset; 00697 00698 bool atEnd = false; 00699 while (!atEnd) { 00700 while (tokOffset->next() && !Token::Match(tokOffset->next(), ";|,")) { 00701 tokOffset = tokOffset->next(); 00702 } 00703 00704 if (!tokOffset->next()) 00705 return; // invalid input 00706 else if (tokOffset->next()->str() == ";") 00707 atEnd = true; 00708 else if (tokOffset->str() == "]") 00709 atEnd = true; 00710 else 00711 tokOffset = tokOffset->next(); 00712 } 00713 00714 arrayEnd = tokOffset; 00715 tokOffset = tokOffset->next(); 00716 } 00717 00718 // check for end or another 00719 if (Token::Match(tokOffset, ";|,")) 00720 tok = tokOffset; 00721 00722 // or a function typedef 00723 else if (tokOffset && tokOffset->str() == "(") { 00724 // unhandled typedef, skip it and continue 00725 if (typeName->str() == "void") { 00726 unsupportedTypedef(typeDef); 00727 tok = deleteInvalidTypedef(typeDef); 00728 if (tok == list.front()) 00729 //now the next token to process is 'tok', not 'tok->next()'; 00730 goback = true; 00731 continue; 00732 } 00733 00734 // unhandled function pointer, skip it and continue 00735 // TODO: handle such typedefs. See ticket #3314 00736 else if (Token::Match(tokOffset, "( %type% ::") && 00737 Token::Match(tokOffset->link()->tokAt(-3), ":: * %var% ) (")) { 00738 unsupportedTypedef(typeDef); 00739 tok = deleteInvalidTypedef(typeDef); 00740 if (tok == list.front()) 00741 //now the next token to process is 'tok', not 'tok->next()'; 00742 goback = true; 00743 continue; 00744 } 00745 00746 // function pointer 00747 else if (Token::Match(tokOffset, "( * %var% ) (")) { 00748 // name token wasn't a name, it was part of the type 00749 typeEnd = typeEnd->next(); 00750 functionPtr = true; 00751 tokOffset = tokOffset->next(); 00752 funcStart = tokOffset; 00753 funcEnd = tokOffset; 00754 tokOffset = tokOffset->tokAt(3); 00755 typeName = tokOffset->tokAt(-2); 00756 argStart = tokOffset; 00757 argEnd = tokOffset->link(); 00758 tok = argEnd->next(); 00759 } 00760 00761 // function 00762 else if (Token::Match(tokOffset->link(), ") const| ;|,")) { 00763 function = true; 00764 if (tokOffset->link()->next()->str() == "const") { 00765 specStart = tokOffset->link()->next(); 00766 specEnd = specStart; 00767 } 00768 argStart = tokOffset; 00769 argEnd = tokOffset->link(); 00770 tok = argEnd->next(); 00771 if (specStart) 00772 tok = tok->next(); 00773 } 00774 00775 // syntax error 00776 else { 00777 syntaxError(tok); 00778 return; 00779 } 00780 } 00781 00782 // unhandled typedef, skip it and continue 00783 else { 00784 unsupportedTypedef(typeDef); 00785 tok = deleteInvalidTypedef(typeDef); 00786 if (tok == list.front()) 00787 //now the next token to process is 'tok', not 'tok->next()'; 00788 goback = true; 00789 continue; 00790 } 00791 } 00792 00793 // typeof: typedef __typeof__ ( ... ) type; 00794 else if (Token::simpleMatch(tokOffset->previous(), "__typeof__ (") && 00795 Token::Match(tokOffset->link(), ") %type% ;")) { 00796 argStart = tokOffset; 00797 argEnd = tokOffset->link(); 00798 typeName = tokOffset->link()->next(); 00799 tok = typeName->next(); 00800 typeOf = true; 00801 } 00802 00803 // function: typedef ... ( .... type )( ... ); 00804 // typedef ... (( .... type )( ... )); 00805 // typedef ... ( * ( .... type )( ... )); 00806 else if ((tokOffset->str() == "(" && 00807 Token::Match(tokOffset->link()->previous(), "%type% ) (") && 00808 Token::Match(tokOffset->link()->next()->link(), ") const|volatile|;")) || 00809 (Token::simpleMatch(tokOffset, "( (") && 00810 Token::Match(tokOffset->next()->link()->previous(), "%type% ) (") && 00811 Token::Match(tokOffset->next()->link()->next()->link(), ") const|volatile| ) ;|,")) || 00812 (Token::simpleMatch(tokOffset, "( * (") && 00813 Token::Match(tokOffset->linkAt(2)->previous(), "%type% ) (") && 00814 Token::Match(tokOffset->linkAt(2)->next()->link(), ") const|volatile| ) ;|,"))) { 00815 if (tokOffset->next()->str() == "(") 00816 tokOffset = tokOffset->next(); 00817 else if (Token::simpleMatch(tokOffset, "( * (")) { 00818 pointers.push_back("*"); 00819 tokOffset = tokOffset->tokAt(2); 00820 } 00821 00822 if (tokOffset->link()->strAt(-2) == "*") 00823 functionPtr = true; 00824 else 00825 function = true; 00826 funcStart = tokOffset->next(); 00827 tokOffset = tokOffset->link(); 00828 funcEnd = tokOffset->tokAt(-2); 00829 typeName = tokOffset->previous(); 00830 argStart = tokOffset->next(); 00831 argEnd = tokOffset->next()->link(); 00832 tok = argEnd->next(); 00833 Token *spec = tok; 00834 if (Token::Match(spec, "const|volatile")) { 00835 specStart = spec; 00836 specEnd = spec; 00837 while (Token::Match(spec->next(), "const|volatile")) { 00838 specEnd = spec->next(); 00839 spec = specEnd; 00840 } 00841 tok = specEnd->next(); 00842 } 00843 if (tok->str() == ")") 00844 tok = tok->next(); 00845 } 00846 00847 else if (Token::Match(tokOffset, "( %type% (")) { 00848 function = true; 00849 if (tokOffset->link()->next()) { 00850 tok = tokOffset->link()->next(); 00851 tokOffset = tokOffset->tokAt(2); 00852 typeName = tokOffset->previous(); 00853 argStart = tokOffset; 00854 argEnd = tokOffset->link(); 00855 } else { 00856 // internal error 00857 continue; 00858 } 00859 } 00860 00861 // pointer to function returning pointer to function 00862 else if (Token::Match(tokOffset, "( * ( * %type% ) (") && 00863 Token::simpleMatch(tokOffset->linkAt(6), ") ) (") && 00864 Token::Match(tokOffset->linkAt(6)->linkAt(2), ") ;|,")) { 00865 functionPtrRetFuncPtr = true; 00866 00867 tokOffset = tokOffset->tokAt(6); 00868 typeName = tokOffset->tokAt(-2); 00869 argStart = tokOffset; 00870 argEnd = tokOffset->link(); 00871 00872 argFuncRetStart = argEnd->tokAt(2); 00873 argFuncRetEnd = argFuncRetStart->link(); 00874 00875 tok = argFuncRetEnd->next(); 00876 } 00877 00878 // function returning pointer to function 00879 else if (Token::Match(tokOffset, "( * %type% (") && 00880 Token::simpleMatch(tokOffset->linkAt(3), ") ) (") && 00881 Token::Match(tokOffset->linkAt(3)->linkAt(2), ") ;|,")) { 00882 functionRetFuncPtr = true; 00883 00884 tokOffset = tokOffset->tokAt(3); 00885 typeName = tokOffset->previous(); 00886 argStart = tokOffset; 00887 argEnd = tokOffset->link(); 00888 00889 argFuncRetStart = argEnd->tokAt(2); 00890 argFuncRetEnd = argFuncRetStart->link(); 00891 00892 tok = argFuncRetEnd->next(); 00893 } else if (Token::Match(tokOffset, "( * ( %type% ) (")) { 00894 functionRetFuncPtr = true; 00895 00896 tokOffset = tokOffset->tokAt(5); 00897 typeName = tokOffset->tokAt(-2); 00898 argStart = tokOffset; 00899 argEnd = tokOffset->link(); 00900 00901 argFuncRetStart = argEnd->tokAt(2); 00902 argFuncRetEnd = argFuncRetStart->link(); 00903 00904 tok = argFuncRetEnd->next(); 00905 } 00906 00907 // pointer/reference to array 00908 else if (Token::Match(tokOffset, "( *|& %type% ) [")) { 00909 ptrToArray = (tokOffset->next()->str() == "*"); 00910 refToArray = (tokOffset->next()->str() == "&"); 00911 tokOffset = tokOffset->tokAt(2); 00912 typeName = tokOffset; 00913 arrayStart = tokOffset->tokAt(2); 00914 arrayEnd = arrayStart->link(); 00915 tok = arrayEnd->next(); 00916 } 00917 00918 // pointer to class member 00919 else if (Token::Match(tokOffset, "( %type% :: * %type% ) ;")) { 00920 tokOffset = tokOffset->tokAt(2); 00921 namespaceStart = tokOffset->previous(); 00922 namespaceEnd = tokOffset; 00923 ptrMember = true; 00924 tokOffset = tokOffset->tokAt(2); 00925 typeName = tokOffset; 00926 tok = tokOffset->tokAt(2); 00927 } 00928 00929 // unhandled typedef, skip it and continue 00930 else { 00931 unsupportedTypedef(typeDef); 00932 tok = deleteInvalidTypedef(typeDef); 00933 if (tok == list.front()) 00934 //now the next token to process is 'tok', not 'tok->next()'; 00935 goback = true; 00936 continue; 00937 } 00938 00939 bool done = false; 00940 bool ok = true; 00941 00942 while (!done) { 00943 std::string pattern = typeName->str(); 00944 int scope = 0; 00945 bool inScope = true; 00946 bool exitThisScope = false; 00947 int exitScope = 0; 00948 bool simplifyType = false; 00949 bool inMemberFunc = false; 00950 int memberScope = 0; 00951 bool globalScope = false; 00952 std::size_t classLevel = spaceInfo.size(); 00953 00954 for (Token *tok2 = tok; tok2; tok2 = tok2->next()) { 00955 // check for end of scope 00956 if (tok2->str() == "}") { 00957 // check for end of member function 00958 if (inMemberFunc) { 00959 --memberScope; 00960 if (memberScope == 0) 00961 inMemberFunc = false; 00962 } 00963 00964 if (classLevel > 0 && tok2 == spaceInfo[classLevel - 1].classEnd) { 00965 --classLevel; 00966 pattern.clear(); 00967 00968 for (std::size_t i = classLevel; i < spaceInfo.size(); ++i) 00969 pattern += (spaceInfo[i].className + " :: "); 00970 00971 pattern += typeName->str(); 00972 } else { 00973 --scope; 00974 if (scope < 0) 00975 inScope = false; 00976 00977 if (exitThisScope) { 00978 if (scope < exitScope) 00979 exitThisScope = false; 00980 } 00981 } 00982 } 00983 00984 // check for operator typedef 00985 /** @todo add support for multi-token operators */ 00986 else if (tok2->str() == "operator" && 00987 tok2->next()->str() == typeName->str() && 00988 tok2->strAt(2) == "(" && 00989 Token::Match(tok2->linkAt(2), ") const| {")) { 00990 // check for qualifier 00991 if (tok2->previous()->str() == "::") { 00992 // check for available and matching class name 00993 if (!spaceInfo.empty() && classLevel < spaceInfo.size() && 00994 tok2->strAt(-2) == spaceInfo[classLevel].className) { 00995 tok2 = tok2->next(); 00996 simplifyType = true; 00997 } 00998 } 00999 } 01000 01001 // check for member functions 01002 else if (Token::Match(tok2, ") const| {")) { 01003 const Token *func = tok2->link()->previous(); 01004 if (!func) 01005 continue; 01006 01007 if (func->previous()) { // Ticket #4239 01008 /** @todo add support for multi-token operators */ 01009 if (func->previous()->str() == "operator") 01010 func = func->previous(); 01011 01012 // check for qualifier 01013 if (func->previous()->str() == "::") { 01014 // check for available and matching class name 01015 if (!spaceInfo.empty() && classLevel < spaceInfo.size() && 01016 func->strAt(-2) == spaceInfo[classLevel].className) { 01017 memberScope = 0; 01018 inMemberFunc = true; 01019 } 01020 } 01021 } 01022 } 01023 01024 // check for entering a new namespace 01025 else if (Token::Match(tok2, "namespace %any% {")) { 01026 if (classLevel < spaceInfo.size() && 01027 spaceInfo[classLevel].isNamespace && 01028 spaceInfo[classLevel].className == tok2->next()->str()) { 01029 ++classLevel; 01030 pattern.clear(); 01031 for (std::size_t i = classLevel; i < spaceInfo.size(); ++i) 01032 pattern += (spaceInfo[i].className + " :: "); 01033 01034 pattern += typeName->str(); 01035 } 01036 ++scope; 01037 } 01038 01039 // check for entering a new scope 01040 else if (tok2->str() == "{") { 01041 // keep track of scopes within member function 01042 if (inMemberFunc) 01043 ++memberScope; 01044 01045 ++scope; 01046 } 01047 01048 // check for typedef that can be substituted 01049 else if (Token::Match(tok2, pattern.c_str()) || 01050 (inMemberFunc && tok2->str() == typeName->str())) { 01051 std::string pattern1; 01052 01053 // member function class variables don't need qualification 01054 if (inMemberFunc && tok2->str() == typeName->str()) 01055 pattern1 = tok2->str(); 01056 else 01057 pattern1 = pattern; 01058 01059 if (pattern1.find("::") != std::string::npos) { // has a "something ::" 01060 if (tok2->strAt(-1) == "::") { 01061 tok2->tokAt(-2)->deleteNext(); 01062 globalScope = true; 01063 } 01064 01065 for (std::size_t i = classLevel; i < spaceInfo.size(); ++i) { 01066 tok2->deleteNext(2); 01067 } 01068 simplifyType = true; 01069 } else if ((inScope && !exitThisScope) || inMemberFunc) { 01070 if (tok2->strAt(-1) == "::") { 01071 // Don't replace this typename if it's preceded by "::" unless it's a namespace 01072 if (!spaceInfo.empty() && (tok2->strAt(-2) == spaceInfo[0].className) && spaceInfo[0].isNamespace) { 01073 tok2->tokAt(-3)->deleteNext(2); 01074 simplifyType = true; 01075 } 01076 } else if (Token::Match(tok2->previous(), "case %type% :")) { 01077 tok2 = tok2->next(); 01078 } else if (duplicateTypedef(&tok2, typeName, typeDef, undefinedStruct)) { 01079 exitScope = scope; 01080 01081 // skip to end of scope if not already there 01082 if (tok2->str() != "}") { 01083 while (tok2->next()) { 01084 if (tok2->next()->str() == "{") 01085 tok2 = tok2->linkAt(1)->previous(); 01086 else if (tok2->next()->str() == "}") 01087 break; 01088 01089 tok2 = tok2->next(); 01090 } 01091 } 01092 } else if (tok2->previous()->str() != ".") { 01093 simplifyType = true; 01094 } 01095 } 01096 } 01097 01098 if (simplifyType) { 01099 // can't simplify 'operator functionPtr ()' and 'functionPtr operator ... ()' 01100 if (functionPtr && (tok2->previous()->str() == "operator" || 01101 tok2->next()->str() == "operator")) { 01102 simplifyType = false; 01103 tok2 = tok2->next(); 01104 continue; 01105 } 01106 01107 // There are 2 categories of typedef substitutions: 01108 // 1. variable declarations that preserve the variable name like 01109 // global, local, and function parameters 01110 // 2. not variable declarations that have no name like derived 01111 // classes, casts, operators, and template parameters 01112 01113 // try to determine which category this substitution is 01114 bool inCast = false; 01115 bool inTemplate = false; 01116 bool inOperator = false; 01117 bool inSizeof = false; 01118 01119 // check for derived class: class A : some_typedef { 01120 bool isDerived = Token::Match(tok2->previous(), "public|protected|private %type% {|,"); 01121 01122 // check for cast: (some_typedef) A or static_cast<some_typedef>(A) 01123 // todo: check for more complicated casts like: (const some_typedef *)A 01124 if ((tok2->previous()->str() == "(" && tok2->next()->str() == ")" && tok2->strAt(-2) != "sizeof") || 01125 (tok2->previous()->str() == "<" && Token::simpleMatch(tok2->next(), "> ("))) 01126 inCast = true; 01127 01128 // check for template parameters: t<some_typedef> t1 01129 else if (Token::Match(tok2->previous(), "<|,") && 01130 Token::Match(tok2->next(), "&|*| &|*| >|,")) 01131 inTemplate = true; 01132 01133 else if (Token::Match(tok2->tokAt(-2), "sizeof ( %type% )")) 01134 inSizeof = true; 01135 01136 // check for operator 01137 if (tok2->strAt(-1) == "operator" || 01138 Token::simpleMatch(tok2->tokAt(-2), "operator const")) 01139 inOperator = true; 01140 01141 // skip over class or struct in derived class declaration 01142 bool structRemoved = false; 01143 if (isDerived && Token::Match(typeStart, "class|struct")) { 01144 if (typeStart->str() == "struct") 01145 structRemoved = true; 01146 typeStart = typeStart->next(); 01147 } 01148 01149 // start substituting at the typedef name by replacing it with the type 01150 tok2->str(typeStart->str()); 01151 01152 // restore qualification if it was removed 01153 if (typeStart->str() == "struct" || structRemoved) { 01154 if (structRemoved) 01155 tok2 = tok2->previous(); 01156 01157 if (globalScope) { 01158 tok2->insertToken("::"); 01159 tok2 = tok2->next(); 01160 } 01161 01162 for (std::size_t i = classLevel; i < spaceInfo.size(); ++i) { 01163 tok2->insertToken(spaceInfo[i].className); 01164 tok2 = tok2->next(); 01165 tok2->insertToken("::"); 01166 tok2 = tok2->next(); 01167 } 01168 } 01169 01170 // add remainder of type 01171 tok2 = copyTokens(tok2, typeStart->next(), typeEnd); 01172 01173 if (!pointers.empty()) { 01174 std::list<std::string>::const_iterator iter; 01175 for (iter = pointers.begin(); iter != pointers.end(); ++iter) { 01176 tok2->insertToken(*iter); 01177 tok2 = tok2->next(); 01178 } 01179 } 01180 01181 if (funcStart && funcEnd) { 01182 tok2->insertToken("("); 01183 tok2 = tok2->next(); 01184 Token *tok3 = tok2; 01185 tok2 = copyTokens(tok2, funcStart, funcEnd); 01186 01187 if (!inCast) 01188 tok2 = processFunc(tok2, inOperator); 01189 01190 if (!tok2) 01191 break; 01192 01193 tok2->insertToken(")"); 01194 tok2 = tok2->next(); 01195 Token::createMutualLinks(tok2, tok3); 01196 01197 tok2 = copyTokens(tok2, argStart, argEnd); 01198 01199 if (specStart) { 01200 Token *spec = specStart; 01201 tok2->insertToken(spec->str()); 01202 tok2 = tok2->next(); 01203 while (spec != specEnd) { 01204 spec = spec->next(); 01205 tok2->insertToken(spec->str()); 01206 tok2 = tok2->next(); 01207 } 01208 } 01209 } 01210 01211 else if (functionPtr || functionRef || function) { 01212 // don't add parentheses around function names because it 01213 // confuses other simplifications 01214 bool needParen = true; 01215 if (!inTemplate && function && tok2->next() && tok2->next()->str() != "*") 01216 needParen = false; 01217 if (needParen) { 01218 tok2->insertToken("("); 01219 tok2 = tok2->next(); 01220 } 01221 Token *tok3 = tok2; 01222 if (namespaceStart) { 01223 const Token *tok4 = namespaceStart; 01224 01225 while (tok4 != namespaceEnd) { 01226 tok2->insertToken(tok4->str()); 01227 tok2 = tok2->next(); 01228 tok4 = tok4->next(); 01229 } 01230 tok2->insertToken(namespaceEnd->str()); 01231 tok2 = tok2->next(); 01232 } 01233 if (functionPtr) { 01234 tok2->insertToken("*"); 01235 tok2 = tok2->next(); 01236 } else if (functionRef) { 01237 tok2->insertToken("&"); 01238 tok2 = tok2->next(); 01239 } 01240 01241 if (!inCast) 01242 tok2 = processFunc(tok2, inOperator); 01243 01244 if (needParen) { 01245 tok2->insertToken(")"); 01246 tok2 = tok2->next(); 01247 Token::createMutualLinks(tok2, tok3); 01248 } 01249 01250 tok2 = copyTokens(tok2, argStart, argEnd); 01251 01252 if (inTemplate) 01253 tok2 = tok2->next(); 01254 01255 if (specStart) { 01256 Token *spec = specStart; 01257 tok2->insertToken(spec->str()); 01258 tok2 = tok2->next(); 01259 while (spec != specEnd) { 01260 spec = spec->next(); 01261 tok2->insertToken(spec->str()); 01262 tok2 = tok2->next(); 01263 } 01264 } 01265 } else if (functionRetFuncPtr || functionPtrRetFuncPtr) { 01266 tok2->insertToken("("); 01267 tok2 = tok2->next(); 01268 Token *tok3 = tok2; 01269 tok2->insertToken("*"); 01270 tok2 = tok2->next(); 01271 01272 Token * tok4 = 0; 01273 if (functionPtrRetFuncPtr) { 01274 tok2->insertToken("("); 01275 tok2 = tok2->next(); 01276 tok4 = tok2; 01277 tok2->insertToken("*"); 01278 tok2 = tok2->next(); 01279 } 01280 01281 // skip over variable name if there 01282 if (!inCast) { 01283 if (tok2->next()->str() != ")") 01284 tok2 = tok2->next(); 01285 } 01286 01287 if (tok4 && functionPtrRetFuncPtr) { 01288 tok2->insertToken(")"); 01289 tok2 = tok2->next(); 01290 Token::createMutualLinks(tok2, tok4); 01291 } 01292 01293 tok2 = copyTokens(tok2, argStart, argEnd); 01294 01295 tok2->insertToken(")"); 01296 tok2 = tok2->next(); 01297 Token::createMutualLinks(tok2, tok3); 01298 01299 tok2 = copyTokens(tok2, argFuncRetStart, argFuncRetEnd); 01300 } else if (ptrToArray || refToArray) { 01301 tok2->insertToken("("); 01302 tok2 = tok2->next(); 01303 Token *tok3 = tok2; 01304 01305 if (ptrToArray) 01306 tok2->insertToken("*"); 01307 else 01308 tok2->insertToken("&"); 01309 tok2 = tok2->next(); 01310 01311 // skip over name 01312 if (tok2->next()->str() != ")") { 01313 if (tok2->next()->str() != "(") 01314 tok2 = tok2->next(); 01315 01316 // check for function and skip over args 01317 if (tok2->next()->str() == "(") 01318 tok2 = tok2->next()->link(); 01319 01320 // check for array 01321 if (tok2->next()->str() == "[") 01322 tok2 = tok2->next()->link(); 01323 } else { 01324 // syntax error 01325 } 01326 01327 tok2->insertToken(")"); 01328 Token::createMutualLinks(tok2->next(), tok3); 01329 } else if (ptrMember) { 01330 if (Token::simpleMatch(tok2, "* (")) { 01331 tok2->insertToken("*"); 01332 tok2 = tok2->next(); 01333 } else { 01334 tok2->insertToken("("); 01335 tok2 = tok2->next(); 01336 Token *tok3 = tok2; 01337 01338 const Token *tok4 = namespaceStart; 01339 01340 while (tok4 != namespaceEnd) { 01341 tok2->insertToken(tok4->str()); 01342 tok2 = tok2->next(); 01343 tok4 = tok4->next(); 01344 } 01345 tok2->insertToken(namespaceEnd->str()); 01346 tok2 = tok2->next(); 01347 01348 tok2->insertToken("*"); 01349 tok2 = tok2->next(); 01350 01351 // skip over name 01352 tok2 = tok2->next(); 01353 01354 tok2->insertToken(")"); 01355 tok2 = tok2->next(); 01356 Token::createMutualLinks(tok2, tok3); 01357 } 01358 } else if (typeOf) { 01359 tok2 = copyTokens(tok2, argStart, argEnd); 01360 } else if (tok2->tokAt(2) && tok2->strAt(2) == "[") { 01361 while (tok2->tokAt(2) && tok2->strAt(2) == "[") 01362 tok2 = tok2->linkAt(2)->previous(); 01363 } 01364 01365 if (arrayStart && arrayEnd) { 01366 do { 01367 if (!tok2->next()) { 01368 syntaxError(tok2); 01369 return; // can't recover so quit 01370 } 01371 01372 if (!inCast && !inSizeof) 01373 tok2 = tok2->next(); 01374 01375 // reference to array? 01376 if (tok2->str() == "&") { 01377 tok2 = tok2->previous(); 01378 tok2->insertToken("("); 01379 Token *tok3 = tok2->next(); 01380 01381 // handle missing variable name 01382 if (tok2->strAt(3) == ")" || tok2->strAt(3) == ",") 01383 tok2 = tok2->tokAt(2); 01384 else 01385 tok2 = tok2->tokAt(3); 01386 01387 tok2->insertToken(")"); 01388 tok2 = tok2->next(); 01389 Token::createMutualLinks(tok2, tok3); 01390 } 01391 01392 if (!tok2->next()) { 01393 syntaxError(tok2); 01394 return; // can't recover so quit 01395 } 01396 01397 tok2 = copyTokens(tok2, arrayStart, arrayEnd); 01398 tok2 = tok2->next(); 01399 01400 if (tok2->str() == "=") { 01401 if (tok2->next()->str() == "{") 01402 tok2 = tok2->next()->link()->next(); 01403 else if (tok2->next()->str().at(0) == '\"') 01404 tok2 = tok2->tokAt(2); 01405 } 01406 } while (Token::Match(tok2, ", %var% ;|'|=|,")); 01407 } 01408 01409 simplifyType = false; 01410 } 01411 } 01412 01413 if (tok->str() == ";") 01414 done = true; 01415 else if (tok->str() == ",") { 01416 arrayStart = 0; 01417 arrayEnd = 0; 01418 tokOffset = tok->next(); 01419 pointers.clear(); 01420 01421 while (Token::Match(tokOffset, "*|&")) { 01422 pointers.push_back(tokOffset->str()); 01423 tokOffset = tokOffset->next(); 01424 } 01425 01426 if (Token::Match(tokOffset, "%type%")) { 01427 typeName = tokOffset; 01428 tokOffset = tokOffset->next(); 01429 01430 if (tokOffset && tokOffset->str() == "[") { 01431 arrayStart = tokOffset; 01432 01433 bool atEnd = false; 01434 while (!atEnd) { 01435 while (tokOffset->next() && !Token::Match(tokOffset->next(), ";|,")) 01436 tokOffset = tokOffset->next(); 01437 01438 if (!tokOffset->next()) 01439 return; // invalid input 01440 else if (tokOffset->next()->str() == ";") 01441 atEnd = true; 01442 else if (tokOffset->str() == "]") 01443 atEnd = true; 01444 else 01445 tokOffset = tokOffset->next(); 01446 } 01447 01448 arrayEnd = tokOffset; 01449 tokOffset = tokOffset->next(); 01450 } 01451 01452 if (Token::Match(tokOffset, ";|,")) 01453 tok = tokOffset; 01454 else { 01455 // we encountered a typedef we don't support yet so just continue 01456 done = true; 01457 ok = false; 01458 } 01459 } else { 01460 // we encountered a typedef we don't support yet so just continue 01461 done = true; 01462 ok = false; 01463 } 01464 } else { 01465 // something is really wrong (internal error) 01466 done = true; 01467 ok = false; 01468 } 01469 } 01470 01471 if (ok) { 01472 // remove typedef 01473 Token::eraseTokens(typeDef, tok); 01474 01475 if (typeDef != list.front()) { 01476 tok = typeDef->previous(); 01477 tok->deleteNext(); 01478 //no need to remove last token in the list 01479 if (tok->tokAt(2)) 01480 tok->deleteNext(); 01481 } else { 01482 list.front()->deleteThis(); 01483 //no need to remove last token in the list 01484 if (list.front()->next()) 01485 list.front()->deleteThis(); 01486 tok = list.front(); 01487 //now the next token to process is 'tok', not 'tok->next()'; 01488 goback = true; 01489 } 01490 } 01491 } 01492 } 01493 01494 void Tokenizer::simplifyMulAndParens() 01495 { 01496 for (Token *tok = list.front()->tokAt(3); tok; tok = tok->next()) { 01497 if (tok->isName()) { 01498 //fix ticket #2784 - improved by ticket #3184 01499 unsigned int closedpars = 0; 01500 Token *tokend = tok->next(); 01501 Token *tokbegin = tok->previous(); 01502 while (tokend && tokend->str() == ")") { 01503 ++closedpars; 01504 tokend = tokend->next(); 01505 } 01506 if (!tokend || !(tokend->isAssignmentOp())) 01507 continue; 01508 while (tokbegin && (tokbegin->str() == "&" || tokbegin->str() == "(")) { 01509 if (tokbegin->str() == "&") { 01510 if (Token::Match(tokbegin->tokAt(-2), "[;{}&(] *")) { 01511 //remove '* &' 01512 tokbegin = tokbegin->tokAt(-2); 01513 tokbegin->deleteNext(2); 01514 } else if (Token::Match(tokbegin->tokAt(-3), "[;{}&(] * (")) { 01515 if (!closedpars) 01516 break; 01517 --closedpars; 01518 //remove ')' 01519 tok->deleteNext(); 01520 //remove '* ( &' 01521 tokbegin = tokbegin->tokAt(-3); 01522 tokbegin->deleteNext(3); 01523 } else 01524 break; 01525 } else if (tokbegin->str() == "(") { 01526 if (!closedpars) 01527 break; 01528 01529 //find consecutive opening parentheses 01530 unsigned int openpars = 0; 01531 while (tokbegin && tokbegin->str() == "(" && openpars <= closedpars) { 01532 ++openpars; 01533 tokbegin = tokbegin->previous(); 01534 } 01535 if (!tokbegin || openpars > closedpars) 01536 break; 01537 01538 if ((openpars == closedpars && Token::Match(tokbegin, "[;{}]")) || 01539 Token::Match(tokbegin->tokAt(-2), "[;{}&(] * &") || 01540 Token::Match(tokbegin->tokAt(-3), "[;{}&(] * ( &")) { 01541 //remove the excessive parentheses around the variable 01542 while (openpars--) { 01543 tok->deleteNext(); 01544 tokbegin->deleteNext(); 01545 --closedpars; 01546 } 01547 } else 01548 break; 01549 } 01550 } 01551 } 01552 } 01553 } 01554 01555 bool Tokenizer::tokenize(std::istream &code, 01556 const char FileName[], 01557 const std::string &configuration) 01558 { 01559 // make sure settings specified 01560 assert(_settings); 01561 01562 // Fill the map _typeSize.. 01563 fillTypeSizes(); 01564 01565 _configuration = configuration; 01566 01567 if (!list.createTokens(code, Path::getRelativePath(Path::simplifyPath(FileName), _settings->_basePaths))) { 01568 cppcheckError(0); 01569 return false; 01570 } 01571 01572 // if MACRO 01573 for (Token *tok = list.front(); tok; tok = tok->next()) { 01574 if (Token::Match(tok, "if|for|while|BOOST_FOREACH %var% (")) { 01575 if (Token::simpleMatch(tok, "for each")) 01576 // 'for each ( )' -> 'for ( )' 01577 tok->deleteNext(); 01578 else { 01579 syntaxError(tok); 01580 return false; 01581 } 01582 } 01583 } 01584 01585 // remove MACRO in variable declaration: MACRO int x; 01586 removeMacroInVarDecl(); 01587 01588 // Combine strings 01589 combineStrings(); 01590 01591 // replace inline SQL with "asm()" (Oracle PRO*C). Ticket: #1959 01592 simplifySQL(); 01593 01594 // replace __LINE__ macro with line number 01595 simplifyFileAndLineMacro(); 01596 01597 // Concatenate double sharp: 'a ## b' -> 'ab' 01598 concatenateDoubleSharp(); 01599 01600 if (!createLinks()) { 01601 // Source has syntax errors, can't proceed 01602 return false; 01603 } 01604 01605 // replace 'NULL' and similar '0'-defined macros with '0' 01606 simplifyNull(); 01607 01608 // replace 'sin(0)' to '0' and other similar math expressions 01609 simplifyMathExpressions(); 01610 01611 // combine "- %num%" 01612 concatenateNegativeNumberAndAnyPositive(); 01613 01614 // simplify simple calculations 01615 for (Token *tok = list.front() ? list.front()->next() : NULL; tok; tok = tok->next()) { 01616 if (tok->isNumber()) 01617 TemplateSimplifier::simplifyNumericCalculations(tok->previous()); 01618 } 01619 01620 // remove extern "C" and extern "C" {} 01621 if (isCPP()) 01622 simplifyExternC(); 01623 01624 // simplify weird but legal code: "[;{}] ( { code; } ) ;"->"[;{}] code;" 01625 simplifyRoundCurlyParentheses(); 01626 01627 // check for simple syntax errors.. 01628 for (const Token *tok = list.front(); tok; tok = tok->next()) { 01629 if (Token::simpleMatch(tok, "> struct {") && 01630 Token::simpleMatch(tok->linkAt(2), "} ;")) { 01631 syntaxError(tok); 01632 list.deallocateTokens(); 01633 return false; 01634 } 01635 } 01636 01637 if (!simplifyAddBraces()) 01638 return false; 01639 01640 // Combine tokens.. 01641 combineOperators(); 01642 01643 // Simplify: 0[foo] -> *(foo) 01644 for (Token* tok = list.front(); tok; tok = tok->next()) { 01645 if (Token::simpleMatch(tok, "0 [") && tok->linkAt(1)) { 01646 tok->str("*"); 01647 tok->next()->str("("); 01648 tok->linkAt(1)->str(")"); 01649 } 01650 } 01651 01652 // Remove "volatile", "inline", "register", and "restrict" 01653 simplifyKeyword(); 01654 01655 // Convert K&R function declarations to modern C 01656 simplifyVarDecl(true); 01657 if (!simplifyFunctionParameters()) 01658 return false; 01659 01660 // specify array size.. 01661 arraySize(); 01662 01663 // simplify labels and 'case|default'-like syntaxes 01664 if (!simplifyLabelsCaseDefault()) 01665 return false; 01666 01667 // simplify '[;{}] * & ( %any% ) =' to '%any% =' 01668 simplifyMulAndParens(); 01669 01670 // ";a+=b;" => ";a=a+b;" 01671 simplifyCompoundAssignment(); 01672 01673 if (hasComplicatedSyntaxErrorsInTemplates()) { 01674 list.deallocateTokens(); 01675 return false; 01676 } 01677 01678 // Remove __declspec() 01679 simplifyDeclspec(); 01680 01681 // remove some unhandled macros in global scope 01682 removeMacrosInGlobalScope(); 01683 01684 // remove calling conventions __cdecl, __stdcall.. 01685 simplifyCallingConvention(); 01686 01687 // remove __attribute__((?)) 01688 simplifyAttribute(); 01689 01690 // remove unnecessary member qualification.. 01691 removeUnnecessaryQualification(); 01692 01693 // Add std:: in front of std classes, when using namespace std; was given 01694 simplifyNamespaceStd(); 01695 01696 // remove Microsoft MFC.. 01697 simplifyMicrosoftMFC(); 01698 01699 // convert Microsoft memory functions 01700 simplifyMicrosoftMemoryFunctions(); 01701 01702 // convert Microsoft string functions 01703 simplifyMicrosoftStringFunctions(); 01704 01705 // Remove Qt signals and slots 01706 simplifyQtSignalsSlots(); 01707 01708 // remove Borland stuff.. 01709 simplifyBorland(); 01710 01711 // Remove __builtin_expect, likely and unlikely 01712 simplifyBuiltinExpect(); 01713 01714 if (hasEnumsWithTypedef()) { 01715 // #2449: syntax error: enum with typedef in it 01716 list.deallocateTokens(); 01717 return false; 01718 } 01719 01720 simplifyDebugNew(); 01721 01722 // typedef.. 01723 if (m_timerResults) { 01724 Timer t("Tokenizer::tokenize::simplifyTypedef", _settings->_showtime, m_timerResults); 01725 simplifyTypedef(); 01726 } else { 01727 simplifyTypedef(); 01728 } 01729 01730 for (Token* tok = list.front(); tok;) { 01731 if (Token::Match(tok, "union|struct|class union|struct|class")) 01732 tok->deleteNext(); 01733 else 01734 tok = tok->next(); 01735 } 01736 01737 // class x y { 01738 if (_settings->isEnabled("information")) { 01739 for (const Token *tok = list.front(); tok; tok = tok->next()) { 01740 if (Token::Match(tok, "class %type% %type% [:{]")) { 01741 unhandled_macro_class_x_y(tok); 01742 } 01743 } 01744 } 01745 01746 // catch bad typedef canonicalization 01747 // 01748 // to reproduce bad typedef, download upx-ucl from: 01749 // http://packages.debian.org/sid/upx-ucl 01750 // analyse the file src/stub/src/i386-linux.elf.interp-main.c 01751 if (!validate()) { 01752 // Source has syntax errors, can't proceed 01753 return false; 01754 } 01755 01756 // enum.. 01757 simplifyEnum(); 01758 01759 // Remove __asm.. 01760 simplifyAsm(); 01761 01762 // When the assembly code has been cleaned up, no @ is allowed 01763 for (const Token *tok = list.front(); tok; tok = tok->next()) { 01764 if (tok->str() == "(") 01765 tok = tok->link(); 01766 else if (tok->str()[0] == '@') { 01767 list.deallocateTokens(); 01768 return false; 01769 } 01770 } 01771 01772 // convert platform dependent types to standard types 01773 // 32 bits: size_t -> unsigned long 01774 // 64 bits: size_t -> unsigned long long 01775 simplifyPlatformTypes(); 01776 01777 // collapse compound standard types into a single token 01778 // unsigned long long int => long _isUnsigned=true,_isLong=true 01779 simplifyStdType(); 01780 01781 // simplify bit fields.. 01782 simplifyBitfields(); 01783 01784 // Use "<" comparison instead of ">" 01785 simplifyComparisonOrder(); 01786 01787 // Simplify '(p == 0)' to '(!p)' 01788 simplifyIfNot(); 01789 simplifyIfNotNull(); 01790 01791 //simplify for: move out start-statement "for (a;b;c);" => "{ a; for(;b;c); }" 01792 //not enabled because it fails many tests with testrunner. 01793 //@todo fix these fails before enabling this simplification 01794 /*for (Token* tok = list.front(); tok; tok = tok->next()) { 01795 if (tok->str() == "(" && ( !tok->previous() || tok->previous()->str() != "for")) { 01796 tok = tok->link(); 01797 continue; 01798 } 01799 if (!Token::Match(tok->previous(),"[{};] for (")) 01800 continue; 01801 01802 //find the two needed semicolons inside the 'for' 01803 const Token *firstsemicolon = Token::findsimplematch(tok->next(), ";", tok->next()->link()); 01804 if (!firstsemicolon) 01805 continue; 01806 const Token *secondsemicolon = Token::findsimplematch(firstsemicolon->next(), ";", tok->next()->link()); 01807 if (!secondsemicolon) 01808 continue; 01809 if (Token::findsimplematch(secondsemicolon->next(), ";", tok->next()->link())) 01810 continue; //no more than two semicolons! 01811 if (!tok->next()->link()->next()) 01812 continue; //there should be always something after 'for (...)' 01813 01814 Token *fortok = tok; 01815 Token *begin = tok->tokAt(2); 01816 Token *end = tok->next()->link(); 01817 if ( begin->str() != ";" ) { 01818 tok = tok->previous(); 01819 tok->insertToken(";"); 01820 tok->insertToken("{"); 01821 tok = tok->next(); 01822 if (end->next()->str() =="{") { 01823 end = end->next()->link(); 01824 end->insertToken("}"); 01825 Token::createMutualLinks(tok, end->next()); 01826 end = end->link()->previous(); 01827 } else { 01828 if (end->next()->str() != ";") 01829 end->insertToken(";"); 01830 end = end->next(); 01831 end->insertToken("}"); 01832 Token::createMutualLinks(tok, end->next()); 01833 } 01834 end = firstsemicolon->previous(); 01835 Token::move(begin, end, tok); 01836 tok = fortok; 01837 end = fortok->next()->link(); 01838 } 01839 //every 'for' is changed to 'for(;b;c), now it's possible to convert the 'for' to a 'while'. 01840 //precisely, 'for(;b;c){code}'-> 'while(b){code + c;}' 01841 fortok->str("while"); 01842 begin = firstsemicolon->previous(); 01843 begin->deleteNext(); 01844 begin = secondsemicolon->previous(); 01845 begin->deleteNext(); 01846 begin = begin->next(); 01847 if (begin->str() == ")") { //'for(;b;)' -> 'while(b)' 01848 if (begin->previous()->str() == "(") //'for(;;)' -> 'while(true)' 01849 begin->previous()->insertToken("true"); 01850 tok = fortok; 01851 continue; 01852 } 01853 if (end->next()->str() =="{") { 01854 tok = end->next()->link()->previous(); 01855 tok->insertToken(";"); 01856 } else { 01857 tok = end; 01858 if (end->next()->str() != ";") 01859 tok->insertToken(";"); 01860 tok->insertToken("{"); 01861 tok = tok->tokAt(2); 01862 tok->insertToken("}"); 01863 Token::createMutualLinks(tok->previous(), tok->next()); 01864 tok = tok->previous(); 01865 } 01866 end = end->previous(); 01867 Token::move(begin, end, tok); 01868 tok = fortok; 01869 }*/ 01870 01871 simplifyConst(); 01872 01873 // struct simplification "struct S {} s; => struct S { } ; S s ; 01874 simplifyStructDecl(); 01875 01876 // struct initialization (must be used before simplifyVarDecl) 01877 simplifyStructInit(); 01878 01879 // Change initialisation of variable to assignment 01880 simplifyInitVar(); 01881 01882 // Split up variable declarations. 01883 simplifyVarDecl(false); 01884 01885 // specify array size.. needed when arrays are split 01886 arraySize(); 01887 01888 // f(x=g()) => x=g(); f(x) 01889 simplifyAssignmentInFunctionCall(); 01890 01891 // x = ({ 123; }); => { x = 123; } 01892 simplifyAssignmentBlock(); 01893 01894 simplifyVariableMultipleAssign(); 01895 01896 // Remove redundant parentheses 01897 simplifyRedundantParentheses(); 01898 for (Token *tok = list.front(); tok; tok = tok->next()) 01899 while (TemplateSimplifier::simplifyNumericCalculations(tok)) 01900 ; 01901 01902 // Handle templates.. 01903 simplifyTemplates(); 01904 01905 // Simplify templates.. sometimes the "simplifyTemplates" fail and 01906 // then unsimplified function calls etc remain. These have the 01907 // "wrong" syntax. So this function will just fix so that the 01908 // syntax is corrected. 01909 TemplateSimplifier::cleanupAfterSimplify(list.front()); 01910 01911 // Simplify the operator "?:" 01912 simplifyConditionOperator(); 01913 01914 // remove exception specifications.. 01915 removeExceptionSpecifications(); 01916 01917 // Collapse operator name tokens into single token 01918 // operator = => operator= 01919 simplifyOperatorName(); 01920 01921 // Simplify pointer to standard types (C only) 01922 simplifyPointerToStandardType(); 01923 01924 // simplify function pointers 01925 simplifyFunctionPointers(); 01926 01927 // "if (not p)" => "if (!p)" 01928 // "if (p and q)" => "if (p && q)" 01929 // "if (p or q)" => "if (p || q)" 01930 while (simplifyLogicalOperators()) { } 01931 01932 // Change initialisation of variable to assignment 01933 simplifyInitVar(); 01934 01935 // Split up variable declarations. 01936 simplifyVarDecl(false); 01937 01938 if (m_timerResults) { 01939 Timer t("Tokenizer::tokenize::setVarId", _settings->_showtime, m_timerResults); 01940 setVarId(); 01941 } else { 01942 setVarId(); 01943 } 01944 01945 createLinks2(); 01946 01947 // Change initialisation of variable to assignment 01948 simplifyInitVar(); 01949 01950 // Convert e.g. atol("0") into 0 01951 simplifyMathFunctions(); 01952 01953 simplifyDoublePlusAndDoubleMinus(); 01954 01955 simplifyArrayAccessSyntax(); 01956 01957 list.front()->assignProgressValues(); 01958 01959 removeRedundantSemicolons(); 01960 01961 simplifyParameterVoid(); 01962 01963 simplifyRedundantConsecutiveBraces(); 01964 01965 simplifyEmptyNamespaces(); 01966 01967 bool valid = validate(); 01968 if (valid) 01969 createSymbolDatabase(); 01970 return valid; 01971 } 01972 //--------------------------------------------------------------------------- 01973 01974 bool Tokenizer::tokenizeCondition(const std::string &code) 01975 { 01976 assert(_settings); 01977 01978 // Fill the map _typeSize.. 01979 fillTypeSizes(); 01980 01981 { 01982 std::istringstream istr(code); 01983 if (!list.createTokens(istr, "")) { 01984 cppcheckError(0); 01985 return false; 01986 } 01987 } 01988 01989 // Combine strings 01990 combineStrings(); 01991 01992 // Remove "volatile", "inline", "register", and "restrict" 01993 simplifyKeyword(); 01994 01995 // convert platform dependent types to standard types 01996 // 32 bits: size_t -> unsigned long 01997 // 64 bits: size_t -> unsigned long long 01998 simplifyPlatformTypes(); 01999 02000 // collapse compound standard types into a single token 02001 // unsigned long long int => long _isUnsigned=true,_isLong=true 02002 simplifyStdType(); 02003 02004 // Concatenate double sharp: 'a ## b' -> 'ab' 02005 concatenateDoubleSharp(); 02006 02007 if (!createLinks()) { 02008 // Source has syntax errors, can't proceed 02009 return false; 02010 } 02011 02012 // replace 'NULL' and similar '0'-defined macros with '0' 02013 simplifyNull(); 02014 02015 // replace 'sin(0)' to '0' and other similar math expressions 02016 simplifyMathExpressions(); 02017 02018 // combine "- %num%" 02019 concatenateNegativeNumberAndAnyPositive(); 02020 02021 // simplify simple calculations 02022 for (Token *tok = list.front() ? list.front()->next() : NULL; 02023 tok; 02024 tok = tok->next()) { 02025 if (tok->isNumber()) 02026 TemplateSimplifier::simplifyNumericCalculations(tok->previous()); 02027 } 02028 02029 combineOperators(); 02030 02031 simplifyRedundantParentheses(); 02032 for (Token *tok = list.front(); 02033 tok; 02034 tok = tok->next()) 02035 while (TemplateSimplifier::simplifyNumericCalculations(tok)) 02036 ; 02037 02038 while (simplifyLogicalOperators()) { } 02039 02040 // Convert e.g. atol("0") into 0 02041 simplifyMathFunctions(); 02042 02043 simplifyDoublePlusAndDoubleMinus(); 02044 02045 return true; 02046 } 02047 02048 bool Tokenizer::hasComplicatedSyntaxErrorsInTemplates() 02049 { 02050 const Token *tok = TemplateSimplifier::hasComplicatedSyntaxErrorsInTemplates(list.front()); 02051 if (tok) { 02052 syntaxError(tok); 02053 return true; 02054 } 02055 02056 return false; 02057 } 02058 02059 bool Tokenizer::hasEnumsWithTypedef() 02060 { 02061 for (const Token *tok = list.front(); tok; tok = tok->next()) { 02062 if (Token::Match(tok, "enum %var% {")) { 02063 tok = tok->tokAt(2); 02064 const Token *tok2 = Token::findsimplematch(tok, "typedef", tok->link()); 02065 if (tok2) { 02066 syntaxError(tok2); 02067 return true; 02068 } 02069 } 02070 } 02071 02072 return false; 02073 } 02074 02075 void Tokenizer::fillTypeSizes() 02076 { 02077 _typeSize.clear(); 02078 _typeSize["char"] = 1; 02079 _typeSize["bool"] = _settings->sizeof_bool; 02080 _typeSize["short"] = _settings->sizeof_short; 02081 _typeSize["int"] = _settings->sizeof_int; 02082 _typeSize["long"] = _settings->sizeof_long; 02083 _typeSize["float"] = _settings->sizeof_float; 02084 _typeSize["double"] = _settings->sizeof_double; 02085 _typeSize["wchar_t"] = _settings->sizeof_wchar_t; 02086 _typeSize["size_t"] = _settings->sizeof_size_t; 02087 _typeSize["*"] = _settings->sizeof_pointer; 02088 } 02089 02090 void Tokenizer::combineOperators() 02091 { 02092 // Combine tokens.. 02093 for (Token *tok = list.front(); 02094 tok && tok->next(); 02095 tok = tok->next()) { 02096 const char c1 = tok->str()[0]; 02097 02098 if (tok->str().length() == 1 && tok->next()->str().length() == 1) { 02099 const char c2 = tok->next()->str()[0]; 02100 02101 // combine +-*/ and = 02102 if (c2 == '=' && (std::strchr("+-*/%&|^=!<>", c1))) { 02103 tok->str(tok->str() + c2); 02104 tok->deleteNext(); 02105 continue; 02106 } 02107 02108 // replace "->" with "." 02109 else if (c1 == '-' && c2 == '>') { 02110 tok->str("."); 02111 tok->deleteNext(); 02112 continue; 02113 } 02114 } 02115 02116 else if (tok->str() == ">>" && tok->next()->str() == "=") { 02117 tok->str(">>="); 02118 tok->deleteNext(); 02119 } 02120 02121 else if (tok->str() == "<<" && tok->next()->str() == "=") { 02122 tok->str("<<="); 02123 tok->deleteNext(); 02124 } 02125 02126 else if ((c1 == 'p' || c1 == '_') && tok->next()->str() == ":" && tok->strAt(2) != ":") { 02127 if (tok->str() == "private" || tok->str() == "protected" || tok->str() == "public" || tok->str() == "__published") { 02128 tok->str(tok->str() + ":"); 02129 tok->deleteNext(); 02130 continue; 02131 } 02132 } 02133 } 02134 } 02135 02136 void Tokenizer::combineStrings() 02137 { 02138 // Combine wide strings 02139 for (Token *tok = list.front(); 02140 tok; 02141 tok = tok->next()) { 02142 while (tok->str() == "L" && tok->next() && tok->next()->type() == Token::eString) { 02143 // Combine 'L "string"' 02144 tok->str(tok->next()->str()); 02145 tok->deleteNext(); 02146 tok->isLong(true); 02147 } 02148 } 02149 02150 // Combine strings 02151 for (Token *tok = list.front(); 02152 tok; 02153 tok = tok->next()) { 02154 if (tok->str()[0] != '"') 02155 continue; 02156 02157 tok->str(simplifyString(tok->str())); 02158 while (tok->next() && tok->next()->type() == Token::eString) { 02159 tok->next()->str(simplifyString(tok->next()->str())); 02160 02161 // Two strings after each other, combine them 02162 tok->concatStr(tok->next()->str()); 02163 tok->deleteNext(); 02164 } 02165 } 02166 } 02167 02168 void Tokenizer::concatenateDoubleSharp() 02169 { 02170 for (Token *tok = list.front(); tok; tok = tok->next()) { 02171 while (Token::Match(tok, "%num%|%var% ## %num%|%var%")) { 02172 tok->str(tok->str() + tok->strAt(2)); 02173 tok->deleteNext(2); 02174 } 02175 } 02176 } 02177 02178 void Tokenizer::simplifyFileAndLineMacro() 02179 { 02180 for (Token *tok = list.front(); tok; tok = tok->next()) { 02181 if (tok->str() == "__FILE__") 02182 tok->str(list.file(tok)); 02183 else if (tok->str() == "__LINE__") 02184 tok->str(MathLib::longToString(tok->linenr())); 02185 } 02186 } 02187 02188 void Tokenizer::simplifyNull() 02189 { 02190 for (Token *tok = list.front(); tok; tok = tok->next()) { 02191 if (tok->str() == "NULL" && !Token::Match(tok->previous(), "[(,] NULL [,)]")) 02192 tok->str("0"); 02193 else if (tok->str() == "__null" || tok->str() == "'\\0'" || tok->str() == "'\\x0'") 02194 tok->str("0"); 02195 else if (tok->isNumber() && 02196 MathLib::isInt(tok->str()) && 02197 MathLib::toLongNumber(tok->str()) == 0) 02198 tok->str("0"); 02199 } 02200 02201 // nullptr.. 02202 if (isCPP() && _settings->standards.cpp == Standards::CPP11) { 02203 for (Token *tok = list.front(); tok; tok = tok->next()) { 02204 if (tok->str() == "nullptr") 02205 tok->str("0"); 02206 } 02207 } 02208 } 02209 02210 void Tokenizer::concatenateNegativeNumberAndAnyPositive() 02211 { 02212 for (Token *tok = list.front(); tok; tok = tok->next()) { 02213 if (!Token::Match(tok, "?|:|,|(|[|{|return|case|sizeof|%op% +|-") || tok->type() == Token::eIncDecOp) 02214 continue; 02215 if (tok->next()->str() == "+") 02216 tok->deleteNext(); 02217 else if (Token::Match(tok->next(), "- %num%")) { 02218 tok->deleteNext(); 02219 tok->next()->str("-" + tok->next()->str()); 02220 } 02221 } 02222 } 02223 02224 void Tokenizer::simplifyExternC() 02225 { 02226 for (Token *tok = list.front(); tok; tok = tok->next()) { 02227 if (Token::Match(tok, "extern \"C\" {|")) { 02228 if (tok->strAt(2) == "{") { 02229 tok->linkAt(2)->deleteThis(); 02230 tok->deleteNext(2); 02231 } else 02232 tok->deleteNext(); 02233 tok->deleteThis(); 02234 } 02235 } 02236 } 02237 02238 void Tokenizer::simplifyRoundCurlyParentheses() 02239 { 02240 for (Token *tok = list.front(); tok; tok = tok->next()) { 02241 while (Token::Match(tok, "[;{}] ( {") && 02242 Token::simpleMatch(tok->linkAt(2), "} ) ;")) { 02243 tok->linkAt(2)->previous()->deleteNext(3); 02244 tok->deleteNext(2); 02245 } 02246 if (Token::Match(tok, "( { %bool%|%char%|%num%|%str%|%var% ; } )")) { 02247 tok->deleteNext(); 02248 tok->deleteThis(); 02249 tok->deleteNext(3); 02250 } 02251 } 02252 } 02253 02254 void Tokenizer::simplifySQL() 02255 { 02256 for (Token *tok = list.front(); tok; tok = tok->next()) { 02257 if (Token::simpleMatch(tok, "EXEC SQL")) { 02258 const Token *end = tok->tokAt(2); 02259 while (end && end->str() != ";") 02260 end = end->next(); 02261 02262 std::string instruction = tok->stringifyList(end); 02263 // delete all tokens until ';' 02264 Token::eraseTokens(tok, end); 02265 02266 // insert "asm ( "instruction" ) ;" 02267 tok->str("asm"); 02268 // it can happen that 'end' is NULL when wrong code is inserted 02269 if (!tok->next()) 02270 tok->insertToken(";"); 02271 tok->insertToken(")"); 02272 tok->insertToken("\"" + instruction + "\""); 02273 tok->insertToken("("); 02274 // jump to ';' and continue 02275 tok = tok->tokAt(3); 02276 } 02277 } 02278 } 02279 02280 void Tokenizer::simplifyDebugNew() 02281 { 02282 // convert Microsoft DEBUG_NEW macro to new 02283 for (Token *tok = list.front(); tok; tok = tok->next()) { 02284 if (tok->str() == "DEBUG_NEW") 02285 tok->str("new"); 02286 } 02287 } 02288 02289 void Tokenizer::simplifyArrayAccessSyntax() 02290 { 02291 // 0[a] -> a[0] 02292 for (Token *tok = list.front(); tok; tok = tok->next()) { 02293 if (Token::Match(tok, "%num% [ %var% ]")) { 02294 const std::string temp = tok->str(); 02295 tok->str(tok->strAt(2)); 02296 tok->tokAt(2)->str(temp); 02297 } 02298 } 02299 } 02300 02301 void Tokenizer::simplifyParameterVoid() 02302 { 02303 for (Token* tok = list.front(); tok; tok = tok->next()) { 02304 if (Token::Match(tok, "%var% ( void )")) 02305 tok->next()->deleteNext(); 02306 } 02307 } 02308 02309 void Tokenizer::simplifyRedundantConsecutiveBraces() 02310 { 02311 // Remove redundant consecutive braces, i.e. '.. { { .. } } ..' -> '.. { .. } ..'. 02312 for (Token *tok = list.front(); tok;) { 02313 if (Token::simpleMatch(tok, "= {")) { 02314 tok = tok->linkAt(1); 02315 } else if (Token::simpleMatch(tok, "{ {") && Token::simpleMatch(tok->next()->link(), "} }")) { 02316 //remove internal parentheses 02317 tok->next()->link()->deleteThis(); 02318 tok->deleteNext(); 02319 } else 02320 tok = tok->next(); 02321 } 02322 } 02323 02324 void Tokenizer::simplifyDoublePlusAndDoubleMinus() 02325 { 02326 // Convert + + into + and + - into - 02327 for (Token *tok = list.front(); tok; tok = tok->next()) { 02328 while (tok->next()) { 02329 if (tok->str() == "+") { 02330 if (tok->next()->str() == "+") { 02331 tok->deleteNext(); 02332 continue; 02333 } else if (tok->next()->str()[0] == '-') { 02334 tok = tok->next(); 02335 if (tok->str().size() == 1) { 02336 tok = tok->previous(); 02337 tok->str("-"); 02338 tok->deleteNext(); 02339 } else if (tok->isNumber()) { 02340 tok->str(tok->str().substr(1)); 02341 tok = tok->previous(); 02342 tok->str("-"); 02343 } 02344 continue; 02345 } 02346 } else if (tok->str() == "-") { 02347 if (tok->next()->str() == "+") { 02348 tok->deleteNext(); 02349 continue; 02350 } else if (tok->next()->str()[0] == '-') { 02351 tok = tok->next(); 02352 if (tok->str().size() == 1) { 02353 tok = tok->previous(); 02354 tok->str("+"); 02355 tok->deleteNext(); 02356 } else if (tok->isNumber()) { 02357 tok->str(tok->str().substr(1)); 02358 tok = tok->previous(); 02359 tok->str("+"); 02360 } 02361 continue; 02362 } 02363 } 02364 02365 break; 02366 } 02367 } 02368 } 02369 02370 /** Specify array size if it hasn't been given */ 02371 02372 void Tokenizer::arraySize() 02373 { 02374 bool addlength = false; 02375 for (Token *tok = list.front(); tok; tok = tok->next()) { 02376 if (Token::Match(tok, "%var% [ ] = { %str% } ;")) { 02377 Token *t = tok->tokAt(3); 02378 t->deleteNext(); 02379 t->next()->deleteNext(); 02380 addlength = true; 02381 } 02382 02383 if (addlength || Token::Match(tok, "%var% [ ] = %str% ;")) { 02384 tok = tok->next(); 02385 std::size_t sz = tok->strAt(3).length() - 1; 02386 tok->insertToken(MathLib::longToString((unsigned int)sz)); 02387 addlength = false; 02388 tok = tok->tokAt(5); 02389 } 02390 02391 else if (Token::Match(tok, "%var% [ ] = {")) { 02392 unsigned int sz = 1; 02393 tok = tok->next(); 02394 Token *end = tok->linkAt(3); 02395 for (Token *tok2 = tok->tokAt(4); tok2 && tok2 != end; tok2 = tok2->next()) { 02396 if (tok2->str() == "{" || tok2->str() == "(" || tok2->str() == "[") 02397 tok2 = tok2->link(); 02398 else if (tok2->str() == "<") { // Bailout. TODO: When link() supports <>, this bailout becomes unnecessary 02399 sz = 0; 02400 break; 02401 } else if (tok2->str() == ",") { 02402 if (!Token::Match(tok2->next(), "[},]")) 02403 ++sz; 02404 else { 02405 tok2 = tok2->previous(); 02406 tok2->deleteNext(); 02407 } 02408 } 02409 } 02410 02411 if (sz != 0) 02412 tok->insertToken(MathLib::longToString(sz)); 02413 02414 tok = end->next() ? end->next() : end; 02415 } 02416 } 02417 } 02418 02419 static Token *skipTernaryOp(Token *); 02420 02421 static Token *skipTernaryOp(Token *tok) 02422 { 02423 if (!tok || tok->str() != "?") 02424 return tok; 02425 unsigned int colonlevel = 1; 02426 while (NULL != (tok = tok->next())) { 02427 if (tok->str() == "?") { 02428 ++colonlevel; 02429 } else if (tok->str() == ":") { 02430 --colonlevel; 02431 if (colonlevel == 0) { 02432 tok = tok->next(); 02433 break; 02434 } 02435 } 02436 if (Token::Match(tok->next(), "[{};]")) 02437 break; 02438 } 02439 return tok; 02440 } 02441 02442 /** simplify labels and case|default in the code: add a ";" if not already in.*/ 02443 02444 bool Tokenizer::simplifyLabelsCaseDefault() 02445 { 02446 bool executablescope = false; 02447 unsigned int indentlevel = 0; 02448 for (Token *tok = list.front(); tok; tok = tok->next()) { 02449 // Simplify labels in the executable scope.. 02450 if (Token::Match(tok, ") const| {")) { 02451 tok = tok->next(); 02452 if (tok->str() != "{") 02453 tok = tok->next(); 02454 executablescope = true; 02455 } 02456 02457 if (!executablescope) 02458 continue; 02459 02460 if (tok->str() == "{") { 02461 if (tok->previous()->str() == "=") 02462 tok = tok->link(); 02463 else 02464 ++indentlevel; 02465 } else if (tok->str() == "}") { 02466 --indentlevel; 02467 if (!indentlevel) { 02468 executablescope = false; 02469 continue; 02470 } 02471 } else if (tok->str() == "(" || tok->str() == "[") 02472 tok = tok->link(); 02473 02474 if (Token::Match(tok, "[;{}] case")) { 02475 while (NULL != (tok = tok->next())) { 02476 if (tok->str() == "(" || tok->str() == "[") { 02477 tok = tok->link(); 02478 } else if (tok->str() == "?") { 02479 tok = skipTernaryOp(tok); 02480 } 02481 if (Token::Match(tok->next(),"[:{};]")) 02482 break; 02483 } 02484 if (tok->str() != "case" && tok->next()->str() == ":") { 02485 tok = tok->next(); 02486 if (tok->next()->str() != ";") 02487 tok->insertToken(";"); 02488 } else { 02489 syntaxError(tok); 02490 return false; 02491 } 02492 } else if (Token::Match(tok, "[;{}] %var% : !!;")) { 02493 tok = tok->tokAt(2); 02494 tok->insertToken(";"); 02495 } 02496 } 02497 return true; 02498 } 02499 02500 02501 02502 02503 void Tokenizer::simplifyTemplates() 02504 { 02505 if (isC()) 02506 return; 02507 02508 for (Token *tok = list.front(); tok; tok = tok->next()) { 02509 // #2648 - simple fix for sizeof used as template parameter 02510 // TODO: this is a bit hardcoded. make a bit more generic 02511 if (Token::Match(tok, "%var% < sizeof ( %type% ) >") && tok->tokAt(4)->isStandardType()) { 02512 Token * const tok3 = tok->next(); 02513 const unsigned int sizeOfResult = sizeOfType(tok3->tokAt(3)); 02514 tok3->deleteNext(4); 02515 tok3->insertToken(MathLib::longToString(sizeOfResult)); 02516 } 02517 } 02518 02519 TemplateSimplifier::simplifyTemplates( 02520 list, 02521 *_errorLogger, 02522 _settings, 02523 _codeWithTemplates); 02524 } 02525 //--------------------------------------------------------------------------- 02526 02527 02528 static bool setVarIdParseDeclaration(const Token **tok, const std::map<std::string,unsigned int> &variableId, bool executableScope) 02529 { 02530 const Token *tok2 = *tok; 02531 02532 bool ref = false; 02533 02534 if (!tok2->isName()) 02535 return false; 02536 02537 unsigned int typeCount = 0; 02538 bool hasstruct = false; // Is there a "struct" or "class"? 02539 while (tok2) { 02540 if (tok2->isName()) { 02541 if (tok2->str() == "class" || tok2->str() == "struct" || tok2->str() == "union" || tok2->str() == "typename") { 02542 hasstruct = true; 02543 typeCount = 0; 02544 } else if (tok2->str() == "const") { 02545 ; // just skip "const" 02546 } else if (!hasstruct && variableId.find(tok2->str()) != variableId.end() && tok2->previous()->str() != "::") { 02547 ++typeCount; 02548 tok2 = tok2->next(); 02549 if (!tok2 || tok2->str() != "::") 02550 break; 02551 } else { 02552 ++typeCount; 02553 } 02554 } else if (tok2->str() == "<" && TemplateSimplifier::templateParameters(tok2) > 0) { 02555 bool ok = tok2->findClosingBracket(tok2); 02556 if (!ok || !tok2) 02557 break; 02558 } else if (tok2->str() == "&") { 02559 ref = true; 02560 } else if (tok2->str() != "*" && tok2->str() != "::") { 02561 break; 02562 } 02563 tok2 = tok2->next(); 02564 } 02565 02566 if (tok2) { 02567 *tok = tok2; 02568 02569 // In executable scopes, references must be assigned 02570 // Catching by reference is an exception 02571 if (executableScope && ref) { 02572 if (tok2->str() == "(" || tok2->str() == "=") 02573 ; // reference is assigned => ok 02574 else if (tok2->str() != ")" || tok2->link()->strAt(-1) != "catch") 02575 return false; // not catching by reference => not declaration 02576 } 02577 } 02578 02579 // Check if array declaration is valid (#2638) 02580 // invalid declaration: AAA a[4] = 0; 02581 if (typeCount >= 2 && tok2 && tok2->str() == "[") { 02582 const Token *tok3 = tok2; 02583 while (tok3 && tok3->str() == "[") { 02584 tok3 = tok3->link()->next(); 02585 } 02586 if (Token::Match(tok3, "= %num%")) 02587 return false; 02588 } 02589 02590 return bool(typeCount >= 2 && tok2 && Token::Match(tok2->tokAt(-2), "!!:: %type%")); 02591 } 02592 02593 02594 static void setVarIdStructMembers(Token **tok1, 02595 std::map<unsigned int, std::map<std::string,unsigned int> > *structMembers, 02596 unsigned int *_varId) 02597 { 02598 Token *tok = *tok1; 02599 while (Token::Match(tok->next(), ". %var% !!(")) { 02600 const unsigned int struct_varid = tok->varId(); 02601 tok = tok->tokAt(2); 02602 if (struct_varid == 0) 02603 continue; 02604 02605 // Don't set varid for template function 02606 if (TemplateSimplifier::templateParameters(tok->next()) > 0) 02607 break; 02608 02609 std::map<std::string,unsigned int>& members = (*structMembers)[struct_varid]; 02610 if (members.empty() || members.find(tok->str()) == members.end()) { 02611 members[tok->str()] = ++(*_varId); 02612 tok->varId(*_varId); 02613 } else { 02614 tok->varId(members[tok->str()]); 02615 } 02616 } 02617 if (tok) 02618 *tok1 = tok; 02619 } 02620 02621 02622 static void setVarIdClassDeclaration(Token * const startToken, 02623 const std::map<std::string, unsigned int> &variableId, 02624 const unsigned int scopeStartVarId, 02625 std::map<unsigned int, std::map<std::string,unsigned int> > *structMembers, 02626 unsigned int *_varId) 02627 { 02628 // end of scope 02629 const Token * const endToken = startToken->link(); 02630 02631 // determine class name 02632 std::string className; 02633 for (const Token *tok = startToken->previous(); tok; tok = tok->previous()) { 02634 if (!tok->isName() && tok->str() != ":") 02635 break; 02636 if (Token::Match(tok, "class|struct %type% [:{]")) { 02637 className = tok->next()->str(); 02638 break; 02639 } 02640 } 02641 02642 // replace varids.. 02643 unsigned int indentlevel = 0; 02644 bool initList = false; 02645 for (Token *tok = startToken->next(); tok != endToken; tok = tok->next()) { 02646 if (tok->str() == "{") { 02647 initList = false; 02648 ++indentlevel; 02649 } else if (tok->str() == "}") 02650 --indentlevel; 02651 else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %var% (")) { 02652 const std::map<std::string, unsigned int>::const_iterator it = variableId.find(tok->str()); 02653 if (it != variableId.end()) { 02654 tok->varId(it->second); 02655 } 02656 } else if (tok->isName() && tok->varId() <= scopeStartVarId) { 02657 if (indentlevel > 0) { 02658 if (Token::Match(tok->previous(), "::|.")) 02659 continue; 02660 if (tok->next()->str() == "::") { 02661 if (tok->str() == className) 02662 tok = tok->tokAt(2); 02663 else 02664 continue; 02665 } 02666 02667 const std::map<std::string, unsigned int>::const_iterator it = variableId.find(tok->str()); 02668 if (it != variableId.end()) { 02669 tok->varId(it->second); 02670 setVarIdStructMembers(&tok, structMembers, _varId); 02671 } 02672 } 02673 } else if (indentlevel == 0 && tok->str() == ":") 02674 initList = true; 02675 } 02676 } 02677 02678 02679 02680 // Update the variable ids.. 02681 // Parse each function.. 02682 static void setVarIdClassFunction(Token * const startToken, 02683 const Token * const endToken, 02684 const std::map<std::string, unsigned int> &varlist, 02685 std::map<unsigned int, std::map<std::string,unsigned int> > *structMembers, 02686 unsigned int *_varId) 02687 { 02688 for (Token *tok2 = startToken; tok2 && tok2 != endToken; tok2 = tok2->next()) { 02689 if (tok2->varId() == 0 && (tok2->previous()->str() != "." || tok2->strAt(-2) == "this")) { 02690 const std::map<std::string,unsigned int>::const_iterator it = varlist.find(tok2->str()); 02691 if (it != varlist.end()) { 02692 tok2->varId(it->second); 02693 setVarIdStructMembers(&tok2, structMembers, _varId); 02694 } 02695 } 02696 } 02697 } 02698 02699 static bool isInitList(const Token *tok) 02700 { 02701 if (!Token::Match(tok, ") : %var% (")) 02702 return false; 02703 02704 tok = tok->linkAt(3); 02705 while (Token::Match(tok, ") , %var% (")) 02706 tok = tok->linkAt(3); 02707 02708 return Token::simpleMatch(tok, ") {"); 02709 } 02710 02711 void Tokenizer::setVarId() 02712 { 02713 // Clear all variable ids 02714 for (Token *tok = list.front(); tok; tok = tok->next()) 02715 tok->varId(0); 02716 02717 // Variable declarations can't start with "return" etc. 02718 std::set<std::string> notstart; 02719 notstart.insert("goto"); 02720 notstart.insert("NOT"); 02721 notstart.insert("return"); 02722 notstart.insert("sizeof"); 02723 if (!isC()) { 02724 static const char *str[] = {"delete","friend","new","throw","using","virtual","explicit"}; 02725 notstart.insert(str, str+(sizeof(str)/sizeof(*str))); 02726 } 02727 02728 // variable id 02729 _varId = 0; 02730 std::map<std::string, unsigned int> variableId; 02731 std::map<unsigned int, std::map<std::string, unsigned int> > structMembers; 02732 std::stack< std::map<std::string, unsigned int> > scopeInfo; 02733 std::stack<bool> executableScope; 02734 executableScope.push(false); 02735 std::stack<unsigned int> scopestartvarid; // varid when scope starts 02736 scopestartvarid.push(0); 02737 bool initlist = false; 02738 for (Token *tok = list.front(); tok; tok = tok->next()) { 02739 02740 // scope info to handle shadow variables.. 02741 if (!initlist && tok->str() == "(" && 02742 (Token::simpleMatch(tok->link(), ") {") || Token::Match(tok->link(), ") %type% {") || isInitList(tok->link()))) { 02743 scopeInfo.push(variableId); 02744 initlist = Token::simpleMatch(tok->link(), ") :"); 02745 } else if (tok->str() == "{") { 02746 initlist = false; 02747 // parse anonymous unions as part of the current scope 02748 if (!(tok->strAt(-1) == "union" && Token::simpleMatch(tok->link(), "} ;"))) { 02749 scopestartvarid.push(_varId); 02750 if (tok->strAt(-1) == ")" || Token::Match(tok->tokAt(-2), ") %type%")) { 02751 executableScope.push(true); 02752 } else { 02753 executableScope.push(executableScope.top()); 02754 scopeInfo.push(variableId); 02755 } 02756 } 02757 } else if (tok->str() == "}") { 02758 // parse anonymous unions as part of the current scope 02759 if (!(Token::simpleMatch(tok, "} ;") && Token::simpleMatch(tok->link()->previous(), "union {"))) { 02760 // Set variable ids in class declaration.. 02761 if (!isC() && !executableScope.top() && tok->link()) { 02762 setVarIdClassDeclaration(tok->link(), 02763 variableId, 02764 scopestartvarid.top(), 02765 &structMembers, 02766 &_varId); 02767 } 02768 02769 scopestartvarid.pop(); 02770 if (scopestartvarid.empty()) { // should be impossible 02771 scopestartvarid.push(0); 02772 } 02773 02774 if (scopeInfo.empty()) { 02775 variableId.clear(); 02776 } else { 02777 variableId.swap(scopeInfo.top()); 02778 scopeInfo.pop(); 02779 } 02780 02781 executableScope.pop(); 02782 if (executableScope.empty()) { // should not possibly happen 02783 executableScope.push(false); 02784 } 02785 } 02786 } 02787 02788 if (tok == list.front() || Token::Match(tok, "[;{}]") || 02789 (Token::Match(tok,"[(,]") && (!executableScope.top() || Token::simpleMatch(tok->link(), ") {"))) || 02790 (tok->isName() && tok->str().at(tok->str().length()-1U) == ':')) { 02791 02792 // No variable declarations in sizeof 02793 if (Token::simpleMatch(tok->previous(), "sizeof (")) { 02794 continue; 02795 } 02796 02797 // locate the variable name.. 02798 const Token *tok2 = (tok->isName()) ? tok : tok->next(); 02799 02800 // private: protected: public: etc 02801 while (tok2 && tok2->str()[tok2->str().size() - 1U] == ':') { 02802 tok2 = tok2->next(); 02803 } 02804 if (!tok2) 02805 break; 02806 02807 // Variable declaration can't start with "return", etc 02808 if (notstart.find(tok2->str()) != notstart.end()) 02809 continue; 02810 02811 const bool decl = setVarIdParseDeclaration(&tok2, variableId, executableScope.top()); 02812 02813 if (decl && Token::Match(tok2->previous(), "%type% [;[=,)]") && tok2->previous()->str() != "const") { 02814 variableId[tok2->previous()->str()] = ++_varId; 02815 tok = tok2->previous(); 02816 } 02817 02818 else if (decl && Token::Match(tok2->previous(), "%type% ( !!)") && Token::simpleMatch(tok2->link(), ") ;")) { 02819 // In C++ , a variable can't be called operator+ or something like that. 02820 if (isCPP() && 02821 tok2->previous()->str().size() >= 9 && 02822 tok2->previous()->str().compare(0, 8, "operator") == 0 && 02823 tok2->previous()->str()[8] != '_' && 02824 !std::isalnum(tok2->previous()->str()[8])) 02825 continue; 02826 02827 const Token *tok3 = tok2->next(); 02828 if (!tok3->isStandardType() && tok3->str() != "void" && !Token::Match(tok3,"struct|union|class %type%") && tok3->str() != "." && !setVarIdParseDeclaration(&tok3,variableId,executableScope.top())) { 02829 variableId[tok2->previous()->str()] = ++_varId; 02830 tok = tok2->previous(); 02831 } 02832 } 02833 } 02834 02835 if (tok->isName()) { 02836 // don't set variable id after a struct|enum|union 02837 if (Token::Match(tok->previous(), "struct|enum|union")) 02838 continue; 02839 02840 if (!isC()) { 02841 if (tok->previous() && tok->previous()->str() == "::") 02842 continue; 02843 if (tok->next() && tok->next()->str() == "::") 02844 continue; 02845 } 02846 02847 const std::map<std::string, unsigned int>::const_iterator it = variableId.find(tok->str()); 02848 if (it != variableId.end()) { 02849 tok->varId(it->second); 02850 setVarIdStructMembers(&tok, &structMembers, &_varId); 02851 } 02852 } else if (Token::Match(tok, "::|. %var%")) { 02853 // Don't set varid after a :: or . token 02854 tok = tok->next(); 02855 } else if (tok->str() == ":" && Token::Match(tok->tokAt(-2), "class %type%")) { 02856 do { 02857 tok = tok->next(); 02858 } while (tok && (tok->isName() || tok->str() == ",")); 02859 if (!tok) 02860 break; 02861 tok = tok->previous(); 02862 } 02863 } 02864 02865 // Clear the structMembers because it will be used when member functions 02866 // are parsed. The old info is not bad, it is just redundant. 02867 structMembers.clear(); 02868 02869 // Member functions and variables in this source 02870 std::list<Token *> allMemberFunctions; 02871 std::list<Token *> allMemberVars; 02872 { 02873 for (Token *tok2 = list.front(); tok2; tok2 = tok2->next()) { 02874 if (Token::Match(tok2, "%var% :: %var%")) { 02875 if (tok2->strAt(3) == "(") 02876 allMemberFunctions.push_back(tok2); 02877 else if (tok2->tokAt(2)->varId() != 0) 02878 allMemberVars.push_back(tok2); 02879 } 02880 } 02881 } 02882 02883 // class members.. 02884 for (Token *tok = list.front(); tok; tok = tok->next()) { 02885 if (Token::Match(tok, "class|struct %var% {|:")) { 02886 const std::string &classname(tok->next()->str()); 02887 02888 // What member variables are there in this class? 02889 std::map<std::string, unsigned int> varlist; 02890 const Token* tokStart = Token::findsimplematch(tok, "{"); 02891 if (tokStart) { 02892 for (const Token *tok2 = tokStart->next(); tok2 != tokStart->link(); tok2 = tok2->next()) { 02893 // skip parentheses.. 02894 if (tok2->str() == "{") 02895 tok2 = tok2->link(); 02896 else if (tok2->str() == "(") 02897 tok2 = tok2->link(); 02898 02899 // Found a member variable.. 02900 else if (tok2->varId() > 0) 02901 varlist[tok2->str()] = tok2->varId(); 02902 } 02903 } 02904 02905 // Are there any member variables in this class? 02906 if (varlist.empty()) 02907 continue; 02908 02909 // Member variables 02910 for (std::list<Token *>::iterator func = allMemberVars.begin(); func != allMemberVars.end(); ++func) { 02911 if (!Token::simpleMatch(*func, classname.c_str())) 02912 continue; 02913 02914 Token *tok2 = *func; 02915 tok2 = tok2->tokAt(2); 02916 tok2->varId(varlist[tok2->str()]); 02917 } 02918 02919 // Set variable ids in member functions for this class.. 02920 const std::string funcpattern(classname + " :: %var% ("); 02921 for (std::list<Token *>::iterator func = allMemberFunctions.begin(); func != allMemberFunctions.end(); ++func) { 02922 Token *tok2 = *func; 02923 02924 // Found a class function.. 02925 if (Token::Match(tok2, funcpattern.c_str())) { 02926 // Goto the end parentheses.. 02927 tok2 = tok2->linkAt(3); 02928 if (!tok2) 02929 break; 02930 02931 // If this is a function implementation.. add it to funclist 02932 if (Token::Match(tok2, ") const|volatile| {")) { 02933 while (tok2->str() != "{") 02934 tok2 = tok2->next(); 02935 setVarIdClassFunction(tok2, tok2->link(), varlist, &structMembers, &_varId); 02936 } 02937 02938 // constructor with initializer list 02939 if (Token::Match(tok2, ") : %var% (")) { 02940 Token *tok3 = tok2; 02941 while (Token::Match(tok3, ") [:,] %var% (")) { 02942 Token *vartok = tok3->tokAt(2); 02943 if (varlist.find(vartok->str()) != varlist.end()) 02944 vartok->varId(varlist[vartok->str()]); 02945 tok3 = tok3->linkAt(3); 02946 } 02947 if (Token::simpleMatch(tok3, ") {")) { 02948 setVarIdClassFunction(tok2, tok3->next()->link(), varlist, &structMembers, &_varId); 02949 } 02950 } 02951 } 02952 } 02953 } 02954 } 02955 } 02956 02957 static bool linkBrackets(Tokenizer* tokenizer, std::stack<const Token*>& type, std::stack<Token*>& links, Token* token, char open, char close) 02958 { 02959 if (token->str()[0] == open) { 02960 links.push(token); 02961 type.push(token); 02962 } else if (token->str()[0] == close) { 02963 if (links.empty()) { 02964 // Error, { and } don't match. 02965 tokenizer->syntaxError(token, open); 02966 return false; 02967 } 02968 if (type.top()->str()[0] != open) { 02969 tokenizer->syntaxError(type.top(), type.top()->str()[0]); 02970 return false; 02971 } 02972 type.pop(); 02973 02974 Token::createMutualLinks(links.top(), token); 02975 links.pop(); 02976 } 02977 return(true); 02978 } 02979 02980 bool Tokenizer::createLinks() 02981 { 02982 std::stack<const Token*> type; 02983 std::stack<Token*> links1; 02984 std::stack<Token*> links2; 02985 std::stack<Token*> links3; 02986 for (Token *token = list.front(); token; token = token->next()) { 02987 if (token->link()) { 02988 token->link(0); 02989 } 02990 02991 bool validSyntax = linkBrackets(this, type, links1, token, '{', '}'); 02992 if (!validSyntax) 02993 return false; 02994 02995 validSyntax = linkBrackets(this, type, links2, token, '(', ')'); 02996 if (!validSyntax) 02997 return false; 02998 02999 validSyntax = linkBrackets(this, type, links3, token, '[', ']'); 03000 if (!validSyntax) 03001 return false; 03002 } 03003 03004 if (!links1.empty()) { 03005 // Error, { and } don't match. 03006 syntaxError(links1.top(), '{'); 03007 return false; 03008 } 03009 03010 if (!links2.empty()) { 03011 // Error, ( and ) don't match. 03012 syntaxError(links2.top(), '('); 03013 return false; 03014 } 03015 03016 if (!links3.empty()) { 03017 // Error, [ and ] don't match. 03018 syntaxError(links3.top(), '['); 03019 return false; 03020 } 03021 03022 return true; 03023 } 03024 03025 void Tokenizer::createLinks2() 03026 { 03027 if (isC()) 03028 return; 03029 03030 std::stack<Token*> type; 03031 for (Token *token = list.front(); token; token = token->next()) { 03032 if (token->link()) { 03033 if (Token::Match(token, "{|[|(")) 03034 type.push(token); 03035 else if (Token::Match(token, "}|]|)")) { 03036 while (type.top()->str() == "<") 03037 type.pop(); 03038 type.pop(); 03039 } else 03040 token->link(0); 03041 } 03042 03043 else if (token->str() == ";") 03044 while (!type.empty() && type.top()->str() == "<") 03045 type.pop(); 03046 else if (token->str() == "<" && token->previous() && token->previous()->isName() && !token->previous()->varId()) 03047 type.push(token); 03048 else if (token->str() == ">" || token->str() == ">>") { 03049 if (type.empty() || type.top()->str() != "<") // < and > don't match. 03050 continue; 03051 if (token->next() && !token->next()->isName() && !Token::Match(token->next(), ">|&|*|::|,|(|)")) 03052 continue; 03053 03054 // Check type of open link 03055 if (type.empty() || type.top()->str() != "<" || (token->str() == ">>" && type.size() < 2)) { 03056 continue; 03057 } 03058 03059 Token* top = type.top(); 03060 type.pop(); 03061 if (token->str() == ">>" && type.top()->str() != "<") { 03062 type.push(top); 03063 continue; 03064 } 03065 03066 if (token->str() == ">>") { // C++11 right angle bracket 03067 token->str(">"); 03068 token->insertToken(">"); 03069 } 03070 03071 Token::createMutualLinks(top, token); 03072 } 03073 } 03074 } 03075 03076 bool Tokenizer::simplifySizeof() 03077 { 03078 // Locate variable declarations and calculate the size 03079 std::map<unsigned int, std::string> sizeOfVar; 03080 for (Token *tok = list.front(); tok; tok = tok->next()) { 03081 if (tok->varId() != 0 && sizeOfVar.find(tok->varId()) == sizeOfVar.end()) { 03082 const unsigned int varId = tok->varId(); 03083 if (Token::Match(tok->tokAt(-3), "[;{}(,] %type% * %var% [;,)]") || 03084 Token::Match(tok->tokAt(-4), "[;{}(,] const %type% * %var% [;),]") || 03085 Token::Match(tok->tokAt(-2), "[;{}(,] %type% %var% [;),]") || 03086 Token::Match(tok->tokAt(-3), "[;{}(,] const %type% %var% [;),]")) { 03087 const unsigned int size = sizeOfType(tok->previous()); 03088 if (size == 0) { 03089 continue; 03090 } 03091 03092 sizeOfVar[varId] = MathLib::longToString(size); 03093 } 03094 03095 else if (Token::Match(tok->previous(), "%type% %var% [ %num% ] [;=]") || 03096 Token::Match(tok->tokAt(-2), "%type% * %var% [ %num% ] [;=]")) { 03097 const unsigned int size = sizeOfType(tok->previous()); 03098 if (size == 0) 03099 continue; 03100 03101 sizeOfVar[varId] = MathLib::longToString(size * static_cast<unsigned long>(MathLib::toLongNumber(tok->strAt(2)))); 03102 } 03103 03104 else if (Token::Match(tok->previous(), "%type% %var% [ %num% ] [,)]") || 03105 Token::Match(tok->tokAt(-2), "%type% * %var% [ %num% ] [,)]")) { 03106 Token tempTok(0); 03107 tempTok.str("*"); 03108 sizeOfVar[varId] = MathLib::longToString(sizeOfType(&tempTok)); 03109 } 03110 } 03111 } 03112 03113 bool ret = false; 03114 for (Token *tok = list.front(); tok; tok = tok->next()) { 03115 if (tok->str() != "sizeof") 03116 continue; 03117 03118 if (!tok->next()) 03119 break; 03120 03121 if (tok->strAt(1) == "sizeof") 03122 continue; 03123 03124 if (Token::simpleMatch(tok->next(), ". . .")) { 03125 tok->deleteNext(3); 03126 } 03127 03128 // sizeof 'x' 03129 if (tok->next()->type() == Token::eChar) { 03130 tok->deleteThis(); 03131 std::ostringstream sz; 03132 sz << sizeof 'x'; 03133 tok->str(sz.str()); 03134 ret = true; 03135 continue; 03136 } 03137 03138 // sizeof('x') 03139 if (Token::Match(tok, "sizeof ( %char% )")) { 03140 tok->deleteNext(); 03141 tok->deleteThis(); 03142 tok->deleteNext(); 03143 std::ostringstream sz; 03144 sz << sizeof 'x'; 03145 tok->str(sz.str()); 03146 ret = true; 03147 continue; 03148 } 03149 03150 // sizeof "text" 03151 if (tok->next()->type() == Token::eString) { 03152 tok->deleteThis(); 03153 std::ostringstream ostr; 03154 ostr << (Token::getStrLength(tok) + 1); 03155 tok->str(ostr.str()); 03156 ret = true; 03157 continue; 03158 } 03159 03160 // sizeof ("text") 03161 if (Token::Match(tok->next(), "( %str% )")) { 03162 tok->deleteNext(); 03163 tok->deleteThis(); 03164 tok->deleteNext(); 03165 std::ostringstream ostr; 03166 ostr << (Token::getStrLength(tok) + 1); 03167 tok->str(ostr.str()); 03168 ret = true; 03169 continue; 03170 } 03171 03172 // sizeof * (...) -> sizeof(*...) 03173 if (Token::simpleMatch(tok->next(), "* (") && !Token::simpleMatch(tok->linkAt(2), ") .")) { 03174 tok->deleteNext(); 03175 tok->next()->insertToken("*"); 03176 } 03177 03178 // sizeof a++ -> sizeof(a++) 03179 if (Token::Match(tok->next(), "++|-- %var% !!.") || Token::Match(tok->next(), "%var% ++|--")) { 03180 tok->insertToken("("); 03181 tok->tokAt(3)->insertToken(")"); 03182 Token::createMutualLinks(tok->next(), tok->tokAt(4)); 03183 } 03184 03185 // sizeof 1 => sizeof ( 1 ) 03186 if (tok->next()->isNumber()) { 03187 Token *tok2 = tok->next(); 03188 tok->insertToken("("); 03189 tok2->insertToken(")"); 03190 Token::createMutualLinks(tok->next(), tok2->next()); 03191 } 03192 03193 // sizeof int -> sizeof( int ) 03194 else if (tok->next()->str() != "(") { 03195 // Add parentheses around the sizeof 03196 int parlevel = 0; 03197 for (Token *tempToken = tok->next(); tempToken; tempToken = tempToken->next()) { 03198 if (tempToken->str() == "(") 03199 ++parlevel; 03200 else if (tempToken->str() == ")") 03201 --parlevel; 03202 if (Token::Match(tempToken, "%var%")) { 03203 while (tempToken && tempToken->next() && tempToken->next()->str() == "[") { 03204 tempToken = tempToken->next()->link(); 03205 } 03206 if (!tempToken || !tempToken->next()) { 03207 break; 03208 } 03209 03210 if (tempToken->next()->str() == ".") { 03211 // We are checking a class or struct, search next varname 03212 tempToken = tempToken->next(); 03213 continue; 03214 } else if (tempToken->next()->type() == Token::eIncDecOp) { 03215 // We have variable++ or variable--, there should be 03216 // nothing after this 03217 tempToken = tempToken->tokAt(2); 03218 } else if (parlevel > 0 && Token::simpleMatch(tempToken->next(), ") .")) { 03219 --parlevel; 03220 tempToken = tempToken->tokAt(2); 03221 continue; 03222 } 03223 03224 // Ok, we should be clean. Add ) after tempToken 03225 tok->insertToken("("); 03226 tempToken->insertToken(")"); 03227 Token::createMutualLinks(tok->next(), tempToken->next()); 03228 break; 03229 } 03230 } 03231 } 03232 03233 // sizeof(type *) => sizeof(*) 03234 if (Token::Match(tok->next(), "( %type% * )")) { 03235 tok->next()->deleteNext(); 03236 } 03237 03238 if (Token::simpleMatch(tok->next(), "( * )")) { 03239 tok->str(MathLib::longToString(sizeOfType(tok->tokAt(2)))); 03240 tok->deleteNext(3); 03241 ret = true; 03242 } 03243 03244 // sizeof( a ) 03245 else if (Token::Match(tok->next(), "( %var% )") && tok->tokAt(2)->varId() != 0) { 03246 if (sizeOfVar.find(tok->tokAt(2)->varId()) != sizeOfVar.end()) { 03247 tok->deleteNext(); 03248 tok->deleteThis(); 03249 tok->deleteNext(); 03250 tok->str(sizeOfVar[tok->varId()]); 03251 ret = true; 03252 } else { 03253 // don't try to replace size of variable if variable has 03254 // similar name with type (#329) 03255 } 03256 } 03257 03258 else if (Token::Match(tok, "sizeof ( %type% )")) { 03259 unsigned int size = sizeOfType(tok->tokAt(2)); 03260 if (size > 0) { 03261 tok->str(MathLib::longToString(size)); 03262 tok->deleteNext(3); 03263 ret = true; 03264 } 03265 } 03266 03267 else if (Token::Match(tok, "sizeof ( * %var% )") || Token::Match(tok, "sizeof ( %var% [ %num% ] )")) { 03268 // Some default value.. 03269 std::size_t sz = 0; 03270 03271 unsigned int varid = tok->tokAt((tok->strAt(2) == "*") ? 3 : 2)->varId(); 03272 if (varid != 0) { 03273 // Try to locate variable declaration.. 03274 const Token *decltok = Token::findmatch(list.front(), "%varid%", varid); 03275 if (Token::Match(decltok->previous(), "%type% %var% [")) { 03276 sz = sizeOfType(decltok->previous()); 03277 } else if (Token::Match(decltok->previous(), "* %var% [")) { 03278 sz = sizeOfType(decltok->previous()); 03279 } else if (Token::Match(decltok->tokAt(-2), "%type% * %var%")) { 03280 sz = sizeOfType(decltok->tokAt(-2)); 03281 } 03282 } else if (tok->strAt(3) == "[" && tok->tokAt(2)->isStandardType()) { 03283 sz = sizeOfType(tok->tokAt(2)); 03284 if (sz == 0) 03285 continue; 03286 sz *= static_cast<unsigned long>(MathLib::toLongNumber(tok->strAt(4))); 03287 } 03288 03289 if (sz > 0) { 03290 tok->str(MathLib::longToString(sz)); 03291 Token::eraseTokens(tok, tok->next()->link()->next()); 03292 ret = true; 03293 } 03294 } 03295 } 03296 return ret; 03297 } 03298 03299 bool Tokenizer::simplifyTokenList() 03300 { 03301 // clear the _functionList so it can't contain dead pointers 03302 deleteSymbolDatabase(); 03303 03304 simplifyCharAt(); 03305 03306 // simplify references 03307 simplifyReference(); 03308 03309 simplifyStd(); 03310 03311 simplifyGoto(); 03312 03313 simplifySizeof(); 03314 03315 simplifyUndefinedSizeArray(); 03316 03317 // Replace constants.. 03318 for (Token *tok = list.front(); tok; tok = tok->next()) { 03319 if (Token::Match(tok, "const static| %type% %var% = %num% ;")) { 03320 unsigned int offset = 0; 03321 if (tok->strAt(1) == "static") 03322 offset = 1; 03323 const unsigned int varId(tok->tokAt(2 + offset)->varId()); 03324 if (varId == 0) { 03325 tok = tok->tokAt(5); 03326 continue; 03327 } 03328 03329 const std::string& num = tok->strAt(4 + offset); 03330 int indent = 1; 03331 for (Token *tok2 = tok->tokAt(6); tok2; tok2 = tok2->next()) { 03332 if (tok2->str() == "{") { 03333 ++indent; 03334 } else if (tok2->str() == "}") { 03335 --indent; 03336 if (indent == 0) 03337 break; 03338 } 03339 03340 // Compare constants, but don't touch members of other structures 03341 else if (tok2->varId() == varId) { 03342 tok2->str(num); 03343 } 03344 } 03345 } 03346 } 03347 03348 simplifyCasts(); 03349 03350 // Simplify simple calculations.. 03351 simplifyCalculations(); 03352 03353 // Replace "*(str + num)" => "str[num]" 03354 for (Token *tok = list.front(); tok; tok = tok->next()) { 03355 if (!Token::Match(tok, "%var%") && !tok->isNumber() 03356 && !Token::Match(tok, "]|)") 03357 && (Token::Match(tok->next(), "* ( %var% + %num%|%var% )"))) { 03358 // remove '* (' 03359 tok->deleteNext(2); 03360 03361 tok = tok->tokAt(2); 03362 // '+'->'[' 03363 tok->str("["); 03364 03365 tok = tok->tokAt(2); 03366 tok->str("]"); 03367 Token::createMutualLinks(tok->tokAt(-2), tok); 03368 } 03369 } 03370 03371 // Replace "&str[num]" => "(str + num)" 03372 std::set<unsigned int> pod; 03373 for (const Token *tok = list.front(); tok; tok = tok->next()) { 03374 if (tok->isStandardType()) { 03375 tok = tok->next(); 03376 while (tok && (tok->str() == "*" || tok->isName())) { 03377 if (tok->varId() > 0) { 03378 pod.insert(tok->varId()); 03379 break; 03380 } 03381 tok = tok->next(); 03382 } 03383 if (!tok) 03384 break; 03385 } 03386 } 03387 03388 for (Token *tok = list.front(); tok; tok = tok->next()) { 03389 if (!Token::Match(tok, "%num%|%var%") && !Token::Match(tok, "]|)") && 03390 (Token::Match(tok->next(), "& %var% [ %num%|%var% ]"))) { 03391 tok = tok->next(); 03392 03393 if (tok->next()->varId()) { 03394 if (pod.find(tok->next()->varId()) == pod.end()) { 03395 tok = tok->tokAt(5); 03396 continue; 03397 } 03398 } 03399 03400 // '&' => '(' 03401 tok->str("("); 03402 03403 tok = tok->next(); 03404 // '[' => '+' 03405 tok->deleteNext(); 03406 tok->insertToken("+"); 03407 03408 tok = tok->tokAt(3); 03409 //remove ']' 03410 tok->str(")"); 03411 Token::createMutualLinks(tok->tokAt(-4), tok); 03412 } 03413 } 03414 03415 removeRedundantAssignment(); 03416 03417 simplifyRealloc(); 03418 03419 // Change initialisation of variable to assignment 03420 simplifyInitVar(); 03421 03422 // Simplify variable declarations 03423 simplifyVarDecl(false); 03424 03425 elseif(); 03426 simplifyErrNoInWhile(); 03427 simplifyIfAssign(); 03428 simplifyRedundantParentheses(); 03429 simplifyIfNot(); 03430 simplifyIfNotNull(); 03431 simplifyIfSameInnerCondition(); 03432 simplifyComparisonOrder(); 03433 simplifyNestedStrcat(); 03434 simplifyWhile0(); 03435 simplifyFuncInWhile(); 03436 03437 simplifyIfAssign(); // could be affected by simplifyIfNot 03438 03439 bool modified = true; 03440 while (modified) { 03441 if (_settings && _settings->terminated()) 03442 return false; 03443 03444 modified = false; 03445 modified |= simplifyConditions(); 03446 modified |= simplifyFunctionReturn(); 03447 modified |= simplifyKnownVariables(); 03448 modified |= removeRedundantConditions(); 03449 modified |= simplifyRedundantParentheses(); 03450 modified |= simplifyConstTernaryOp(); 03451 modified |= simplifyCalculations(); 03452 } 03453 03454 simplifyConditionOperator(); 03455 03456 // replace strlen(str) 03457 for (Token *tok = list.front(); tok; tok = tok->next()) { 03458 if (Token::Match(tok, "strlen ( %str% )")) { 03459 std::ostringstream ostr; 03460 ostr << Token::getStrLength(tok->tokAt(2)); 03461 tok->str(ostr.str()); 03462 tok->deleteNext(3); 03463 } 03464 } 03465 03466 // simplify redundant for 03467 removeRedundantFor(); 03468 03469 // Remove redundant parentheses in return.. 03470 for (Token *tok = list.front(); tok; tok = tok->next()) { 03471 while (Token::simpleMatch(tok, "return (")) { 03472 Token *tok2 = tok->next()->link(); 03473 if (Token::simpleMatch(tok2, ") ;")) { 03474 tok->deleteNext(); 03475 tok2->deleteThis(); 03476 } else { 03477 break; 03478 } 03479 } 03480 } 03481 03482 simplifyReturnStrncat(); 03483 03484 removeRedundantAssignment(); 03485 03486 simplifyComma(); 03487 03488 removeRedundantSemicolons(); 03489 03490 simplifyFlowControl(); 03491 03492 simplifyRedundantConsecutiveBraces(); 03493 03494 simplifyEmptyNamespaces(); 03495 03496 if (!validate()) 03497 return false; 03498 03499 list.front()->assignProgressValues(); 03500 03501 // Create symbol database and then remove const keywords 03502 createSymbolDatabase(); 03503 for (Token *tok = list.front(); tok; tok = tok->next()) { 03504 if (Token::simpleMatch(tok, "* const")) 03505 tok->deleteNext(); 03506 } 03507 03508 if (_settings->debug) { 03509 list.front()->printOut(0, list.getFiles()); 03510 03511 if (_settings->_verbose) 03512 _symbolDatabase->printOut("Symbol database"); 03513 } 03514 03515 if (_settings->debugwarnings) { 03516 printUnknownTypes(); 03517 } 03518 03519 return true; 03520 } 03521 //--------------------------------------------------------------------------- 03522 03523 void Tokenizer::removeMacrosInGlobalScope() 03524 { 03525 for (Token *tok = list.front(); tok; tok = tok->next()) { 03526 if (tok->str() == "(") { 03527 tok = tok->link(); 03528 if (Token::Match(tok, ") %type% {") && 03529 !Token::Match(tok->next(), "const|namespace|class|struct|union")) 03530 tok->deleteNext(); 03531 } 03532 03533 if (Token::Match(tok, "[;{}] %type%") && tok->next()->isUpperCaseName()) { 03534 const Token *tok2 = tok->tokAt(2); 03535 if (tok2 && tok2->str() == "(") { 03536 unsigned int par = 0; 03537 for (; tok2; tok2 = tok2->next()) { 03538 if (tok2->str() == "(") 03539 ++par; 03540 else if (tok2->str() == ")") { 03541 if (par <= 1) 03542 break; 03543 --par; 03544 } 03545 } 03546 if (tok2 && tok2->str() == ")") 03547 tok2 = tok2->next(); 03548 } 03549 03550 // remove unknown macros before namespace|class|struct|union 03551 if (Token::Match(tok2, "namespace|class|struct|union")) { 03552 // is there a "{" for? 03553 const Token *tok3 = tok2; 03554 while (tok3 && !Token::Match(tok3,"[;{}()]")) 03555 tok3 = tok3->next(); 03556 if (tok3 && tok3->str() == "{") 03557 Token::eraseTokens(tok, tok2); 03558 continue; 03559 } 03560 03561 // remove unknown macros before foo::foo( 03562 if (Token::Match(tok2, "%type% :: %type%")) { 03563 const Token *tok3 = tok2; 03564 while (Token::Match(tok3, "%type% :: %type% ::")) 03565 tok3 = tok3->tokAt(2); 03566 if (Token::Match(tok3, "%type% :: %type% (") && tok3->str() == tok3->strAt(2)) 03567 Token::eraseTokens(tok, tok2); 03568 continue; 03569 } 03570 } 03571 03572 if (tok->str() == "{") 03573 tok = tok->link(); 03574 } 03575 } 03576 //--------------------------------------------------------------------------- 03577 03578 void Tokenizer::removeMacroInVarDecl() 03579 { 03580 for (Token *tok = list.front(); tok; tok = tok->next()) { 03581 if (Token::Match(tok, "[;{}] %var% (") && tok->next()->isUpperCaseName()) { 03582 // goto ')' parentheses 03583 const Token *tok2 = tok; 03584 int parlevel = 0; 03585 while (tok2) { 03586 if (tok2->str() == "(") 03587 ++parlevel; 03588 else if (tok2->str() == ")") { 03589 if (--parlevel <= 0) 03590 break; 03591 } 03592 tok2 = tok2->next(); 03593 } 03594 tok2 = tok2 ? tok2->next() : NULL; 03595 03596 // check if this is a variable declaration.. 03597 const Token *tok3 = tok2; 03598 while (tok3 && tok3->isUpperCaseName()) 03599 tok3 = tok3->next(); 03600 if (tok3 && (tok3->isStandardType() || Token::Match(tok3,"const|static|struct|union|class"))) 03601 Token::eraseTokens(tok,tok2); 03602 } 03603 } 03604 } 03605 //--------------------------------------------------------------------------- 03606 03607 void Tokenizer::removeRedundantAssignment() 03608 { 03609 for (Token *tok = list.front(); tok; tok = tok->next()) { 03610 if (tok->str() == "{") 03611 tok = tok->link(); 03612 03613 if (Token::Match(tok, ") const| {")) { 03614 // parse in this function.. 03615 std::set<unsigned int> localvars; 03616 if (tok->next()->str() == "const") 03617 tok = tok->next(); 03618 const Token * const end = tok->next()->link(); 03619 for (Token *tok2 = tok->next(); tok2 && tok2 != end; tok2 = tok2->next()) { 03620 // skip local class or struct 03621 if (Token::Match(tok2, "class|struct %type% {|:")) { 03622 // skip to '{' 03623 while (tok2 && tok2->str() != "{") 03624 tok2 = tok2->next(); 03625 03626 if (tok2) 03627 tok2 = tok2->link(); // skip local class or struct 03628 else 03629 return; 03630 } else if (Token::Match(tok2, "[;{}] %type% * %var% ;") && tok2->next()->str() != "return") { 03631 tok2 = tok2->tokAt(3); 03632 localvars.insert(tok2->varId()); 03633 } else if (Token::Match(tok2, "[;{}] %type% %var% ;") && tok2->next()->isStandardType()) { 03634 tok2 = tok2->tokAt(2); 03635 localvars.insert(tok2->varId()); 03636 } else if (tok2->varId() && 03637 !Token::Match(tok2->previous(), "[;{}] %var% = %char%|%num%|%var% ;")) { 03638 localvars.erase(tok2->varId()); 03639 } 03640 } 03641 localvars.erase(0); 03642 if (!localvars.empty()) { 03643 for (Token *tok2 = tok->next(); tok2 && tok2 != end;) { 03644 if (Token::Match(tok2, "[;{}] %type% %var% ;") && localvars.find(tok2->tokAt(2)->varId()) != localvars.end()) { 03645 tok2->deleteNext(3); 03646 } else if ((Token::Match(tok2, "[;{}] %type% * %var% ;") && 03647 localvars.find(tok2->tokAt(3)->varId()) != localvars.end()) || 03648 (Token::Match(tok2, "[;{}] %var% = %any% ;") && 03649 localvars.find(tok2->next()->varId()) != localvars.end())) { 03650 tok2->deleteNext(4); 03651 } else 03652 tok2 = tok2->next(); 03653 } 03654 } 03655 } 03656 } 03657 } 03658 03659 void Tokenizer::simplifyRealloc() 03660 { 03661 for (Token *tok = list.front(); tok; tok = tok->next()) { 03662 if (tok->str() == "(" || tok->str() == "[" || 03663 (tok->str() == "{" && tok->previous() && tok->previous()->str() == "=")) 03664 tok = tok->link(); 03665 else if (Token::Match(tok, "[;{}] %var% = realloc (")) { 03666 tok = tok->tokAt(3); 03667 if (Token::simpleMatch(tok->next(), "( 0 ,")) { 03668 //no "x = realloc(0,);" 03669 if (!Token::simpleMatch(tok->next()->link(), ") ;") || tok->next()->link()->previous() == tok->tokAt(3)) 03670 continue; 03671 03672 // delete "0 ," 03673 tok->next()->deleteNext(2); 03674 03675 // Change function name "realloc" to "malloc" 03676 tok->str("malloc"); 03677 tok = tok->next()->link(); 03678 } else { 03679 Token *tok2 = tok->next()->link()->tokAt(-2); 03680 //no "x = realloc(,0);" 03681 if (!Token::simpleMatch(tok2, ", 0 ) ;") || tok2 == tok->tokAt(2)) 03682 continue; 03683 03684 //remove ", 0" 03685 tok2 = tok2->previous(); 03686 tok2->deleteNext(2); 03687 //change "realloc" to "free" 03688 tok->str("free"); 03689 //insert "0" after "var =" 03690 tok = tok->previous(); 03691 tok->insertToken("0"); 03692 //move "var = 0" between "free(...)" and ";" 03693 tok2 = tok2->next(); 03694 Token::move(tok->previous(), tok->next(), tok2); 03695 //add missing ";" after "free(...)" 03696 tok2->insertToken(";"); 03697 //goto before last ";" and continue 03698 tok = tok->next(); 03699 } 03700 } 03701 } 03702 } 03703 03704 void Tokenizer::simplifyEmptyNamespaces() 03705 { 03706 if (isC()) 03707 return; 03708 03709 bool goback = false; 03710 for (Token *tok = list.front(); tok; tok = tok ? tok->next() : NULL) { 03711 if (goback) { 03712 tok = tok->previous(); 03713 goback = false; 03714 } 03715 if (tok->str() == "(" || tok->str() == "[" || tok->str() == "{") { 03716 tok = tok->link(); 03717 continue; 03718 } 03719 if (!Token::Match(tok, "namespace %var% {")) 03720 continue; 03721 if (tok->strAt(3) == "}") { 03722 tok->deleteNext(3); // remove '%var% { }' 03723 if (!tok->previous()) { 03724 // remove 'namespace' or replace it with ';' if isolated 03725 tok->deleteThis(); 03726 goback = true; 03727 } else { // '%any% namespace %any%' 03728 tok = tok->previous(); // goto previous token 03729 tok->deleteNext(); // remove next token: 'namespace' 03730 } 03731 } else { 03732 tok = tok->tokAt(2); 03733 } 03734 } 03735 } 03736 03737 void Tokenizer::simplifyFlowControl() 03738 { 03739 03740 for (Token *begin = list.front(); begin; begin = begin->next()) { 03741 03742 if (begin->str() == "(" || begin->str() == "[" || 03743 (begin->str() == "{" && begin->previous() && begin->strAt(-1) == "=")) 03744 begin = begin->link(); 03745 03746 //function scope 03747 if (!Token::simpleMatch(begin, ") {") && !Token::Match(begin, ") %var% {")) 03748 continue; 03749 03750 Token *end = begin->linkAt(1+(begin->next()->str() == "{" ? 0 : 1)); 03751 unsigned int indentlevel = 0; 03752 bool stilldead = false; 03753 03754 for (Token *tok = begin; tok != end; tok = tok->next()) { 03755 if (tok->str() == "(" || tok->str() == "[") { 03756 tok = tok->link(); 03757 continue; 03758 } 03759 03760 if (tok->str() == "{") { 03761 if (tok->previous() && tok->previous()->str() == "=") { 03762 tok = tok->link(); 03763 continue; 03764 } 03765 ++indentlevel; 03766 } else if (tok->str() == "}") { 03767 if (!indentlevel) 03768 break; 03769 --indentlevel; 03770 if (stilldead) { 03771 eraseDeadCode(tok, 0); 03772 if (indentlevel == 1 || tok->next()->str() != "}" || !Token::Match(tok->next()->link()->previous(), ";|{|}|do {")) 03773 stilldead = false; 03774 continue; 03775 } 03776 } 03777 03778 if (!indentlevel) 03779 continue; 03780 03781 if (Token::Match(tok,"continue|break ;")) { 03782 tok = tok->next(); 03783 eraseDeadCode(tok, 0); 03784 03785 } else if (Token::Match(tok,"return|goto") || 03786 Token::Match(tok,"exit|abort") || 03787 (tok->str() == "throw" && !isC())) { 03788 //TODO: ensure that we exclude user-defined 'exit|abort|throw', except for 'noreturn' 03789 //catch the first ';' 03790 for (Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) { 03791 if (tok2->str() == "(" || tok2->str() == "[") { 03792 tok2 = tok2->link(); 03793 } else if (tok2->str() == ";") { 03794 tok = tok2; 03795 eraseDeadCode(tok, 0); 03796 break; 03797 } else if (Token::Match(tok2, "[{}]")) 03798 break; //Wrong code. 03799 } 03800 //if everything is removed, then remove also the code after an inferior scope 03801 //only if the actual scope is not special 03802 if (indentlevel > 1 && tok->next()->str() == "}" && Token::Match(tok->next()->link()->previous(), ";|{|}|do {")) 03803 stilldead = true; 03804 } 03805 } 03806 begin = end; 03807 } 03808 } 03809 03810 03811 bool Tokenizer::removeRedundantConditions() 03812 { 03813 // Return value for function. Set to true if there are any simplifications 03814 bool ret = false; 03815 03816 for (Token *tok = list.front(); tok; tok = tok->next()) { 03817 if (tok->str() != "if") 03818 continue; 03819 03820 if (!Token::Match(tok->next(), "( %bool% ) {")) 03821 continue; 03822 03823 // Find matching else 03824 Token *elseTag = tok->linkAt(4)->next(); 03825 03826 bool boolValue = (tok->strAt(2) == "true"); 03827 03828 // Handle if with else 03829 if (Token::simpleMatch(elseTag, "else {")) { 03830 // Handle else 03831 if (boolValue == false) { 03832 // Convert "if( false ) {aaa;} else {bbb;}" => "{bbb;}" 03833 03834 //remove '(false)' 03835 tok->deleteNext(3); 03836 //delete dead code inside scope 03837 eraseDeadCode(tok, elseTag); 03838 //remove 'else' 03839 elseTag->deleteThis(); 03840 //remove 'if' 03841 tok->deleteThis(); 03842 } else { 03843 // Convert "if( true ) {aaa;} else {bbb;}" => "{aaa;}" 03844 const Token *end = elseTag->next()->link()->next(); 03845 03846 // Remove "else { bbb; }" 03847 elseTag = elseTag->previous(); 03848 eraseDeadCode(elseTag, end); 03849 03850 // Remove "if( true )" 03851 tok->deleteNext(3); 03852 tok->deleteThis(); 03853 } 03854 03855 ret = true; 03856 } 03857 03858 // Handle if without else 03859 else { 03860 if (boolValue == false) { 03861 //remove '(false)' 03862 tok->deleteNext(3); 03863 //delete dead code inside scope 03864 eraseDeadCode(tok, elseTag); 03865 //remove 'if' 03866 tok->deleteThis(); 03867 } else { 03868 // convert "if( true ) {aaa;}" => "{aaa;}" 03869 tok->deleteNext(3); 03870 tok->deleteThis(); 03871 } 03872 03873 ret = true; 03874 } 03875 } 03876 03877 return ret; 03878 } 03879 03880 void Tokenizer::removeRedundantFor() 03881 { 03882 for (Token *tok = list.front(); tok; tok = tok->next()) { 03883 if (Token::Match(tok, "[;{}] for ( %var% = %num% ; %var% < %num% ; ++| %var% ++| ) {")) { 03884 // Same variable name.. 03885 const std::string varname(tok->strAt(3)); 03886 const unsigned int varid(tok->tokAt(3)->varId()); 03887 if (varname != tok->strAt(7)) 03888 continue; 03889 const Token *vartok = tok->tokAt(11); 03890 if (vartok->str() == "++") 03891 vartok = vartok->next(); 03892 if (varname != vartok->str()) 03893 continue; 03894 03895 // Check that the difference of the numeric values is 1 03896 const MathLib::bigint num1(MathLib::toLongNumber(tok->strAt(5))); 03897 const MathLib::bigint num2(MathLib::toLongNumber(tok->strAt(9))); 03898 if (num1 + 1 != num2) 03899 continue; 03900 03901 // check how loop variable is used in loop.. 03902 bool read = false; 03903 bool write = false; 03904 const Token* end = tok->linkAt(2)->next()->link(); 03905 for (const Token *tok2 = tok->linkAt(2); tok2 != end; tok2 = tok2->next()) { 03906 if (tok2->str() == varname) { 03907 if (tok2->previous()->isArithmeticalOp() && 03908 tok2->next() && 03909 (tok2->next()->isArithmeticalOp() || tok2->next()->str() == ";")) { 03910 read = true; 03911 } else { 03912 read = write = true; 03913 break; 03914 } 03915 } 03916 } 03917 03918 // Simplify loop if loop variable isn't written 03919 if (!write) { 03920 // remove "for (" 03921 tok->deleteNext(2); 03922 03923 // If loop variable is read then keep assignment before 03924 // loop body.. 03925 if (read) { 03926 // goto ";" 03927 tok = tok->tokAt(4); 03928 } else { 03929 // remove "x = 0 ;" 03930 tok->deleteNext(4); 03931 } 03932 03933 // remove "x < 1 ; x ++ )" 03934 tok->deleteNext(7); 03935 03936 // Add assignment after the loop body so the loop variable 03937 // get the correct end value 03938 Token *tok2 = tok->next()->link(); 03939 tok2->insertToken(";"); 03940 tok2->insertToken(MathLib::longToString(num2)); 03941 tok2->insertToken("="); 03942 tok2->insertToken(varname); 03943 tok2->next()->varId(varid); 03944 } 03945 } 03946 } 03947 } 03948 03949 03950 void Tokenizer::removeRedundantSemicolons() 03951 { 03952 for (Token *tok = list.front(); tok; tok = tok->next()) { 03953 if (tok->str() == "(") { 03954 tok = tok->link(); 03955 } 03956 for (;;) { 03957 if (Token::simpleMatch(tok, "; ;")) { 03958 tok->deleteNext(); 03959 } else if (Token::simpleMatch(tok, "; { ; }")) { 03960 tok->deleteNext(3); 03961 } else { 03962 break; 03963 } 03964 } 03965 } 03966 } 03967 03968 03969 bool Tokenizer::simplifyAddBraces() 03970 { 03971 for (Token *tok = list.front(); tok; tok = tok->next()) { 03972 Token const * tokRet=simplifyAddBracesToCommand(tok); 03973 if (!tokRet) 03974 return false; 03975 } 03976 return true; 03977 } 03978 03979 Token *Tokenizer::simplifyAddBracesToCommand(Token *tok) 03980 { 03981 Token * tokEnd=tok; 03982 if (tok->str()=="for" || 03983 tok->str()=="BOOST_FOREACH" || 03984 tok->str()=="switch") { 03985 tokEnd=simplifyAddBracesPair(tok,true); 03986 } else if (tok->str()=="while") { 03987 Token *tokPossibleDo=tok->previous(); 03988 if (tokPossibleDo && 03989 tokPossibleDo->str()=="}") 03990 tokPossibleDo=tokPossibleDo->link(); 03991 if (tokPossibleDo) 03992 tokPossibleDo=tokPossibleDo->previous(); 03993 if (!tokPossibleDo || 03994 tokPossibleDo->str()!="do") 03995 tokEnd=simplifyAddBracesPair(tok,true); 03996 } else if (tok->str()=="do") { 03997 tokEnd=simplifyAddBracesPair(tok,false); 03998 if (tokEnd!=tok) { 03999 // walk on to next token, i.e. "while" 04000 // such that simplifyAddBracesPair does not close other braces 04001 // before the "while" 04002 if (tokEnd) { 04003 tokEnd=tokEnd->next(); 04004 if (!tokEnd) { 04005 // no while return input token 04006 syntaxError(tok); 04007 return NULL; 04008 } 04009 } 04010 } 04011 } else if (tok->str()=="if") { 04012 tokEnd=simplifyAddBracesPair(tok,true); 04013 if (!tokEnd) 04014 return NULL; 04015 Token * tokEndNext=tokEnd->next(); 04016 if (tokEndNext && tokEndNext->str()=="else") { 04017 Token * tokEndNextNext=tokEndNext->next(); 04018 if (tokEndNextNext && tokEndNextNext->str()=="if") { 04019 // do not change "else if ..." to "else { if ... }" 04020 tokEnd=simplifyAddBracesToCommand(tokEndNextNext); 04021 } else 04022 tokEnd=simplifyAddBracesPair(tokEndNext,false); 04023 } 04024 } 04025 04026 return tokEnd; 04027 } 04028 04029 Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition) 04030 { 04031 Token * tokCondition=tok->next(); 04032 Token *tokAfterCondition=tokCondition; 04033 if (commandWithCondition) { 04034 if (!tokCondition) { 04035 // Missing condition 04036 return tok; 04037 } 04038 if (tokCondition->str()=="(") 04039 tokAfterCondition=tokCondition->link(); 04040 else 04041 tokAfterCondition=NULL; 04042 if (!tokAfterCondition) { 04043 // Bad condition 04044 syntaxError(tok); 04045 return NULL; 04046 } 04047 tokAfterCondition=tokAfterCondition->next(); 04048 } 04049 if (!tokAfterCondition || 04050 ((tokAfterCondition->type()==Token::eBracket || 04051 tokAfterCondition->type()==Token::eExtendedOp)&& 04052 Token::Match(tokAfterCondition,")|}|>|,"))) { 04053 // No tokens left where to add braces around 04054 return tok; 04055 } 04056 Token * tokBracesEnd=NULL; 04057 if (tokAfterCondition->str()=="{") { 04058 // already surrounded by braces 04059 tokBracesEnd=tokAfterCondition->link(); 04060 } else { 04061 Token * tokEnd = simplifyAddBracesToCommand(tokAfterCondition); 04062 if (tokEnd->str()!="}") { 04063 // Token does not end with brace 04064 // Look for ; to add own closing brace after it 04065 while (tokEnd && 04066 tokEnd->str()!=";" && 04067 !((tokEnd->type()==Token::eBracket || 04068 tokEnd->type()==Token::eExtendedOp)&& 04069 Token::Match(tokEnd,")|}|>"))) { 04070 if (tokEnd->type()==Token::eBracket || 04071 (tokEnd->type()==Token::eExtendedOp && tokEnd->str()=="(")) { 04072 Token *tokInnerCloseBraket=tokEnd->link(); 04073 if (!tokInnerCloseBraket) { 04074 // Inner bracket does not close 04075 return tok; 04076 } 04077 tokEnd=tokInnerCloseBraket; 04078 } 04079 tokEnd=tokEnd->next(); 04080 } 04081 if (!tokEnd || 04082 tokEnd->str()!=";") { 04083 // No trailing ; 04084 return tok; 04085 } 04086 } 04087 04088 tokAfterCondition->previous()->insertToken("{"); 04089 Token * tokOpenBrace=tokAfterCondition->previous(); 04090 04091 tokEnd->insertToken("}"); 04092 Token * TokCloseBrace=tokEnd->next(); 04093 04094 Token::createMutualLinks(tokOpenBrace,TokCloseBrace); 04095 tokBracesEnd=TokCloseBrace; 04096 } 04097 04098 return tokBracesEnd; 04099 } 04100 04101 void Tokenizer::simplifyCompoundAssignment() 04102 { 04103 // Simplify compound assignments: 04104 // "a+=b" => "a = a + b" 04105 for (Token *tok = list.front(); tok; tok = tok->next()) { 04106 if (Token::Match(tok, "[;{}] (| *| (| %var%")) { 04107 // backup current token.. 04108 Token * const tok1 = tok; 04109 04110 if (tok->next()->str() == "*") 04111 tok = tok->next(); 04112 04113 if (tok->next() && tok->next()->str() == "(") { 04114 tok = tok->next()->link()->next(); 04115 } else { 04116 // variable.. 04117 tok = tok->tokAt(2); 04118 while (Token::Match(tok, ". %var%") || 04119 Token::Match(tok, "[|(")) { 04120 if (tok->str() == ".") 04121 tok = tok->tokAt(2); 04122 else { 04123 // goto "]" or ")" 04124 tok = tok->link(); 04125 04126 // goto next token.. 04127 tok = tok ? tok->next() : 0; 04128 } 04129 } 04130 } 04131 if (!tok) 04132 break; 04133 04134 // Is current token at a compound assignment: +=|-=|.. ? 04135 const std::string &str = tok->str(); 04136 std::string op; // operator used in assignment 04137 if (tok->isAssignmentOp() && str.size() == 2) 04138 op = str.substr(0, 1); 04139 else if (tok->isAssignmentOp() && str.size() == 3) 04140 op = str.substr(0, 2); 04141 else { 04142 tok = tok1; 04143 continue; 04144 } 04145 04146 // Remove the whole statement if it says: "+=0;", "-=0;", "*=1;" or "/=1;" 04147 if (Token::Match(tok, "+=|-= 0 ;") || 04148 Token::Match(tok, "+=|-= '\\0' ;") || 04149 Token::simpleMatch(tok, "|= 0 ;") || 04150 Token::Match(tok, "*=|/= 1 ;")) { 04151 tok = tok1; 04152 while (tok->next()->str() != ";") 04153 tok->deleteNext(); 04154 } else { 04155 // Enclose the rhs in parentheses.. 04156 if (!Token::Match(tok->tokAt(2), "[;)]")) { 04157 // Only enclose rhs in parentheses if there is some operator 04158 bool someOperator = false; 04159 for (Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) { 04160 if (tok2->str() == "(") 04161 tok2 = tok2->link(); 04162 04163 if (Token::Match(tok2->next(), "[;)]")) { 04164 if (someOperator) { 04165 tok->insertToken("("); 04166 tok2->insertToken(")"); 04167 Token::createMutualLinks(tok->next(), tok2->next()); 04168 } 04169 break; 04170 } 04171 04172 someOperator |= (tok2->isOp() || tok2->str() == "?"); 04173 } 04174 } 04175 04176 // simplify the compound assignment.. 04177 tok->str("="); 04178 tok->insertToken(op); 04179 04180 std::stack<Token *> tokend; 04181 for (Token *tok2 = tok->previous(); tok2 && tok2 != tok1; tok2 = tok2->previous()) { 04182 // Don't duplicate ++ and --. Put preincrement in lhs. Put 04183 // postincrement in rhs. 04184 if (tok2->type() == Token::eIncDecOp) { 04185 // pre increment/decrement => don't copy 04186 if (tok2->next()->isName()) { 04187 continue; 04188 } 04189 04190 // post increment/decrement => move from lhs to rhs 04191 tok->insertToken(tok2->str()); 04192 tok2->deleteThis(); 04193 continue; 04194 } 04195 04196 // Copy token from lhs to rhs 04197 tok->insertToken(tok2->str()); 04198 tok->next()->varId(tok2->varId()); 04199 if (Token::Match(tok->next(), "]|)")) 04200 tokend.push(tok->next()); 04201 else if (Token::Match(tok->next(), "(|[")) { 04202 Token::createMutualLinks(tok->next(), tokend.top()); 04203 tokend.pop(); 04204 } 04205 } 04206 } 04207 } 04208 } 04209 } 04210 04211 void Tokenizer::simplifyConditionOperator() 04212 { 04213 for (Token *tok = list.front(); tok; tok = tok->next()) { 04214 if (tok->str() == "(" || tok->str() == "[" || 04215 (tok->str() == "{" && tok->previous() && tok->previous()->str() == "=")) 04216 tok = tok->link(); 04217 04218 if (Token::Match(tok, "[{};] *| %var% = %any% ? %any% : %any% ;") || 04219 Token::Match(tok, "[{};] return %any% ? %any% : %any% ;")) { 04220 04221 // backup varids so they can be set properly 04222 std::map<std::string, unsigned int> varid; 04223 for (const Token *tok2 = tok->next(); tok2->str() != ";"; tok2 = tok2->next()) { 04224 if (tok2->varId()) 04225 varid[tok2->str()] = tok2->varId(); 04226 } 04227 04228 std::string var(tok->next()->str()); 04229 bool isPointer = false; 04230 bool isReturn = false; 04231 if (tok->next()->str() == "*") { 04232 tok = tok->next(); 04233 var = tok->next()->str(); 04234 isPointer = true; 04235 } else if (tok->next()->str() == "return") { 04236 isReturn = true; 04237 } 04238 04239 Token *tok2 = tok->tokAt(3 - (isReturn ? 1 : 0)); 04240 if (!tok2->isName() && !tok2->isNumber() && tok2->str()[0] != '\"') 04241 continue; 04242 const std::string condition(tok2->str()); 04243 tok2 = tok2->tokAt(2); 04244 if (!tok2->isName() && !tok2->isNumber() && tok2->str()[0] != '\"') 04245 continue; 04246 const std::string value1(tok2->str()); 04247 tok2 = tok2->tokAt(2); 04248 if (!tok2->isName() && !tok2->isNumber() && tok2->str()[0] != '\"') 04249 continue; 04250 const std::string value2(tok2->str()); 04251 04252 if (isPointer) { 04253 tok = tok->previous(); 04254 tok->deleteNext(9); 04255 } else if (isReturn) 04256 tok->deleteNext(6); 04257 else 04258 tok->deleteNext(8); 04259 04260 Token *starttok = 0; 04261 04262 std::string str; 04263 if (isReturn) 04264 str = "if ( condition ) { return value1 ; } return value2 ;"; 04265 else 04266 str = "if ( condition ) { * var = value1 ; } else { * var = value2 ; }"; 04267 04268 std::string::size_type pos1 = 0; 04269 while (pos1 != std::string::npos) { 04270 if (str[pos1] == '*') { 04271 pos1 += 2; 04272 if (isPointer) { 04273 tok->insertToken("*"); 04274 tok = tok->next(); 04275 } 04276 } 04277 std::string::size_type pos2 = str.find(" ", pos1); 04278 if (pos2 == std::string::npos) { 04279 tok->insertToken(str.substr(pos1)); 04280 pos1 = pos2; 04281 } else { 04282 tok->insertToken(str.substr(pos1, pos2 - pos1)); 04283 pos1 = pos2 + 1; 04284 } 04285 tok = tok->next(); 04286 04287 // set links. 04288 if (tok->str() == "(" || tok->str() == "{") 04289 starttok = tok; 04290 else if (starttok && (tok->str() == ")" || tok->str() == "}")) { 04291 Token::createMutualLinks(starttok, tok); 04292 starttok = 0; 04293 } else if (tok->str() == "condition") 04294 tok->str(condition); 04295 else if (tok->str() == "var") 04296 tok->str(var); 04297 else if (tok->str() == "value1") 04298 tok->str(value1); 04299 else if (tok->str() == "value2") 04300 tok->str(value2); 04301 04302 // set varid. 04303 if (varid.find(tok->str()) != varid.end()) 04304 tok->varId(varid[tok->str()]); 04305 } 04306 } 04307 } 04308 } 04309 04310 bool Tokenizer::simplifyConditions() 04311 { 04312 bool ret = false; 04313 04314 for (Token *tok = list.front(); tok; tok = tok->next()) { 04315 if (Token::Match(tok, "! %bool%|%num%")) { 04316 tok->deleteThis(); 04317 if (tok->str() == "0" || tok->str() == "false") 04318 tok->str("true"); 04319 else 04320 tok->str("false"); 04321 04322 ret = true; 04323 } 04324 04325 if (Token::simpleMatch(tok, "( true &&") || 04326 Token::simpleMatch(tok, "&& true &&") || 04327 Token::simpleMatch(tok->next(), "&& true )")) { 04328 tok->deleteNext(2); 04329 ret = true; 04330 } 04331 04332 else if (Token::simpleMatch(tok, "( false ||") || 04333 Token::simpleMatch(tok, "|| false ||") || 04334 Token::simpleMatch(tok->next(), "|| false )")) { 04335 tok->deleteNext(2); 04336 ret = true; 04337 } 04338 04339 else if (Token::simpleMatch(tok, "( true ||") || 04340 Token::simpleMatch(tok, "( false &&")) { 04341 Token::eraseTokens(tok->next(), tok->link()); 04342 ret = true; 04343 } 04344 04345 else if (Token::simpleMatch(tok, "|| true )") || 04346 Token::simpleMatch(tok, "&& false )")) { 04347 tok = tok->next(); 04348 Token::eraseTokens(tok->next()->link(), tok); 04349 ret = true; 04350 } 04351 04352 else if (Token::simpleMatch(tok, "&& false &&") || 04353 Token::simpleMatch(tok, "|| true ||")) { 04354 //goto '(' 04355 Token *tok2 = tok; 04356 while (tok2->previous()) { 04357 if (tok2->previous()->str() == ")") 04358 tok2 = tok2->previous()->link(); 04359 else { 04360 tok2 = tok2->previous(); 04361 if (tok2->str() == "(") 04362 break; 04363 } 04364 } 04365 if (!tok2) 04366 continue; 04367 //move tok to 'true|false' position 04368 tok = tok->next(); 04369 //remove everything before 'true|false' 04370 Token::eraseTokens(tok2, tok); 04371 //remove everything after 'true|false' 04372 Token::eraseTokens(tok, tok2->link()); 04373 ret = true; 04374 } 04375 04376 // Change numeric constant in condition to "true" or "false" 04377 if (Token::Match(tok, "if|while ( %num% )|%oror%|&&")) { 04378 tok->tokAt(2)->str((tok->strAt(2) != "0") ? "true" : "false"); 04379 ret = true; 04380 } 04381 if (Token::Match(tok, "&&|%oror% %num% )|%oror%|&&")) { 04382 tok->next()->str((tok->next()->str() != "0") ? "true" : "false"); 04383 ret = true; 04384 } 04385 04386 // Reduce "(%num% == %num%)" => "(true)"/"(false)" 04387 if (Token::Match(tok, "&&|%oror%|(") && 04388 (Token::Match(tok->next(), "%num% %any% %num%") || 04389 Token::Match(tok->next(), "%bool% %any% %bool%")) && 04390 Token::Match(tok->tokAt(4), "&&|%oror%|)|?")) { 04391 std::string cmp = tok->strAt(2); 04392 bool result = false; 04393 if (tok->next()->isNumber()) { 04394 // Compare numbers 04395 04396 if (cmp == "==" || cmp == "!=") { 04397 const std::string& op1(tok->next()->str()); 04398 const std::string& op2(tok->strAt(3)); 04399 04400 bool eq = false; 04401 if (MathLib::isInt(op1) && MathLib::isInt(op2)) 04402 eq = (MathLib::toLongNumber(op1) == MathLib::toLongNumber(op2)); 04403 else 04404 eq = (op1 == op2); 04405 04406 if (cmp == "==") 04407 result = eq; 04408 else 04409 result = !eq; 04410 } else { 04411 double op1 = MathLib::toDoubleNumber(tok->next()->str()); 04412 double op2 = MathLib::toDoubleNumber(tok->strAt(3)); 04413 if (cmp == ">=") 04414 result = (op1 >= op2); 04415 else if (cmp == ">") 04416 result = (op1 > op2); 04417 else if (cmp == "<=") 04418 result = (op1 <= op2); 04419 else if (cmp == "<") 04420 result = (op1 < op2); 04421 else 04422 cmp = ""; 04423 } 04424 } else { 04425 // Compare boolean 04426 bool op1 = (tok->next()->str() == std::string("true")); 04427 bool op2 = (tok->strAt(3) == std::string("true")); 04428 04429 if (cmp == "==") 04430 result = (op1 == op2); 04431 else if (cmp == "!=") 04432 result = (op1 != op2); 04433 else if (cmp == ">=") 04434 result = (op1 >= op2); 04435 else if (cmp == ">") 04436 result = (op1 > op2); 04437 else if (cmp == "<=") 04438 result = (op1 <= op2); 04439 else if (cmp == "<") 04440 result = (op1 < op2); 04441 else 04442 cmp = ""; 04443 } 04444 04445 if (! cmp.empty()) { 04446 tok = tok->next(); 04447 tok->deleteNext(2); 04448 04449 tok->str(result ? "true" : "false"); 04450 ret = true; 04451 } 04452 } 04453 } 04454 04455 return ret; 04456 } 04457 04458 bool Tokenizer::simplifyConstTernaryOp() 04459 { 04460 bool ret = false; 04461 for (Token *tok = list.front(); tok; tok = tok->next()) { 04462 if (tok->str() != "?") 04463 continue; 04464 04465 if (!Token::Match(tok->tokAt(-2), "<|=|,|(|[|{|}|;|case|return %bool%|%num%") && 04466 !Token::Match(tok->tokAt(-4), "<|=|,|(|[|{|}|;|case|return ( %bool%|%num% )")) 04467 continue; 04468 04469 const int offset = (tok->previous()->str() == ")") ? 2 : 1; 04470 04471 if (tok->strAt(-2*offset) == "<" && !TemplateSimplifier::templateParameters(tok->tokAt(-2*offset))) 04472 continue; 04473 04474 // Find the token ":" then go to the next token 04475 Token *semicolon = skipTernaryOp(tok); 04476 if (!semicolon || semicolon->previous()->str() != ":" || !semicolon->next()) 04477 continue; 04478 04479 //handle the GNU extension: "x ? : y" <-> "x ? x : y" 04480 if (semicolon->previous() == tok->next()) 04481 tok->insertToken(tok->strAt(-offset)); 04482 04483 // go back before the condition, if possible 04484 tok = tok->tokAt(-2); 04485 if (offset == 2) { 04486 // go further back before the "(" 04487 tok = tok->tokAt(-2); 04488 //simplify the parentheses 04489 tok->deleteNext(); 04490 tok->next()->deleteNext(); 04491 } 04492 04493 if (tok->next()->str() == "false" || tok->next()->str() == "0") { 04494 // Use code after semicolon, remove code before it. 04495 Token::eraseTokens(tok, semicolon); 04496 04497 tok = tok->next(); 04498 ret = true; 04499 } 04500 04501 // The condition is true. Delete the operator after the ":".. 04502 else { 04503 // delete the condition token and the "?" 04504 tok->deleteNext(2); 04505 04506 unsigned int ternaryOplevel = 0; 04507 for (const Token *endTok = semicolon; endTok; endTok = endTok->next()) { 04508 if (endTok->str() == "(" || endTok->str() == "[" || endTok->str() == "{") { 04509 endTok = endTok->link(); 04510 } 04511 04512 else if (endTok->str() == "?") 04513 ++ternaryOplevel; 04514 else if (Token::Match(endTok, ")|}|]|;|,|:")) { 04515 if (endTok->str() == ":" && ternaryOplevel) 04516 --ternaryOplevel; 04517 else { 04518 Token::eraseTokens(semicolon->tokAt(-2), endTok); 04519 ret = true; 04520 break; 04521 } 04522 } 04523 } 04524 } 04525 } 04526 04527 return ret; 04528 } 04529 04530 void Tokenizer::simplifyUndefinedSizeArray() 04531 { 04532 for (Token *tok = list.front(); tok; tok = tok->next()) { 04533 if (Token::Match(tok, "%type%")) { 04534 Token *tok2 = tok->next(); 04535 while (tok2 && tok2->str() == "*") 04536 tok2 = tok2->next(); 04537 if (!Token::Match(tok2, "%var% [ ]")) 04538 continue; 04539 04540 tok = tok2->previous(); 04541 Token *end = tok2->next(); 04542 unsigned int count = 0; 04543 while (Token::Match(end, "[ ] [;=[]")) { 04544 end = end->tokAt(2); 04545 ++count; 04546 } 04547 if (Token::Match(end, "[;=]")) { 04548 do { 04549 tok2->deleteNext(2); 04550 tok->insertToken("*"); 04551 } while (--count); 04552 tok = end; 04553 } else 04554 tok = tok->tokAt(3); 04555 } 04556 } 04557 } 04558 04559 void Tokenizer::simplifyCasts() 04560 { 04561 for (Token *tok = list.front(); tok; tok = tok->next()) { 04562 // #2897 : don't remove cast in such cases: 04563 // *((char *)a + 1) = 0; 04564 // #3596 : remove cast when casting a function pointer: 04565 // (*(void (*)(char *))fp)(x); 04566 if (!tok->isName() && 04567 Token::simpleMatch(tok->next(), "* (") && 04568 !Token::Match(tok->linkAt(2), ") %var%") && 04569 !Token::simpleMatch(tok->linkAt(2), ") &")) { 04570 tok = tok->linkAt(2); 04571 continue; 04572 } 04573 // #3935 : don't remove cast in such cases: 04574 // ((char *)a)[1] = 0; 04575 if (tok->str() == "(" && Token::simpleMatch(tok->link(), ") [")) { 04576 tok = tok->link(); 04577 continue; 04578 } 04579 // #4164 : ((unsigned char)1) => (1) 04580 if (Token::Match(tok->next(), "( unsigned| %type% ) %num%") && tok->next()->link()->previous()->isStandardType()) { 04581 const MathLib::bigint value = MathLib::toLongNumber(tok->next()->link()->next()->str()); 04582 unsigned int bits = 8 * _typeSize[tok->next()->link()->previous()->str()]; 04583 if (!tok->tokAt(2)->isUnsigned()) 04584 bits--; 04585 if (bits < 31 && value >= 0 && value < (1LL << bits)) { 04586 Token::eraseTokens(tok, tok->next()->link()->next()); 04587 } 04588 continue; 04589 } 04590 04591 while ((Token::Match(tok->next(), "( %type% *| *| *| ) *|&| %var%") && (tok->str() != ")" || tok->tokAt(2)->isStandardType())) || 04592 Token::Match(tok->next(), "( %type% %type% *| *| *| ) *|&| %var%") || 04593 (!tok->isName() && (Token::Match(tok->next(), "( %type% * *| *| ) (") || 04594 Token::Match(tok->next(), "( %type% %type% * *| *| ) (")))) { 04595 if (tok->isName() && tok->str() != "return") 04596 break; 04597 04598 if (tok->strAt(-1) == "operator") 04599 break; 04600 04601 // Remove cast.. 04602 Token::eraseTokens(tok, tok->next()->link()->next()); 04603 04604 // Remove '* &' 04605 if (Token::simpleMatch(tok, "* &")) { 04606 tok->deleteNext(); 04607 tok->deleteThis(); 04608 } 04609 04610 if (tok->str() == ")" && tok->link()->previous()) { 04611 // If there was another cast before this, go back 04612 // there to check it also. e.g. "(int)(char)x" 04613 tok = tok->link()->previous(); 04614 } 04615 } 04616 04617 // Replace pointer casts of 0.. "(char *)0" => "0" 04618 while (Token::Match(tok->next(), "( %type% * ) 0") || 04619 Token::Match(tok->next(), "( %type% %type% * ) 0")) { 04620 Token::eraseTokens(tok, tok->next()->link()->next()); 04621 if (tok->str() == ")" && tok->link()->previous()) { 04622 // If there was another cast before this, go back 04623 // there to check it also. e.g. "(char*)(char*)0" 04624 tok = tok->link()->previous(); 04625 } 04626 } 04627 04628 while (Token::Match(tok->next(), "dynamic_cast|reinterpret_cast|const_cast|static_cast <")) { 04629 Token *tok2 = tok->next(); 04630 tok2->next()->findClosingBracket(tok2); 04631 04632 if (Token::simpleMatch(tok2, "> (")) { 04633 Token *closeBracket = tok2->next()->link(); 04634 if (closeBracket) { 04635 Token::eraseTokens(tok, tok2->tokAt(2)); 04636 closeBracket->deleteThis(); 04637 } else { 04638 break; 04639 } 04640 } else { 04641 break; 04642 } 04643 } 04644 } 04645 } 04646 04647 04648 bool Tokenizer::simplifyFunctionParameters() 04649 { 04650 for (Token *tok = list.front(); tok; tok = tok->next()) { 04651 if (tok->str() == "{" || tok->str() == "[" || tok->str() == "(") { 04652 tok = tok->link(); 04653 } 04654 04655 // Find the function e.g. foo( x ) or foo( x, y ) 04656 else if (Token::Match(tok, "%var% ( %var% [,)]") && 04657 !(tok->strAt(-1) == ":" || tok->strAt(-1) == ",")) { 04658 // We have found old style function, now we need to change it 04659 04660 // First step: Get list of argument names in parentheses 04661 std::map<std::string, Token *> argumentNames; 04662 bool bailOut = false; 04663 Token * tokparam = NULL; 04664 04665 //take count of the function name.. 04666 const std::string& funcName(tok->str()); 04667 04668 //floating token used to check for parameters 04669 Token *tok1 = tok; 04670 04671 while (NULL != (tok1 = tok1->tokAt(2))) { 04672 if (!Token::Match(tok1, "%var% [,)]")) { 04673 bailOut = true; 04674 break; 04675 } 04676 04677 //same parameters: take note of the parameter 04678 if (argumentNames.find(tok1->str()) != argumentNames.end()) 04679 tokparam = tok1; 04680 else if (tok1->str() != funcName) 04681 argumentNames[tok1->str()] = tok1; 04682 else { 04683 if (tok1->next()->str() == ")") { 04684 if (tok1->previous()->str() == ",") { 04685 tok1 = tok1->tokAt(-2); 04686 tok1->deleteNext(2); 04687 } else { 04688 tok1 = tok1->previous(); 04689 tok1->deleteNext(); 04690 bailOut = true; 04691 break; 04692 } 04693 } else { 04694 tok1 = tok1->tokAt(-2); 04695 tok1->next()->deleteNext(2); 04696 } 04697 } 04698 04699 if (tok1->next()->str() == ")") { 04700 tok1 = tok1->tokAt(2); 04701 //expect at least a type name after round brace.. 04702 if (!tok1 || !tok1->isName()) 04703 bailOut = true; 04704 break; 04705 } 04706 } 04707 04708 //goto '(' 04709 tok = tok->next(); 04710 04711 if (bailOut) { 04712 tok = tok->link(); 04713 continue; 04714 } 04715 04716 tok1 = tok->link()->next(); 04717 04718 // there should be the sequence '; {' after the round parentheses 04719 for (const Token* tok2 = tok1; tok2; tok2 = tok2->next()) { 04720 if (Token::simpleMatch(tok2, "; {")) 04721 break; 04722 else if (tok2->str() == "{") { 04723 bailOut = true; 04724 break; 04725 } 04726 } 04727 04728 if (bailOut) { 04729 tok = tok->link(); 04730 continue; 04731 } 04732 04733 // Last step: check out if the declarations between ')' and '{' match the parameters list 04734 std::map<std::string, Token *> argumentNames2; 04735 04736 while (tok1 && tok1->str() != "{") { 04737 if (tok1->str() == "(" || tok1->str() == ")") { 04738 bailOut = true; 04739 break; 04740 } 04741 if (tok1->str() == ";") { 04742 if (tokparam) { 04743 syntaxError(tokparam); 04744 return false; 04745 } 04746 Token *tok2 = tok1->previous(); 04747 while (tok2->str() == "]") 04748 tok2 = tok2->link()->previous(); 04749 04750 //it should be a name.. 04751 if (!tok2->isName()) { 04752 bailOut = true; 04753 break; 04754 } 04755 04756 if (argumentNames2.find(tok2->str()) != argumentNames2.end()) { 04757 //same parameter names... 04758 syntaxError(tok1); 04759 return false; 04760 } else 04761 argumentNames2[tok2->str()] = tok2; 04762 04763 if (argumentNames.find(tok2->str()) == argumentNames.end()) { 04764 //non-matching parameter... bailout 04765 bailOut = true; 04766 break; 04767 } 04768 } 04769 tok1 = tok1->next(); 04770 } 04771 04772 if (bailOut || !tok1) { 04773 tok = tok->link(); 04774 continue; 04775 } 04776 04777 //the two containers may not hold the same size... 04778 //in that case, the missing parameters are defined as 'int' 04779 if (argumentNames.size() != argumentNames2.size()) { 04780 //move back 'tok1' to the last ';' 04781 tok1 = tok1->previous(); 04782 std::map<std::string, Token *>::iterator it; 04783 for (it = argumentNames.begin(); it != argumentNames.end(); ++it) { 04784 if (argumentNames2.find(it->first) == argumentNames2.end()) { 04785 //add the missing parameter argument declaration 04786 tok1->insertToken(";"); 04787 tok1->insertToken(it->first); 04788 //register the change inside argumentNames2 04789 argumentNames2[it->first] = tok1->next(); 04790 tok1->insertToken("int"); 04791 } 04792 } 04793 } 04794 04795 while (tok->str() != ")") { 04796 //initialize start and end tokens to be moved 04797 Token *declStart = argumentNames2[tok->next()->str()]; 04798 Token *declEnd = declStart; 04799 while (declStart->previous()->str() != ";" && declStart->previous()->str() != ")") 04800 declStart = declStart->previous(); 04801 while (declEnd->next()->str() != ";" && declEnd->next()->str() != "{") 04802 declEnd = declEnd->next(); 04803 04804 //remove ';' after declaration 04805 declEnd->deleteNext(); 04806 04807 //replace the parameter name in the parentheses with all the declaration 04808 Token::replace(tok->next(), declStart, declEnd); 04809 04810 //since there are changes to tokens, put tok where tok1 is 04811 tok = declEnd->next(); 04812 } 04813 //goto forward and continue 04814 tok = tok->next()->link(); 04815 } 04816 } 04817 return true; 04818 } 04819 04820 void Tokenizer::simplifyPointerToStandardType() 04821 { 04822 if (!isC()) 04823 return; 04824 04825 for (Token *tok = list.front(); tok; tok = tok->next()) { 04826 if (!Token::Match(tok, "& %var% [ 0 ]")) 04827 continue; 04828 04829 // Remove '[ 0 ]' suffix 04830 tok->next()->eraseTokens(tok->next(), tok->tokAt(5)); 04831 // Remove '&' prefix 04832 tok = tok->previous(); 04833 tok->deleteNext(); 04834 } 04835 } 04836 04837 void Tokenizer:: simplifyFunctionPointers() 04838 { 04839 for (Token *tok = list.front(); tok; tok = tok->next()) { 04840 // #2873 - dont simplify function pointer usage here: 04841 // (void)(xy(*p)(0)); 04842 if (Token::simpleMatch(tok, ") (")) { 04843 tok = tok->next()->link(); 04844 continue; 04845 } 04846 04847 // check for function pointer cast 04848 if (Token::Match(tok, "( %type% *| *| ( * ) (") || 04849 Token::Match(tok, "( %type% %type% *| *| ( * ) (") || 04850 Token::Match(tok, "static_cast < %type% *| *| ( * ) (") || 04851 Token::Match(tok, "static_cast < %type% %type% *| *| ( * ) (")) { 04852 Token *tok1 = tok; 04853 04854 if (tok1->str() == "static_cast") 04855 tok1 = tok1->next(); 04856 04857 tok1 = tok1->next(); 04858 04859 if (Token::Match(tok1->next(), "%type%")) 04860 tok1 = tok1->next(); 04861 04862 while (tok1->next()->str() == "*") 04863 tok1 = tok1->next(); 04864 04865 // check that the cast ends 04866 if (!Token::Match(tok1->linkAt(4), ") )|>")) 04867 continue; 04868 04869 // ok simplify this function pointer cast to an ordinary pointer cast 04870 tok1->deleteNext(); 04871 tok1->next()->deleteNext(); 04872 Token::eraseTokens(tok1->next(), tok1->linkAt(2)->next()); 04873 continue; 04874 } 04875 04876 // check for start of statement 04877 else if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|(|public:|protected:|private:")) 04878 continue; 04879 04880 if (Token::Match(tok, "%type% *| *| ( * %var% [| ]| ) (")) 04881 ; 04882 else if (Token::Match(tok, "%type% %type% *| *| ( * %var% [| ]| ) (")) 04883 tok = tok->next(); 04884 else 04885 continue; 04886 04887 while (tok->next()->str() == "*") 04888 tok = tok->next(); 04889 04890 // check that the declaration ends 04891 const Token *endTok = tok->next()->link()->next()->link(); 04892 if (!Token::Match(endTok, ") ;|,|)|=|[")) 04893 continue; 04894 04895 // ok simplify this function pointer to an ordinary pointer 04896 Token::eraseTokens(tok->next()->link(), endTok->next()); 04897 tok->next()->link()->deleteThis(); 04898 tok->deleteNext(); 04899 } 04900 } 04901 04902 04903 bool Tokenizer::simplifyFunctionReturn() 04904 { 04905 bool ret = false; 04906 for (const Token *tok = tokens(); tok; tok = tok->next()) { 04907 if (tok->str() == "{") 04908 tok = tok->link(); 04909 04910 else if (Token::Match(tok, "%var% ( ) { return %bool%|%char%|%num%|%str% ; }")) { 04911 const Token* const any = tok->tokAt(5); 04912 04913 const std::string pattern("(|[|=|%cop% " + tok->str() + " ( ) ;|]|)|%cop%"); 04914 for (Token *tok2 = list.front(); tok2; tok2 = tok2->next()) { 04915 if (Token::Match(tok2, pattern.c_str())) { 04916 tok2 = tok2->next(); 04917 tok2->str(any->str()); 04918 tok2->deleteNext(2); 04919 ret = true; 04920 } 04921 } 04922 } 04923 } 04924 04925 return ret; 04926 } 04927 04928 04929 static void incdec(std::string &value, const std::string &op) 04930 { 04931 int ivalue = 0; 04932 std::istringstream istr(value); 04933 istr >> ivalue; 04934 if (op == "++") 04935 ++ivalue; 04936 else if (op == "--") 04937 --ivalue; 04938 std::ostringstream ostr; 04939 ostr << ivalue; 04940 value = ostr.str(); 04941 } 04942 04943 04944 04945 void Tokenizer::simplifyVarDecl(bool only_k_r_fpar) 04946 { 04947 // Split up variable declarations.. 04948 // "int a=4;" => "int a; a=4;" 04949 bool finishedwithkr = true; 04950 for (Token *tok = list.front(); tok; tok = tok->next()) { 04951 if (Token::simpleMatch(tok, "= {")) { 04952 tok = tok->next()->link(); 04953 } 04954 04955 if (only_k_r_fpar && finishedwithkr) { 04956 if (tok->str() == "(" || tok->str() == "[" || tok->str() == "{") { 04957 tok = tok->link(); 04958 if (tok->next() && Token::Match(tok, ") !!{")) 04959 tok = tok->next(); 04960 else 04961 continue; 04962 } else 04963 continue; 04964 } else if (tok->str() == "(") { 04965 tok = tok->link(); 04966 04967 // TestTokenizer::vardecl24 - lambda functions.. 04968 if (isCPP() && tok->previous()->str() == "}") 04969 tok = tok->previous()->link(); 04970 } 04971 04972 if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|)|public:|protected:|private:")) 04973 continue; 04974 04975 Token *type0 = tok; 04976 if (!Token::Match(type0, "::| %type%")) 04977 continue; 04978 if (Token::Match(type0, "else|return|public:|protected:|private:")) 04979 continue; 04980 04981 bool isconst = false; 04982 bool isstatic = false; 04983 Token *tok2 = type0; 04984 unsigned int typelen = 1; 04985 04986 if (tok2->str() == "::") { 04987 tok2 = tok2->next(); 04988 typelen++; 04989 } 04990 04991 //check if variable is declared 'const' or 'static' or both 04992 while (tok2) { 04993 if (!Token::Match(tok2, "const|static") && Token::Match(tok2, "%type% const|static")) { 04994 tok2 = tok2->next(); 04995 ++typelen; 04996 } 04997 04998 if (tok2->str() == "const") 04999 isconst = true; 05000 05001 else if (tok2->str() == "static") 05002 isstatic = true; 05003 05004 else if (Token::Match(tok2, "%type% :: %type%")) { 05005 tok2 = tok2->next(); 05006 ++typelen; 05007 } 05008 05009 else 05010 break; 05011 05012 if (tok2->strAt(1) == "*") 05013 break; 05014 05015 tok2 = tok2->next(); 05016 ++typelen; 05017 } 05018 05019 // strange looking variable declaration => don't split up. 05020 if (Token::Match(tok2, "%type% *| %var% , %type% *| %var%")) 05021 continue; 05022 05023 if (Token::Match(tok2, "struct|union|class %type%")) { 05024 tok2 = tok2->next(); 05025 ++typelen; 05026 } 05027 05028 // check for qualification.. 05029 if (Token::Match(tok2, ":: %type%")) { 05030 ++typelen; 05031 tok2 = tok2->next(); 05032 } 05033 05034 //skip combinations of templates and namespaces 05035 while (Token::Match(tok2, "%type% <") || Token::Match(tok2, "%type% ::")) { 05036 if (tok2->next()->str() == "<" && !TemplateSimplifier::templateParameters(tok2->next())) { 05037 tok2 = NULL; 05038 break; 05039 } 05040 typelen += 2; 05041 tok2 = tok2->tokAt(2); 05042 if (tok2 && tok2->previous()->str() == "::") 05043 continue; 05044 unsigned int indentlevel = 0; 05045 unsigned int parens = 0; 05046 05047 for (Token *tok3 = tok2; tok3; tok3 = tok3->next()) { 05048 ++typelen; 05049 05050 if (tok3->str() == "<" && !parens) { 05051 ++indentlevel; 05052 } else if (tok3->str() == ">" && !parens) { 05053 if (indentlevel == 0) { 05054 tok2 = tok3->next(); 05055 break; 05056 } 05057 --indentlevel; 05058 } else if (tok3->str() == ">>" && !parens) { 05059 if (indentlevel <= 1U) { 05060 tok2 = tok3->next(); 05061 break; 05062 } 05063 indentlevel -= 2; 05064 } else if (tok3->str() == "(") { 05065 ++parens; 05066 } else if (tok3->str() == ")") { 05067 if (!parens) { 05068 tok2 = NULL; 05069 break; 05070 } 05071 --parens; 05072 } else if (tok3->str() == ";") { 05073 break; 05074 } 05075 } 05076 05077 if (Token::Match(tok2, ":: %type%")) { 05078 ++typelen; 05079 tok2 = tok2->next(); 05080 } 05081 } 05082 05083 //pattern: "%type% *| ... *| const| %var% ,|=" 05084 if (Token::Match(tok2, "%type%") || 05085 (tok2 && tok2->previous() && tok2->previous()->str() == ">")) { 05086 bool ispointer = false; 05087 Token *varName = tok2; 05088 if (!tok2->previous() || tok2->previous()->str() != ">") 05089 varName = varName->next(); 05090 else 05091 --typelen; 05092 //skip all the pointer part 05093 while (varName && varName->str() == "*") { 05094 ispointer = true; 05095 varName = varName->next(); 05096 } 05097 05098 while (Token::Match(varName, "%type% %type%")) { 05099 if (varName->str() != "const") { 05100 ++typelen; 05101 } 05102 varName = varName->next(); 05103 } 05104 //non-VLA case 05105 if (Token::Match(varName, "%var% ,|=")) { 05106 if (varName->str() != "operator") { 05107 tok2 = varName->next(); // The ',' or '=' token 05108 05109 if (tok2->str() == "=") { 05110 if (isstatic) { 05111 if (Token::Match(tok2->next(), "%num% ,")) 05112 tok2 = tok2->tokAt(2); 05113 else 05114 tok2 = NULL; 05115 } else if (isconst && !ispointer) { 05116 //do not split const non-pointer variables.. 05117 while (tok2 && tok2->str() != "," && tok2->str() != ";") { 05118 if (tok2->str() == "{" || tok2->str() == "(" || tok2->str() == "[") 05119 tok2 = tok2->link(); 05120 if (tok2->str() == "<" && TemplateSimplifier::templateParameters(tok2) > 0) 05121 tok2->findClosingBracket(tok2); 05122 tok2 = tok2->next(); 05123 } 05124 if (tok2 && tok2->str() == ";") 05125 tok2 = NULL; 05126 } 05127 } 05128 } else 05129 tok2 = NULL; 05130 } 05131 05132 //VLA case 05133 else if (Token::Match(varName, "%var% [")) { 05134 tok2 = varName->next(); 05135 05136 while (Token::Match(tok2->link(), "] ,|=|[")) 05137 tok2 = tok2->link()->next(); 05138 if (!Token::Match(tok2, "=|,")) 05139 tok2 = NULL; 05140 if (tok2 && tok2->str() == "=") { 05141 while (tok2 && tok2->str() != "," && tok2->str() != ";") { 05142 if (tok2->str() == "{" || tok2->str() == "(" || tok2->str() == "[") 05143 tok2 = tok2->link(); 05144 tok2 = tok2->next(); 05145 } 05146 if (tok2 && tok2->str() == ";") 05147 tok2 = NULL; 05148 } 05149 } else 05150 tok2 = NULL; 05151 } else { 05152 tok2 = NULL; 05153 } 05154 05155 if (!tok2) { 05156 if (only_k_r_fpar) 05157 finishedwithkr = false; 05158 continue; 05159 } 05160 05161 if (tok2->str() == ",") { 05162 tok2->str(";"); 05163 //TODO: should we have to add also template '<>' links? 05164 list.insertTokens(tok2, type0, typelen); 05165 } 05166 05167 else { 05168 Token *eq = tok2; 05169 05170 while (tok2) { 05171 if (tok2->str() == "{" || tok2->str() == "(") 05172 tok2 = tok2->link(); 05173 05174 else if (tok2->str() == "<" && tok2->previous()->isName() && !tok2->previous()->varId()) 05175 tok2->findClosingBracket(tok2); 05176 05177 else if (std::strchr(";,", tok2->str()[0])) { 05178 // "type var =" => "type var; var =" 05179 const Token *VarTok = type0->tokAt((int)typelen); 05180 while (Token::Match(VarTok, "*|&|const")) 05181 VarTok = VarTok->next(); 05182 list.insertTokens(eq, VarTok, 2); 05183 eq->str(";"); 05184 05185 // "= x, " => "= x; type " 05186 if (tok2->str() == ",") { 05187 tok2->str(";"); 05188 list.insertTokens(tok2, type0, typelen); 05189 } 05190 break; 05191 } 05192 05193 tok2 = tok2->next(); 05194 } 05195 } 05196 finishedwithkr = (only_k_r_fpar && tok2 && tok2->strAt(1) == "{"); 05197 } 05198 } 05199 05200 void Tokenizer::simplifyPlatformTypes() 05201 { 05202 enum { isLongLong, isLong, isInt } type; 05203 05204 /** @todo This assumes a flat address space. Not true for segmented address space (FAR *). */ 05205 if (_settings->sizeof_size_t == 8) 05206 type = isLongLong; 05207 else if (_settings->sizeof_size_t == 4 && _settings->sizeof_long == 4) 05208 type = isLong; 05209 else if (_settings->sizeof_size_t == 4) 05210 type = isInt; 05211 else 05212 return; 05213 05214 for (Token *tok = list.front(); tok; tok = tok->next()) { 05215 if (Token::Match(tok, "std :: size_t|ssize_t|ptrdiff_t|intptr_t|uintptr_t")) { 05216 tok->deleteNext(); 05217 tok->deleteThis(); 05218 } else if (Token::Match(tok, ":: size_t|ssize_t|ptrdiff_t|intptr_t|uintptr_t")) { 05219 tok->deleteThis(); 05220 } 05221 05222 if (Token::Match(tok, "size_t|uintptr_t")) { 05223 tok->str("unsigned"); 05224 05225 switch (type) { 05226 case isLongLong: 05227 tok->insertToken("long"); 05228 tok->insertToken("long"); 05229 break; 05230 case isLong : 05231 tok->insertToken("long"); 05232 break; 05233 case isInt: 05234 tok->insertToken("int"); 05235 break; 05236 } 05237 } else if (Token::Match(tok, "ssize_t|ptrdiff_t|intptr_t")) { 05238 switch (type) { 05239 case isLongLong: 05240 tok->str("long"); 05241 tok->insertToken("long"); 05242 break; 05243 case isLong : 05244 tok->str("long"); 05245 break; 05246 case isInt: 05247 tok->str("int"); 05248 break; 05249 } 05250 } 05251 } 05252 05253 if (_settings->platformType == Settings::Win32A || 05254 _settings->platformType == Settings::Win32W || 05255 _settings->platformType == Settings::Win64) { 05256 for (Token *tok = list.front(); tok; tok = tok->next()) { 05257 if (Token::Match(tok, "BOOL|INT|INT32|HFILE|LONG32")) 05258 tok->str("int"); 05259 else if (Token::Match(tok, "BOOLEAN|BYTE|UCHAR")) { 05260 tok->str("unsigned"); 05261 tok->insertToken("char"); 05262 } else if (tok->str() == "CHAR") 05263 tok->str("char"); 05264 else if (Token::Match(tok, "DWORD|ULONG|COLORREF|LCID|LCTYPE|LGRPID")) { 05265 tok->str("unsigned"); 05266 tok->insertToken("long"); 05267 } else if (Token::Match(tok, "DWORD_PTR|ULONG_PTR|SIZE_T")) { 05268 tok->str("unsigned"); 05269 tok->insertToken("long"); 05270 if (_settings->platformType == Settings::Win64) 05271 tok->insertToken("long"); 05272 } else if (tok->str() == "FLOAT") 05273 tok->str("float"); 05274 else if (Token::Match(tok, "HRESULT|LONG")) 05275 tok->str("long"); 05276 else if (Token::Match(tok, "INT64|LONG64")) { 05277 tok->str("long"); 05278 tok->insertToken("long"); 05279 } else if (Token::Match(tok, "LONG_PTR|LPARAM|LRESULT|SSIZE_T")) { 05280 tok->str("long"); 05281 if (_settings->platformType == Settings::Win64) 05282 tok->insertToken("long"); 05283 } else if (Token::Match(tok, "LPBOOL|PBOOL")) { 05284 tok->str("int"); 05285 tok->insertToken("*"); 05286 } else if (Token::Match(tok, "LPBYTE|PBOOLEAN|PBYTE|PUCHAR")) { 05287 tok->str("unsigned"); 05288 tok->insertToken("*"); 05289 tok->insertToken("char"); 05290 } else if (Token::Match(tok, "LPCSTR|PCSTR")) { 05291 tok->str("const"); 05292 tok->insertToken("*"); 05293 tok->insertToken("char"); 05294 } else if (tok->str() == "LPCVOID") { 05295 tok->str("const"); 05296 tok->insertToken("*"); 05297 tok->insertToken("void"); 05298 } else if (Token::Match(tok, "LPDWORD|LPCOLORREF|PDWORD|PULONG")) { 05299 tok->str("unsigned"); 05300 tok->insertToken("*"); 05301 tok->insertToken("long"); 05302 } else if (Token::Match(tok, "LPINT|PINT")) { 05303 tok->str("int"); 05304 tok->insertToken("*"); 05305 } else if (Token::Match(tok, "LPLONG|PLONG")) { 05306 tok->str("long"); 05307 tok->insertToken("*"); 05308 } else if (Token::Match(tok, "LPSTR|PSTR|PCHAR")) { 05309 tok->str("char"); 05310 tok->insertToken("*"); 05311 } else if (Token::Match(tok, "PWSTR|PWCHAR")) { 05312 tok->str("wchar_t"); 05313 tok->insertToken("*"); 05314 } else if (Token::Match(tok, "LPVOID|PVOID|HANDLE|HBITMAP|HBRUSH|HCOLORSPACE|HCURSOR|HDC|HFONT|HGDIOBJ|HGLOBAL|HICON|HINSTANCE|HKEY|HLOCAL|HMENU|HMETAFILE|HMODULE|HPALETTE|HPEN|HRGN|HRSRC|HWND|SERVICE_STATUS_HANDLE|SC_LOCK|SC_HANDLE|HACCEL|HCONV|HCONVLIST|HDDEDATA|HDESK|HDROP|HDWP|HENHMETAFILE|HHOOK|HKL|HMONITOR|HSZ|HWINSTA")) { 05315 tok->str("void"); 05316 tok->insertToken("*"); 05317 } else if ((tok->str() == "PHANDLE")) { 05318 tok->str("void"); 05319 tok->insertToken("*"); 05320 tok->insertToken("*"); 05321 } else if (Token::Match(tok, "LPWORD|PWORD|PUSHORT")) { 05322 tok->str("unsigned"); 05323 tok->insertToken("*"); 05324 tok->insertToken("short"); 05325 } else if (tok->str() == "SHORT") 05326 tok->str("short"); 05327 else if (Token::Match(tok, "UINT|MMRESULT|SOCKET|ULONG32|UINT32|DWORD32")) { 05328 tok->str("unsigned"); 05329 tok->insertToken("int"); 05330 } else if (Token::Match(tok, "UINT_PTR|WPARAM")) { 05331 tok->str("unsigned"); 05332 if (_settings->platformType == Settings::Win64) { 05333 tok->insertToken("long"); 05334 tok->insertToken("long"); 05335 } else { 05336 tok->insertToken("int"); 05337 } 05338 } else if (Token::Match(tok, "USHORT|WORD|ATOM|LANGID")) { 05339 tok->str("unsigned"); 05340 tok->insertToken("short"); 05341 } else if (tok->str() == "VOID") 05342 tok->str("void"); 05343 else if (tok->str() == "TCHAR") { 05344 if (_settings->platformType == Settings::Win32A) 05345 tok->str("char"); 05346 else { 05347 tok->str("wchar_t"); 05348 } 05349 } else if (tok->str() == "TBYTE") { 05350 tok->str("unsigned"); 05351 if (_settings->platformType == Settings::Win32A) 05352 tok->insertToken("short"); 05353 else 05354 tok->insertToken("char"); 05355 } else if (Token::Match(tok, "PTSTR|LPTSTR")) { 05356 if (_settings->platformType == Settings::Win32A) { 05357 tok->str("char"); 05358 tok->insertToken("*"); 05359 } else { 05360 tok->str("wchar_t"); 05361 tok->insertToken("*"); 05362 } 05363 } else if (Token::Match(tok, "PCTSTR|LPCTSTR")) { 05364 tok->str("const"); 05365 if (_settings->platformType == Settings::Win32A) { 05366 tok->insertToken("*"); 05367 tok->insertToken("char"); 05368 } else { 05369 tok->insertToken("*"); 05370 tok->insertToken("wchar_t"); 05371 } 05372 } else if (Token::Match(tok, "ULONG64|DWORD64")) { 05373 tok->str("unsigned"); 05374 tok->insertToken("long"); 05375 } else if (tok->str() == "HALF_PTR") { 05376 if (_settings->platformType == Settings::Win64) 05377 tok->str("int"); 05378 else 05379 tok->str("short"); 05380 } else if (tok->str() == "INT_PTR") { 05381 if (_settings->platformType == Settings::Win64) { 05382 tok->str("long"); 05383 tok->insertToken("long"); 05384 } else { 05385 tok->str("int"); 05386 } 05387 } else if (tok->str() == "LPWSTR") { 05388 tok->str("wchar_t"); 05389 tok->insertToken("*"); 05390 } else if (tok->str() == "LPCWSTR") { 05391 tok->str("const"); 05392 tok->insertToken("*"); 05393 tok->insertToken("wchar_t"); 05394 } 05395 } 05396 } 05397 } 05398 05399 void Tokenizer::simplifyStdType() 05400 { 05401 for (Token *tok = list.front(); tok; tok = tok->next()) { 05402 // long unsigned => unsigned long 05403 if (Token::Match(tok, "char|short|int|long|__int8|__int16|__int32|__int64 unsigned|signed")) { 05404 bool isUnsigned = tok->next()->str() == "unsigned"; 05405 tok->deleteNext(); 05406 tok->isUnsigned(isUnsigned); 05407 tok->isSigned(!isUnsigned); 05408 } 05409 05410 else if (!Token::Match(tok, "unsigned|signed|char|short|int|long|__int8|__int16|__int32|__int64")) 05411 continue; 05412 05413 // check if signed or unsigned specified 05414 if (Token::Match(tok, "unsigned|signed")) { 05415 bool isUnsigned = tok->str() == "unsigned"; 05416 05417 // unsigned i => unsigned int i 05418 if (!Token::Match(tok->next(), "char|short|int|long|__int8|__int16|__int32|__int64")) 05419 tok->str("int"); 05420 else 05421 tok->deleteThis(); 05422 tok->isUnsigned(isUnsigned); 05423 tok->isSigned(!isUnsigned); 05424 } 05425 05426 if (tok->str() == "__int8") 05427 tok->str("char"); 05428 else if (tok->str() == "__int16") 05429 tok->str("short"); 05430 else if (tok->str() == "__int32") 05431 tok->str("int"); 05432 else if (tok->str() == "__int64") { 05433 tok->str("long"); 05434 tok->isLong(true); 05435 } else if (tok->str() == "long") { 05436 if (tok->strAt(1) == "long") { 05437 tok->isLong(true); 05438 tok->deleteNext(); 05439 } 05440 05441 if (tok->strAt(1) == "int") 05442 tok->deleteNext(); 05443 else if (tok->strAt(1) == "double") { 05444 tok->str("double"); 05445 tok->isLong(true); 05446 tok->deleteNext(); 05447 } 05448 } else if (tok->str() == "short") { 05449 if (tok->strAt(1) == "int") 05450 tok->deleteNext(); 05451 } 05452 } 05453 } 05454 05455 void Tokenizer::simplifyIfAssign() 05456 { 05457 // See also simplifyFunctionAssign 05458 05459 for (Token *tok = list.front(); tok; tok = tok->next()) { 05460 if (!Token::Match(tok->next(), "if|while ( !| (| %var% =") && 05461 !Token::Match(tok->next(), "if|while ( !| (| %var% . %var% =")) 05462 continue; 05463 05464 // simplifying a "while" condition ? 05465 const bool iswhile(tok->next()->str() == "while"); 05466 05467 // delete the "if" 05468 tok->deleteNext(); 05469 05470 // Remember if there is a "!" or not. And delete it if there are. 05471 const bool isNot(tok->strAt(2) == "!"); 05472 if (isNot) 05473 tok->next()->deleteNext(); 05474 05475 // Delete parentheses.. and remember how many there are with 05476 // their links. 05477 std::stack<Token *> braces; 05478 while (tok->next()->str() == "(") { 05479 braces.push(tok->next()->link()); 05480 tok->deleteNext(); 05481 } 05482 05483 // Skip the "%var% = ..." 05484 Token *tok2; 05485 for (tok2 = tok->next(); tok2; tok2 = tok2->next()) { 05486 if (tok2->str() == "(") 05487 tok2 = tok2->link(); 05488 else if (tok2->str() == ")") 05489 break; 05490 } 05491 05492 // Insert "; if|while ( .." 05493 tok2 = tok2->previous(); 05494 if (tok->strAt(2) == ".") { 05495 tok2->insertToken(tok->strAt(3)); 05496 tok2->next()->varId(tok->tokAt(3)->varId()); 05497 tok2->insertToken("."); 05498 } 05499 tok2->insertToken(tok->next()->str()); 05500 tok2->next()->varId(tok->next()->varId()); 05501 05502 while (! braces.empty()) { 05503 tok2->insertToken("("); 05504 Token::createMutualLinks(tok2->next(), braces.top()); 05505 braces.pop(); 05506 } 05507 05508 if (isNot) 05509 tok2->next()->insertToken("!"); 05510 tok2->insertToken(iswhile ? "while" : "if"); 05511 tok2->insertToken(";"); 05512 05513 // If it's a while loop.. insert the assignment in the loop 05514 if (iswhile) { 05515 unsigned int indentlevel = 0; 05516 Token *tok3 = tok2; 05517 for (; tok3; tok3 = tok3->next()) { 05518 if (tok3->str() == "{") 05519 ++indentlevel; 05520 else if (tok3->str() == "}") { 05521 if (indentlevel <= 1) 05522 break; 05523 --indentlevel; 05524 } 05525 } 05526 05527 if (tok3 && indentlevel == 1) { 05528 tok3 = tok3->previous(); 05529 std::stack<Token *> braces2; 05530 05531 for (tok2 = tok2->next(); tok2 && tok2 != tok; tok2 = tok2->previous()) { 05532 tok3->insertToken(tok2->str()); 05533 tok3->next()->varId(tok2->varId()); 05534 05535 Token *newTok = tok3->next(); 05536 newTok->fileIndex(tok2->fileIndex()); 05537 newTok->linenr(tok2->linenr()); 05538 05539 // link() newly tokens manually 05540 if (Token::Match(newTok, "}|)|]")) { 05541 braces2.push(newTok); 05542 } else if (Token::Match(newTok, "{|(|[")) { 05543 Token::createMutualLinks(newTok, braces2.top()); 05544 braces2.pop(); 05545 } 05546 } 05547 } 05548 } 05549 } 05550 } 05551 05552 05553 void Tokenizer::simplifyVariableMultipleAssign() 05554 { 05555 for (Token *tok = list.front(); tok; tok = tok->next()) { 05556 if (Token::Match(tok, "%var% = %var% = %num%|%var% ;")) { 05557 // skip intermediate assignments 05558 Token *tok2 = tok->previous(); 05559 while (tok2 && 05560 tok2->str() == "=" && 05561 Token::Match(tok2->previous(), "%var%")) { 05562 tok2 = tok2->tokAt(-2); 05563 } 05564 05565 if (!tok2 || tok2->str() != ";") { 05566 continue; 05567 } 05568 05569 Token *stopAt = tok->tokAt(2); 05570 const Token *valueTok = tok->tokAt(4); 05571 const std::string value(valueTok->str()); 05572 tok2 = tok2->next(); 05573 05574 while (tok2 != stopAt) { 05575 tok2->next()->insertToken(";"); 05576 tok2->next()->insertToken(value); 05577 tok2 = tok2->tokAt(4); 05578 } 05579 } 05580 } 05581 } 05582 05583 05584 void Tokenizer::simplifyIfNot() 05585 { 05586 for (Token *tok = list.front(); tok; tok = tok->next()) { 05587 if (Token::Match(tok, "(|&&|%oror%")) { 05588 tok = tok->next(); 05589 while (tok && tok->str() == "(") 05590 tok = tok->next(); 05591 05592 if (!tok) 05593 break; 05594 05595 if (Token::Match(tok, "0|false == (") || 05596 Token::Match(tok, "0|false == %var%")) { 05597 tok->deleteNext(); 05598 tok->str("!"); 05599 } 05600 05601 else if (Token::Match(tok, "%var% == 0|false")) { 05602 tok->deleteNext(2); 05603 tok = tok->previous(); 05604 tok->insertToken("!"); 05605 tok = tok->next(); 05606 } 05607 05608 else if (Token::Match(tok, "%var% .|:: %var% == 0|false")) { 05609 tok = tok->previous(); 05610 tok->insertToken("!"); 05611 tok = tok->tokAt(4); 05612 tok->deleteNext(2); 05613 } 05614 05615 else if (Token::Match(tok, "* %var% == 0|false")) { 05616 tok = tok->previous(); 05617 tok->insertToken("!"); 05618 tok = tok->tokAt(3); 05619 tok->deleteNext(2); 05620 } 05621 } 05622 05623 else if (tok->link() && Token::Match(tok, ") == 0|false")) { 05624 // if( foo(x) == 0 ) 05625 if (Token::Match(tok->link()->tokAt(-2), "( %var%")) { 05626 tok->deleteNext(2); 05627 tok->link()->previous()->insertToken(tok->link()->previous()->str()); 05628 tok->link()->tokAt(-2)->str("!"); 05629 } 05630 05631 // if( (x) == 0 ) 05632 else if (tok->link()->strAt(-1) == "(") { 05633 tok->deleteNext(2); 05634 tok->link()->insertToken("("); 05635 tok->link()->str("!"); 05636 Token *temp = tok->link(); 05637 Token::createMutualLinks(tok->link()->next(), tok); 05638 temp->link(0); 05639 } 05640 } 05641 } 05642 } 05643 05644 05645 void Tokenizer::simplifyIfNotNull() 05646 { 05647 for (Token *tok = list.front(); tok; tok = tok->next()) { 05648 Token *deleteFrom = NULL; 05649 05650 // Remove 'x = (x != 0)' 05651 if (Token::simpleMatch(tok, "= (")) { 05652 if (Token::Match(tok->tokAt(-2), "[;{}] %var%")) { 05653 const std::string varname(tok->previous()->str()); 05654 05655 if (Token::simpleMatch(tok->tokAt(2), (varname + " != 0 ) ;").c_str()) || 05656 Token::simpleMatch(tok->tokAt(2), ("0 != " + varname + " ) ;").c_str())) { 05657 tok = tok->tokAt(-2); 05658 tok->deleteNext(8); 05659 } 05660 } 05661 continue; 05662 } 05663 05664 if (Token::Match(tok, "(|&&|%oror%")) { 05665 tok = tok->next(); 05666 05667 if (!tok) 05668 break; 05669 05670 if (Token::simpleMatch(tok, "0 != (") || 05671 Token::Match(tok, "0 != %var%")) { 05672 deleteFrom = tok->previous(); 05673 if (tok->tokAt(2)) 05674 tok->tokAt(2)->isPointerCompare(true); 05675 } 05676 05677 else if (Token::Match(tok, "%var% != 0")) { 05678 deleteFrom = tok; 05679 tok->isPointerCompare(true); 05680 } 05681 05682 else if (Token::Match(tok, "%var% .|:: %var% != 0")) { 05683 tok = tok->tokAt(2); 05684 deleteFrom = tok; 05685 tok->isPointerCompare(true); 05686 } 05687 } 05688 05689 else if (tok->link() && Token::simpleMatch(tok, ") != 0")) { 05690 deleteFrom = tok; 05691 } 05692 05693 if (deleteFrom) { 05694 Token::eraseTokens(deleteFrom, deleteFrom->tokAt(3)); 05695 tok = deleteFrom; 05696 } 05697 } 05698 } 05699 05700 05701 void Tokenizer::simplifyIfSameInnerCondition() 05702 { 05703 // same inner condition 05704 for (Token *tok = list.front(); tok; tok = tok->next()) { 05705 if (Token::Match(tok, "if ( %var% ) {")) { 05706 const unsigned int varid(tok->tokAt(2)->varId()); 05707 if (!varid) 05708 continue; 05709 05710 for (Token *tok2 = tok->tokAt(5); tok2; tok2 = tok2->next()) { 05711 if (tok2->str() == "{" || tok2->str() == "}") 05712 break; 05713 if (Token::simpleMatch(tok2, "if (")) { 05714 tok2 = tok2->tokAt(2); 05715 if (Token::Match(tok2, "%varid% )", varid)) 05716 tok2->str("true"); 05717 else if (Token::Match(tok2, "! %varid% )", varid)) 05718 tok2->next()->varId(varid); 05719 break; 05720 } 05721 } 05722 } 05723 } 05724 } 05725 05726 05727 bool Tokenizer::simplifyLogicalOperators() 05728 { 05729 bool ret = false; 05730 05731 // "if (not p)" => "if (!p)" 05732 // "if (p and q)" => "if (p && q)" 05733 // "if (p or q)" => "if (p || q)" 05734 for (Token *tok = list.front(); tok; tok = tok->next()) { 05735 if (Token::Match(tok, "if|while ( not|compl %var%")) { 05736 tok->tokAt(2)->str(tok->strAt(2) == "not" ? "!" : "~"); 05737 ret = true; 05738 } else if (Token::Match(tok, "&& not|compl %var%")) { 05739 tok->next()->str(tok->next()->str() == "not" ? "!" : "~"); 05740 ret = true; 05741 } else if (Token::Match(tok, "|| not|compl %var%")) { 05742 tok->next()->str(tok->next()->str() == "not" ? "!" : "~"); 05743 ret = true; 05744 } 05745 // "%var%|) and %var%|(" 05746 else if (Token::Match(tok, "%var% %any%")) { 05747 if (!Token::Match(tok, "and|or|bitand|bitor|xor|not_eq")) 05748 continue; 05749 05750 const Token *tok2 = tok; 05751 while (NULL != (tok2 = tok2->previous())) { 05752 if (tok2->str() == ")") 05753 tok2 = tok2->link(); 05754 else if (Token::Match(tok2, "(|;|{|}")) 05755 break; 05756 } 05757 if (tok2 && Token::Match(tok2->previous(), "if|while (")) { 05758 if (tok->str() == "and") 05759 tok->str("&&"); 05760 else if (tok->str() == "or") 05761 tok->str("||"); 05762 else if (tok->str() == "bitand") 05763 tok->str("&"); 05764 else if (tok->str() == "bitor") 05765 tok->str("|"); 05766 else if (tok->str() == "xor") 05767 tok->str("^"); 05768 else if (tok->str() == "not_eq") 05769 tok->str("!="); 05770 ret = true; 05771 } 05772 } 05773 } 05774 return ret; 05775 } 05776 05777 // int i(0); => int i; i = 0; 05778 // int i(0), j; => int i; i = 0; int j; 05779 void Tokenizer::simplifyInitVar() 05780 { 05781 for (Token *tok = list.front(); tok; tok = tok->next()) { 05782 if (!tok->isName() || (tok->previous() && !Token::Match(tok->previous(), "[;{}]"))) 05783 continue; 05784 05785 if (tok->str() == "return") 05786 continue; 05787 05788 if (Token::Match(tok, "class|struct|union| %type% *| %var% ( &| %any% ) ;") || 05789 Token::Match(tok, "%type% *| %var% ( %type% (")) { 05790 tok = initVar(tok); 05791 } else if (Token::Match(tok, "class|struct|union| %type% *| %var% ( &| %any% ) ,")) { 05792 Token *tok1 = tok; 05793 while (tok1->str() != ",") 05794 tok1 = tok1->next(); 05795 tok1->str(";"); 05796 Token *tok2 = tok; 05797 if (Token::Match(tok2, "class|struct|union")) { 05798 tok1->insertToken(tok2->str()); 05799 tok1 = tok1->next(); 05800 tok2 = tok2->next(); 05801 } 05802 tok1->insertToken(tok2->str()); 05803 tok1 = tok1->next(); 05804 tok2 = tok2->next(); 05805 if (tok2->str() == "*") { 05806 tok1->insertToken("*"); 05807 } 05808 tok = initVar(tok); 05809 } 05810 } 05811 } 05812 05813 Token * Tokenizer::initVar(Token * tok) 05814 { 05815 // call constructor of class => no simplification 05816 if (Token::Match(tok, "class|struct|union")) { 05817 if (tok->strAt(2) != "*") 05818 return tok; 05819 05820 tok = tok->next(); 05821 } else if (!tok->isStandardType() && tok->next()->str() != "*") 05822 return tok; 05823 05824 // goto variable name.. 05825 tok = tok->next(); 05826 if (tok->str() == "*") 05827 tok = tok->next(); 05828 05829 // sizeof is not a variable name.. 05830 if (tok->str() == "sizeof") 05831 return tok; 05832 05833 // check initializer.. 05834 if (tok->tokAt(2)->isStandardType() || tok->strAt(2) == "void") 05835 return tok; 05836 else if (!tok->tokAt(2)->isNumber() && !Token::Match(tok->tokAt(2), "%type% (") && tok->strAt(2) != "&" && tok->tokAt(2)->varId() == 0) 05837 return tok; 05838 05839 // insert '; var =' 05840 tok->insertToken(";"); 05841 tok->next()->insertToken(tok->str()); 05842 tok->tokAt(2)->varId(tok->varId()); 05843 tok = tok->tokAt(2); 05844 tok->insertToken("="); 05845 05846 // goto '('.. 05847 tok = tok->tokAt(2); 05848 05849 // delete ')' 05850 tok->link()->deleteThis(); 05851 05852 // delete this 05853 tok->deleteThis(); 05854 05855 return tok; 05856 } 05857 05858 05859 bool Tokenizer::simplifyKnownVariables() 05860 { 05861 // return value for function. Set to true if any simplifications are made 05862 bool ret = false; 05863 05864 // constants.. 05865 { 05866 std::map<unsigned int, std::string> constantValues; 05867 bool goback = false; 05868 for (Token *tok = list.front(); tok; tok = tok->next()) { 05869 if (goback) { 05870 tok = tok->previous(); 05871 goback = false; 05872 } 05873 if (tok->isName() && Token::Match(tok, "static| const| static| %type% const| %var% = %any% ;")) { 05874 bool isconst = false; 05875 for (const Token *tok2 = tok; tok2->str() != "="; tok2 = tok2->next()) { 05876 if (tok2->str() == "const") { 05877 isconst = true; 05878 break; 05879 } 05880 } 05881 if (!isconst) 05882 continue; 05883 05884 Token *tok1 = tok; 05885 05886 // start of statement 05887 if (tok != list.front() && !Token::Match(tok->previous(),";|{|}|private:|protected:|public:")) 05888 continue; 05889 // skip "const" and "static" 05890 while (tok->str() == "const" || tok->str() == "static") 05891 tok = tok->next(); 05892 // pod type 05893 if (!tok->isStandardType()) 05894 continue; 05895 05896 const Token * const vartok = (tok->next() && tok->next()->str() == "const") ? tok->tokAt(2) : tok->next(); 05897 const Token * const valuetok = vartok->tokAt(2); 05898 if (Token::Match(valuetok, "%bool%|%char%|%num%|%str% ;")) { 05899 //check if there's not a reference usage inside the code 05900 bool withreference = false; 05901 for (const Token *tok2 = valuetok->tokAt(2); tok2; tok2 = tok2->next()) { 05902 if (Token::Match(tok2,"(|[|,|{|return|%op% & %varid%", vartok->varId())) { 05903 withreference = true; 05904 break; 05905 } 05906 } 05907 //don't simplify 'f(&x)' to 'f(&100)' 05908 if (withreference) 05909 continue; 05910 05911 constantValues[vartok->varId()] = valuetok->str(); 05912 05913 // remove statement 05914 while (tok1->next()->str() != ";") 05915 tok1->deleteNext(); 05916 tok1->deleteNext(); 05917 tok1->deleteThis(); 05918 tok = tok1; 05919 goback = true; 05920 } 05921 } 05922 05923 else if (tok->varId() && constantValues.find(tok->varId()) != constantValues.end()) { 05924 tok->str(constantValues[tok->varId()]); 05925 } 05926 } 05927 } 05928 05929 // variable id for float/double variables 05930 std::set<unsigned int> floatvars; 05931 05932 // auto variables.. 05933 for (Token *tok = list.front(); tok; tok = tok->next()) { 05934 // Search for a block of code 05935 if (! Token::Match(tok, ") const| {")) 05936 continue; 05937 05938 // parse the block of code.. 05939 int indentlevel = 0; 05940 Token *tok2 = tok; 05941 for (; tok2; tok2 = tok2->next()) { 05942 if (Token::Match(tok2, "[;{}] float|double %var% ;")) { 05943 floatvars.insert(tok2->tokAt(2)->varId()); 05944 } 05945 05946 if (tok2->str() == "{") 05947 ++indentlevel; 05948 05949 else if (tok2->str() == "}") { 05950 --indentlevel; 05951 if (indentlevel <= 0) 05952 break; 05953 } 05954 05955 else if (tok2->previous()->str() != "*" && 05956 (Token::Match(tok2, "%var% = %bool%|%char%|%num%|%str%|%var% ;") || 05957 Token::Match(tok2, "%var% [ ] = %str% ;") || 05958 Token::Match(tok2, "%var% [ %num% ] = %str% ;") || 05959 Token::Match(tok2, "%var% = & %var% ;") || 05960 Token::Match(tok2, "%var% = & %var% [ 0 ] ;"))) { 05961 const unsigned int varid = tok2->varId(); 05962 if (varid == 0) 05963 continue; 05964 05965 // initialization of static variable => the value is not *known* 05966 { 05967 bool isstatic = false; 05968 const Token *decl = tok2->previous(); 05969 while (decl && (decl->isName() || decl->str() == "*")) { 05970 if (decl->str() == "static") { 05971 isstatic = true; 05972 break; 05973 } 05974 decl = decl->previous(); 05975 } 05976 if (isstatic) 05977 continue; 05978 } 05979 05980 // skip loop variable 05981 if (Token::Match(tok2->tokAt(-2), "(|:: %type%")) { 05982 const Token *tok3 = tok2->previous(); 05983 while (Token::Match(tok3->previous(), ":: %type%")) 05984 tok3 = tok3->tokAt(-2); 05985 if (Token::Match(tok3->tokAt(-2), "for ( %type%")) 05986 continue; 05987 } 05988 05989 // struct name.. 05990 const std::string structname = Token::Match(tok2->tokAt(-3), "[;{}] %var% .") ? 05991 std::string(tok2->strAt(-2) + " .") : 05992 std::string(""); 05993 05994 if (tok2->str() == tok2->strAt(2)) 05995 continue; 05996 05997 const Token * const valueToken = tok2->tokAt(2); 05998 05999 std::string value; 06000 unsigned int valueVarId = 0; 06001 06002 Token *tok3 = NULL; 06003 bool valueIsPointer = false; 06004 06005 // there could be a hang here if tok2 is moved back by the function calls below for some reason 06006 if (_settings->terminated()) 06007 return false; 06008 06009 if (!simplifyKnownVariablesGetData(varid, &tok2, &tok3, value, valueVarId, valueIsPointer, floatvars.find(tok2->varId()) != floatvars.end())) 06010 continue; 06011 06012 ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, valueToken, indentlevel); 06013 } 06014 06015 else if (Token::Match(tok2, "( %var% == %num% ) {")) { 06016 const unsigned int varid = tok2->next()->varId(); 06017 if (varid == 0) 06018 continue; 06019 06020 const std::string structname; 06021 06022 const Token *valueToken = tok2->tokAt(3); 06023 std::string value(tok2->strAt(3)); 06024 const unsigned int valueVarId = 0; 06025 const bool valueIsPointer = false; 06026 06027 Token *scopeStart = tok2->tokAt(6); 06028 ret |= simplifyKnownVariablesSimplify(&scopeStart, scopeStart, varid, structname, value, valueIsPointer, valueVarId, valueToken, -1); 06029 } 06030 06031 else if (Token::Match(tok2, "strcpy|sprintf ( %var% , %str% ) ;")) { 06032 const unsigned int varid(tok2->tokAt(2)->varId()); 06033 std::string::size_type n = std::string::npos; 06034 if (varid == 0) 06035 continue; 06036 const std::string structname; 06037 const Token * const valueToken = tok2->tokAt(4); 06038 std::string value(valueToken->str()); 06039 if (tok2->str() == "sprintf") { 06040 while ((n = value.find("%%",n+1)) != std::string::npos) { 06041 value.replace(n,2,"%"); 06042 } 06043 } 06044 const unsigned int valueVarId(0); 06045 const bool valueIsPointer(false); 06046 Token *tok3 = tok2->tokAt(6); 06047 ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, valueToken, indentlevel); 06048 06049 // there could be a hang here if tok2 was moved back by the function call above for some reason 06050 if (_settings->terminated()) 06051 return false; 06052 } 06053 } 06054 06055 if (tok2) 06056 tok = tok2->previous(); 06057 } 06058 06059 return ret; 06060 } 06061 06062 bool Tokenizer::simplifyKnownVariablesGetData(unsigned int varid, Token **_tok2, Token **_tok3, std::string &value, unsigned int &valueVarId, bool &valueIsPointer, bool floatvar) 06063 { 06064 Token *tok2 = *_tok2; 06065 Token *tok3 = NULL; 06066 06067 if (Token::simpleMatch(tok2->tokAt(-2), "for (")) { 06068 // only specific for loops is handled 06069 if (!Token::Match(tok2, "%varid% = %num% ; %varid% <|<= %num% ; ++| %varid% ++| ) {", varid)) 06070 return false; 06071 06072 // is there a "break" in the for loop? 06073 bool hasbreak = false; 06074 const Token* end4 = tok2->linkAt(-1)->linkAt(1); 06075 for (const Token *tok4 = tok2->previous()->link(); tok4 != end4; tok4 = tok4->next()) { 06076 if (tok4->str() == "break") { 06077 hasbreak = true; 06078 break; 06079 } 06080 } 06081 if (hasbreak) 06082 return false; 06083 06084 // no break => the value of the counter value is known after the for loop.. 06085 const std::string& compareop = tok2->strAt(5); 06086 if (compareop == "<") { 06087 value = tok2->strAt(6); 06088 valueVarId = tok2->tokAt(6)->varId(); 06089 } else 06090 value = MathLib::longToString(MathLib::toLongNumber(tok2->strAt(6)) + 1); 06091 06092 // Skip for-body.. 06093 tok3 = tok2->previous()->link()->next()->link()->next(); 06094 } else { 06095 value = tok2->strAt(2); 06096 valueVarId = tok2->tokAt(2)->varId(); 06097 if (tok2->strAt(1) == "[") { 06098 value = tok2->next()->link()->strAt(2); 06099 valueVarId = 0; 06100 } else if (value == "&") { 06101 value = tok2->strAt(3); 06102 valueVarId = tok2->tokAt(3)->varId(); 06103 06104 // *ptr = &var; *ptr = 5; 06105 // equals 06106 // var = 5; not *var = 5; 06107 if (tok2->strAt(4) == ";") 06108 valueIsPointer = true; 06109 } 06110 06111 // float value should contain a "." 06112 else if (tok2->tokAt(2)->isNumber() && 06113 floatvar && 06114 value.find(".") == std::string::npos) { 06115 value += ".0"; 06116 } 06117 06118 // float variable: convert true/false to 1.0 / 0.0 06119 else if (tok2->tokAt(2)->isBoolean() && floatvar) { 06120 value = (value == "true") ? "1.0" : "0.0"; 06121 } 06122 06123 if (Token::simpleMatch(tok2->next(), "= &")) 06124 tok2 = tok2->tokAt(3); 06125 06126 tok3 = tok2->next(); 06127 } 06128 *_tok2 = tok2; 06129 *_tok3 = tok3; 06130 return true; 06131 } 06132 06133 bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, const Token * const valueToken, int indentlevel) const 06134 { 06135 const bool pointeralias(valueToken->isName() || Token::Match(valueToken, "& %var% [")); 06136 06137 if (_errorLogger && !list.getFiles().empty()) 06138 _errorLogger->reportProgress(list.getFiles()[0], "Tokenize (simplifyKnownVariables)", tok3->progressValue()); 06139 06140 bool ret = false; 06141 06142 // skip increments and decrements if the given indentlevel is -1 06143 const bool skipincdec = (indentlevel == -1); 06144 06145 Token* bailOutFromLoop = 0; 06146 int indentlevel3 = indentlevel; 06147 bool ret3 = false; 06148 for (; tok3; tok3 = tok3->next()) { 06149 if (tok3->str() == "{") { 06150 ++indentlevel3; 06151 } else if (tok3->str() == "}") { 06152 --indentlevel3; 06153 if (indentlevel3 < indentlevel) { 06154 if (Token::Match((*tok2)->tokAt(-7), "%type% * %var% ; %var% = & %var% ;") && 06155 (*tok2)->strAt(-5) == (*tok2)->strAt(-3)) { 06156 (*tok2) = (*tok2)->tokAt(-4); 06157 Token::eraseTokens((*tok2), (*tok2)->tokAt(6)); 06158 } 06159 break; 06160 } 06161 } 06162 06163 // Stop if there is a pointer alias and a shadow variable is 06164 // declared in an inner scope (#3058) 06165 if (valueIsPointer && tok3->varId() > 0 && 06166 tok3->previous() && (tok3->previous()->isName() || tok3->previous()->str() == "*") && 06167 valueToken->str() == "&" && 06168 valueToken->next() && 06169 valueToken->next()->isName() && 06170 tok3->str() == valueToken->next()->str() && 06171 tok3->varId() > valueToken->next()->varId()) { 06172 // more checking if this is a variable declaration 06173 bool decl = true; 06174 for (const Token *tok4 = tok3->previous(); tok4; tok4 = tok4->previous()) { 06175 if (Token::Match(tok4, "[;{}]")) 06176 break; 06177 06178 else if (tok4->isName()) { 06179 if (tok4->varId() > 0) { 06180 decl = false; 06181 break; 06182 } 06183 } 06184 06185 else if (!Token::Match(tok4, "[&*]")) { 06186 decl = false; 06187 break; 06188 } 06189 } 06190 if (decl) 06191 break; 06192 } 06193 06194 // Stop if label is found 06195 if (Token::Match(tok3, "; %type% : ;")) 06196 break; 06197 06198 // Stop if break/continue is found .. 06199 if (tok3->str() == "break" || tok3->str() == "continue") 06200 break; 06201 if ((indentlevel3 > 1 || !Token::simpleMatch(Token::findsimplematch(tok3,";"), "; }")) && tok3->str() == "return") 06202 ret3 = true; 06203 if (ret3 && tok3->str() == ";") 06204 break; 06205 06206 if (pointeralias && Token::Match(tok3, ("!!= " + value).c_str())) 06207 break; 06208 06209 // Stop if do is found 06210 if (tok3->str() == "do") 06211 break; 06212 06213 // Stop if unknown function call is seen 06214 // If the variable is a global or a member variable it might be 06215 // changed by the function call 06216 // TODO: don't bail out if the variable is a local variable, 06217 // then it can't be changed by the function call. 06218 if (tok3->str() == ")" && tok3->link() && 06219 Token::Match(tok3->link()->tokAt(-2), "[;{}] %var% (") && 06220 !Token::Match(tok3->link()->previous(), "if|for|while|switch|BOOST_FOREACH")) 06221 break; 06222 06223 // Stop if something like 'while (--var)' is found 06224 if (tok3->str() == "for" || tok3->str() == "while" || tok3->str() == "do") { 06225 const Token *endpar = tok3->next()->link(); 06226 if (Token::simpleMatch(endpar, ") {")) 06227 endpar = endpar->next()->link(); 06228 bool bailout = false; 06229 for (const Token *tok4 = tok3; tok4 && tok4 != endpar; tok4 = tok4->next()) { 06230 if (Token::Match(tok4, "++|-- %varid%", varid) || 06231 Token::Match(tok4, "%varid% ++|--|=", varid)) { 06232 bailout = true; 06233 break; 06234 } 06235 } 06236 if (bailout) 06237 break; 06238 } 06239 06240 if (bailOutFromLoop) { 06241 // This could be a loop, skip it, but only if it doesn't contain 06242 // the variable we are checking for. If it contains the variable 06243 // we will bail out. 06244 if (tok3->varId() == varid) { 06245 // Continue 06246 //tok2 = bailOutFromLoop; 06247 break; 06248 } else if (tok3 == bailOutFromLoop) { 06249 // We have skipped the loop 06250 bailOutFromLoop = 0; 06251 continue; 06252 } 06253 06254 continue; 06255 } else if (tok3->str() == "{" && tok3->previous()->str() == ")") { 06256 // There is a possible loop after the assignment. Try to skip it. 06257 if (tok3->previous()->link() && 06258 tok3->previous()->link()->strAt(-1) != "if") 06259 bailOutFromLoop = tok3->link(); 06260 continue; 06261 } 06262 06263 // Variable used in realloc (see Ticket #1649) 06264 if (Token::Match(tok3, "%var% = realloc ( %var% ,") && 06265 tok3->varId() == varid && 06266 tok3->tokAt(4)->varId() == varid) { 06267 tok3->tokAt(4)->str(value); 06268 ret = true; 06269 } 06270 06271 // condition "(|&&|%OROR% %varid% )|&&|%OROR% 06272 if (!Token::Match(tok3->previous(), "( %var% )") && 06273 Token::Match(tok3->previous(), "&&|(|%oror% %varid% &&|%oror%|)", varid)) { 06274 tok3->str(value); 06275 tok3->varId(valueVarId); 06276 ret = true; 06277 } 06278 06279 // parameter in function call.. 06280 if (tok3->varId() == varid && Token::Match(tok3->previous(), "[(,] %var% [,)]")) { 06281 // If the parameter is passed by value then simplify it 06282 if (isFunctionParameterPassedByValue(tok3)) { 06283 tok3->str(value); 06284 tok3->varId(valueVarId); 06285 ret = true; 06286 } 06287 } 06288 06289 // Variable is used somehow in a non-defined pattern => bail out 06290 if (tok3->varId() == varid) { 06291 // This is a really generic bailout so let's try to avoid this. 06292 // There might be lots of false negatives. 06293 if (_settings->debugwarnings) { 06294 // FIXME: Fix all the debug warnings for values and then 06295 // remove this bailout 06296 if (pointeralias) 06297 break; 06298 06299 // suppress debug-warning when calling member function 06300 if (Token::Match(tok3->next(), ". %var% (")) 06301 break; 06302 06303 // suppress debug-warning when assignment 06304 if (tok3->strAt(1) == "=") 06305 break; 06306 06307 // taking address of variable.. 06308 if (Token::Match(tok3->tokAt(-2), "return|= & %var% ;")) 06309 break; 06310 06311 // parameter in function call.. 06312 if (Token::Match(tok3->tokAt(-2), "%var% ( %var% ,|)") || 06313 Token::Match(tok3->previous(), ", %var% ,|)")) 06314 break; 06315 06316 // conditional increment 06317 if (Token::Match(tok3->tokAt(-3), ") { ++|--") || 06318 Token::Match(tok3->tokAt(-2), ") { %var% ++|--")) 06319 break; 06320 06321 reportError(tok3, Severity::debug, "debug", 06322 "simplifyKnownVariables: bailing out (variable="+tok3->str()+", value="+value+")"); 06323 } 06324 06325 break; 06326 } 06327 06328 // Using the variable in condition.. 06329 if (Token::Match(tok3->previous(), ("if ( " + structname + " %varid% %comp%|)").c_str(), varid) || 06330 Token::Match(tok3, ("( " + structname + " %varid% %comp%").c_str(), varid) || 06331 Token::Match(tok3, ("%comp%|! " + structname + " %varid% %comp%|)|;").c_str(), varid) || 06332 Token::Match(tok3->previous(), "strlen|free ( %varid% )", varid)) { 06333 if (value[0] == '\"' && tok3->previous()->str() != "strlen") { 06334 // bail out if value is a string unless if it's just given 06335 // as parameter to strlen 06336 break; 06337 } 06338 if (!structname.empty()) { 06339 tok3->deleteNext(2); 06340 } 06341 if (Token::Match(valueToken, "& %var% ;")) { 06342 tok3->insertToken("&"); 06343 tok3 = tok3->next(); 06344 } 06345 tok3 = tok3->next(); 06346 tok3->str(value); 06347 tok3->varId(valueVarId); 06348 ret = true; 06349 } 06350 06351 // Delete pointer alias 06352 if (pointeralias && tok3->str() == "delete" && 06353 (Token::Match(tok3, "delete %varid% ;", varid) || 06354 Token::Match(tok3, "delete [ ] %varid%", varid))) { 06355 tok3 = (tok3->next() && tok3->next()->str() == "[") ? tok3->tokAt(3) : tok3->next(); 06356 tok3->str(value); 06357 tok3->varId(valueVarId); 06358 ret = true; 06359 } 06360 06361 // Variable is used in function call.. 06362 if (Token::Match(tok3, ("%var% ( " + structname + " %varid% ,").c_str(), varid)) { 06363 static const char * const functionName[] = { 06364 "memcmp","memcpy","memmove","memset", 06365 "strcmp","strcpy","strncmp","strncpy","strdup" 06366 }; 06367 for (unsigned int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i) { 06368 if (tok3->str() == functionName[i]) { 06369 Token *par1 = tok3->tokAt(2); 06370 if (!structname.empty()) { 06371 par1->deleteNext(); 06372 par1->deleteThis(); 06373 } 06374 par1->str(value); 06375 par1->varId(valueVarId); 06376 break; 06377 } 06378 } 06379 } 06380 06381 // Variable is used as 2nd parameter in function call.. 06382 if (Token::Match(tok3, ("%var% ( %any% , " + structname + " %varid% ,|)").c_str(), varid)) { 06383 static const char * const functionName[] = { 06384 "memcmp","memcpy","memmove", 06385 "strcmp","strcpy","strncmp","strncpy" 06386 }; 06387 for (unsigned int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i) { 06388 if (tok3->str() == functionName[i]) { 06389 Token *par = tok3->tokAt(4); 06390 if (!structname.empty()) { 06391 par->deleteNext(); 06392 par->deleteThis(); 06393 } 06394 par->str(value); 06395 par->varId(valueVarId); 06396 break; 06397 } 06398 } 06399 } 06400 06401 // array usage 06402 if (value[0] != '\"' && Token::Match(tok3, ("[(,] " + structname + " %varid% [|%cop%").c_str(), varid)) { 06403 if (!structname.empty()) { 06404 tok3->deleteNext(2); 06405 } 06406 tok3 = tok3->next(); 06407 tok3->str(value); 06408 tok3->varId(valueVarId); 06409 ret = true; 06410 } 06411 06412 // The >> operator is sometimes used to assign a variable in C++ 06413 if (isCPP() && Token::Match(tok3, (">> " + structname + " %varid%").c_str(), varid)) { 06414 // bailout for such code: ; std :: cin >> i ; 06415 const Token *prev = tok3->previous(); 06416 while (prev && prev->str() != "return" && (prev->isName() || prev->str() == "::")) 06417 prev = prev->previous(); 06418 if (Token::Match(prev, ";|{|}|>>")) 06419 break; 06420 } 06421 06422 // Variable is used in calculation.. 06423 if (((tok3->previous()->varId() > 0) && Token::Match(tok3, ("& " + structname + " %varid%").c_str(), varid)) || 06424 (Token::Match(tok3, ("[=+-*/%^|[] " + structname + " %varid% [=?+-*/%^|;])]").c_str(), varid) && !Token::Match(tok3, ("= " + structname + " %var% =").c_str())) || 06425 Token::Match(tok3, ("[(=+-*/%^|[] " + structname + " %varid% <<|>>").c_str(), varid) || 06426 Token::Match(tok3, ("<<|>> " + structname + " %varid% %cop%|;|]|)").c_str(), varid) || 06427 Token::Match(tok3->previous(), ("[=+-*/%^|[] ( " + structname + " %varid% !!=").c_str(), varid)) { 06428 if (value[0] == '\"') 06429 break; 06430 if (!structname.empty()) { 06431 tok3->deleteNext(2); 06432 ret = true; 06433 } 06434 tok3 = tok3->next(); 06435 if (tok3->str() != value) 06436 ret = true; 06437 tok3->str(value); 06438 tok3->varId(valueVarId); 06439 if (tok3->previous()->str() == "*" && valueIsPointer) { 06440 tok3 = tok3->previous(); 06441 tok3->deleteThis(); 06442 ret = true; 06443 } 06444 } 06445 06446 if (Token::simpleMatch(tok3, "= {")) { 06447 const Token* const end4 = tok3->linkAt(1); 06448 for (const Token *tok4 = tok3; tok4 != end4; tok4 = tok4->next()) { 06449 if (Token::Match(tok4, "{|, %varid% ,|}", varid)) { 06450 tok4->next()->str(value); 06451 tok4->next()->varId(valueVarId); 06452 ret = true; 06453 } 06454 } 06455 } 06456 06457 // Using the variable in for-condition.. 06458 if (Token::simpleMatch(tok3, "for (")) { 06459 for (Token *tok4 = tok3->tokAt(2); tok4; tok4 = tok4->next()) { 06460 if (tok4->str() == "(" || tok4->str() == ")") 06461 break; 06462 06463 // Replace variable used in condition.. 06464 if (Token::Match(tok4, "; %var% <|<=|!= %var% ; ++| %var% ++| )")) { 06465 const Token *inctok = tok4->tokAt(5); 06466 if (inctok->str() == "++") 06467 inctok = inctok->next(); 06468 if (inctok->varId() == varid) 06469 break; 06470 06471 if (tok4->next()->varId() == varid) { 06472 tok4->next()->str(value); 06473 tok4->next()->varId(valueVarId); 06474 ret = true; 06475 } 06476 if (tok4->tokAt(3)->varId() == varid) { 06477 tok4->tokAt(3)->str(value); 06478 tok4->tokAt(3)->varId(valueVarId); 06479 ret = true; 06480 } 06481 } 06482 } 06483 } 06484 06485 if (!skipincdec && indentlevel == indentlevel3 && Token::Match(tok3->next(), "%varid% ++|--", varid) && MathLib::isInt(value)) { 06486 const std::string op(tok3->strAt(2)); 06487 if (Token::Match(tok3, "[{};] %any% %any% ;")) { 06488 tok3->deleteNext(3); 06489 } else { 06490 tok3 = tok3->next(); 06491 tok3->str(value); 06492 tok3->varId(valueVarId); 06493 tok3->deleteNext(); 06494 } 06495 incdec(value, op); 06496 if (!Token::simpleMatch((*tok2)->tokAt(-2), "for (")) { 06497 (*tok2)->tokAt(2)->str(value); 06498 (*tok2)->tokAt(2)->varId(valueVarId); 06499 } 06500 ret = true; 06501 } 06502 06503 if (indentlevel == indentlevel3 && Token::Match(tok3->next(), "++|-- %varid%", varid) && MathLib::isInt(value) && 06504 !Token::Match(tok3->tokAt(3), "[.[]")) { 06505 incdec(value, tok3->next()->str()); 06506 (*tok2)->tokAt(2)->str(value); 06507 (*tok2)->tokAt(2)->varId(valueVarId); 06508 if (Token::Match(tok3, "[;{}] %any% %any% ;")) { 06509 tok3->deleteNext(3); 06510 } else { 06511 tok3->deleteNext(); 06512 tok3->next()->str(value); 06513 tok3->next()->varId(valueVarId); 06514 } 06515 tok3 = tok3->next(); 06516 ret = true; 06517 } 06518 06519 // return variable.. 06520 if (Token::Match(tok3, "return %varid% %any%", varid) && 06521 (tok3->tokAt(2)->isExtendedOp() || tok3->strAt(2) == ";") && 06522 value[0] != '\"') { 06523 tok3->next()->str(value); 06524 tok3->next()->varId(valueVarId); 06525 } 06526 06527 else if (pointeralias && Token::Match(tok3, "return * %varid% ;", varid) && value[0] != '\"') { 06528 tok3->deleteNext(); 06529 tok3->next()->str(value); 06530 tok3->next()->varId(valueVarId); 06531 } 06532 } 06533 return ret; 06534 } 06535 06536 06537 void Tokenizer::elseif() 06538 { 06539 for (Token *tok = list.front(); tok; tok = tok->next()) { 06540 if (tok->str() == "(" || tok->str() == "[" || 06541 (tok->str() == "{" && tok->previous() && tok->previous()->str() == "=")) 06542 tok = tok->link(); 06543 06544 if (!Token::simpleMatch(tok, "else if")) 06545 continue; 06546 for (Token *tok2 = tok; tok2; tok2 = tok2->next()) { 06547 if (Token::Match(tok2, "(|{|[")) 06548 tok2 = tok2->link(); 06549 06550 if (Token::Match(tok2, "}|;")) { 06551 if (tok2->next() && tok2->next()->str() != "else") { 06552 tok->insertToken("{"); 06553 tok2->insertToken("}"); 06554 Token::createMutualLinks(tok->next(), tok2->next()); 06555 break; 06556 } 06557 } 06558 } 06559 } 06560 } 06561 06562 06563 bool Tokenizer::simplifyRedundantParentheses() 06564 { 06565 bool ret = false; 06566 for (Token *tok = list.front(); tok; tok = tok->next()) { 06567 if (tok->str() != "(") 06568 continue; 06569 06570 // !!operator = ( x ) ; 06571 if (tok->strAt(-2) != "operator" && 06572 tok->previous() && tok->previous()->str() == "=" && 06573 tok->next() && tok->next()->str() != "{" && 06574 Token::simpleMatch(tok->link(), ") ;")) { 06575 tok->link()->deleteThis(); 06576 tok->deleteThis(); 06577 continue; 06578 } 06579 06580 while (Token::simpleMatch(tok, "( (") && 06581 tok->link()->previous() == tok->next()->link()) { 06582 // We have "(( *something* ))", remove the inner 06583 // parentheses 06584 tok->deleteNext(); 06585 tok->link()->tokAt(-2)->deleteNext(); 06586 ret = true; 06587 } 06588 06589 if (Token::Match(tok->previous(), "! ( %var% )")) { 06590 // Remove the parentheses 06591 tok->deleteThis(); 06592 tok->deleteNext(); 06593 ret = true; 06594 } 06595 06596 if (Token::Match(tok->previous(), "[(,;{}] ( %var% (") && 06597 tok->link()->previous() == tok->linkAt(2)) { 06598 // We have "( func ( *something* ))", remove the outer 06599 // parentheses 06600 tok->link()->deleteThis(); 06601 tok->deleteThis(); 06602 ret = true; 06603 } 06604 06605 if (Token::Match(tok->previous(), "[,;{}] ( delete [| ]| %var% ) ;")) { 06606 // We have "( delete [| ]| var )", remove the outer 06607 // parentheses 06608 tok->link()->deleteThis(); 06609 tok->deleteThis(); 06610 ret = true; 06611 } 06612 06613 if (!Token::simpleMatch(tok->tokAt(-2), "operator delete") && 06614 Token::Match(tok->previous(), "delete|; (") && 06615 (tok->previous()->str() != "delete" || tok->next()->varId() > 0) && 06616 Token::Match(tok->link(), ") ;|,")) { 06617 tok->link()->deleteThis(); 06618 tok->deleteThis(); 06619 ret = true; 06620 } 06621 06622 if (Token::Match(tok->previous(), "[(!*;{}] ( %var% )") && 06623 (tok->next()->varId() != 0 || Token::Match(tok->tokAt(3), "[+-/=]"))) { 06624 // We have "( var )", remove the parentheses 06625 tok->deleteThis(); 06626 tok->deleteNext(); 06627 ret = true; 06628 } 06629 06630 while (Token::Match(tok->previous(), "[;{}[]().,!*] ( %var% .")) { 06631 Token *tok2 = tok->tokAt(2); 06632 while (Token::Match(tok2, ". %var%")) { 06633 tok2 = tok2->tokAt(2); 06634 } 06635 if (tok2 != tok->link()) 06636 break; 06637 // We have "( var . var . ... . var )", remove the parentheses 06638 tok = tok->previous(); 06639 tok->deleteNext(); 06640 tok2->deleteThis(); 06641 ret = true; 06642 continue; 06643 } 06644 06645 if (Token::simpleMatch(tok->previous(), "? (") && Token::simpleMatch(tok->link(), ") :")) { 06646 const Token *tok2 = tok->next(); 06647 while (tok2 && (Token::Match(tok2,"%bool%|%num%|%var%") || tok2->isArithmeticalOp())) 06648 tok2 = tok2->next(); 06649 if (tok2 && tok2->str() == ")") { 06650 tok->link()->deleteThis(); 06651 tok->deleteThis(); 06652 ret = true; 06653 continue; 06654 } 06655 } 06656 06657 while (Token::Match(tok->previous(), "[{([,:] ( !!{") && 06658 Token::Match(tok->link(), ") [;,])]") && 06659 !Token::findsimplematch(tok, ",", tok->link())) { 06660 // We have "( ... )", remove the parentheses 06661 tok->link()->deleteThis(); 06662 tok->deleteThis(); 06663 ret = true; 06664 } 06665 06666 if (Token::simpleMatch(tok->previous(), ", (") && 06667 Token::simpleMatch(tok->link(), ") =")) { 06668 tok->link()->deleteThis(); 06669 tok->deleteThis(); 06670 ret = true; 06671 } 06672 06673 // Simplify "!!operator !!(%var%|)) ( %num%|%bool% ) %op%|;|,|)" 06674 if (Token::Match(tok, "( %bool%|%num% ) %cop%|;|,|)") && 06675 tok->strAt(-2) != "operator" && 06676 tok->previous() && 06677 !tok->previous()->isName() && 06678 tok->previous()->str() != ")" && 06679 (!isCPP() || tok->previous()->str() != ">")) { 06680 tok->link()->deleteThis(); 06681 tok->deleteThis(); 06682 ret = true; 06683 } 06684 } 06685 return ret; 06686 } 06687 06688 void Tokenizer::simplifyCharAt() 06689 { 06690 // Replace "string"[0] with 's' 06691 for (Token *tok = list.front(); tok; tok = tok->next()) { 06692 if (Token::Match(tok, "%str% [ %num% ]")) { 06693 const MathLib::bigint index = MathLib::toLongNumber(tok->strAt(2)); 06694 // Check within range 06695 if (index >= 0 && index <= (MathLib::bigint)Token::getStrLength(tok)) { 06696 tok->str(std::string("'" + Token::getCharAt(tok, (size_t)index) + "'")); 06697 tok->deleteNext(3); 06698 } 06699 } 06700 } 06701 } 06702 06703 void Tokenizer::simplifyReference() 06704 { 06705 if (isC()) 06706 return; 06707 06708 for (Token *tok = list.front(); tok; tok = tok->next()) { 06709 // starting executable scope.. 06710 if (Token::Match(tok, ") const| {")) { 06711 // replace references in this scope.. 06712 if (tok->next()->str() != "{") 06713 tok = tok->next(); 06714 Token * const end = tok->next()->link(); 06715 for (Token *tok2 = tok; tok2 && tok2 != end; tok2 = tok2->next()) { 06716 // found a reference.. 06717 if (Token::Match(tok2, "[;{}] %type% & %var% (|= %var% )| ;")) { 06718 const unsigned int ref_id = tok2->tokAt(3)->varId(); 06719 if (!ref_id) 06720 continue; 06721 06722 // replace reference in the code.. 06723 for (Token *tok3 = tok2->tokAt(7); tok3 && tok3 != end; tok3 = tok3->next()) { 06724 if (tok3->varId() == ref_id) { 06725 tok3->str(tok2->strAt(5)); 06726 tok3->varId(tok2->tokAt(5)->varId()); 06727 } 06728 } 06729 06730 tok2->deleteNext(6+(tok->strAt(6)==")" ? 1 : 0)); 06731 } 06732 } 06733 } 06734 } 06735 } 06736 06737 bool Tokenizer::simplifyCalculations() 06738 { 06739 return TemplateSimplifier::simplifyCalculations(list.front()); 06740 } 06741 06742 06743 06744 06745 void Tokenizer::simplifyGoto() 06746 { 06747 std::list<Token *> gotos; 06748 unsigned int indentlevel = 0; 06749 unsigned int indentspecial = 0; 06750 Token *beginfunction = 0; 06751 for (Token *tok = list.front(); tok; tok = tok->next()) { 06752 if (tok->str() == "(" || tok->str() == "[") 06753 tok = tok->link(); 06754 06755 else if (Token::Match(tok, "class|namespace|struct|union %type% :|{")) { 06756 tok = tok->tokAt(2); 06757 while (tok && !Token::Match(tok, "[;{=]")) 06758 tok = tok->next(); 06759 if (tok && tok->str() == "{") 06760 ++indentspecial; 06761 else if (!tok) 06762 break; 06763 else 06764 continue; 06765 } 06766 06767 else if (Token::Match(tok, "namespace|struct|union {")) { 06768 tok = tok->next(); 06769 ++indentspecial; 06770 } 06771 06772 else if (tok->str() == "{") { 06773 if ((!beginfunction && !indentlevel) || 06774 (tok->previous() && tok->previous()->str() == "=")) 06775 tok = tok->link(); 06776 else 06777 ++indentlevel; 06778 } 06779 06780 else if (tok->str() == "}") { 06781 if (indentlevel == 0) { 06782 if (indentspecial) 06783 --indentspecial; 06784 } else { 06785 --indentlevel; 06786 if (indentlevel == 0) { 06787 gotos.clear(); 06788 beginfunction = 0; 06789 } 06790 } 06791 } 06792 06793 if (!indentlevel && Token::Match(tok, ") const| {")) 06794 beginfunction = tok; 06795 06796 else if (indentlevel && Token::Match(tok, "[{};] goto %var% ;")) 06797 gotos.push_back(tok->next()); 06798 06799 else if (indentlevel == 1 && Token::Match(tok, "[{};] %var% : ;") && tok->next()->str() != "default") { 06800 // Is this label at the end.. 06801 bool end = false; 06802 unsigned int level = 0; 06803 for (const Token *tok2 = tok->tokAt(3); tok2; tok2 = tok2->next()) { 06804 if (tok2->str() == "(" || tok2->str() == "[") 06805 tok2 = tok2->link(); 06806 06807 else if (tok2->str() == "{") { 06808 ++level; 06809 } 06810 06811 else if (tok2->str() == "}") { 06812 if (!level) { 06813 end = true; 06814 break; 06815 } 06816 --level; 06817 } 06818 06819 if ((Token::Match(tok2, "[{};] %var% : ;") && tok2->next()->str() != "default") || 06820 Token::Match(tok2, "[{};] goto %var% ;")) { 06821 break; 06822 } 06823 } 06824 if (!end) 06825 continue; 06826 06827 const std::string name(tok->next()->str()); 06828 06829 tok->deleteNext(3); 06830 06831 // This label is at the end of the function.. replace all matching goto statements.. 06832 for (std::list<Token *>::iterator it = gotos.begin(); it != gotos.end(); ++it) { 06833 Token *token = *it; 06834 if (token->next()->str() == name) { 06835 // Delete the "goto name;" 06836 token = token->previous(); 06837 // change 'tok' before 'goto' if it coincides with the ';' token after 'name' 06838 if (token->tokAt(3) == tok) 06839 tok = token; 06840 token->deleteNext(3); 06841 06842 // Insert the statements.. 06843 bool ret = false; // is there return 06844 bool ret2 = false; // is there return in indentlevel 0 06845 std::list<Token*> links; 06846 std::list<Token*> links2; 06847 std::list<Token*> links3; 06848 unsigned int lev = 0; 06849 unsigned int roundbraces = 0; 06850 for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) { 06851 if (tok2->str() == ")") { 06852 if (!roundbraces) 06853 break; 06854 --roundbraces; 06855 } 06856 if (tok2->str() == "(") 06857 ++roundbraces; 06858 06859 if (!roundbraces && tok2->str() == "}") { 06860 if (!lev) 06861 break; 06862 --lev; 06863 } else if (!roundbraces && tok2->str() == "{") { 06864 ++lev; 06865 } else if (!roundbraces && tok2->str() == "return") { 06866 ret = true; 06867 if (indentlevel == 1 && lev == 0) 06868 ret2 = true; 06869 } 06870 token->insertToken(tok2->str()); 06871 token = token->next(); 06872 token->linenr(tok2->linenr()); 06873 token->varId(tok2->varId()); 06874 if (ret2 && roundbraces == 0 && tok2->str() == ";") { 06875 break; 06876 } 06877 if (token->str() == "(") { 06878 links.push_back(token); 06879 } else if (token->str() == ")") { 06880 if (links.empty()) { 06881 // This should never happen at this point 06882 syntaxError(token, ')'); 06883 return; 06884 } 06885 06886 Token::createMutualLinks(links.back(), token); 06887 links.pop_back(); 06888 } else if (token->str() == "{") { 06889 links2.push_back(token); 06890 } else if (token->str() == "}") { 06891 if (links2.empty()) { 06892 // This should never happen at this point 06893 syntaxError(token, '}'); 06894 return; 06895 } 06896 06897 Token::createMutualLinks(links2.back(), token); 06898 links2.pop_back(); 06899 } else if (token->str() == "[") { 06900 links3.push_back(token); 06901 } else if (token->str() == "]") { 06902 if (links3.empty()) { 06903 // This should never happen at this point 06904 syntaxError(token, ']'); 06905 return; 06906 } 06907 06908 Token::createMutualLinks(links3.back(), token); 06909 links3.pop_back(); 06910 } 06911 } 06912 06913 if (!ret) { 06914 token->insertToken(";"); 06915 token->insertToken("return"); 06916 } 06917 } 06918 } 06919 06920 // goto the end of the function 06921 if (tok->str() == "{") 06922 tok = tok->link(); 06923 else { 06924 while (tok) { 06925 if (tok->str() == "{") 06926 tok = tok->link(); 06927 else if (tok->str() == "}") 06928 break; 06929 tok = tok->next(); 06930 } 06931 } 06932 if (!tok) 06933 break; 06934 gotos.clear(); 06935 beginfunction = 0; 06936 indentlevel = 0; 06937 continue; 06938 } 06939 } 06940 } 06941 06942 void Tokenizer::simplifyNestedStrcat() 06943 { 06944 for (Token *tok = list.front(); tok; tok = tok->next()) { 06945 if (! Token::Match(tok, "[;{}] strcat ( strcat (")) { 06946 continue; 06947 } 06948 06949 // find inner strcat call 06950 Token *tok2 = tok->tokAt(3); 06951 while (Token::simpleMatch(tok2, "strcat ( strcat")) { 06952 tok2 = tok2->tokAt(2); 06953 } 06954 06955 // If we have this code: 06956 // strcat(strcat(dst, foo), bar); 06957 // We move this part of code before all strcat() calls: strcat(dst, foo) 06958 // And place "dst" token where the code was. 06959 Token *prevTok = tok2->previous(); 06960 06961 // Move tokens to new place 06962 Token::move(tok2, tok2->next()->link(), tok); 06963 tok = tok2->next()->link(); 06964 06965 // Insert the "dst" token 06966 prevTok->insertToken(tok2->strAt(2)); 06967 prevTok->next()->varId(tok2->tokAt(2)->varId()); 06968 06969 // Insert semicolon after the moved strcat() 06970 tok->insertToken(";"); 06971 } 06972 06973 } 06974 06975 void Tokenizer::duplicateEnumError(const Token * tok1, const Token * tok2, const std::string & type) const 06976 { 06977 if (tok1 && !(_settings->isEnabled("style"))) 06978 return; 06979 06980 std::list<const Token*> locationList; 06981 locationList.push_back(tok1); 06982 locationList.push_back(tok2); 06983 const std::string tok2_str = tok2 ? tok2->str() : std::string("name"); 06984 06985 reportError(locationList, Severity::style, "variableHidingEnum", 06986 std::string(type + " '" + tok2_str + "' hides enumerator with same name")); 06987 } 06988 06989 // Check if this statement is a duplicate definition. A duplicate 06990 // definition will hide the enumerator within it's scope so just 06991 // skip the entire scope of the duplicate. 06992 bool Tokenizer::duplicateDefinition(Token ** tokPtr, const Token * name) const 06993 { 06994 // check for an end of definition 06995 const Token * tok = *tokPtr; 06996 if (tok && Token::Match(tok->next(), ";|,|[|=|)|>")) { 06997 const Token * end = tok->next(); 06998 06999 if (end->str() == "[") { 07000 end = end->link()->next(); 07001 } else if (end->str() == ",") { 07002 // check for function argument 07003 if (Token::Match(tok->previous(), "(|,")) 07004 return false; 07005 07006 // find end of definition 07007 int level = 0; 07008 while (end->next() && (!Token::Match(end->next(), ";|)|>") || 07009 (end->next()->str() == ")" && level == 0))) { 07010 if (end->next()->str() == "(") 07011 ++level; 07012 else if (end->next()->str() == ")") 07013 --level; 07014 07015 end = end->next(); 07016 } 07017 } else if (end->str() == ")") { 07018 // check for function argument 07019 if (tok->previous()->str() == ",") 07020 return false; 07021 } 07022 07023 if (end) { 07024 if (Token::simpleMatch(end, ") {")) { // function parameter ? 07025 // make sure it's not a conditional 07026 if (Token::Match(end->link()->previous(), "if|for|while|switch|BOOST_FOREACH")) 07027 return false; 07028 07029 // look backwards 07030 if (tok->previous()->str() == "enum" || 07031 (Token::Match(tok->previous(), "%type%") && 07032 tok->previous()->str() != "return") || 07033 Token::Match(tok->tokAt(-2), "%type% &|*")) { 07034 duplicateEnumError(*tokPtr, name, "Function parameter"); 07035 // duplicate definition so skip entire function 07036 *tokPtr = end->next()->link(); 07037 return true; 07038 } 07039 } else if (end->str() == ">") { // template parameter ? 07040 // look backwards 07041 if (tok->previous()->str() == "enum" || 07042 (Token::Match(tok->previous(), "%type%") && 07043 tok->previous()->str() != "return")) { 07044 // duplicate definition so skip entire template 07045 while (end && end->str() != "{") 07046 end = end->next(); 07047 if (end) { 07048 duplicateEnumError(*tokPtr, name, "Template parameter"); 07049 *tokPtr = end->link(); 07050 return true; 07051 } 07052 } 07053 } else { 07054 if (Token::Match(tok->previous(), "enum|,")) { 07055 duplicateEnumError(*tokPtr, name, "Variable"); 07056 return true; 07057 } else if (Token::Match(tok->previous(), "%type%")) { 07058 // look backwards 07059 const Token *back = tok; 07060 while (back && back->isName()) 07061 back = back->previous(); 07062 if (!back || Token::Match(back, "[(,;{}] !!return")) { 07063 duplicateEnumError(*tokPtr, name, "Variable"); 07064 return true; 07065 } 07066 } 07067 } 07068 } 07069 } 07070 return false; 07071 } 07072 07073 class EnumValue { 07074 public: 07075 EnumValue() { 07076 name = 0; 07077 value = 0; 07078 start = 0; 07079 end = 0; 07080 } 07081 EnumValue(const EnumValue &ev) { 07082 name = ev.name; 07083 value = ev.value; 07084 start = ev.start; 07085 end = ev.end; 07086 } 07087 EnumValue(Token *name_, Token *value_, Token *start_, Token *end_) { 07088 name = name_; 07089 value = value_; 07090 start = start_; 07091 end = end_; 07092 } 07093 07094 void simplify(const std::map<std::string, EnumValue> &enumValues) { 07095 for (Token *tok = start; tok; tok = tok->next()) { 07096 if (enumValues.find(tok->str()) != enumValues.end()) { 07097 const EnumValue &other = enumValues.find(tok->str())->second; 07098 if (other.value != NULL) 07099 tok->str(other.value->str()); 07100 else { 07101 bool islast = (tok == end); 07102 Token *last = Tokenizer::copyTokens(tok, other.start, other.end); 07103 if (last == tok->next()) // tok->deleteThis() invalidates a pointer that points at the next token 07104 last = tok; 07105 tok->deleteThis(); 07106 if (islast) { 07107 end = last; 07108 } 07109 tok = last; 07110 } 07111 } 07112 if (tok == end) 07113 break; 07114 } 07115 07116 // Simplify calculations.. 07117 while (start && start->previous() && TemplateSimplifier::simplifyNumericCalculations(start->previous())) { } 07118 07119 if (Token::Match(start, "%num% [,}]")) { 07120 value = start; 07121 start = end = NULL; 07122 } 07123 } 07124 07125 Token *name; 07126 Token *value; 07127 Token *start; 07128 Token *end; 07129 }; 07130 07131 void Tokenizer::simplifyEnum() 07132 { 07133 std::string className; 07134 int classLevel = 0; 07135 bool goback = false; 07136 for (Token *tok = list.front(); tok; tok = tok->next()) { 07137 07138 if (goback) { 07139 //jump back once, see the comment at the end of the function 07140 goback = false; 07141 tok = tok->previous(); 07142 } 07143 07144 if (Token::Match(tok, "class|struct|namespace") && tok->next() && 07145 (!tok->previous() || (tok->previous() && tok->previous()->str() != "enum"))) { 07146 className = tok->next()->str(); 07147 classLevel = 0; 07148 } else if (tok->str() == "}") { 07149 --classLevel; 07150 if (classLevel < 0) 07151 className = ""; 07152 } else if (tok->str() == "{") { 07153 ++classLevel; 07154 } else if (tok->str() == "enum") { 07155 Token *temp = tok->next(); 07156 if (!temp) 07157 break; 07158 if (Token::Match(temp, "class|struct")) 07159 temp = temp->next(); 07160 if (!Token::Match(temp, "[{:]") && 07161 (!temp->isName() || !Token::Match(temp->next(), "[{:;]"))) 07162 continue; 07163 Token *start = tok; 07164 Token *enumType = 0; 07165 Token *typeTokenStart = 0; 07166 Token *typeTokenEnd = 0; 07167 07168 // check for C++0x enum class 07169 if (Token::Match(tok->next(), "class|struct")) 07170 tok->deleteNext(); 07171 07172 // check for name 07173 if (tok->next()->isName()) { 07174 enumType = tok->next(); 07175 tok = tok->next(); 07176 } 07177 07178 // check for C++0x typed enumeration 07179 if (tok->next()->str() == ":") { 07180 tok = tok->next(); 07181 07182 if (!tok->next()) { 07183 syntaxError(tok); 07184 return; // can't recover 07185 } 07186 07187 typeTokenStart = tok->next(); 07188 tok = tok->next(); 07189 typeTokenEnd = typeTokenStart; 07190 07191 while (typeTokenEnd->next() && (typeTokenEnd->next()->str() == "::" || 07192 Token::Match(typeTokenEnd->next(), "%type%"))) { 07193 typeTokenEnd = typeTokenEnd->next(); 07194 tok = tok->next(); 07195 } 07196 07197 if (!tok->next()) { 07198 syntaxError(tok); 07199 return; // can't recover 07200 } 07201 } 07202 07203 // check for forward declaration 07204 if (tok->next()->str() == ";") { 07205 tok = tok->next(); 07206 07207 /** @todo start substitution check at forward declaration */ 07208 // delete forward declaration 07209 Token::eraseTokens(start, tok); 07210 start->deleteThis(); 07211 tok = start; 07212 continue; 07213 } else if (tok->next()->str() != "{") { 07214 syntaxError(tok->next()); 07215 return; 07216 } 07217 07218 Token *tok1 = tok->next(); 07219 Token *end = tok1->link(); 07220 tok1 = tok1->next(); 07221 07222 MathLib::bigint lastValue = -1; 07223 Token * lastEnumValueStart = 0; 07224 Token * lastEnumValueEnd = 0; 07225 07226 // iterate over all enumerators between { and } 07227 // Give each enumerator the const value specified or if not specified, 1 + the 07228 // previous value or 0 if it is the first one. 07229 std::map<std::string,EnumValue> enumValues; 07230 for (; tok1 && tok1 != end; tok1 = tok1->next()) { 07231 Token * enumName = 0; 07232 Token * enumValue = 0; 07233 Token * enumValueStart = 0; 07234 Token * enumValueEnd = 0; 07235 07236 if (tok1->str() == "(") { 07237 tok1 = tok1->link(); 07238 continue; 07239 } 07240 07241 if (Token::Match(tok1->previous(), ",|{ %type% ,|}")) { 07242 // no value specified 07243 enumName = tok1; 07244 ++lastValue; 07245 tok1->insertToken("="); 07246 tok1 = tok1->next(); 07247 07248 if (lastEnumValueStart && lastEnumValueEnd) { 07249 // previous value was an expression 07250 Token *valueStart = tok1; 07251 tok1 = copyTokens(tok1, lastEnumValueStart, lastEnumValueEnd); 07252 07253 // value is previous expression + 1 07254 tok1->insertToken("+"); 07255 tok1 = tok1->next(); 07256 tok1->insertToken("1"); 07257 enumValue = 0; 07258 enumValueStart = valueStart->next(); 07259 enumValueEnd = tok1->next(); 07260 } else { 07261 // value is previous numeric value + 1 07262 tok1->insertToken(MathLib::longToString(lastValue)); 07263 enumValue = tok1->next(); 07264 } 07265 } else if (Token::Match(tok1->previous(), ",|{ %type% = %num% ,|}")) { 07266 // value is specified numeric value 07267 enumName = tok1; 07268 lastValue = MathLib::toLongNumber(tok1->strAt(2)); 07269 enumValue = tok1->tokAt(2); 07270 lastEnumValueStart = 0; 07271 lastEnumValueEnd = 0; 07272 } else if (Token::Match(tok1->previous(), ",|{ %type% =")) { 07273 // value is specified expression 07274 enumName = tok1; 07275 lastValue = 0; 07276 tok1 = tok1->tokAt(2); 07277 enumValueStart = tok1; 07278 enumValueEnd = tok1; 07279 int level = 0; 07280 while (enumValueEnd->next() && (!Token::Match(enumValueEnd->next(), "[},]") || level)) { 07281 if (Token::Match(enumValueEnd, "(|[")) 07282 ++level; 07283 else if (Token::Match(enumValueEnd->next(), "]|)")) 07284 --level; 07285 07286 enumValueEnd = enumValueEnd->next(); 07287 } 07288 // remember this expression in case it needs to be incremented 07289 lastEnumValueStart = enumValueStart; 07290 lastEnumValueEnd = enumValueEnd; 07291 // skip over expression 07292 tok1 = enumValueEnd; 07293 } 07294 07295 // add enumerator constant.. 07296 if (enumName && (enumValue || (enumValueStart && enumValueEnd))) { 07297 EnumValue ev(enumName, enumValue, enumValueStart, enumValueEnd); 07298 ev.simplify(enumValues); 07299 enumValues[enumName->str()] = ev; 07300 lastEnumValueStart = ev.start; 07301 lastEnumValueEnd = ev.end; 07302 if (ev.start == NULL) 07303 lastValue = MathLib::toLongNumber(ev.value->str()); 07304 tok1 = ev.end ? ev.end : ev.value; 07305 } 07306 } 07307 07308 // Substitute enum values 07309 { 07310 const std::string pattern = className.empty() ? 07311 std::string("") : 07312 std::string(className + " :: "); 07313 int level = 0; 07314 bool inScope = true; 07315 07316 std::stack<std::set<std::string> > shadowId; // duplicate ids in inner scope 07317 bool simplify = false; 07318 bool hasClass = false; 07319 EnumValue *ev = NULL; 07320 07321 if (!tok1) 07322 return; 07323 for (Token *tok2 = tok1->next(); tok2; tok2 = tok2->next()) { 07324 if (tok2->str() == "}") { 07325 --level; 07326 if (level < 0) 07327 inScope = false; 07328 07329 if (!shadowId.empty()) 07330 shadowId.pop(); 07331 } else if (tok2->str() == "{") { 07332 // Is the same enum redefined? 07333 const Token *begin = end->link(); 07334 if (tok2->fileIndex() == begin->fileIndex() && 07335 tok2->linenr() == begin->linenr() && 07336 Token::Match(begin->tokAt(-2), "enum %type% {") && 07337 Token::Match(tok2->tokAt(-2), "enum %type% {") && 07338 begin->previous()->str() == tok2->previous()->str()) { 07339 // remove duplicate enum 07340 Token * startToken = tok2->tokAt(-3); 07341 tok2 = tok2->link()->next(); 07342 Token::eraseTokens(startToken, tok2); 07343 if (!tok2) 07344