Permalink
Fetching contributors…
Cannot retrieve contributors at this time
9768 lines (8551 sloc) 361 KB
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2016 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 "utils.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 VarIdscopeInfo {
VarIdscopeInfo()
:isExecutable(false), isStructInit(false), startVarid(0) {
}
VarIdscopeInfo(bool _isExecutable, bool _isStructInit, unsigned int _startVarid)
:isExecutable(_isExecutable), isStructInit(_isStructInit), startVarid(_startVarid) {
}
const bool isExecutable;
const bool isStructInit;
const unsigned int startVarid;
};
}
const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &endsWith) const
{
return Tokenizer::isFunctionHead(tok, endsWith, isCPP());
}
const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &endsWith, bool cpp)
{
if (!tok)
return nullptr;
if (tok->str() == "(")
tok = tok->link();
if (Token::Match(tok, ") [;{]")) {
tok = tok->next();
if (tok->isName())
tok = tok->next();
return (endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
}
if (cpp && tok->str() == ")") {
tok = tok->next();
while (Token::Match(tok, "const|noexcept|override|volatile|&|&& !!(") ||
(Token::Match(tok, "%name% !!(") && tok->isUpperCaseName()))
tok = tok->next();
if (Token::Match(tok, "throw|noexcept ("))
tok = tok->linkAt(1)->next();
if (Token::Match(tok, "%name% (") && tok->isUpperCaseName())
tok = tok->linkAt(1)->next();
if (tok && tok->str() == ".") { // trailing return type
for (tok = tok->next(); tok && !Token::Match(tok, "[;{]"); tok = tok->next())
if (tok->link() && Token::Match(tok, "<|[|("))
tok = tok->link();
}
if (Token::Match(tok, "= 0|default|delete ;"))
tok = tok->tokAt(2);
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->tokType() == Token::eString)
return Token::getStrLength(type) + 1U;
std::map<std::string, unsigned int>::const_iterator it = _typeSize.find(type->str());
if (it == _typeSize.end()) {
const Library::PodType* podtype = _settings->library.podtype(type->str());
if (!podtype)
return 0;
return podtype->size;
} 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->tokType(tok->tokType());
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;
}
//---------------------------------------------------------------------------
// check if this statement is a duplicate definition
bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name, const Token *typeDef) 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() == "[") {
if (!end->link())
syntaxError(end); // #6680 invalid code
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;
*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|struct")) {
// 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) {
*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") {
return true;
} else if (tok->previous()->str() == "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() == "{") {
return true;
} else if (Token::Match(tok->next(), ")|*")) {
return true;
} else if (tok->next()->str() == name->str()) {
return true;
} else if (tok->next()->str() != ";") {
return true;
} else {
return false;
}
} else if (tok->previous()->str() == "union") {
if (tok->next()->str() != ";") {
return true;
} else {
return false;
}
} else if (isCPP() && tok->previous()->str() == "class") {
if (tok->next()->str() != ";") {
return true;
} else {
return false;
}
}
if (tok)
tok = tok->previous();
}
if ((*tokPtr)->strAt(1) != "(" || !Token::Match((*tokPtr)->linkAt(1), ") .|(|["))
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 */
Token *Tokenizer::processFunc(Token *tok2, bool inOperator) const
{
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() &&
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())
syntaxError(tok2);
if (tok2->next()->str() == "(")
tok2 = tok2->next()->link();
}
}
}
}
return tok2;
}
void Tokenizer::simplifyTypedef()
{
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;
if (isMaxTime())
return;
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()->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);
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|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);
// 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);
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);
}
// 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() == "(" && (
(tokOffset->link() && Token::Match(tokOffset->link()->previous(), "%type% ) (") &&
Token::Match(tokOffset->link()->next()->link(), ") const|volatile|;")) ||
(Token::simpleMatch(tokOffset, "( (") &&
tokOffset->next() && Token::Match(tokOffset->next()->link()->previous(), "%type% ) (") &&
Token::Match(tokOffset->next()->link()->next()->link(), ") const|volatile| ) ;|,")) ||
(Token::simpleMatch(tokOffset, "( * (") &&
tokOffset->linkAt(2) && 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();
if (!argEnd)
syntaxError(argStart);
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)
syntaxError(specEnd);
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();
if (!argEnd)
syntaxError(arrayStart);
argFuncRetStart = argEnd->tokAt(2);
argFuncRetEnd = argFuncRetStart->link();
if (!argFuncRetEnd)
syntaxError(argFuncRetStart);
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);
if (!argFuncRetStart)
syntaxError(tokOffset);
argFuncRetEnd = argFuncRetStart->link();
if (!argFuncRetEnd)
syntaxError(tokOffset);
tok = argFuncRetEnd->next();
} else if (Token::Match(tokOffset, "( * ( %type% ) (")) {
functionRetFuncPtr = true;
tokOffset = tokOffset->tokAt(5);
typeName = tokOffset->tokAt(-2);
argStart = tokOffset;
argEnd = tokOffset->link();
if (!argEnd)
syntaxError(arrayStart);
argFuncRetStart = argEnd->tokAt(2);
if (!argFuncRetStart)
syntaxError(tokOffset);
argFuncRetEnd = argFuncRetStart->link();
if (!argFuncRetEnd)
syntaxError(tokOffset);
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();
if (!arrayEnd)
syntaxError(arrayStart);
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();
unsigned 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;
if (tok2->link()) { // Pre-check for performance
// 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 {
if (scope == 0)
break;
--scope;
}
}
// check for member functions
else if (isCPP() && Token::Match(tok2, ") const| {")) {
const Token *func = tok2->link()->previous();
if (!func || !func->previous()) // Ticket #4239
continue;
/** @todo add support for multi-token operators */
if (func->previous()->str() == "operator")
func = func->previous();
if (!func->previous()) // #7020
syntaxError(func);
// 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 scope
else if (tok2->str() == "{") {
// check for entering a new namespace
if (isCPP() && tok2->strAt(-2) == "namespace") {
if (classLevel < spaceInfo.size() &&
spaceInfo[classLevel].isNamespace &&
spaceInfo[classLevel].className == tok2->previous()->str()) {
++classLevel;
pattern.clear();
for (std::size_t i = classLevel; i < spaceInfo.size(); ++i)
pattern += (spaceInfo[i].className + " :: ");
pattern += typeName->str();
}
++scope;
}
// keep track of scopes within member function
if (inMemberFunc)
++memberScope;
++scope;
}
}
// check for operator typedef
/** @todo add support for multi-token operators */
else if (isCPP() &&
tok2->str() == "operator" &&
tok2->next() &&
tok2->next()->str() == typeName->str() &&
tok2->linkAt(2) &&
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 typedef that can be substituted
else if (Token::simpleMatch(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;
std::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) == "::") {
std::size_t relativeSpaceInfoSize = spaceInfo.size();
Token * tokBeforeType = tok2->previous();
while (relativeSpaceInfoSize != 0 &&
tokBeforeType && tokBeforeType->str() == "::" &&
tokBeforeType->strAt(-1) == spaceInfo[relativeSpaceInfoSize-1].className) {
tokBeforeType = tokBeforeType->tokAt(-2);
--relativeSpaceInfoSize;
}
if (tokBeforeType && tokBeforeType->str() != "::") {
Token::eraseTokens(tokBeforeType, tok2);
simplifyType = true;
}
} else if (Token::Match(tok2->previous(), "case|;|{|} %type% :")) {
tok2 = tok2->next();
} else if (duplicateTypedef(&tok2, typeName, typeDef)) {
// 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 (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() && 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;
const bool sameStartEnd = (typeStart == typeEnd);
// check for derived class: class A : some_typedef {
const 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;
if (typeStart->str() == "typename" && tok2->strAt(-1)=="typename") {
// Remove one typename if it is already contained in the goal
typeStart = typeStart->next();
}
// 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();
}
if (typeStart->str() == "struct" && Token::Match(tok2, "%name% ::"))
typeStart = typeStart->next();
if (sameStartEnd)
typeEnd = typeStart;
// 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) {
if (!tok2)
syntaxError(nullptr);
tok2->insertToken(")");
tok2 = tok2->next();
Token::createMutualLinks(tok2, tok3);
}
if (!tok2)
syntaxError(nullptr);
tok2 = copyTokens(tok2, argStart, argEnd);
if (inTemplate) {
if (!tok2)
syntaxError(nullptr);
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 = nullptr;
if (functionPtrRetFuncPtr) {
tok2->insertToken("(");
tok2 = tok2->next();
tok4 = tok2;
tok2->insertToken("*");
tok2 = tok2->next();
}
// skip over variable name if there
if (!inCast) {
if (!tok2 || !tok2->next())
syntaxError(nullptr);
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() && tok2->next()->str() != ")") {
if (tok2->next()->str() != "(")
tok2 = tok2->next();
// check for function and skip over args
if (tok2 && tok2->next() && tok2->next()->str() == "(")
tok2 = tok2->next()->link();
// check for array
if (tok2 && tok2->next() && 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 {
// This is the case of casting operator.
// Name is not available, and () should not be
// inserted
const bool castOperator = inOperator && Token::Match(tok2, "%type% (");
Token *tok3;
if (!castOperator) {
tok2->insertToken("(");
tok2 = tok2->next();
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();
if (!castOperator) {
// 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->strAt(2) == "[") {
do {
if (!tok2->linkAt(2))
syntaxError(tok2); // #6807
tok2 = tok2->linkAt(2)->previous();
} while (tok2->strAt(2) == "[");
}
if (arrayStart && arrayEnd) {
do {
if (!tok2->next())
syntaxError(tok2); // 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);
if (!tok2)
syntaxError(nullptr);
tok2->insertToken(")");
tok2 = tok2->next();
Token::createMutualLinks(tok2, tok3);
}
if (!tok2->next())
syntaxError(tok2); // can't recover so quit
tok2 = copyTokens(tok2, arrayStart, arrayEnd);
if (!tok2->next())
syntaxError(tok2);
tok2 = tok2->next();
if (tok2->str() == "=") {
if (!tok2->next())
syntaxError(tok2);
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 (!tok2)
break;
}
if (!tok)
syntaxError(nullptr);
if (tok->str() == ";")
done = true;
else if (tok->str() == ",") {
arrayStart = nullptr;
arrayEnd = nullptr;
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::createTokens(std::istream &code,
const std::string& FileName)
{
// make sure settings specified
assert(_settings);
return list.createTokens(code, Path::getRelativePath(Path::simplifyPath(FileName), _settings->basePaths));
}
bool Tokenizer::simplifyTokens1(const std::string &configuration)
{
// Fill the map _typeSize..
fillTypeSizes();
_configuration = configuration;
if (!simplifyTokenList1(list.getFiles().front().c_str()))
return false;
list.createAst();
list.validateAst();
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()) {
Token* endTok = const_cast<Token*>(var->typeEndToken());
endTok->str("&");
endTok->astOperand1(nullptr);
endTok->astOperand2(nullptr);
endTok->insertToken("&");
endTok->next()->scope(endTok->scope());
}
}
SymbolDatabase::setValueTypeInTokenList(list.front(), isCPP(), _settings);
ValueFlow::setValues(&list, _symbolDatabase, _errorLogger, _settings);
printDebugOutput(1);
return true;
}
bool Tokenizer::tokenize(std::istream &code,
const char FileName[],
const std::string &configuration)
{
if (!createTokens(code, FileName))
return false;
return simplifyTokens1(configuration);
}
//---------------------------------------------------------------------------
void Tokenizer::findComplicatedSyntaxErrorsInTemplates()
{
validate();
TemplateSimplifier::checkComplicatedSyntaxErrorsInTemplates(list.front());
}
void Tokenizer::checkForEnumsWithTypedef()
{
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();
}
}
}
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()
{
const bool cpp = isCPP();
// 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;
}
// simplify "->"
else if (c1 == '-' && c2 == '>') {
// If the preceding sequence is "( & %name% )", replace it by "%name%"
Token *t = tok->tokAt(-4);
if (t && Token::Match(t, "( & %name% )")) {
t->deleteThis();
t->deleteThis();
t->deleteNext();
tok = t->next();
}
// Replace "->" with "."
tok->str(".");
tok->originalName("->");
tok->deleteNext();
continue;
}
} else if (tok->next()->str() == "=") {
if (tok->str() == ">>") {
tok->str(">>=");
tok->deleteNext();
} else if (tok->str() == "<<") {
tok->str("<<=");
tok->deleteNext();
}
} else if (cpp && (c1 == 'p' || c1 == '_') &&
Token::Match(tok, "private|protected|public|__published : !!:")) {
bool simplify = false;
unsigned int par = 0U;
for (const Token *prev = tok->tokAt(-1); prev; prev = prev->previous()) {
if (prev->str() == ")") {
++par;
} else if (prev->str() == "(") {
if (par == 0U)
break;
--par;
}
if (par != 0U || prev->str() == "(")
continue;
if (Token::Match(prev, "[;{}]")) {
simplify = true;
break;
}
if (prev->isName() && prev->isUpperCaseName())
continue;
if (prev->isName() && prev->str()[prev->str().size() - 1U] == ':')
simplify = true;
break;
}
if (simplify) {
tok->str(tok->str() + ":");
tok->deleteNext();
}
}
}
}
void Tokenizer::combineStrings()
{
// Combine wide strings
for (Token *tok = list.front();
tok;
tok = tok->next()) {
while (tok->str() == "L" && tok->next() && tok->next()->tokType() == 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()->tokType() == Token::eString) {
// Two strings after each other, combine them
tok->concatStr(simplifyString(tok->next()->str()));
tok->deleteNext();
}
}
}
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");
}
}
// 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->tokType() == Token::eIncDecOp)
continue;
while (tok->next() && tok->next()->str() == "+")
tok->deleteNext();
if (Token::Match(tok->next(), "- %num%")) {
tok->deleteNext();
tok->next()->str("-" + tok->next()->str());
}
}
}
void Tokenizer::simplifyExternC()
{
if (isC())
return;
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::simpleMatch(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::simplifyArrayAccessSyntax()
{
// 0[a] -> a[0]
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->isNumber() && Token::Match(tok, "%num% [ %name% ]")) {
const std::string number(tok->str());
Token* indexTok = tok->tokAt(2);
tok->str(indexTok->str());
tok->varId(indexTok->varId());
indexTok->str(number);
}
}
}
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()[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()[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()) {
if (!tok->isName() || !Token::Match(tok, "%var% [ ] ="))
continue;
bool addlength = false;
if (Token::Match(tok, "%var% [ ] = { %str% } ;")) {
Token *t = tok->tokAt(3);
t->deleteNext();
t->next()->deleteNext();
addlength = true;
}
if (addlength || Token::Match(tok, "%var% [ ] = %str% ;")) {
tok = tok->next();
std::size_t sz = Token::getStrSize(tok->tokAt(3));
tok->insertToken(MathLib::toString(sz));
tok = tok->tokAt(5);
}
else if (Token::Match(tok, "%var% [ ] = {")) {
MathLib::biguint 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, MathLib::toULongNumber(tok2->strAt(1)) + 1U);
else {
sz = 0;
break;
}
}
tok2 = tok2->link();
} 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)
{
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 (tok->link() && Token::Match(tok, "[(<]"))
tok = tok->link();
else if (Token::Match(tok->next(), "[{};)]"))
break;
}
if (colonlevel) // Ticket #5214: Make sure the ':' matches the proper '?'
return 0;
return tok;
}
const Token * Tokenizer::startOfExecutableScope(const Token * tok)
{
if (tok->str() != ")")
return nullptr;
tok = isFunctionHead(tok, ":{", true);
if (Token::Match(tok, ": %name% [({]")) {
while (Token::Match(tok, "[:,] %name% [({]"))
tok = tok->linkAt(2)->next();
}
return (tok && tok->str() == "{") ? tok : 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 = const_cast<Token *>(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())
syntaxError(tok); // #7270 invalid code
if (tok->next()->str() != ";" && tok->next()->str() != "case")
tok->insertToken(";");
else
tok = tok->previous();
} else {
syntaxError(tok);
}
} else if (Token::Match(tok, "[;{}] %name% : !!;")) {
tok = tok->tokAt(2);
tok->insertToken(";");
}
}
}
void Tokenizer::simplifyCaseRange()
{
for (Token* tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "case %num% . . . %num% :")) {
MathLib::bigint start = MathLib::toLongNumber(tok->strAt(1));
MathLib::bigint end = MathLib::toLongNumber(tok->strAt(5));
end = std::min(start + 50, end); // Simplify it 50 times at maximum
if (start < end) {
tok = tok->tokAt(2);
tok->str(":");
tok->deleteNext();
tok->next()->str("case");
for (MathLib::bigint i = end-1; i > start; i--) {
tok->insertToken(":");
tok->insertToken(MathLib::toString(i));
tok->insertToken("case");
}
}
} else if (Token::Match(tok, "case %char% . . . %char% :")) {
char start = tok->strAt(1)[1];
char end = tok->strAt(5)[1];
if (start < end) {
tok = tok->tokAt(2);
tok->str(":");
tok->deleteNext();
tok->next()->str("case");
for (char i = end - 1; i > start; i--) {
tok->insertToken(":");
tok->insertToken(std::string(1, '\'') + i + '\'');
tok->insertToken("case");
}
}
}
}
}
void Tokenizer::simplifyTemplates()
{
if (isC())
return;
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,
#ifdef MAXTIME
maxtime,
#else
0, // ignored
#endif
_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|enum") || (!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->link()->next();
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;
if (Token::Match(tok, "%name% = { . %name% =")) {
const unsigned int struct_varid = tok->varId();
if (struct_varid == 0)
return;
std::map<std::string, unsigned int>& members = structMembers[struct_varid];
tok = tok->tokAt(3);
while (tok->str() != "}") {
if (Token::Match(tok, "{|[|("))
tok = tok->link();
if (Token::Match(tok->previous(), "[,{] . %name% =")) {
tok = tok->next();
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 = tok->next();
}
return;
}
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;
}
void Tokenizer::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)
{
// 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 (!tok)
syntaxError(nullptr); // #7089 invalid code
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 || initList) {
if (Token::Match(tok->previous(), "::|.") && tok->strAt(-2) != "this" && !Token::simpleMatch(tok->tokAt(-5), "( * this ) ."))
continue;
if (!tok->next())
syntaxError(nullptr); // #7237 invalid code
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 .") && !Token::simpleMatch(tok2->tokAt(-5), "( * 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();
setVarIdPass1();
setVarIdPass2();
}
// Variable declarations can't start with "return" etc.
static const std::set<std::string> notstart_c = make_container< std::set<std::string> > ()
<< "goto" << "NOT" << "return" << "sizeof"<< "typedef";
static const std::set<std::string> notstart_cpp = make_container< std::set<std::string> > ()
<< notstart_c
<< "delete" << "friend" << "new" << "throw" << "using" << "virtual" << "explicit" << "const_cast" << "dynamic_cast" << "reinterpret_cast" << "static_cast" << "template";
void Tokenizer::setVarIdPass1()
{
// Variable declarations can't start with "return" etc.
const std::set<std::string>& notstart = (isC()) ? notstart_c : notstart_cpp;
// 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<VarIdscopeInfo> scopeStack;
scopeStack.push(VarIdscopeInfo());
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(VarIdscopeInfo(true, scopeStack.top().isStructInit || tok->strAt(-1) == "=", _varId));
} else if (!initlist && tok->str()=="(") {
const Token * newFunctionDeclEnd = nullptr;
if (!scopeStack.top().isExecutable)
newFunctionDeclEnd = isFunctionHead(tok, "{:;");
else {
Token const * const tokenLinkNext = tok->link()->next();
if (tokenLinkNext && 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 (Token::Match(tok, "{|}")) {
const Token * const startToken = (tok->str() == "{") ? tok : tok->link();
// parse anonymous unions as part of the current scope
if (!Token::Match(startToken->previous(), "union|struct|enum {") &&
!(initlist && Token::Match(startToken->previous(), "%name%|>|>>") && Token::Match(startToken->link(), "} ,|{"))) {
if (tok->str() == "{") {
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));
if (!(scopeStack.top().isStructInit || tok->strAt(-1) == "="))
scopeInfo.push(variableId);
}
initlist = false;
scopeStack.push(VarIdscopeInfo(isExecutable, scopeStack.top().isStructInit || tok->strAt(-1) == "=", _varId));
} else { /* if (tok->str() == "}") */
bool isNamespace = false;
for (const Token *tok1 = tok->link()->previous(); tok1 && tok1->isName(); tok1 = tok1->previous())
isNamespace |= (tok1->str() == "namespace");
// Set variable ids in class declaration..
if (!initlist && !isC() && !scopeStack.top().isExecutable && tok->link() && !isNamespace) {
setVarIdClassDeclaration(tok->link(),
variableId,
scopeStack.top().startVarid,
structMembers);
}
if (!scopeStack.top().isStructInit) {
if (scopeInfo.empty()) {
variableId.clear();
} else {
variableId.swap(scopeInfo.top());
scopeInfo.pop();
}
}
scopeStack.pop();
if (scopeStack.empty()) { // should be impossible
scopeStack.push(VarIdscopeInfo());
}
}
}
}
if (!scopeStack.top().isStructInit &&
(tok == list.front() ||
Token::Match(tok, "[;{}]") ||
(tok->str() == "(" && isFunctionHead(tok,"{")) ||
(tok->str() == "(" && !scopeStack.top().isExecutable && isFunctionHead(tok,";:")) ||
(tok->str() == "," && !scopeStack.top().isExecutable) ||
(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% :") && tok->strAt(-1) == "for")
;
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->isOperatorKeyword())
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() ||
tok3->str() == "(" ||
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;
// set varid for template parameters..
tok = tok->next();
while (Token::Match(tok, "%name%|::"))
tok = tok->next();
if (tok && tok->str() == "<") {
const Token *end = tok->findClosingBracket();
while (tok != end) {
if (tok->isName() && variableId.find(tok->str()) != variableId.end())
tok->varId(variableId[tok->str()]);
tok = tok->next();
}
}
tok = tok2->previous();
}
}
}
if (tok->isName()) {
// don't set variable id after a struct|enum|union
if (Token::Match(tok->previous(), "struct|enum|union") || (isCPP() && tok->strAt(-1) == "class"))
continue;
if (!isC()) {
if (tok->previous() && tok->previous()->str() == "::")
continue;
if (tok->next() && tok->next()->str() == "::")
continue;
}
// function declaration inside executable scope?
if (scopeStack.top().isExecutable && Token::Match(tok, "%name% [,)]")) {
bool par = false;
const Token *start, *end;
for (start = tok; Token::Match(start, "%name%|*|&|,|("); start = start->previous()) {
if (start->str() == "(") {
if (par)
break;
par = true;
}
if (Token::Match(start, "[(,]")) {
if (!Token::Match(start, "[(,] %type% %name%|*|&"))
break;
}
if (start->varId() > 0U)
break;
}
for (end = tok->next(); Token::Match(end, "%name%|*|&|,"); end = end->next()) {}
if (Token::Match(start, "[;{}] %type% %name%|*") && par && Token::simpleMatch(end, ") ;"))
// function declaration => don't set varid
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();
}
}
}
void Tokenizer::setVarIdPass2()
{
std::map<unsigned int, std::map<std::string, unsigned int> > structMembers;
// 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()) {
const Token* tok3 = nullptr;
if (Token::Match(tok2, "%name% :: ~| %name%"))
tok3 = tok2->next();
else if (Token::Match(tok2, "%name% <") && Token::Match(tok2->next()->findClosingBracket(),"> :: ~| %name%"))
tok3 = tok2->next()->findClosingBracket()->next();
else
continue;
while (Token::Match(tok3, ":: ~| %name%")) {
tok3 = tok3->next();
if (tok3->str() == "~")
tok3 = tok3->next();
tok3 = tok3->next();
}
if (!tok3)
syntaxError(tok2);
const std::string& str3 = tok3->str();
if (str3 == "(")
allMemberFunctions.push_back(tok2);
else if (str3 != "::" && tok2->strAt(-1) != "::") // Support only one depth
allMemberVars.push_back(tok2);
}
}
// class members..
std::map<std::string, std::map<std::string, unsigned int> > varsByClass;
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (!Token::Match(tok, "namespace|class|struct %name% {|:|::"))
continue;
std::string classname(tok->next()->str());
const Token* tokStart = tok->tokAt(2);
unsigned int nestedCount = 1;
while (Token::Match(tokStart, ":: %name%")) {
classname += " :: " + tokStart->strAt(1);
tokStart = tokStart->tokAt(2);
nestedCount++;
}
std::map<std::string, unsigned int>& thisClassVars = varsByClass[classname];
while (tokStart && tokStart->str() != "{") {
if (Token::Match(tokStart, "public|private|protected %name%"))
tokStart = tokStart->next();
if (tokStart->strAt(1) == "," || tokStart->strAt(1) == "{") {
const std::map<std::string, unsigned int>& baseClassVars = varsByClass[tokStart->str()];
thisClassVars.insert(baseClassVars.begin(), baseClassVars.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(), thisClassVars, 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)
thisClassVars[tok2->str()] = tok2->varId();
}
}
// Are there any member variables in this class?
if (thisClassVars.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(thisClassVars[tok2->str()]);
}
if (isC() || tok->str() == "namespace")
continue;
// Set variable ids in member functions for this class..
for (std::list<Token *>::iterator func = allMemberFunctions.begin(); func != allMemberFunctions.end(); ++func) {
Token *tok2 = *func;
if (!Token::Match(tok2, classname.c_str()))
continue;
if (Token::Match(tok2, "%name% <"))
tok2 = tok2->next()->findClosingBracket();
// Found a class function..
if (!Token::Match(tok2, "%any% :: ~| %name%"))
continue;
// Goto the end parentheses..
tok2 = tok2->tokAt(nestedCount*2);
if (tok2->str() == "~")
tok2 = tok2->linkAt(2);
else
tok2 = tok2->linkAt(1);
// If this is a function implementation.. add it to funclist
Token * start = const_cast<Token *>(isFunctionHead(tok2, "{"));
if (start) {
setVarIdClassFunction(classname, start, start->link(), thisClassVars, structMembers, &_varId);
}
if (Token::Match(tok2, ") %name% ("))
tok2 = tok2->linkAt(2);
// constructor with initializer list
if (!Token::Match(tok2, ") : ::| %name%"))
continue;
Token *tok3 = tok2;
while (Token::Match(tok3, "[)}] [,:]")) {
tok3 = tok3->tokAt(2);
if (Token::Match(tok3, ":: %name%"))
tok3 = tok3->next();
while (Token::Match(tok3, "%name% :: %name%"))
tok3 = tok3->tokAt(2);
if (!Token::Match(tok3, "%name% (|{|<"))
break;
// set varid
std::map<std::string, unsigned int>::const_iterator varpos = thisClassVars.find(tok3->str());
if (varpos != thisClassVars.end())
tok3->varId(varpos->second);
// goto end of var
if (tok3->strAt(1) == "<") {
tok3 = tok3->next()->findClosingBracket();
if (tok3 && tok3->next() && tok3->next()->link())
tok3 = tok3->next()->link();
} else
tok3 = tok3->linkAt(1);
}
if (Token::Match(tok3, ")|} {")) {
setVarIdClassFunction(classname, tok2, tok3->next()->link(), thisClassVars, 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;
const Token * templateToken = nullptr;
bool isStruct = false;
std::stack<Token*> type;
for (Token *token = list.front(); token; token = token->next()) {
if (Token::Match(token, "struct|class %name% :"))
isStruct = true;
else if (Token::Match(token, "[;{}]"))
isStruct = false;
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();
templateToken = nullptr;
} else
token->link(0);
} else if (!templateToken && !isStruct && Token::Match(token, "%oror%|&&|;")) {
if (Token::Match(token, "&& [,>]"))
continue;
while (!type.empty() && type.top()->str() == "<")
type.pop();
} else if (token->str() == "<" && token->previous() && token->previous()->isName() && !token->previous()->varId()) {
type.push(token);
if (!templateToken && (token->previous()->str() == "template"))
templateToken = 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();
if (top == templateToken)
templateToken = nullptr;
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, const Token *> declTokOfVar;
for (const 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;
const Token* tok2 = tok->next();
do {
const MathLib::bigint num = MathLib::toLongNumber(tok2->strAt(1));
if (num<0)
break; // #6940 negative number
size *= (unsigned)num;
tok2 = tok2->tokAt(3);
} while (Token::Match(tok2, "[ %num% ]"));
if (Token::Match(tok2, "[;=]")) {
sizeOfVar[varId] = size;
declTokOfVar[varId] = tok;
}
if (!tok2) {
syntaxError(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 (Token::simpleMatch(tok->next(), ". . .")) {
tok->deleteNext(3);
}
// sizeof('x')
if (Token::Match(tok->next(), "( %char% )")) {
tok->deleteNext();
tok->deleteThis();
tok->deleteNext();
std::ostringstream sz;
sz << ((isC()) ? _settings->sizeof_int : 1) ; // #7490 sizeof('a') should be sizeof(int) in C mode
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% )")) {
std::map<unsigned int, unsigned int>::const_iterator sizeOfVarPos = sizeOfVar.find(tok->tokAt(2)->varId());
if (sizeOfVarPos != sizeOfVar.end()) {
tok->deleteNext();
tok->deleteThis();
tok->deleteNext();
tok->str(MathLib::toString(sizeOfVarPos->second));
ret = true;
} else {
// don't try to replace size of variable if variable has
// similar name with type (#329)
}
}
else if (Token::Match(tok->next(), "( %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::simpleMatch(tok->next(), "( *") || Token::Match(tok->next(), "( %name% [")) {
unsigned int derefs = 0;
const Token* nametok = tok->tokAt(2);
if (nametok->str() == "*") {
do {
nametok = nametok->next();
derefs++;
} while (nametok && nametok->str() == "*");
if (!Token::Match(nametok, "%name% )"))
continue;
} else {
const Token* tok2 = nametok->next();
do {
tok2 = tok2->link()->next();
derefs++;
} while (tok2 && tok2->str() == "[");
if (!tok2 || tok2->str() != ")")
continue;
}
// Some default value
MathLib::biguint size = 0;
const unsigned int varid = nametok->varId();
if (derefs != 0 && varid != 0 && declTokOfVar.find(varid) != declTokOfVar.end()) {
// Try to locate variable declaration..
const Token *decltok = declTokOfVar[varid];
if (Token::Match(decltok->previous(), "%type%|* %name% [")) {
size = sizeOfType(decltok->previous());
} else if (Token::Match(decltok->tokAt(-2), "%type% * %name%")) {
size = sizeOfType(decltok->tokAt(-2));
}
// Multi-dimensional array..
if (Token::Match(decltok, "%name% [") && Token::simpleMatch(decltok->linkAt(1), "] [")) {
const Token *tok2 = decltok;
for (unsigned int i = 0; i < derefs; i++)
tok2 = tok2->linkAt(1); // Skip all dimensions that are derefenced before the sizeof call
while (Token::Match(tok2, "] [ %num% ]")) {
size *= MathLib::toULongNumber(tok2->strAt(2));
tok2 = tok2->linkAt(1);
}
if (Token::simpleMatch(tok2, "] ["))
continue;
}
} else if (nametok->strAt(1) == "[" && nametok->isStandardType()) {
size = sizeOfType(nametok);
if (size == 0)
continue;
const Token *tok2 = nametok->next();
while (Token::Match(tok2, "[ %num% ]")) {
size *= MathLib::toULongNumber(tok2->strAt(1));
tok2 = tok2->link()->next();
}
if (!tok2 || tok2->str() != ")")
continue;
}
if (size > 0) {
tok->str(MathLib::toString(size));
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);
}
}
}
// remove MACRO in variable declaration: MACRO int x;
removeMacroInVarDecl();
// Combine strings
combineStrings();
// replace inline SQL with "asm()" (Oracle PRO*C). Ticket: #1959
simplifySQL();
createLinks();
// Bail out if code is garbage
if (const Token *garbage = findGarbageCode())
syntaxError(garbage);
// 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());
}
}
}
if (_settings->terminated())
return false;
// Remove [[deprecated]]
simplifyDeprecated();
// remove __attribute__((?))
simplifyAttribute();
// 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();
// Combine tokens..
combineOperators();
// 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);
}
}
if (!simplifyAddBraces())
return false;
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();
// simplify simple calculations inside <..>
if (isCPP()) {
Token *lt = nullptr;
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "[;{}]"))
lt = nullptr;
else if (Token::Match(tok, "%type% <"))
lt = tok->next();
else if (lt && Token::Match(tok, ">|>> %name%|::|(")) {
const Token * const end = tok;
for (tok = lt; tok != end; tok = tok->next()) {
if (tok->isNumber())
TemplateSimplifier::simplifyNumericCalculations(tok->previous());
}
lt = tok->next();
}
}
}
// Convert K&R function declarations to modern C
simplifyVarDecl(true);
simplifyFunctionParameters();
// simplify case ranges (gcc extension)
simplifyCaseRange();
// simplify labels and 'case|default'-like syntaxes
simplifyLabelsCaseDefault();
// simplify '[;{}] * & ( %any% ) =' to '%any% ='
simplifyMulAndParens();
if (!isC() && !_settings->library.markupFile(FileName)) {
findComplicatedSyntaxErrorsInTemplates();
}
if (_settings->terminated())
return false;
// remove calling conventions __cdecl, __stdcall..
simplifyCallingConvention();
// Remove __declspec()
simplifyDeclspec();
validate();
// remove some unhandled macros in global scope
removeMacrosInGlobalScope();
// remove undefined macro in class definition:
// class DLLEXPORT Fred { };
// class Fred FINAL : Base { };
removeMacroInClassDef();
// That call here fixes #7190
validate();
// remove unnecessary member qualification..
removeUnnecessaryQualification();
// 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();
// #2449: syntax error: enum with typedef in it
checkForEnumsWithTypedef();
// Remove __asm..
simplifyAsm();
// Add parentheses to ternary operator where necessary
prepareTernaryOpForAST();
// 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();
}
// Add parentheses to ternary operator where necessary
// TODO: this is only necessary if one typedef simplification had a comma and was used within ?:
// If typedef handling is refactored and moved to symboldatabase someday we can remove this
prepareTernaryOpForAST();
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 (isCPP() && _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();
// The simplify enum have inner loops
if (_settings->terminated())
return false;
// Put ^{} statements in asm()
simplifyAsm2();
// Order keywords "static" and "const"
simplifyStaticConst();
// 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 (with _isUnsigned=true,_isLong=true)
simplifyStdType();
if (_settings->terminated())
return false;
// simplify bit fields..
simplifyBitfields();
if (_settings->terminated())
return false;
// struct simplification "struct S {} s; => struct S { } ; S s ;
simplifyStructDecl();
if (_settings->terminated())
return false;
// x = ({ 123; }); => { x = 123; }
simplifyAssignmentBlock();
if (_settings->terminated())
return false;
simplifyVariableMultipleAssign();
// Collapse operator name tokens into single token
// operator = => operator=
simplifyOperatorName();
// Remove redundant parentheses
simplifyRedundantParentheses();
if (!isC()) {
// TODO: Only simplify template parameters
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;
// 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.
validate(); // #6847 - invalid code
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);
validate(); // #6772 "segmentation fault (invalid code) in Tokenizer::setVarId"
if (m_timerResults) {
Timer t("Tokenizer::tokenize::setVarId", _settings->showtime, m_timerResults);
setVarId();
} else {
setVarId();
}