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:
parent
f09a5b408b
commit
f306246c7f
|
@ -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 + " ]");
|
||||
|
||||
// count { and } for tok2
|
||||
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;
|
||||
}
|
||||
|
||||
for (const Token* tok2 = tok; tok2 && tok2 != tok->link(); tok2 = tok2->next()) {
|
||||
// TODO: try to reduce false negatives. This is just a quick fix
|
||||
// for TestBufferOverrun::array_index_for_question
|
||||
if (tok2->str() == "?")
|
||||
|
@ -713,31 +699,22 @@ void CheckBufferOverrun::checkFunctionCall(const Token *tok, const ArrayInfo &ar
|
|||
}
|
||||
callstack.push_back(tok);
|
||||
|
||||
const Token *tok2 = tok->tokAt(2);
|
||||
// 1st parameter..
|
||||
if (Token::Match(tok->tokAt(2), "%varid% ,|)", arrayInfo.varid()))
|
||||
if (Token::Match(tok2, "%varid% ,|)", arrayInfo.varid()))
|
||||
checkFunctionParameter(*tok, 1, arrayInfo, callstack);
|
||||
else if (Token::Match(tok->tokAt(2), "%varid% + %num% ,|)", arrayInfo.varid())) {
|
||||
const ArrayInfo ai(arrayInfo.limit(MathLib::toLongNumber(tok->strAt(4))));
|
||||
else if (Token::Match(tok2, "%varid% + %num% ,|)", arrayInfo.varid())) {
|
||||
const ArrayInfo ai(arrayInfo.limit(MathLib::toLongNumber(tok2->strAt(2))));
|
||||
checkFunctionParameter(*tok, 1, ai, callstack);
|
||||
}
|
||||
|
||||
// goto 2nd parameter and check it..
|
||||
for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) {
|
||||
if (tok2->str() == "(") {
|
||||
tok2 = tok2->link();
|
||||
continue;
|
||||
}
|
||||
if (tok2->str() == ";" || tok2->str() == ")")
|
||||
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;
|
||||
}
|
||||
tok2 = tok2->nextArgument();
|
||||
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(2))));
|
||||
checkFunctionParameter(*tok, 2, ai, callstack);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
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));
|
||||
if (index > size && _settings->isEnabled("portability"))
|
||||
pointerOutOfBoundsError(tok->next(), "buffer");
|
||||
|
@ -1020,7 +997,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -288,31 +288,6 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown)
|
|||
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()
|
||||
{
|
||||
const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||
|
@ -327,12 +302,10 @@ void CheckNullPointer::nullPointerAfterLoop()
|
|||
continue;
|
||||
|
||||
// Get variable id for the loop variable
|
||||
const unsigned int varid(tok->tokAt(2)->varId());
|
||||
if (varid == 0)
|
||||
continue;
|
||||
const Variable* var(symbolDatabase->getVariableFromVarId(tok->tokAt(2)->varId()));
|
||||
|
||||
// Is variable a pointer?
|
||||
if (!isPointer(varid))
|
||||
if (!var || !var->isPointer())
|
||||
continue;
|
||||
|
||||
// Get variable name for the loop variable
|
||||
|
@ -371,7 +344,7 @@ void CheckNullPointer::nullPointerAfterLoop()
|
|||
break;
|
||||
|
||||
// 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?
|
||||
bool unknown = _settings->inconclusive;
|
||||
|
||||
|
@ -445,8 +418,9 @@ void CheckNullPointer::nullPointerLinkedList()
|
|||
++indentlevel4;
|
||||
else if (tok4->str() == "}") {
|
||||
if (indentlevel4 <= 1) {
|
||||
const Variable* var = symbolDatabase->getVariableFromVarId(varid);
|
||||
// Is this variable a pointer?
|
||||
if (isPointer(varid))
|
||||
if (var && var->isPointer())
|
||||
nullPointerError(tok1, varname, tok3->linenr());
|
||||
|
||||
break;
|
||||
|
@ -580,7 +554,9 @@ void CheckNullPointer::nullPointerStructByDeRefAndChec()
|
|||
// is pointer local?
|
||||
bool isLocal = false;
|
||||
const Variable * var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(tok1->varId());
|
||||
if (var && (var->isLocal() || var->isArgument()))
|
||||
if (!var)
|
||||
continue;
|
||||
if (var->isLocal() || var->isArgument())
|
||||
isLocal = true;
|
||||
|
||||
// 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 || .."
|
||||
else if (Token::Match(tok2, "if ( !| %varid% )|&&", varid1)) {
|
||||
// Is this variable a pointer?
|
||||
if (isPointer(varid1))
|
||||
if (var->isPointer())
|
||||
nullPointerError(tok1, varname, tok2->linenr(), inconclusive);
|
||||
break;
|
||||
}
|
||||
|
@ -674,13 +650,9 @@ void CheckNullPointer::nullPointerByDeRefAndChec()
|
|||
// Name of pointer
|
||||
const std::string varname(vartok->str());
|
||||
|
||||
const Variable* var = symbolDatabase->getVariableFromVarId(varid);
|
||||
// Check that variable is a pointer..
|
||||
if (!isPointer(varid))
|
||||
continue;
|
||||
|
||||
// Token where pointer is declared
|
||||
const Variable *var = symbolDatabase->getVariableFromVarId(varid);
|
||||
if (!var)
|
||||
if (!var || !var->isPointer())
|
||||
continue;
|
||||
|
||||
const Token * const decltok = var->nameToken();
|
||||
|
@ -785,15 +757,8 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
|
|||
{
|
||||
// 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()) {
|
||||
if (Token::Match(tok, "* %var% [;,)=]"))
|
||||
pointerVariables.insert(tok->next()->varId());
|
||||
|
||||
else if (Token::simpleMatch(tok, "if (")) {
|
||||
if (Token::simpleMatch(tok, "if (")) {
|
||||
// TODO: investigate false negatives:
|
||||
// - handle "while"?
|
||||
// - if there are logical operators
|
||||
|
@ -828,8 +793,9 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
|
|||
|
||||
const unsigned int linenr = vartok->linenr();
|
||||
|
||||
// Check if variable is a pointer. TODO: Use isPointer?
|
||||
if (pointerVariables.find(varid) == pointerVariables.end())
|
||||
const Variable* var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(varid);
|
||||
// Check if variable is a pointer
|
||||
if (!var || !var->isPointer())
|
||||
continue;
|
||||
|
||||
if (Token::Match(vartok->next(), "&& ( %varid% =", varid))
|
||||
|
@ -906,9 +872,9 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
|
|||
|
||||
// function call, check if pointer is dereferenced
|
||||
if (Token::Match(tok2, "%var% (")) {
|
||||
std::list<const Token *> var;
|
||||
parseFunctionCall(*tok2, var, 0);
|
||||
for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it) {
|
||||
std::list<const Token *> vars;
|
||||
parseFunctionCall(*tok2, vars, 0);
|
||||
for (std::list<const Token *>::const_iterator it = vars.begin(); it != vars.end(); ++it) {
|
||||
if (Token::Match(*it, "%varid% [,)]", varid)) {
|
||||
nullPointerError(*it, pointerName, linenr, inconclusive);
|
||||
break;
|
||||
|
@ -932,8 +898,6 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
|
|||
}
|
||||
|
||||
// init function (global variables)
|
||||
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||
const Variable *var = symbolDatabase->getVariableFromVarId(varid);
|
||||
if (!var || !(var->isLocal() || var->isArgument()))
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -120,12 +120,6 @@ public:
|
|||
|
||||
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().
|
||||
* Locate insufficient null-pointer handling after loop
|
||||
|
|
|
@ -750,24 +750,25 @@ void CheckOther::coutCerrMisusageError(const Token* tok, const std::string& stre
|
|||
//
|
||||
// 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()
|
||||
{
|
||||
if (!_settings->isEnabled("style"))
|
||||
return;
|
||||
|
||||
// POD variables..
|
||||
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 SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||
|
||||
const char selfAssignmentPattern[] = "%var% = %var% ;|=|)";
|
||||
const Token *tok = Token::findmatch(_tokenizer->tokens(), selfAssignmentPattern);
|
||||
while (tok) {
|
||||
if (Token::Match(tok->previous(), "[;{}]") &&
|
||||
tok->varId() && tok->varId() == tok->tokAt(2)->varId() &&
|
||||
pod.find(tok->varId()) != pod.end()) {
|
||||
isPOD(symbolDatabase->getVariableFromVarId(tok->varId()))) {
|
||||
bool err = true;
|
||||
|
||||
// no false positive for 'x = x ? x : 1;'
|
||||
|
@ -1512,29 +1513,26 @@ void CheckOther::unreachableCodeError(const Token *tok)
|
|||
//---------------------------------------------------------------------------
|
||||
// Check for unsigned divisions
|
||||
//---------------------------------------------------------------------------
|
||||
static bool isUnsigned(const Variable* var)
|
||||
{
|
||||
return(var && var->typeStartToken()->isUnsigned() && var->typeStartToken() == var->typeEndToken());
|
||||
}
|
||||
|
||||
void CheckOther::checkUnsignedDivision()
|
||||
{
|
||||
// Check for "ivar / uvar" and "uvar / ivar"
|
||||
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());
|
||||
}
|
||||
const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||
|
||||
else if (!Token::Match(tok, "[).]") && Token::Match(tok->next(), "%var% / %num%")) {
|
||||
if (tok->strAt(3)[0] == '-') {
|
||||
if (uvars.find(tok->next()->varId()) != uvars.end()) {
|
||||
udivError(tok->next());
|
||||
}
|
||||
// Check for "ivar / uvar" and "uvar / ivar"
|
||||
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
|
||||
if (!Token::Match(tok, "[).]") && Token::Match(tok->next(), "%var% / %num%")) {
|
||||
if (tok->strAt(3)[0] == '-' && isUnsigned(symbolDatabase->getVariableFromVarId(tok->next()->varId()))) {
|
||||
udivError(tok->next());
|
||||
}
|
||||
}
|
||||
|
||||
else if (Token::Match(tok, "(|[|=|%op% %num% / %var%")) {
|
||||
if (tok->strAt(1)[0] == '-') {
|
||||
if (uvars.find(tok->tokAt(3)->varId()) != uvars.end()) {
|
||||
udivError(tok->next());
|
||||
}
|
||||
if (tok->strAt(1)[0] == '-' && isUnsigned(symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId()))) {
|
||||
udivError(tok->next());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1805,6 +1803,11 @@ void CheckOther::passedByValueError(const Token *tok, const std::string &parname
|
|||
//---------------------------------------------------------------------------
|
||||
// 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()
|
||||
{
|
||||
if (!_settings->isEnabled("style"))
|
||||
|
@ -1813,87 +1816,50 @@ void CheckOther::checkCharVariable()
|
|||
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||
|
||||
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
|
||||
// Declaring the variable..
|
||||
if (Token::Match(tok, "[{};(,] const| char *| const| %var% [;=,)]") ||
|
||||
Token::Match(tok, "[{};(,] const| char %var% [")) {
|
||||
// goto 'char' token
|
||||
tok = tok->next();
|
||||
if (tok->str() == "const")
|
||||
tok = tok->next();
|
||||
if ((tok->str() != ".") && Token::Match(tok->next(), "%var% [ %var% ]")) {
|
||||
const Variable* var = symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId());
|
||||
if (isSignedChar(var))
|
||||
charArrayIndexError(tok->next());
|
||||
}
|
||||
|
||||
// Check for unsigned char
|
||||
if (tok->isUnsigned())
|
||||
else if (Token::Match(tok, "[;{}] %var% = %any% [&|] %any% ;")) {
|
||||
// is a char variable used in the calculation?
|
||||
if (!isSignedChar(symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId())) &&
|
||||
!isSignedChar(symbolDatabase->getVariableFromVarId(tok->tokAt(5)->varId())))
|
||||
continue;
|
||||
|
||||
// Set tok to point to the variable name
|
||||
tok = tok->next();
|
||||
const bool isPointer(tok->str() == "*" || tok->strAt(1) == "[");
|
||||
if (tok->str() == "*")
|
||||
tok = tok->next();
|
||||
if (tok->str() == "const")
|
||||
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;
|
||||
}
|
||||
// it's ok with a bitwise and where the other operand is 0xff or less..
|
||||
if (tok->strAt(4) == "&") {
|
||||
if (tok->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok->strAt(3)))
|
||||
continue;
|
||||
if (tok->tokAt(5)->isNumber() && MathLib::isGreater("0x100", tok->strAt(5)))
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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
|
||||
//---------------------------------------------------------------------------
|
||||
static bool isChar(const Variable* var)
|
||||
{
|
||||
return(var && var->nameToken()->previous()->str() == "char" && var->nameToken()->next()->str() != "[");
|
||||
}
|
||||
|
||||
void CheckOther::strPlusChar()
|
||||
{
|
||||
// Don't use this check for Java and C# programs..
|
||||
|
@ -1980,25 +1951,17 @@ void CheckOther::strPlusChar()
|
|||
return;
|
||||
}
|
||||
|
||||
std::set<unsigned int> charVars;
|
||||
const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||
|
||||
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
|
||||
// Declaring char variable..
|
||||
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%")) {
|
||||
if (Token::Match(tok, "[=(] %str% + %any%")) {
|
||||
// char constant..
|
||||
if (tok->strAt(3)[0] == '\'')
|
||||
strPlusCharError(tok->next());
|
||||
|
||||
// char variable..
|
||||
unsigned int varid = tok->tokAt(3)->varId();
|
||||
if (varid > 0 && charVars.find(varid) != charVars.end())
|
||||
if (isChar(symbolDatabase->getVariableFromVarId(varid)))
|
||||
strPlusCharError(tok->next());
|
||||
}
|
||||
}
|
||||
|
@ -2102,7 +2065,7 @@ void CheckOther::checkCCTypeFunctions()
|
|||
{
|
||||
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
|
||||
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))) {
|
||||
cctypefunctionCallError(tok, tok->str(), tok->tokAt(2)->str());
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
const Variable* var = symbolDatabase->getVariableFromVarId(varid);
|
||||
|
@ -1023,13 +1017,16 @@ void CheckStl::string_c_str()
|
|||
// Invalid usage..
|
||||
if (Token::Match(tok, "throw %var% . c_str ( ) ;") && isLocal(symbolDatabase, tok->next()->varId())) {
|
||||
string_c_strThrowError(tok);
|
||||
} else if (Token::Match(tok, "[;{}] %var% = %var% . str ( ) . c_str ( ) ;") && isPointer(symbolDatabase, tok->next()->varId())) {
|
||||
string_c_strError(tok);
|
||||
} else if (Token::Match(tok, "[;{}] %var% = %var% . str ( ) . c_str ( ) ;")) {
|
||||
const Variable* var = symbolDatabase->getVariableFromVarId(tok->next()->varId());
|
||||
if (var && var->isPointer())
|
||||
string_c_strError(tok);
|
||||
} else if (Token::Match(tok, "[;{}] %var% = %var% (") &&
|
||||
Token::simpleMatch(tok->linkAt(4), ") . c_str ( ) ;") &&
|
||||
isPointer(symbolDatabase, tok->next()->varId()) &&
|
||||
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*
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
#include "errorlogger.h"
|
||||
#include "check.h"
|
||||
|
||||
#include <locale>
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
@ -111,19 +109,26 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
|
||||
// unnamed struct and 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));
|
||||
|
||||
Scope *new_scope = &scopeList.back();
|
||||
|
||||
std::vector<Dimension> dimensions;
|
||||
|
||||
bool isPointer = false;
|
||||
bool isArray = false;
|
||||
|
||||
if (tok->next()->link()->strAt(2) == "[")
|
||||
isArray = arrayDimensions(dimensions, tok->next()->link()->tokAt(2));
|
||||
const Token* varNameTok = tok->next()->link()->next();
|
||||
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();
|
||||
|
||||
|
@ -1210,20 +1215,14 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Function
|
|||
// check for non-empty argument list "( ... )"
|
||||
if (arg->link() != arg->next() && !Token::simpleMatch(arg, "( void )")) {
|
||||
unsigned int count = 0;
|
||||
const Token *startTok;
|
||||
const Token *endTok;
|
||||
const Token *nameTok;
|
||||
bool isConstVar;
|
||||
bool isArrayVar;
|
||||
bool hasDefault;
|
||||
const Token *tok = arg->next();
|
||||
for (;;) {
|
||||
startTok = tok;
|
||||
endTok = NULL;
|
||||
nameTok = NULL;
|
||||
isConstVar = bool(tok->str() == "const");
|
||||
isArrayVar = false;
|
||||
hasDefault = false;
|
||||
|
||||
for (const Token* tok = arg->next(); tok; tok = tok->next()) {
|
||||
const Token* startTok = tok;
|
||||
const Token* endTok = NULL;
|
||||
const Token* nameTok = NULL;
|
||||
bool isConstVar = bool(tok->str() == "const");
|
||||
bool isArrayVar = false;
|
||||
bool hasDefault = false;
|
||||
std::vector<Dimension> dimensions;
|
||||
|
||||
while (tok->str() != "," && tok->str() != ")" && tok->str() != "=") {
|
||||
|
@ -1282,6 +1281,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Function
|
|||
argType = symbolDatabase->findVariableType(scope, typeTok);
|
||||
|
||||
bool isClassVar = startTok == endTok && !startTok->isStandardType();
|
||||
bool isPointerVar = nameTok->strAt(-1) == "*" || nameTok->strAt(-2) == "*";
|
||||
|
||||
// skip default values
|
||||
if (tok->str() == "=") {
|
||||
|
@ -1291,12 +1291,10 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Function
|
|||
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() == ")")
|
||||
break;
|
||||
|
||||
tok = tok->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1359,8 +1357,7 @@ Scope::Scope(SymbolDatabase *check_, const Token *classDef_, Scope *nestedIn_) :
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Scope::hasDefaultConstructor() const
|
||||
bool Scope::hasDefaultConstructor() const
|
||||
{
|
||||
if (numConstructors) {
|
||||
std::list<Function>::const_iterator func;
|
||||
|
@ -1548,10 +1545,12 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess)
|
|||
}
|
||||
|
||||
bool isArray = false;
|
||||
bool isPointer = false;
|
||||
std::vector<Dimension> dimensions;
|
||||
|
||||
if (tok && isVariableDeclaration(tok, vartok, typetok, isArray)) {
|
||||
isClass = (!typetok->isStandardType() && vartok->previous()->str() != "*");
|
||||
if (tok && isVariableDeclaration(tok, vartok, typetok, isArray, isPointer)) {
|
||||
isPointer = vartok->previous()->str() == "*" || vartok->strAt(-2) == "*";
|
||||
isClass = (!typetok->isStandardType() && !isPointer && vartok->previous()->str() != "&");
|
||||
if (isArray) {
|
||||
isArray = check->arrayDimensions(dimensions, vartok->next());
|
||||
tok = vartok->next();
|
||||
|
@ -1571,7 +1570,7 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess)
|
|||
if (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;
|
||||
|
@ -1607,14 +1606,14 @@ inline const Token* skipPointers(const Token* tok)
|
|||
{
|
||||
const Token* ret = tok;
|
||||
|
||||
while (Token::simpleMatch(ret, "*")) {
|
||||
while (Token::Match(ret, "*|&")) {
|
||||
ret = ret->next();
|
||||
}
|
||||
|
||||
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* localVarTok = NULL;
|
||||
|
@ -1649,6 +1648,7 @@ bool Scope::isVariableDeclaration(const Token* tok, const Token*& vartok, const
|
|||
typetok = localTypeTok;
|
||||
isArray = false;
|
||||
}
|
||||
isPointer = vartok && (vartok->strAt(-1) == "*" || vartok->strAt(-2) == "*");
|
||||
|
||||
return NULL != vartok;
|
||||
}
|
||||
|
|
|
@ -61,7 +61,8 @@ class Variable {
|
|||
fIsConst = (1 << 2), /** @brief const variable */
|
||||
fIsClass = (1 << 3), /** @brief user defined type */
|
||||
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_,
|
||||
std::size_t index_, AccessControl access_, bool mutable_,
|
||||
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_)
|
||||
: _name(name_),
|
||||
_start(start_),
|
||||
|
@ -101,6 +102,7 @@ public:
|
|||
setFlag(fIsConst, const_);
|
||||
setFlag(fIsClass, class_);
|
||||
setFlag(fIsArray, array_);
|
||||
setFlag(fIsPointer, pointer_);
|
||||
setFlag(fHasDefault, default_);
|
||||
_dimensions = dimensions_;
|
||||
}
|
||||
|
@ -259,6 +261,14 @@ public:
|
|||
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.
|
||||
* @return true if has a default falue, false if not
|
||||
|
@ -451,11 +461,11 @@ public:
|
|||
void addVariable(const Token *token_, const Token *start_,
|
||||
const Token *end_, AccessControl access_, bool mutable_,
|
||||
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_) {
|
||||
varlist.push_back(Variable(token_, start_, end_, varlist.size(),
|
||||
access_, mutable_, static_, const_, class_,
|
||||
type_, scope_, array_, false, dimensions_));
|
||||
type_, scope_, array_, pointer_, false, dimensions_));
|
||||
}
|
||||
|
||||
/** @brief initialize varlist */
|
||||
|
@ -497,9 +507,10 @@ private:
|
|||
* @param vartok populated with pointer to the variable 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 isPointer reference to variable to set if pointer is found
|
||||
* @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 isArrayVariable(const Token* tok) const;
|
||||
bool findClosingBracket(const Token* tok, const Token*& close) const;
|
||||
|
|
|
@ -38,6 +38,7 @@ public:
|
|||
,t(NULL)
|
||||
,found(false)
|
||||
,isArray(false)
|
||||
,isPointer(false)
|
||||
{}
|
||||
|
||||
virtual void reportOut(const std::string &outmsg) {
|
||||
|
@ -51,6 +52,7 @@ private:
|
|||
const Token* t;
|
||||
bool found;
|
||||
bool isArray;
|
||||
bool isPointer;
|
||||
|
||||
void reset() {
|
||||
vartok = NULL;
|
||||
|
@ -58,6 +60,7 @@ private:
|
|||
t = NULL;
|
||||
found = false;
|
||||
isArray = false;
|
||||
isPointer = false;
|
||||
}
|
||||
|
||||
void run() {
|
||||
|
@ -132,209 +135,230 @@ private:
|
|||
|
||||
void test_isVariableDeclarationCanHandleNull() {
|
||||
reset();
|
||||
bool result = si.isVariableDeclaration(NULL, vartok, typetok, isArray);
|
||||
bool result = si.isVariableDeclaration(NULL, vartok, typetok, isArray, isPointer);
|
||||
ASSERT_EQUALS(false, result);
|
||||
ASSERT(NULL == vartok);
|
||||
ASSERT(NULL == typetok);
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(false == isPointer);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesSimpleDeclaration() {
|
||||
reset();
|
||||
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("x", vartok->str());
|
||||
ASSERT_EQUALS("int", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(false == isPointer);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesScopedDeclaration() {
|
||||
reset();
|
||||
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("x", vartok->str());
|
||||
ASSERT_EQUALS("int", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(false == isPointer);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesStdDeclaration() {
|
||||
reset();
|
||||
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("x", vartok->str());
|
||||
ASSERT_EQUALS("string", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(false == isPointer);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesScopedStdDeclaration() {
|
||||
reset();
|
||||
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("x", vartok->str());
|
||||
ASSERT_EQUALS("string", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(false == isPointer);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesManyScopes() {
|
||||
reset();
|
||||
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("x", vartok->str());
|
||||
ASSERT_EQUALS("EE", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(false == isPointer);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesPointers() {
|
||||
reset();
|
||||
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("p", vartok->str());
|
||||
ASSERT_EQUALS("int", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(true == isPointer);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationDoesNotIdentifyConstness() {
|
||||
reset();
|
||||
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(NULL == vartok);
|
||||
ASSERT(NULL == typetok);
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(false == isPointer);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesFirstOfManyVariables() {
|
||||
reset();
|
||||
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("first", vartok->str());
|
||||
ASSERT_EQUALS("int", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(false == isPointer);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesScopedPointerDeclaration() {
|
||||
reset();
|
||||
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("p", vartok->str());
|
||||
ASSERT_EQUALS("EE", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(true == isPointer);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesDeclarationWithIndirection() {
|
||||
reset();
|
||||
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("pp", vartok->str());
|
||||
ASSERT_EQUALS("int", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(true == isPointer);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesDeclarationWithMultipleIndirection() {
|
||||
reset();
|
||||
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("p", vartok->str());
|
||||
ASSERT_EQUALS("int", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(true == isPointer);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesArray() {
|
||||
reset();
|
||||
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("v", vartok->str());
|
||||
ASSERT_EQUALS("string", typetok->str());
|
||||
ASSERT(true == isArray);
|
||||
ASSERT(false == isPointer);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesOfArrayPointers() {
|
||||
reset();
|
||||
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("a", vartok->str());
|
||||
ASSERT_EQUALS("A", typetok->str());
|
||||
ASSERT(true == isArray);
|
||||
ASSERT(true == isPointer);
|
||||
}
|
||||
|
||||
void isVariableDeclarationIdentifiesTemplatedPointerVariable() {
|
||||
reset();
|
||||
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("chars", vartok->str());
|
||||
ASSERT_EQUALS("set", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(true == isPointer);
|
||||
}
|
||||
|
||||
void isVariableDeclarationIdentifiesTemplatedPointerToPointerVariable() {
|
||||
reset();
|
||||
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("ints", vartok->str());
|
||||
ASSERT_EQUALS("deque", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(true == isPointer);
|
||||
}
|
||||
|
||||
void isVariableDeclarationIdentifiesTemplatedArrayVariable() {
|
||||
reset();
|
||||
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("ints", vartok->str());
|
||||
ASSERT_EQUALS("deque", typetok->str());
|
||||
ASSERT(true == isArray);
|
||||
ASSERT(false == isPointer);
|
||||
}
|
||||
|
||||
void isVariableDeclarationIdentifiesTemplatedVariable() {
|
||||
reset();
|
||||
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("ints", vartok->str());
|
||||
ASSERT_EQUALS("vector", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(false == isPointer);
|
||||
}
|
||||
|
||||
void isVariableDeclarationIdentifiesTemplatedVariableIterator() {
|
||||
reset();
|
||||
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("floats", vartok->str());
|
||||
ASSERT_EQUALS("const_iterator", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(false == isPointer);
|
||||
}
|
||||
|
||||
void isVariableDeclarationIdentifiesNestedTemplateVariable() {
|
||||
reset();
|
||||
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("intsets", vartok->str());
|
||||
ASSERT_EQUALS("deque", typetok->str());
|
||||
ASSERT(false == isArray);
|
||||
ASSERT(false == isPointer);
|
||||
}
|
||||
|
||||
void isVariableDeclarationDoesNotIdentifyTemplateClass() {
|
||||
reset();
|
||||
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(false == isArray);
|
||||
ASSERT(false == isPointer);
|
||||
}
|
||||
|
||||
void canFindMatchingBracketsNeedsOpen() {
|
||||
|
|
Loading…
Reference in New Issue