Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

10346 lines (9079 sloc) 392.03 kb
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2015 Daniel Marjamäki and Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
#include "tokenize.h"
#include "mathlib.h"
#include "settings.h"
#include "check.h"
#include "path.h"
#include "symboldatabase.h"
#include "templatesimplifier.h"
#include "timer.h"
#include <cstring>
#include <sstream>
#include <cassert>
#include <cctype>
#include <stack>
#include <iostream>
//---------------------------------------------------------------------------
namespace {
// local struct used in setVarId
// in order to store information about the scope
struct scopeStackEntryType {
scopeStackEntryType()
:isExecutable(false), startVarid(0) {
}
scopeStackEntryType(bool _isExecutable, unsigned int _startVarid)
:isExecutable(_isExecutable), startVarid(_startVarid) {
}
const bool isExecutable;
const unsigned int startVarid;
};
}
/**
* is token pointing at function head?
* @param tok A '(' or ')' token in a possible function head
* @param endsWith string after function head
* @return token matching with endsWith if syntax seems to be a function head else nullptr
*/
static const Token * isFunctionHead(const Token *tok, const std::string &endsWith)
{
if (tok->str() == "(")
tok = tok->link();
if (Token::Match(tok, ") const| [;:{]")) {
tok = tok->next();
if (tok->isName())
tok = tok->next();
return (endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
}
if (Token::Match(tok, ") const| throw (")) {
tok = tok->next();
while (tok->isName())
tok = tok->next();
tok = tok->link()->next();
while (tok && tok->isName())
tok = tok->next();
return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
}
return nullptr;
}
/**
* is tok the start brace { of a class, struct, union, or enum
*/
static bool isClassStructUnionEnumStart(const Token * tok)
{
if (!Token::Match(tok->previous(), "class|struct|union|enum|%name%|>|>> {"))
return false;
const Token * tok2 = tok->previous();
while (tok2 && !Token::Match(tok2, "class|struct|union|enum|{|}|;"))
tok2 = tok2->previous();
return Token::Match(tok2, "class|struct|union|enum");
}
//---------------------------------------------------------------------------
Tokenizer::Tokenizer() :
list(0),
_settings(0),
_errorLogger(0),
_symbolDatabase(0),
_varId(0),
_codeWithTemplates(false), //is there any templates?
m_timerResults(nullptr)
#ifdef MAXTIME
,maxtime(std::time(0) + MAXTIME)
#endif
{
}
Tokenizer::Tokenizer(const Settings *settings, ErrorLogger *errorLogger) :
list(settings),
_settings(settings),
_errorLogger(errorLogger),
_symbolDatabase(0),
_varId(0),
_codeWithTemplates(false), //is there any templates?
m_timerResults(nullptr)
#ifdef MAXTIME
,maxtime(std::time(0) + MAXTIME)
#endif
{
// make sure settings are specified
assert(_settings);
}
Tokenizer::~Tokenizer()
{
delete _symbolDatabase;
}
//---------------------------------------------------------------------------
// SizeOfType - gives the size of a type
//---------------------------------------------------------------------------
unsigned int Tokenizer::sizeOfType(const Token *type) const
{
if (!type || type->str().empty())
return 0;
if (type->type() == Token::eString)
return static_cast<unsigned int>(Token::getStrLength(type) + 1);
std::map<std::string, unsigned int>::const_iterator it = _typeSize.find(type->str());
if (it == _typeSize.end())
return 0;
else if (type->isLong()) {
if (type->str() == "double")
return _settings->sizeof_long_double;
else if (type->str() == "long")
return _settings->sizeof_long_long;
}
return it->second;
}
//---------------------------------------------------------------------------
Token *Tokenizer::copyTokens(Token *dest, const Token *first, const Token *last, bool one_line)
{
std::stack<Token *> links;
Token *tok2 = dest;
unsigned int linenrs = dest->linenr();
const unsigned int commonFileIndex = dest->fileIndex();
for (const Token *tok = first; tok != last->next(); tok = tok->next()) {
tok2->insertToken(tok->str());
tok2 = tok2->next();
tok2->fileIndex(commonFileIndex);
tok2->linenr(linenrs);
tok2->type(tok->type());
tok2->flags(tok->flags());
tok2->varId(tok->varId());
// Check for links and fix them up
if (Token::Match(tok2, "(|[|{"))
links.push(tok2);
else if (Token::Match(tok2, ")|]|}")) {
if (links.empty())
return tok2;
Token * link = links.top();
tok2->link(link);
link->link(tok2);
links.pop();
}
if (!one_line && tok->next())
linenrs += tok->next()->linenr() - tok->linenr();
}
return tok2;
}
//---------------------------------------------------------------------------
void Tokenizer::duplicateTypedefError(const Token *tok1, const Token *tok2, const std::string &type) const
{
if (tok1 && !(_settings->isEnabled("style") && _settings->inconclusive))
return;
std::list<const Token*> locationList;
locationList.push_back(tok1);
locationList.push_back(tok2);
const std::string tok2_str = tok2 ? tok2->str() : std::string("name");
reportError(locationList, Severity::style, "variableHidingTypedef",
std::string("The " + type + " '" + tok2_str + "' hides a typedef with the same name."), true);
}
void Tokenizer::duplicateDeclarationError(const Token *tok1, const Token *tok2, const std::string &type) const
{
if (tok1 && !(_settings->isEnabled("style")))
return;
std::list<const Token*> locationList;
locationList.push_back(tok1);
locationList.push_back(tok2);
const std::string tok2_str = tok2 ? tok2->str() : std::string("name");
reportError(locationList, Severity::style, "unnecessaryForwardDeclaration",
std::string("The " + type + " '" + tok2_str + "' forward declaration is unnecessary. Type " + type + " is already declared earlier."));
}
// check if this statement is a duplicate definition
bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name, const Token *typeDef, const std::set<std::string>& structs) const
{
// 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 derived class
if (Token::Match(tok->previous(), "public|private|protected"))
return false;
// find end of definition
while (end && end->next() && !Token::Match(end->next(), ";|)|>")) {
if (end->next()->str() == "(")
end = end->linkAt(1);
end = (end)?end->next():nullptr;
}
if (end)
end = end->next();
} else if (end->str() == "(") {
if (tok->previous()->str().find("operator") == 0) {
// conversion operator
return false;
} else if (tok->previous()->str() == "typedef") {
// typedef of function returning this type
return false;
} else if (Token::Match(tok->previous(), "public:|private:|protected:")) {
return false;
} else if (tok->previous()->str() == ">") {
if (!Token::Match(tok->tokAt(-2), "%type%"))
return false;
if (!Token::Match(tok->tokAt(-3), ",|<"))
return false;
duplicateTypedefError(*tokPtr, name, "template instantiation");
*tokPtr = end->link();
return true;
}
}
if (end) {
if (Token::simpleMatch(end, ") {")) { // function parameter ?
// look backwards
if (Token::Match(tok->previous(), "%type%") &&
!Token::Match(tok->previous(), "return|new|const")) {
duplicateTypedefError(*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 (Token::Match(tok->previous(), "%type%") &&
!Token::Match(tok->previous(), "return|new|const|volatile")) {
// duplicate definition so skip entire template
while (end && end->str() != "{")
end = end->next();
if (end) {
duplicateTypedefError(*tokPtr, name, "template parameter");
*tokPtr = end->link();
return true;
}
}
} else {
// look backwards
if (Token::Match(tok->previous(), "typedef|}|>") ||
(end->str() == ";" && tok->previous()->str() == ",") ||
(tok->previous()->str() == "*" && tok->next()->str() != "(") ||
(Token::Match(tok->previous(), "%type%") &&
(!Token::Match(tok->previous(), "return|new|const|friend|public|private|protected|throw|extern") &&
!Token::simpleMatch(tok->tokAt(-2), "friend class")))) {
// scan backwards for the end of the previous statement
while (tok && tok->previous() && !Token::Match(tok->previous(), ";|{")) {
if (tok->previous()->str() == "}") {
tok = tok->previous()->link();
} else if (tok->previous()->str() == "typedef") {
duplicateTypedefError(*tokPtr, name, "typedef");
return true;
} else if (tok->previous()->str() == "enum") {
duplicateTypedefError(*tokPtr, name, "enum");
return true;
} else if (tok->previous()->str() == "struct") {
if (tok->strAt(-2) == "typedef" &&
tok->next()->str() == "{" &&
typeDef->strAt(3) != "{") {
// declaration after forward declaration
return true;
} else if (tok->next()->str() == "{") {
if (structs.find(name->strAt(-1)) == structs.end())
duplicateTypedefError(*tokPtr, name, "struct");
return true;
} else if (Token::Match(tok->next(), ")|*")) {
return true;
} else if (tok->next()->str() == name->str()) {
return true;
} else if (tok->next()->str() != ";") {
duplicateTypedefError(*tokPtr, name, "struct");
return true;
} else {
// forward declaration after declaration
duplicateDeclarationError(*tokPtr, name, "struct");
return false;
}
} else if (tok->previous()->str() == "union") {
if (tok->next()->str() != ";") {
duplicateTypedefError(*tokPtr, name, "union");
return true;
} else {
// forward declaration after declaration
duplicateDeclarationError(*tokPtr, name, "union");
return false;
}
} else if (tok->previous()->str() == "class") {
if (tok->next()->str() != ";") {
duplicateTypedefError(*tokPtr, name, "class");
return true;
} else {
// forward declaration after declaration
duplicateDeclarationError(*tokPtr, name, "class");
return false;
}
}
tok = tok->previous();
}
duplicateTypedefError(*tokPtr, name, "variable");
return true;
}
}
}
}
return false;
}
void Tokenizer::unsupportedTypedef(const Token *tok) const
{
if (!_settings->debugwarnings)
return;
std::ostringstream str;
const Token *tok1 = tok;
unsigned int level = 0;
while (tok) {
if (level == 0 && tok->str() == ";")
break;
else if (tok->str() == "{")
++level;
else if (tok->str() == "}") {
if (!level)
break;
--level;
}
if (tok != tok1)
str << " ";
str << tok->str();
tok = tok->next();
}
if (tok)
str << " ;";
reportError(tok1, Severity::debug, "debug",
"Failed to parse \'" + str.str() + "\'. The checking continues anyway.");
}
Token * Tokenizer::deleteInvalidTypedef(Token *typeDef)
{
Token *tok = nullptr;
// remove typedef but leave ;
while (typeDef->next()) {
if (typeDef->next()->str() == ";") {
typeDef->deleteNext();
break;
} else if (typeDef->next()->str() == "{")
Token::eraseTokens(typeDef, typeDef->linkAt(1));
else if (typeDef->next()->str() == "}")
break;
typeDef->deleteNext();
}
if (typeDef != list.front()) {
tok = typeDef->previous();
tok->deleteNext();
} else {
list.front()->deleteThis();
tok = list.front();
}
return tok;
}
struct Space {
Space() : classEnd(nullptr), isNamespace(false) { }
std::string className;
const Token * classEnd;
bool isNamespace;
};
static Token *splitDefinitionFromTypedef(Token *tok)
{
Token *tok1;
std::string name;
bool isConst = false;
if (tok->next()->str() == "const") {
tok->deleteNext();
isConst = true;
}
if (tok->strAt(2) == "{") { // unnamed
tok1 = tok->linkAt(2);
if (tok1 && tok1->next()) {
// use typedef name if available
if (Token::Match(tok1->next(), "%type%"))
name = tok1->next()->str();
else { // create a unique name
static unsigned int count = 0;
name = "Unnamed" + MathLib::toString(count++);
}
tok->next()->insertToken(name);
} else
return nullptr;
} else if (tok->strAt(3) == ":") {
tok1 = tok->tokAt(4);
while (tok1 && tok1->str() != "{")
tok1 = tok1->next();
if (!tok1)
return nullptr;
tok1 = tok1->link();
name = tok->strAt(2);
} else { // has a name
tok1 = tok->linkAt(3);
if (!tok1)
return nullptr;
name = tok->strAt(2);
}
tok1->insertToken(";");
tok1 = tok1->next();
if (tok1->next() && tok1->next()->str() == ";" && tok1->previous()->str() == "}") {
tok->deleteThis();
tok1->deleteThis();
return nullptr;
} else {
tok1->insertToken("typedef");
tok1 = tok1->next();
Token * tok3 = tok1;
if (isConst) {
tok1->insertToken("const");
tok1 = tok1->next();
}
tok1->insertToken(tok->next()->str()); // struct, union or enum
tok1 = tok1->next();
tok1->insertToken(name);
tok->deleteThis();
tok = tok3;
}
return tok;
}
/* This function is called when processing function related typedefs.
* If simplifyTypedef generates an "Internal Error" message and the
* code that generated it deals in some way with functions, then this
* function will probably need to be extended to handle a new function
* related pattern */
static Token *processFunc(Token *tok2, bool inOperator)
{
if (tok2->next() && tok2->next()->str() != ")" &&
tok2->next()->str() != ",") {
// skip over tokens for some types of canonicalization
if (Token::Match(tok2->next(), "( * %type% ) ("))
tok2 = tok2->linkAt(5);
else if (Token::Match(tok2->next(), "* ( * %type% ) ("))
tok2 = tok2->linkAt(6);
else if (Token::Match(tok2->next(), "* ( * %type% ) ;"))
tok2 = tok2->tokAt(5);
else if (Token::Match(tok2->next(), "* ( %type% [") &&
Token::Match(tok2->linkAt(4), "] ) ;|="))
tok2 = tok2->linkAt(4)->next();
else if (Token::Match(tok2->next(), "* ( * %type% ("))
tok2 = tok2->linkAt(5)->next();
else if (Token::simpleMatch(tok2->next(), "* [") &&
Token::simpleMatch(tok2->linkAt(2), "] ;"))
tok2 = tok2->next();
else {
if (tok2->next()->str() == "(")
tok2 = tok2->next()->link();
else if (!inOperator && !Token::Match(tok2->next(), "[|>|;")) {
tok2 = tok2->next();
while (Token::Match(tok2, "*|&") &&
!Token::Match(tok2->next(), ")|>"))
tok2 = tok2->next();
// skip over namespace
while (Token::Match(tok2, "%name% ::"))
tok2 = tok2->tokAt(2);
if (!tok2)
return nullptr;
if (tok2->str() == "(" &&
tok2->link()->next()->str() == "(") {
tok2 = tok2->link();
if (tok2->next()->str() == "(")
tok2 = tok2->next()->link();
}
// skip over typedef parameter
if (tok2->next() && tok2->next()->str() == "(") {
tok2 = tok2->next()->link();
if (tok2->next()->str() == "(")
tok2 = tok2->next()->link();
}
}
}
}
return tok2;
}
void Tokenizer::simplifyTypedef()
{
// Collect all structs for later detection of undefined structs
std::set<std::string> structs;
for (const Token* tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "struct %type% {|:"))
structs.insert(tok->strAt(1));
}
std::vector<Space> spaceInfo;
bool isNamespace = false;
std::string className;
bool hasClass = false;
bool goback = false;
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (_errorLogger && !list.getFiles().empty())
_errorLogger->reportProgress(list.getFiles()[0], "Tokenize (typedef)", tok->progressValue());
if (_settings->terminated())
return;
#ifdef MAXTIME
if (std::time(0) > maxtime)
return;
#endif
if (goback) {
//jump back once, see the comment at the end of the function
goback = false;
tok = tok->previous();
}
if (tok->str() != "typedef") {
if (tok->str() == "(" && tok->strAt(1) == "typedef") {
// Skip typedefs inside parentheses (#2453 and #4002)
tok = tok->next();
} else if (Token::Match(tok, "class|struct|namespace %any%") &&
(!tok->previous() || (tok->previous() && tok->previous()->str() != "enum"))) {
isNamespace = (tok->str() == "namespace");
hasClass = true;
className = tok->next()->str();
} else if (hasClass && tok->str() == ";") {
hasClass = false;
} else if (hasClass && tok->str() == "{") {
Space info;
info.isNamespace = isNamespace;
info.className = className;
info.classEnd = tok->link();
spaceInfo.push_back(info);
hasClass = false;
} else if (!spaceInfo.empty() && tok->str() == "}" && spaceInfo.back().classEnd == tok) {
spaceInfo.pop_back();
}
continue;
}
// pull struct, union, enum or class definition out of typedef
// use typedef name for unnamed struct, union, enum or class
if (Token::Match(tok->next(), "const| struct|enum|union|class %type%| {")) {
Token *tok1 = splitDefinitionFromTypedef(tok);
if (!tok1)
continue;
tok = tok1;
} else if (Token::Match(tok->next(), "const| struct|class %type% :")) {
Token *tok1 = tok;
while (tok1 && tok1->str() != ";" && tok1->str() != "{")
tok1 = tok1->next();
if (tok1 && tok1->str() == "{") {
tok1 = splitDefinitionFromTypedef(tok);
if (!tok1)
continue;
tok = tok1;
}
}
/** @todo add support for union */
if (Token::Match(tok->next(), "enum %type% %type% ;") && tok->strAt(2) == tok->strAt(3)) {
tok->deleteNext(3);
tok->deleteThis();
if (tok->next())
tok->deleteThis();
//now the next token to process is 'tok', not 'tok->next()';
goback = true;
continue;
}
Token *typeName;
Token *typeStart = nullptr;
Token *typeEnd = nullptr;
Token *argStart = nullptr;
Token *argEnd = nullptr;
Token *arrayStart = nullptr;
Token *arrayEnd = nullptr;
Token *specStart = nullptr;
Token *specEnd = nullptr;
Token *typeDef = tok;
Token *argFuncRetStart = nullptr;
Token *argFuncRetEnd = nullptr;
Token *funcStart = nullptr;
Token *funcEnd = nullptr;
Token *tokOffset = tok->next();
bool function = false;
bool functionPtr = false;
bool functionRef = false;
bool functionRetFuncPtr = false;
bool functionPtrRetFuncPtr = false;
bool ptrToArray = false;
bool refToArray = false;
bool ptrMember = false;
bool typeOf = false;
Token *namespaceStart = nullptr;
Token *namespaceEnd = nullptr;
// check for invalid input
if (!tokOffset) {
syntaxError(tok);
return;
}
if (tokOffset->str() == "::") {
typeStart = tokOffset;
tokOffset = tokOffset->next();
while (Token::Match(tokOffset, "%type% ::"))
tokOffset = tokOffset->tokAt(2);
typeEnd = tokOffset;
if (Token::Match(tokOffset, "%type%"))
tokOffset = tokOffset->next();
} else if (Token::Match(tokOffset, "%type% ::")) {
typeStart = tokOffset;
do {
tokOffset = tokOffset->tokAt(2);
} while (Token::Match(tokOffset, "%type% ::"));
typeEnd = tokOffset;
if (Token::Match(tokOffset, "%type%"))
tokOffset = tokOffset->next();
} else if (Token::Match(tokOffset, "%type%")) {
typeStart = tokOffset;
while (Token::Match(tokOffset, "const|signed|unsigned|struct|enum %type%") ||
(tokOffset->next() && tokOffset->next()->isStandardType()))
tokOffset = tokOffset->next();
typeEnd = tokOffset;
tokOffset = tokOffset->next();
bool atEnd = false;
while (!atEnd) {
if (tokOffset && tokOffset->str() == "::") {
typeEnd = tokOffset;
tokOffset = tokOffset->next();
}
if (Token::Match(tokOffset, "%type%") &&
tokOffset->next() && !Token::Match(tokOffset->next(), "[|;|,|(")) {
typeEnd = tokOffset;
tokOffset = tokOffset->next();
} else if (Token::simpleMatch(tokOffset, "const (")) {
typeEnd = tokOffset;
tokOffset = tokOffset->next();
atEnd = true;
} else
atEnd = true;
}
} else
continue; // invalid input
// check for invalid input
if (!tokOffset) {
syntaxError(tok);
return;
}
// check for template
if (!isC() && tokOffset->str() == "<") {
typeEnd = tokOffset->findClosingBracket();
while (typeEnd && Token::Match(typeEnd->next(), ":: %type%"))
typeEnd = typeEnd->tokAt(2);
if (!typeEnd) {
// internal error
return;
}
while (Token::Match(typeEnd->next(), "const|volatile"))
typeEnd = typeEnd->next();
tok = typeEnd;
tokOffset = tok->next();
}
std::list<std::string> pointers;
// check for pointers and references
while (Token::Match(tokOffset, "*|&|&&|const")) {
pointers.push_back(tokOffset->str());
tokOffset = tokOffset->next();
}
// check for invalid input
if (!tokOffset) {
syntaxError(tok);
return;
}
if (Token::Match(tokOffset, "%type%")) {
// found the type name
typeName = tokOffset;
tokOffset = tokOffset->next();
// check for array
if (tokOffset && tokOffset->str() == "[") {
arrayStart = tokOffset;
bool atEnd = false;
while (!atEnd) {
while (tokOffset->next() && !Token::Match(tokOffset->next(), ";|,")) {
tokOffset = tokOffset->next();
}
if (!tokOffset->next())
return; // invalid input
else if (tokOffset->next()->str() == ";")
atEnd = true;
else if (tokOffset->str() == "]")
atEnd = true;
else
tokOffset = tokOffset->next();
}
arrayEnd = tokOffset;
tokOffset = tokOffset->next();
}
// check for end or another
if (Token::Match(tokOffset, ";|,"))
tok = tokOffset;
// or a function typedef
else if (tokOffset && tokOffset->str() == "(") {
// unhandled typedef, skip it and continue
if (typeName->str() == "void") {
unsupportedTypedef(typeDef);
tok = deleteInvalidTypedef(typeDef);
if (tok == list.front())
//now the next token to process is 'tok', not 'tok->next()';
goback = true;
continue;
}
// function pointer
else if (Token::Match(tokOffset, "( * %name% ) (")) {
// name token wasn't a name, it was part of the type
typeEnd = typeEnd->next();
functionPtr = true;
tokOffset = tokOffset->next();
funcStart = tokOffset;
funcEnd = tokOffset;
tokOffset = tokOffset->tokAt(3);
typeName = tokOffset->tokAt(-2);
argStart = tokOffset;
argEnd = tokOffset->link();
tok = argEnd->next();
}
// function
else if (isFunctionHead(tokOffset->link(), ";,")) {
function = true;
if (tokOffset->link()->next()->str() == "const") {
specStart = tokOffset->link()->next();
specEnd = specStart;
}
argStart = tokOffset;
argEnd = tokOffset->link();
tok = argEnd->next();
if (specStart)
tok = tok->next();
}
// syntax error
else {
syntaxError(tok);
return;
}
}
// unhandled typedef, skip it and continue
else {
unsupportedTypedef(typeDef);
tok = deleteInvalidTypedef(typeDef);
if (tok == list.front())
//now the next token to process is 'tok', not 'tok->next()';
goback = true;
continue;
}
}
// typeof: typedef __typeof__ ( ... ) type;
else if (Token::simpleMatch(tokOffset->previous(), "__typeof__ (") &&
Token::Match(tokOffset->link(), ") %type% ;")) {
argStart = tokOffset;
argEnd = tokOffset->link();
typeName = tokOffset->link()->next();
tok = typeName->next();
typeOf = true;
}
// function: typedef ... ( ... type )( ... );
// typedef ... (( ... type )( ... ));
// typedef ... ( * ( ... type )( ... ));
else if (tokOffset->str() == "(" && (
(Token::Match(tokOffset->link()->previous(), "%type% ) (") &&
Token::Match(tokOffset->link()->next()->link(), ") const|volatile|;")) ||
(Token::simpleMatch(tokOffset, "( (") &&
Token::Match(tokOffset->next()->link()->previous(), "%type% ) (") &&
Token::Match(tokOffset->next()->link()->next()->link(), ") const|volatile| ) ;|,")) ||
(Token::simpleMatch(tokOffset, "( * (") &&
Token::Match(tokOffset->linkAt(2)->previous(), "%type% ) (") &&
Token::Match(tokOffset->linkAt(2)->next()->link(), ") const|volatile| ) ;|,")))) {
if (tokOffset->next()->str() == "(")
tokOffset = tokOffset->next();
else if (Token::simpleMatch(tokOffset, "( * (")) {
pointers.push_back("*");
tokOffset = tokOffset->tokAt(2);
}
if (tokOffset->link()->strAt(-2) == "*")
functionPtr = true;
else
function = true;
funcStart = tokOffset->next();
tokOffset = tokOffset->link();
funcEnd = tokOffset->tokAt(-2);
typeName = tokOffset->previous();
argStart = tokOffset->next();
argEnd = tokOffset->next()->link();
tok = argEnd->next();
Token *spec = tok;
if (Token::Match(spec, "const|volatile")) {
specStart = spec;
specEnd = spec;
while (Token::Match(spec->next(), "const|volatile")) {
specEnd = spec->next();
spec = specEnd;
}
tok = specEnd->next();
}
if (tok->str() == ")")
tok = tok->next();
}
else if (Token::Match(tokOffset, "( %type% (")) {
function = true;
if (tokOffset->link()->next()) {
tok = tokOffset->link()->next();
tokOffset = tokOffset->tokAt(2);
typeName = tokOffset->previous();
argStart = tokOffset;
argEnd = tokOffset->link();
} else {
// internal error
continue;
}
}
// pointer to function returning pointer to function
else if (Token::Match(tokOffset, "( * ( * %type% ) (") &&
Token::simpleMatch(tokOffset->linkAt(6), ") ) (") &&
Token::Match(tokOffset->linkAt(6)->linkAt(2), ") ;|,")) {
functionPtrRetFuncPtr = true;
tokOffset = tokOffset->tokAt(6);
typeName = tokOffset->tokAt(-2);
argStart = tokOffset;
argEnd = tokOffset->link();
argFuncRetStart = argEnd->tokAt(2);
argFuncRetEnd = argFuncRetStart->link();
tok = argFuncRetEnd->next();
}
// function returning pointer to function
else if (Token::Match(tokOffset, "( * %type% (") &&
Token::simpleMatch(tokOffset->linkAt(3), ") ) (") &&
Token::Match(tokOffset->linkAt(3)->linkAt(2), ") ;|,")) {
functionRetFuncPtr = true;
tokOffset = tokOffset->tokAt(3);
typeName = tokOffset->previous();
argStart = tokOffset;
argEnd = tokOffset->link();
argFuncRetStart = argEnd->tokAt(2);
argFuncRetEnd = argFuncRetStart->link();
tok = argFuncRetEnd->next();
} else if (Token::Match(tokOffset, "( * ( %type% ) (")) {
functionRetFuncPtr = true;
tokOffset = tokOffset->tokAt(5);
typeName = tokOffset->tokAt(-2);
argStart = tokOffset;
argEnd = tokOffset->link();
argFuncRetStart = argEnd->tokAt(2);
argFuncRetEnd = argFuncRetStart->link();
tok = argFuncRetEnd->next();
}
// pointer/reference to array
else if (Token::Match(tokOffset, "( *|& %type% ) [")) {
ptrToArray = (tokOffset->next()->str() == "*");
refToArray = !ptrToArray;
tokOffset = tokOffset->tokAt(2);
typeName = tokOffset;
arrayStart = tokOffset->tokAt(2);
arrayEnd = arrayStart->link();
tok = arrayEnd->next();
}
// pointer to class member
else if (Token::Match(tokOffset, "( %type% :: * %type% ) ;")) {
tokOffset = tokOffset->tokAt(2);
namespaceStart = tokOffset->previous();
namespaceEnd = tokOffset;
ptrMember = true;
tokOffset = tokOffset->tokAt(2);
typeName = tokOffset;
tok = tokOffset->tokAt(2);
}
// unhandled typedef, skip it and continue
else {
unsupportedTypedef(typeDef);
tok = deleteInvalidTypedef(typeDef);
if (tok == list.front())
//now the next token to process is 'tok', not 'tok->next()';
goback = true;
continue;
}
bool done = false;
bool ok = true;
while (!done) {
std::string pattern = typeName->str();
int scope = 0;
bool simplifyType = false;
bool inMemberFunc = false;
int memberScope = 0;
bool globalScope = false;
std::size_t classLevel = spaceInfo.size();
for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
if (_settings->terminated())
return;
// check for end of scope
if (tok2->str() == "}") {
// check for end of member function
if (inMemberFunc) {
--memberScope;
if (memberScope == 0)
inMemberFunc = false;
}
if (classLevel > 0 && tok2 == spaceInfo[classLevel - 1].classEnd) {
--classLevel;
pattern.clear();
for (std::size_t i = classLevel; i < spaceInfo.size(); ++i)
pattern += (spaceInfo[i].className + " :: ");
pattern += typeName->str();
} else {
--scope;
if (scope < 0)
break;
}
}
// check for operator typedef
/** @todo add support for multi-token operators */
else if (tok2->str() == "operator" &&
tok2->next()->str() == typeName->str() &&
tok2->strAt(2) == "(" &&
Token::Match(tok2->linkAt(2), ") const| {")) {
// check for qualifier
if (tok2->previous()->str() == "::") {
// check for available and matching class name
if (!spaceInfo.empty() && classLevel < spaceInfo.size() &&
tok2->strAt(-2) == spaceInfo[classLevel].className) {
tok2 = tok2->next();
simplifyType = true;
}
}
}
// check for member functions
else if (Token::Match(tok2, ") const| {")) {
const Token *func = tok2->link()->previous();
if (!func)
continue;
if (func->previous()) { // Ticket #4239
/** @todo add support for multi-token operators */
if (func->previous()->str() == "operator")
func = func->previous();
// check for qualifier
if (func->previous()->str() == "::") {
// check for available and matching class name
if (!spaceInfo.empty() && classLevel < spaceInfo.size() &&
func->strAt(-2) == spaceInfo[classLevel].className) {
memberScope = 0;
inMemberFunc = true;
}
}
}
}
// check for entering a new namespace
else if (Token::Match(tok2, "namespace %any% {")) {
if (classLevel < spaceInfo.size() &&
spaceInfo[classLevel].isNamespace &&
spaceInfo[classLevel].className == tok2->next()->str()) {
++classLevel;
pattern.clear();
for (std::size_t i = classLevel; i < spaceInfo.size(); ++i)
pattern += (spaceInfo[i].className + " :: ");
pattern += typeName->str();
}
++scope;
}
// check for entering a new scope
else if (tok2->str() == "{") {
// keep track of scopes within member function
if (inMemberFunc)
++memberScope;
++scope;
}
// check for typedef that can be substituted
else if (Token::Match(tok2, pattern.c_str()) ||
(inMemberFunc && tok2->str() == typeName->str())) {
// member function class variables don't need qualification
if (!(inMemberFunc && tok2->str() == typeName->str()) && pattern.find("::") != std::string::npos) { // has a "something ::"
Token *start = tok2;
size_t count = 0;
int back = int(classLevel) - 1;
bool good = true;
// check for extra qualification
while (back >= 0 && Token::Match(start->tokAt(-2), "%type% ::")) {
if (start->strAt(-2) == spaceInfo[back].className) {
start = start->tokAt(-2);
back--;
count++;
} else {
good = false;
break;
}
}
// check global namespace
if (good && back == 0 && start->strAt(-1) == "::")
good = false;
if (good) {
// remove any extra qualification if present
while (count) {
tok2->tokAt(-3)->deleteNext(2);
--count;
}
// remove global namespace if present
if (tok2->strAt(-1) == "::") {
tok2->tokAt(-2)->deleteNext();
globalScope = true;
}
// remove qualification if present
for (std::size_t i = classLevel; i < spaceInfo.size(); ++i) {
tok2->deleteNext(2);
}
simplifyType = true;
}
} else {
if (tok2->strAt(-1) == "::") {
// Don't replace this typename if it's preceded by "::" unless it's a namespace
if (!spaceInfo.empty() && (tok2->strAt(-2) == spaceInfo[0].className) && spaceInfo[0].isNamespace) {
tok2->tokAt(-3)->deleteNext(2);
simplifyType = true;
}
} else if (Token::Match(tok2->previous(), "case %type% :")) {
tok2 = tok2->next();
} else if (duplicateTypedef(&tok2, typeName, typeDef, structs)) {
// skip to end of scope if not already there
if (tok2->str() != "}") {
while (tok2->next()) {
if (tok2->next()->str() == "{")
tok2 = tok2->linkAt(1)->previous();
else if (tok2->next()->str() == "}")
break;
tok2 = tok2->next();
}
}
} else if (tok2->tokAt(-2) && Token::Match(tok2->tokAt(-2), "%type% *|&")) {
// Ticket #5868: Don't substitute variable names
} else if (tok2->previous()->str() != ".") {
simplifyType = true;
}
}
}
if (simplifyType) {
// can't simplify 'operator functionPtr ()' and 'functionPtr operator ... ()'
if (functionPtr && (tok2->previous()->str() == "operator" ||
tok2->next()->str() == "operator")) {
simplifyType = false;
tok2 = tok2->next();
continue;
}
// There are 2 categories of typedef substitutions:
// 1. variable declarations that preserve the variable name like
// global, local, and function parameters
// 2. not variable declarations that have no name like derived
// classes, casts, operators, and template parameters
// try to determine which category this substitution is
bool inCast = false;
bool inTemplate = false;
bool inOperator = false;
bool inSizeof = false;
// check for derived class: class A : some_typedef {
bool isDerived = Token::Match(tok2->previous(), "public|protected|private %type% {|,");
// check for cast: (some_typedef) A or static_cast<some_typedef>(A)
// todo: check for more complicated casts like: (const some_typedef *)A
if ((tok2->previous()->str() == "(" && tok2->next()->str() == ")" && tok2->strAt(-2) != "sizeof") ||
(tok2->previous()->str() == "<" && Token::simpleMatch(tok2->next(), "> (")))
inCast = true;
// check for template parameters: t<some_typedef> t1
else if (Token::Match(tok2->previous(), "<|,") &&
Token::Match(tok2->next(), "&|*| &|*| >|,"))
inTemplate = true;
else if (Token::Match(tok2->tokAt(-2), "sizeof ( %type% )"))
inSizeof = true;
// check for operator
if (tok2->strAt(-1) == "operator" ||
Token::simpleMatch(tok2->tokAt(-2), "operator const"))
inOperator = true;
// skip over class or struct in derived class declaration
bool structRemoved = false;
if (isDerived && Token::Match(typeStart, "class|struct")) {
if (typeStart->str() == "struct")
structRemoved = true;
typeStart = typeStart->next();
}
// start substituting at the typedef name by replacing it with the type
tok2->str(typeStart->str());
// restore qualification if it was removed
if (typeStart->str() == "struct" || structRemoved) {
if (structRemoved)
tok2 = tok2->previous();
if (globalScope) {
tok2->insertToken("::");
tok2 = tok2->next();
}
for (std::size_t i = classLevel; i < spaceInfo.size(); ++i) {
tok2->insertToken(spaceInfo[i].className);
tok2 = tok2->next();
tok2->insertToken("::");
tok2 = tok2->next();
}
}
// add remainder of type
tok2 = copyTokens(tok2, typeStart->next(), typeEnd);
if (!pointers.empty()) {
for (std::list<std::string>::const_iterator iter = pointers.begin(); iter != pointers.end(); ++iter) {
tok2->insertToken(*iter);
tok2 = tok2->next();
}
}
if (funcStart && funcEnd) {
tok2->insertToken("(");
tok2 = tok2->next();
Token *tok3 = tok2;
tok2 = copyTokens(tok2, funcStart, funcEnd);
if (!inCast)
tok2 = processFunc(tok2, inOperator);
if (!tok2)
break;
tok2->insertToken(")");
tok2 = tok2->next();
Token::createMutualLinks(tok2, tok3);
tok2 = copyTokens(tok2, argStart, argEnd);
if (specStart) {
Token *spec = specStart;
tok2->insertToken(spec->str());
tok2 = tok2->next();
while (spec != specEnd) {
spec = spec->next();
tok2->insertToken(spec->str());
tok2 = tok2->next();
}
}
}
else if (functionPtr || functionRef || function) {
// don't add parentheses around function names because it
// confuses other simplifications
bool needParen = true;
if (!inTemplate && function && tok2->next() && tok2->next()->str() != "*")
needParen = false;
if (needParen) {
tok2->insertToken("(");
tok2 = tok2->next();
}
Token *tok3 = tok2;
if (namespaceStart) {
const Token *tok4 = namespaceStart;
while (tok4 != namespaceEnd) {
tok2->insertToken(tok4->str());
tok2 = tok2->next();
tok4 = tok4->next();
}
tok2->insertToken(namespaceEnd->str());
tok2 = tok2->next();
}
if (functionPtr) {
tok2->insertToken("*");
tok2 = tok2->next();
} else if (functionRef) {
tok2->insertToken("&");
tok2 = tok2->next();
}
if (!inCast)
tok2 = processFunc(tok2, inOperator);
if (needParen) {
tok2->insertToken(")");
tok2 = tok2->next();
Token::createMutualLinks(tok2, tok3);
}
tok2 = copyTokens(tok2, argStart, argEnd);
if (inTemplate)
tok2 = tok2->next();
if (specStart) {
Token *spec = specStart;
tok2->insertToken(spec->str());
tok2 = tok2->next();
while (spec != specEnd) {
spec = spec->next();
tok2->insertToken(spec->str());
tok2 = tok2->next();
}
}
} else if (functionRetFuncPtr || functionPtrRetFuncPtr) {
tok2->insertToken("(");
tok2 = tok2->next();
Token *tok3 = tok2;
tok2->insertToken("*");
tok2 = tok2->next();
Token * tok4 = 0;
if (functionPtrRetFuncPtr) {
tok2->insertToken("(");
tok2 = tok2->next();
tok4 = tok2;
tok2->insertToken("*");
tok2 = tok2->next();
}
// skip over variable name if there
if (!inCast) {
if (tok2->next()->str() != ")")
tok2 = tok2->next();
}
if (tok4 && functionPtrRetFuncPtr) {
tok2->insertToken(")");
tok2 = tok2->next();
Token::createMutualLinks(tok2, tok4);
}
tok2 = copyTokens(tok2, argStart, argEnd);
tok2->insertToken(")");
tok2 = tok2->next();
Token::createMutualLinks(tok2, tok3);
tok2 = copyTokens(tok2, argFuncRetStart, argFuncRetEnd);
} else if (ptrToArray || refToArray) {
tok2->insertToken("(");
tok2 = tok2->next();
Token *tok3 = tok2;
if (ptrToArray)
tok2->insertToken("*");
else
tok2->insertToken("&");
tok2 = tok2->next();
// skip over name
if (tok2->next()->str() != ")") {
if (tok2->next()->str() != "(")
tok2 = tok2->next();
// check for function and skip over args
if (tok2->next()->str() == "(")
tok2 = tok2->next()->link();
// check for array
if (tok2->next()->str() == "[")
tok2 = tok2->next()->link();
} else {
// syntax error
}
tok2->insertToken(")");
Token::createMutualLinks(tok2->next(), tok3);
} else if (ptrMember) {
if (Token::simpleMatch(tok2, "* (")) {
tok2->insertToken("*");
tok2 = tok2->next();
} else {
tok2->insertToken("(");
tok2 = tok2->next();
Token *tok3 = tok2;
const Token *tok4 = namespaceStart;
while (tok4 != namespaceEnd) {
tok2->insertToken(tok4->str());
tok2 = tok2->next();
tok4 = tok4->next();
}
tok2->insertToken(namespaceEnd->str());
tok2 = tok2->next();
tok2->insertToken("*");
tok2 = tok2->next();
// skip over name
tok2 = tok2->next();
tok2->insertToken(")");
tok2 = tok2->next();
Token::createMutualLinks(tok2, tok3);
}
} else if (typeOf) {
tok2 = copyTokens(tok2, argStart, argEnd);
} else if (tok2->tokAt(2) && tok2->strAt(2) == "[") {
while (tok2->tokAt(2) && tok2->strAt(2) == "[")
tok2 = tok2->linkAt(2)->previous();
}
if (arrayStart && arrayEnd) {
do {
if (!tok2->next()) {
syntaxError(tok2);
return; // can't recover so quit
}
if (!inCast && !inSizeof)
tok2 = tok2->next();
// reference to array?
if (tok2->str() == "&") {
tok2 = tok2->previous();
tok2->insertToken("(");
Token *tok3 = tok2->next();
// handle missing variable name
if (tok2->strAt(3) == ")" || tok2->strAt(3) == ",")
tok2 = tok2->tokAt(2);
else
tok2 = tok2->tokAt(3);
tok2->insertToken(")");
tok2 = tok2->next();
Token::createMutualLinks(tok2, tok3);
}
if (!tok2->next()) {
syntaxError(tok2);
return; // can't recover so quit
}
tok2 = copyTokens(tok2, arrayStart, arrayEnd);
tok2 = tok2->next();
if (tok2->str() == "=") {
if (tok2->next()->str() == "{")
tok2 = tok2->next()->link()->next();
else if (tok2->next()->str().at(0) == '\"')
tok2 = tok2->tokAt(2);
}
} while (Token::Match(tok2, ", %name% ;|=|,"));
}
simplifyType = false;
}
}
if (tok->str() == ";")
done = true;
else if (tok->str() == ",") {
arrayStart = 0;
arrayEnd = 0;
tokOffset = tok->next();
pointers.clear();
while (Token::Match(tokOffset, "*|&")) {
pointers.push_back(tokOffset->str());
tokOffset = tokOffset->next();
}
if (Token::Match(tokOffset, "%type%")) {
typeName = tokOffset;
tokOffset = tokOffset->next();
if (tokOffset && tokOffset->str() == "[") {
arrayStart = tokOffset;
for (;;) {
while (tokOffset->next() && !Token::Match(tokOffset->next(), ";|,"))
tokOffset = tokOffset->next();
if (!tokOffset->next())
return; // invalid input
else if (tokOffset->next()->str() == ";")
break;
else if (tokOffset->str() == "]")
break;
else
tokOffset = tokOffset->next();
}
arrayEnd = tokOffset;
tokOffset = tokOffset->next();
}
if (Token::Match(tokOffset, ";|,"))
tok = tokOffset;
else {
// we encountered a typedef we don't support yet so just continue
done = true;
ok = false;
}
} else {
// we encountered a typedef we don't support yet so just continue
done = true;
ok = false;
}
} else {
// something is really wrong (internal error)
done = true;
ok = false;
}
}
if (ok) {
// remove typedef
Token::eraseTokens(typeDef, tok);
if (typeDef != list.front()) {
tok = typeDef->previous();
tok->deleteNext();
//no need to remove last token in the list
if (tok->tokAt(2))
tok->deleteNext();
} else {
list.front()->deleteThis();
//no need to remove last token in the list
if (list.front()->next())
list.front()->deleteThis();
tok = list.front();
//now the next token to process is 'tok', not 'tok->next()';
goback = true;
}
}
}
}
void Tokenizer::simplifyMulAndParens()
{
if (!list.front())
return;
for (Token *tok = list.front()->tokAt(3); tok; tok = tok->next()) {
if (tok->isName()) {
//fix ticket #2784 - improved by ticket #3184
unsigned int closedpars = 0;
Token *tokend = tok->next();
Token *tokbegin = tok->previous();
while (tokend && tokend->str() == ")") {
++closedpars;
tokend = tokend->next();
}
if (!tokend || !(tokend->isAssignmentOp()))
continue;
while (Token::Match(tokbegin, "&|(")) {
if (tokbegin->str() == "&") {
if (Token::Match(tokbegin->tokAt(-2), "[;{}&(] *")) {
//remove '* &'
tokbegin = tokbegin->tokAt(-2);
tokbegin->deleteNext(2);
} else if (Token::Match(tokbegin->tokAt(-3), "[;{}&(] * (")) {
if (!closedpars)
break;
--closedpars;
//remove ')'
tok->deleteNext();
//remove '* ( &'
tokbegin = tokbegin->tokAt(-3);
tokbegin->deleteNext(3);
} else
break;
} else if (tokbegin->str() == "(") {
if (!closedpars)
break;
//find consecutive opening parentheses
unsigned int openpars = 0;
while (tokbegin && tokbegin->str() == "(" && openpars <= closedpars) {
++openpars;
tokbegin = tokbegin->previous();
}
if (!tokbegin || openpars > closedpars)
break;
if ((openpars == closedpars && Token::Match(tokbegin, "[;{}]")) ||
Token::Match(tokbegin->tokAt(-2), "[;{}&(] * &") ||
Token::Match(tokbegin->tokAt(-3), "[;{}&(] * ( &")) {
//remove the excessive parentheses around the variable
while (openpars) {
tok->deleteNext();
tokbegin->deleteNext();
--closedpars;
--openpars;
}
} else
break;
}
}
}
}
}
bool Tokenizer::tokenize(std::istream &code,
const char FileName[],
const std::string &configuration,
bool noSymbolDB_AST)
{
// make sure settings specified
assert(_settings);
// Fill the map _typeSize..
fillTypeSizes();
_configuration = configuration;
if (!list.createTokens(code, Path::getRelativePath(Path::simplifyPath(FileName), _settings->_basePaths))) {
cppcheckError(0);
return false;
}
if (simplifyTokenList1(FileName)) {
if (!noSymbolDB_AST) {
createSymbolDatabase();
// Use symbol database to identify rvalue references. Split && to & &. This is safe, since it doesn't delete any tokens (which might be referenced by symbol database)
for (std::size_t i = 0; i < _symbolDatabase->getVariableListSize(); i++) {
const Variable* var = _symbolDatabase->getVariableFromVarId(i);
if (var && var->isRValueReference()) {
const_cast<Token*>(var->typeEndToken())->str("&");
const_cast<Token*>(var->typeEndToken())->insertToken("&");
const_cast<Token*>(var->typeEndToken()->next())->scope(var->typeEndToken()->scope());
}
}
list.createAst();
ValueFlow::setValues(&list, _symbolDatabase, _errorLogger, _settings);
}
return true;
}
return false;
}
//---------------------------------------------------------------------------
bool Tokenizer::tokenizeCondition(const std::string &code)
{
assert(_settings);
// Fill the map _typeSize..
fillTypeSizes();
{
std::istringstream istr(code);
if (!list.createTokens(istr)) {
cppcheckError(0);
return false;
}
}
// Combine strings
combineStrings();
// Remove "volatile", "inline", "register", and "restrict"
simplifyKeyword();
// convert platform dependent types to standard types
// 32 bits: size_t -> unsigned long
// 64 bits: size_t -> unsigned long long
simplifyPlatformTypes();
// collapse compound standard types into a single token
// unsigned long long int => long _isUnsigned=true,_isLong=true
simplifyStdType();
// Concatenate double sharp: 'a ## b' -> 'ab'
concatenateDoubleSharp();
createLinks();
// replace 'NULL' and similar '0'-defined macros with '0'
simplifyNull();
// replace 'sin(0)' to '0' and other similar math expressions
simplifyMathExpressions();
// combine "- %num%"
concatenateNegativeNumberAndAnyPositive();
// simplify simple calculations
for (Token *tok = list.front() ? list.front()->next() : nullptr;
tok;
tok = tok->next()) {
if (tok->isNumber())
TemplateSimplifier::simplifyNumericCalculations(tok->previous());
}
combineOperators();
simplifyRedundantParentheses();
for (Token *tok = list.front();
tok;
tok = tok->next())
while (TemplateSimplifier::simplifyNumericCalculations(tok))
;
simplifyCAlternativeTokens();
// Convert e.g. atol("0") into 0
simplifyMathFunctions();
simplifyDoublePlusAndDoubleMinus();
return true;
}
void Tokenizer::findComplicatedSyntaxErrorsInTemplates()
{
const Token *tok = TemplateSimplifier::hasComplicatedSyntaxErrorsInTemplates(list.front());
if (tok)
syntaxError(tok);
}
bool Tokenizer::hasEnumsWithTypedef()
{
for (const Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "enum %name% {")) {
tok = tok->tokAt(2);
const Token *tok2 = Token::findsimplematch(tok, "typedef", tok->link());
if (tok2)
syntaxError(tok2);
tok = tok->link();
}
}
return false;
}
void Tokenizer::fillTypeSizes()
{
_typeSize.clear();
_typeSize["char"] = 1;
_typeSize["char16_t"] = 2;
_typeSize["char32_t"] = 4;
_typeSize["bool"] = _settings->sizeof_bool;
_typeSize["short"] = _settings->sizeof_short;
_typeSize["int"] = _settings->sizeof_int;
_typeSize["long"] = _settings->sizeof_long;
_typeSize["float"] = _settings->sizeof_float;
_typeSize["double"] = _settings->sizeof_double;
_typeSize["wchar_t"] = _settings->sizeof_wchar_t;
_typeSize["size_t"] = _settings->sizeof_size_t;
_typeSize["*"] = _settings->sizeof_pointer;
}
void Tokenizer::combineOperators()
{
// Combine tokens..
for (Token *tok = list.front();
tok && tok->next();
tok = tok->next()) {
const char c1 = tok->str()[0];
if (tok->str().length() == 1 && tok->next()->str().length() == 1) {
const char c2 = tok->next()->str()[0];
// combine +-*/ and =
if (c2 == '=' && (std::strchr("+-*/%&|^=!<>", c1))) {
tok->str(tok->str() + c2);
tok->deleteNext();
continue;
}
// replace "->" with "."
else if (c1 == '-' && c2 == '>') {
tok->str(".");
tok->originalName("->");
tok->deleteNext();
continue;
}
}
else if (tok->str() == ">>" && tok->next()->str() == "=") {
tok->str(">>=");
tok->deleteNext();
}
else if (tok->str() == "<<" && tok->next()->str() == "=") {
tok->str("<<=");
tok->deleteNext();
}
else if ((c1 == 'p' || c1 == '_') && tok->next()->str() == ":" && tok->strAt(2) != ":") {
if (Token::Match(tok, "private|protected|public|__published")) {
tok->str(tok->str() + ":");
tok->deleteNext();
continue;
}
}
}
}
void Tokenizer::combineStrings()
{
// Combine wide strings
for (Token *tok = list.front();
tok;
tok = tok->next()) {
while (tok->str() == "L" && tok->next() && tok->next()->type() == Token::eString) {
// Combine 'L "string"'
tok->str(tok->next()->str());
tok->deleteNext();
tok->isLong(true);
}
}
// Combine strings
for (Token *tok = list.front();
tok;
tok = tok->next()) {
if (tok->str()[0] != '"')
continue;
tok->str(simplifyString(tok->str()));
while (tok->next() && tok->next()->type() == Token::eString) {
tok->next()->str(simplifyString(tok->next()->str()));
// Two strings after each other, combine them
tok->concatStr(tok->next()->str());
tok->deleteNext();
}
}
}
void Tokenizer::concatenateDoubleSharp()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {
while (Token::Match(tok, "%num%|%name% ## %num%|%name%")) {
tok->str(tok->str() + tok->strAt(2));
tok->deleteNext(2);
}
}
}
void Tokenizer::simplifyFileAndLineMacro()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->str() == "__FILE__")
tok->str("\"" + list.file(tok) + "\"");
else if (tok->str() == "__LINE__")
tok->str(MathLib::toString(tok->linenr()));
}
}
void Tokenizer::simplifyNull()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->str() == "NULL" && (!Token::Match(tok->previous(), "[(,] NULL [,)]") || tok->strAt(-2) == "="))
tok->str("0");
else if (tok->str() == "__null" || tok->str() == "'\\0'" || tok->str() == "'\\x0'") {
tok->originalName(tok->str());
tok->str("0");
} else if (tok->isNumber() &&
MathLib::isInt(tok->str()) &&
MathLib::toLongNumber(tok->str()) == 0)
tok->str("0");
}
// nullptr..
if (isCPP() && _settings->standards.cpp == Standards::CPP11) {
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->str() == "nullptr")
tok->str("0");
}
}
}
void Tokenizer::concatenateNegativeNumberAndAnyPositive()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (!Token::Match(tok, "?|:|,|(|[|{|return|case|sizeof|%op% +|-") || tok->type() == Token::eIncDecOp)
continue;
if (tok->next()->str() == "+")
tok->deleteNext();
else if (Token::Match(tok->next(), "- %num%")) {
tok->deleteNext();
tok->next()->str("-" + tok->next()->str());
}
}
}
void Tokenizer::simplifyExternC()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "extern \"C\" {|")) {
if (tok->strAt(2) == "{") {
tok->linkAt(2)->deleteThis();
tok->deleteNext(2);
} else
tok->deleteNext();
tok->deleteThis();
}
}
}
void Tokenizer::simplifyRoundCurlyParentheses()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {
while (Token::Match(tok, "[;{}:] ( {") &&
Token::simpleMatch(tok->linkAt(2), "} ) ;")) {
if (tok->str() == ":" && !Token::Match(tok->tokAt(-2),"[;{}] %type% :"))
break;
Token *end = tok->linkAt(2)->tokAt(-3);
if (Token::Match(end, "[;{}] %num%|%str% ;"))
end->deleteNext(2);
tok->linkAt(2)->previous()->deleteNext(3);
tok->deleteNext(2);
}
if (Token::Match(tok, "( { %bool%|%char%|%num%|%str%|%name% ; } )")) {
tok->deleteNext();
tok->deleteThis();
tok->deleteNext(3);
}
}
}
void Tokenizer::simplifySQL()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "EXEC SQL")) {
const Token *end = tok->tokAt(2);
while (end && end->str() != ";")
end = end->next();
std::string instruction = tok->stringifyList(end);
// delete all tokens until ';'
Token::eraseTokens(tok, end);
// insert "asm ( "instruction" ) ;"
tok->str("asm");
// it can happen that 'end' is NULL when wrong code is inserted
if (!tok->next())
tok->insertToken(";");
tok->insertToken(")");
tok->insertToken("\"" + instruction + "\"");
tok->insertToken("(");
// jump to ';' and continue
tok = tok->tokAt(3);
}
}
}
void Tokenizer::simplifyDebugNew()
{
if (!_settings->isWindowsPlatform())
return;
// convert Microsoft DEBUG_NEW macro to new
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->str() == "DEBUG_NEW")
tok->str("new");
}
}
void Tokenizer::simplifyArrayAccessSyntax()
{
// 0[a] -> a[0]
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "%num% [ %name% ]")) {
std::string temp = tok->str();
tok->str(tok->strAt(2));
tok->tokAt(2)->str(temp);
}
}
}
void Tokenizer::simplifyParameterVoid()
{
for (Token* tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "%name% ( void )"))
tok->next()->deleteNext();
}
}
void Tokenizer::simplifyRedundantConsecutiveBraces()
{
// Remove redundant consecutive braces, i.e. '.. { { .. } } ..' -> '.. { .. } ..'.
for (Token *tok = list.front(); tok;) {
if (Token::simpleMatch(tok, "= {")) {
tok = tok->linkAt(1);
} else if (Token::simpleMatch(tok, "{ {") && Token::simpleMatch(tok->next()->link(), "} }")) {
//remove internal parentheses
tok->next()->link()->deleteThis();
tok->deleteNext();
} else
tok = tok->next();
}
}
void Tokenizer::simplifyDoublePlusAndDoubleMinus()
{
// Convert + + into + and + - into -
for (Token *tok = list.front(); tok; tok = tok->next()) {
while (tok->next()) {
if (tok->str() == "+") {
if (tok->next()->str() == "+") {
tok->deleteNext();
continue;
} else if (tok->next()->str()[0] == '-') {
tok = tok->next();
if (tok->str().size() == 1) {
tok = tok->previous();
tok->str("-");
tok->deleteNext();
} else if (tok->isNumber()) {
tok->str(tok->str().substr(1));
tok = tok->previous();
tok->str("-");
}
continue;
}
} else if (tok->str() == "-") {
if (tok->next()->str() == "+") {
tok->deleteNext();
continue;
} else if (tok->next()->str()[0] == '-') {
tok = tok->next();
if (tok->str().size() == 1) {
tok = tok->previous();
tok->str("+");
tok->deleteNext();
} else if (tok->isNumber()) {
tok->str(tok->str().substr(1));
tok = tok->previous();
tok->str("+");
}
continue;
}
}
break;
}
}
}
/** Specify array size if it hasn't been given */
void Tokenizer::arraySize()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {
bool addlength = false;
if (Token::Match(tok, "%name% [ ] = { %str% } ;")) {
Token *t = tok->tokAt(3);
t->deleteNext();
t->next()->deleteNext();
addlength = true;
}
if (addlength || Token::Match(tok, "%name% [ ] = %str% ;")) {
tok = tok->next();
std::size_t sz = Token::getStrSize(tok->tokAt(3));
tok->insertToken(MathLib::toString((unsigned int)sz));
tok = tok->tokAt(5);
}
else if (Token::Match(tok, "%name% [ ] = {")) {
unsigned int sz = 1;
tok = tok->next();
Token *end = tok->linkAt(3);
for (Token *tok2 = tok->tokAt(4); tok2 && tok2 != end; tok2 = tok2->next()) {
if (tok2->link() && Token::Match(tok2, "{|(|[|<")) {
if (tok2->str() == "[" && tok2->link()->strAt(1) == "=") { // designated initializer
if (Token::Match(tok2, "[ %num% ]"))
sz = std::max(sz, (unsigned int)MathLib::toULongNumber(tok2->strAt(1)) + 1U);
else {
sz = 0;
break;
}
}
tok2 = tok2->link();
} else if (tok2->str() == "<") { // Bailout. TODO: When link() supports <>, this bailout becomes unnecessary
sz = 0;
break;
} else if (tok2->str() == ",") {
if (!Token::Match(tok2->next(), "[},]"))
++sz;
else {
tok2 = tok2->previous();
tok2->deleteNext();
}
}
}
if (sz != 0)
tok->insertToken(MathLib::toString(sz));
tok = end->next() ? end->next() : end;
}
}
}
static Token *skipTernaryOp(Token *tok)
{
if (!tok || tok->str() != "?")
return tok;
unsigned int colonlevel = 1;
while (nullptr != (tok = tok->next())) {
if (tok->str() == "?") {
++colonlevel;
} else if (tok->str() == ":") {
--colonlevel;
if (colonlevel == 0) {
tok = tok->next();
break;
}
}
if (Token::Match(tok->next(), "[{};]"))
break;
}
if (colonlevel) // Ticket #5214: Make sure the ':' matches the proper '?'
return 0;
return tok;
}
Token * Tokenizer::startOfFunction(Token * tok)
{
if (tok && tok->str() == ")") {
tok = tok->next();
while (tok && tok->str() != "{") {
if (Token::Match(tok, "const|volatile")) {
tok = tok->next();
} else if (tok->str() == "noexcept") {
tok = tok->next();
if (tok && tok->str() == "(") {
tok = tok->link()->next();
}
} else if (tok->str() == "throw" && tok->next() && tok->next()->str() == "(") {
tok = tok->next()->link()->next();
}
// unknown macros ") MACRO {" and ") MACRO(...) {"
else if (tok->isUpperCaseName()) {
tok = tok->next();
if (tok && tok->str() == "(") {
tok = tok->link()->next();
}
} else
return nullptr;
}
return tok;
}
return nullptr;
}
const Token * Tokenizer::startOfExecutableScope(const Token * tok)
{
if (tok && tok->str() == ")") {
tok = tok->next();
bool inInit = false;
while (tok && tok->str() != "{") {
if (!inInit) {
if (Token::Match(tok, "const|volatile")) {
tok = tok->next();
} else if (tok->str() == "noexcept") {
tok = tok->next();
if (tok && tok->str() == "(") {
tok = tok->link()->next();
}
} else if (tok->str() == "throw" && tok->next() && tok->next()->str() == "(") {
tok = tok->next()->link()->next();
} else if (tok->str() == ":") {
inInit = true;
tok = tok->next();
}
// unknown macros ") MACRO {" and ") MACRO(...) {"
else if (tok->isUpperCaseName()) {
tok = tok->next();
if (tok && tok->str() == "(") {
tok = tok->link()->next();
}
} else
return nullptr;
} else {
if (tok->isName() && tok->next() && (tok->next()->str() == "(" ||
(inInit && tok->next()->str() == "{"))) {
tok = tok->next()->link()->next();
} else if (tok->str() == ",") {
tok = tok->next();
} else
return nullptr;
}
}
return tok;
}
return nullptr;
}
/** simplify labels and case|default in the code: add a ";" if not already in.*/
void Tokenizer::simplifyLabelsCaseDefault()
{
bool executablescope = false;
unsigned int indentlevel = 0;
for (Token *tok = list.front(); tok; tok = tok->next()) {
// Simplify labels in the executable scope..
Token *start = startOfExecutableScope(tok);
if (start) {
tok = start;
executablescope = true;
}
if (!executablescope)
continue;
if (tok->str() == "{") {
if (tok->previous()->str() == "=")
tok = tok->link();
else
++indentlevel;
} else if (tok->str() == "}") {
--indentlevel;
if (!indentlevel) {
executablescope = false;
continue;
}
} else if (Token::Match(tok, "(|["))
tok = tok->link();
if (Token::Match(tok, "[;{}] case")) {
while (nullptr != (tok = tok->next())) {
if (Token::Match(tok, "(|[")) {
tok = tok->link();
} else if (tok->str() == "?") {
Token *tok1 = skipTernaryOp(tok);
if (!tok1) {
syntaxError(tok);
}
tok = tok1;
}
if (Token::Match(tok->next(),"[:{};]"))
break;
}
if (!tok)
break;
if (tok->str() != "case" && tok->next() && tok->next()->str() == ":") {
tok = tok->next();
if (tok->next()->str() != ";")
tok->insertToken(";");
} else {
syntaxError(tok);
}
} else if (Token::Match(tok, "[;{}] %name% : !!;")) {
tok = tok->tokAt(2);
tok->insertToken(";");
}
}
}
void Tokenizer::simplifyTemplates()
{
if (isC())
return;
for (const Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->str()[0] == '=' && tok->str().length() > 2) {
std::cout << "BAD TOKEN" << std::endl;
}
}
for (Token *tok = list.front(); tok; tok = tok->next()) {
// #2648 - simple fix for sizeof used as template parameter
// TODO: this is a bit hardcoded. make a bit more generic
if (Token::Match(tok, "%name% < sizeof ( %type% ) >") && tok->tokAt(4)->isStandardType()) {
Token * const tok3 = tok->next();
const unsigned int sizeOfResult = sizeOfType(tok3->tokAt(3));
tok3->deleteNext(4);
tok3->insertToken(MathLib::toString(sizeOfResult));
}
// Ticket #6181: normalize C++11 template parameter list closing syntax
if (tok->str() == "<" && TemplateSimplifier::templateParameters(tok)) {
Token *endTok = tok->findClosingBracket();
if (endTok && endTok->str() == ">>") {
endTok->str(">");
endTok->insertToken(">");
}
}
}
TemplateSimplifier::simplifyTemplates(
list,
_errorLogger,
_settings,
_codeWithTemplates);
}
//---------------------------------------------------------------------------
static bool setVarIdParseDeclaration(const Token **tok, const std::map<std::string,unsigned int> &variableId, bool executableScope, bool cpp, bool c)
{
const Token *tok2 = *tok;
if (!tok2->isName())
return false;
unsigned int typeCount = 0;
unsigned int singleNameCount = 0;
bool hasstruct = false; // Is there a "struct" or "class"?
bool bracket = false;
bool ref = false;
while (tok2) {
if (tok2->isName()) {
if (cpp && Token::Match(tok2, "namespace|public|private|protected"))
return false;
if (Token::Match(tok2, "struct|union") || (!c && Token::Match(tok2, "class|typename"))) {
hasstruct = true;
typeCount = 0;
singleNameCount = 0;
} else if (tok2->str() == "const") {
; // just skip "const"
} else if (!hasstruct && variableId.find(tok2->str()) != variableId.end() && tok2->previous()->str() != "::") {
++typeCount;
tok2 = tok2->next();
if (!tok2 || tok2->str() != "::")
break;
} else {
if (tok2->str() != "void" || Token::Match(tok2, "void const| *|(")) // just "void" cannot be a variable type
++typeCount;
++singleNameCount;
}
} else if (!c && ((TemplateSimplifier::templateParameters(tok2) > 0) ||
Token::simpleMatch(tok2, "< >") /* Ticket #4764 */)) {
tok2 = tok2->findClosingBracket();
if (tok2->str() != ">")
break;
singleNameCount = 1;
} else if (Token::Match(tok2, "&|&&")) {
ref = !bracket;
} else if (singleNameCount == 1 && tok2->str() == "(" && Token::Match(tok2->link()->next(), "(|[")) {
bracket = true; // Skip: Seems to be valid pointer to array or function pointer
} else if (tok2->str() == "::") {
singleNameCount = 0;
} else if (tok2->str() != "*" && tok2->str() != "::") {
break;
}
tok2 = tok2->next();
}
if (tok2) {
*tok = tok2;
// In executable scopes, references must be assigned
// Catching by reference is an exception
if (executableScope && ref) {
if (Token::Match(tok2, "(|=|{"))
; // reference is assigned => ok
else if (tok2->str() != ")" || tok2->link()->strAt(-1) != "catch")
return false; // not catching by reference => not declaration
}
}
// Check if array declaration is valid (#2638)
// invalid declaration: AAA a[4] = 0;
if (typeCount >= 2 && executableScope && tok2 && tok2->str() == "[") {
const Token *tok3 = tok2;
while (tok3 && tok3->str() == "[") {
tok3 = tok3->link()->next();
}
if (Token::Match(tok3, "= %num%"))
return false;
}
return bool(typeCount >= 2 && tok2 && Token::Match(tok2->tokAt(-2), "!!:: %type%"));
}
static void setVarIdStructMembers(Token **tok1,
std::map<unsigned int, std::map<std::string, unsigned int> > *structMembers,
unsigned int *_varId)
{
Token *tok = *tok1;
while (Token::Match(tok->next(), ". %name% !!(")) {
const unsigned int struct_varid = tok->varId();
tok = tok->tokAt(2);
if (struct_varid == 0)
continue;
// Don't set varid for template function
if (TemplateSimplifier::templateParameters(tok->next()) > 0)
break;
std::map<std::string, unsigned int>& members = (*structMembers)[struct_varid];
const std::map<std::string, unsigned int>::iterator it = members.find(tok->str());
if (it == members.end()) {
members[tok->str()] = ++(*_varId);
tok->varId(*_varId);
} else {
tok->varId(it->second);
}
}
// tok can't be null
*tok1 = tok;
}
static void setVarIdClassDeclaration(Token * const startToken,
const std::map<std::string, unsigned int> &variableId,
const unsigned int scopeStartVarId,
std::map<unsigned int, std::map<std::string,unsigned int> > *structMembers,
unsigned int *_varId)
{
// end of scope
const Token * const endToken = startToken->link();
// determine class name
std::string className;
for (const Token *tok = startToken->previous(); tok; tok = tok->previous()) {
if (!tok->isName() && tok->str() != ":")
break;
if (Token::Match(tok, "class|struct %type% [:{]")) {
className = tok->next()->str();
break;
}
}
// replace varids..
unsigned int indentlevel = 0;
bool initList = false;
const Token *initListArgLastToken = nullptr;
for (Token *tok = startToken->next(); tok != endToken; tok = tok->next()) {
if (initList) {
if (tok == initListArgLastToken)
initListArgLastToken = nullptr;
else if (!initListArgLastToken &&
Token::Match(tok->previous(), "%name%|>|>> {|(") &&
Token::Match(tok->link(), "}|) ,|{"))
initListArgLastToken = tok->link();
}
if (tok->str() == "{") {
if (initList && !initListArgLastToken)
initList = false;
++indentlevel;
} else if (tok->str() == "}")
--indentlevel;
else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %name% [({]")) {
const std::map<std::string, unsigned int>::const_iterator it = variableId.find(tok->str());
if (it != variableId.end()) {
tok->varId(it->second);
}
} else if (tok->isName() && tok->varId() <= scopeStartVarId) {
if (indentlevel > 0) {
if (Token::Match(tok->previous(), "::|."))
continue;
if (tok->next()->str() == "::") {
if (tok->str() == className)
tok = tok->tokAt(2);
else
continue;
}
const std::map<std::string, unsigned int>::const_iterator it = variableId.find(tok->str());
if (it != variableId.end()) {
tok->varId(it->second);
setVarIdStructMembers(&tok, structMembers, _varId);
}
}
} else if (indentlevel == 0 && tok->str() == ":" && !initListArgLastToken)
initList = true;
}
}
// Update the variable ids..
// Parse each function..
static void setVarIdClassFunction(const std::string &classname,
Token * const startToken,
const Token * const endToken,
const std::map<std::string, unsigned int> &varlist,
std::map<unsigned int, std::map<std::string, unsigned int> > *structMembers,
unsigned int *_varId)
{
for (Token *tok2 = startToken; tok2 && tok2 != endToken; tok2 = tok2->next()) {
if (tok2->varId() != 0 || !tok2->isName())
continue;
if (Token::Match(tok2->tokAt(-2), ("!!" + classname + " ::").c_str()))
continue;
if (Token::Match(tok2->tokAt(-4), "%name% :: %name% ::")) // Currently unsupported
continue;
if (Token::Match(tok2->tokAt(-2), "!!this ."))
continue;
const std::map<std::string,unsigned int>::const_iterator it = varlist.find(tok2->str());
if (it != varlist.end()) {
tok2->varId(it->second);
setVarIdStructMembers(&tok2, structMembers, _varId);
}
}
}
void Tokenizer::setVarId()
{
// Clear all variable ids
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->isName())
tok->varId(0);
}
setPodTypes();
// Variable declarations can't start with "return" etc.
std::set<std::string> notstart;
notstart.insert("goto");
notstart.insert("NOT");
notstart.insert("return");
notstart.insert("sizeof");
notstart.insert("typedef");
if (!isC()) {
static const char *str[] = {"delete","friend","new","throw","using","virtual","explicit","const_cast","dynamic_cast","reinterpret_cast","static_cast"};
notstart.insert(str, str+(sizeof(str)/sizeof(*str)));
}
// variable id
_varId = 0;
std::map<std::string, unsigned int> variableId;
std::map<unsigned int, std::map<std::string, unsigned int> > structMembers;
std::stack< std::map<std::string, unsigned int> > scopeInfo;
std::stack<scopeStackEntryType> scopeStack;
scopeStack.push(scopeStackEntryType());
std::stack<const Token *> functionDeclEndStack;
bool initlist = false;
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (!functionDeclEndStack.empty() && tok == functionDeclEndStack.top()) {
functionDeclEndStack.pop();
if (tok->str() == ":")
initlist = true;
else if (tok->str() == ";") {
if (scopeInfo.empty())
cppcheckError(tok);
variableId.swap(scopeInfo.top());
scopeInfo.pop();
} else if (tok->str() == "{")
scopeStack.push(scopeStackEntryType(true, _varId));
} else if (!initlist && tok->str()=="(") {
const Token * newFunctionDeclEnd = nullptr;
if (!scopeStack.top().isExecutable)
newFunctionDeclEnd = isFunctionHead(tok, "{:;");
else {
Token const * tokenLinkNext = tok->link()->next();
if (tokenLinkNext->str() == "{") // might be for- or while-loop or if-statement
newFunctionDeclEnd = tokenLinkNext;
}
if (newFunctionDeclEnd &&
(functionDeclEndStack.empty() || newFunctionDeclEnd != functionDeclEndStack.top())) {
functionDeclEndStack.push(newFunctionDeclEnd);
scopeInfo.push(variableId);
}
} else if (tok->str() == "{") {
// parse anonymous unions as part of the current scope
if (!(initlist && Token::Match(tok->previous(), "%name%|>|>>") && Token::Match(tok->link(), "} ,|{"))) {
bool isExecutable;
if (tok->strAt(-1) == ")" || Token::Match(tok->tokAt(-2), ") %type%") ||
(initlist && tok->strAt(-1) == "}")) {
isExecutable = true;
} else {
isExecutable = ((scopeStack.top().isExecutable || initlist || tok->strAt(-1) == "else") &&
!isClassStructUnionEnumStart(tok));
scopeInfo.push(variableId);
}
initlist = false;
scopeStack.push(scopeStackEntryType(isExecutable, _varId));
}
} else if (tok->str() == "}") {
// parse anonymous unions as part of the current scope
if (!(Token::simpleMatch(tok, "} ;") && tok->link() && Token::simpleMatch(tok->link()->previous(), "union {")) &&
!(initlist && Token::Match(tok, "} ,|{") && Token::Match(tok->link()->previous(), "%name%|>|>> {"))) {
// Set variable ids in class declaration..
if (!initlist && !isC() && !scopeStack.top().isExecutable && tok->link()) {
setVarIdClassDeclaration(tok->link(),
variableId,
scopeStack.top().startVarid,
&structMembers,
&_varId);
}
if (scopeInfo.empty()) {
variableId.clear();
} else {
variableId.swap(scopeInfo.top());
scopeInfo.pop();
}
scopeStack.pop();
if (scopeStack.empty()) { // should be impossible
scopeStack.push(scopeStackEntryType());
}
}
}
if (tok == list.front() || Token::Match(tok, "[;{}]") ||
(Token::Match(tok, "[(,]") && (!scopeStack.top().isExecutable || Token::simpleMatch(tok->link(), ") {"))) ||
(tok->isName() && tok->str().at(tok->str().length()-1U) == ':')) {
// No variable declarations in sizeof
if (Token::simpleMatch(tok->previous(), "sizeof (")) {
continue;
}
if (_settings->terminated())
return;
// locate the variable name..
const Token *tok2 = (tok->isName()) ? tok : tok->next();
// private: protected: public: etc
while (tok2 && tok2->str()[tok2->str().size() - 1U] == ':') {
tok2 = tok2->next();
}
if (!tok2)
break;
// Variable declaration can't start with "return", etc
if (notstart.find(tok2->str()) != notstart.end())
continue;
if (!isC() && Token::simpleMatch(tok2, "const new"))
continue;
bool decl = setVarIdParseDeclaration(&tok2, variableId, scopeStack.top().isExecutable, isCPP(), isC());
if (decl) {
const Token* prev2 = tok2->previous();
if (Token::Match(prev2, "%type% [;[=,)]") && tok2->previous()->str() != "const")
;
else if (Token::Match(prev2, "%type% ( !!)") && Token::simpleMatch(tok2->link(), ") ;")) {
// In C++ , a variable can't be called operator+ or something like that.
if (isCPP() &&
prev2->str().size() >= 9 &&
prev2->str().compare(0, 8, "operator") == 0 &&
prev2->str()[8] != '_' &&
!std::isalnum(prev2->str()[8]))
continue;
const Token *tok3 = tok2->next();
if (!tok3->isStandardType() && tok3->str() != "void" && !Token::Match(tok3, "struct|union|class %type%") && tok3->str() != "." && !Token::Match(tok2->link()->previous(), "[&*]")) {
if (!scopeStack.top().isExecutable) {
// Detecting initializations with () in non-executable scope is hard and often impossible to be done safely. Thus, only treat code as a variable that definitly is one.
decl = false;
bool rhs = false;
for (; tok3; tok3 = tok3->nextArgumentBeforeCreateLinks2()) {
if (tok3->str() == "=") {
rhs = true;
continue;
}
if (tok3->str() == ",") {
rhs = false;
continue;
}
if (rhs)
continue;
if (tok3->isLiteral() || (tok3->isName() && (variableId.find(tok3->str()) != variableId.end())) || tok3->isOp() || notstart.find(tok3->str()) != notstart.end()) {
decl = true;
break;
}
}
}
} else
decl = false;
} else if (isCPP() && Token::Match(prev2, "%type% {") && Token::simpleMatch(tok2->link(), "} ;")) { // C++11 initialization style
if (Token::Match(prev2, "do|try|else") || Token::Match(prev2->tokAt(-2), "struct|class|:"))
continue;
} else
decl = false;
if (decl) {
variableId[prev2->str()] = ++_varId;
tok = tok2->previous();
}
}
}
if (tok->isName()) {
// don't set variable id after a struct|enum|union
if (Token::Match(tok->previous(), "struct|enum|union"))
continue;
if (!isC()) {
if (tok->previous() && tok->previous()->str() == "::")
continue;
if (tok->next() && tok->next()->str() == "::")
continue;
}
const std::map<std::string, unsigned int>::const_iterator it = variableId.find(tok->str());
if (it != variableId.end()) {
tok->varId(it->second);
setVarIdStructMembers(&tok, &structMembers, &_varId);
}
} else if (Token::Match(tok, "::|. %name%")) {
// Don't set varid after a :: or . token
tok = tok->next();
} else if (tok->str() == ":" && Token::Match(tok->tokAt(-2), "class %type%")) {
do {
tok = tok->next();
} while (tok && (tok->isName() || tok->str() == ","));
if (!tok)
break;
tok = tok->previous();
}
}
// Clear the structMembers because it will be used when member functions
// are parsed. The old info is not bad, it is just redundant.
structMembers.clear();
// Member functions and variables in this source
std::list<Token *> allMemberFunctions;
std::list<Token *> allMemberVars;
if (!isC()) {
for (Token *tok2 = list.front(); tok2; tok2 = tok2->next()) {
if (Token::Match(tok2, "%name% :: %name%")) {
if (tok2->strAt(3) == "(")
allMemberFunctions.push_back(tok2);
else if (tok2->strAt(3) != "::" && tok2->strAt(-1) != "::") // Support only one depth
allMemberVars.push_back(tok2);
}
}
}
// class members..
std::map<std::string, std::map<std::string, unsigned int> > varlist;
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "namespace|class|struct %name% {|:")) {
const std::string &classname(tok->next()->str());
bool namesp = tok->str() == "namespace";
const Token* tokStart = tok->tokAt(2);
while (tokStart && tokStart->str() != "{") {
if (Token::Match(tokStart, "public|private|protected"))
tokStart = tokStart->next();
if (tokStart->strAt(1) == "," || tokStart->strAt(1) == "{")
varlist[classname].insert(varlist[tokStart->str()].begin(), varlist[tokStart->str()].end());
tokStart = tokStart->next();
}
// What member variables are there in this class?
if (tokStart) {
for (Token *tok2 = tokStart->next(); tok2 && tok2 != tokStart->link(); tok2 = tok2->next()) {
// skip parentheses..
if (tok2->link()) {
if (tok2->str() == "{") {
if (tok2->strAt(-1) == ")" || tok2->strAt(-2) == ")")
setVarIdClassFunction(classname, tok2, tok2->link(), varlist[classname], &structMembers, &_varId);
tok2 = tok2->link();
} else if (tok2->str() == "(" && tok2->link()->strAt(1) != "(")
tok2 = tok2->link();
}
// Found a member variable..
else if (tok2->varId() > 0)
varlist[classname][tok2->str()] = tok2->varId();
}
}
// Are there any member variables in this class?
if (varlist[classname].empty())
continue;
// Member variables
for (std::list<Token *>::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[classname][tok2->str()]);
}
if (namesp || isC())
continue;
// Set variable ids in member functions for this class..
const std::string funcpattern(classname + " :: %name% (");
for (std::list<Token *>::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 parentheses..
tok2 = tok2->linkAt(3);
if (!tok2)
break;
// If this is a function implementation.. add it to funclist
Token * start = startOfFunction(tok2);
if (start) {
setVarIdClassFunction(classname, start, start->link(), varlist[classname], &structMembers, &_varId);
}
// constructor with initializer list
if (Token::Match(tok2, ") : %name% (")) {
Token *tok3 = tok2;
while (Token::Match(tok3, ") [:,] %name% (")) {
Token *vartok = tok3->tokAt(2);
if (varlist[classname].find(vartok->str()) != varlist[classname].end())
vartok->varId(varlist[classname][vartok->str()]);
tok3 = tok3->linkAt(3);
}
if (Token::simpleMatch(tok3, ") {")) {
setVarIdClassFunction(classname, tok2, tok3->next()->link(), varlist[classname], &structMembers, &_varId);
}
}
}
}
}
}
}
static void linkBrackets(Tokenizer* tokenizer, std::stack<const Token*>& type, std::stack<Token*>& links, Token* token, char open, char close)
{
if (token->str()[0] == open) {
links.push(token);
type.push(token);
} else if (token->str()[0] == close) {
if (links.empty()) {
// Error, { and } don't match.
tokenizer->syntaxError(token, open);
}
if (type.top()->str()[0] != open) {
tokenizer->syntaxError(type.top(), type.top()->str()[0]);
}
type.pop();
Token::createMutualLinks(links.top(), token);
links.pop();
}
}
void Tokenizer::createLinks()
{
std::stack<const Token*> type;
std::stack<Token*> links1;
std::stack<Token*> links2;
std::stack<Token*> links3;
for (Token *token = list.front(); token; token = token->next()) {
if (token->link()) {
token->link(0);
}
linkBrackets(this, type, links1, token, '{', '}');
linkBrackets(this, type, links2, token, '(', ')');
linkBrackets(this, type, links3, token, '[', ']');
}
if (!links1.empty()) {
// Error, { and } don't match.
syntaxError(links1.top(), '{');
}
if (!links2.empty()) {
// Error, ( and ) don't match.
syntaxError(links2.top(), '(');
}
if (!links3.empty()) {
// Error, [ and ] don't match.
syntaxError(links3.top(), '[');
}
}
void Tokenizer::createLinks2()
{
if (isC())
return;
std::stack<Token*> type;
for (Token *token = list.front(); token; token = token->next()) {
if (token->link()) {
if (Token::Match(token, "{|[|("))
type.push(token);
else if (!type.empty() && Token::Match(token, "}|]|)")) {
while (type.top()->str() == "<")
type.pop();
type.pop();
} else
token->link(0);
}
else if (Token::Match(token, "%oror%|&&|;"))
while (!type.empty() && type.top()->str() == "<")
type.pop();
else if (token->str() == "<" && token->previous() && token->previous()->isName() && !token->previous()->varId())
type.push(token);
else if (token->str() == ">") {
if (type.empty() || type.top()->str() != "<") // < and > don't match.
continue;
if (token->next() && !Token::Match(token->next(), "%name%|>|&|*|::|,|(|)|{|;|["))
continue;
// if > is followed by [ .. "new a<b>[" is expected
if (token->strAt(1) == "[") {
Token *prev = type.top()->previous();
while (prev && Token::Match(prev->previous(), ":: %name%"))
prev = prev->tokAt(-2);
if (prev && prev->str() != "new")
prev = prev->previous();
if (!prev || prev->str() != "new")
continue;
}
Token* top = type.top();
type.pop();
Token::createMutualLinks(top, token);
}
}
}
void Tokenizer::sizeofAddParentheses()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {
Token* next = tok->next();
if (Token::Match(tok, "sizeof !!(") && next && (next->isLiteral() || next->isName() || Token::Match(next, "[*~!]"))) {
Token *endToken = next;
while (Token::Match(endToken->next(), "%name%|%num%|%str%|[|(|.|::|++|--|!|~") || (Token::Match(endToken, "%type% * %op%|?|:|const|;|,"))) {
if (endToken->strAt(1) == "[" || endToken->strAt(1) == "(")
endToken = endToken->linkAt(1);
else
endToken = endToken->next();
}
// Add ( after sizeof and ) behind endToken
tok->insertToken("(");
endToken->insertToken(")");
Token::createMutualLinks(tok->next(), endToken->next());
}
}
}
bool Tokenizer::simplifySizeof()
{
// Locate variable declarations and calculate the size
std::map<unsigned int, unsigned int> sizeOfVar;
std::map<unsigned int, Token *> declTokOfVar;
for (Token *tok = list.front(); 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% * %name% [;,)]") ||
Token::Match(tok->tokAt(-4), "[;{}(,] const %type% * %name% [;),]") ||
Token::Match(tok->tokAt(-2), "[;{}(,] %type% %name% [;),]") ||
Token::Match(tok->tokAt(-3), "[;{}(,] const %type% %name% [;),]")) {
const unsigned int size = sizeOfType(tok->previous());
if (size == 0) {
continue;
}
sizeOfVar[varId] = size;
declTokOfVar[varId] = tok;
}
else if (Token::Match(tok->previous(), "%type% %name% [ %num% ] [[;=]") ||
Token::Match(tok->tokAt(-2), "%type% * %name% [ %num% ] [[;=]")) {
unsigned int size = sizeOfType(tok->previous());
if (size == 0)
continue;
Token* tok2 = tok->next();
while (Token::Match(tok2, "[ %num% ]")) {
size *= static_cast<unsigned int>(MathLib::toLongNumber(tok2->strAt(1)));
tok2 = tok2->tokAt(3);
}
if (Token::Match(tok2, "[;=]")) {
sizeOfVar[varId] = size;
declTokOfVar[varId] = tok;
}
tok = tok2;
}
else if (Token::Match(tok->previous(), "%type% %name% [ %num% ] [,)]") ||
Token::Match(tok->tokAt(-2), "%type% * %name% [ %num% ] [,)]")) {
Token tempTok(0);
tempTok.str("*");
sizeOfVar[varId] = sizeOfType(&tempTok);
declTokOfVar[varId] = tok;
}
}
}
bool ret = false;
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->str() != "sizeof")
continue;
if (!tok->next())
break;
if (tok->strAt(1) == "sizeof")
continue;
if (Token::simpleMatch(tok->next(), ". . .")) {
tok->deleteNext(3);
}
// sizeof('x')
if (Token::Match(tok, "sizeof ( %char% )")) {
tok->deleteNext();
tok->deleteThis();
tok->deleteNext();
std::ostringstream sz;
sz << sizeof 'x';
tok->str(sz.str());
ret = true;
continue;
}
// sizeof ("text")
if (Token::Match(tok->next(), "( %str% )")) {
tok->deleteNext();
tok->deleteThis();
tok->deleteNext();
std::ostringstream ostr;
ostr << (Token::getStrLength(tok) + 1);
tok->str(ostr.str());
ret = true;
continue;
}
// 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))));
tok->deleteNext(3);
ret = true;
}
// sizeof( a )
else if (Token::Match(tok->next(), "( %var% )")) {
if (sizeOfVar.find(tok->tokAt(2)->varId()) != sizeOfVar.end()) {
tok->deleteNext();
tok->deleteThis();
tok->deleteNext();
tok->str(MathLib::toString(sizeOfVar[tok->varId()]));
ret = true;
} else {
// don't try to replace size of variable if variable has
// similar name with type (#329)
}
}
else if (Token::Match(tok, "sizeof ( %type% )")) {
const unsigned int size = sizeOfType(tok->tokAt(2));
if (size > 0) {
tok->str(MathLib::toString(size));
tok->deleteNext(3);
ret = true;
}
}
else if (Token::Match(tok, "sizeof ( * %name% )") || Token::Match(tok, "sizeof ( %name% [ %num% ] )")) {
// Some default value..
std::size_t sz = 0;
const unsigned int varid = tok->tokAt((tok->strAt(2) == "*") ? 3 : 2)->varId();
if ((varid != 0) && (declTokOfVar.find(varid) != declTokOfVar.end())) {
// Try to locate variable declaration..
const Token *decltok = declTokOfVar[varid];
if (Token::Match(decltok->previous(), "%type%|* %name% [")) {
sz = sizeOfType(decltok->previous());
} else if (Token::Match(decltok->tokAt(-2), "%type% * %name%")) {
sz = sizeOfType(decltok->tokAt(-2));
}
// Multi-dimensional array..
if (Token::Match(decltok,"%name% [") && Token::simpleMatch(decltok->linkAt(1), "] [")) {
const Token *tok2 = decltok->linkAt(1);
while (Token::Match(tok2, "] [ %num% ]")) {
sz = sz * MathLib::toLongNumber(tok2->strAt(2));
tok2 = tok2->linkAt(3);
}
if (Token::simpleMatch(tok2, "] ["))
sz = 0;
}
} else if (tok->strAt(3) == "[" && tok->tokAt(2)->isStandardType()) {
sz = sizeOfType(tok->tokAt(2));
if (sz == 0)
continue;
sz *= static_cast<unsigned long>(MathLib::toLongNumber(tok->strAt(4)));
}
if (sz > 0) {
tok->str(MathLib::toString(sz));
Token::eraseTokens(tok, tok->next()->link()->next());
ret = true;
}
}
}
return ret;
}
bool Tokenizer::simplifyTokenList1(const char FileName[])
{
if (_settings->terminated())
return false;
// if MACRO
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "if|for|while|BOOST_FOREACH %name% (")) {
if (Token::simpleMatch(tok, "for each")) {
// 'for each ( )' -> 'asm ( )'
tok->str("asm");
tok->deleteNext();
} else {
syntaxError(tok);
return false;
}
}
}
// remove MACRO in variable declaration: MACRO int x;
removeMacroInVarDecl();
// Combine strings
combineStrings();
// replace inline SQL with "asm()" (Oracle PRO*C). Ticket: #1959
simplifySQL();
// replace __LINE__ macro with line number
simplifyFileAndLineMacro();
// Concatenate double sharp: 'a ## b' -> 'ab'
concatenateDoubleSharp();
createLinks();
// if (x) MACRO() ..
for (const Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "if (")) {
tok = tok->next()->link();
if (Token::Match(tok, ") %name% (") &&
tok->next()->isUpperCaseName() &&
Token::Match(tok->linkAt(2), ") {|else")) {
syntaxError(tok->next());
return false;
}
}
}
if (_settings->terminated())
return false;
// Simplify the C alternative tokens (and, or, etc.)
simplifyCAlternativeTokens();
// replace 'NULL' and similar '0'-defined macros with '0'
simplifyNull();
// replace 'sin(0)' to '0' and other similar math expressions
simplifyMathExpressions();
// combine "- %num%"
concatenateNegativeNumberAndAnyPositive();
// simplify simple calculations
for (Token *tok = list.front() ? list.front()->next() : nullptr; tok; tok = tok->next()) {
if (tok->isNumber())
TemplateSimplifier::simplifyNumericCalculations(tok->previous());
}
// remove extern "C" and extern "C" {}
if (isCPP())
simplifyExternC();
// simplify weird but legal code: "[;{}] ( { code; } ) ;"->"[;{}] code;"
simplifyRoundCurlyParentheses();
// check for simple syntax errors..
for (const Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "> struct {") &&
Token::simpleMatch(tok->linkAt(2), "} ;")) {
syntaxError(tok);
list.deallocateTokens();
return false;
}
}
if (!simplifyAddBraces())
return false;
// Combine tokens..
combineOperators();
sizeofAddParentheses();
// Simplify: 0[foo] -> *(foo)
for (Token* tok = list.front(); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "0 [") && tok->linkAt(1)) {
tok->str("*");
tok->next()->str("(");
tok->linkAt(1)->str(")");
}
}
if (_settings->terminated())
return false;
// Remove "volatile", "inline", "register", and "restrict"
simplifyKeyword();
// Convert K&R function declarations to modern C
simplifyVarDecl(true);
simplifyFunctionParameters();
// specify array size..
arraySize();
// simplify labels and 'case|default'-like syntaxes
simplifyLabelsCaseDefault();
// simplify '[;{}] * & ( %any% ) =' to '%any% ='
simplifyMulAndParens();
// ";a+=b;" => ";a=a+b;"
simplifyCompoundAssignment();
if (!isC() && !_settings->library.markupFile(FileName)) {
findComplicatedSyntaxErrorsInTemplates();
}
if (_settings->terminated())
return false;
// remove calling conventions __cdecl, __stdcall..
simplifyCallingConvention();
// Remove __declspec()
simplifyDeclspec();
// remove some unhandled macros in global scope
removeMacrosInGlobalScope();
// remove undefined macro in class definition:
// class DLLEXPORT Fred { };
// class Fred FINAL : Base { };
removeMacroInClassDef();
// remove __attribute__((?))
simplifyAttribute();
// remove unnecessary member qualification..
removeUnnecessaryQualification();
// remove Microsoft MFC..
simplifyMicrosoftMFC();
// convert Microsoft memory functions
simplifyMicrosoftMemoryFunctions();
// convert Microsoft string functions
simplifyMicrosoftStringFunctions();
if (_settings->terminated())
return false;
// Remove Qt signals and slots
simplifyQtSignalsSlots();
// remove Borland stuff..
simplifyBorland();
// Remove __builtin_expect, likely and unlikely
simplifyBuiltinExpect();
if (hasEnumsWithTypedef()) {
// #2449: syntax error: enum with typedef in it
list.deallocateTokens();
return false;
}
simplifyDebugNew();
// Remove __asm..
simplifyAsm();
// Change initialisation of variable to assignment
simplifyInitVar();
// Split up variable declarations.
simplifyVarDecl(false);
// typedef..
if (m_timerResults) {
Timer t("Tokenizer::tokenize::simplifyTypedef", _settings->_showtime, m_timerResults);
simplifyTypedef();
} else {
simplifyTypedef();
}
for (Token* tok = list.front(); tok;) {
if (Token::Match(tok, "union|struct|class union|struct|class"))
tok->deleteNext();
else
tok = tok->next();
}
// class x y {
if (_settings->isEnabled("information")) {
for (const Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "class %type% %type% [:{]")) {
unhandled_macro_class_x_y(tok);
}
}
}
// catch bad typedef canonicalization
//
// to reproduce bad typedef, download upx-ucl from:
// http://packages.debian.org/sid/upx-ucl
// analyse the file src/stub/src/i386-linux.elf.interp-main.c
validate();
// enum..
simplifyEnum();
// The simplify enum have inner loops
if (_settings->terminated())
return false;
// Put ^{} statements in asm()
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "^ {")) {
Token * start = tok;
while (start && !Token::Match(start, "[;{}]"))
start = start->previous();
if (start)
start = start->next();
const Token *last = tok->next()->link();
if (start != tok) {
last = last->next();
while (last && !Token::Match(last->next(), "[;{}()]"))
last = last->next();
}
if (start && last) {
std::string asmcode(start->str());
while (start->next() != last) {
asmcode += start->next()->str();
start->deleteNext();
}
asmcode += last->str();
start->deleteNext();
start->insertToken(";");
start->insertToken(")");
start->insertToken("\"" + asmcode + "\"");
start->insertToken("(");
start->str("asm");
start->link(nullptr);
start->next()->link(start->tokAt(3));
start->tokAt(3)->link(start->next());
tok = start->tokAt(4);
}
}
}
// When the assembly code has been cleaned up, no @ is allowed
for (const Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->str() == "(")
tok = tok->link();
else if (tok->str()[0] == '@') {
list.deallocateTokens();
return false;
}
}
// convert platform dependent types to standard types
// 32 bits: size_t -> unsigned long
// 64 bits: size_t -> unsigned long long
simplifyPlatformTypes();
// collapse compound standard types into a single token
// unsigned long long int => long _isUnsigned=true,_isLong=true
simplifyStdType();
if (_settings->terminated())
return false;
// simplify bit fields..
simplifyBitfields();
if (_settings->terminated())
return false;
simplifyConst();
// struct simplification "struct S {} s; => struct S { } ; S s ;
simplifyStructDecl();
if (_settings->terminated())
return false;
// specify array size.. needed when arrays are split
arraySize();
// f(x=g()) => x=g(); f(x)
simplifyAssignmentInFunctionCall();
// x = ({ 123; }); => { x = 123; }
simplifyAssignmentBlock();
if (_settings->terminated())
return false;
simplifyVariableMultipleAssign();
// Simplify float casts (float)1 => 1.0
simplifyFloatCasts();
// Collapse operator name tokens into single token
// operator = => operator=
simplifyOperatorName();
// Remove redundant parentheses
simplifyRedundantParentheses();
for (Token *tok = list.front(); tok; tok = tok->next())
while (TemplateSimplifier::simplifyNumericCalculations(tok))
;
// Handle templates..
simplifyTemplates();
// The simplifyTemplates have inner loops
if (_settings->terminated())
return false;
// Simplify templates.. sometimes the "simplifyTemplates" fail and
// then unsimplified function calls etc remain. These have the
// "wrong" syntax. So this function will just fix so that the
// syntax is corrected.
if (!isC())
TemplateSimplifier::cleanupAfterSimplify(list.front());
// Simplify pointer to standard types (C only)
simplifyPointerToStandardType();
// simplify function pointers
simplifyFunctionPointers();
// Change initialisation of variable to assignment
simplifyInitVar();
// Split up variable declarations.
simplifyVarDecl(false);
if (m_timerResults) {
Timer t("Tokenizer::tokenize::setVarId", _settings->_showtime, m_timerResults);
setVarId();
} else {
setVarId();
}
// Link < with >
createLinks2();
// The simplify enum might have inner loops
if (_settings->terminated())
return false;
// Add std:: in front of std classes, when using namespace std; was given
simplifyNamespaceStd();
// Change initialisation of variable to assignment
simplifyInitVar();
// Convert e.g. atol("0") into 0
simplifyMathFunctions();
simplifyDoublePlusAndDoubleMinus();
simplifyArrayAccessSyntax();
Token::assignProgressValues(list.front());
removeRedundantSemicolons();
simplifyParameterVoid();
simplifyRedundantConsecutiveBraces();
simplifyEmptyNamespaces();
elseif();
// Simplify nameless rValue references - named ones are simplified later
for (Token* tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "&& [,)]")) {
tok->str("&");
tok->insertToken("&");
}
}
validate();
return true;
}
bool Tokenizer::simplifyTokenList2()
{
// clear the _functionList so it can't contain dead pointers
deleteSymbolDatabase();
// Experimental AST handling.
for (Token *tok = list.front(); tok; tok = tok->next())
tok->clearAst();
simplifyCharAt();
// simplify references
simplifyReference();
simplifyStd();
if (_settings->terminated())
return false;
simplifySizeof();
simplifyUndefinedSizeArray();
simplifyCasts();
// Simplify simple calculations before replace constants, this allows the replacement of constants that are calculated
// e.g. const static int value = sizeof(X)/sizeof(Y);
simplifyCalculations();
// Replace constants..
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "const static| %type% %name% = %num% ;") ||
Token::Match(tok, "const static| %type% %name% ( %num% ) ;")) {
int offset = 0;
if (tok->strAt(1) == "static")
offset = 1;
const unsigned int varId(tok->tokAt(2 + offset)->varId());
if (varId == 0) {
tok = tok->tokAt(5 + offset);
continue;
}
const std::string& num = tok->strAt(4 + offset);
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);
}
}
}
}
if (_settings->terminated())
return false;
// Simplify simple calculations..
simplifyCalculations();
// Replace "*(ptr + num)" => "ptr[num]"
simplifyOffsetPointerDereference();
// Replace "&str[num]" => "(str + num)"
std::set<unsigned int> pod;
for (const Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->isStandardType()) {
tok = tok->next();
while (tok && (tok->str() == "*" || tok->isName())) {
if (tok->varId() > 0) {
pod.insert(tok->varId());
break;
}
tok = tok->next();
}
if (!tok)
break;
}
}
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (!Token::Match(tok, "%num%|%name%|]|)") &&
(Token::Match(tok->next(), "& %name% [ %num%|%name% ] !!["))) {
tok = tok->next();
if (tok->next()->varId()) {
if (pod.find(tok->next()->varId()) == pod.end()) {
tok = tok->tokAt(5);
continue;
}
}
// '&' => '('
tok->str("(");