diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 3e529bb97..82e0d05a5 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2714,7 +2714,7 @@ std::list Tokenizer::simplifyTemplatesGetTemplateInstantiations() if (!tok) break; } - else if (Token::Match(tok->previous(), "[({};=] %type% <") || + else if (Token::Match(tok->previous(), "[{};=] %var% <") || Token::Match(tok->tokAt(-2), "[,:] private|protected|public %var% <")) { if (templateParameters(tok->next())) @@ -3087,4 +3087,6432 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, } // link() newly tokens manually - \ No newline at end of file + if (tok3->str() == "{") + { + braces.push(_tokensBack); + } + else if (tok3->str() == "}") + { + assert(braces.empty() == false); + Token::createMutualLinks(braces.top(), _tokensBack); + braces.pop(); + } + else if (tok3->str() == "(") + { + brackets.push(_tokensBack); + } + else if (tok3->str() == "[") + { + brackets2.push(_tokensBack); + } + else if (tok3->str() == ")") + { + assert(brackets.empty() == false); + Token::createMutualLinks(brackets.top(), _tokensBack); + brackets.pop(); + } + else if (tok3->str() == "]") + { + assert(brackets2.empty() == false); + Token::createMutualLinks(brackets2.top(), _tokensBack); + brackets2.pop(); + } + + } + + assert(braces.empty()); + assert(brackets.empty()); + } + } + + // Replace all these template usages.. + for (Token *tok4 = tok2; tok4; tok4 = tok4->next()) + { + if (Token::simpleMatch(tok4, s1.c_str())) + { + bool match = true; + Token * tok5 = tok4->tokAt(2); + unsigned int count = 0; + const Token *typetok = (!types2.empty()) ? types2[0] : 0; + while (tok5->str() != ">") + { + if (tok5->str() != ",") + { + if (!typetok || + tok5->isUnsigned() != typetok->isUnsigned() || + tok5->isSigned() != typetok->isSigned() || + tok5->isLong() != typetok->isLong()) + { + match = false; + break; + } + + typetok = typetok ? typetok->next() : 0; + } + else + { + ++count; + typetok = (count < types2.size()) ? types2[count] : 0; + } + tok5 = tok5->next(); + } + + if (match) + { + tok4->str(name2); + while (tok4->next()->str() != ">") + { + used.remove(tok4->next()); + tok4->deleteNext(); + } + used.remove(tok4->next()); + tok4->deleteNext(); + } + } + } + } +} + +void Tokenizer::simplifyTemplates() +{ + std::set expandedtemplates(simplifyTemplatesExpandSpecialized()); + + // Locate templates.. + std::list templates(simplifyTemplatesGetTemplateDeclarations()); + + if (templates.empty()) + { + removeTemplates(_tokens); + return; + } + + // There are templates.. + // Remove "typename" unless used in template arguments.. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "typename") + tok->deleteThis(); + + if (Token::simpleMatch(tok, "template <")) + { + while (tok && tok->str() != ">") + tok = tok->next(); + if (!tok) + break; + } + } + + // Locate possible instantiations of templates.. + std::list used(simplifyTemplatesGetTemplateInstantiations()); + + // No template instantiations? Then remove all templates. + if (used.empty()) + { + removeTemplates(_tokens); + return; + } + + // Template arguments with default values + simplifyTemplatesUseDefaultArgumentValues(templates, used); + + // expand templates + bool done = false; + //while (!done) + { + done = true; + for (std::list::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) + { + simplifyTemplatesInstantiate(*iter1, used, expandedtemplates); + } + } + + removeTemplates(_tokens); +} +//--------------------------------------------------------------------------- + +void Tokenizer::simplifyTemplates2() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "(") + tok = tok->link(); + + else if (Token::Match(tok, "; %type% <")) + { + const Token *tok2 = tok->tokAt(3); + std::string type; + while (Token::Match(tok2, "%type% ,") || Token::Match(tok2, "%num% ,")) + { + type += tok2->str() + ","; + tok2 = tok2->tokAt(2); + } + if (Token::Match(tok2, "%type% > (") || Token::Match(tok2, "%num% > (")) + { + type += tok2->str(); + tok = tok->next(); + tok->str(tok->str() + "<" + type + ">"); + Token::eraseTokens(tok, tok2->tokAt(2)); + } + } + } +} +//--------------------------------------------------------------------------- + +std::string Tokenizer::getNameForFunctionParams(const Token *start) +{ + if (start->next() == start->link()) + return ""; + + std::string result; + bool findNextComma = false; + for (const Token *tok = start->next(); tok && tok != start->link(); tok = tok->next()) + { + if (findNextComma) + { + if (tok->str() == ",") + findNextComma = false; + + continue; + } + + result.append(tok->str() + ","); + findNextComma = true; + } + + return result; +} + +void Tokenizer::setVarId() +{ + // Clear all variable ids + for (Token *tok = _tokens; tok; tok = tok->next()) + tok->varId(0); + + // Set variable ids.. + _varId = 0; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok != _tokens && !Token::Match(tok, "[;{}(,] %type%")) + continue; + + if (_errorLogger) + _errorLogger->reportProgress(_files[0], "Tokenize (set variable id)", tok->progressValue()); + + // If pattern is "( %type% *|& %var% )" then check if it's a + // variable declaration or a multiplication / mask + if (Token::Match(tok, "( %type% *|& %var% [),]") && !tok->next()->isStandardType()) + { + if (!Token::Match(tok->previous(), "%type%")) + continue; + if (tok->strAt(-1) == "return") + continue; + if (!Token::Match(tok->tokAt(5), "const|{")) + continue; + } + + if (Token::Match(tok, "[,;{}(] %type%")) + { + // not function declaration? + // TODO: Better checking + if (Token::Match(tok->tokAt(-2), "= %var% (")) + { + continue; + } + if (tok->str() == "(" && + tok->previous() && + !tok->previous()->isName() && + tok->strAt(-2) != "operator") + continue; + tok = tok->next(); + } + + if (tok->str() == "new") + continue; + + if (tok->str() == "throw") + continue; + + if (tok->str() == "unsigned") + tok = tok->next(); + + if (Token::Match(tok, "class|struct %type% :|{|;")) + continue; + + if (Token::Match(tok, "using namespace %type% ;")) + { + tok = tok->next(); + continue; + } + + if (Token::Match(tok, "else|return|typedef|delete|sizeof")) + continue; + + while (Token::Match(tok, "const|static|extern|public:|private:|protected:|;|mutable")) + tok = tok->next(); + + while (Token::Match(tok, "%var% ::")) + tok = tok->tokAt(2); + + // Skip template arguments.. + if (Token::Match(tok, "%type% <")) + { + int level = 1; + bool again; + Token *tok2 = tok->tokAt(2); + + do // Look for start of templates or template arguments + { + again = false; + + if (tok2->str() == "const") + tok2 = tok2->next(); + + while (Token::Match(tok2, "%var% ::")) + tok2 = tok2->tokAt(2); + + if (Token::Match(tok2, "%type% <")) + { + level++; + tok2 = tok2->tokAt(2); + again = true; + } + else if (Token::Match(tok2, "%type% *|&| ,")) + { + tok2 = tok2->tokAt(2); + if (tok2->str() == ",") + tok2 = tok2->next(); + again = true; + } + else if (level > 1 && Token::Match(tok2, "%type% *|&| >")) + { + --level; + while (tok2->str() != ">") + tok2 = tok2->next(); + tok2 = tok2->next(); + if (tok2->str() == ",") + tok2 = tok2->next(); + if (level == 1 && tok2->str() == ">") + break; + again = true; + } + else + { + while (tok2 && (tok2->isName() || tok2->isNumber() || tok2->str() == "*" || tok2->str() == "&" || tok2->str() == ",")) + tok2 = tok2->next(); + if (tok2->str() == "(") + { + tok2 = tok2->link()->next(); + if (tok2->str() == "(") + tok2 = tok2->link()->next(); + again = true; + } + } + } + while (again); + + do // Look for end of templates + { + again = false; + + if (level == 1 && Token::Match(tok2, "> %var%")) + tok = tok2; + else if (level > 1 && tok2->str() == ">") + { + level--; + if (level == 0) + tok = tok2; + else + { + tok2 = tok2->tokAt(1); + again = true; + } + } + else if (level == 1 && Token::Match(tok2, "> ::|*|& %var%")) + tok = tok2->next(); + else + continue; // Not code that I understand / not a variable declaration + } + while (again); + } + + // Determine name of declared variable.. + std::string varname; + Token *tok2 = tok->tokAt(1); + while (tok2) + { + if (tok2->isName()) + varname = tok2->str(); + else if (tok2->str() != "*" && tok2->str() != "&") + break; + tok2 = tok2->next(); + } + + // End of tokens reached.. + if (!tok2) + break; + + if (varname == "operator" && Token::Match(tok2, "=|+|-|*|/|[| ]| (")) + continue; + + if (varname == "new" && Token::Match(tok2->tokAt(-2), "operator new (|[")) + continue; + + // Is it a function? + if (tok2->str() == "(") + { + // Search for function declaration, e.g. void f(); + if (Token::simpleMatch(tok2->next(), ") ;")) + continue; + + // Search for function declaration, e.g. void f( int c ); + if (Token::Match(tok2->next(), "%num%") || + Token::Match(tok2->next(), "%bool%") || + tok2->next()->str()[0] == '"' || + tok2->next()->str()[0] == '\'' || + tok2->next()->varId() != 0) + { + // This is not a function + } + else + { + continue; + } + } + + // Variable declaration found => Set variable ids + if (Token::Match(tok2, "[,();[=]") && !varname.empty()) + { + ++_varId; + int indentlevel = 0; + int parlevel = 0; + bool funcDeclaration = false; + for (tok2 = tok->next(); tok2; tok2 = tok2->next()) + { + const char c = tok2->str()[0]; + if (c == varname[0]) + { + const std::string &prev = tok2->strAt(-1); + if (tok2->str() == varname && prev != "struct" && prev != "union" && prev != "::" && prev != "." && tok2->strAt(1) != "::") + tok2->varId(_varId); + } + else if (c == '{') + ++indentlevel; + else if (c == '}') + { + --indentlevel; + if (indentlevel < 0) + break; + + // We have reached the end of a loop: "for( int i;;) { }" + if (funcDeclaration && indentlevel <= 0) + break; + } + else if (c == '(') + ++parlevel; + else if (c == ')') + { + // Is this a function parameter or a variable declared in for example a for loop? + if (parlevel == 0 && indentlevel == 0 && Token::Match(tok2, ") const| {")) + funcDeclaration = true; + else + --parlevel; + } + else if (parlevel < 0 && c == ';') + break; + } + } + } + + // Struct/Class members + for (Token *tok = _tokens; tok; tok = tok->next()) + { + // str.clear is a variable + // str.clear() is a member function + if (tok->varId() != 0 && + Token::Match(tok->next(), ". %var% !!(") && + tok->tokAt(2)->varId() == 0) + { + ++_varId; + + const std::string pattern(std::string(". ") + tok->strAt(2)); + for (Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (tok2->varId() == tok->varId()) + { + if (Token::Match(tok2->next(), pattern.c_str())) + tok2->tokAt(2)->varId(_varId); + } + } + } + } + + // Member functions and variables in this source + std::list allMemberFunctions; + std::list allMemberVars; + { + for (Token *tok2 = _tokens; tok2; tok2 = tok2->next()) + { + if (Token::Match(tok2, "%var% :: %var%")) + { + if (Token::simpleMatch(tok2->tokAt(3), "(")) + allMemberFunctions.push_back(tok2); + else if (tok2->tokAt(2)->varId() != 0) + allMemberVars.push_back(tok2); + } + } + } + + // class members.. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "class|struct %var% {|:")) + { + const std::string &classname(tok->next()->str()); + + // What member variables are there in this class? + std::map varlist; + { + unsigned int indentlevel = 0; + for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + // Indentation.. + if (tok2->str() == "{") + ++indentlevel; + else if (tok2->str() == "}") + { + if (indentlevel <= 1) + break; + --indentlevel; + } + + // Found a member variable.. + else if (indentlevel == 1 && tok2->varId() > 0) + varlist[tok2->str()] = tok2->varId(); + } + } + + // Are there any member variables in this class? + if (varlist.empty()) + continue; + + // Member variables + for (std::list::iterator func = allMemberVars.begin(); func != allMemberVars.end(); ++func) + { + if (!Token::simpleMatch(*func, classname.c_str())) + continue; + + Token *tok2 = *func; + tok2 = tok2->tokAt(2); + tok2->varId(varlist[tok2->str()]); + } + + // Member functions for this class.. + std::list funclist; + { + const std::string funcpattern(classname + " :: %var% ("); + for (std::list::iterator func = allMemberFunctions.begin(); func != allMemberFunctions.end(); ++func) + { + Token *tok2 = *func; + + // Found a class function.. + if (Token::Match(tok2, funcpattern.c_str())) + { + // Goto the end parenthesis.. + tok2 = tok2->tokAt(3)->link(); + if (!tok2) + break; + + // If this is a function implementation.. add it to funclist + if (Token::Match(tok2, ") const|volatile| {")) + funclist.push_back(tok2); + } + } + } + + // Update the variable ids.. + // Parse each function.. + for (std::list::iterator func = funclist.begin(); func != funclist.end(); ++func) + { + unsigned int indentlevel = 0; + for (Token *tok2 = *func; tok2; tok2 = tok2->next()) + { + if (tok2->str() == "{") + ++indentlevel; + else if (tok2->str() == "}") + { + if (indentlevel <= 1) + break; + --indentlevel; + } + else if (indentlevel > 0 && + tok2->varId() == 0 && + !Token::simpleMatch(tok2->previous(), ".") && + varlist.find(tok2->str()) != varlist.end()) + { + tok2->varId(varlist[tok2->str()]); + } + } + } + + } + } +} + +bool Tokenizer::createLinks() +{ + std::list type; + std::list links; + std::list links2; + std::list links3; + for (Token *token = _tokens; token; token = token->next()) + { + if (token->link()) + { + token->link(0); + } + + if (token->str() == "{") + { + links.push_back(token); + type.push_back(token); + } + else if (token->str() == "}") + { + if (links.empty()) + { + // Error, { and } don't match. + syntaxError(token, '{'); + return false; + } + if (type.back()->str() != "{") + { + syntaxError(type.back(), type.back()->str()[0]); + return false; + } + type.pop_back(); + + Token::createMutualLinks(links.back(), token); + links.pop_back(); + } + else if (token->str() == "(") + { + links2.push_back(token); + type.push_back(token); + } + else if (token->str() == ")") + { + if (links2.empty()) + { + // Error, ( and ) don't match. + syntaxError(token, '('); + return false; + } + if (type.back()->str() != "(") + { + syntaxError(type.back(), type.back()->str()[0]); + return false; + } + type.pop_back(); + + Token::createMutualLinks(links2.back(), token); + links2.pop_back(); + } + else if (token->str() == "[") + { + links3.push_back(token); + type.push_back(token); + } + else if (token->str() == "]") + { + if (links3.empty()) + { + // Error, [ and ] don't match. + syntaxError(token, '['); + return false; + } + if (type.back()->str() != "[") + { + syntaxError(type.back(), type.back()->str()[0]); + return false; + } + type.pop_back(); + + Token::createMutualLinks(links3.back(), token); + links3.pop_back(); + } + } + + if (!links.empty()) + { + // Error, { and } don't match. + syntaxError(links.back(), '{'); + return false; + } + + if (!links2.empty()) + { + // Error, ( and ) don't match. + syntaxError(links2.back(), '('); + return false; + } + + if (!links3.empty()) + { + // Error, [ and ] don't match. + syntaxError(links3.back(), '['); + return false; + } + + return true; +} + +void Tokenizer::simplifySizeof() +{ + // Fill the map _typeSize.. + _typeSize.clear(); + _typeSize["char"] = sizeof(char); + _typeSize["short"] = sizeof(short); + _typeSize["int"] = sizeof(int); + _typeSize["long"] = sizeof(long); + _typeSize["float"] = sizeof(float); + _typeSize["double"] = sizeof(double); + _typeSize["size_t"] = sizeof(size_t); + _typeSize["*"] = sizeof(void *); + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "class|struct %var%")) + { + // we assume that the size of structs and classes are always + // 100 bytes. + _typeSize[tok->strAt(1)] = 100; + } + } + + // Locate variable declarations and calculate the size + std::map sizeOfVar; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->varId() != 0 && sizeOfVar.find(tok->varId()) == sizeOfVar.end()) + { + const unsigned int varId = tok->varId(); + if (Token::Match(tok->tokAt(-3), "[;{}(,] %type% * %var% [;,)]") || + Token::Match(tok->tokAt(-4), "[;{}(,] const %type% * %var% [;),]") || + Token::Match(tok->tokAt(-2), "[;{}(,] %type% %var% [;),]") || + Token::Match(tok->tokAt(-3), "[;{}(,] const %type% %var% [;),]")) + { + const unsigned int size = sizeOfType(tok->previous()); + if (size == 0) + { + continue; + } + + sizeOfVar[varId] = MathLib::toString(size); + } + + else if (Token::Match(tok->tokAt(-1), "%type% %var% [ %num% ] [;=]") || + Token::Match(tok->tokAt(-2), "%type% * %var% [ %num% ] [;=]")) + { + const unsigned int size = sizeOfType(tok->tokAt(-1)); + if (size == 0) + continue; + + sizeOfVar[varId] = MathLib::toString(size * static_cast(MathLib::toLongNumber(tok->strAt(2)))); + } + + else if (Token::Match(tok->tokAt(-1), "%type% %var% [ %num% ] [,)]") || + Token::Match(tok->tokAt(-2), "%type% * %var% [ %num% ] [,)]")) + { + Token tempTok(0); + tempTok.str("*"); + sizeOfVar[varId] = MathLib::toString(sizeOfType(&tempTok)); + } + + else if (Token::Match(tok->tokAt(-1), "%type% %var% [ ] = %str% ;")) + { + const unsigned int size = sizeOfType(tok->tokAt(4)); + if (size == 0) + continue; + + sizeOfVar[varId] = MathLib::toString(size); + } + } + } + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() != "sizeof") + continue; + + if (!tok->next()) + break; + + if (Token::simpleMatch(tok->next(), "sizeof")) + continue; + + if (Token::simpleMatch(tok->next(), ". . .")) + { + Token::eraseTokens(tok, tok->tokAt(4)); + } + + // sizeof 'x' + if (tok->strAt(1)[0] == '\'') + { + tok->deleteThis(); + std::ostringstream sz; + sz << sizeof 'x'; + tok->str(sz.str()); + continue; + } + + // sizeof('x') + if (Token::Match(tok, "sizeof ( %any% )") && tok->strAt(2)[0] == '\'') + { + tok->deleteThis(); + tok->deleteThis(); + tok->deleteNext(); + std::ostringstream sz; + sz << sizeof 'x'; + tok->str(sz.str()); + continue; + } + + // sizeof "text" + if (Token::Match(tok->next(), "%str%")) + { + tok->deleteThis(); + std::ostringstream ostr; + ostr << (Token::getStrLength(tok) + 1); + tok->str(ostr.str()); + continue; + } + + // sizeof ("text") + if (Token::Match(tok->next(), "( %str% )")) + { + tok->deleteThis(); + tok->deleteThis(); + tok->deleteNext(); + std::ostringstream ostr; + ostr << (Token::getStrLength(tok) + 1); + tok->str(ostr.str()); + continue; + } + + // sizeof * (...) -> sizeof(*...) + if (Token::simpleMatch(tok->next(), "* (") && !Token::simpleMatch(tok->tokAt(2)->link(), ") .")) + { + tok->deleteNext(); + tok->next()->insertToken("*"); + } + + // sizeof a++ -> sizeof(a++) + if (Token::Match(tok->next(), "++|-- %var% !!.") || Token::Match(tok->next(), "%var% ++|--")) + { + tok->insertToken("("); + tok->tokAt(3)->insertToken(")"); + Token::createMutualLinks(tok->next(), tok->tokAt(4)); + } + + // sizeof 1 => sizeof ( 1 ) + if (tok->next()->isNumber()) + { + Token *tok2 = tok->next(); + tok->insertToken("("); + tok2->insertToken(")"); + Token::createMutualLinks(tok->next(), tok2->next()); + } + + // sizeof int -> sizeof( int ) + else if (tok->next()->str() != "(") + { + // Add parenthesis around the sizeof + int parlevel = 0; + for (Token *tempToken = tok->next(); tempToken; tempToken = tempToken->next()) + { + if (tempToken->str() == "(") + ++parlevel; + else if (tempToken->str() == ")") + --parlevel; + if (Token::Match(tempToken, "%var%")) + { + while (tempToken && tempToken->next() && tempToken->next()->str() == "[") + { + tempToken = tempToken->next()->link(); + } + if (!tempToken || !tempToken->next()) + { + break; + } + + if (tempToken->next()->str() == ".") + { + // We are checking a class or struct, search next varname + tempToken = tempToken->tokAt(1); + continue; + } + else if (Token::simpleMatch(tempToken->next(), "- >")) + { + // We are checking a class or struct, search next varname + tempToken = tempToken->tokAt(2); + continue; + } + else if (Token::Match(tempToken->next(), "++|--")) + { + // We have variable++ or variable--, there should be + // nothing after this + tempToken = tempToken->tokAt(2); + } + else if (parlevel > 0 && Token::simpleMatch(tempToken->next(), ") .")) + { + --parlevel; + tempToken = tempToken->tokAt(2); + continue; + } + + // Ok, we should be clean. Add ) after tempToken + tok->insertToken("("); + tempToken->insertToken(")"); + Token::createMutualLinks(tok->next(), tempToken->next()); + break; + } + } + } + + // sizeof(type *) => sizeof(*) + if (Token::Match(tok->next(), "( %type% * )")) + { + tok->next()->deleteNext(); + } + + if (Token::simpleMatch(tok->next(), "( * )")) + { + tok->str(MathLib::toString(sizeOfType(tok->tokAt(2)))); + Token::eraseTokens(tok, tok->tokAt(4)); + } + + // sizeof( a ) + else if (Token::Match(tok->next(), "( %var% )") && tok->tokAt(2)->varId() != 0) + { + if (sizeOfVar.find(tok->tokAt(2)->varId()) != sizeOfVar.end()) + { + tok->deleteThis(); + tok->deleteThis(); + tok->deleteNext(); + tok->str(sizeOfVar[tok->varId()]); + } + else + { + // don't try to replace size of variable if variable has + // similar name with type (#329) + } + } + + else if (Token::Match(tok, "sizeof ( %type% )")) + { + unsigned int size = sizeOfType(tok->tokAt(2)); + if (size > 0) + { + tok->str(MathLib::toString(size)); + Token::eraseTokens(tok, tok->tokAt(4)); + } + } + + else if (Token::Match(tok, "sizeof ( * %var% )") || Token::Match(tok, "sizeof ( %var% [ %num% ] )")) + { + // Some default value.. + unsigned int sz = 0; + + unsigned int varid = tok->tokAt((tok->tokAt(2)->str() == "*") ? 3 : 2)->varId(); + if (varid != 0) + { + // Try to locate variable declaration.. + const Token *decltok = Token::findmatch(_tokens, "%varid%", varid); + if (Token::Match(decltok->previous(), "%type% %var% [")) + { + sz = sizeOfType(decltok->previous()); + } + else if (Token::Match(decltok->previous(), "* %var% [")) + { + sz = sizeOfType(decltok->previous()); + } + else if (Token::Match(decltok->tokAt(-2), "%type% * %var%")) + { + sz = sizeOfType(decltok->tokAt(-2)); + } + } + else if (tok->strAt(3) == "[" && tok->tokAt(2)->isStandardType()) + { + sz = sizeOfType(tok->tokAt(2)); + if (sz == 0) + continue; + sz = sz * static_cast(MathLib::toLongNumber(tok->strAt(4))); + } + + if (sz > 0) + { + tok->str(MathLib::toString(sz)); + Token::eraseTokens(tok, tok->next()->link()->next()); + } + } + } + +} + +bool Tokenizer::simplifyTokenList() +{ + // clear the _functionList so it can't contain dead pointers + delete _symbolDatabase; + _symbolDatabase = NULL; + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::simpleMatch(tok, "* const")) + tok->deleteNext(); + } + + // simplify references + simplifyReference(); + + simplifyStd(); + + simplifyGoto(); + + // Combine wide strings + for (Token *tok = _tokens; tok; tok = tok->next()) + { + while (tok->str() == "L" && tok->next() && tok->next()->str()[0] == '"') + { + // Combine 'L "string"' + tok->str(tok->next()->str()); + tok->deleteNext(); + } + } + + // Combine strings + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str()[0] != '"') + continue; + + tok->str(simplifyString(tok->str())); + while (tok->next() && tok->next()->str()[0] == '"') + { + tok->next()->str(simplifyString(tok->next()->str())); + + // Two strings after each other, combine them + tok->concatStr(tok->next()->str()); + tok->deleteNext(); + } + } + + // Convert e.g. atol("0") into 0 + simplifyMathFunctions(); + + // Convert + + into + and + - into - + for (Token *tok = _tokens; tok; tok = tok->next()) + { + while (tok->next()) + { + if (tok->str() == "+") + { + if (tok->next()->str() == "+") + { + tok->deleteNext(); + continue; + } + else if (tok->next()->str() == "-") + { + tok->str("-"); + tok->deleteNext(); + continue; + } + } + else if (tok->str() == "-") + { + if (tok->next()->str() == "-") + { + tok->str("+"); + tok->deleteNext(); + continue; + } + else if (tok->next()->str() == "+") + { + tok->deleteNext(); + continue; + } + } + + break; + } + } + + // 0[a] -> a[0] + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "%num% [ %var% ]")) + { + const std::string temp = tok->str(); + tok->str(tok->tokAt(2)->str()); + tok->tokAt(2)->str(temp); + } + } + + simplifySizeof(); + + // replace strlen(str) + simplifyKnownVariables(); + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "strlen ( %str% )")) + { + std::ostringstream ostr; + ostr << Token::getStrLength(tok->tokAt(2)); + tok->str(ostr.str()); + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + } + } + + // change array to pointer.. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "%type% %var% [ ] [,;=]")) + { + Token::eraseTokens(tok->next(), tok->tokAt(4)); + tok->insertToken("*"); + } + } + + // Replace constants.. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "const %type% %var% = %num% ;")) + { + unsigned int varId = tok->tokAt(2)->varId(); + if (varId == 0) + { + tok = tok->tokAt(5); + continue; + } + + const std::string num = tok->strAt(4); + int indent = 1; + for (Token *tok2 = tok->tokAt(6); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "{") + { + ++indent; + } + else if (tok2->str() == "}") + { + --indent; + if (indent == 0) + break; + } + + // Compare constants, but don't touch members of other structures + else if (tok2->varId() == varId) + { + tok2->str(num); + } + } + } + } + + simplifyCasts(); + + // Simplify simple calculations.. + simplifyCalculations(); + + // Replace "*(str + num)" => "str[num]" + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (! strchr(";{}(=<>", tok->str()[0])) + continue; + + Token *next = tok->next(); + if (! next) + break; + + if (Token::Match(next, "* ( %var% + %num% )") || + Token::Match(next, "* ( %var% + %var% )")) + { + // var + tok = tok->next(); + tok->str(tok->strAt(2)); + + // [ + tok = tok->next(); + tok->str("["); + + // num + tok = tok->next(); + tok->str(tok->strAt(2)); + + // ] + tok = tok->next(); + tok->str("]"); + + tok->deleteNext(); + tok->deleteNext(); + + Token::createMutualLinks(next->tokAt(1), next->tokAt(3)); + } + } + + // simplify "x=realloc(y,0);" => "free(y); x=0;".. + // and "x = realloc (0, n);" => "x = malloc(n);" + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "; %var% = realloc ( %var% , 0 ) ;")) + { + const std::string varname(tok->next()->str()); + const unsigned int varid(tok->next()->varId()); + + // Delete the "%var% =" + tok->deleteNext(); + tok->deleteNext(); + + // Change function name "realloc" to "free" + tok->next()->str("free"); + + // delete the ", 0" + Token::eraseTokens(tok->tokAt(3), tok->tokAt(6)); + + // goto the ";" + tok = tok->tokAt(5); + + // insert "var=0;" + tok->insertToken(";"); + tok->insertToken("0"); + tok->insertToken("="); + tok->insertToken(varname); + tok->next()->varId(varid); + } + else if (Token::Match(tok, "; %var% = realloc ( 0 , %num% ) ;")) + { + const std::string varname(tok->next()->str()); + + tok = tok->tokAt(3); + // Change function name "realloc" to "malloc" + tok->str("malloc"); + + // delete "0 ," + tok->next()->deleteNext(); + tok->next()->deleteNext(); + } + } + + // Change initialisation of variable to assignment + simplifyInitVar(); + + // Simplify variable declarations + simplifyVarDecl(); + + simplifyFunctionParameters(); + elseif(); + simplifyErrNoInWhile(); + simplifyIfAssign(); + simplifyRedundantParanthesis(); + simplifyIfNot(); + simplifyIfNotNull(); + simplifyIfSameInnerCondition(); + simplifyComparisonOrder(); + simplifyNestedStrcat(); + simplifyWhile0(); + simplifyFuncInWhile(); + + simplifyIfAssign(); // could be affected by simplifyIfNot + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "case %any% : %var%")) + tok->tokAt(2)->insertToken(";"); + if (Token::Match(tok, "default : %var%")) + tok->next()->insertToken(";"); + } + + // In case variable declarations have been updated... + setVarId(); + + bool modified = true; + while (modified) + { + modified = false; + modified |= simplifyConditions(); + modified |= simplifyFunctionReturn(); + modified |= simplifyKnownVariables(); + modified |= removeReduntantConditions(); + modified |= simplifyRedundantParanthesis(); + modified |= simplifyQuestionMark(); + modified |= simplifyCalculations(); + } + + // Remove redundant parentheses in return.. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + while (Token::simpleMatch(tok, "return (")) + { + Token *tok2 = tok->next()->link(); + if (Token::simpleMatch(tok2, ") ;")) + { + tok->deleteNext(); + tok2->deleteThis(); + } + else + { + break; + } + } + } + + removeRedundantAssignment(); + + simplifyComma(); + if (_settings->debug) + { + _tokens->printOut(0, _files); + } + + _tokens->assignProgressValues(); + + removeRedundantSemicolons(); + + return validate(); +} +//--------------------------------------------------------------------------- + +void Tokenizer::removeMacrosInGlobalScope() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "(") + { + tok = tok->link(); + if (Token::Match(tok, ") %type% {") && tok->strAt(1) != "const") + tok->deleteNext(); + } + + if (tok->str() == "{") + tok = tok->link(); + } +} +//--------------------------------------------------------------------------- + +void Tokenizer::removeRedundantAssignment() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "{") + tok = tok->link(); + + if (Token::Match(tok, ") const| {")) + { + // parse in this function.. + std::set localvars; + if (tok->next()->str() == "const") + tok = tok->next(); + const Token * const end = tok->next()->link(); + for (Token *tok2 = tok->next(); tok2 && tok2 != end; tok2 = tok2->next()) + { + if (Token::Match(tok2, "[;{}] %type% * %var% ;") && tok2->strAt(1) != "return") + { + tok2 = tok2->tokAt(3); + localvars.insert(tok2->varId()); + } + else if (Token::Match(tok2, "[;{}] %type% %var% ;") && tok2->next()->isStandardType()) + { + tok2 = tok2->tokAt(2); + localvars.insert(tok2->varId()); + } + else if (tok2->varId() && + !Token::Match(tok2->previous(), "[;{}] %var% = %var% ;") && + !Token::Match(tok2->previous(), "[;{}] %var% = %num% ;") && + !(Token::Match(tok2->previous(), "[;{}] %var% = %any% ;") && tok2->strAt(2)[0] == '\'')) + { + localvars.erase(tok2->varId()); + } + } + localvars.erase(0); + if (!localvars.empty()) + { + for (Token *tok2 = tok->next(); tok2 && tok2 != end; tok2 = tok2->next()) + { + if (Token::Match(tok2, "[;{}] %type% %var% ;") && localvars.find(tok2->tokAt(2)->varId()) != localvars.end()) + { + Token::eraseTokens(tok2, tok2->tokAt(3)); + } + else if (Token::Match(tok2, "[;{}] %type% * %var% ;") && localvars.find(tok2->tokAt(3)->varId()) != localvars.end()) + { + Token::eraseTokens(tok2, tok2->tokAt(4)); + } + else if (Token::Match(tok2, "[;{}] %var% = %any% ;") && localvars.find(tok2->next()->varId()) != localvars.end()) + { + Token::eraseTokens(tok2, tok2->tokAt(4)); + } + } + } + } + } +} + +bool Tokenizer::removeReduntantConditions() +{ + // Return value for function. Set to true if there are any simplifications + bool ret = false; + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() != "if") + continue; + + if (!Token::Match(tok->tokAt(1), "( %bool% ) {")) + continue; + + // Find matching else + const Token *elseTag = 0; + + // Find the closing "}" + elseTag = tok->tokAt(4)->link()->next(); + + bool boolValue = false; + if (tok->tokAt(2)->str() == "true") + boolValue = true; + + // Handle if with else + if (elseTag && elseTag->str() == "else") + { + if (Token::simpleMatch(elseTag->next(), "if (")) + { + // Handle "else if" + if (boolValue == false) + { + // Convert "if( false ) {aaa;} else if() {bbb;}" => "if() {bbb;}" + Token::eraseTokens(tok, elseTag->tokAt(2)); + ret = true; + } + else + { + // Keep first if, remove every else if and else after it + const Token *lastTagInIf = elseTag->tokAt(2); + while (lastTagInIf) + { + if (lastTagInIf->str() == "(") + { + lastTagInIf = lastTagInIf->link()->next(); + } + + lastTagInIf = lastTagInIf->link()->next(); + if (!Token::simpleMatch(lastTagInIf, "else")) + break; + + lastTagInIf = lastTagInIf->next(); + if (lastTagInIf->str() == "if") + lastTagInIf = lastTagInIf->next(); + } + + Token::eraseTokens(elseTag->previous(), lastTagInIf); + ret = true; + } + } + else + { + // Handle else + if (boolValue == false) + { + // Convert "if( false ) {aaa;} else {bbb;}" => "{bbb;}" or ";{bbb;}" + if (tok->previous()) + tok = tok->previous(); + else + tok->str(";"); + + Token::eraseTokens(tok, elseTag->tokAt(1)); + } + else + { + if (elseTag->tokAt(1)->str() == "{") + { + // Convert "if( true ) {aaa;} else {bbb;}" => "{aaa;}" + const Token *end = elseTag->tokAt(1)->link(); + + // Remove the "else { aaa; }" + Token::eraseTokens(elseTag->previous(), end->tokAt(1)); + } + + // Remove "if( true )" + if (tok->previous()) + tok = tok->previous(); + else + tok->str(";"); + + Token::eraseTokens(tok, tok->tokAt(5)); + } + + ret = true; + } + } + + // Handle if without else + else + { + if (boolValue == false) + { + // Remove if and its content + if (tok->previous()) + tok = tok->previous(); + else + tok->str(";"); + + Token::eraseTokens(tok, elseTag); + } + else + { + // convert "if( true ) {aaa;}" => "{aaa;}" + if (tok->previous()) + tok = tok->previous(); + else + tok->str(";"); + + Token::eraseTokens(tok, tok->tokAt(5)); + } + + ret = true; + } + } + + return ret; +} + + +void Tokenizer::removeRedundantSemicolons() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "(") + { + tok = tok->link(); + } + while (Token::simpleMatch(tok, "; ;")) + { + tok->deleteNext(); + } + } +} + + +void Tokenizer::simplifyIfAddBraces() +{ + for (Token *tok = _tokens; tok; tok = tok ? tok->next() : NULL) + { + if (tok->str() == "(") + { + tok = tok->link(); + continue; + } + + if (Token::Match(tok, "if|for|while (")) + { + // don't add "{}" around ";" in "do {} while();" (#609) + const Token *prev = tok->previous(); + if (Token::simpleMatch(prev, "} while") && + prev->link() && + prev->link()->previous() && + prev->link()->previous()->str() == "do") + { + continue; + } + + // Goto the ending ')' + tok = tok->next()->link(); + + // ')' should be followed by '{' + if (!tok || Token::simpleMatch(tok, ") {")) + continue; + } + + else if (tok->str() == "else") + { + // An else followed by an if or brace don't need to be processed further + if (Token::Match(tok, "else if|{")) + continue; + } + + else + { + continue; + } + + // If there is no code after he if(), abort + if (!tok->next()) + return; + + + // insert open brace.. + tok->insertToken("{"); + tok = tok->next(); + Token *tempToken = tok; + + bool innerIf = Token::simpleMatch(tempToken->next(), "if"); + + if (Token::simpleMatch(tempToken->next(), "do {")) + tempToken = tempToken->tokAt(2)->link(); + + // insert close brace.. + // In most cases it would work to just search for the next ';' and insert a closing brace after it. + // But here are special cases.. + // * if (cond) for (;;) break; + // * if (cond1) if (cond2) { } + // * if (cond1) if (cond2) ; else ; + while ((tempToken = tempToken->next()) != NULL) + { + if (tempToken->str() == "{") + { + if (Token::simpleMatch(tempToken->previous(),"else {")) + { + if (innerIf) + tempToken = tempToken->link(); + else + tempToken = tempToken->tokAt(-2); + break; + } + tempToken = tempToken->link(); + if (!tempToken || !tempToken->next()) + break; + if (tempToken->next()->isName() && tempToken->next()->str() != "else") + break; + continue; + } + + if (tempToken->str() == "(") + { + tempToken = tempToken->link(); + continue; + } + + if (tempToken->str() == "}") + { + // insert closing brace before this token + tempToken = tempToken->previous(); + break; + } + + if (tempToken->str() == ";") + { + if (!innerIf) + break; + + if (Token::simpleMatch(tempToken, "; else if")) + ; + else if (Token::simpleMatch(tempToken, "; else")) + innerIf = false; + else + break; + } + } + + if (tempToken) + { + tempToken->insertToken("}"); + Token::createMutualLinks(tok, tempToken->next()); + } + } +} + +bool Tokenizer::simplifyDoWhileAddBracesHelper(Token *tok) +{ + if (Token::Match(tok->next(), "[),]")) + { + // fix for #988 + return false; + } + + Token *tok1 = tok; // token with "do" + Token *tok2 = NULL; // token with "while" + Token *tok3 = tok->next(); + + // skip loop body + bool result = false; + while (tok3) + { + if (tok3->str() == "{") + { + // skip all tokens until "}" + tok3 = tok3->link(); + } + else if (tok3->str() == "while") + { + tok2 = tok3; + break; + } + else if (Token::simpleMatch(tok3, "do {")) + { + // Skip do{}while inside the current "do" + tok3 = tok3->next()->link(); + if (Token::simpleMatch(tok3->next(), "while")) + tok3 = tok3->next(); + } + else if (Token::Match(tok3, "do !!{") && + !Token::Match(tok3->next(), "[),]")) + { + // Handle do-while inside the current "do" + // first and return true to get the outer + // "do" to be handled later. + tok1 = tok3; + result = true; + } + + tok3 = tok3->next(); + } + + if (tok2) + { + // insert "{" after "do" + tok1->insertToken("{"); + + // insert "}" before "while" + tok2->previous()->insertToken("}"); + + Token::createMutualLinks(tok1->next(), tok2->previous()); + } + else + result = false; + + return result; +} + +void Tokenizer::simplifyDoWhileAddBraces() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "do !!{")) + { + while (simplifyDoWhileAddBracesHelper(tok)) + { + // Call until the function returns false to + // handle do-while inside do-while + + } + } + } +} + +void Tokenizer::simplifyCompoundAssignment() +{ + // Simplify compound assignments: + // "a+=b" => "a = a + b" + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "[;{}] (") || Token::Match(tok, "[;{}:] *| (| %var%")) + { + if (tok->str() == ":") + { + if (tok->strAt(-2) != "case") + continue; + } + + // backup current token.. + Token * const tok1 = tok; + + if (tok->strAt(1) == "*") + tok = tok->next(); + + if (tok->strAt(1) == "(") + { + tok = tok->next()->link()->next(); + } + else + { + // variable.. + tok = tok->tokAt(2); + while (Token::Match(tok, ". %var%") || + (tok && tok->str() == "[") || + Token::simpleMatch(tok, "( )")) + { + if (tok->str() != "[") + tok = tok->tokAt(2); + else if (tok->str() == "(") + tok = tok->tokAt(2); + else + { + // goto "]" + tok = tok->next(); + while (tok && !Token::Match(tok, "++|--|(|[|]")) + tok = tok->next(); + if (!tok) + break; + else if (tok->str() == "]") + tok = tok->next(); + else + break; + } + } + } + if (!tok) + break; + + // Is current token at a compound assignment: +=|-=|.. ? + const std::string &str = tok->str(); + std::string op; // operator used in assignment + if (str.size() == 2 && str[1] == '=' && str.find_first_of("+-*/%&|^")==0) + op = str.substr(0, 1); + else if (str=="<<=" || str==">>=") + op = str.substr(0, 2); + else + { + tok = tok1; + continue; + } + + // Remove the whole statement if it says: "+=0;", "-=0;", "*=1;" or "/=1;" + if (Token::Match(tok, "+=|-= 0 ;") || + Token::Match(tok, "+=|-= '\\0' ;") || + Token::simpleMatch(tok, "|= 0 ;") || + Token::Match(tok, "*=|/= 1 ;")) + { + tok = tok1; + while (tok->next()->str() != ";") + tok->deleteNext(); + } + else + { + // simplify the compound assignment.. + tok->str("="); + tok->insertToken(op); + std::stack tokend; + for (const Token *tok2 = tok->previous(); tok2 && tok2 != tok1; tok2 = tok2->previous()) + { + tok->insertToken(tok2->str()); + tok->next()->varId(tok2->varId()); + if (Token::Match(tok->next(), "]|)")) + tokend.push(tok->next()); + else if (Token::Match(tok->next(), "(|[")) + { + Token::createMutualLinks(tok->next(), tokend.top()); + tokend.pop(); + } + } + } + } + } +} + +void Tokenizer::simplifyConditionOperator() +{ + int parlevel = 0; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "(") + ++parlevel; + else if (tok->str() == ")") + --parlevel; + else if (parlevel == 0 && Token::Match(tok, "; %var% = %var% ? %var% : %var% ;")) + { + const std::string var(tok->strAt(1)); + const std::string condition(tok->strAt(3)); + const std::string value1(tok->strAt(5)); + const std::string value2(tok->strAt(7)); + + Token::eraseTokens(tok, tok->tokAt(9)); + + std::string str("if ( " + condition + " ) { " + var + " = " + value1 + " ; } else { " + var + " = " + value2 + " ; }"); + std::string::size_type pos1 = 0; + while (pos1 != std::string::npos) + { + std::string::size_type pos2 = str.find(" ", pos1); + if (pos2 == std::string::npos) + { + tok->insertToken(str.substr(pos1).c_str()); + pos1 = pos2; + } + else + { + tok->insertToken(str.substr(pos1, pos2 - pos1).c_str()); + pos1 = pos2 + 1; + } + tok = tok->next(); + } + + Token::createMutualLinks(tok->tokAt(-15), tok->tokAt(-13)); + Token::createMutualLinks(tok->tokAt(-12), tok->tokAt(-7)); + Token::createMutualLinks(tok->tokAt(-5), tok); + } + } +} + +bool Tokenizer::simplifyConditions() +{ + bool ret = false; + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "! %num%") || Token::Match(tok, "! %bool%")) + { + if (tok->next()->str() == "0" || tok->next()->str() == "false") + tok->str("true"); + else + tok->str("false"); + + tok->deleteNext(); + ret = true; + } + + if (Token::simpleMatch(tok, "( true &&") || + Token::simpleMatch(tok, "&& true &&") || + Token::simpleMatch(tok->next(), "&& true )")) + { + Token::eraseTokens(tok, tok->tokAt(3)); + ret = true; + } + + else if (Token::simpleMatch(tok, "( false ||") || + Token::simpleMatch(tok, "|| false ||") || + Token::simpleMatch(tok->next(), "|| false )")) + { + Token::eraseTokens(tok, tok->tokAt(3)); + ret = true; + } + + else if (Token::simpleMatch(tok, "( true ||") || + Token::simpleMatch(tok, "( false &&")) + { + Token::eraseTokens(tok->next(), tok->link()); + ret = true; + } + + else if (Token::simpleMatch(tok, "|| true )") || + Token::simpleMatch(tok, "&& false )")) + { + tok = tok->next(); + Token::eraseTokens(tok->next()->link(), tok); + ret = true; + } + + // Change numeric constant in condition to "true" or "false" + if (Token::Match(tok, "if|while ( %num%") && + (tok->tokAt(3)->str() == ")" || tok->tokAt(3)->str() == "||" || tok->tokAt(3)->str() == "&&")) + { + tok->tokAt(2)->str((tok->tokAt(2)->str() != "0") ? "true" : "false"); + ret = true; + } + Token *tok2 = tok->tokAt(2); + if (tok2 && + (tok->str() == "&&" || tok->str() == "||") && + Token::Match(tok->next(), "%num%") && + (tok2->str() == ")" || tok2->str() == "&&" || tok2->str() == "||")) + { + tok->next()->str((tok->next()->str() != "0") ? "true" : "false"); + ret = true; + } + + // Reduce "(%num% == %num%)" => "(true)"/"(false)" + const Token *tok4 = tok->tokAt(4); + if (! tok4) + break; + if ((tok->str() == "&&" || tok->str() == "||" || tok->str() == "(") && + (Token::Match(tok->tokAt(1), "%num% %any% %num%") || + Token::Match(tok->tokAt(1), "%bool% %any% %bool%")) && + (tok4->str() == "&&" || tok4->str() == "||" || tok4->str() == ")" || tok4->str() == "?")) + { + std::string cmp = tok->strAt(2); + bool result = false; + if (Token::Match(tok->tokAt(1), "%num%")) + { + // Compare numbers + + if (cmp == "==" || cmp == "!=") + { + const std::string op1(tok->strAt(1)); + const std::string op2(tok->strAt(3)); + + bool eq = false; + if (MathLib::isInt(op1) && MathLib::isInt(op2)) + eq = (MathLib::toLongNumber(op1) == MathLib::toLongNumber(op2)); + else + eq = (op1 == op2); + + if (cmp == "==") + result = eq; + else + result = !eq; + } + else + { + double op1 = MathLib::toDoubleNumber(tok->strAt(1)); + double op2 = MathLib::toDoubleNumber(tok->strAt(3)); + if (cmp == ">=") + result = (op1 >= op2); + else if (cmp == ">") + result = (op1 > op2); + else if (cmp == "<=") + result = (op1 <= op2); + else if (cmp == "<") + result = (op1 < op2); + else + cmp = ""; + } + } + else + { + // Compare boolean + bool op1 = (tok->strAt(1) == std::string("true")); + bool op2 = (tok->strAt(3) == std::string("true")); + + if (cmp == "==") + result = (op1 == op2); + else if (cmp == "!=") + result = (op1 != op2); + else if (cmp == ">=") + result = (op1 >= op2); + else if (cmp == ">") + result = (op1 > op2); + else if (cmp == "<=") + result = (op1 <= op2); + else if (cmp == "<") + result = (op1 < op2); + else + cmp = ""; + } + + if (! cmp.empty()) + { + tok = tok->next(); + tok->deleteNext(); + tok->deleteNext(); + + tok->str(result ? "true" : "false"); + ret = true; + } + } + } + + return ret; +} + +bool Tokenizer::simplifyQuestionMark() +{ + bool ret = false; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() != "?") + continue; + + if (!tok->tokAt(-2)) + continue; + + if (!Token::Match(tok->tokAt(-2), "[=,(]")) + continue; + + if (!Token::Match(tok->previous(), "%bool%") && + !Token::Match(tok->previous(), "%num%")) + continue; + + // Find the ":" token.. + Token *semicolon = 0; + { + unsigned int parlevel = 0; + for (Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (tok2->str() == "(") + ++parlevel; + else if (tok2->str() == ")") + { + if (parlevel == 0) + break; + --parlevel; + } + else if (parlevel == 0 && tok2->str() == ":") + { + semicolon = tok2; + break; + } + } + } + if (!semicolon || !semicolon->next()) + continue; + + if (tok->previous()->str() == "false" || + tok->previous()->str() == "0") + { + // Use code after semicolon, remove code before it. + semicolon = semicolon->next(); + tok = tok->tokAt(-2); + Token::eraseTokens(tok, semicolon); + + tok = tok->next(); + ret = true; + } + + // The condition is true. Delete the operator after the ":".. + else + { + const Token *end = 0; + + // check the operator after the : + if (Token::simpleMatch(semicolon, ": (")) + { + end = semicolon->next()->link(); + if (!Token::Match(end, ") !!.")) + continue; + } + + // delete the condition token and the "?" + tok = tok->tokAt(-2); + Token::eraseTokens(tok, tok->tokAt(3)); + + // delete operator after the : + if (end) + { + Token::eraseTokens(semicolon->previous(), end->next()); + continue; + } + + int ind = 0; + for (const Token *endTok = semicolon; endTok; endTok = endTok->next()) + { + if (endTok->str() == ";") + { + Token::eraseTokens(semicolon->previous(), endTok); + ret = true; + break; + } + + else if (Token::Match(endTok, "[({[]")) + { + ++ind; + } + + else if (Token::Match(endTok, "[)}]]")) + { + --ind; + if (ind < 0) + { + Token::eraseTokens(semicolon->previous(), endTok); + ret = true; + break; + } + } + } + } + } + + return ret; +} + +void Tokenizer::simplifyCasts() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + while (Token::Match(tok->next(), "( %type% *| ) *|&| %var%") || + Token::Match(tok->next(), "( %type% %type% *| ) *|&| %var%") || + (!tok->isName() && (Token::Match(tok->next(), "( %type% * ) (") || + Token::Match(tok->next(), "( %type% %type% * ) (")))) + { + if (tok->isName() && tok->str() != "return") + break; + + if (Token::simpleMatch(tok->previous(), "operator")) + break; + + // Remove cast.. + Token::eraseTokens(tok, tok->next()->link()->next()); + + if (tok->str() == ")" && tok->link()->previous()) + { + // If there was another cast before this, go back + // there to check it also. e.g. "(int)(char)x" + tok = tok->link()->previous(); + } + } + + // Replace pointer casts of 0.. "(char *)0" => "0" + while (Token::Match(tok->next(), "( %type% * ) 0") || + Token::Match(tok->next(), "( %type% %type% * ) 0")) + { + Token::eraseTokens(tok, tok->next()->link()->next()); + if (tok->str() == ")" && tok->link()->previous()) + { + // If there was another cast before this, go back + // there to check it also. e.g. "(char*)(char*)0" + tok = tok->link()->previous(); + } + } + + while (Token::Match(tok->next(), "dynamic_cast|reinterpret_cast|const_cast|static_cast <")) + { + Token *tok2 = tok->next(); + unsigned int level = 0; + while (tok2) + { + if (tok2->str() == "<") + ++level; + else if (tok2->str() == ">") + { + --level; + if (level == 0) + break; + } + tok2 = tok2->next(); + } + + if (Token::simpleMatch(tok2, "> (")) + { + Token *closeBracket = tok2->next()->link(); + if (closeBracket) + { + Token::eraseTokens(tok, tok2->tokAt(2)); + closeBracket->deleteThis(); + } + else + { + break; + } + } + else + { + break; + } + } + } +} + + +void Tokenizer::simplifyFunctionParameters() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "{" || tok->str() == "[" || tok->str() == "(") + { + tok = tok->link(); + if (!tok) + break; + continue; + } + + // Find the function e.g. foo( x ) or foo( x, y ) + if (Token::Match(tok, "%var% ( %var% [,)]")) + { + // We have found old style function, now we need to change it + + // backup pointer to the '(' token + Token * const tok1 = tok->next(); + + // Get list of argument names + std::map argumentNames; + bool bailOut = false; + for (tok = tok->tokAt(2); tok; tok = tok->tokAt(2)) + { + if (!Token::Match(tok, "%var% [,)]")) + { + bailOut = true; + break; + } + + if (argumentNames.find(tok->str()) != argumentNames.end()) + { + // Invalid code, two arguments with the same name. + // TODO, print error perhaps? + bailOut = true; + break; + } + + argumentNames[tok->str()] = tok; + if (tok->next()->str() == ")") + { + tok = tok->tokAt(2); + break; + } + } + + if (bailOut) + { + tok = tok1->link(); + if (!tok) + return; + continue; + } + + Token *start = tok; + while (tok && tok->str() != "{") + { + if (tok->str() == ";") + { + tok = tok->previous(); + // Move tokens from start to tok into the place of + // argumentNames[tok->str()] and remove the ";" + + if (argumentNames.find(tok->str()) == argumentNames.end()) + { + bailOut = true; + break; + } + + // Remove the following ";" + Token *temp = tok->tokAt(2); + tok->deleteNext(); + + // Replace "x" with "int x" or similar + Token::replace(argumentNames[tok->str()], start, tok); + argumentNames.erase(tok->str()); + tok = temp; + start = tok; + } + else + { + tok = tok->next(); + } + } + + if (Token::simpleMatch(tok, "{")) + tok = tok->link(); + + if (tok == NULL) + { + break; + } + + if (bailOut) + { + continue; + } + } + } +} + + +void Tokenizer:: simplifyFunctionPointers() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + // check for function pointer cast + if (Token::Match(tok, "( %type% *| *| ( * ) (") || + Token::Match(tok, "( %type% %type% *| *| ( * ) (") || + Token::Match(tok, "static_cast < %type% *| *| ( * ) (") || + Token::Match(tok, "static_cast < %type% %type% *| *| ( * ) (")) + { + Token *tok1 = tok; + + if (tok1->str() == "static_cast") + tok1 = tok1->next(); + + tok1 = tok1->next(); + + if (Token::Match(tok1->next(), "%type%")) + tok1 = tok1->next(); + + while (tok1->next()->str() == "*") + tok1 = tok1->next(); + + // check that the cast ends + if (!Token::Match(tok1->tokAt(4)->link(), ") )|>")) + continue; + + // ok simplify this function pointer cast to an ordinary pointer cast + tok1->deleteNext(); + tok1->next()->deleteNext(); + const Token *tok2 = tok1->tokAt(2)->link(); + Token::eraseTokens(tok1->next(), tok2 ? tok2->next() : 0); + continue; + } + + // check for start of statement + else if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|(|public:|protected:|private:")) + continue; + + if (Token::Match(tok, "%type% *| *| ( * %var% ) (")) + ; + else if (Token::Match(tok, "%type% %type% *| *| ( * %var% ) (")) + tok = tok->next(); + else + continue; + + while (tok->next()->str() == "*") + tok = tok->next(); + + // check that the declaration ends + if (!Token::Match(tok->tokAt(5)->link(), ") ;|,|)|=")) + continue; + + // ok simplify this function pointer to an ordinary pointer + tok->deleteNext(); + tok->tokAt(2)->deleteNext(); + const Token *tok2 = tok->tokAt(3)->link(); + Token::eraseTokens(tok->tokAt(2), tok2 ? tok2->next() : 0); + } +} + + +bool Tokenizer::simplifyFunctionReturn() +{ + bool ret = false; + int indentlevel = 0; + for (const Token *tok = tokens(); tok; tok = tok->next()) + { + if (tok->str() == "{") + ++indentlevel; + + else if (tok->str() == "}") + --indentlevel; + + else if (indentlevel == 0 && Token::Match(tok, "%var% ( ) { return %num% ; }") && tok->str() != ")") + { + std::ostringstream pattern; + pattern << "[(=+-*/] " << tok->str() << " ( ) [;)+-*/]"; + for (Token *tok2 = _tokens; tok2; tok2 = tok2->next()) + { + if (Token::Match(tok2, pattern.str().c_str())) + { + tok2 = tok2->next(); + tok2->str(tok->strAt(5)); + tok2->deleteNext(); + tok2->deleteNext(); + ret = true; + } + } + } + } + + return ret; +} + + +static void incdec(std::string &value, const std::string &op) +{ + int ivalue = 0; + std::istringstream istr(value.c_str()); + istr >> ivalue; + if (op == "++") + ++ivalue; + else if (op == "--") + --ivalue; + std::ostringstream ostr; + ostr << ivalue; + value = ostr.str(); +} + + + +void Tokenizer::simplifyVarDecl() +{ + // Split up variable declarations.. + // "int a=4;" => "int a; a=4;" + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::simpleMatch(tok, "= {")) + { + tok = tok->next()->link(); + if (!tok) + break; + } + + if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|)|public:|protected:|private:")) + continue; + + Token *type0 = tok; + if (!Token::Match(type0, "%type%")) + continue; + if (Token::Match(type0, "else|return|public:|protected:|private:")) + continue; + + bool isconst = false; + bool isstatic = false; + Token *tok2 = type0; + unsigned int typelen = 1; + + while (Token::Match(tok2, "%type% %type% *| *| %var%")) + { + if (tok2->str() == "const") + isconst = true; + + else if (tok2->str() == "static") + isstatic = true; + + tok2 = tok2->next(); + ++typelen; + } + + // Don't split up const declaration.. + if (isconst && Token::Match(tok2, "%type% %var% =")) + continue; + + // strange looking variable declaration => don't split up. + if (Token::Match(tok2, "%type% *| %var% , %type% *| %var%")) + continue; + + if (Token::Match(tok2, "%type% *| %var% ,|=")) + { + const bool isPointer = (tok2->next()->str() == "*"); + const Token *varName = tok2->tokAt((isPointer ? 2 : 1)); + Token *endDeclaration = varName->next(); + + if (varName->str() != "operator") + { + tok2 = endDeclaration; // The ',' or '=' token + + if (isstatic && tok2->str() == "=") + { + if (Token::Match(tok2->next(), "%num% ,")) + tok2 = tok2->tokAt(2); + else + tok2 = NULL; + } + } + else + tok2 = NULL; + } + + else if (Token::Match(tok2, "%type% * * %var% ,|=")) + { + if (tok2->tokAt(3)->str() != "operator") + tok2 = tok2->tokAt(4); // The ',' token + else + tok2 = NULL; + } + + else if (Token::Match(tok2, "%type% * const %var% ,|=")) + { + if (tok2->tokAt(3)->str() != "operator") + { + tok2 = tok2->tokAt(4); // The ',' token + } + else + { + tok2 = NULL; + } + } + + else if (Token::Match(tok2, "%type% %var% [ %num% ] ,|=|[") || + Token::Match(tok2, "%type% %var% [ %var% ] ,|=|[")) + { + tok2 = tok2->tokAt(5); // The ',' token + while (Token::Match(tok2, "[ %num% ]") || Token::Match(tok2, "[ %var% ]")) + tok2 = tok2->tokAt(3); + if (!Token::Match(tok2, "=|,")) + { + tok2 = NULL; + } + + if (tok2 && tok2->str() == "=") + { + while (tok2 && tok2->str() != ",") + { + if (tok2->str() == "{") + tok2 = tok2->link(); + + tok2 = tok2->next(); + + if (tok2->str() == ";") + tok2 = NULL; + } + } + } + + else if (Token::Match(tok2, "%type% * %var% [ %num% ] ,") || + Token::Match(tok2, "%type% * %var% [ %var% ] ,")) + { + tok2 = tok2->tokAt(6); // The ',' token + } + + else if (Token::Match(tok2, "std :: %type% <") || Token::Match(tok2, "%type% <")) + { + // + // Deal with templates and standart types + // + if (Token::simpleMatch(tok2, "std ::")) + { + typelen += 2; + tok2 = tok2->tokAt(2); + } + + typelen += 2; + tok2 = tok2->tokAt(2); + size_t indentlevel = 1; + + for (Token *tok3 = tok2; tok3; tok3 = tok3->next()) + { + ++typelen; + + if (tok3->str() == "<") + { + ++indentlevel; + } + else if (tok3->str() == ">") + { + --indentlevel; + if (indentlevel == 0) + { + tok2 = tok3->next(); + break; + } + } + else if (tok3->str() == ";") + { + break; + } + } + + if (!tok2) + break; + + if (Token::Match(tok2, ":: %type%")) + { + typelen += 2; + tok2 = tok2->tokAt(2); + } + + if (tok2->str() == "*" || tok2->str() == "&") + { + tok2 = tok2->next(); + } + + if (Token::Match(tok2, "%var% ,")) + { + tok2 = tok2->next(); // The ',' token + typelen--; + } + else + { + tok2 = NULL; + typelen = 0; + } + } + else + { + tok2 = NULL; + typelen = 0; + } + + + if (tok2) + { + if (tok2->str() == ",") + { + tok2->str(";"); + insertTokens(tok2, type0, typelen); + std::stack link1; + std::stack link2; + while (((typelen--) > 0) && (0 != (tok2 = tok2->next()))) + { + if (tok2->str() == "(") + link1.push(tok2); + else if (tok2->str() == ")" && !link1.empty()) + { + Token::createMutualLinks(tok2, link1.top()); + link1.pop(); + } + + else if (tok2->str() == "[") + link2.push(tok2); + else if (tok2->str() == "]" && !link2.empty()) + { + Token::createMutualLinks(tok2, link2.top()); + link2.pop(); + } + } + } + + else + { + Token *eq = tok2; + + unsigned int level = 0; + while (tok2) + { + if (Token::Match(tok2, "[{(]")) + tok2 = tok2->link(); + + else if (tok2->str() == "<") + { + if (tok2->previous()->isName() && !tok2->previous()->varId()) + ++level; + } + + else if (level > 0 && tok2->str() == ">") + --level; + + else if (level == 0 && strchr(";,", tok2->str()[0])) + { + // "type var =" => "type var; var =" + Token *VarTok = type0->tokAt((int)typelen); + while (Token::Match(VarTok, "*|const")) + VarTok = VarTok->next(); + insertTokens(eq, VarTok, 2); + eq->str(";"); + + // "= x, " => "= x; type " + if (tok2->str() == ",") + { + tok2->str(";"); + insertTokens(tok2, type0, typelen); + } + break; + } + + tok2 = tok2->next(); + } + } + } + } +} + +void Tokenizer::simplifyStdType() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + // long unsigned => unsigned long + if (Token::Match(tok, "char|short|int|long|__int8|__int16|__int32|__int64 unsigned|signed")) + { + std::string temp = tok->str(); + tok->str(tok->next()->str()); + tok->next()->str(temp); + } + + if (!Token::Match(tok, "unsigned|signed|char|short|int|long|__int8|__int16|__int32|__int64")) + continue; + + // check if signed or unsigned specified + if (Token::Match(tok, "unsigned|signed")) + { + bool isUnsigned = tok->str() == "unsigned"; + + // unsigned i => unsigned int i + if (!Token::Match(tok->next(), "char|short|int|long|__int8|__int16|__int32|__int64")) + tok->str("int"); + else + tok->deleteThis(); + tok->isUnsigned(isUnsigned); + tok->isSigned(!isUnsigned); + } + + if (Token::simpleMatch(tok, "__int8")) + tok->str("char"); + else if (Token::simpleMatch(tok, "__int16")) + tok->str("short"); + else if (Token::simpleMatch(tok, "__int32")) + tok->str("int"); + else if (Token::simpleMatch(tok, "__int64")) + { + tok->str("long"); + tok->isLong(true); + } + else if (Token::simpleMatch(tok, "long")) + { + if (Token::simpleMatch(tok->next(), "long")) + { + tok->isLong(true); + tok->deleteNext(); + } + + if (Token::simpleMatch(tok->next(), "int")) + tok->deleteNext(); + else if (Token::simpleMatch(tok->next(), "double")) + { + tok->str("double"); + tok->isLong(true); + tok->deleteNext(); + } + } + else if (Token::simpleMatch(tok, "short")) + { + if (Token::simpleMatch(tok->next(), "int")) + tok->deleteNext(); + } + } +} + +void Tokenizer::simplifyIfAssign() +{ + // See also simplifyFunctionAssign + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (!Token::Match(tok->next(), "if|while ( !| (| %var% =") && + !Token::Match(tok->next(), "if|while ( !| (| %var% . %var% =")) + continue; + + // simplifying a "while" condition ? + const bool iswhile(tok->next()->str() == "while"); + + // delete the "if" + tok->deleteNext(); + + // Remember if there is a "!" or not. And delete it if there are. + const bool isNot(tok->tokAt(2)->str() == "!"); + if (isNot) + tok->next()->deleteNext(); + + // Delete parenthesis.. and remember how many there are with + // their links. + std::stack braces; + while (tok->next()->str() == "(") + { + braces.push(tok->next()->link()); + tok->deleteNext(); + } + + // Skip the "%var% = ..." + Token *tok2; + unsigned int indentlevel = 0; + for (tok2 = tok->next(); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "(") + ++indentlevel; + else if (tok2->str() == ")") + { + if (indentlevel <= 0) + break; + --indentlevel; + } + } + + // Insert "; if|while ( .." + tok2 = tok2->previous(); + if (Token::simpleMatch(tok->tokAt(2), ".")) + { + tok2->insertToken(tok->strAt(3)); + tok2->insertToken(tok->strAt(2)); + } + tok2->insertToken(tok->strAt(1)); + tok2->next()->varId(tok->tokAt(1)->varId()); + + while (! braces.empty()) + { + tok2->insertToken("("); + Token::createMutualLinks(tok2->next(), braces.top()); + braces.pop(); + } + + if (isNot) + tok2->next()->insertToken("!"); + tok2->insertToken(iswhile ? "while" : "if"); + tok2->insertToken(";"); + + // If it's a while loop.. insert the assignment in the loop + if (iswhile) + { + indentlevel = 0; + Token *tok3 = tok2; + for (tok3 = tok2; tok3; tok3 = tok3->next()) + { + if (tok3->str() == "{") + ++indentlevel; + else if (tok3->str() == "}") + { + if (indentlevel <= 1) + break; + --indentlevel; + } + } + + if (tok3 && indentlevel == 1) + { + tok3 = tok3->previous(); + std::stack braces2; + + for (tok2 = tok2->next(); tok2 && tok2 != tok; tok2 = tok2->previous()) + { + tok3->insertToken(tok2->str()); + + Token *newTok = tok3->next(); + newTok->fileIndex(tok2->fileIndex()); + newTok->linenr(tok2->linenr()); + + // link() newly tokens manually + if (Token::Match(newTok, "}|)|]")) + { + braces2.push(newTok); + } + else if (Token::Match(newTok, "{|(|[")) + { + Token::createMutualLinks(newTok, braces2.top()); + braces2.pop(); + } + } + } + } + } +} + + +void Tokenizer::simplifyVariableMultipleAssign() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "%var% = %var% = %num% ;") || + Token::Match(tok, "%var% = %var% = %var% ;")) + { + + // skip intermediate assignments + Token *tok2 = tok->previous(); + while (tok2 && + tok2->str() == "=" && + Token::Match(tok2->previous(), "%var%")) + { + tok2 = tok2->tokAt(-2); + } + + if (tok2->str() != ";") + { + continue; + } + + Token *stopAt = tok->tokAt(2); + const Token *valueTok = tok->tokAt(4); + const std::string value(valueTok->str()); + tok2 = tok2->next(); + + while (tok2 != stopAt) + { + tok2->next()->insertToken(";"); + tok2->next()->insertToken(value); + tok2 = tok2->tokAt(4); + } + } + } +} + + +void Tokenizer::simplifyIfNot() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "(" || tok->str() == "||" || tok->str() == "&&") + { + tok = tok->next(); + while (tok && tok->str() == "(") + tok = tok->next(); + + if (!tok) + break; + + if (Token::Match(tok, "0|false == (") || + Token::Match(tok, "0|false == %var%")) + { + tok->deleteNext(); + tok->str("!"); + } + + else if (Token::Match(tok, "%var% == 0|false")) + { + tok->deleteNext(); + tok->next()->str(tok->str()); + tok->str("!"); + } + + else if (Token::Match(tok, "%var% .|:: %var% == 0|false")) + { + tok = tok->previous(); + tok->insertToken("!"); + tok = tok->tokAt(4); + Token::eraseTokens(tok, tok->tokAt(3)); + } + + else if (Token::Match(tok, "* %var% == 0|false")) + { + tok = tok->previous(); + tok->insertToken("!"); + tok = tok->tokAt(3); + Token::eraseTokens(tok, tok->tokAt(3)); + } + } + + else if (tok->link() && Token::Match(tok, ") == 0|false")) + { + Token::eraseTokens(tok, tok->tokAt(3)); + if (Token::Match(tok->link()->previous(), "%var%")) + { + // if( foo(x) == 0 ) + tok->link()->previous()->insertToken(tok->link()->previous()->str().c_str()); + tok->link()->previous()->previous()->str("!"); + } + else + { + // if( (x) == 0 ) + tok->link()->insertToken("("); + tok->link()->str("!"); + Token *temp = tok->link(); + Token::createMutualLinks(tok->link()->next(), tok); + temp->link(0); + } + } + } +} + + +void Tokenizer::simplifyIfNotNull() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + Token *deleteFrom = NULL; + + if (tok->str() == "(" || tok->str() == "||" || tok->str() == "&&") + { + tok = tok->next(); + + if (!tok) + break; + + if (Token::simpleMatch(tok, "0 != (") || + Token::Match(tok, "0 != %var%")) + { + deleteFrom = tok->previous(); + } + + else if (Token::Match(tok, "%var% != 0")) + { + deleteFrom = tok; + } + + else if (Token::Match(tok, "%var% .|:: %var% != 0")) + { + tok = tok->tokAt(2); + deleteFrom = tok; + } + } + + else if (tok->link() && Token::simpleMatch(tok, ") != 0")) + { + deleteFrom = tok; + } + + if (deleteFrom) + { + Token::eraseTokens(deleteFrom, deleteFrom->tokAt(3)); + tok = deleteFrom; + } + } +} + + +void Tokenizer::simplifyIfSameInnerCondition() +{ + // same inner condition + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "if ( %var% ) {")) + { + const unsigned int varid(tok->tokAt(2)->varId()); + if (!varid) + continue; + + for (Token *tok2 = tok->tokAt(5); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "{" || tok2->str() == "}") + break; + if (Token::simpleMatch(tok2, "if (")) + { + tok2 = tok2->tokAt(2); + if (Token::Match(tok2, "%varid% )", varid)) + tok2->str("true"); + else if (Token::Match(tok2, "! %varid% )", varid)) + tok2->next()->varId(varid); + break; + } + } + } + } +} + + +bool Tokenizer::simplifyLogicalOperators() +{ + bool ret = false; + + // "if (not p)" => "if (!p)" + // "if (p and q)" => "if (p && q)" + // "if (p or q)" => "if (p || q)" + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "if|while ( not|compl %var%")) + { + tok->tokAt(2)->str(tok->strAt(2) == "not" ? "!" : "~"); + ret = true; + } + else if (Token::Match(tok, "&& not|compl %var%")) + { + tok->next()->str(tok->strAt(1) == "not" ? "!" : "~"); + ret = true; + } + else if (Token::Match(tok, "|| not|compl %var%")) + { + tok->next()->str(tok->strAt(1) == "not" ? "!" : "~"); + ret = true; + } + // "%var%|) and %var%|(" + else if (Token::Match(tok->previous(), "%any% %var% %any%")) + { + if (!Token::Match(tok, "and|or|bitand|bitor|xor|not_eq")) + continue; + + const Token *tok2 = tok; + while (0 != (tok2 = tok2->previous())) + { + if (tok2->str() == ")") + tok2 = tok2->link(); + else if (Token::Match(tok2, "(|;|{|}")) + break; + } + if (tok2 && Token::Match(tok2->previous(), "if|while (")) + { + if (tok->str() == "and") + tok->str("&&"); + else if (tok->str() == "or") + tok->str("||"); + else if (tok->str() == "bitand") + tok->str("&"); + else if (tok->str() == "bitor") + tok->str("|"); + else if (tok->str() == "xor") + tok->str("^"); + else if (tok->str() == "not_eq") + tok->str("!="); + ret = true; + } + } + } + return ret; +} + +// int i(0); => int i; i = 0; +// int i(0), j; => int i; i = 0; int j; +void Tokenizer::simplifyInitVar() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (!tok->isName() || (tok->previous() && !Token::Match(tok->previous(), "[;{}]"))) + continue; + + if (Token::Match(tok, "class|struct|union| %type% *| %var% ( &| %any% ) ;") || + Token::Match(tok, "%type% *| %var% ( %type% (")) + { + tok = initVar(tok); + } + else if (Token::Match(tok, "class|struct|union| %type% *| %var% ( &| %any% ) ,")) + { + Token *tok1 = tok; + while (tok1->str() != ",") + tok1 = tok1->next(); + tok1->str(";"); + Token *tok2 = tok; + if (Token::Match(tok2, "class|struct|union")) + { + tok1->insertToken(tok2->str()); + tok1 = tok1->next(); + tok2 = tok2->next(); + } + tok1->insertToken(tok2->str()); + tok1 = tok1->next(); + tok2 = tok2->next(); + if (tok2->str() == "*") + { + tok1->insertToken("*"); + } + tok = initVar(tok); + } + } +} + +static bool isOp(const Token *tok) +{ + return bool(tok && + (tok->str() == "&&" || + tok->str() == "||" || + tok->str() == "==" || + tok->str() == "!=" || + tok->str() == "<" || + tok->str() == "<=" || + tok->str() == ">" || + tok->str() == ">=" || + tok->str() == "<<" || + tok->str() == ">>" || + Token::Match(tok, "[;+-*/%&|^]"))); +} + +Token * Tokenizer::initVar(Token * tok) +{ + // call constructor of class => no simplification + if (Token::Match(tok, "class|struct|union")) + { + if (tok->tokAt(2)->str() != "*") + return tok; + + tok = tok->next(); + } + else if (!tok->isStandardType() && tok->tokAt(1)->str() != "*") + return tok; + + // goto variable name.. + tok = tok->next(); + if (tok->str() == "*") + tok = tok->next(); + + // sizeof is not a variable name.. + if (tok->str() == "sizeof") + return tok; + + // check initializer.. + if (tok->tokAt(2)->isStandardType() || tok->tokAt(2)->str() == "void") + return tok; + else if (!tok->tokAt(2)->isNumber() && !Token::Match(tok->tokAt(2), "%type% (") && tok->tokAt(2)->str() != "&" && tok->tokAt(2)->varId() == 0) + return tok; + + // insert '; var =' + tok->insertToken(";"); + tok->next()->insertToken(tok->str()); + tok->tokAt(2)->varId(tok->varId()); + tok = tok->tokAt(2); + tok->insertToken("="); + + // goto '('.. + tok = tok->tokAt(2); + + // delete ')' + tok->link()->deleteThis(); + + // delete this + tok->deleteThis(); + + return tok; +} + + +bool Tokenizer::simplifyKnownVariables() +{ + // return value for function. Set to true if any simplifications are made + bool ret = false; + + // constants.. + { + std::map constantValues; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "static| const static| %type% %var% = %any% ;")) + { + Token *tok1 = tok; + + // start of statement + if (tok != _tokens && !Token::Match(tok->previous(),"[;{}]")) + continue; + // skip "const" and "static" + while (tok->str() == "const" || tok->str() == "static") + tok = tok->next(); + // pod type + if (!tok->isStandardType()) + continue; + + const Token * const vartok = tok->next(); + const Token * const valuetok = tok->tokAt(3); + if (valuetok->isNumber() || Token::Match(valuetok, "%str% ;")) + { + constantValues[vartok->varId()] = valuetok->str(); + + // remove statement + while (tok1->str() != ";") + tok1->deleteThis(); + tok = tok1; + } + } + + else if (tok->varId() && constantValues.find(tok->varId()) != constantValues.end()) + { + tok->str(constantValues[tok->varId()]); + } + } + } + + // variable id for float/double variables + std::set floatvars; + + // auto variables.. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + // Search for a block of code + if (! Token::Match(tok, ") const| {")) + continue; + + // parse the block of code.. + int indentlevel = 0; + Token *tok2 = tok; + for (; tok2; tok2 = tok2->next()) + { + if (Token::Match(tok2, "[;{}] float|double %var% ;")) + { + floatvars.insert(tok2->tokAt(2)->varId()); + } + + if (tok2->str() == "{") + ++indentlevel; + + else if (tok2->str() == "}") + { + --indentlevel; + if (indentlevel <= 0) + break; + } + + else if (tok2->previous()->str() != "*" && + (Token::Match(tok2, "%var% = %num% ;") || + Token::Match(tok2, "%var% = %str% ;") || + (Token::Match(tok2, "%var% = %any% ;") && tok2->strAt(2)[0] == '\'') || + Token::Match(tok2, "%var% [ ] = %str% ;") || + Token::Match(tok2, "%var% [ %num% ] = %str% ;") || + Token::Match(tok2, "%var% = %bool% ;") || + Token::Match(tok2, "%var% = %var% ;") || + Token::Match(tok2, "%var% = & %var% ;") || + Token::Match(tok2, "%var% = & %var% [ 0 ] ;"))) + { + const unsigned int varid = tok2->varId(); + if (varid == 0) + continue; + + // skip loop variable + if (Token::Match(tok2->tokAt(-2), "(|:: %type%")) + { + const Token *tok3 = tok2->previous(); + while (Token::Match(tok3->previous(), ":: %type%")) + tok3 = tok3->tokAt(-2); + if (Token::Match(tok3->tokAt(-2), "for ( %type%")) + continue; + } + + // struct name.. + const std::string structname = Token::Match(tok2->tokAt(-3), "[;{}] %var% .") ? + std::string(tok2->strAt(-2) + " .") : + std::string(""); + + if (tok2->str() == tok2->strAt(2)) + continue; + + const Token * const valueToken = tok2->tokAt(2); + + std::string value; + unsigned int valueVarId = 0; + + Token *tok3 = NULL; + bool valueIsPointer = false; + + if (!simplifyKnownVariablesGetData(varid, &tok2, &tok3, value, valueVarId, valueIsPointer, floatvars.find(tok2->varId()) != floatvars.end())) + continue; + + ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, valueToken, indentlevel); + } + + else if (Token::Match(tok2, "strcpy ( %var% , %str% ) ;")) + { + const unsigned int varid(tok2->tokAt(2)->varId()); + if (varid == 0) + continue; + const std::string structname(""); + const Token * const valueToken = tok2->tokAt(4); + std::string value(valueToken->str()); + const unsigned int valueVarId(0); + const bool valueIsPointer(false); + Token *tok3 = tok2; + for (int i = 0; i < 6; ++i) + tok3 = tok3->next(); + ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, valueToken, indentlevel); + } + } + + if (tok2) + tok = tok2->previous(); + } + + return ret; +} + +bool Tokenizer::simplifyKnownVariablesGetData(unsigned int varid, Token **_tok2, Token **_tok3, std::string &value, unsigned int &valueVarId, bool &valueIsPointer, bool floatvar) +{ + Token *tok2 = *_tok2; + Token *tok3 = *_tok3; + + if (Token::Match(tok2->tokAt(-2), "for ( %varid% = %num% ; %varid% <|<= %num% ; ++| %varid% ++| ) {", varid)) + { + // is there a "break" in the for loop? + bool hasbreak = false; + unsigned int indentlevel4 = 0; // indentlevel for tok4 + for (const Token *tok4 = tok2->previous()->link(); tok4; tok4 = tok4->next()) + { + if (tok4->str() == "{") + ++indentlevel4; + else if (tok4->str() == "}") + { + if (indentlevel4 <= 1) + break; + --indentlevel4; + } + else if (tok4->str() == "break") + { + hasbreak = true; + break; + } + } + if (hasbreak) + return false; + + // no break => the value of the counter value is known after the for loop.. + const std::string compareop = tok2->strAt(5); + if (compareop == "<") + { + value = tok2->strAt(6); + valueVarId = tok2->tokAt(6)->varId(); + } + else + value = MathLib::toString(MathLib::toLongNumber(tok2->strAt(6)) + 1); + + // Skip for-body.. + tok3 = tok2->previous()->link()->next()->link()->next(); + } + else + { + value = tok2->strAt(2); + valueVarId = tok2->tokAt(2)->varId(); + if (Token::simpleMatch(tok2->next(), "[")) + { + value = tok2->next()->link()->strAt(2); + valueVarId = 0; + } + else if (value == "&") + { + value = tok2->strAt(3); + valueVarId = tok2->tokAt(3)->varId(); + + // *ptr = &var; *ptr = 5; + // equals + // var = 5; not *var = 5; + if (tok2->strAt(4) == ";") + valueIsPointer = true; + } + + // float value should contain a "." + else if (tok2->tokAt(2)->isNumber() && + floatvar && + value.find(".") == std::string::npos) + { + value += ".0"; + } + + if (Token::simpleMatch(tok2->next(), "= &")) + tok2 = tok2->tokAt(3); + + tok3 = tok2->next(); + } + *_tok2 = tok2; + *_tok3 = tok3; + return true; +} + +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 bool pointeralias(valueToken->isName() || Token::Match(valueToken, "& %var% [")); + + bool ret = false; + + Token* bailOutFromLoop = 0; + int indentlevel3 = indentlevel; + bool ret3 = false; + for (; tok3; tok3 = tok3->next()) + { + if (tok3->str() == "{") + { + ++indentlevel3; + } + else if (tok3->str() == "}") + { + --indentlevel3; + if (indentlevel3 < indentlevel) + { + if (Token::Match((*tok2)->tokAt(-7), "%type% * %var% ; %var% = & %var% ;") && + (*tok2)->tokAt(-5)->str() == (*tok2)->tokAt(-3)->str()) + { + (*tok2) = (*tok2)->tokAt(-4); + Token::eraseTokens((*tok2), (*tok2)->tokAt(5)); + } + break; + } + } + + // Stop if label is found + if (Token::Match(tok3, "; %type% : ;")) + break; + + // Stop if return or break is found .. + if (tok3->str() == "break") + break; + if ((indentlevel3 > 1 || !Token::simpleMatch(Token::findmatch(tok3,";"), "; }")) && tok3->str() == "return") + ret3 = true; + if (ret3 && tok3->str() == ";") + break; + + if (pointeralias && Token::Match(tok3, ("!!= " + value).c_str())) + break; + + // Stop if do is found + if (tok3->str() == "do") + break; + + // Stop if something like 'while (--var)' is found + if (tok3->str() == "for" || tok3->str() == "while" || tok3->str() == "do") + { + const Token *endpar = tok3->next()->link(); + if (Token::simpleMatch(endpar, ") {")) + endpar = endpar->next()->link(); + bool bailout = false; + for (const Token *tok4 = tok3; tok4 && tok4 != endpar; tok4 = tok4->next()) + { + if (Token::Match(tok4, "++|-- %varid%", varid) || + Token::Match(tok4, "%varid% ++|--|=", varid)) + { + bailout = true; + break; + } + } + if (bailout) + break; + } + + if (bailOutFromLoop) + { + // This could be a loop, skip it, but only if it doesn't contain + // the variable we are checking for. If it contains the variable + // we will bail out. + if (tok3->varId() == varid) + { + // Continue + //tok2 = bailOutFromLoop; + break; + } + else if (tok3 == bailOutFromLoop) + { + // We have skipped the loop + bailOutFromLoop = 0; + continue; + } + + continue; + } + else if (tok3->str() == "{" && tok3->previous()->str() == ")") + { + // There is a possible loop after the assignment. Try to skip it. + if (tok3->previous()->link() && + !Token::simpleMatch(tok3->previous()->link()->previous(), "if")) + bailOutFromLoop = tok3->link(); + continue; + } + + // Variable used in realloc (see Ticket #1649) + if (Token::Match(tok3, "%var% = realloc ( %var% ,") && + tok3->varId() == varid && + tok3->tokAt(4)->varId() == varid) + { + tok3->tokAt(4)->str(value); + ret = true; + } + + // condition "(|&&|%OROR% %varid% )|&&|%OROR% + if (!Token::Match(tok3->previous(), "( %var% )") && + (Token::Match(tok3->previous(), "&&|(") || tok3->strAt(-1) == "||") && + tok3->varId() == varid && + (Token::Match(tok3->next(), "&&|)") || tok3->strAt(1) == "||")) + { + tok3->str(value); + ret = true; + } + + // Variable is used somehow in a non-defined pattern => bail out + if (tok3->varId() == varid) + { + // This is a really generic bailout so let's try to avoid this. + // There might be lots of false negatives. + if (_settings->debugwarnings) + { + // FIXME: Fix all the debug warnings for values and then + // remove this bailout + if (pointeralias) + break; + + // suppress debug-warning when calling member function + if (Token::Match(tok3->next(), ". %var% (")) + break; + + // suppress debug-warning when assignment + if (Token::simpleMatch(tok3->next(), "=")) + break; + + // taking address of variable.. + if (Token::Match(tok3->tokAt(-2), "return|= & %var% ;")) + break; + + // parameter in function call.. + if (Token::Match(tok3->tokAt(-2), "%var% ( %var% ,|)") || + Token::Match(tok3->previous(), ", %var% ,|)")) + break; + + // conditional increment + if (Token::Match(tok3->tokAt(-3), ") { ++|--") || + Token::Match(tok3->tokAt(-2), ") { %var% ++|--")) + break; + + std::list locationList; + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok3->linenr(); + loc.setfile(file(tok3)); + locationList.push_back(loc); + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::debug, + "simplifyKnownVariables: bailing out (variable="+tok3->str()+", value="+value+")", + "debug"); + + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); + } + + break; + } + + // Using the variable in condition.. + if (Token::Match(tok3->previous(), ("if ( " + structname + " %varid% ==|!=|<|<=|>|>=|)").c_str(), varid) || + Token::Match(tok3, ("( " + structname + " %varid% ==|!=|<|<=|>|>=").c_str(), varid) || + Token::Match(tok3, ("!|==|!=|<|<=|>|>= " + structname + " %varid% ==|!=|<|<=|>|>=|)|;").c_str(), varid) || + Token::Match(tok3->previous(), "strlen|free ( %varid% )", varid)) + { + if (value[0] == '\"' && tok3->strAt(-1) != "strlen") + { + // bail out if value is a string unless if it's just given + // as parameter to strlen + break; + } + if (!structname.empty()) + { + tok3->deleteNext(); + tok3->deleteNext(); + } + if (Token::Match(valueToken, "& %var% ;")) + { + tok3->insertToken("&"); + tok3 = tok3->next(); + } + tok3 = tok3->next(); + tok3->str(value); + tok3->varId(valueVarId); + ret = true; + } + + // Delete pointer alias + if (pointeralias && tok3->str() == "delete" && + (Token::Match(tok3, "delete %varid% ;", varid) || + Token::Match(tok3, "delete [ ] %varid%", varid))) + { + tok3 = (tok3->strAt(1) == "[") ? tok3->tokAt(3) : tok3->next(); + tok3->str(value); + tok3->varId(valueVarId); + ret = true; + } + + // Variable is used in function call.. + if (Token::Match(tok3, ("%var% ( " + structname + " %varid% ,").c_str(), varid)) + { + const char * const functionName[] = + { + "memcmp","memcpy","memmove","memset", + "strcmp","strcpy","strncpy","strdup" + }; + for (unsigned int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i) + { + if (tok3->str() == functionName[i]) + { + Token *par1 = tok3->next()->next(); + if (!structname.empty()) + { + par1->deleteThis(); + par1->deleteThis(); + } + par1->str(value); + par1->varId(valueVarId); + break; + } + } + } + + // Variable is used as 2nd parameter in function call.. + if (Token::Match(tok3, ("%var% ( %any% , " + structname + " %varid% ,|)").c_str(), varid)) + { + const char * const functionName[] = + { + "memcmp","memcpy","memmove", + "strcmp","strcpy","strncmp","strncpy" + }; + for (unsigned int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i) + { + if (tok3->str() == functionName[i]) + { + Token *par = tok3->tokAt(4); + if (!structname.empty()) + { + par->deleteThis(); + par->deleteThis(); + } + par->str(value); + par->varId(valueVarId); + break; + } + } + } + + // array usage + if (Token::Match(tok3, ("[(,] " + structname + " %varid% [+-*/[]").c_str(), varid)) + { + if (!structname.empty()) + { + tok3->deleteNext(); + tok3->deleteNext(); + } + tok3 = tok3->next(); + tok3->str(value); + tok3->varId(valueVarId); + ret = true; + } + + // Variable is used in calculation.. + if (((tok3->previous()->varId() > 0) && Token::Match(tok3, ("& " + structname + " %varid%").c_str(), varid)) || + Token::Match(tok3, ("[=+-*/%^|[] " + structname + " %varid% [=?+-*/%^|;])]").c_str(), varid) || + Token::Match(tok3, ("[(=+-*/%^|[] " + structname + " %varid% <<|>>").c_str(), varid) || + Token::Match(tok3, ("<<|>> " + structname + " %varid% [+-*/%^|;])]").c_str(), varid) || + Token::Match(tok3->previous(), ("[=+-*/%^|[] ( " + structname + " %varid%").c_str(), varid)) + { + if (value[0] == '\"') + break; + if (!structname.empty()) + { + tok3->deleteNext(); + tok3->deleteNext(); + } + tok3 = tok3->next(); + tok3->str(value); + tok3->varId(valueVarId); + if (tok3->previous()->str() == "*" && valueIsPointer) + { + tok3 = tok3->previous(); + tok3->deleteThis(); + } + ret = true; + } + + if (Token::simpleMatch(tok3, "= {")) + { + unsigned int indentlevel4 = 0; + for (const Token *tok4 = tok3; tok4; tok4 = tok4->next()) + { + if (tok4->str() == "{") + ++indentlevel4; + else if (tok4->str() == "}") + { + if (indentlevel4 <= 1) + break; + --indentlevel4; + } + if (Token::Match(tok4, "{|, %varid% ,|}", varid)) + { + tok4->next()->str(value); + tok4->next()->varId(valueVarId); + ret = true; + } + } + } + + // Using the variable in for-condition.. + if (Token::simpleMatch(tok3, "for (")) + { + for (Token *tok4 = tok3->tokAt(2); tok4; tok4 = tok4->next()) + { + if (tok4->str() == "(" || tok4->str() == ")") + break; + + // Replace variable used in condition.. + if (Token::Match(tok4, "; %var% <|<=|!= %var% ; ++| %var% ++| )")) + { + const Token *inctok = tok4->tokAt(5); + if (inctok->str() == "++") + inctok = inctok->next(); + if (inctok->varId() == varid) + break; + + if (tok4->next()->varId() == varid) + { + tok4->next()->str(value); + tok4->next()->varId(valueVarId); + ret = true; + } + if (tok4->tokAt(3)->varId() == varid) + { + tok4->tokAt(3)->str(value); + tok4->tokAt(3)->varId(valueVarId); + ret = true; + } + } + } + } + + if (indentlevel == indentlevel3 && Token::Match(tok3->next(), "%varid% ++|--", varid) && MathLib::isInt(value)) + { + const std::string op(tok3->strAt(2)); + if (Token::Match(tok3, "[{};] %any% %any% ;")) + { + Token::eraseTokens(tok3, tok3->tokAt(3)); + } + else + { + tok3 = tok3->next(); + tok3->str(value); + tok3->varId(valueVarId); + tok3->deleteNext(); + } + incdec(value, op); + if (!Token::simpleMatch((*tok2)->tokAt(-2), "for (")) + { + (*tok2)->tokAt(2)->str(value); + (*tok2)->tokAt(2)->varId(valueVarId); + } + ret = true; + } + + if (indentlevel == indentlevel3 && Token::Match(tok3->next(), "++|-- %varid%", varid) && MathLib::isInt(value) && + !Token::Match(tok3->tokAt(3), "[.[]")) + { + incdec(value, tok3->strAt(1)); + (*tok2)->tokAt(2)->str(value); + (*tok2)->tokAt(2)->varId(valueVarId); + if (Token::Match(tok3, "[;{}] %any% %any% ;")) + { + Token::eraseTokens(tok3, tok3->tokAt(3)); + } + else + { + tok3->deleteNext(); + tok3->next()->str(value); + tok3->next()->varId(valueVarId); + } + tok3 = tok3->next(); + ret = true; + } + + // return variable.. + if (Token::Match(tok3, "return %varid% %any%", varid) && + isOp(tok3->tokAt(2)) && + value[0] != '\"') + { + tok3->next()->str(value); + tok3->next()->varId(valueVarId); + } + + else if (pointeralias && Token::Match(tok3, "return * %varid% ;", varid) && value[0] != '\"') + { + tok3->deleteNext(); + tok3->next()->str(value); + tok3->next()->varId(valueVarId); + } + } + return ret; +} + + +void Tokenizer::elseif() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (!Token::simpleMatch(tok, "else if")) + continue; + int indent = 0; + for (Token *tok2 = tok; indent >= 0 && tok2; tok2 = tok2->next()) + { + if (Token::Match(tok2, "(|{")) + ++indent; + else if (Token::Match(tok2, ")|}")) + --indent; + + if (indent == 0 && Token::Match(tok2, "}|;")) + { + if (tok2->next() && tok2->next()->str() != "else") + { + tok->insertToken("{"); + tok2->insertToken("}"); + Token::createMutualLinks(tok->next(), tok2->next()); + break; + } + } + } + } +} + + +bool Tokenizer::simplifyRedundantParanthesis() +{ + bool ret = false; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() != "(") + continue; + + // !!operator = ( x ) ; + if (tok->strAt(-2) != "operator" && + tok->strAt(-1) == "=" && + tok->strAt(1) != "{" && + Token::simpleMatch(tok->link(), ") ;")) + { + tok->link()->deleteThis(); + tok->deleteThis(); + continue; + } + + while (Token::simpleMatch(tok, "( (") && + tok->link()->previous() == tok->next()->link()) + { + // We have "(( *something* ))", remove the inner + // parenthesis + tok->deleteNext(); + tok->link()->tokAt(-2)->deleteNext(); + ret = true; + } + + while (Token::Match(tok->previous(), "[,;{}(] ( %var% (") && + tok->link()->previous() == tok->tokAt(2)->link()) + { + // We have "( func ( *something* ))", remove the outer + // parenthesis + tok->link()->deleteThis(); + tok->deleteThis(); + ret = true; + } + + while (Token::Match(tok->previous(), "[;{] ( delete %var% ) ;")) + { + // We have "( delete var )", remove the outer + // parenthesis + tok->tokAt(3)->deleteThis(); + tok->deleteThis(); + ret = true; + } + + while (Token::Match(tok->previous(), "[;{] ( delete [ ] %var% ) ;")) + { + // We have "( delete [] var )", remove the outer + // parenthesis + tok->tokAt(5)->deleteThis(); + tok->deleteThis(); + ret = true; + } + + if (!Token::simpleMatch(tok->tokAt(-2), "operator delete") && + Token::Match(tok->previous(), "delete|; (") && + (tok->strAt(-1) != "delete" || tok->next()->varId() > 0) && + Token::Match(tok->link(), ") ;|,")) + { + tok->link()->deleteThis(); + tok->deleteThis(); + ret = true; + } + + if (Token::Match(tok->previous(), "[(!*;{}] ( %var% )") && tok->next()->varId() != 0) + { + // We have "( var )", remove the parenthesis + tok->deleteThis(); + tok->deleteNext(); + ret = true; + continue; + } + + if (Token::Match(tok->previous(), "[(!] ( %var% . %var% )")) + { + // We have "( var . var )", remove the parenthesis + tok->deleteThis(); + tok = tok->tokAt(2); + tok->deleteNext(); + ret = true; + continue; + } + + if (Token::Match(tok, "( ( %bool% )") || + Token::Match(tok, "( ( %num% )")) + { + tok->tokAt(2)->deleteNext(); + tok->deleteNext(); + ret = true; + } + } + return ret; +} + +void Tokenizer::simplifyReference() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + // starting executable scope.. + if (Token::Match(tok, ") const| {")) + { + // replace references in this scope.. + if (tok->next()->str() != "{") + tok = tok->next(); + Token * const end = tok->next()->link(); + for (Token *tok2 = tok; tok2 && tok2 != end; tok2 = tok2->next()) + { + // found a reference.. + if (Token::Match(tok2, "[;{}] %type% & %var% (|= %var% )| ;")) + { + const unsigned int ref_id = tok2->tokAt(3)->varId(); + if (!ref_id) + continue; + + // replace reference in the code.. + for (Token *tok3 = tok2->tokAt(7); tok3 && tok3 != end; tok3 = tok3->next()) + { + if (tok3->varId() == ref_id) + { + tok3->str(tok2->strAt(5)); + tok3->varId(tok2->tokAt(5)->varId()); + } + } + + Token::eraseTokens(tok2, tok2->tokAt(7)); + } + } + } + } +} + +bool Tokenizer::simplifyCalculations() +{ + bool ret = false; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + // Remove parentheses around variable.. + // keep parentheses here: dynamic_cast(p); + // keep parentheses here: A operator * (int); + // keep parentheses here: int ( * ( * f ) ( ... ) ) (int) ; + // keep parentheses here: int ( * * ( * compilerHookVector ) (void) ) ( ) ; + // keep parentheses here: operator new [] (size_t); + // keep parentheses here: Functor()(a ... ) + // keep parentheses here: ) ( var ) ; + if (Token::Match(tok->next(), "( %var% ) [;),+-*/><]]") && + !tok->isName() && + tok->str() != ">" && + tok->str() != "]" && + !Token::simpleMatch(tok->previous(), "operator") && + !Token::simpleMatch(tok->previous(), "* )") && + !Token::simpleMatch(tok->previous(), ") )") && + !Token::Match(tok->tokAt(-2), "* %var% )") && + !Token::Match(tok->tokAt(-2), "%type% ( ) ( %var%") && + !Token::Match(tok, ") ( %var% ) ;") + ) + { + tok->deleteNext(); + tok = tok->next(); + tok->deleteNext(); + ret = true; + } + + if (tok->isNumber()) + { + if (tok->str() == "0") + { + if (Token::Match(tok->previous(), "[+-] 0")) + { + tok = tok->previous(); + if (Token::Match(tok->tokAt(-4), "[;{}] %var% = %var% [+-] 0 ;") && + tok->strAt(-3) == tok->strAt(-1)) + { + tok = tok->previous()->previous()->previous(); + tok->deleteThis(); + tok->deleteThis(); + tok->deleteThis(); + } + tok->deleteThis(); + tok->deleteThis(); + ret = true; + } + else if (Token::Match(tok->previous(), "[=([,] 0 +")) + { + tok->deleteThis(); + tok->deleteThis(); + ret = true; + } + else if (Token::Match(tok->previous(), "[=[(,] 0 * %any% [+-*/,]);]")) + { + tok->deleteNext(); + if (tok->next()->str() == "(") + Token::eraseTokens(tok, tok->next()->link()); + tok->deleteNext(); + ret = true; + } + } + + if (Token::simpleMatch(tok->previous(), "* 1") || Token::simpleMatch(tok, "1 *")) + { + if (Token::simpleMatch(tok->previous(), "*")) + tok = tok->previous(); + tok->deleteThis(); + tok->deleteThis(); + ret = true; + } + + // Remove parentheses around number.. + if (Token::Match(tok->tokAt(-2), "%any% ( %num% )") && !tok->tokAt(-2)->isName() && tok->strAt(-2) != ">") + { + tok = tok->previous(); + tok->deleteThis(); + tok->deleteNext(); + ret = true; + } + + if (Token::simpleMatch(tok->previous(), "( 0 ||") || + Token::simpleMatch(tok->previous(), "|| 0 )") || + Token::simpleMatch(tok->previous(), "( 1 &&") || + Token::simpleMatch(tok->previous(), "&& 1 )")) + { + if (!Token::simpleMatch(tok->previous(), "(")) + tok = tok->previous(); + tok->deleteThis(); + tok->deleteThis(); + } + + if (Token::Match(tok, "%num% ==|!=|<=|>=|<|> %num%") && + MathLib::isInt(tok->str()) && + MathLib::isInt(tok->tokAt(2)->str())) + { + const std::string prev(tok->previous() ? tok->strAt(-1).c_str() : ""); + const std::string after(tok->tokAt(3) ? tok->strAt(3).c_str() : ""); + if ((prev == "(" || prev == "&&" || prev == "||") && (after == ")" || after == "&&" || after == "||")) + { + const MathLib::bigint op1(MathLib::toLongNumber(tok->str())); + const std::string &cmp(tok->next()->str()); + const MathLib::bigint op2(MathLib::toLongNumber(tok->tokAt(2)->str())); + + std::string result; + + if (cmp == "==") + result = (op1 == op2) ? "1" : "0"; + else if (cmp == "!=") + result = (op1 != op2) ? "1" : "0"; + else if (cmp == "<=") + result = (op1 <= op2) ? "1" : "0"; + else if (cmp == ">=") + result = (op1 >= op2) ? "1" : "0"; + else if (cmp == "<") + result = (op1 < op2) ? "1" : "0"; + else if (cmp == ">") + result = (op1 > op2) ? "1" : "0"; + + tok->str(result); + tok->deleteNext(); + tok->deleteNext(); + } + } + + if (Token::Match(tok->previous(), "[([,=] %num% <<|>> %num%")) + { + const MathLib::bigint op1(MathLib::toLongNumber(tok->str())); + const MathLib::bigint op2(MathLib::toLongNumber(tok->tokAt(2)->str())); + MathLib::bigint result; + + if (tok->next()->str() == "<<") + result = op1 << op2; + else + result = op1 >> op2; + + std::ostringstream ss; + ss << result; + + tok->str(ss.str()); + tok->deleteNext(); + tok->deleteNext(); + } + } + + else if (tok->next() && tok->next()->isNumber()) + { + + // (1-2) + while (Token::Match(tok, "[[,(=<>+-*|&^] %num% [+-*/] %num% [],);=<>+-*/|&^]") || + Token::Match(tok, "<< %num% [+-*/] %num% [],);=<>+-*/|&^]") || + Token::Match(tok, "[[,(=<>+-*|&^] %num% [+-*/] %num% <<|>>") || + Token::Match(tok, "<< %num% [+-*/] %num% <<") || + Token::Match(tok, "[(,[] %num% [|&^] %num% [];,);]")) + { + tok = tok->next(); + + // Don't simplify "%num% / 0" + if (Token::simpleMatch(tok->next(), "/ 0")) + continue; + + // & | ^ + if (Token::Match(tok->next(), "[&|^]")) + { + std::string result; + const std::string first(tok->str()); + const std::string second(tok->strAt(2)); + const char op = tok->next()->str()[0]; + if (op == '&') + result = MathLib::toString(MathLib::toLongNumber(first) & MathLib::toLongNumber(second)); + else if (op == '|') + result = MathLib::toString(MathLib::toLongNumber(first) | MathLib::toLongNumber(second)); + else if (op == '^') + result = MathLib::toString(MathLib::toLongNumber(first) ^ MathLib::toLongNumber(second)); + + if (!result.empty()) + { + ret = true; + tok->str(result); + Token::eraseTokens(tok, tok->tokAt(3)); + continue; + } + } + + // + and - are calculated after * and / + if (Token::Match(tok->next(), "[+-/]")) + { + if (tok->previous()->str() == "*") + continue; + if (Token::Match(tok->tokAt(3), "[*/]")) + continue; + } + + if (Token::Match(tok->previous(), "- %num% - %num%")) + tok->str(MathLib::add(tok->str(), tok->tokAt(2)->str())); + else if (Token::Match(tok->previous(), "- %num% + %num%")) + tok->str(MathLib::subtract(tok->str(), tok->tokAt(2)->str())); + else + tok->str(MathLib::calculate(tok->str(), tok->tokAt(2)->str(), tok->strAt(1)[0], this)); + + Token::eraseTokens(tok, tok->tokAt(3)); + + // evaluate "2 + 2 - 2 - 2" + // as (((2 + 2) - 2) - 2) = 0 + // instead of ((2 + 2) - (2 - 2)) = 4 + if (Token::Match(tok->next(), "[+-*/]")) + { + tok = tok->previous(); + continue; + } + + ret = true; + } + } + } + return ret; +} + + + + +void Tokenizer::simplifyGoto() +{ + std::list gotos; + unsigned int indentlevel = 0; + Token *beginfunction = 0; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "{") + { + if (beginfunction == 0 && indentlevel == 0 && tok->link()) + tok = tok->link(); + else + ++indentlevel; + } + + else if (tok->str() == "}") + { + if (indentlevel == 0) + break; // break out - it seems the code is wrong + --indentlevel; + if (indentlevel == 0) + { + gotos.clear(); + beginfunction = 0; + } + } + + else if (indentlevel > 0 && tok->str() == "(") + { + tok = tok->link(); + } + + else if (indentlevel == 0 && Token::Match(tok, ") const| {")) + { + gotos.clear(); + beginfunction = tok; + } + + else if (Token::Match(tok, "goto %var% ;")) + gotos.push_back(tok); + + else if (indentlevel == 1 && Token::Match(tok->previous(), "[};] %var% :")) + { + // Is this label at the end.. + bool end = false; + int level = 0; + for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "}") + { + --level; + if (level < 0) + { + end = true; + break; + } + } + else if (tok2->str() == "{") + { + ++level; + } + + if (Token::Match(tok2, "%var% :") || tok2->str() == "goto") + { + break; + } + } + if (!end) + continue; + + const std::string name(tok->str()); + + tok->deleteThis(); + tok->deleteThis(); + if (Token::Match(tok, "; %any%")) + tok->deleteThis(); + + // This label is at the end of the function.. replace all matching goto statements.. + for (std::list::iterator it = gotos.begin(); it != gotos.end(); ++it) + { + Token *token = *it; + if (token->next()->str() == name) + { + // Delete the "goto name;" + token = token->previous(); + token->deleteNext(); + token->deleteNext(); + token->deleteNext(); + + // Insert the statements.. + bool ret = false; // is there return + bool ret2 = false; // is there return in indentlevel 0 + std::list links; + std::list links2; + std::list links3; + int lev = 0; + for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (tok2->str() == "}") + { + --lev; + if (lev < 0) + break; + } + if (tok2->str() == "{") + { + ++lev; + } + else if (tok2->str() == "return") + { + ret = true; + if (indentlevel == 1 && lev == 0) + ret2 = true; + } + token->insertToken(tok2->str().c_str()); + token = token->next(); + token->linenr(tok2->linenr()); + token->varId(tok2->varId()); + if (ret2 && tok2->str() == ";") + { + break; + } + if (token->str() == "(") + { + links.push_back(token); + } + else if (token->str() == ")") + { + if (links.empty()) + { + // This should never happen at this point + syntaxError(token, ')'); + return; + } + + Token::createMutualLinks(links.back(), token); + links.pop_back(); + } + else if (token->str() == "{") + { + links2.push_back(token); + } + else if (token->str() == "}") + { + if (links2.empty()) + { + // This should never happen at this point + syntaxError(token, '}'); + return; + } + + Token::createMutualLinks(links2.back(), token); + links2.pop_back(); + } + else if (token->str() == "[") + { + links3.push_back(token); + } + else if (token->str() == "]") + { + if (links3.empty()) + { + // This should never happen at this point + syntaxError(token, ']'); + return; + } + + Token::createMutualLinks(links3.back(), token); + links3.pop_back(); + } + } + + if (!ret) + { + token->insertToken("return"); + token = token->next(); + token->insertToken(";"); + token = token->next(); + } + } + } + + gotos.clear(); + tok = beginfunction; + indentlevel = 0; + continue; + } + } +} + +void Tokenizer::simplifyNestedStrcat() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (! Token::Match(tok, "[;{}] strcat ( strcat (")) + { + continue; + } + + // find inner strcat call + Token *tok2 = tok->tokAt(3); + while (Token::simpleMatch(tok2, "strcat ( strcat")) + { + tok2 = tok2->tokAt(2); + } + + // If we have this code: + // strcat(strcat(dst, foo), bar); + // We move this part of code before all strcat() calls: strcat(dst, foo) + // And place "dst" token where the code was. + Token *prevTok = tok2->previous(); + + // Move tokens to new place + Token::move(tok2, tok2->next()->link(), tok); + tok = tok2->next()->link(); + + // Insert the "dst" token + prevTok->insertToken(tok2->strAt(2)); + + // Insert semicolon after the moved strcat() + tok->insertToken(";"); + } + +} + +void Tokenizer::duplicateEnumError(const Token * tok1, const Token * tok2, const std::string & type) +{ + if (!(_settings->_checkCodingStyle)) + return; + + std::list locationList; + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok1->linenr(); + loc.setfile(file(tok1)); + locationList.push_back(loc); + loc.line = tok2->linenr(); + loc.setfile(file(tok2)); + locationList.push_back(loc); + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::style, + std::string(type + " '" + tok2->str() + + "' hides enumerator with same name"), + "variableHidingEnum"); + + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); +} + +// Check if this statement is a duplicate definition. A duplicate +// definition will hide the enumerator within it's scope so just +// skip the entire scope of the duplicate. +bool Tokenizer::duplicateDefinition(Token ** tokPtr, const Token * name) +{ + // check for an end of definition + const Token * tok = *tokPtr; + if (tok && Token::Match(tok->next(), ";|,|[|=|)|>")) + { + const Token * end = tok->next(); + + if (end->str() == "[") + { + end = end->link()->next(); + } + else if (end->str() == ",") + { + // check for function argument + if (Token::Match(tok->previous(), "(|,")) + return false; + + // find end of definition + int level = 0; + while (end && end->next() && (!Token::Match(end->next(), ";|)|>") || + (end->next()->str() == ")" && level == 0))) + { + if (end->next()->str() == "(") + level++; + else if (end->next()->str() == ")") + level--; + + end = end->next(); + } + } + else if (end->str() == ")") + { + // check of function argument + if (tok->previous()->str() == ",") + return false; + } + + if (end) + { + if (Token::simpleMatch(end, ") {")) // function parameter ? + { + // look backwards + if (tok->previous()->str() == "enum" || + (Token::Match(tok->previous(), "%type%") && + tok->previous()->str() != "return")) + { + duplicateEnumError(*tokPtr, name, "Function parameter"); + // duplicate definition so skip entire function + *tokPtr = end->next()->link(); + return true; + } + } + else if (end->str() == ">") // template parameter ? + { + // look backwards + if (tok->previous()->str() == "enum" || + (Token::Match(tok->previous(), "%type%") && + tok->previous()->str() != "return")) + { + // duplicate definition so skip entire template + while (end && end->str() != "{") + end = end->next(); + if (end) + { + duplicateEnumError(*tokPtr, name, "Template parameter"); + *tokPtr = end->link(); + return true; + } + } + } + else + { + // look backwards + if (Token::Match(tok->previous(), "enum|,") || + (Token::Match(tok->previous(), "%type%") && + tok->previous()->str() != "return")) + { + duplicateEnumError(*tokPtr, name, "Variable"); + return true; + } + } + } + } + return false; +} + +void Tokenizer::simplifyEnum() +{ + // Don't simplify enums in java files + if (isJavaOrCSharp()) + return; + + std::string className; + int classLevel = 0; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "class|struct|namespace %any%") && + (!tok->previous() || (tok->previous() && tok->previous()->str() != "enum"))) + { + className = tok->next()->str(); + classLevel = 0; + continue; + } + else if (tok->str() == "}") + { + --classLevel; + if (classLevel < 0) + className = ""; + + continue; + } + else if (tok->str() == "{") + { + ++classLevel; + continue; + } + else if (Token::Match(tok, "enum class|struct| {|:") || + Token::Match(tok, "enum class|struct| %type% {|:|;")) + { + Token *tok1; + Token *start = tok; + Token *end; + Token *enumType = 0; + Token *typeTokenStart = 0; + Token *typeTokenEnd = 0; + + // check for C++0x enum class + if (Token::Match(tok->next(), "class|struct")) + tok->deleteNext(); + + // check for C++0x typed enumeration + if (Token::Match(tok->next(), "%type% :") || tok->next()->str() == ":") + { + int offset = 2; + if (tok->next()->str() != ":") + offset = 3; + + // check for forward declaration + const Token *temp = tok->tokAt(offset); + while (!Token::Match(temp, "{|;")) + temp = temp->next(); + if (temp->str() == ";") + { + /** @todo start substitution check at forward declaration */ + // delete forward declaration + tok->deleteThis(); + tok->deleteThis(); + tok->deleteThis(); + tok->deleteThis(); + continue; + } + + typeTokenStart = tok->tokAt(offset); + typeTokenEnd = typeTokenStart; + while (Token::Match(typeTokenEnd->next(), "signed|unsigned|char|short|int|long")) + typeTokenEnd = typeTokenEnd->next(); + + if (!Token::Match(typeTokenEnd->next(), "{|;")) + { + syntaxError(typeTokenEnd->next()); + return; + } + } + + // check for forward declaration + else if (Token::Match(tok->next(), "%type% ;")) + { + /** @todo start substitution check at forward declaration */ + // delete forward declaration + tok->deleteThis(); + tok->deleteThis(); + continue; + } + + if (tok->tokAt(1)->str() == "{") + tok1 = tok->tokAt(2); + else if (tok->tokAt(1)->str() == ":") + tok1 = typeTokenEnd->tokAt(2); + else if (tok->tokAt(2)->str() == "{") + { + enumType = tok->tokAt(1); + tok1 = tok->tokAt(3); + } + else + { + enumType = tok->tokAt(1); + tok1 = typeTokenEnd->tokAt(2); + } + + end = tok1->tokAt(-1)->link(); + + MathLib::bigint lastValue = -1; + Token * lastEnumValueStart = 0; + Token * lastEnumValueEnd = 0; + + // iterate over all enumerators between { and } + // Give each enumerator the const value specified or if not specified, 1 + the + // previous value or 0 if it is the first one. + for (; tok1 && tok1 != end; tok1 = tok1->next()) + { + Token * enumName = 0; + Token * enumValue = 0; + Token * enumValueStart = 0; + Token * enumValueEnd = 0; + + if (tok1->str() == "(") + { + tok1 = tok1->link(); + continue; + } + + if (Token::Match(tok1->previous(), ",|{ %type% ,|}")) + { + // no value specified + enumName = tok1; + lastValue++; + tok1->insertToken("="); + tok1 = tok1->next(); + + if (lastEnumValueStart && lastEnumValueEnd) + { + // previous value was an expression + Token *valueStart = tok1; + tok1 = copyTokens(tok1, lastEnumValueStart, lastEnumValueEnd); + + // value is previous expression + 1 + tok1->insertToken("+"); + tok1 = tok1->next(); + tok1->insertToken(MathLib::toString(lastValue)); + enumValue = 0; + enumValueStart = valueStart->next(); + enumValueEnd = tok1->next(); + } + else + { + // value is previous numeric value + 1 + tok1->insertToken(MathLib::toString(lastValue)); + enumValue = tok1->next(); + } + } + else if (Token::Match(tok1->previous(), ",|{ %type% = %num% ,|}")) + { + // value is specified numeric value + enumName = tok1; + lastValue = MathLib::toLongNumber(tok1->strAt(2)); + enumValue = tok1->tokAt(2); + lastEnumValueStart = 0; + lastEnumValueEnd = 0; + } + else if (Token::Match(tok1->previous(), ",|{ %type% =")) + { + // value is specified expression + enumName = tok1; + lastValue = 0; + tok1 = tok1->tokAt(2); + enumValueStart = tok1; + enumValueEnd = tok1; + int level = 0; + if (enumValueEnd->str() == "(" || + enumValueEnd->str() == "[" || + enumValueEnd->str() == "{") + level++; + while (enumValueEnd->next() && + (!Token::Match(enumValueEnd->next(), "}|,") || level)) + { + if (enumValueEnd->next()->str() == "(" || + enumValueEnd->next()->str() == "[" || + enumValueEnd->next()->str() == "{") + level++; + else if (enumValueEnd->next()->str() == ")" || + enumValueEnd->next()->str() == "]" || + enumValueEnd->next()->str() == "}") + level--; + + enumValueEnd = enumValueEnd->next(); + } + // remember this expression in case it needs to be incremented + lastEnumValueStart = enumValueStart; + lastEnumValueEnd = enumValueEnd; + // skip over expression + tok1 = enumValueEnd; + } + + // find all uses of this enumerator and substitute it's value for it's name + if (enumName && (enumValue || (enumValueStart && enumValueEnd))) + { + const std::string pattern = className.empty() ? + std::string("") : + std::string(className + " :: " + enumName->str()); + int level = 1; + bool inScope = true; + + bool exitThisScope = false; + int exitScope = 0; + bool simplify = false; + bool hasClass = false; + for (Token *tok2 = tok1->next(); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "}") + { + --level; + if (level < 0) + inScope = false; + + if (exitThisScope) + { + if (level < exitScope) + exitThisScope = false; + } + } + else if (tok2->str() == "{") + { + // Is the same enum redefined? + const Token *begin = end->link(); + if (tok2->fileIndex() == begin->fileIndex() && + tok2->linenr() == begin->linenr() && + Token::Match(begin->tokAt(-2), "enum %type% {") && + Token::Match(tok2->tokAt(-2), "enum %type% {") && + begin->strAt(-1) == tok2->strAt(-1)) + { + // remove duplicate enum + Token * startToken = tok2->tokAt(-3); + tok2 = tok2->link()->next(); + Token::eraseTokens(startToken, tok2); + if (!tok2) + break; + } + else + { + // Not a duplicate enum.. + ++level; + } + } + else if (!pattern.empty() && Token::Match(tok2, pattern.c_str())) + { + simplify = true; + hasClass = true; + } + else if (inScope && !exitThisScope && tok2->str() == enumName->str()) + { + if (Token::simpleMatch(tok2->previous(), "::") || + Token::Match(tok2->next(), "::|[")) + { + // Don't replace this enum if: + // * it's preceded or followed by "::" + // * it's followed by "[" + } + else if (!duplicateDefinition(&tok2, enumName)) + { + simplify = true; + hasClass = false; + } + else + { + // something with the same name. + exitScope = level; + } + } + + if (simplify) + { + if (enumValue) + tok2->str(enumValue->str()); + else + { + tok2 = tok2->previous(); + tok2->deleteNext(); + tok2 = copyTokens(tok2, enumValueStart, enumValueEnd); + } + + if (hasClass) + { + tok2->deleteNext(); + tok2->deleteNext(); + } + + simplify = false; + } + } + } + } + + // check for a variable definition: enum {} x; + if (end->next() && end->next()->str() != ";") + { + Token *tempTok = end; + + tempTok->insertToken(";"); + tempTok = tempTok->next(); + if (typeTokenStart == 0) + tempTok->insertToken("int"); + else + { + Token *tempTok1 = typeTokenStart; + + tempTok->insertToken(tempTok1->str()); + + while (tempTok1 != typeTokenEnd) + { + tempTok1 = tempTok1->next(); + + tempTok->insertToken(tempTok1->str()); + tempTok = tempTok->next(); + } + } + } + + if (enumType) + { + const std::string pattern(className.empty() ? "" : (className + " :: " + enumType->str()).c_str()); + + // count { and } for tok2 + int level = 0; + bool inScope = true; + + bool exitThisScope = false; + int exitScope = 0; + bool simplify = false; + bool hasClass = false; + for (Token *tok2 = end->next(); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "}") + { + --level; + if (level < 0) + inScope = false; + + if (exitThisScope) + { + if (level < exitScope) + exitThisScope = false; + } + } + else if (tok2->str() == "{") + ++level; + else if (!pattern.empty() && ((Token::simpleMatch(tok2, "enum") && Token::Match(tok2->next(), pattern.c_str())) || Token::Match(tok2, pattern.c_str()))) + { + simplify = true; + hasClass = true; + } + else if (inScope && !exitThisScope && (tok2->str() == enumType->str() || (tok2->str() == "enum" && tok2->next()->str() == enumType->str()))) + { + if (Token::simpleMatch(tok2->previous(), "::")) + { + // Don't replace this enum if it's preceded by "::" + } + else if (tok2->next() && + (tok2->next()->isName() || tok2->next()->str() == "(")) + { + simplify = true; + hasClass = false; + } + } + + if (simplify) + { + if (tok2->str() == "enum") + tok2->deleteNext(); + if (typeTokenStart == 0) + tok2->str("int"); + else + { + Token *tok3 = typeTokenStart; + + tok2->str(tok3->str()); + + while (tok3 != typeTokenEnd) + { + tok3 = tok3->next(); + + tok2->insertToken(tok3->str()); + tok2 = tok2->next(); + } + } + + if (hasClass) + { + tok2->deleteNext(); + tok2->deleteNext(); + } + + simplify = false; + } + } + } + + tok1 = start; + while (tok1->next() && tok1->next() != end) + tok1->deleteNext(); + tok1->deleteNext(); + if (start != _tokens) + { + tok1 = start->previous(); + tok1->deleteNext(); + tok = tok1; + } + else + _tokens->deleteThis(); + } + } +} + + +void Tokenizer::simplifyStd() +{ + std::set f; + f.insert("strcat"); + f.insert("strcpy"); + f.insert("strncat"); + f.insert("strncpy"); + f.insert("free"); + f.insert("malloc"); + f.insert("strdup"); + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() != "std") + continue; + + if (Token::Match(tok->previous(), "[(,{};] std :: %var% (") && + f.find(tok->strAt(2)) != f.end()) + { + tok->deleteNext(); + tok->deleteThis(); + } + } +} + +//--------------------------------------------------------------------------- +// Helper functions for handling the tokens list +//--------------------------------------------------------------------------- + + + +//--------------------------------------------------------------------------- + +const Token *Tokenizer::getFunctionTokenByName(const char funcname[]) const +{ + getSymbolDatabase(); + + std::list::const_iterator i; + + for (i = _symbolDatabase->scopeList.begin(); i != _symbolDatabase->scopeList.end(); ++i) + { + const Scope *scope = *i; + + if (scope->type == Scope::eFunction) + { + if (scope->classDef->str() == funcname) + return scope->classDef; + } + } + return NULL; +} + + +void Tokenizer::fillFunctionList() +{ + getSymbolDatabase(); +} + +//--------------------------------------------------------------------------- + +// Deallocate lists.. +void Tokenizer::deallocateTokens() +{ + deleteTokens(_tokens); + _tokens = 0; + _tokensBack = 0; + _files.clear(); +} + +void Tokenizer::deleteTokens(Token *tok) +{ + while (tok) + { + Token *next = tok->next(); + delete tok; + tok = next; + } +} + +//--------------------------------------------------------------------------- + +const char *Tokenizer::getParameterName(const Token *ftok, unsigned int par) +{ + unsigned int _par = 1; + for (; ftok; ftok = ftok->next()) + { + if (ftok->str() == ")") + break; + if (ftok->str() == ",") + ++_par; + if (par == _par && Token::Match(ftok, "%var% [,)]")) + return ftok->str().c_str(); + } + return NULL; +} + +//--------------------------------------------------------------------------- + +std::string Tokenizer::fileLine(const Token *tok) const +{ + std::ostringstream ostr; + ostr << "[" << _files.at(tok->fileIndex()) << ":" << tok->linenr() << "]"; + return ostr.str(); +} + +std::string Tokenizer::file(const Token *tok) const +{ + return _files.at(tok->fileIndex()); +} + +//--------------------------------------------------------------------------- + +void Tokenizer::syntaxError(const Token *tok) +{ + std::list locationList; + if (tok) + { + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok->linenr(); + loc.setfile(file(tok)); + locationList.push_back(loc); + } + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::error, + "syntax error", + "syntaxError"); + + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); +} + +void Tokenizer::syntaxError(const Token *tok, char c) +{ + std::list locationList; + if (tok) + { + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok->linenr(); + loc.setfile(file(tok)); + locationList.push_back(loc); + } + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::error, + std::string("Invalid number of character (") + + c + + ") " + + "when these macros are defined: '" + + _configuration + + "'.", + "syntaxError"); + + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); +} + +void Tokenizer::cppcheckError(const Token *tok) const +{ + std::list locationList; + if (tok) + { + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok->linenr(); + loc.setfile(file(tok)); + locationList.push_back(loc); + } + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::error, + "Analysis failed. If the code is valid then please report this failure.", + "cppcheckError"); + + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); +} + + +void Tokenizer::simplifyMathFunctions() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "atol ( %str% )")) + { + if (!MathLib::isInt(tok->tokAt(2)->strValue())) + { + // Ignore strings which we can't convert + continue; + } + + if (tok->previous() && + Token::simpleMatch(tok->previous()->previous(), "std ::")) + { + // Delete "std ::" + tok = tok->previous()->previous(); + tok->deleteNext(); + tok->deleteThis(); + } + + // Delete atol( + tok->deleteNext(); + tok->deleteThis(); + + // Convert string into a number + tok->str(MathLib::toString(MathLib::toLongNumber(tok->strValue()))); + + // Delete remaining ) + tok->deleteNext(); + } + } +} + +void Tokenizer::simplifyComma() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::simpleMatch(tok, "for (") || + Token::Match(tok, "=|enum {")) + { + tok = tok->next()->link(); + if (!tok) + break; + + continue; + } + + if (tok->str() == "(") + { + tok = tok->link(); + continue; + } + + // Skip unhandled template specifiers.. + if (Token::Match(tok, "%var% <")) + { + // Todo.. use the link instead. + unsigned int comparelevel = 0; + for (Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (tok2->str() == "<") + ++comparelevel; + else if (tok2->str() == ">") + { + if (comparelevel <= 1) + { + tok = tok2; + break; + } + ++comparelevel; + } + else if (Token::Match(tok2, "[;{}]")) + break; + } + } + + // If token after the comma is a constant number, simplification is not required. + if (tok->str() != "," || Token::Match(tok->next(), "%num%")) + continue; + + // We must not accept just any keyword, e.g. accepting int + // would cause function parameters to corrupt. + if (Token::simpleMatch(tok->next(), "delete")) + { + // Handle "delete a, delete b;" + tok->str(";"); + } + + if (tok->previous() && tok->previous()->previous()) + { + if (Token::simpleMatch(tok->previous()->previous(), "delete") && + tok->next()->varId() != 0) + { + // Handle "delete a, b;" + tok->str(";"); + tok->insertToken("delete"); + } + else + { + for (Token *tok2 = tok->previous(); tok2; tok2 = tok2->previous()) + { + if (tok2->str() == "=") + { + // Handle "a = 0, b = 0;" + tok->str(";"); + break; + } + else if (Token::Match(tok2, "delete %var%") || + Token::Match(tok2, "delete [ ] %var%")) + { + // Handle "delete a, a = 0;" + tok->str(";"); + break; + } + else if (Token::Match(tok2, "[;,{}()]")) + { + break; + } + } + } + } + + bool inReturn = false; + Token *startFrom = NULL; // next tokean after "; return" + Token *endAt = NULL; // first ";" token after "; return" + + // find "; return" pattern before comma + for (Token *tok2 = tok; tok2; tok2 = tok2->previous()) + { + if (Token::Match(tok2, "[;{}]")) + { + break; + + } + else if (tok2->str() == "return" && Token::Match(tok2->previous(), "[;{}]")) + { + inReturn = true; + startFrom = tok2->next(); + break; + } + } + + // find token where return ends and also count commas + if (inReturn) + { + size_t commaCounter = 0; + size_t indentlevel = 0; + + for (Token *tok2 = startFrom; tok2; tok2 = tok2->next()) + { + if (tok2->str() == ";") + { + endAt = tok2; + break; + + } + else if (tok2->str() == "(") + { + ++indentlevel; + + } + else if (tok2->str() == ")") + { + --indentlevel; + + } + else if (tok2->str() == "," && indentlevel == 0) + { + ++commaCounter; + } + } + + if (commaCounter) + { + indentlevel = 0; + + // change tokens: + // "; return a ( ) , b ( ) , c ;" + // to + // "; return a ( ) ; b ( ) ; c ;" + for (Token *tok2 = startFrom; tok2 != endAt; tok2 = tok2->next()) + { + if (tok2->str() == "(") + { + ++indentlevel; + + } + else if (tok2->str() == ")") + { + --indentlevel; + + } + else if (tok2->str() == "," && indentlevel == 0) + { + tok2->str(";"); + --commaCounter; + if (commaCounter == 0) + { + tok2->insertToken("return"); + } + } + } + + // delete old "return" + startFrom->previous()->deleteThis(); + startFrom = 0; // give dead pointer a value + + tok = endAt; + if (!tok) + return; + } + } + + } +} + + +void Tokenizer::removeExceptionSpecifications(Token *tok) const +{ + while (tok) + { + if (tok->str() == "{") + tok = tok->link(); + + else if (tok->str() == "}") + break; + + else if (Token::simpleMatch(tok, ") throw (")) + { + Token::eraseTokens(tok, tok->tokAt(2)->link()); + tok->deleteNext(); + } + + else if (Token::Match(tok, "class|namespace|struct %type%")) + { + while (tok && !Token::Match(tok, "[;{]")) + tok = tok->next(); + if (tok && tok->str() == "{") + { + removeExceptionSpecifications(tok->next()); + tok = tok->link(); + } + } + + tok = tok ? tok->next() : 0; + } +} + + + +bool Tokenizer::validate() const +{ + std::stack linktok; + const Token *lastTok = 0; + for (const Token *tok = tokens(); tok; tok = tok->next()) + { + lastTok = tok; + if (Token::Match(tok, "[{([]")) + { + if (tok->link() == 0) + { + cppcheckError(tok); + return false; + } + + linktok.push(tok); + continue; + } + + else if (Token::Match(tok, "[})]]")) + { + if (tok->link() == 0) + { + cppcheckError(tok); + return false; + } + + if (linktok.empty() == true) + { + cppcheckError(tok); + return false; + } + + if (tok->link() != linktok.top()) + { + cppcheckError(tok); + return false; + } + + if (tok != tok->link()->link()) + { + cppcheckError(tok); + return false; + } + + linktok.pop(); + continue; + } + + if (tok->link() != 0) + { + cppcheckError(tok); + return false; + } + } + + if (!linktok.empty()) + { + cppcheckError(linktok.top()); + return false; + } + + // Validate that the Tokenizer::_tokensBack is updated correctly during simplifications + if (lastTok != _tokensBack) + { + cppcheckError(lastTok); + return false; + } + + return true; +} + +std::string Tokenizer::simplifyString(const std::string &source) +{ + std::string str = source; + + // true when previous char is a \ . + bool escaped = false; + for (std::string::size_type i = 0; i + 2 < str.size(); i++) + { + if (!escaped) + { + if (str[i] == '\\') + escaped = true; + + continue; + } + + if (str[i] == 'x') + { + // Hex value + if (str[i+1] == '0' && str[i+2] == '0') + str.replace(i, 3, "0"); + else if (i > 0) + { + // We will replace all other character as 'a' + // If that causes problems in the future, this can + // be improved. But for now, this should be OK. + unsigned int n = 1; + while (n < 2 && std::isxdigit(str[i+1+n])) + ++n; + --i; + n += 2; + str.replace(i, n, "a"); + } + } + else if (MathLib::isOctalDigit(str[i])) + { + if (MathLib::isOctalDigit(str[i+1]) && + MathLib::isOctalDigit(str[i+2])) + { + if (str[i+1] == '0' && str[i+2] == '0') + str.replace(i, 3, "0"); + else + { + // We will replace all other character as 'a' + // If that causes problems in the future, this can + // be improved. But for now, this should be OK. + --i; + str.replace(i, 4, "a"); + } + } + } + + escaped = false; + } + + return str; +} + + +void Tokenizer::simplifyStructInit() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "[;{}] struct| %type% %var% = { . %type% =")) + { + // Goto "." and check if the initializations have an expected format + const Token *tok2 = tok; + while (tok2->str() != ".") + tok2 = tok2->next(); + while (tok2 && tok2->str() == ".") + { + if (Token::Match(tok2, ". %type% = %num% [,}]")) + tok2 = tok2->tokAt(4); + else if (Token::Match(tok2, ". %type% = %var% [,}]")) + tok2 = tok2->tokAt(4); + else if (Token::Match(tok2, ". %type% = & %var% [,}]")) + tok2 = tok2->tokAt(5); + else + break; + + if (Token::simpleMatch(tok2, ", .")) + tok2 = tok2->next(); + } + if (!Token::simpleMatch(tok2, "} ;")) + continue; + + // Known expression format => Perform simplification + Token *vartok = tok->tokAt(3); + if (vartok->str() == "=") + vartok = vartok->previous(); + vartok->next()->str(";"); + + Token *tok3 = vartok->tokAt(2); + tok3->link(0); + while (Token::Match(tok3, "[{,] . %type% =")) + { + tok3->str(vartok->str()); + tok3->varId(vartok->varId()); + tok3 = tok3->tokAt(5); + while (!Token::Match(tok3, "[,}]")) + tok3 = tok3->next(); + if (tok3->str() == "}") + { + tok3->deleteThis(); + break; + } + tok3->previous()->insertToken(";"); + } + } + } +} + + +void Tokenizer::simplifyComparisonOrder() +{ + // Use "<" comparison instead of ">" + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "[;(] %any% >|>= %any% [);]")) + { + if (!tok->next()->isName() && !tok->next()->isNumber()) + continue; + const std::string op1(tok->strAt(1)); + tok->next()->str(tok->strAt(3)); + tok->tokAt(3)->str(op1); + if (tok->tokAt(2)->str() == ">") + tok->tokAt(2)->str("<"); + else + tok->tokAt(2)->str("<="); + } + else if (Token::Match(tok, "( %num% ==|!= %var% )")) + { + if (!tok->next()->isName() && !tok->next()->isNumber()) + continue; + const std::string op1(tok->strAt(1)); + tok->next()->str(tok->strAt(3)); + tok->tokAt(3)->str(op1); + } + } +} + +void Tokenizer::simplifyConst() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "[;{}(,] %type% const") && + tok->next()->str().find(":") == std::string::npos && + tok->next()->str() != "operator") + { + tok->tokAt(2)->str(tok->tokAt(1)->str()); + tok->tokAt(1)->str("const"); + } + } +} + +void Tokenizer::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) +{ + Tokenizer t(settings, errorLogger); + t.syntaxError(0, ' '); + t.cppcheckError(0); +} + +/** find pattern */ +static bool findmatch(const Token *tok1, const Token *tok2, const char pattern[]) +{ + for (const Token *tok = tok1; tok && tok != tok2; tok = tok->next()) + { + if (Token::Match(tok, pattern)) + return true; + } + return false; +} + +void Tokenizer::simplifyWhile0() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + // while (0) + const bool while0(Token::Match(tok, "while ( 0|false )")); + + // for (0) + const bool for0(Token::Match(tok, "for ( %var% = %num% ; %var% < %num% ;") && + tok->strAt(2) == tok->strAt(6) && + tok->strAt(4) == tok->strAt(8)); + + if (!while0 && !for0) + continue; + + if (while0 && Token::simpleMatch(tok->previous(), "}")) + { + // find "do" + Token *tok2 = tok->previous()->link(); + tok2 = tok2 ? tok2->previous() : 0; + if (tok2 && tok2->str() == "do" && !findmatch(tok2, tok, "continue|break")) + { + // delete "do {" + tok2->deleteThis(); + tok2->deleteThis(); + + // delete "} while ( 0 )" + tok = tok->previous(); + tok->deleteNext(); // while + tok->deleteNext(); // ( + tok->deleteNext(); // 0 + tok->deleteNext(); // ) + tok->deleteThis(); // } + + continue; + } + } + + // remove "while (0) { .. }" + if (Token::simpleMatch(tok->next()->link(), ") {")) + { + const Token *end = tok->next()->link()->next()->link(); + if (!findmatch(tok, end, "continue|break")) + { + Token::eraseTokens(tok, end ? end->next() : 0); + tok->deleteThis(); // delete "while" + } + } + + } +} + +void Tokenizer::simplifyErrNoInWhile() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() != "errno") + continue; + + Token *endpar = 0; + if (Token::Match(tok->previous(), "&& errno == EINTR ) { ;| }")) + endpar = tok->tokAt(3); + else if (Token::Match(tok->tokAt(-2), "&& ( errno == EINTR ) ) { ;| }")) + endpar = tok->tokAt(4); + else + continue; + + if (Token::simpleMatch(endpar->link()->previous(), "while (")) + { + Token *tok1 = tok->previous(); + if (tok1->str() == "(") + tok1 = tok1->previous(); + + // erase "&& errno == EINTR" + Token::eraseTokens(tok1->previous(), endpar); + + // tok is invalid.. move to endpar + tok = endpar; + + } + } +} + + +void Tokenizer::simplifyFuncInWhile() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (!Token::Match(tok, "while ( %var% ( %var% ) ) {")) + continue; + + Token *func = tok->tokAt(2); + Token *var = tok->tokAt(4); + Token *end = tok->tokAt(7)->link(); + if (!end) + break; + + tok->str("int"); + tok->insertToken("cppcheck:r"); + tok->tokAt(1)->insertToken("="); + tok->tokAt(2)->insertToken(func->str()); + tok->tokAt(3)->insertToken("("); + tok->tokAt(4)->insertToken(var->str()); + tok->tokAt(5)->varId(var->varId()); + tok->tokAt(5)->insertToken(")"); + tok->tokAt(6)->insertToken(";"); + tok->tokAt(7)->insertToken("while"); + tok->tokAt(9)->insertToken("cppcheck:r"); + Token::createMutualLinks(tok->tokAt(4), tok->tokAt(6)); + end->previous()->insertToken("cppcheck:r"); + end->previous()->insertToken("="); + Token::move(func, func->tokAt(3), end->previous()); + end->previous()->insertToken(";"); + + tok = end; + } +} + +void Tokenizer::simplifyStructDecl() +{ + // A counter that is used when giving unique names for anonymous structs. + unsigned int count = 0; + + // Skip simplification of unions in class definition + std::list skip; + skip.push_back(false); + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + Token *restart; + + if (tok->str() == "{") + skip.push_back(!Token::Match(tok->previous(), "const|)")); + else if (tok->str() == "}" && !skip.empty()) + skip.pop_back(); + else if (!skip.empty() && skip.back() && tok->str() == "union") + continue; + + // check for named struct/union + if (Token::Match(tok, "struct|union %type% :|{")) + { + Token *isStatic = tok->previous() && tok->previous()->str() == "static" ? tok->previous() : NULL; + Token *type = tok->next(); + Token *next = tok->tokAt(2); + + while (next && next->str() != "{") + next = next->next(); + if (!next) + continue; + + tok = next->link(); + restart = next; + + // check for named type + if (Token::Match(tok->next(), "*|&| %type% ,|;|[")) + { + tok->insertToken(";"); + tok = tok->next(); + if (isStatic) + { + isStatic->deleteThis(); + tok->insertToken("static"); + tok = tok->next(); + } + tok->insertToken(type->str().c_str()); + } + + tok = restart; + } + + // check for anonymous struct/union + else if (Token::Match(tok, "struct|union {")) + { + Token *tok1 = tok; + + restart = tok->next(); + tok = tok->next()->link(); + + // check for named type + if (Token::Match(tok->next(), "*|&| %type% ,|;|[")) + { + std::string name; + + name = "Anonymous" + MathLib::toString(count++); + + tok1->insertToken(name.c_str()); + + tok->insertToken(";"); + tok = tok->next(); + tok->insertToken(name.c_str()); + } + + // unnamed anonymous struct/union so remove it + else if (tok->next() && tok->next()->str() == ";") + { + if (tok1->str() == "union") + { + // Try to create references in the union.. + Token *tok2 = tok1->tokAt(2); + while (tok2) + { + if (Token::Match(tok2, "%type% %var% ;")) + tok2 = tok2->tokAt(3); + else + break; + } + if (!Token::simpleMatch(tok2, "} ;")) + continue; + Token *vartok = 0; + tok2 = tok1->tokAt(2); + while (Token::Match(tok2, "%type% %var% ;")) + { + if (!vartok) + { + vartok = tok2->next(); + tok2 = tok2->tokAt(3); + } + else + { + tok2->insertToken("&"); + tok2 = tok2->tokAt(2); + tok2->insertToken(vartok->str()); + tok2->next()->varId(vartok->varId()); + tok2->insertToken("="); + tok2 = tok2->tokAt(4); + } + } + } + + tok1->deleteThis(); + if (tok1->next() == tok) + { + tok1->deleteThis(); + tok = tok1; + } + else + tok1->deleteThis(); + restart = tok1->previous(); + tok->deleteThis(); + if (tok->next()) + tok->deleteThis(); + } + + if (!restart) + { + simplifyStructDecl(); + return; + } + else if (!restart->next()) + return; + + tok = restart; + } + } +} + +void Tokenizer::simplifyCallingConvention() +{ + const char * pattern = "__cdecl|__stdcall|__fastcall|__thiscall|__clrcall|__syscall|__pascal|__fortran|__far|__near|WINAPI|APIENTRY|CALLBACK"; + while (Token::Match(_tokens, pattern)) + { + _tokens->deleteThis(); + } + for (Token *tok = _tokens; tok; tok = tok->next()) + { + while (Token::Match(tok->next(), pattern)) + { + tok->deleteNext(); + } + } +} + +void Tokenizer::simplifyDeclspec() +{ + while (Token::simpleMatch(_tokens, "__declspec (") && _tokens->next()->link() && _tokens->next()->link()->next()) + { + Token::eraseTokens(_tokens, _tokens->next()->link()->next()); + _tokens->deleteThis(); + } + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::simpleMatch(tok, "__declspec (") && tok->next()->link() && tok->next()->link()->next()) + { + Token::eraseTokens(tok, tok->next()->link()->next()); + tok->deleteThis(); + } + } +} + +void Tokenizer::simplifyAttribute() +{ + while (Token::simpleMatch(_tokens, "__attribute__ (") && _tokens->next()->link() && _tokens->next()->link()->next()) + { + Token::eraseTokens(_tokens, _tokens->next()->link()->next()); + _tokens->deleteThis(); + } + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::simpleMatch(tok, "__attribute__ (") && tok->next()->link() && tok->next()->link()->next()) + { + if (Token::simpleMatch(tok->tokAt(2), "( unused )")) + { + // check if after variable name + if (Token::Match(tok->next()->link()->next(), ";|=")) + { + if (Token::Match(tok->previous(), "%type%")) + tok->previous()->isUnused(true); + } + + // check if before variable name + else if (Token::Match(tok->next()->link()->next(), "%type%")) + tok->next()->link()->next()->isUnused(true); + } + + Token::eraseTokens(tok, tok->next()->link()->next()); + tok->deleteThis(); + } + } +} + +// Remove "volatile", "inline", "register", and "restrict" +void Tokenizer::simplifyKeyword() +{ + const char pattern[] = "volatile|inline|__inline|__forceinline|register|restrict|__restrict|__restrict__"; + while (Token::Match(_tokens, pattern)) + { + _tokens->deleteThis(); + } + for (Token *tok = _tokens; tok; tok = tok->next()) + { + while (Token::Match(tok->next(), pattern)) + { + tok->deleteNext(); + } + } +} + +void Tokenizer::simplifyAssignmentInFunctionCall() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "(") + tok = tok->link(); + + // Find 'foo(var='. Exclude 'assert(var=' to allow tests to check that assert(...) does not contain side-effects + else if (Token::Match(tok, "[;{}] %var% ( %var% =") && + Token::simpleMatch(tok->tokAt(2)->link(), ") ;") && + tok->strAt(1) != "assert") + { + const std::string funcname(tok->strAt(1)); + const Token * const vartok = tok->tokAt(3); + + // Goto ',' or ')'.. + for (Token *tok2 = tok->tokAt(4); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "(") + tok2 = tok2->link(); + else if (tok2->str() == ";") + break; + else if (tok2->str() == ")" || tok2->str() == ",") + { + tok2 = tok2->previous(); + + tok2->insertToken(vartok->str()); + tok2->next()->varId(vartok->varId()); + + tok2->insertToken("("); + Token::createMutualLinks(tok2->next(), tok->tokAt(2)->link()); + + tok2->insertToken(funcname); + tok2->insertToken(";"); + + Token::eraseTokens(tok, vartok); + break; + } + } + } + } +} + +// Remove __asm.. +void Tokenizer::simplifyAsm() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok->next(), "__asm|_asm|asm {") && + tok->tokAt(2)->link() && + tok->tokAt(2)->link()->next()) + { + Token::eraseTokens(tok, tok->tokAt(2)->link()->next()); + } + + else if (Token::Match(tok->next(), "asm|__asm|__asm__ volatile|__volatile__| (")) + { + // Goto "(" + Token *partok = tok->tokAt(2); + if (partok->str() != "(") + partok = partok->next(); + Token::eraseTokens(tok, partok->link() ? partok->link()->next() : NULL); + } + + else if (Token::simpleMatch(tok->next(), "__asm")) + { + const Token *tok2 = tok->next(); + while (tok2 && (tok2->isNumber() || tok2->isName() || tok2->str() == ",")) + tok2 = tok2->next(); + if (tok2 && tok2->str() == ";") + Token::eraseTokens(tok, tok2); + else + continue; + } + + else + continue; + + // insert "asm ( )" + tok->insertToken(")"); + tok->insertToken("("); + tok->insertToken("asm"); + + Token::createMutualLinks(tok->tokAt(2), tok->tokAt(3)); + } +} + +// Simplify bitfields +void Tokenizer::simplifyBitfields() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + Token *last = 0; + + if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% %var% : %any% ;|,") && + tok->next()->str() != "case") + { + int offset = 0; + if (tok->next()->str() == "const") + offset = 1; + + last = tok->tokAt(5 + offset); + Token::eraseTokens(tok->tokAt(2 + offset), tok->tokAt(5 + offset)); + } + else if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% : %any% ;") && + tok->next()->str() != "default") + { + int offset = 0; + if (tok->next()->str() == "const") + offset = 1; + + Token::eraseTokens(tok->tokAt(0), tok->tokAt(5 + offset)); + tok = tok->previous(); + } + + if (last && last->str() == ",") + { + Token *tok1 = last; + tok1->str(";"); + + Token *tok2 = tok->next(); + tok1->insertToken(tok2->str()); + tok1 = tok1->next(); + tok1->isSigned(tok2->isSigned()); + tok1->isUnsigned(tok2->isUnsigned()); + tok1->isLong(tok2->isLong()); + } + } +} + + +// Remove __builtin_expect(...), likely(...), and unlikely(...) +void Tokenizer::simplifyBuiltinExpect() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::simpleMatch(tok->next(), "__builtin_expect (")) + { + // Count parantheses for tok2 + unsigned int parlevel = 0; + for (Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "(") + ++parlevel; + else if (tok2->str() == ")") + { + if (parlevel <= 1) + break; + --parlevel; + } + if (parlevel == 1 && tok2->str() == ",") + { + if (Token::Match(tok2, ", %num% )")) + { + tok->deleteNext(); + Token::eraseTokens(tok2->previous(), tok2->tokAt(2)); + } + break; + } + } + } + else if (Token::Match(tok->next(), "likely|unlikely (")) + { + // remove closing ')' + tok->tokAt(2)->link()->previous()->deleteNext(); + + // remove "likely|unlikely (" + tok->deleteNext(); + tok->deleteNext(); + } + } +} + + +// Remove Microsoft MFC 'DECLARE_MESSAGE_MAP()' +void Tokenizer::simplifyMicrosoftMFC() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::simpleMatch(tok->next(), "DECLARE_MESSAGE_MAP ( )")) + { + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + } + else if (Token::Match(tok->next(), "DECLARE_DYNAMIC|DECLARE_DYNAMIC_CLASS|DECLARE_DYNCREATE ( %any% )")) + { + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + } + } +} + + +// Remove Borland code +void Tokenizer::simplifyBorland() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "( __closure * %var% )")) + { + tok->deleteNext(); + } + } + + // I think that these classes are always declared at the outer scope + // I save some time by ignoring inner classes. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "{") + { + tok = tok->link(); + if (!tok) + break; + } + + if (Token::Match(tok, "class %var% :|{")) + { + // count { and } for tok2 + unsigned int indentlevel = 0; + for (Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (tok2->str() == "{") + { + if (indentlevel == 0) + indentlevel = 1; + else + tok2 = tok2->link(); + } + else if (tok2->str() == "}") + { + break; + } + else if (tok2->str() == "__property" && + Token::Match(tok2->previous(), ";|{|}|protected:|public:|__published:")) + { + while (tok2->next() && !Token::Match(tok2, "{|;")) + tok2->deleteThis(); + if (Token::simpleMatch(tok2, "{")) + { + Token::eraseTokens(tok2, tok2->link()); + tok2->deleteThis(); + tok2->deleteThis(); + + // insert "; __property ;" + tok2->previous()->insertToken(";"); + tok2->previous()->insertToken("__property"); + tok2->previous()->insertToken(";"); + } + } + } + } + } +} + +// Remove Qt signals and slots +void Tokenizer::simplifyQtSignalsSlots() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (!Token::Match(tok, "class %var% :")) + continue; + + if (tok->previous() && tok->previous()->str() == "enum") + { + tok = tok->tokAt(2); + continue; + } + + // count { and } for tok2 + unsigned int indentlevel = 0; + for (Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (tok2->str() == "{") + { + indentlevel++; + if (indentlevel == 1) + tok = tok2; + else + tok2 = tok2->link(); + } + else if (tok2->str() == "}") + { + indentlevel--; + if (indentlevel == 0) + break; + } + + if (Token::simpleMatch(tok2->next(), "Q_OBJECT")) + { + tok2->deleteNext(); + } + else if (Token::Match(tok2->next(), "public|protected|private slots|Q_SLOTS :")) + { + tok2 = tok2->next(); + tok2->str(tok2->str() + ":"); + tok2->deleteNext(); + tok2->deleteNext(); + } + else if (Token::Match(tok2->next(), "signals|Q_SIGNALS :")) + { + tok2 = tok2->next(); + tok2->str("protected:"); + tok2->deleteNext(); + } + } + } +} + +const SymbolDatabase *Tokenizer::getSymbolDatabase() const +{ + if (!_symbolDatabase) + _symbolDatabase = new SymbolDatabase(this, _settings, _errorLogger); + + return _symbolDatabase; +} + +void Tokenizer::simplifyOperatorName() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "operator") + { + // operator op + std::string op; + Token *par = tok->next(); + bool done = false; + while (!done && par) + { + done = true; + if (par && par->isName()) + { + op += par->str(); + par = par->next(); + done = false; + } + if (Token::Match(par, "[<>+-*&/=.]") || Token::Match(par, "==|!=|<=|>=")) + { + op += par->str(); + par = par->next(); + done = false; + } + if (Token::simpleMatch(par, "[ ]")) + { + op += "[]"; + par = par->next()->next(); + done = false; + } + if (Token::Match(par, "( *| )")) + { + // break out and simplify.. + if (Token::Match(par, "( ) const| [=;{),]")) + break; + + while (par->str() != ")") + { + op += par->str(); + par = par->next(); + } + op += ")"; + par = par->next(); + done = false; + } + } + + if (par && Token::Match(par->link(), ") const| [=;{),]")) + { + tok->str("operator" + op); + Token::eraseTokens(tok,par); + } + } + } +} + +// remove unnecessary member qualification.. +struct ClassInfo +{ + std::string className; + Token *end; +}; + +void Tokenizer::removeUnnecessaryQualification() +{ + std::stack classInfo; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "class|struct %type% :|{") && + (!tok->previous() || (tok->previous() && tok->previous()->str() != "enum"))) + { + tok = tok->next(); + ClassInfo info; + info.className = tok->str(); + tok = tok->next(); + while (tok && tok->str() != "{") + tok = tok->next(); + if (!tok) + return; + info.end = tok->link(); + classInfo.push(info); + } + else if (!classInfo.empty()) + { + if (tok == classInfo.top().end) + classInfo.pop(); + else if (tok->str() == classInfo.top().className && + Token::Match(tok, "%type% :: %type% (") && + Token::Match(tok->tokAt(3)->link(), ") const| {|;") && + tok->previous()->str() != ":") + { + std::list locationList; + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok->linenr(); + loc.setfile(file(tok)); + locationList.push_back(loc); + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::portability, + "Extra qualification \'" + tok->str() + "::\' unnecessary and considered an error by many compilers.", + "portability"); + + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); + + tok->deleteThis(); + tok->deleteThis(); + } + } + } +} + diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index def7e688e..96ec83945 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -113,7 +113,6 @@ private: TEST_CASE(template20); TEST_CASE(template21); TEST_CASE(template22); - TEST_CASE(template23); TEST_CASE(template_unhandled); TEST_CASE(template_default_parameter); TEST_CASE(template_default_type); @@ -2026,23 +2025,6 @@ private: ASSERT_EQUALS(expected, sizeof_(code)); } - void template23() - { - const char code[] = "template void foo(double &ac) {}\n" - "\n" - "void bar() {\n" - " std::cout << (foo(r));\n" - "}\n"; - - const char expected[] = "; " - "void bar ( ) {" - " std :: cout << ( foo ( r ) ) ; " - "} " - "void foo ( double & ac ) { }"; - - ASSERT_EQUALS(expected, sizeof_(code)); - } - void template_unhandled() { @@ -2823,4 +2805,3773 @@ private: { const char code[] = "void foo(int x)\n" - \ No newline at end of file + "{\n" + " goto A;\n" + "A:\n" + " fooA();\n" + " goto B;\n" + " fooNever();\n" + "B:\n" + " fooB();\n" + " return 3;\n" + "}"; + + const char expect[] = "void foo ( int x ) " + "{ " + "fooA ( ) ; " + "fooB ( ) ; " + "return 3 ; " + "fooA ( ) ; " + "fooB ( ) ; " + "return 3 ; " + "fooNever ( ) ; " + "fooB ( ) ; " + "return 3 ; " + "}"; + + ASSERT_EQUALS(expect, tok(code)); + } + + { + const char code[] = "void foo(int x)\n" + "{\n" + " goto A;\n" + "A:\n" + " fooA();\n" + " if( x ) { goto B; }\n" + " fooNever();\n" + "B:\n" + " fooB();\n" + " return 3;\n" + "}"; + + const char expect[] = "void foo ( int x ) " + "{ " + "fooA ( ) ; " + "if ( x ) { " + "fooB ( ) ; " + "return 3 ; } " + "fooNever ( ) ; " + "fooB ( ) ; " + "return 3 ; " + "fooA ( ) ; " + "if ( x ) { " + "fooB ( ) ; " + "return 3 ; } " + "fooNever ( ) ; " + "fooB ( ) ; " + "return 3 ; " + "}"; + + ASSERT_EQUALS(expect, tok(code)); + } + } + + void goto2() + { + // Don't simplify goto inside function call (macro) + const char code[] = "void f ( ) { slist_iter ( if ( a ) { goto dont_write ; } dont_write : ; x ( ) ; ) ; }"; + ASSERT_EQUALS(code, tok(code)); + } + + void strcat1() + { + const char code[] = "; strcat(strcat(strcat(strcat(strcat(strcat(dst, \"this \"), \"\"), \"is \"), \"a \"), \"test\"), \".\");"; + const char expect[] = "; " + "strcat ( dst , \"this \" ) ; " + "strcat ( dst , \"\" ) ; " + "strcat ( dst , \"is \" ) ; " + "strcat ( dst , \"a \" ) ; " + "strcat ( dst , \"test\" ) ; " + "strcat ( dst , \".\" ) ;"; + + ASSERT_EQUALS(expect, tok(code)); + } + void strcat2() + { + const char code[] = "; strcat(strcat(dst, foo[0]), \" \");"; + const char expect[] = "; " + "strcat ( dst , foo [ 0 ] ) ; " + "strcat ( dst , \" \" ) ;"; + + ASSERT_EQUALS(expect, tok(code)); + } + + void argumentsWithSameName() + { + // This code has syntax error, two variables can not have the same name + { + const char code[] = "void foo(x, x)\n" + " int x;\n" + " int x;\n" + "{}\n"; + ASSERT_EQUALS("void foo ( x , x ) int x ; int x ; { }", tok(code)); + } + + { + const char code[] = "void foo(x, y)\n" + " int x;\n" + " int x;\n" + "{}\n"; + ASSERT_EQUALS("void foo ( int x , y ) int x ; { }", tok(code)); + } + } + + void simplifyAtol() + { + ASSERT_EQUALS("a = std :: atol ( x ) ;", tok("a = std::atol(x);")); + ASSERT_EQUALS("a = atol ( \"text\" ) ;", tok("a = atol(\"text\");")); + ASSERT_EQUALS("a = 0 ;", tok("a = std::atol(\"0\");")); + ASSERT_EQUALS("a = 10 ;", tok("a = atol(\"0xa\");")); + } + + void simplifyHexInString() + { + ASSERT_EQUALS("\"a\"", tok("\"\\x61\"")); + ASSERT_EQUALS("\"a\"", tok("\"\\141\"")); + + ASSERT_EQUALS("\"\\0\"", tok("\"\\x00\"")); + ASSERT_EQUALS("\"\\0\"", tok("\"\\000\"")); + + ASSERT_EQUALS("\"\\nhello\"", tok("\"\\nhello\"")); + + ASSERT_EQUALS("\"aaa\"", tok("\"\\x61\\x61\\x61\"")); + ASSERT_EQUALS("\"aaa\"", tok("\"\\141\\141\\141\"")); + + ASSERT_EQUALS("\"\\\\x61\"", tok("\"\\\\x61\"")); + + // These tests can fail, if other characters are handled + // more correctly. But for now all non null characters should + // become 'a' + ASSERT_EQUALS("\"a\"", tok("\"\\x62\"")); + ASSERT_EQUALS("\"a\"", tok("\"\\177\"")); + } + + + std::string simplifyTypedef(const char code[]) + { + errout.str(""); + + Settings settings; + Tokenizer tokenizer(&settings, this); + + std::istringstream istr(code); + tokenizer.createTokens(istr); + tokenizer.createLinks(); + tokenizer.simplifyTypedef(); + + std::string ret; + for (const Token *tok1 = tokenizer.tokens(); tok1; tok1 = tok1->next()) + { + if (tok1 != tokenizer.tokens()) + ret += " "; + ret += tok1->str(); + } + + return ret; + } + + + + void simplifyTypedef1() + { + const char code[] = "class A\n" + "{\n" + "public:\n" + " typedef wchar_t duplicate;\n" + " void foo() {}\n" + "};\n" + "typedef A duplicate;\n" + "int main()\n" + "{\n" + " duplicate a;\n" + " a.foo();\n" + " A::duplicate c = 0;\n" + "}\n"; + + const std::string expected = + "class A " + "{ " + "public: " + "; " + "void foo ( ) { } " + "} ; " + "int main ( ) " + "{ " + "A a ; " + "a . foo ( ) ; " + "wchar_t c ; c = 0 ; " + "}"; + ASSERT_EQUALS(expected, tok(code)); + } + + void simplifyTypedef2() + { + const char code[] = "class A;\n" + "typedef A duplicate;\n" + "class A\n" + "{\n" + "public:\n" + "typedef wchar_t duplicate;\n" + "duplicate foo() { wchar_t b; return b; }\n" + "};\n"; + + const std::string expected = + "class A ; " + "class A " + "{ " + "public: " + "; " + "wchar_t foo ( ) { wchar_t b ; return b ; } " + "} ;"; + ASSERT_EQUALS(expected, tok(code)); + } + + void simplifyTypedef3() + { + const char code[] = "class A {};\n" + "typedef A duplicate;\n" + "wchar_t foo()\n" + "{\n" + "typedef wchar_t duplicate;\n" + "duplicate b;\n" + "return b;\n" + "}\n" + "int main()\n" + "{\n" + "duplicate b;\n" + "}\n"; + + const std::string expected = + "class A { } ; " + "wchar_t foo ( ) " + "{ " + "; " + "wchar_t b ; " + "return b ; " + "} " + "int main ( ) " + "{ " + "A b ; " + "}"; + ASSERT_EQUALS(expected, tok(code)); + } + + void simplifyTypedef4() + { + const char code[] = "typedef int s32;\n" + "typedef unsigned int u32;\n" + "void f()\n" + "{\n" + " s32 ivar = -2;\n" + " u32 uvar = 2;\n" + " return uvar / ivar;\n" + "}\n"; + + const std::string expected = + "; " + "void f ( ) " + "{ " + "int ivar ; ivar = -2 ; " + "unsigned int uvar ; uvar = 2 ; " + "return uvar / ivar ; " + "}"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef5() + { + // ticket #780 + const char code[] = + "typedef struct yy_buffer_state *YY_BUFFER_STATE;\n" + "void f()\n" + "{\n" + " YY_BUFFER_STATE state;\n" + "}\n"; + + const char expected[] = + "; " + "void f ( ) " + "{ " + "struct yy_buffer_state * state ; " + "}"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef6() + { + // ticket #983 + const char code[] = + "namespace VL {\n" + " typedef float float_t ;\n" + " inline VL::float_t fast_atan2(VL::float_t y, VL::float_t x){}\n" + "}\n"; + + const char expected[] = + "namespace VL { " + "; " + "float fast_atan2 ( float y , float x ) { } " + "}"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef7() + { + const char code[] = "typedef int abc ; " + "Fred :: abc f ;"; + const char expected[] = + "; " + "Fred :: abc f ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef8() + { + const char code[] = "typedef int INT;\n" + "typedef unsigned int UINT;\n" + "typedef int * PINT;\n" + "typedef unsigned int * PUINT;\n" + "typedef int & RINT;\n" + "typedef unsigned int & RUINT;\n" + "typedef const int & RCINT;\n" + "typedef const unsigned int & RCUINT;\n" + "INT ti;\n" + "UINT tui;\n" + "PINT tpi;\n" + "PUINT tpui;\n" + "RINT tri;\n" + "RUINT trui;\n" + "RCINT trci;\n" + "RCUINT trcui;"; + + const char expected[] = + "; " + "int ti ; " + "unsigned int tui ; " + "int * tpi ; " + "unsigned int * tpui ; " + "int & tri ; " + "unsigned int & trui ; " + "const int & trci ; " + "const unsigned int & trcui ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef9() + { + const char code[] = "typedef struct s S, * PS;\n" + "typedef struct t { int a; } T, *TP;\n" + "typedef struct { int a; } U;\n" + "typedef struct { int a; } * V;\n" + "S s;\n" + "PS ps;\n" + "T t;\n" + "TP tp;\n" + "U u;\n" + "V v;"; + + const char expected[] = + "; " + "struct t { int a ; } ; " + "struct U { int a ; } ; " + "struct Unnamed0 { int a ; } ; " + "struct s s ; " + "struct s * ps ; " + "struct t t ; " + "struct t * tp ; " + "struct U u ; " + "struct Unnamed0 * v ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef10() + { + const char code[] = "typedef union s S, * PS;\n" + "typedef union t { int a; float b ; } T, *TP;\n" + "typedef union { int a; float b; } U;\n" + "typedef union { int a; float b; } * V;\n" + "S s;\n" + "PS ps;\n" + "T t;\n" + "TP tp;\n" + "U u;\n" + "V v;"; + + const char expected[] = + "; " + "union t { int a ; float b ; } ; " + "union U { int a ; float b ; } ; " + "union Unnamed1 { int a ; float b ; } ; " + "union s s ; " + "union s * ps ; " + "union t t ; " + "union t * tp ; " + "union U u ; " + "union Unnamed1 * v ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef11() + { + const char code[] = "typedef enum { a = 0 , b = 1 , c = 2 } abc;\n" + "typedef enum xyz { x = 0 , y = 1 , z = 2 } XYZ;\n" + "abc e1;\n" + "XYZ e2;"; + + const char expected[] = + "; " + "int e1 ; " + "int e2 ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef12() + { + const char code[] = "typedef vector V1;\n" + "typedef std::vector V2;\n" + "typedef std::vector > V3;\n" + "typedef std::list::iterator IntListIterator;\n" + "V1 v1;\n" + "V2 v2;\n" + "V3 v3;\n" + "IntListIterator iter;"; + + const char expected[] = + "; " + "vector < int > v1 ; " + "std :: vector < int > v2 ; " + "std :: vector < std :: vector < int > > v3 ; " + "std :: list < int > :: iterator iter ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef13() + { + // ticket # 1167 + const char code[] = "typedef std::pair Func;" + "typedef std::vector CallQueue;" + "int main() {}"; + + // Clear the error buffer.. + errout.str(""); + + Settings settings; + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + + tokenizer.simplifyTokenList(); + + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef14() + { + // ticket # 1232 + const char code[] = "template struct E" + "{" + " typedef E0)?(N-1):0> v;" + " typedef typename add::val val;" + " FP_M(val);" + "};" + "template struct E " + "{" + " typedef typename D<1>::val val;" + " FP_M(val);" + "};"; + + // Clear the error buffer.. + errout.str(""); + + Settings settings; + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + + tokenizer.simplifyTokenList(); + + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef15() + { + { + const char code[] = "typedef char frame[10];\n" + "frame f;"; + + const char expected[] = + "; " + "char f [ 10 ] ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "typedef unsigned char frame[10];\n" + "frame f;"; + + const char expected[] = + "; " + "unsigned char f [ 10 ] ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyTypedef16() + { + // ticket # 1252 + const char code[] = "typedef char MOT8;\n" + "typedef MOT8 CHFOO[4096];\n" + "typedef struct {\n" + " CHFOO freem;\n" + "} STRFOO;"; + + // Clear the error buffer.. + errout.str(""); + + Settings settings; + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + + tokenizer.simplifyTokenList(); + + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef17() + { + const char code[] = "typedef char * PCHAR, CHAR;\n" + "PCHAR pc;\n" + "CHAR c;"; + + const char expected[] = + "; " + "char * pc ; " + "char c ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef18() + { + const char code[] = "typedef vector a;\n" + "a b;\n"; + + // Clear the error buffer.. + errout.str(""); + + Settings settings; + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + + tokenizer.simplifyTokenList(); + + ASSERT_EQUALS(true, tokenizer.validate()); + } + + void simplifyTypedef19() + { + { + // ticket #1275 + const char code[] = "typedef struct {} A, *B, **C;\n" + "A a;\n" + "B b;\n" + "C c;"; + + const char expected[] = + "struct A { } ; " + "struct A a ; " + "struct A * b ; " + "struct A * * c ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "typedef struct {} A, *********B;\n" + "A a;\n" + "B b;"; + + const char expected[] = + "struct A { } ; " + "struct A a ; " + "struct A * * * * * * * * * b ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "typedef struct {} **********A, *B, C;\n" + "A a;\n" + "B b;\n" + "C c;"; + + const char expected[] = + "struct Unnamed2 { } ; " + "struct Unnamed2 * * * * * * * * * * a ; " + "struct Unnamed2 * b ; " + "struct Unnamed2 c ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyTypedef20() + { + // ticket #1284 + const char code[] = "typedef jobject invoke_t (jobject, Proxy *, Method *, JArray< jobject > *);"; + + // Clear the error buffer.. + errout.str(""); + + Settings settings; + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + + tokenizer.simplifyTokenList(); + + ASSERT_EQUALS(true, tokenizer.validate()); + } + + void simplifyTypedef21() + { + const char code[] = "typedef void (* PF)();\n" + "typedef void * (* PFV)(void *);\n" + "PF pf;\n" + "PFV pfv;"; + + const char expected[] = + "; " + "; " + "void ( * pf ) ( ) ; " + "void * ( * pfv ) ( void * ) ;"; + + ASSERT_EQUALS(expected, simplifyTypedef(code)); + } + + void simplifyTypedef22() + { + { + const char code[] = "class Fred {\n" + " typedef void (*testfp)();\n" + " testfp get() { return test; }\n" + " static void test() { }\n" + "};"; + + const char expected[] = + "class Fred { " + "; " + "void ( * get ( ) ) ( ) { return test ; } " + "static void test ( ) { } " + "} ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "class Fred {\n" + " typedef void * (*testfp)(void *);\n" + " testfp get() { return test; }\n" + " static void * test(void * p) { return p; }\n" + "};\n"; + + const char expected[] = + "class Fred { " + "; " + "void * ( * get ( ) ) ( void * ) { return test ; } " + "static void * test ( void * p ) { return p ; } " + "} ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "class Fred {\n" + " typedef unsigned int * (*testfp)(unsigned int *);\n" + " testfp get() { return test; }\n" + " static unsigned int * test(unsigned int * p) { return p; }\n" + "};\n"; + + const char expected[] = + "class Fred { " + "; " + "unsigned int * ( * get ( ) ) ( unsigned int * ) { return test ; } " + "static unsigned int * test ( unsigned int * p ) { return p ; } " + "} ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "class Fred {\n" + " typedef const unsigned int * (*testfp)(const unsigned int *);\n" + " testfp get() { return test; }\n" + " static const unsigned int * test(const unsigned int * p) { return p; }\n" + "};\n"; + + // static const gets changed to const static + const char expected[] = + "class Fred { " + "; " + "const unsigned int * ( * get ( ) ) ( const unsigned int * ) { return test ; } " + "const static unsigned int * test ( const unsigned int * p ) { return p ; } " + "} ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "class Fred {\n" + " typedef void * (*testfp)(void *);\n" + " testfp get(int i) { return test; }\n" + " static void * test(void * p) { return p; }\n" + "};\n"; + + const char expected[] = + "class Fred { " + "; " + "void * ( * get ( int i ) ) ( void * ) { return test ; } " + "static void * test ( void * p ) { return p ; } " + "} ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyTypedef23() + { + const char code[] = "typedef bool (*Callback) (int i);\n" + "void addCallback(Callback callback) { }\n" + "void addCallback1(Callback callback, int j) { }"; + + const char expected[] = + "; " + "void addCallback ( bool * callback ) { } " + "void addCallback1 ( bool * callback , int j ) { }"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef24() + { + { + const char code[] = "typedef int (*fp)();\n" + "void g( fp f )\n" + "{\n" + " fp f2 = (fp)f;\n" + "}"; + + const char expected[] = + "; " + "void g ( int * f ) " + "{ " + "int * f2 ; f2 = ( int * ) f ; " + "}"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "typedef int (*fp)();\n" + "void g( fp f )\n" + "{\n" + " fp f2 = static_cast(f);\n" + "}"; + + const char expected[] = + "; " + "void g ( int * f ) " + "{ " + "int * f2 ; f2 = static_cast < int * > ( f ) ; " + "}"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyTypedef25() + { + { + // ticket #1298 + const char code[] = "typedef void (*fill_names_f) (const char *);\n" + "struct vfs_class {\n" + " void (*fill_names) (struct vfs_class *me, fill_names_f);\n" + "}"; + + const char expected[] = + "; " + "struct vfs_class { " + "void ( * fill_names ) ( struct vfs_class * me , void ( * ) ( const char * ) ) ; " + "}"; + + ASSERT_EQUALS(expected, simplifyTypedef(code)); + } + + { + const char code[] = "typedef void (*fill_names_f) (const char *);\n" + "struct vfs_class {\n" + " void (*fill_names) (fill_names_f, struct vfs_class *me);\n" + "}"; + + const char expected[] = + "; " + "struct vfs_class { " + "void ( * fill_names ) ( void ( * ) ( const char * ) , struct vfs_class * me ) ; " + "}"; + + ASSERT_EQUALS(expected, simplifyTypedef(code)); + } + } + + void simplifyTypedef26() + { + { + const char code[] = "typedef void (*Callback) ();\n" + "void addCallback(Callback (*callback)());"; + + const char expected[] = + "; " + "void addCallback ( void ( * ( * callback ) ( ) ) ( ) ) ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + // ticket # 1307 + const char code[] = "typedef void (*pc_video_update_proc)(bitmap_t *bitmap,\n" + "struct mscrtc6845 *crtc);\n" + "\n" + "struct mscrtc6845 *pc_video_start(pc_video_update_proc (*choosevideomode)(running_machine *machine, int *width, int *height, struct mscrtc6845 *crtc));"; + + const char expected[] = + "; " + "struct mscrtc6845 * pc_video_start ( void ( * ( * choosevideomode ) ( running_machine * machine , int * width , int * height , struct mscrtc6845 * crtc ) ) ( bitmap_t * bitmap , struct mscrtc6845 * crtc ) ) ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyTypedef27() + { + // ticket #1316 + const char code[] = "int main()\n" + "{\n" + " typedef int (*func_ptr)(float, double);\n" + " VERIFY((is_same::type, int>::value));\n" + "}"; + + const char expected[] = + "int main ( ) " + "{ " + "; " + "VERIFY ( is_same < result_of < int ( * ( char , float ) ) ( float , double ) > :: type , int > :: value ) ; " + "}"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef28() + { + const char code[] = "typedef std::pair (*F)(double);\n" + "F f;"; + + const char expected[] = + "; " + "std :: pair < double , double > ( * f ) ( double ) ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef29() + { + const char code[] = "typedef int array [ice_or::value, is_int::value>::value ? 1 : -1];\n" + "typedef int array1 [N];\n" + "typedef int array2 [N][M];\n" + "typedef int int_t, int_array[N];\n" + "array a;\n" + "array1 a1;\n" + "array2 a2;\n" + "int_t t;\n" + "int_array ia;"; + + const char expected[] = + "; " + "int a [ ice_or < is_int < int > :: value , is_int < UDT > :: value > :: value ? 1 : - 1 ] ; " + "int a1 [ N ] ; " + "int a2 [ N ] [ M ] ; " + "int t ; " + "int ia [ N ] ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef30() + { + const char code[] = "typedef ::std::list int_list;\n" + "typedef ::std::list::iterator int_list_iterator;\n" + "typedef ::std::list int_list_array[10];\n" + "int_list il;\n" + "int_list_iterator ili;\n" + "int_list_array ila;"; + + const char expected[] = + "; " + ":: std :: list < int > il ; " + ":: std :: list < int > :: iterator ili ; " + ":: std :: list < int > ila [ 10 ] ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef31() + { + { + const char code[] = "class A {\n" + "public:\n" + " typedef int INT;\n" + " INT get() const;\n" + " void put(INT x) { a = x; }\n" + " INT a;\n" + "};\n" + "A::INT A::get() const { return a; }\n" + "A::INT i = A::a;"; + + const char expected[] = "class A { " + "public: " + "; " + "int get ( ) const ; " + "void put ( int x ) { a = x ; } " + "int a ; " + "} ; " + "int A :: get ( ) const { return a ; } " + "int i ; i = A :: a ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct A {\n" + " typedef int INT;\n" + " INT get() const;\n" + " void put(INT x) { a = x; }\n" + " INT a;\n" + "};\n" + "A::INT A::get() const { return a; }\n" + "A::INT i = A::a;"; + + const char expected[] = "struct A { " + "; " + "int get ( ) const ; " + "void put ( int x ) { a = x ; } " + "int a ; " + "} ; " + "int A :: get ( ) const { return a ; } " + "int i ; i = A :: a ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyTypedef32() + { + const char code[] = "typedef char CHAR;\n" + "typedef CHAR * LPSTR;\n" + "typedef const CHAR * LPCSTR;\n" + "CHAR c;\n" + "LPSTR cp;\n" + "LPCSTR ccp;"; + + const char expected[] = + "; " + "char c ; " + "char * cp ; " + "const char * ccp ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef33() + { + const char code[] = "class A {\n" + "public:\n" + " typedef char CHAR_A;\n" + " CHAR_A funA();\n" + " class B {\n" + " public:\n" + " typedef short SHRT_B;\n" + " SHRT_B funB();\n" + " class C {\n" + " public:\n" + " typedef int INT_C;\n" + " INT_C funC();\n" + " struct D {\n" + " typedef long LONG_D;\n" + " LONG_D funD();\n" + " LONG_D d;\n" + " };\n" + " INT_C c;\n" + " };\n" + " SHRT_B b;\n" + " };\n" + " CHAR_A a;\n" + "};\n" + "A::CHAR_A A::funA() { return a; }\n" + "A::B::SHRT_B A::B::funB() { return b; }\n" + "A::B::C::INT_C A::B::C::funC() { return c; }" + "A::B::C::D::LONG_D A::B::C::D::funD() { return d; }"; + + const char expected[] = + "class A { " + "public: " + "; " + "char funA ( ) ; " + "class B { " + "public: " + "; " + "short funB ( ) ; " + "class C { " + "public: " + "; " + "int funC ( ) ; " + "struct D { " + "; " + "long funD ( ) ; " + "long d ; " + "} ; " + "int c ; " + "} ; " + "short b ; " + "} ; " + "char a ; " + "} ; " + "char A :: funA ( ) { return a ; } " + "short A :: B :: funB ( ) { return b ; } " + "int A :: B :: C :: funC ( ) { return c ; } " + "long A :: B :: C :: D :: funD ( ) { return d ; }"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef34() + { + // ticket #1411 + const char code[] = "class X { };\n" + "typedef X (*foofunc)(const X&);\n" + "int main()\n" + "{\n" + " foofunc *Foo = new foofunc[2];\n" + "}"; + const char expected[] = + "class X { } ; " + "int main ( ) " + "{ " + "X ( * * Foo ) ( const X & ) = new X ( * ) ( const X & ) [ 2 ] ; " + "}"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + // Check simplifyTypedef + void checkSimplifyTypedef(const char code[]) + { + errout.str(""); + // Tokenize.. + Settings settings; + settings.inconclusive = true; + settings._checkCodingStyle = true; + settings.debugwarnings = true; // show warnings about unhandled typedef + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + } + + void simplifyTypedef35() + { + const char code[] = "typedef int A;\n" + "class S\n" + "{\n" + "public:\n" + " typedef float A;\n" + " A a;\n" + " virtual void fun(A x);\n" + "};\n" + "void S::fun(S::A) { };\n" + "class S1 : public S\n" + "{\n" + "public:\n" + " void fun(S::A) { }\n" + "};\n" + "struct T\n" + "{\n" + " typedef A B;\n" + " B b;\n" + "};\n" + "float fun1(float A) { return A; }\n" + "float fun2(float a) { float A = a++; return A; }\n" + "float fun3(int a)\n" + "{\n" + " typedef struct { int a; } A;\n" + " A s; s.a = a;\n" + " return s.a;\n" + "}\n" + "int main()\n" + "{\n" + " A a = 0;\n" + " S::A s = fun1(a) + fun2(a) - fun3(a);\n" + " return a + s;\n" + "}"; + + const char expected[] = "; " + "class S " + "{ " + "public: " + "; " + "float a ; " + "virtual void fun ( float x ) ; " + "} ; " + "void S :: fun ( float ) { } ; " + "class S1 : public S " + "{ " + "public: " + "void fun ( float ) { } " + "} ; " + "struct T " + "{ " + "; " + "int b ; " + "} ; " + "float fun1 ( float A ) { return A ; } " + "float fun2 ( float a ) { float A ; A = a ++ ; return A ; } " + "float fun3 ( int a ) " + "{ " + "struct A { int a ; } ; " + "struct A s ; s . a = a ; " + "return s . a ; " + "} " + "int main ( ) " + "{ " + "int a ; a = 0 ; " + "float s ; s = fun1 ( a ) + fun2 ( a ) - fun3 ( a ) ; " + "return a + s ; " + "}"; + + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:1]: (style) Typedef 'A' hides typedef with same name\n" + "[test.cpp:20] -> [test.cpp:1]: (style) Function parameter 'A' hides typedef with same name\n" + "[test.cpp:21] -> [test.cpp:1]: (style) Variable 'A' hides typedef with same name\n" + "[test.cpp:24] -> [test.cpp:1]: (style) Typedef 'A' hides typedef with same name\n", errout.str()); + } + + void simplifyTypedef36() + { + // ticket #1434 + const char code[] = "typedef void (*TIFFFaxFillFunc)();\n" + "void f(va_list ap)\n" + "{\n" + " *va_arg(ap, TIFFFaxFillFunc*) = 0;\n" + "}"; + const char expected[] = "; " + "void f ( va_list ap ) " + "{ " + "* va_arg ( ap , void ( * * ) ( ) ) = 0 ; " + "}"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef37() + { + { + // ticket #1449 + const char code[] = "template class V {};\n" + "typedef V A;\n" + "typedef int B;\n" + "typedef V A;\n" + "typedef int B;"; + + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:2]: (style) Typedef 'A' hides typedef with same name\n" + "[test.cpp:5] -> [test.cpp:3]: (style) Typedef 'B' hides typedef with same name\n", errout.str()); + } + + { + const char code[] = "typedef int INT;\n" + "void f()\n" + "{\n" + " INT i; { }\n" + "}"; + const char expected[] = "; " + "void f ( ) " + "{ " + "int i ; { } " + "}"; + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyTypedef38() + { + const char code[] = "typedef C A;\n" + "struct AB : public A, public B { };"; + const char expected[] = "; struct AB : public C , public B { } ;"; + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef39() + { + const char code[] = "typedef int A;\n" + "template ::value;"; + const char expected[] = ";"; + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef40() + { + const char code[] = "typedef int A;\n" + "typedef int B;\n" + "template class C { };"; + const char expected[] = ";"; + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:1]: (style) Template parameter 'A' hides typedef with same name\n" + "[test.cpp:3] -> [test.cpp:2]: (style) Template parameter 'B' hides typedef with same name\n", errout.str()); + + checkSimplifyTypedef("typedef tuple t2;\n" + "void ordering_test()\n" + "{\n" + " tuple t2(5, 3.3f);\n" + " BOOST_CHECK(t3 > t2);\n" + "}"); + ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:1]: (style) Template instantiation 't2' hides typedef with same name\n", errout.str()); + + checkSimplifyTypedef("class MyOverflowingUnsigned\n" + "{\n" + "public:\n" + " typedef unsigned self_type::* bool_type;\n" + " operator bool_type() const { return this->v_ ? &self_type::v_ : 0; }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + checkSimplifyTypedef("typedef int (*fptr_type)(int, int);\n" + "struct which_one {\n" + " typedef fptr_type (*result_type)(bool x);\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + checkSimplifyTypedef("class my_configuration\n" + "{\n" + "public:\n" + " template < typename T >\n" + " class hook\n" + " {\n" + " public:\n" + " typedef ::boost::rational rational_type;\n" + " public:\n" + " rational_type ( &r_ )[ 9 ];\n" + " };\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + checkSimplifyTypedef("class A\n" + "{\n" + " typedef B b;\n" + " friend b;\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef41() + { + // ticket #1488 + checkSimplifyTypedef("class Y;\n" + "class X\n" + "{\n" + " typedef Y type;\n" + " friend class type;\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef42() + { + // ticket #1506 + checkSimplifyTypedef("typedef struct A { } A;\n" + "struct A;"); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Struct 'A' forward declaration unnecessary, already declared\n", errout.str()); + + checkSimplifyTypedef("typedef union A { int i; float f; } A;\n" + "union A;"); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Union 'A' forward declaration unnecessary, already declared\n", errout.str()); + + checkSimplifyTypedef("typedef std::map A;\n" + "class A;"); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Class 'A' forward declaration unnecessary, already declared\n", errout.str()); + } + + void simplifyTypedef43() + { + // ticket #1588 + { + const char code[] = "typedef struct foo A;\n" + "struct A\n" + "{\n" + " int alloclen;\n" + "};\n"; + + // The expected result.. + const std::string expected("; " + "struct A " + "{ " + "int alloclen ; " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Struct 'A' hides typedef with same name\n", errout.str()); + } + + { + const char code[] = "typedef union foo A;\n" + "union A\n" + "{\n" + " int alloclen;\n" + "};\n"; + + // The expected result.. + const std::string expected("; " + "union A " + "{ " + "int alloclen ; " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Union 'A' hides typedef with same name\n", errout.str()); + } + + { + const char code[] = "typedef class foo A;\n" + "class A\n" + "{\n" + " int alloclen;\n" + "};\n"; + + // The expected result.. + const std::string expected("; " + "class A " + "{ " + "int alloclen ; " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Class 'A' hides typedef with same name\n", errout.str()); + } + } + + void simplifyTypedef44() + { + { + const char code[] = "typedef std::map Map;\n" + "class MyMap : public Map\n" + "{\n" + "};\n"; + + // The expected result.. + const std::string expected("; " + "class MyMap : public std :: map < std :: string , int > " + "{ " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef std::map Map;\n" + "class MyMap : protected Map\n" + "{\n" + "};\n"; + + // The expected result.. + const std::string expected("; " + "class MyMap : protected std :: map < std :: string , int > " + "{ " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef std::map Map;\n" + "class MyMap : private Map\n" + "{\n" + "};\n"; + + // The expected result.. + const std::string expected("; " + "class MyMap : private std :: map < std :: string , int > " + "{ " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef struct foo { } A;\n" + "struct MyA : public A\n" + "{\n" + "};\n"; + + // The expected result.. + const std::string expected("struct foo { } ; " + "struct MyA : public foo " + "{ " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef class foo { } A;\n" + "class MyA : public A\n" + "{\n" + "};\n"; + + // The expected result.. + const std::string expected("class foo { } ; " + "class MyA : public foo " + "{ " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + } + + void simplifyTypedef45() + { + // ticket # 1613 + const char code[] = "void fn() {\n" + " typedef foo<> bar;\n" + " while (0 > bar(1)) {}\n" + "}"; + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef46() + { + const char code[] = "typedef const struct A { int a; } * AP;\n" + "AP ap;\n"; + + // The expected result.. + const std::string expected("struct A { int a ; } ; " + "const struct A * ap ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef47() + { + { + const char code[] = "typedef std::pair const I;\n" + "I i;"; + + // The expected result.. + const std::string expected("; " + "std :: pair < int , int > const i ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + + { + const char code[] = "typedef void (X:: *F)();\n" + "F f;"; + + // The expected result.. + const std::string expected("; " + "void ( X :: * f ) ( ) ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + } + + void simplifyTypedef48() // ticket #1673 + { + const char code[] = "typedef struct string { } string;\n" + "void foo (LIST *module_name)\n" + "{\n" + " bar(module_name ? module_name->string : 0);\n" + "}\n"; + + // The expected result.. + const std::string expected("struct string { } ; " + "void foo ( LIST * module_name ) " + "{ " + "bar ( module_name ? module_name . string : 0 ) ; " + "}"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef49() // ticket #1691 + { + const char code[] = "class Class2 {\n" + "typedef const Class & Const_Reference;\n" + "void some_method (Const_Reference x) const {}\n" + "void another_method (Const_Reference x) const {}\n" + "}"; + + // The expected result.. + const std::string expected("class Class2 { " + "; " + "void some_method ( const Class & x ) const { } " + "void another_method ( const Class & x ) const { } " + "}"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef50() + { + const char code[] = "typedef char (* type1)[10];\n" + "typedef char (& type2)[10];\n" + "typedef char (& type3)[x];\n" + "typedef char (& type4)[x + 2];\n" + "type1 t1;\n" + "type1 (*tp1)[2];\n" + "type2 t2;\n" + "type3 t3;\n" + "type4 t4;"; + + // The expected result.. + const std::string expected("; " + "char ( * t1 ) [ 10 ] ; " + "char ( * ( * tp1 ) [ 2 ] ) [ 10 ] ; " + "char ( & t2 ) [ 10 ] ; " + "char ( & t3 ) [ x ] ; " + "char ( & t4 ) [ x + 2 ] ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef51() + { + const char code[] = "class A { public: int i; };\n" + "typedef const char (A :: * type1);\n" + "type1 t1 = &A::i;"; + + // The expected result.. + const std::string expected("class A { public: int i ; } ; " + "const char ( A :: * t1 ) = & A :: i ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef52() // ticket #1782 + { + { + const char code[] = "typedef char (* type1)[10];\n" + "type1 foo() { }"; + + // The expected result.. + const std::string expected("; " + "char ( * foo ( ) ) [ 10 ] { }"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef char (* type1)[10];\n" + "LOCAL(type1) foo() { }"; + + // this is invalid C so just make sure it doesn't generate an internal error + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + } + + void simplifyTypedef53() // ticket #1801 + { + { + const char code[] = "typedef int ( * int ( * ) ( ) ) ( ) ;"; + + // this is invalid C so just make sure it doesn't crash + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:1]: (debug) Failed to parse 'typedef int ( * int ( * ) ( ) ) ( ) ;'. The checking continues anyway.\n", errout.str()); + } + + { + const char code[] = "typedef int (*PPDMarkOption)(ppd_file_t *ppd, const char *keyword, const char *option);\n" + "typedef int (*PPDMarkOption)(ppd_file_t *ppd, const char *keyword, const char *option);\n"; + + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Typedef 'PPDMarkOption' hides typedef with same name\n", errout.str()); + } + + { + const char code[] = "typedef int * A;\n" + "typedef int * A;\n"; + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Typedef 'A' hides typedef with same name\n", errout.str()); + } + } + + void simplifyTypedef54() // ticket #1814 + { + const char code[] = "void foo()\n" + "{\n" + " typedef std::basic_string string_type;\n" + " try\n" + " {\n" + " throw string_type(\"leak\");\n" + " }\n" + " catch (const string_type&)\n" + " {\n" + " pthread_exit (0);\n" + " }\n" + "}"; + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef55() + { + const char code[] = "typedef volatile unsigned long * const hwreg_t ;\n" + "typedef void *const t1[2];\n" + "typedef int*const *_Iterator;\n" + "hwreg_t v1;\n" + "t1 v2;\n" + "_Iterator v3;\n"; + + // The expected result.. + const std::string expected("; " + "long * v1 ; " + "void * v2 [ 2 ] ; " + "int * * v3 ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef56() // ticket #1829 + { + const char code[] = "struct C {\n" + " typedef void (*fptr)();\n" + " const fptr pr;\n" + " operator const fptr& () { return pr; }\n" + "};\n"; + + // The expected result.. + const std::string expected("struct C { " + "; " + "const void * pr ; " // this gets simplified to a regular pointer + "operatorconstvoid(*)()& ( ) { return pr ; } " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef57() // ticket #1846 + { + const char code[] = "void foo {\n" + " typedef int A;\n" + " A a = A(1) * A(2);\n" + "};\n"; + + // The expected result.. + const std::string expected("void foo { " + "; " + "int a ; a = int ( 1 ) * int ( 2 ) ; " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef58() // ticket #1963 + { + { + const char code[] = "typedef int vec2_t[2];\n" + "vec2_t coords[4] = {1,2,3,4,5,6,7,8};\n"; + + // The expected result.. + const std::string expected("; " + "int coords [ 4 ] [ 2 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef int vec2_t[2];\n" + "vec2_t coords[4][5][6+1] = {1,2,3,4,5,6,7,8};\n"; + + // The expected result.. + const std::string expected("; " + "int coords [ 4 ] [ 5 ] [ 7 ] [ 2 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + } + + void simplifyTypedef59() // ticket #2011 + { + const char code[] = "template class SomeTemplateClass {\n" + " typedef void (SomeTemplateClass::*MessageDispatcherFunc)(SerialInputMessage&);\n" + "};\n"; + // The expected result.. + const std::string expected(";"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef60() // ticket #2035 + { + const char code[] = "typedef enum {qfalse, qtrue} qboolean;\n" + "typedef qboolean (*localEntitiyAddFunc_t) (struct le_s * le, entity_t * ent);\n" + "void f()\n" + "{\n" + " qboolean b;\n" + " localEntitiyAddFunc_t f;\n" + "}\n"; + // The expected result.. + const std::string expected("; void f ( ) { int b ; int * f ; }"); + ASSERT_EQUALS(expected, sizeof_(code, false)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef61() // ticket #2074 and 2075 + { + const char code1[] = "typedef unsigned char (*Mf_GetIndexByte_Func) (void);\n" + "typedef const unsigned char * (*Mf_GetPointerToCurrentPos_Func)(void);\n"; + + // Check for output.. + checkSimplifyTypedef(code1); + ASSERT_EQUALS("", errout.str()); + + const char code2[] = "typedef unsigned long uint32_t;\n" + "typedef uint32_t (*write_type_t) (uint32_t);\n"; + + // Check for output.. + checkSimplifyTypedef(code2); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef62() // ticket #2082 + { + const char code1[] = "typedef char TString[256];\n" + "void f()\n" + "{\n" + " TString a, b;\n" + "}"; + + // The expected tokens.. + const std::string expected1("; void f ( ) { char a [ 256 ] ; char b [ 256 ] ; }"); + ASSERT_EQUALS(expected1, sizeof_(code1, false)); + + // Check for output.. + checkSimplifyTypedef(code1); + ASSERT_EQUALS("", errout.str()); + + const char code2[] = "typedef char TString[256];\n" + "void f()\n" + "{\n" + " TString a = { 0 }, b = { 0 };\n" + "}"; + + // The expected tokens.. + const std::string expected2("; void f ( ) { char a [ 256 ] = { 0 } ; char b [ 256 ] = { 0 } ; }"); + ASSERT_EQUALS(expected2, tok(code2, false)); + + // Check for output.. + checkSimplifyTypedef(code2); + ASSERT_EQUALS("", errout.str()); + + const char code3[] = "typedef char TString[256];\n" + "void f()\n" + "{\n" + " TString a = \"\", b = \"\";\n" + "}"; + + // The expected tokens.. + const std::string expected3("; void f ( ) { char a [ 256 ] = \"\" ; char b [ 256 ] = \"\" ; }"); + ASSERT_EQUALS(expected3, tok(code3, false)); + + // Check for output.. + checkSimplifyTypedef(code3); + ASSERT_EQUALS("", errout.str()); + + const char code4[] = "typedef char TString[256];\n" + "void f()\n" + "{\n" + " TString a = \"1234\", b = \"5678\";\n" + "}"; + + // The expected tokens.. + const std::string expected4("; void f ( ) { char a [ 256 ] = \"1234\" ; char b [ 256 ] = \"5678\" ; }"); + ASSERT_EQUALS(expected4, tok(code4, false)); + + // Check for output.. + checkSimplifyTypedef(code4); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef63() // ticket #2175 'typedef float x[3];' + { + const char code[] = "typedef float x[3];\n" + "x a,b,c;\n"; + const std::string actual(sizeof_(code)); + ASSERT_EQUALS("; float a [ 3 ] ; float b [ 3 ] ; float c [ 3 ] ;", actual); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef64() + { + const char code[] = "typedef __typeof__(__type1() + __type2()) __type;" + "__type t;\n"; + const std::string actual(sizeof_(code)); + ASSERT_EQUALS("; __typeof__ ( __type1 ( ) + __type2 ( ) ) t ;", actual); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef65() // ticket #2314 + { + const char code[] = "typedef BAR Foo; \n" + "int main() { \n" + " Foo b(0); \n" + " return b > Foo(10); \n" + "}"; + const std::string actual(sizeof_(code)); + ASSERT_EQUALS("; int main ( ) { BAR < int > b ( 0 ) ; return b > BAR < int > ( 10 ) ; }", actual); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef66() // ticket #2341 + { + const char code[] = "typedef long* GEN;\n" + "extern GEN (*foo)(long);"; + const std::string actual(sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef67() // ticket #2354 + { + const char code[] = "typedef int ( * Function ) ( ) ;\n" + "void f ( ) {\n" + " ((Function * (*) (char *, char *, int, int)) global[6]) ( \"assoc\", \"eggdrop\", 106, 0);\n" + "}\n"; + const std::string expected = "; " + "void f ( ) { " + "( ( int ( * * ( * ) ( char * , char * , int , int ) ) ( ) ) global [ 6 ] ) ( \"assoc\" , \"eggdrop\" , 106 , 0 ) ; " + "}"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef68() // ticket #2355 + { + const char code[] = "typedef FMAC1 void (* a) ();\n" + "void *(*b) ();\n"; + const std::string actual(sizeof_(code)); + ASSERT_EQUALS("; void * * b ;", actual); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef69() // ticket #2348 + { + const char code[] = "typedef int (*CompilerHook)();\n" + "typedef struct VirtualMachine \n" + "{\n" + " CompilerHook *(*compilerHookVector)(void);\n" + "}VirtualMachine;\n"; + const std::string expected = "; " + "struct VirtualMachine " + "{ " + "int ( * * ( * compilerHookVector ) ( void ) ) ( ) ; " + "} ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef70() // ticket #2348 + { + const char code[] = "typedef int pread_f ( int ) ;\n" + "pread_f *(*test_func)(char *filename);\n"; + const std::string expected = "; " + "int ( * ( * test_func ) ( char * filename ) ) ( int ) ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef71() // ticket #2348 + { + { + const char code[] = "typedef int RexxFunctionHandler();\n" + "RexxFunctionHandler *(efuncs[1]);\n"; + const std::string expected = "; " + "int ( * ( efuncs [ 1 ] ) ) ( ) ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + { + const char code[] = "typedef int RexxFunctionHandler();\n" + "RexxFunctionHandler *(efuncs[]) = { NULL, NULL };\n"; + const std::string expected = "; " + "int ( * ( efuncs [ ] ) ) ( ) = { 0 , 0 } ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + } + + void simplifyTypedef72() // ticket #2374 + { + // inline operator + { + const char code[] = "class Fred {\n" + " typedef int* (Fred::*F);\n" + " operator F() const { }\n" + "};\n"; + const std::string expected = "class Fred { " + "; " + "operatorint** ( ) const { } " + "} ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + // inline local variable + { + const char code[] = "class Fred {\n" + " typedef int INT;\n" + " void f1() const { INT i; }\n" + "};\n"; + const std::string expected = "class Fred { " + "; " + "void f1 ( ) const { int i ; } " + "} ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + // out of line member variable + { + const char code[] = "class Fred {\n" + " typedef int INT;\n" + " void f1() const;\n" + "};\n" + "void Fred::f1() const { INT i; f(i); }\n"; + const std::string expected = "class Fred { " + "; " + "void f1 ( ) const ; " + "} ; " + "void Fred :: f1 ( ) const { int i ; f ( i ) ; }"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + // out of line operator + { + const char code[] = "class Fred {\n" + " typedef int* (Fred::*F);\n" + " operator F() const;\n" + "};\n" + "Fred::operator F() const { }\n"; + const std::string expected = "class Fred { " + "; " + "operatorint** ( ) const ; " + "} ; " + "Fred :: operatorint** ( ) const { }"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + } + + void simplifyTypedef73() // ticket #2412 + { + const char code[] = "struct B {};\n" + "typedef struct A : public B {\n" + " void f();\n" + "} a, *aPtr;\n"; + const std::string expected = "struct B { } ; " + "struct A : public B { " + "void f ( ) ; " + "} ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef74() // ticket #2414 + { + const char code[] = "typedef long (*state_func_t)(void);\n" + "typedef state_func_t (*state_t)(void);\n" + "state_t current_state = death;\n" + "static char get_runlevel(const state_t);\n"; + const std::string expected = "; " + "long ( * ( * current_state ) ( void ) ) ( void ) = death ; " + "static char get_runlevel ( const long ( * ( * ) ( void ) ) ( void ) ) ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef75() // ticket #2426 + { + const char code[] = "typedef _Packed struct S { long l; }; \n"; + const std::string expected = ";"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef76() // ticket #2453 segmentation fault + { + const char code[] = "void f1(typedef int x) {}\n"; + const std::string expected = "void f1 ( typedef int x ) { }"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); + } + + void simplifyTypedef77() // ticket #2554 + { + const char code[] = "typedef char Str[10]; int x = sizeof(Str);\n"; + const std::string expected = "; int x ; x = 10 ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef78() // ticket #2568 + { + const char code[] = "typedef struct A A_t;\n" + "A_t a;\n" + "typedef struct A { } A_t;\n" + "A_t a1;\n"; + const std::string expected = "; struct A a ; struct A { } ; struct A a1 ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef79() // ticket #2348 + { + const char code[] = "typedef int (Tcl_ObjCmdProc) (int x);\n" + "typedef struct LangVtab\n" + "{\n" + " Tcl_ObjCmdProc * (*V_LangOptionCommand);\n" + "} LangVtab;\n"; + const std::string expected = "; " + "struct LangVtab " + "{ " + "int ( * ( * V_LangOptionCommand ) ) ( int x ) ; " + "} ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef80() // ticket #2587 + { + const char code[] = "typedef struct s { };\n" + "void f() {\n" + " sizeof(struct s);\n" + "};\n"; + const std::string expected = "struct s { } ; " + "void f ( ) { " + "sizeof ( struct s ) ; " + "} ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef81() // ticket #2603 segmentation fault + { + checkSimplifyTypedef("typedef\n"); + ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); + + checkSimplifyTypedef("typedef constexpr\n"); + ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); + } + + void simplifyTypedef82() // ticket #2403 + { + checkSimplifyTypedef("class A {\n" + "public:\n" + " typedef int F(int idx);\n" + "};\n" + "class B {\n" + "public:\n" + " A::F ** f;\n" + "};\n" + "int main()\n" + "{\n" + " B * b = new B;\n" + " b->f = new A::F * [ 10 ];\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef83() // ticket #2620 + { + const char code[] = "typedef char Str[10];\n" + "void f(Str &cl) { }\n"; + + // The expected result.. + const std::string expected("; " + "void f ( char ( & cl ) [ 10 ] ) { }"); + + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedefFunction1() + { + { + const char code[] = "typedef void (*my_func)();\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (*my_func)(void);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( void ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (*my_func)(int);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (*my_func)(int*);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + // ticket # 1615 + const char code[] = "typedef void (*my_func)(arg_class*);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( arg_class * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + + { + const char code[] = "typedef void (my_func)();\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func)(void);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( void ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func)(int);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func)(int*);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func)(arg_class*);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( arg_class * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + + { + const char code[] = "typedef void my_func();\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void my_func(void);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( void ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void my_func(int);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void my_func(int*);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void my_func(arg_class*);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( arg_class * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + + { + const char code[] = "typedef void (my_func());\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func(void));\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( void ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func(int));\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func(int*));\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func(arg_class*));\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( arg_class * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + } + + void simplifyTypedefFunction2() // ticket #1685 + { + const char code[] = "typedef void voidfn (int);\n" + "voidfn xxx;"; + + // The expected result.. + const std::string expected("; " + "void xxx ( int ) ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedefFunction3() + { + { + const char code[] = "typedef C func1();\n" + "typedef C (* func2)();\n" + "typedef C (& func3)();\n" + "typedef C (C::* func4)();\n" + "typedef C (C::* func5)() const;\n" + "typedef C (C::* func6)() volatile;\n" + "typedef C (C::* func7)() const volatile;\n" + "func1 f1;\n" + "func2 f2;\n" + "func3 f3;\n" + "func4 f4;\n" + "func5 f5;\n" + "func6 f6;\n" + "func7 f7;"; + + // The expected result.. + const std::string expected("; " + "C f1 ( ) ; " + "C * f2 ; " // this gets simplified to a regular pointer + "C ( & f3 ) ( ) ; " + "C ( C :: * f4 ) ( ) ; " + "C ( C :: * f5 ) ( ) const ; " + "C ( C :: * f6 ) ( ) ; " // volatile is removed + "C ( C :: * f7 ) ( ) const ;"); // volatile is removed + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef C const func1();\n" + "typedef C const (* func2)();\n" + "typedef C const (& func3)();\n" + "typedef C const (C::* func4)();\n" + "typedef C const (C::* func5)() const;\n" + "typedef C const (C::* func6)() volatile;\n" + "typedef C const (C::* func7)() const volatile;\n" + "func1 f1;\n" + "func2 f2;\n" + "func3 f3;\n" + "func4 f4;\n" + "func5 f5;\n" + "func6 f6;\n" + "func7 f7;"; + + // The expected result.. + // C const -> const C + const std::string expected("; " + "const C f1 ( ) ; " + "const C * f2 ; " // this gets simplified to a regular pointer + "const C ( & f3 ) ( ) ; " + "const C ( C :: * f4 ) ( ) ; " + "const C ( C :: * f5 ) ( ) const ; " + "const C ( C :: * f6 ) ( ) ; " // volatile is removed + "const C ( C :: * f7 ) ( ) const ;"); // volatile is removed + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef const C func1();\n" + "typedef const C (* func2)();\n" + "typedef const C (& func3)();\n" + "typedef const C (C::* func4)();\n" + "typedef const C (C::* func5)() const;\n" + "typedef const C (C::* func6)() volatile;\n" + "typedef const C (C::* func7)() const volatile;\n" + "func1 f1;\n" + "func2 f2;\n" + "func3 f3;\n" + "func4 f4;\n" + "func5 f5;\n" + "func6 f6;\n" + "func7 f7;"; + + // The expected result.. + const std::string expected("; " + "const C f1 ( ) ; " + "const C * f2 ; " // this gets simplified to a regular pointer + "const C ( & f3 ) ( ) ; " + "const C ( C :: * f4 ) ( ) ; " + "const C ( C :: * f5 ) ( ) const ; " + "const C ( C :: * f6 ) ( ) ; " // volatile is removed + "const C ( C :: * f7 ) ( ) const ;"); // volatile is removed + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef C * func1();\n" + "typedef C * (* func2)();\n" + "typedef C * (& func3)();\n" + "typedef C * (C::* func4)();\n" + "typedef C * (C::* func5)() const;\n" + "typedef C * (C::* func6)() volatile;\n" + "typedef C * (C::* func7)() const volatile;\n" + "func1 f1;\n" + "func2 f2;\n" + "func3 f3;\n" + "func4 f4;\n" + "func5 f5;\n" + "func6 f6;\n" + "func7 f7;"; + + // The expected result.. + const std::string expected("; " + "C * f1 ( ) ; " + "C * * f2 ; " // this gets simplified to a regular pointer + "C * ( & f3 ) ( ) ; " + "C * ( C :: * f4 ) ( ) ; " + "C * ( C :: * f5 ) ( ) const ; " + "C * ( C :: * f6 ) ( ) ; " // volatile is removed + "C * ( C :: * f7 ) ( ) const ;"); // volatile is removed + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef const C * func1();\n" + "typedef const C * (* func2)();\n" + "typedef const C * (& func3)();\n" + "typedef const C * (C::* func4)();\n" + "typedef const C * (C::* func5)() const;\n" + "typedef const C * (C::* func6)() volatile;\n" + "typedef const C * (C::* func7)() const volatile;\n" + "func1 f1;\n" + "func2 f2;\n" + "func3 f3;\n" + "func4 f4;\n" + "func5 f5;\n" + "func6 f6;\n" + "func7 f7;"; + + // The expected result.. + const std::string expected("; " + "const C * f1 ( ) ; " + "const C * * f2 ; " // this gets simplified to a regular pointer + "const C * ( & f3 ) ( ) ; " + "const C * ( C :: * f4 ) ( ) ; " + "const C * ( C :: * f5 ) ( ) const ; " + "const C * ( C :: * f6 ) ( ) ; " // volatile is removed + "const C * ( C :: * f7 ) ( ) const ;"); // volatile is removed + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef C const * func1();\n" + "typedef C const * (* func2)();\n" + "typedef C const * (& func3)();\n" + "typedef C const * (C::* func4)();\n" + "typedef C const * (C::* func5)() const;\n" + "typedef C const * (C::* func6)() volatile;\n" + "typedef C const * (C::* func7)() const volatile;\n" + "func1 f1;\n" + "func2 f2;\n" + "func3 f3;\n" + "func4 f4;\n" + "func5 f5;\n" + "func6 f6;\n" + "func7 f7;"; + + // The expected result.. + // C const -> const C + const std::string expected("; " + "const C * f1 ( ) ; " + "const C * * f2 ; " // this gets simplified to a regular pointer + "const C * ( & f3 ) ( ) ; " + "const C * ( C :: * f4 ) ( ) ; " + "const C * ( C :: * f5 ) ( ) const ; " + "const C * ( C :: * f6 ) ( ) ; " // volatile is removed + "const C * ( C :: * f7 ) ( ) const ;"); // volatile is removed + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + } + + void simplifyTypedefFunction4() + { + const char code[] = "typedef int ( * ( * type1 ) ( bool ) ) ( int , int ) ;\n" + "typedef int ( * ( type2 ) ( bool ) ) ( int , int ) ;\n" + "typedef int ( * type3 ( bool ) ) ( int , int ) ;\n" + "type1 t1;\n" + "type2 t2;\n" + "type3 t3;"; + + // The expected result.. + const std::string expected("; " + "int ( * ( * t1 ) ( bool ) ) ( int , int ) ; " + "int ( * t2 ( bool ) ) ( int , int ) ; " + "int ( * t3 ( bool ) ) ( int , int ) ;"); + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedefFunction5() + { + const char code[] = "typedef int ( * type1 ) ( float ) ;\n" + "typedef int ( * const type2 ) ( float ) ;\n" + "typedef int ( * volatile type3 ) ( float ) ;\n" + "typedef int ( * const volatile type4 ) ( float ) ;\n" + "typedef int ( C :: * type5 ) ( float ) ;\n" + "typedef int ( C :: * const type6 ) ( float ) ;\n" + "typedef int ( C :: * volatile type7 ) ( float ) ;\n" + "typedef int ( C :: * const volatile type8 ) ( float ) ;\n" + "typedef int ( :: C :: * type9 ) ( float ) ;\n" + "typedef int ( :: C :: * const type10 ) ( float ) ;\n" + "typedef int ( :: C :: * volatile type11 ) ( float ) ;\n" + "typedef int ( :: C :: * const volatile type12 ) ( float ) ;\n" + "type1 t1;\n" + "type2 t2;\n" + "type3 t3;\n" + "type4 t4;\n" + "type5 t5;\n" + "type6 t6;\n" + "type7 t7;\n" + "type8 t8;\n" + "type9 t9;\n" + "type10 t10;\n" + "type11 t11;\n" + "type12 t12;"; + + // The expected result.. + const std::string expected("; " + "int * t1 ; " // simplified to regular pointer + "int ( * const t2 ) ( float ) ; " + "int * t3 ; " // volatile removed, gets simplified to regular pointer + "int ( * const t4 ) ( float ) ; " // volatile removed + "int ( C :: * t5 ) ( float ) ; " + "int ( C :: * const t6 ) ( float ) ; " + "int ( C :: * t7 ) ( float ) ; " // volatile removed + "int ( C :: * const t8 ) ( float ) ; " // volatile removed + "int ( :: C :: * t9 ) ( float ) ; " + "int ( :: C :: * const t10 ) ( float ) ; " + "int ( :: C :: * t11 ) ( float ) ; " // volatile removed + "int ( :: C :: * const t12 ) ( float ) ;"); // volatile removed + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedefFunction6() + { + const char code[] = "typedef void (*testfp)();\n" + "struct Fred\n" + "{\n" + " testfp get1() { return 0; }\n" + " void ( * get2 ( ) ) ( ) { return 0 ; }\n" + " testfp get3();\n" + " void ( * get4 ( ) ) ( );\n" + "};\n" + "testfp Fred::get3() { return 0; }\n" + "void ( * Fred::get4 ( ) ) ( ) { return 0 ; }\n"; + + // The expected result.. + const std::string expected("; " + "struct Fred " + "{ " + "void ( * get1 ( ) ) ( ) { return 0 ; } " + "void ( * get2 ( ) ) ( ) { return 0 ; } " + "void ( * get3 ( ) ) ( ) ; " + "void ( * get4 ( ) ) ( ) ; " + "} ; " + "void ( * Fred :: get3 ( ) ) ( ) { return 0 ; } " + "void ( * Fred :: get4 ( ) ) ( ) { return 0 ; }"); + + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedefFunction7() + { + const char code[] = "typedef void ( __gnu_cxx :: _SGIAssignableConcept < _Tp > :: * _func_Tp_SGIAssignableConcept ) () ;" + "_func_Tp_SGIAssignableConcept X;\n"; + + // The expected result.. + const std::string expected("; " + "void ( __gnu_cxx :: _SGIAssignableConcept < _Tp > :: * X ) ( ) ;"); + + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedefFunction8() + { + // #2376 - internal error + const char code[] = "typedef int f_expand(const nrv_byte *);\n" + "void f(f_expand *(*get_fexp(int))){}\n"; + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); // make sure that there is no internal error + } + + void reverseArraySyntax() + { + ASSERT_EQUALS("a [ 13 ]", tok("13[a]")); + } + + void simplify_numeric_condition() + { + { + const char code[] = + "void f()\n" + "{\n" + "int x = 0;\n" + "if( !x || 0 )\n" + "{ g();\n" + "}\n" + "}"; + + ASSERT_EQUALS("void f ( ) { ; { g ( ) ; } }", tok(code)); + } + + { + const char code[] = + "void f()\n" + "{\n" + "int x = 1;\n" + "if( !x )\n" + "{ g();\n" + "}\n" + "}"; + + ASSERT_EQUALS("void f ( ) { ; }", tok(code)); + } + + { + const char code[] = + "void f()\n" + "{\n" + "bool x = true;\n" + "if( !x )\n" + "{ g();\n" + "}\n" + "}"; + + ASSERT_EQUALS("void f ( ) { ; }", tok(code)); + } + + { + const char code[] = + "void f()\n" + "{\n" + "bool x = false;\n" + "if( !x )\n" + "{ g();\n" + "}\n" + "}"; + + ASSERT_EQUALS("void f ( ) { ; { g ( ) ; } }", tok(code)); + } + + { + const char code[] = "void f()\n" + "{\n" + " if (5==5);\n" + "}\n"; + + ASSERT_EQUALS("void f ( ) { { ; } }", tok(code)); + } + + { + const char code[] = "void f()\n" + "{\n" + " if (4<5);\n" + "}\n"; + + ASSERT_EQUALS("void f ( ) { { ; } }", tok(code)); + } + + { + const char code[] = "void f()\n" + "{\n" + " if (5<5);\n" + "}\n"; + + ASSERT_EQUALS("void f ( ) { }", tok(code)); + } + + { + const char code[] = "void f()\n" + "{\n" + " if (13>12?true:false);\n" + "}\n"; + + ASSERT_EQUALS("void f ( ) { { ; } }", tok(code)); + } + } + + void simplify_condition() + { + { + const char code[] = + "void f(int a)\n" + "{\n" + "if (a && false) g();\n" + "}"; + ASSERT_EQUALS("void f ( int a ) { }", tok(code)); + } + + { + const char code[] = + "void f(int a)\n" + "{\n" + "if (false && a) g();\n" + "}"; + ASSERT_EQUALS("void f ( int a ) { }", tok(code)); + } + + { + const char code[] = + "void f(int a)\n" + "{\n" + "if (true || a) g();\n" + "}"; + ASSERT_EQUALS("void f ( int a ) { { g ( ) ; } }", tok(code)); + } + + { + const char code[] = + "void f(int a)\n" + "{\n" + "if (a || true) g();\n" + "}"; + ASSERT_EQUALS("void f ( int a ) { { g ( ) ; } }", tok(code)); + } + } + + + void pointeralias1() + { + { + const char code[] = "void f()\n" + "{\n" + " char buf[100];\n" + " char *p = buf;\n" + " free(p);\n" + "}\n"; + + const char expected[] = "void f ( ) " + "{ " + "char buf [ 100 ] ; " + "free ( buf ) ; " + "}"; + + ASSERT_EQUALS(expected, tok(code)); + } + + { + const char code[] = "void f(char *p1)\n" + "{\n" + " char *p = p1;\n" + " p1 = 0;" + " x(p);\n" + "}\n"; + + const char expected[] = "void f ( char * p1 ) " + "{ " + "char * p ; p = p1 ; " + "p1 = 0 ; " + "x ( p ) ; " + "}"; + + ASSERT_EQUALS(expected, tok(code)); + } + + { + const char code[] = "void foo(Result* ptr)\n" + "{\n" + " Result* obj = ptr;\n" + " ++obj->total;\n" + "}\n"; + + const char expected[] = "void foo ( Result * ptr ) " + "{ " + "Result * obj ; obj = ptr ; " + "++ obj . total ; " + "}"; + + ASSERT_EQUALS(expected, tok(code)); + } + + { + const char code[] = "int *foo()\n" + "{\n" + " int a[10];\n" + " int *b = a;\n" + " return b;\n" + "}\n"; + + const char expected[] = "int * foo ( ) " + "{ " + "int a [ 10 ] ; " + "return a ; " + "}"; + + ASSERT_EQUALS(expected, tok(code)); + } + + { + const char code[] = "void f() {\n" + " int a[10];\n" + " int *b = a;\n" + " memset(b,0,sizeof(a));\n" + "}"; + + const char expected[] = "void f ( ) {" + " int a [ 10 ] ;" + " memset ( a , 0 , 40 ) ; " + "}"; + + ASSERT_EQUALS(expected, tok(code)); + } + } + + void pointeralias2() + { + const char code[] = "void f()\n" + "{\n" + " int i;\n" + " int *p = &i;\n" + " return *p;\n" + "}\n"; + ASSERT_EQUALS("void f ( ) { int i ; return i ; }", tok(code)); + } + + void pointeralias3() + { + const char code[] = "void f()\n" + "{\n" + " int i, j, *p;\n" + " if (ab) p = &i;\n" + " else p = &j;\n" + " *p = 0;\n" + "}\n"; + const char expected[] = "void f ( ) " + "{" + " int i ; int j ; int * p ;" + " if ( ab ) { p = & i ; }" + " else { p = & j ; }" + " * p = 0 ; " + "}"; + ASSERT_EQUALS(expected, tok(code)); + } + + void pointeralias4() + { + const char code[] = "void f()\n" + "{\n" + " int a[10];\n" + " int *p = &a[0];\n" + " *p = 0;\n" + "}\n"; + const char expected[] = "void f ( ) " + "{" + " int a [ 10 ] ;" + " int * p ; p = & a [ 0 ] ;" + " * a = 0 ; " + "}"; + ASSERT_EQUALS(expected, tok(code)); + } + + void pointeralias5() + { + const char code[] = "int f()\n" + "{\n" + " int i;\n" + " int *p = &i;\n" + " *p = 5;\n" + " return i;\n" + "}\n"; + const char expected[] = "int f ( ) " + "{" + " ; return 5 ; " + "}"; + ASSERT_EQUALS(expected, tok(code)); + } + + void reduceConstness() + { + ASSERT_EQUALS("char * p ;", tok("char * const p;")); + } + + void while0() + { + ASSERT_EQUALS("; x = 1 ;", tok("; do { x = 1 ; } while (0);")); + ASSERT_EQUALS("; do { continue ; } while ( false ) ;", tok("; do { continue ; } while (0);")); + ASSERT_EQUALS("; do { break ; } while ( false ) ;", tok("; do { break; } while (0);")); + ASSERT_EQUALS(";", tok("; while (false) { a; }")); + + // for (condition is always false) + ASSERT_EQUALS("void f ( ) { ; }", tok("void f() { int i; for (i = 0; i < 0; i++) { a; } }")); + } + + void while1() + { + // ticket #1197 + const char code[] = "void do {} while (0) { }"; + const char expected[] = "void { }"; + ASSERT_EQUALS(expected, tok(code)); + } + + void enum1() + { + const char code[] = "enum A { a, b, c }; A c1 = c;"; + const char expected[] = "; int c1 ; c1 = 2 ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void enum2() + { + const char code[] = "enum A { a, }; int array[a];"; + const char expected[] = "; int array [ 0 ] ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void enum3() + { + const char code[] = "enum { a, }; int array[a];"; + const char expected[] = "; int array [ 0 ] ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void enum4() + { + { + const char code[] = "class A {\n" + "public:\n" + " enum EA { a1, a2, a3 };\n" + " EA get() const;\n" + " void put(EA a) { ea = a; ea = a1; }\n" + "private:\n" + " EA ea;\n" + "};\n" + "A::EA A::get() const { return ea; }\n" + "A::EA e = A::a1;"; + + const char expected[] = "class A { " + "public: " + "; " + "int get ( ) const ; " + "void put ( int a ) { ea = a ; ea = 0 ; } " + "private: " + "int ea ; " + "} ; " + "int A :: get ( ) const { return ea ; } " + "int e ; e = 0 ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct A {\n" + " enum EA { a1, a2, a3 };\n" + " EA get() const;\n" + " void put(EA a) { ea = a; ea = a1; }\n" + " EA ea;\n" + "};\n" + "A::EA A::get() const { return ea; }\n" + "A::EA e = A::a1;"; + + const char expected[] = "struct A { " + "; " + "int get ( ) const ; " + "void put ( int a ) { ea = a ; ea = 0 ; } " + "int ea ; " + "} ; " + "int A :: get ( ) const { return ea ; } " + "int e ; e = 0 ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void enum5() + { + const char code[] = "enum ABC {\n" + " a = sizeof(int),\n" + " b = 1 + a,\n" + " c = b + 100,\n" + " d,\n" + " e,\n" + " f = 90,\n" + " g\n" + "};\n" + "int sum = a + b + c + d + e + f + g;"; + const char expected[] = "; " + "int sum ; sum = " + "sizeof ( int ) + " + "1 + sizeof ( int ) + " + "1 + sizeof ( int ) + 100 + " + "1 + sizeof ( int ) + 100 + 1 + " + "1 + sizeof ( int ) + 100 + 2 + " + "90 + " + "91 ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + ASSERT_EQUALS("; int sum ; sum = 508 ;", tok(code, true)); + } + + void enum6() + { + const char code[] = "enum { a = MAC(A, B, C) }; void f(a) { }"; + const char expected[] = "; void f ( MAC ( A , B , C ) ) { }"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void enum7() + { + { + // ticket 1388 + const char code[] = "enum FOO {A,B,C};\n" + "int main()\n" + "{\n" + " int A = B;\n" + " { float A = C; }\n" + "}"; + const char expected[] = "; " + "int main ( ) " + "{ " + "int A ; A = 1 ; " + "{ float A ; A = 2 ; } " + "}"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "enum FOO {A,B,C};\n" + "void f(int A, float B, char C) { }"; + const char expected[] = "; " + "void f ( int A , float B , char C ) { }"; + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + // Check simplifyEnum + void checkSimplifyEnum(const char code[]) + { + errout.str(""); + // Tokenize.. + Settings settings; + settings.inconclusive = true; + settings._checkCodingStyle = true; + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + tokenizer.simplifyTokenList(); + } + + void enum8() + { + // ticket 1388 + checkSimplifyEnum("enum Direction {N=100,E,S,W,ALL};\n" + "template class EF_Vector{\n" + " T v_v[S];\n" + "\n" + "public:\n" + " EF_Vector();\n" + " explicit EF_Vector(const T &);\n" + " explicit EF_Vector(const T arr[S]);\n" + "};\n" + "\n" + "template\n" + "EF_Vector::EF_Vector()\n" + "{\n" + "}\n" + "\n" + "template\n" + "EF_Vector::EF_Vector(const T &t)\n" + "{\n" + " for(int i=0;i\n" + "EF_Vector::EF_Vector(const T arr[S])\n" + "{\n" + " for(int i=0;i d;\n" + "}"); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator with same name\n" + "[test.cpp:11] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator with same name\n" + "[test.cpp:16] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator with same name\n" + "[test.cpp:23] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator with same name\n", errout.str()); + } + + void enum9() + { + // ticket 1404 + checkSimplifyEnum("class XX {\n" + "public:\n" + "static void Set(const int &p){m_p=p;}\n" + "static int m_p;\n" + "};\n" + "int XX::m_p=0;\n" + "int main() {\n" + " enum { XX };\n" + " XX::Set(std::numeric_limits::digits());\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + void enum10() + { + // ticket 1445 + const char code[] = "enum {\n" + "SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1, \n" + "} e = SHELL_SIZE;"; + const char expected[] = "; int e ; e = sizeof ( union { int i ; char * cp ; double d ; } ) - 1 ;"; + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyEnum(code); + ASSERT_EQUALS("", errout.str()); + } + + void enum11() + { + const char code[] = "int main()\n" + "{\n" + " enum { u, v };\n" + " A u = 1, v = 2;\n" + "}"; + const char expected[] = "int main ( ) " + "{ " + "; " + "A u ; u = 1 ; A v ; v = 2 ; " + "}"; + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyEnum(code); + ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3]: (style) Variable 'u' hides enumerator with same name\n" + "[test.cpp:4] -> [test.cpp:3]: (style) Variable 'v' hides enumerator with same name\n", errout.str()); + } + + void enum12() + { + const char code[] = "enum fred { a, b };\n" + "void foo()\n" + "{\n" + " unsigned int fred = 0;\n" + "}"; + const char expected[] = "; void foo ( ) { unsigned int fred ; fred = 0 ; }"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void enum13() + { + const char code[] = "enum ab { ENTRY(1, a = 0), ENTRY(2, b) };\n" + "void foo()\n" + "{\n" + " unsigned int fred = a;\n" + "}"; + const char expected[] = "; void foo ( ) { unsigned int fred ; fred = a ; }"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void enum14() + { + const char code[] = "enum ab { a };\n" + "ab"; + const char expected[] = "; ab"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void enum15() // C++0x features + { + { + const char code[] = "enum : char { a = 99 };\n" + "char c1 = a;"; + const char expected[] = "; char c1 ; c1 = 99 ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "enum class Enum1 { a };\n" + "Enum1 e1 = a;"; + const char expected[] = "; int e1 ; e1 = 0 ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "enum Enum1 : char { a };\n" + "Enum1 e1 = a;"; + const char expected[] = "; char e1 ; e1 = 0 ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "enum class Enum1 : unsigned char { a };\n" + "Enum1 e1 = a;"; + const char expected[] = "; unsigned char e1 ; e1 = 0 ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "enum class Enum1 : unsigned int { a };\n" + "Enum1 e1 = a;"; + const char expected[] = "; unsigned int e1 ; e1 = 0 ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "enum class Enum1 : unsigned long long int { a };\n" + "Enum1 e1 = a;"; + const char expected[] = "; unsigned long long e1 ; e1 = 0 ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void enum16() // ticket #1988 + { + const char code[] = "enum D : auto * { FF = 0 };"; + checkSimplifyEnum(code); + ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); + } + + void enum17() // ticket #2381 + { + // if header is included twice its enums will be duplicated + const char code[] = "enum ab { a=0, b };" + "enum ab { a=0, b };\n"; + ASSERT_EQUALS(";", tok(code, false)); + ASSERT_EQUALS("", errout.str()); + } + + void enum18() // ticket #2466 - array with same name as enum constant + { + const char code[] = "enum ab { a=0, b };\n" + "void f() { a[0]; }\n"; + ASSERT_EQUALS("; void f ( ) { a [ 0 ] ; }", tok(code, false)); + } + + void enum19() // ticket #2536 + { + const char code[] = "enum class E1;\n" + "enum class E2 : int;\n"; + ASSERT_EQUALS(";", tok(code, false)); + } + + void enum20() // ticket #2600 segmentation fault + { + const char code[] = "enum { const }\n"; + ASSERT_EQUALS(";", tok(code, false)); + } + + void removestd() + { + ASSERT_EQUALS("; strcpy ( a , b ) ;", tok("; std::strcpy(a,b);")); + ASSERT_EQUALS("; strcat ( a , b ) ;", tok("; std::strcat(a,b);")); + ASSERT_EQUALS("; strncpy ( a , b , 10 ) ;", tok("; std::strncpy(a,b,10);")); + ASSERT_EQUALS("; strncat ( a , b , 10 ) ;", tok("; std::strncat(a,b,10);")); + ASSERT_EQUALS("; free ( p ) ;", tok("; std::free(p);")); + ASSERT_EQUALS("; malloc ( 10 ) ;", tok("; std::malloc(10);")); + } + + void simplifyInitVar() + { + // ticket #1005 - int *p(0); => int *p = 0; + { + const char code[] = "void foo() { int *p(0); }"; + ASSERT_EQUALS("void foo ( ) { ; }", tok(code)); + } + + { + const char code[] = "void foo() { int p(0); }"; + ASSERT_EQUALS("void foo ( ) { ; }", tok(code)); + } + + { + const char code[] = "void a() { foo *p(0); }"; + ASSERT_EQUALS("void a ( ) { ; }", tok(code)); + } + } + + void simplifyReference() + { + ASSERT_EQUALS("void f ( ) { int a ; a ++ ; }", + tok("void f() { int a; int &b(a); b++; }")); + ASSERT_EQUALS("void f ( ) { int a ; a ++ ; }", + tok("void f() { int a; int &b = a; b++; }")); + } + + void simplifyRealloc() + { + ASSERT_EQUALS("; free ( p ) ; p = 0 ;", + tok("; p = realloc(p,0);")); + ASSERT_EQUALS("; p = malloc ( 100 ) ;", + tok("; p = realloc(0, 100);")); + ASSERT_EQUALS("; p = malloc ( 0 ) ;", + tok("; p = realloc(0, sizeof(char)*0);")); + } + + void simplifyErrNoInWhile() + { + ASSERT_EQUALS("; while ( f ( ) ) { }", + tok("; while (f() && errno == EINTR) { }")); + ASSERT_EQUALS("; while ( f ( ) ) { }", + tok("; while (f() && (errno == EINTR)) { }")); + } + + void simplifyFuncInWhile() + { + ASSERT_EQUALS("int cppcheck:r = fclose ( f ) ; " + "while ( cppcheck:r ) " + "{ " + "foo ( ) ; " + "cppcheck:r = fclose ( f ) ; " + "}", + tok("while(fclose(f))foo();")); + + ASSERT_EQUALS("int cppcheck:r = fclose ( f ) ; " + "while ( cppcheck:r ) " + "{ " + "; cppcheck:r = fclose ( f ) ; " + "}", + tok("while(fclose(f));")); + + ASSERT_EQUALS("int cppcheck:r = fclose ( f ) ; " + "while ( cppcheck:r ) " + "{ " + "; cppcheck:r = fclose ( f ) ; " + "} " + "int cppcheck:r = fclose ( g ) ; " + "while ( cppcheck:r ) " + "{ " + "; cppcheck:r = fclose ( g ) ; " + "}", + tok("while(fclose(f)); while(fclose(g));")); + } + + void initstruct() + { + ASSERT_EQUALS("; struct A a ; a . buf = 3 ;", tok("; struct A a = { .buf = 3 };")); + ASSERT_EQUALS("; struct A a ; a . buf = x ;", tok("; struct A a = { .buf = x };")); + ASSERT_EQUALS("; struct A a ; a . buf = & key ;", tok("; struct A a = { .buf = &key };")); + ASSERT_EQUALS("; struct ABC abc ; abc . a = 3 ; abc . b = x ; abc . c = & key ;", tok("; struct ABC abc = { .a = 3, .b = x, .c = &key };")); + TODO_ASSERT_EQUALS("; struct A a ; a . buf = { 0 } ;", + "; struct A a ; a = { . buf = { 0 } } ;", + tok("; struct A a = { .buf = {0} };")); + } + + void simplifyStructDecl1() + { + { + const char code[] = "struct ABC { } abc;"; + const char expected[] = "struct ABC { } ; ABC abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC { } * pabc;"; + const char expected[] = "struct ABC { } ; ABC * pabc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC { } abc[4];"; + const char expected[] = "struct ABC { } ; ABC abc [ 4 ] ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC { } abc, def;"; + const char expected[] = "struct ABC { } ; ABC abc ; ABC def ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC { } abc, * pabc;"; + const char expected[] = "struct ABC { } ; ABC abc ; ABC * pabc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC { struct DEF {} def; } abc;"; + const char expected[] = "struct ABC { struct DEF { } ; DEF def ; } ; ABC abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { } abc;"; + const char expected[] = "struct Anonymous0 { } ; Anonymous0 abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { } * pabc;"; + const char expected[] = "struct Anonymous0 { } ; Anonymous0 * pabc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { } abc[4];"; + const char expected[] = "struct Anonymous0 { } ; Anonymous0 abc [ 4 ] ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { } abc, def;"; + const char expected[] = "struct Anonymous0 { } ; Anonymous0 abc ; Anonymous0 def ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { } abc, * pabc;"; + const char expected[] = "struct Anonymous0 { } ; Anonymous0 abc ; Anonymous0 * pabc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { struct DEF {} def; } abc;"; + const char expected[] = "struct Anonymous0 { struct DEF { } ; DEF def ; } ; Anonymous0 abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC { struct {} def; } abc;"; + const char expected[] = "struct ABC { struct Anonymous0 { } ; Anonymous0 def ; } ; ABC abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { struct {} def; } abc;"; + const char expected[] = "struct Anonymous0 { struct Anonymous1 { } ; Anonymous1 def ; } ; Anonymous0 abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "union ABC { int i; float f; } abc;"; + const char expected[] = "union ABC { int i ; float f ; } ; ABC abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC { struct {} def; };"; + const char expected[] = "struct ABC { struct Anonymous0 { } ; Anonymous0 def ; } ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC : public XYZ { struct {} def; };"; + const char expected[] = "struct ABC : public XYZ { struct Anonymous0 { } ; Anonymous0 def ; } ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { int x; }; int y;"; + const char expected[] = "int x ; int y ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { int x; };"; + const char expected[] = "int x ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { };"; + const char expected[] = ";"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { struct { struct { } ; } ; };"; + const char expected[] = ";"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + // ticket 2464 + { + const char code[] = "static struct ABC { } abc ;"; + const char expected[] = "struct ABC { } ; static ABC abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + // ticket #980 + { + const char code[] = "void f() { int A(1),B(2),C=3,D,E(5),F=6; }"; + const char expected[] = "void f ( ) { int A ; A = 1 ; int B ; B = 2 ; int C ; C = 3 ; int D ; int E ; E = 5 ; int F ; F = 6 ; }"; + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyStructDecl2() // ticket #2479 (segmentation fault) + { + const char code[] = "struct { char c; }"; + const char expected[] = "struct { char c ; }"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void removeUnwantedKeywords() + { + ASSERT_EQUALS("int var ;", tok("register int var ;", true)); + ASSERT_EQUALS("short var ;", tok("register short int var ;", true)); + ASSERT_EQUALS("int foo ( ) { }", tok("inline int foo ( ) { }", true)); + ASSERT_EQUALS("int foo ( ) { }", tok("__inline int foo ( ) { }", true)); + ASSERT_EQUALS("int foo ( ) { }", tok("__forceinline int foo ( ) { }", true)); + ASSERT_EQUALS("if ( a ) { }", tok("if ( likely ( a ) ) { }", true)); + ASSERT_EQUALS("if ( a ) { }", tok("if ( unlikely ( a ) ) { }", true)); + ASSERT_EQUALS("int * p ;", tok("int * __restrict p;", true)); + ASSERT_EQUALS("int * * p ;", tok("int * __restrict__ * p;", true)); + ASSERT_EQUALS("void foo ( float * a , float * b ) ;", tok("void foo(float * __restrict__ a, float * __restrict__ b);", true)); + ASSERT_EQUALS("int * p ;", tok("int * restrict p;", true)); + ASSERT_EQUALS("int * * p ;", tok("int * restrict * p;", true)); + ASSERT_EQUALS("void foo ( float * a , float * b ) ;", tok("void foo(float * restrict a, float * restrict b);", true)); + ASSERT_EQUALS("; int * p ;", tok("typedef int * __restrict__ rint; rint p;", true)); + } + + void simplifyCallingConvention() + { + ASSERT_EQUALS("int f ( ) ;", tok("int __cdecl f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __stdcall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __fastcall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __clrcall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __thiscall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __syscall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __pascal f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __fortran f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __cdecl f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __stdcall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __fastcall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __clrcall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __thiscall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __syscall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __pascal f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __fortran f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int WINAPI f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int APIENTRY f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int CALLBACK f();", true)); + } + + void simplifyFunctorCall() + { + ASSERT_EQUALS("IncrementFunctor ( ) ( a ) ;", tok("IncrementFunctor()(a);", true)); + } + + void redundant_semicolon() + { + ASSERT_EQUALS("void f ( ) { ; }", tok("void f() { ; }", false)); + ASSERT_EQUALS("void f ( ) { ; }", tok("void f() { do { ; } while (0); }", true)); + } + + void simplifyFunctionReturn() + { + const char code[] = "typedef void (*testfp)();\n" + "struct Fred\n" + "{\n" + " testfp get1() { return 0; }\n" + " void ( * get2 ( ) ) ( ) { return 0 ; }\n" + " testfp get3();\n" + " void ( * get4 ( ) ) ( );\n" + "};"; + const char expected[] = "; " + "struct Fred " + "{ " + "void ( * get1 ( ) ) ( ) { return 0 ; } " + "void ( * get2 ( ) ) ( ) { return 0 ; } " + "void ( * get3 ( ) ) ( ) ; " + "void ( * get4 ( ) ) ( ) ; " + "} ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void removeUnnecessaryQualification1() + { + const char code[] = "class Fred { Fred::Fred() {} };"; + const char expected[] = "class Fred { Fred ( ) { } } ;"; + ASSERT_EQUALS(expected, tok(code, false)); + ASSERT_EQUALS("[test.cpp:1]: (portability) Extra qualification 'Fred::' unnecessary and considered an error by many compilers.\n", errout.str()); + } + + void removeUnnecessaryQualification2() + { + const char code[] = "template\n" + "struct grammar : qi::grammar {\n" + " grammar() : grammar::base_type(start) { }\n" + "};\n"; + tok(code, false); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyIfNotNull() // ticket # 2601 segmentation fault + { + const char code[] = "|| #if #define <="; + tok(code, false); + ASSERT_EQUALS("", errout.str()); + } +}; + +REGISTER_TEST(TestSimplifyTokens)