Refactorization:

- Implemented consistent behaviour of Variable::typeStartToken/typeEndToken: Skip const and static on all variables.
- Simplified patterns containing "static|" or "const|" when matching typeStartToken.
This commit is contained in:
PKEuS 2012-06-08 09:05:02 -07:00
parent 69846b2a06
commit c463d97386
5 changed files with 43 additions and 13 deletions

View File

@ -306,14 +306,14 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Sym
return true; return true;
if (Token::Match(tok->tokAt(-2), "%var% ( %var% )")) { if (Token::Match(tok->tokAt(-2), "%var% ( %var% )")) {
const Variable* var = symbolDatabase->getVariableFromVarId(tok->tokAt(-2)->varId()); const Variable* var = symbolDatabase->getVariableFromVarId(tok->tokAt(-2)->varId());
if (var && !var->isPointer() && !var->isArray() && Token::Match(var->typeStartToken(), "const| std :: string !!::")) if (var && !var->isPointer() && !var->isArray() && Token::Match(var->typeStartToken(), "std :: string !!::"))
return true; return true;
} }
// streams dereference nullpointers // streams dereference nullpointers
if (Token::Match(tok->previous(), "<<|>> %var%")) { if (Token::Match(tok->previous(), "<<|>> %var%")) {
const Variable* var = symbolDatabase->getVariableFromVarId(tok->varId()); const Variable* var = symbolDatabase->getVariableFromVarId(tok->varId());
if (var && Token::Match(var->typeStartToken(), "const| char const| *")) { // Only outputing or reading to char* can cause problems if (var && var->isPointer() && var->typeStartToken()->str() == "char") { // Only outputing or reading to char* can cause problems
const Token* tok2 = tok->previous(); // Find start of statement const Token* tok2 = tok->previous(); // Find start of statement
for (; tok2; tok2 = tok2->previous()) { for (; tok2; tok2 = tok2->previous()) {
if (Token::Match(tok2->previous(), ";|{|}|:")) if (Token::Match(tok2->previous(), ";|{|}|:"))
@ -323,7 +323,7 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Sym
return true; return true;
if (tok2 && tok2->varId() != 0) { if (tok2 && tok2->varId() != 0) {
const Variable* var2 = symbolDatabase->getVariableFromVarId(tok2->varId()); const Variable* var2 = symbolDatabase->getVariableFromVarId(tok2->varId());
if (var2 && Token::Match(var2->typeStartToken(), "const| std :: istream|ifstream|istringstream|ostream|ofstream|ostringstream|stringstream|fstream|iostream")) if (var2 && Token::Match(var2->typeStartToken(), "std :: istream|ifstream|istringstream|ostream|ofstream|ostringstream|stringstream|fstream|iostream"))
return true; return true;
} }
} }
@ -338,7 +338,7 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Sym
ovarid = tok->tokAt(-2)->varId(); ovarid = tok->tokAt(-2)->varId();
if (ovarid) { if (ovarid) {
const Variable* var = symbolDatabase->getVariableFromVarId(ovarid); const Variable* var = symbolDatabase->getVariableFromVarId(ovarid);
if (var && !var->isPointer() && !var->isArray() && Token::Match(var->typeStartToken(), "const| std :: string !!::")) if (var && !var->isPointer() && !var->isArray() && Token::Match(var->typeStartToken(), "std :: string !!::"))
return true; return true;
} }
@ -1152,7 +1152,7 @@ void CheckNullPointer::nullConstantDereference()
else if (Token::Match(tok->previous(), "!!. %var% (") && (tok->previous()->str() != "::" || tok->strAt(-2) == "std")) { else if (Token::Match(tok->previous(), "!!. %var% (") && (tok->previous()->str() != "::" || tok->strAt(-2) == "std")) {
if (Token::simpleMatch(tok->tokAt(2), "0 )") && tok->varId()) { // constructor call if (Token::simpleMatch(tok->tokAt(2), "0 )") && tok->varId()) { // constructor call
const Variable* var = symbolDatabase->getVariableFromVarId(tok->varId()); const Variable* var = symbolDatabase->getVariableFromVarId(tok->varId());
if (var && !var->isPointer() && !var->isArray() && Token::Match(var->typeStartToken(), "const| std :: string !!::")) if (var && !var->isPointer() && !var->isArray() && Token::Match(var->typeStartToken(), "std :: string !!::"))
nullPointerError(tok); nullPointerError(tok);
} else { // function call } else { // function call
std::list<const Token *> var; std::list<const Token *> var;
@ -1178,7 +1178,7 @@ void CheckNullPointer::nullConstantDereference()
nullPointerError(tok); nullPointerError(tok);
if (tok2 && tok2->varId() != 0) { if (tok2 && tok2->varId() != 0) {
const Variable* var = symbolDatabase->getVariableFromVarId(tok2->varId()); const Variable* var = symbolDatabase->getVariableFromVarId(tok2->varId());
if (var && Token::Match(var->typeStartToken(), "const| std :: istream|ifstream|istringstream|stringstream|fstream|iostream")) if (var && Token::Match(var->typeStartToken(), "std :: istream|ifstream|istringstream|stringstream|fstream|iostream"))
nullPointerError(tok); nullPointerError(tok);
} }
} }
@ -1192,7 +1192,7 @@ void CheckNullPointer::nullConstantDereference()
ovarid = tok->varId(); ovarid = tok->varId();
if (ovarid) { if (ovarid) {
const Variable* var = symbolDatabase->getVariableFromVarId(ovarid); const Variable* var = symbolDatabase->getVariableFromVarId(ovarid);
if (var && !var->isPointer() && !var->isArray() && Token::Match(var->typeStartToken(), "const| std :: string !!::")) if (var && !var->isPointer() && !var->isArray() && Token::Match(var->typeStartToken(), "std :: string !!::"))
nullPointerError(tok); nullPointerError(tok);
} }
} }

View File

@ -1719,7 +1719,7 @@ void CheckOther::checkConstantFunctionParameter()
if (!var || !var->isArgument() || !var->isClass() || !var->isConst() || var->isPointer() || var->isArray() || var->isReference()) if (!var || !var->isArgument() || !var->isClass() || !var->isConst() || var->isPointer() || var->isArray() || var->isReference())
continue; continue;
const Token* tok = var->typeStartToken()->next(); const Token* const tok = var->typeStartToken();
// TODO: False negatives. This pattern only checks for string. // TODO: False negatives. This pattern only checks for string.
// Investigate if there are other classes in the std // Investigate if there are other classes in the std
// namespace and add them to the pattern. There are // namespace and add them to the pattern. There are
@ -1748,7 +1748,7 @@ void CheckOther::passedByValueError(const Token *tok, const std::string &parname
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static bool isChar(const Variable* var) static bool isChar(const Variable* var)
{ {
return(var && !var->isPointer() && !var->isArray() && Token::Match(var->typeStartToken(), "static| const| char")); return(var && !var->isPointer() && !var->isArray() && var->typeStartToken()->str() == "char");
} }
static bool isSignedChar(const Variable* var) static bool isSignedChar(const Variable* var)
@ -1788,13 +1788,13 @@ void CheckOther::checkCharVariable()
// is the result stored in a short|int|long? // is the result stored in a short|int|long?
const Variable *var = symbolDatabase->getVariableFromVarId(tok->next()->varId()); const Variable *var = symbolDatabase->getVariableFromVarId(tok->next()->varId());
if (var && Token::Match(var->typeStartToken(), "static| const| short|int|long") && !var->isPointer() && !var->isArray()) if (var && Token::Match(var->typeStartToken(), "short|int|long") && !var->isPointer() && !var->isArray())
charBitOpError(tok->tokAt(4)); // This is an error.. charBitOpError(tok->tokAt(4)); // This is an error..
} }
else if (Token::Match(tok, "[;{}] %var% = %any% [&^|] ( * %var% ) ;")) { else if (Token::Match(tok, "[;{}] %var% = %any% [&^|] ( * %var% ) ;")) {
const Variable* var = symbolDatabase->getVariableFromVarId(tok->tokAt(7)->varId()); const Variable* var = symbolDatabase->getVariableFromVarId(tok->tokAt(7)->varId());
if (!var || !var->isPointer() || !Token::Match(var->typeStartToken(), "static| const| char")) if (!var || !var->isPointer() || var->typeStartToken()->str() != "char")
continue; continue;
// it's ok with a bitwise and where the other operand is 0xff or less.. // 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))) if (tok->strAt(4) == "&" && tok->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok->strAt(3)))
@ -1802,7 +1802,7 @@ void CheckOther::checkCharVariable()
// is the result stored in a short|int|long? // is the result stored in a short|int|long?
var = symbolDatabase->getVariableFromVarId(tok->next()->varId()); var = symbolDatabase->getVariableFromVarId(tok->next()->varId());
if (var && Token::Match(var->typeStartToken(), "static| const| short|int|long") && !var->isPointer() && !var->isArray()) if (var && Token::Match(var->typeStartToken(), "short|int|long") && !var->isPointer() && !var->isArray())
charBitOpError(tok->tokAt(4)); // This is an error.. charBitOpError(tok->tokAt(4)); // This is an error..
} }
} }

View File

@ -65,7 +65,7 @@ void CheckPostfixOperator::postfixOperator()
if (result && tok->previous()->varId()) { if (result && tok->previous()->varId()) {
const Variable *var = symbolDatabase->getVariableFromVarId(tok->previous()->varId()); const Variable *var = symbolDatabase->getVariableFromVarId(tok->previous()->varId());
if (!var || !Token::Match(var->typeEndToken(), "%type%")) if (!var || var->isPointer() || var->isArray() || var->isReference())
continue; continue;
const Token *decltok = var->nameToken(); const Token *decltok = var->nameToken();

View File

@ -858,6 +858,11 @@ void Variable::evaluate()
tok = tok->next(); tok = tok->next();
} }
while (_start && _start->next() && (_start->str() == "static" || _start->str() == "const"))
_start = _start->next();
while (_end && _end->previous() && _end->str() == "const")
_end = _end->previous();
if (_name) if (_name)
setFlag(fIsArray, arrayDimensions(_dimensions, _name->next())); setFlag(fIsArray, arrayDimensions(_dimensions, _name->next()));
if (_start) if (_start)

View File

@ -108,6 +108,8 @@ private:
TEST_CASE(hasGlobalVariables2); TEST_CASE(hasGlobalVariables2);
TEST_CASE(hasGlobalVariables3); TEST_CASE(hasGlobalVariables3);
TEST_CASE(checkTypeStartEndToken);
TEST_CASE(functionArgs1); TEST_CASE(functionArgs1);
TEST_CASE(functionArgs2); TEST_CASE(functionArgs2);
TEST_CASE(functionArgs3); TEST_CASE(functionArgs3);
@ -746,6 +748,29 @@ private:
} }
} }
void checkTypeStartEndToken() {
GET_SYMBOL_DB("static std::string i;\n"
"static const std::string j;\n"
"const std::string* k;\n"
"const char m[];\n"
"void f(const char* const l;) {}");
ASSERT(db && db->getVariableListSize() == 6 && db->getVariableFromVarId(1) && db->getVariableFromVarId(2) && db->getVariableFromVarId(3) && db->getVariableFromVarId(4) && db->getVariableFromVarId(5));
if (db && db->getVariableFromVarId(1) && db->getVariableFromVarId(2) && db->getVariableFromVarId(3) && db->getVariableFromVarId(4) && db->getVariableFromVarId(5)) {
ASSERT_EQUALS("std", db->getVariableFromVarId(1)->typeStartToken()->str());
ASSERT_EQUALS("std", db->getVariableFromVarId(2)->typeStartToken()->str());
ASSERT_EQUALS("std", db->getVariableFromVarId(3)->typeStartToken()->str());
ASSERT_EQUALS("char", db->getVariableFromVarId(4)->typeStartToken()->str());
ASSERT_EQUALS("char", db->getVariableFromVarId(5)->typeStartToken()->str());
ASSERT_EQUALS("string", db->getVariableFromVarId(1)->typeEndToken()->str());
ASSERT_EQUALS("string", db->getVariableFromVarId(2)->typeEndToken()->str());
ASSERT_EQUALS("*", db->getVariableFromVarId(3)->typeEndToken()->str());
ASSERT_EQUALS("char", db->getVariableFromVarId(4)->typeEndToken()->str());
ASSERT_EQUALS("*", db->getVariableFromVarId(5)->typeEndToken()->str());
}
}
void check(const char code[], bool debug = true) { void check(const char code[], bool debug = true) {
// Clear the error log // Clear the error log
errout.str(""); errout.str("");