Improved support for references and pointers in SymbolDatabase

Replaced several isPointer functions by Variable::isPointer function
Refactorizations & Make use of symbolDatabase more often
This commit is contained in:
PKEuS 2011-12-17 19:04:03 +01:00 committed by Daniel Marjamäki
parent f09a5b408b
commit f306246c7f
8 changed files with 205 additions and 275 deletions

View File

@ -422,25 +422,11 @@ static bool for_bailout(const Token * const tok1, unsigned int varid)
} }
void CheckBufferOverrun::parse_for_body(const Token *tok2, const ArrayInfo &arrayInfo, const std::string &strindex, bool condition_out_of_bounds, unsigned int counter_varid, const std::string &min_counter_value, const std::string &max_counter_value) void CheckBufferOverrun::parse_for_body(const Token *tok, const ArrayInfo &arrayInfo, const std::string &strindex, bool condition_out_of_bounds, unsigned int counter_varid, const std::string &min_counter_value, const std::string &max_counter_value)
{ {
const std::string pattern((arrayInfo.varid() ? std::string("%varid%") : arrayInfo.varname()) + " [ " + strindex + " ]"); const std::string pattern((arrayInfo.varid() ? std::string("%varid%") : arrayInfo.varname()) + " [ " + strindex + " ]");
// count { and } for tok2 for (const Token* tok2 = tok; tok2 && tok2 != tok->link(); tok2 = tok2->next()) {
int indentlevel2 = 0;
for (; tok2; tok2 = tok2->next()) {
if (tok2->str() == ";" && indentlevel2 == 0)
break;
if (tok2->str() == "{")
++indentlevel2;
if (tok2->str() == "}") {
--indentlevel2;
if (indentlevel2 <= 0)
break;
}
// TODO: try to reduce false negatives. This is just a quick fix // TODO: try to reduce false negatives. This is just a quick fix
// for TestBufferOverrun::array_index_for_question // for TestBufferOverrun::array_index_for_question
if (tok2->str() == "?") if (tok2->str() == "?")
@ -713,31 +699,22 @@ void CheckBufferOverrun::checkFunctionCall(const Token *tok, const ArrayInfo &ar
} }
callstack.push_back(tok); callstack.push_back(tok);
const Token *tok2 = tok->tokAt(2);
// 1st parameter.. // 1st parameter..
if (Token::Match(tok->tokAt(2), "%varid% ,|)", arrayInfo.varid())) if (Token::Match(tok2, "%varid% ,|)", arrayInfo.varid()))
checkFunctionParameter(*tok, 1, arrayInfo, callstack); checkFunctionParameter(*tok, 1, arrayInfo, callstack);
else if (Token::Match(tok->tokAt(2), "%varid% + %num% ,|)", arrayInfo.varid())) { else if (Token::Match(tok2, "%varid% + %num% ,|)", arrayInfo.varid())) {
const ArrayInfo ai(arrayInfo.limit(MathLib::toLongNumber(tok->strAt(4)))); const ArrayInfo ai(arrayInfo.limit(MathLib::toLongNumber(tok2->strAt(2))));
checkFunctionParameter(*tok, 1, ai, callstack); checkFunctionParameter(*tok, 1, ai, callstack);
} }
// goto 2nd parameter and check it.. // goto 2nd parameter and check it..
for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) { tok2 = tok2->nextArgument();
if (tok2->str() == "(") { if (Token::Match(tok2, "%varid% ,|)", arrayInfo.varid()))
tok2 = tok2->link(); checkFunctionParameter(*tok, 2, arrayInfo, callstack);
continue; else if (Token::Match(tok2, "%varid% + %num% ,|)", arrayInfo.varid())) {
} const ArrayInfo ai(arrayInfo.limit(MathLib::toLongNumber(tok2->strAt(2))));
if (tok2->str() == ";" || tok2->str() == ")") checkFunctionParameter(*tok, 2, ai, callstack);
break;
if (tok2->str() == ",") {
if (Token::Match(tok2, ", %varid% ,|)", arrayInfo.varid()))
checkFunctionParameter(*tok, 2, arrayInfo, callstack);
else if (Token::Match(tok2, ", %varid% + %num% ,|)", arrayInfo.varid())) {
const ArrayInfo ai(arrayInfo.limit(MathLib::toLongNumber(tok2->strAt(3))));
checkFunctionParameter(*tok, 2, ai, callstack);
}
break;
}
} }
} }
@ -1012,7 +989,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
} }
// undefined behaviour: result of pointer arithmetic is out of bounds // undefined behaviour: result of pointer arithmetic is out of bounds
if (varid && Token::Match(tok, "= %varid% + %num% ;", varid)) { else if (varid && Token::Match(tok, "= %varid% + %num% ;", varid)) {
const MathLib::bigint index = MathLib::toLongNumber(tok->strAt(3)); const MathLib::bigint index = MathLib::toLongNumber(tok->strAt(3));
if (index > size && _settings->isEnabled("portability")) if (index > size && _settings->isEnabled("portability"))
pointerOutOfBoundsError(tok->next(), "buffer"); pointerOutOfBoundsError(tok->next(), "buffer");
@ -1020,7 +997,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
pointerIsOutOfBounds = true; pointerIsOutOfBounds = true;
} }
if (pointerIsOutOfBounds && Token::Match(tok, "[;{}=] * %varid% [;=]", varid)) { else if (pointerIsOutOfBounds && Token::Match(tok, "[;{}=] * %varid% [;=]", varid)) {
outOfBoundsError(tok->tokAt(2), tok->strAt(2), false, 0, 0); outOfBoundsError(tok->tokAt(2), tok->strAt(2), false, 0, 0);
} }
} }

View File

@ -288,31 +288,6 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown)
return false; return false;
} }
bool CheckNullPointer::isPointer(const unsigned int varid)
{
// Check if given variable is a pointer
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
const Variable *variableInfo = symbolDatabase->getVariableFromVarId(varid);
const Token *tok = variableInfo ? variableInfo->typeStartToken() : NULL;
if (Token::Match(tok, "%type% %type% * %varid% [;)=]", varid))
return true;
// maybe not a pointer
if (!Token::Match(tok, "%type% * %varid% [;)=]", varid))
return false;
// it is a pointer
if (!tok->previous() ||
Token::Match(tok->previous(), "[({};]") ||
tok->previous()->isName()) {
return true;
}
// it is not a pointer
return false;
}
void CheckNullPointer::nullPointerAfterLoop() void CheckNullPointer::nullPointerAfterLoop()
{ {
const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
@ -327,12 +302,10 @@ void CheckNullPointer::nullPointerAfterLoop()
continue; continue;
// Get variable id for the loop variable // Get variable id for the loop variable
const unsigned int varid(tok->tokAt(2)->varId()); const Variable* var(symbolDatabase->getVariableFromVarId(tok->tokAt(2)->varId()));
if (varid == 0)
continue;
// Is variable a pointer? // Is variable a pointer?
if (!isPointer(varid)) if (!var || !var->isPointer())
continue; continue;
// Get variable name for the loop variable // Get variable name for the loop variable
@ -371,7 +344,7 @@ void CheckNullPointer::nullPointerAfterLoop()
break; break;
// loop variable is found.. // loop variable is found..
else if (tok2->varId() == varid) { else if (tok2->varId() == var->varId()) {
// dummy variable.. is it unknown if pointer is dereferenced or not? // dummy variable.. is it unknown if pointer is dereferenced or not?
bool unknown = _settings->inconclusive; bool unknown = _settings->inconclusive;
@ -445,8 +418,9 @@ void CheckNullPointer::nullPointerLinkedList()
++indentlevel4; ++indentlevel4;
else if (tok4->str() == "}") { else if (tok4->str() == "}") {
if (indentlevel4 <= 1) { if (indentlevel4 <= 1) {
const Variable* var = symbolDatabase->getVariableFromVarId(varid);
// Is this variable a pointer? // Is this variable a pointer?
if (isPointer(varid)) if (var && var->isPointer())
nullPointerError(tok1, varname, tok3->linenr()); nullPointerError(tok1, varname, tok3->linenr());
break; break;
@ -580,7 +554,9 @@ void CheckNullPointer::nullPointerStructByDeRefAndChec()
// is pointer local? // is pointer local?
bool isLocal = false; bool isLocal = false;
const Variable * var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(tok1->varId()); const Variable * var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(tok1->varId());
if (var && (var->isLocal() || var->isArgument())) if (!var)
continue;
if (var->isLocal() || var->isArgument())
isLocal = true; isLocal = true;
// member function may or may not nullify the pointer if it's global (#2647) // member function may or may not nullify the pointer if it's global (#2647)
@ -641,7 +617,7 @@ void CheckNullPointer::nullPointerStructByDeRefAndChec()
// TODO: false negatives for "if (!p || .." // TODO: false negatives for "if (!p || .."
else if (Token::Match(tok2, "if ( !| %varid% )|&&", varid1)) { else if (Token::Match(tok2, "if ( !| %varid% )|&&", varid1)) {
// Is this variable a pointer? // Is this variable a pointer?
if (isPointer(varid1)) if (var->isPointer())
nullPointerError(tok1, varname, tok2->linenr(), inconclusive); nullPointerError(tok1, varname, tok2->linenr(), inconclusive);
break; break;
} }
@ -674,13 +650,9 @@ void CheckNullPointer::nullPointerByDeRefAndChec()
// Name of pointer // Name of pointer
const std::string varname(vartok->str()); const std::string varname(vartok->str());
const Variable* var = symbolDatabase->getVariableFromVarId(varid);
// Check that variable is a pointer.. // Check that variable is a pointer..
if (!isPointer(varid)) if (!var || !var->isPointer())
continue;
// Token where pointer is declared
const Variable *var = symbolDatabase->getVariableFromVarId(varid);
if (!var)
continue; continue;
const Token * const decltok = var->nameToken(); const Token * const decltok = var->nameToken();
@ -785,15 +757,8 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
{ {
// Check if pointer is NULL and then dereference it.. // Check if pointer is NULL and then dereference it..
// used to check if a variable is a pointer.
// TODO: Use isPointer?
std::set<unsigned int> pointerVariables;
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (Token::Match(tok, "* %var% [;,)=]")) if (Token::simpleMatch(tok, "if (")) {
pointerVariables.insert(tok->next()->varId());
else if (Token::simpleMatch(tok, "if (")) {
// TODO: investigate false negatives: // TODO: investigate false negatives:
// - handle "while"? // - handle "while"?
// - if there are logical operators // - if there are logical operators
@ -828,8 +793,9 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
const unsigned int linenr = vartok->linenr(); const unsigned int linenr = vartok->linenr();
// Check if variable is a pointer. TODO: Use isPointer? const Variable* var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(varid);
if (pointerVariables.find(varid) == pointerVariables.end()) // Check if variable is a pointer
if (!var || !var->isPointer())
continue; continue;
if (Token::Match(vartok->next(), "&& ( %varid% =", varid)) if (Token::Match(vartok->next(), "&& ( %varid% =", varid))
@ -906,9 +872,9 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
// function call, check if pointer is dereferenced // function call, check if pointer is dereferenced
if (Token::Match(tok2, "%var% (")) { if (Token::Match(tok2, "%var% (")) {
std::list<const Token *> var; std::list<const Token *> vars;
parseFunctionCall(*tok2, var, 0); parseFunctionCall(*tok2, vars, 0);
for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it) { for (std::list<const Token *>::const_iterator it = vars.begin(); it != vars.end(); ++it) {
if (Token::Match(*it, "%varid% [,)]", varid)) { if (Token::Match(*it, "%varid% [,)]", varid)) {
nullPointerError(*it, pointerName, linenr, inconclusive); nullPointerError(*it, pointerName, linenr, inconclusive);
break; break;
@ -932,8 +898,6 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
} }
// init function (global variables) // init function (global variables)
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
const Variable *var = symbolDatabase->getVariableFromVarId(varid);
if (!var || !(var->isLocal() || var->isArgument())) if (!var || !(var->isLocal() || var->isArgument()))
break; break;
} }

View File

@ -120,12 +120,6 @@ public:
private: private:
/**
* Check if a variable is a pointer
* @param varid variable id for variable
*/
bool isPointer(const unsigned int varid);
/** /**
* @brief Does one part of the check for nullPointer(). * @brief Does one part of the check for nullPointer().
* Locate insufficient null-pointer handling after loop * Locate insufficient null-pointer handling after loop

View File

@ -750,24 +750,25 @@ void CheckOther::coutCerrMisusageError(const Token* tok, const std::string& stre
// //
// int y = y; // <- redundant initialization to self // int y = y; // <- redundant initialization to self
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static bool isPOD(const Variable* var)
{
// TODO: Implement real support for POD definition
return(var && var->nameToken()->previous()->isStandardType());
}
void CheckOther::checkSelfAssignment() void CheckOther::checkSelfAssignment()
{ {
if (!_settings->isEnabled("style")) if (!_settings->isEnabled("style"))
return; return;
// POD variables.. const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
std::set<unsigned int> pod;
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (tok->isStandardType() && Token::Match(tok->tokAt(2), "[,);]") && tok->next()->varId())
pod.insert(tok->next()->varId());
}
const char selfAssignmentPattern[] = "%var% = %var% ;|=|)"; const char selfAssignmentPattern[] = "%var% = %var% ;|=|)";
const Token *tok = Token::findmatch(_tokenizer->tokens(), selfAssignmentPattern); const Token *tok = Token::findmatch(_tokenizer->tokens(), selfAssignmentPattern);
while (tok) { while (tok) {
if (Token::Match(tok->previous(), "[;{}]") && if (Token::Match(tok->previous(), "[;{}]") &&
tok->varId() && tok->varId() == tok->tokAt(2)->varId() && tok->varId() && tok->varId() == tok->tokAt(2)->varId() &&
pod.find(tok->varId()) != pod.end()) { isPOD(symbolDatabase->getVariableFromVarId(tok->varId()))) {
bool err = true; bool err = true;
// no false positive for 'x = x ? x : 1;' // no false positive for 'x = x ? x : 1;'
@ -1512,29 +1513,26 @@ void CheckOther::unreachableCodeError(const Token *tok)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Check for unsigned divisions // Check for unsigned divisions
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static bool isUnsigned(const Variable* var)
{
return(var && var->typeStartToken()->isUnsigned() && var->typeStartToken() == var->typeEndToken());
}
void CheckOther::checkUnsignedDivision() void CheckOther::checkUnsignedDivision()
{ {
// Check for "ivar / uvar" and "uvar / ivar" const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
std::set<unsigned int> uvars;
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (Token::Match(tok, "[{};(,] %type% %var% [;=,)]")) {
if (tok->next()->isUnsigned())
uvars.insert(tok->tokAt(2)->varId());
}
else if (!Token::Match(tok, "[).]") && Token::Match(tok->next(), "%var% / %num%")) { // Check for "ivar / uvar" and "uvar / ivar"
if (tok->strAt(3)[0] == '-') { for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (uvars.find(tok->next()->varId()) != uvars.end()) { if (!Token::Match(tok, "[).]") && Token::Match(tok->next(), "%var% / %num%")) {
udivError(tok->next()); if (tok->strAt(3)[0] == '-' && isUnsigned(symbolDatabase->getVariableFromVarId(tok->next()->varId()))) {
} udivError(tok->next());
} }
} }
else if (Token::Match(tok, "(|[|=|%op% %num% / %var%")) { else if (Token::Match(tok, "(|[|=|%op% %num% / %var%")) {
if (tok->strAt(1)[0] == '-') { if (tok->strAt(1)[0] == '-' && isUnsigned(symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId()))) {
if (uvars.find(tok->tokAt(3)->varId()) != uvars.end()) { udivError(tok->next());
udivError(tok->next());
}
} }
} }
} }
@ -1805,6 +1803,11 @@ void CheckOther::passedByValueError(const Token *tok, const std::string &parname
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Check usage of char variables.. // Check usage of char variables..
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static bool isSignedChar(const Variable* var)
{
return(var && var->nameToken()->previous()->str() == "char" && !var->nameToken()->previous()->isUnsigned() && var->nameToken()->next()->str() != "[");
}
void CheckOther::checkCharVariable() void CheckOther::checkCharVariable()
{ {
if (!_settings->isEnabled("style")) if (!_settings->isEnabled("style"))
@ -1813,87 +1816,50 @@ void CheckOther::checkCharVariable()
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
// Declaring the variable.. if ((tok->str() != ".") && Token::Match(tok->next(), "%var% [ %var% ]")) {
if (Token::Match(tok, "[{};(,] const| char *| const| %var% [;=,)]") || const Variable* var = symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId());
Token::Match(tok, "[{};(,] const| char %var% [")) { if (isSignedChar(var))
// goto 'char' token charArrayIndexError(tok->next());
tok = tok->next(); }
if (tok->str() == "const")
tok = tok->next();
// Check for unsigned char else if (Token::Match(tok, "[;{}] %var% = %any% [&|] %any% ;")) {
if (tok->isUnsigned()) // is a char variable used in the calculation?
if (!isSignedChar(symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId())) &&
!isSignedChar(symbolDatabase->getVariableFromVarId(tok->tokAt(5)->varId())))
continue; continue;
// Set tok to point to the variable name // it's ok with a bitwise and where the other operand is 0xff or less..
tok = tok->next(); if (tok->strAt(4) == "&") {
const bool isPointer(tok->str() == "*" || tok->strAt(1) == "["); if (tok->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok->strAt(3)))
if (tok->str() == "*") continue;
tok = tok->next(); if (tok->tokAt(5)->isNumber() && MathLib::isGreater("0x100", tok->strAt(5)))
if (tok->str() == "const") continue;
tok = tok->next();
const unsigned int varid = tok->varId();
if (!varid)
continue;
// Check usage of char variable..
unsigned int indentlevel = 0;
for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
if (tok2->str() == "{")
++indentlevel;
else if (tok2->str() == "}") {
if (!indentlevel)
break;
--indentlevel;
}
if (!isPointer) {
if ((tok2->str() != ".") && Token::Match(tok2->next(), "%var% [ %varid% ]", varid)) {
charArrayIndexError(tok2->next());
break;
}
}
if (Token::Match(tok2, "[;{}] %var% = %any% [&|] %any% ;")) {
// is the char variable used in the calculation?
if (tok2->tokAt(3)->varId() != tok->varId() && tok2->tokAt(5)->varId() != tok->varId())
continue;
// it's ok with a bitwise and where the other operand is 0xff or less..
if (tok2->strAt(4) == "&") {
if (tok2->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok2->strAt(3)))
continue;
if (tok2->tokAt(5)->isNumber() && MathLib::isGreater("0x100", tok2->strAt(5)))
continue;
}
// is the result stored in a short|int|long?
const Variable *var = symbolDatabase->getVariableFromVarId(tok2->next()->varId());
if (!(var && Token::Match(var->typeEndToken(), "short|int|long")))
continue;
// This is an error..
charBitOpError(tok2);
break;
}
if (isPointer && Token::Match(tok2, "[;{}] %var% = %any% [&|] ( * %varid% ) ;", tok->varId())) {
// it's ok with a bitwise and where the other operand is 0xff or less..
if (tok2->strAt(4) == "&" && tok2->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok2->strAt(3)))
continue;
// is the result stored in a short|int|long?
const Variable *var = symbolDatabase->getVariableFromVarId(tok2->next()->varId());
if (!(var && Token::Match(var->typeEndToken(), "short|int|long")))
continue;
// This is an error..
charBitOpError(tok2);
break;
}
} }
// is the result stored in a short|int|long?
const Variable *var = symbolDatabase->getVariableFromVarId(tok->next()->varId());
if (!(var && Token::Match(var->typeEndToken(), "short|int|long")))
continue;
// This is an error..
charBitOpError(tok);
}
else if (Token::Match(tok, "[;{}] %var% = %any% [&|] ( * %var% ) ;")) {
const Variable* var = symbolDatabase->getVariableFromVarId(tok->tokAt(7)->varId());
if (!var || !var->isPointer())
continue;
// it's ok with a bitwise and where the other operand is 0xff or less..
if (tok->strAt(4) == "&" && tok->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok->strAt(3)))
continue;
// is the result stored in a short|int|long?
var = symbolDatabase->getVariableFromVarId(tok->next()->varId());
if (!(var && Token::Match(var->typeEndToken(), "short|int|long")))
continue;
// This is an error..
charBitOpError(tok);
} }
} }
} }
@ -1973,6 +1939,11 @@ void CheckOther::constStatementError(const Token *tok, const std::string &type)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// str plus char // str plus char
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static bool isChar(const Variable* var)
{
return(var && var->nameToken()->previous()->str() == "char" && var->nameToken()->next()->str() != "[");
}
void CheckOther::strPlusChar() void CheckOther::strPlusChar()
{ {
// Don't use this check for Java and C# programs.. // Don't use this check for Java and C# programs..
@ -1980,25 +1951,17 @@ void CheckOther::strPlusChar()
return; return;
} }
std::set<unsigned int> charVars; const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
// Declaring char variable.. if (Token::Match(tok, "[=(] %str% + %any%")) {
if (Token::Match(tok, "char %var% [;=]")) {
unsigned int varid = tok->next()->varId();
if (varid > 0)
charVars.insert(varid);
}
//
else if (Token::Match(tok, "[=(] %str% + %any%")) {
// char constant.. // char constant..
if (tok->strAt(3)[0] == '\'') if (tok->strAt(3)[0] == '\'')
strPlusCharError(tok->next()); strPlusCharError(tok->next());
// char variable.. // char variable..
unsigned int varid = tok->tokAt(3)->varId(); unsigned int varid = tok->tokAt(3)->varId();
if (varid > 0 && charVars.find(varid) != charVars.end()) if (isChar(symbolDatabase->getVariableFromVarId(varid)))
strPlusCharError(tok->next()); strPlusCharError(tok->next());
} }
} }
@ -2102,7 +2065,7 @@ void CheckOther::checkCCTypeFunctions()
{ {
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (tok->varId() == 0 && if (tok->varId() == 0 &&
Token::Match(tok, "isalnum|isalpha|iscntrl|isdigit|isgraph|islower|isprint|ispunct|isspace|isupper|isxdigit ( %num% )") && Token::Match(tok, "isalnum|isalpha|iscntrl|isdigit|isgraph|islower|isprint|ispunct|isspace|isupper|isxdigit ( %num% )") &&
MathLib::isNegative(tok->strAt(2))) { MathLib::isNegative(tok->strAt(2))) {
cctypefunctionCallError(tok, tok->str(), tok->tokAt(2)->str()); cctypefunctionCallError(tok, tok->str(), tok->tokAt(2)->str());
} }

View File

@ -997,12 +997,6 @@ void CheckStl::missingComparisonError(const Token *incrementToken1, const Token
} }
static bool isPointer(const SymbolDatabase* symbolDatabase, unsigned int varid)
{
const Variable* var = symbolDatabase->getVariableFromVarId(varid);
return var && var->nameToken()->previous()->str() == "*";
}
static bool isLocal(const SymbolDatabase* symbolDatabase, unsigned int varid) static bool isLocal(const SymbolDatabase* symbolDatabase, unsigned int varid)
{ {
const Variable* var = symbolDatabase->getVariableFromVarId(varid); const Variable* var = symbolDatabase->getVariableFromVarId(varid);
@ -1023,13 +1017,16 @@ void CheckStl::string_c_str()
// Invalid usage.. // Invalid usage..
if (Token::Match(tok, "throw %var% . c_str ( ) ;") && isLocal(symbolDatabase, tok->next()->varId())) { if (Token::Match(tok, "throw %var% . c_str ( ) ;") && isLocal(symbolDatabase, tok->next()->varId())) {
string_c_strThrowError(tok); string_c_strThrowError(tok);
} else if (Token::Match(tok, "[;{}] %var% = %var% . str ( ) . c_str ( ) ;") && isPointer(symbolDatabase, tok->next()->varId())) { } else if (Token::Match(tok, "[;{}] %var% = %var% . str ( ) . c_str ( ) ;")) {
string_c_strError(tok); const Variable* var = symbolDatabase->getVariableFromVarId(tok->next()->varId());
if (var && var->isPointer())
string_c_strError(tok);
} else if (Token::Match(tok, "[;{}] %var% = %var% (") && } else if (Token::Match(tok, "[;{}] %var% = %var% (") &&
Token::simpleMatch(tok->linkAt(4), ") . c_str ( ) ;") && Token::simpleMatch(tok->linkAt(4), ") . c_str ( ) ;") &&
isPointer(symbolDatabase, tok->next()->varId()) &&
Token::findmatch(_tokenizer->tokens(), ("std :: string " + tok->strAt(3) + " (").c_str())) { Token::findmatch(_tokenizer->tokens(), ("std :: string " + tok->strAt(3) + " (").c_str())) {
string_c_strError(tok); const Variable* var = symbolDatabase->getVariableFromVarId(tok->next()->varId());
if (var && var->isPointer())
string_c_strError(tok);
} }
// Using c_str() to get the return value is only dangerous if the function returns a char* // Using c_str() to get the return value is only dangerous if the function returns a char*

View File

@ -25,8 +25,6 @@
#include "errorlogger.h" #include "errorlogger.h"
#include "check.h" #include "check.h"
#include <locale>
#include <cstring> #include <cstring>
#include <string> #include <string>
#include <sstream> #include <sstream>
@ -111,19 +109,26 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// unnamed struct and union // unnamed struct and union
else if (Token::Match(tok, "struct|union {") && else if (Token::Match(tok, "struct|union {") &&
Token::Match(tok->next()->link(), "} %var% ;|[")) { Token::Match(tok->next()->link(), "} |* %var% ;|[")) {
scopeList.push_back(Scope(this, tok, scope)); scopeList.push_back(Scope(this, tok, scope));
Scope *new_scope = &scopeList.back(); Scope *new_scope = &scopeList.back();
std::vector<Dimension> dimensions; std::vector<Dimension> dimensions;
bool isPointer = false;
bool isArray = false; bool isArray = false;
if (tok->next()->link()->strAt(2) == "[") const Token* varNameTok = tok->next()->link()->next();
isArray = arrayDimensions(dimensions, tok->next()->link()->tokAt(2)); if (varNameTok->str() == "*") {
isPointer = true;
varNameTok = varNameTok->next();
}
scope->addVariable(tok->next()->link()->next(), tok, tok, scope->access, false, false, false, true, new_scope, scope, isArray, dimensions); if (varNameTok->next()->str() == "[")
isArray = arrayDimensions(dimensions, varNameTok->next());
scope->addVariable(varNameTok, tok, tok, scope->access, false, false, false, true, new_scope, scope, isArray, isPointer, dimensions);
const Token *tok2 = tok->next(); const Token *tok2 = tok->next();
@ -1210,20 +1215,14 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Function
// check for non-empty argument list "( ... )" // check for non-empty argument list "( ... )"
if (arg->link() != arg->next() && !Token::simpleMatch(arg, "( void )")) { if (arg->link() != arg->next() && !Token::simpleMatch(arg, "( void )")) {
unsigned int count = 0; unsigned int count = 0;
const Token *startTok;
const Token *endTok; for (const Token* tok = arg->next(); tok; tok = tok->next()) {
const Token *nameTok; const Token* startTok = tok;
bool isConstVar; const Token* endTok = NULL;
bool isArrayVar; const Token* nameTok = NULL;
bool hasDefault; bool isConstVar = bool(tok->str() == "const");
const Token *tok = arg->next(); bool isArrayVar = false;
for (;;) { bool hasDefault = false;
startTok = tok;
endTok = NULL;
nameTok = NULL;
isConstVar = bool(tok->str() == "const");
isArrayVar = false;
hasDefault = false;
std::vector<Dimension> dimensions; std::vector<Dimension> dimensions;
while (tok->str() != "," && tok->str() != ")" && tok->str() != "=") { while (tok->str() != "," && tok->str() != ")" && tok->str() != "=") {
@ -1282,6 +1281,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Function
argType = symbolDatabase->findVariableType(scope, typeTok); argType = symbolDatabase->findVariableType(scope, typeTok);
bool isClassVar = startTok == endTok && !startTok->isStandardType(); bool isClassVar = startTok == endTok && !startTok->isStandardType();
bool isPointerVar = nameTok->strAt(-1) == "*" || nameTok->strAt(-2) == "*";
// skip default values // skip default values
if (tok->str() == "=") { if (tok->str() == "=") {
@ -1291,12 +1291,10 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Function
tok = tok->next(); tok = tok->next();
} }
argumentList.push_back(Variable(nameTok, startTok, endTok, count++, Argument, false, false, isConstVar, isClassVar, argType, functionScope, isArrayVar, hasDefault, dimensions)); argumentList.push_back(Variable(nameTok, startTok, endTok, count++, Argument, false, false, isConstVar, isClassVar, argType, functionScope, isArrayVar, isPointerVar, hasDefault, dimensions));
if (tok->str() == ")") if (tok->str() == ")")
break; break;
tok = tok->next();
} }
} }
} }
@ -1359,8 +1357,7 @@ Scope::Scope(SymbolDatabase *check_, const Token *classDef_, Scope *nestedIn_) :
} }
} }
bool bool Scope::hasDefaultConstructor() const
Scope::hasDefaultConstructor() const
{ {
if (numConstructors) { if (numConstructors) {
std::list<Function>::const_iterator func; std::list<Function>::const_iterator func;
@ -1548,10 +1545,12 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess)
} }
bool isArray = false; bool isArray = false;
bool isPointer = false;
std::vector<Dimension> dimensions; std::vector<Dimension> dimensions;
if (tok && isVariableDeclaration(tok, vartok, typetok, isArray)) { if (tok && isVariableDeclaration(tok, vartok, typetok, isArray, isPointer)) {
isClass = (!typetok->isStandardType() && vartok->previous()->str() != "*"); isPointer = vartok->previous()->str() == "*" || vartok->strAt(-2) == "*";
isClass = (!typetok->isStandardType() && !isPointer && vartok->previous()->str() != "&");
if (isArray) { if (isArray) {
isArray = check->arrayDimensions(dimensions, vartok->next()); isArray = check->arrayDimensions(dimensions, vartok->next());
tok = vartok->next(); tok = vartok->next();
@ -1571,7 +1570,7 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess)
if (typetok) if (typetok)
scope = check->findVariableType(this, typetok); scope = check->findVariableType(this, typetok);
addVariable(vartok, typestart, vartok->previous(), varaccess, isMutable, isStatic, isConst, isClass, scope, this, isArray, dimensions); addVariable(vartok, typestart, vartok->previous(), varaccess, isMutable, isStatic, isConst, isClass, scope, this, isArray, isPointer, dimensions);
} }
return tok; return tok;
@ -1607,14 +1606,14 @@ inline const Token* skipPointers(const Token* tok)
{ {
const Token* ret = tok; const Token* ret = tok;
while (Token::simpleMatch(ret, "*")) { while (Token::Match(ret, "*|&")) {
ret = ret->next(); ret = ret->next();
} }
return ret; return ret;
} }
bool Scope::isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok, bool &isArray) const bool Scope::isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok, bool &isArray, bool &isPointer) const
{ {
const Token* localTypeTok = skipScopeIdentifiers(tok); const Token* localTypeTok = skipScopeIdentifiers(tok);
const Token* localVarTok = NULL; const Token* localVarTok = NULL;
@ -1649,6 +1648,7 @@ bool Scope::isVariableDeclaration(const Token* tok, const Token*& vartok, const
typetok = localTypeTok; typetok = localTypeTok;
isArray = false; isArray = false;
} }
isPointer = vartok && (vartok->strAt(-1) == "*" || vartok->strAt(-2) == "*");
return NULL != vartok; return NULL != vartok;
} }

View File

@ -61,7 +61,8 @@ class Variable {
fIsConst = (1 << 2), /** @brief const variable */ fIsConst = (1 << 2), /** @brief const variable */
fIsClass = (1 << 3), /** @brief user defined type */ fIsClass = (1 << 3), /** @brief user defined type */
fIsArray = (1 << 4), /** @brief array variable */ fIsArray = (1 << 4), /** @brief array variable */
fHasDefault = (1 << 5) /** @brief function argument with default value */ fIsPointer = (1 << 5), /** @brief pointer variable */
fHasDefault = (1 << 6) /** @brief function argument with default value */
}; };
/** /**
@ -86,7 +87,7 @@ public:
Variable(const Token *name_, const Token *start_, const Token *end_, Variable(const Token *name_, const Token *start_, const Token *end_,
std::size_t index_, AccessControl access_, bool mutable_, std::size_t index_, AccessControl access_, bool mutable_,
bool static_, bool const_, bool class_, const Scope *type_, bool static_, bool const_, bool class_, const Scope *type_,
const Scope *scope_, bool array_, bool default_, const Scope *scope_, bool array_, bool pointer_, bool default_,
const std::vector<Dimension> &dimensions_) const std::vector<Dimension> &dimensions_)
: _name(name_), : _name(name_),
_start(start_), _start(start_),
@ -101,6 +102,7 @@ public:
setFlag(fIsConst, const_); setFlag(fIsConst, const_);
setFlag(fIsClass, class_); setFlag(fIsClass, class_);
setFlag(fIsArray, array_); setFlag(fIsArray, array_);
setFlag(fIsPointer, pointer_);
setFlag(fHasDefault, default_); setFlag(fHasDefault, default_);
_dimensions = dimensions_; _dimensions = dimensions_;
} }
@ -259,6 +261,14 @@ public:
return getFlag(fIsArray); return getFlag(fIsArray);
} }
/**
* Is pointer or array variable.
* @return true if pointer, false otherwise
*/
bool isPointer() const {
return getFlag(fIsPointer);
}
/** /**
* Does variable have a default value. * Does variable have a default value.
* @return true if has a default falue, false if not * @return true if has a default falue, false if not
@ -451,11 +461,11 @@ public:
void addVariable(const Token *token_, const Token *start_, void addVariable(const Token *token_, const Token *start_,
const Token *end_, AccessControl access_, bool mutable_, const Token *end_, AccessControl access_, bool mutable_,
bool static_, bool const_, bool class_, const Scope *type_, bool static_, bool const_, bool class_, const Scope *type_,
const Scope *scope_, bool array_, const Scope *scope_, bool array_, bool pointer_,
const std::vector<Dimension> &dimensions_) { const std::vector<Dimension> &dimensions_) {
varlist.push_back(Variable(token_, start_, end_, varlist.size(), varlist.push_back(Variable(token_, start_, end_, varlist.size(),
access_, mutable_, static_, const_, class_, access_, mutable_, static_, const_, class_,
type_, scope_, array_, false, dimensions_)); type_, scope_, array_, pointer_, false, dimensions_));
} }
/** @brief initialize varlist */ /** @brief initialize varlist */
@ -497,9 +507,10 @@ private:
* @param vartok populated with pointer to the variable token, if found * @param vartok populated with pointer to the variable token, if found
* @param typetok populated with pointer to the type token, if found * @param typetok populated with pointer to the type token, if found
* @param isArray reference to variable to set if array is found * @param isArray reference to variable to set if array is found
* @param isPointer reference to variable to set if pointer is found
* @return true if tok points to a variable declaration, false otherwise * @return true if tok points to a variable declaration, false otherwise
*/ */
bool isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok, bool &isArray) const; bool isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok, bool &isArray, bool &isPointer) const;
bool isSimpleVariable(const Token* tok) const; bool isSimpleVariable(const Token* tok) const;
bool isArrayVariable(const Token* tok) const; bool isArrayVariable(const Token* tok) const;
bool findClosingBracket(const Token* tok, const Token*& close) const; bool findClosingBracket(const Token* tok, const Token*& close) const;

View File

@ -38,6 +38,7 @@ public:
,t(NULL) ,t(NULL)
,found(false) ,found(false)
,isArray(false) ,isArray(false)
,isPointer(false)
{} {}
virtual void reportOut(const std::string &outmsg) { virtual void reportOut(const std::string &outmsg) {
@ -51,6 +52,7 @@ private:
const Token* t; const Token* t;
bool found; bool found;
bool isArray; bool isArray;
bool isPointer;
void reset() { void reset() {
vartok = NULL; vartok = NULL;
@ -58,6 +60,7 @@ private:
t = NULL; t = NULL;
found = false; found = false;
isArray = false; isArray = false;
isPointer = false;
} }
void run() { void run() {
@ -132,209 +135,230 @@ private:
void test_isVariableDeclarationCanHandleNull() { void test_isVariableDeclarationCanHandleNull() {
reset(); reset();
bool result = si.isVariableDeclaration(NULL, vartok, typetok, isArray); bool result = si.isVariableDeclaration(NULL, vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(false, result); ASSERT_EQUALS(false, result);
ASSERT(NULL == vartok); ASSERT(NULL == vartok);
ASSERT(NULL == typetok); ASSERT(NULL == typetok);
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(false == isPointer);
} }
void test_isVariableDeclarationIdentifiesSimpleDeclaration() { void test_isVariableDeclarationIdentifiesSimpleDeclaration() {
reset(); reset();
givenACodeSampleToTokenize simpleDeclaration("int x;"); givenACodeSampleToTokenize simpleDeclaration("int x;");
bool result = si.isVariableDeclaration(simpleDeclaration.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(simpleDeclaration.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("x", vartok->str()); ASSERT_EQUALS("x", vartok->str());
ASSERT_EQUALS("int", typetok->str()); ASSERT_EQUALS("int", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(false == isPointer);
} }
void test_isVariableDeclarationIdentifiesScopedDeclaration() { void test_isVariableDeclarationIdentifiesScopedDeclaration() {
reset(); reset();
givenACodeSampleToTokenize ScopedDeclaration("::int x;"); givenACodeSampleToTokenize ScopedDeclaration("::int x;");
bool result = si.isVariableDeclaration(ScopedDeclaration.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(ScopedDeclaration.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("x", vartok->str()); ASSERT_EQUALS("x", vartok->str());
ASSERT_EQUALS("int", typetok->str()); ASSERT_EQUALS("int", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(false == isPointer);
} }
void test_isVariableDeclarationIdentifiesStdDeclaration() { void test_isVariableDeclarationIdentifiesStdDeclaration() {
reset(); reset();
givenACodeSampleToTokenize StdDeclaration("std::string x;"); givenACodeSampleToTokenize StdDeclaration("std::string x;");
bool result = si.isVariableDeclaration(StdDeclaration.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(StdDeclaration.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("x", vartok->str()); ASSERT_EQUALS("x", vartok->str());
ASSERT_EQUALS("string", typetok->str()); ASSERT_EQUALS("string", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(false == isPointer);
} }
void test_isVariableDeclarationIdentifiesScopedStdDeclaration() { void test_isVariableDeclarationIdentifiesScopedStdDeclaration() {
reset(); reset();
givenACodeSampleToTokenize StdDeclaration("::std::string x;"); givenACodeSampleToTokenize StdDeclaration("::std::string x;");
bool result = si.isVariableDeclaration(StdDeclaration.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(StdDeclaration.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("x", vartok->str()); ASSERT_EQUALS("x", vartok->str());
ASSERT_EQUALS("string", typetok->str()); ASSERT_EQUALS("string", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(false == isPointer);
} }
void test_isVariableDeclarationIdentifiesManyScopes() { void test_isVariableDeclarationIdentifiesManyScopes() {
reset(); reset();
givenACodeSampleToTokenize manyScopes("AA::BB::CC::DD::EE x;"); givenACodeSampleToTokenize manyScopes("AA::BB::CC::DD::EE x;");
bool result = si.isVariableDeclaration(manyScopes.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(manyScopes.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("x", vartok->str()); ASSERT_EQUALS("x", vartok->str());
ASSERT_EQUALS("EE", typetok->str()); ASSERT_EQUALS("EE", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(false == isPointer);
} }
void test_isVariableDeclarationIdentifiesPointers() { void test_isVariableDeclarationIdentifiesPointers() {
reset(); reset();
givenACodeSampleToTokenize pointer("int* p;"); givenACodeSampleToTokenize pointer("int* p;");
bool result = si.isVariableDeclaration(pointer.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(pointer.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("p", vartok->str()); ASSERT_EQUALS("p", vartok->str());
ASSERT_EQUALS("int", typetok->str()); ASSERT_EQUALS("int", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(true == isPointer);
} }
void test_isVariableDeclarationDoesNotIdentifyConstness() { void test_isVariableDeclarationDoesNotIdentifyConstness() {
reset(); reset();
givenACodeSampleToTokenize constness("const int* cp;"); givenACodeSampleToTokenize constness("const int* cp;");
bool result = si.isVariableDeclaration(constness.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(constness.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(false, result); ASSERT_EQUALS(false, result);
ASSERT(NULL == vartok); ASSERT(NULL == vartok);
ASSERT(NULL == typetok); ASSERT(NULL == typetok);
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(false == isPointer);
} }
void test_isVariableDeclarationIdentifiesFirstOfManyVariables() { void test_isVariableDeclarationIdentifiesFirstOfManyVariables() {
reset(); reset();
givenACodeSampleToTokenize multipleDeclaration("int first, second;"); givenACodeSampleToTokenize multipleDeclaration("int first, second;");
bool result = si.isVariableDeclaration(multipleDeclaration.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(multipleDeclaration.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("first", vartok->str()); ASSERT_EQUALS("first", vartok->str());
ASSERT_EQUALS("int", typetok->str()); ASSERT_EQUALS("int", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(false == isPointer);
} }
void test_isVariableDeclarationIdentifiesScopedPointerDeclaration() { void test_isVariableDeclarationIdentifiesScopedPointerDeclaration() {
reset(); reset();
givenACodeSampleToTokenize manyScopes("AA::BB::CC::DD::EE* p;"); givenACodeSampleToTokenize manyScopes("AA::BB::CC::DD::EE* p;");
bool result = si.isVariableDeclaration(manyScopes.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(manyScopes.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("p", vartok->str()); ASSERT_EQUALS("p", vartok->str());
ASSERT_EQUALS("EE", typetok->str()); ASSERT_EQUALS("EE", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(true == isPointer);
} }
void test_isVariableDeclarationIdentifiesDeclarationWithIndirection() { void test_isVariableDeclarationIdentifiesDeclarationWithIndirection() {
reset(); reset();
givenACodeSampleToTokenize pointerToPointer("int** pp;"); givenACodeSampleToTokenize pointerToPointer("int** pp;");
bool result = si.isVariableDeclaration(pointerToPointer.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(pointerToPointer.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("pp", vartok->str()); ASSERT_EQUALS("pp", vartok->str());
ASSERT_EQUALS("int", typetok->str()); ASSERT_EQUALS("int", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(true == isPointer);
} }
void test_isVariableDeclarationIdentifiesDeclarationWithMultipleIndirection() { void test_isVariableDeclarationIdentifiesDeclarationWithMultipleIndirection() {
reset(); reset();
givenACodeSampleToTokenize pointerToPointer("int***** p;"); givenACodeSampleToTokenize pointerToPointer("int***** p;");
bool result = si.isVariableDeclaration(pointerToPointer.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(pointerToPointer.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("p", vartok->str()); ASSERT_EQUALS("p", vartok->str());
ASSERT_EQUALS("int", typetok->str()); ASSERT_EQUALS("int", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(true == isPointer);
} }
void test_isVariableDeclarationIdentifiesArray() { void test_isVariableDeclarationIdentifiesArray() {
reset(); reset();
givenACodeSampleToTokenize array("::std::string v[3];"); givenACodeSampleToTokenize array("::std::string v[3];");
bool result = si.isVariableDeclaration(array.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(array.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("v", vartok->str()); ASSERT_EQUALS("v", vartok->str());
ASSERT_EQUALS("string", typetok->str()); ASSERT_EQUALS("string", typetok->str());
ASSERT(true == isArray); ASSERT(true == isArray);
ASSERT(false == isPointer);
} }
void test_isVariableDeclarationIdentifiesOfArrayPointers() { void test_isVariableDeclarationIdentifiesOfArrayPointers() {
reset(); reset();
givenACodeSampleToTokenize array("A *a[5];"); givenACodeSampleToTokenize array("A *a[5];");
bool result = si.isVariableDeclaration(array.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(array.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("a", vartok->str()); ASSERT_EQUALS("a", vartok->str());
ASSERT_EQUALS("A", typetok->str()); ASSERT_EQUALS("A", typetok->str());
ASSERT(true == isArray); ASSERT(true == isArray);
ASSERT(true == isPointer);
} }
void isVariableDeclarationIdentifiesTemplatedPointerVariable() { void isVariableDeclarationIdentifiesTemplatedPointerVariable() {
reset(); reset();
givenACodeSampleToTokenize var("std::set<char>* chars;"); givenACodeSampleToTokenize var("std::set<char>* chars;");
bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("chars", vartok->str()); ASSERT_EQUALS("chars", vartok->str());
ASSERT_EQUALS("set", typetok->str()); ASSERT_EQUALS("set", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(true == isPointer);
} }
void isVariableDeclarationIdentifiesTemplatedPointerToPointerVariable() { void isVariableDeclarationIdentifiesTemplatedPointerToPointerVariable() {
reset(); reset();
givenACodeSampleToTokenize var("std::deque<int>*** ints;"); givenACodeSampleToTokenize var("std::deque<int>*** ints;");
bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("ints", vartok->str()); ASSERT_EQUALS("ints", vartok->str());
ASSERT_EQUALS("deque", typetok->str()); ASSERT_EQUALS("deque", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(true == isPointer);
} }
void isVariableDeclarationIdentifiesTemplatedArrayVariable() { void isVariableDeclarationIdentifiesTemplatedArrayVariable() {
reset(); reset();
givenACodeSampleToTokenize var("std::deque<int> ints[3];"); givenACodeSampleToTokenize var("std::deque<int> ints[3];");
bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("ints", vartok->str()); ASSERT_EQUALS("ints", vartok->str());
ASSERT_EQUALS("deque", typetok->str()); ASSERT_EQUALS("deque", typetok->str());
ASSERT(true == isArray); ASSERT(true == isArray);
ASSERT(false == isPointer);
} }
void isVariableDeclarationIdentifiesTemplatedVariable() { void isVariableDeclarationIdentifiesTemplatedVariable() {
reset(); reset();
givenACodeSampleToTokenize var("std::vector<int> ints;"); givenACodeSampleToTokenize var("std::vector<int> ints;");
bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("ints", vartok->str()); ASSERT_EQUALS("ints", vartok->str());
ASSERT_EQUALS("vector", typetok->str()); ASSERT_EQUALS("vector", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(false == isPointer);
} }
void isVariableDeclarationIdentifiesTemplatedVariableIterator() { void isVariableDeclarationIdentifiesTemplatedVariableIterator() {
reset(); reset();
givenACodeSampleToTokenize var("std::list<int>::const_iterator floats;"); givenACodeSampleToTokenize var("std::list<int>::const_iterator floats;");
bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("floats", vartok->str()); ASSERT_EQUALS("floats", vartok->str());
ASSERT_EQUALS("const_iterator", typetok->str()); ASSERT_EQUALS("const_iterator", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(false == isPointer);
} }
void isVariableDeclarationIdentifiesNestedTemplateVariable() { void isVariableDeclarationIdentifiesNestedTemplateVariable() {
reset(); reset();
givenACodeSampleToTokenize var("std::deque<std::set<int> > intsets;"); givenACodeSampleToTokenize var("std::deque<std::set<int> > intsets;");
bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
ASSERT_EQUALS("intsets", vartok->str()); ASSERT_EQUALS("intsets", vartok->str());
ASSERT_EQUALS("deque", typetok->str()); ASSERT_EQUALS("deque", typetok->str());
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(false == isPointer);
} }
void isVariableDeclarationDoesNotIdentifyTemplateClass() { void isVariableDeclarationDoesNotIdentifyTemplateClass() {
reset(); reset();
givenACodeSampleToTokenize var("template <class T> class SomeClass{};"); givenACodeSampleToTokenize var("template <class T> class SomeClass{};");
bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok, isArray); bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok, isArray, isPointer);
ASSERT_EQUALS(false, result); ASSERT_EQUALS(false, result);
ASSERT(false == isArray); ASSERT(false == isArray);
ASSERT(false == isPointer);
} }
void canFindMatchingBracketsNeedsOpen() { void canFindMatchingBracketsNeedsOpen() {