Refactor checks using Variable::isStlType()

This commit is contained in:
Lucas Manuel Rodriguez 2014-01-30 01:26:48 -03:00
parent 8db904692a
commit ad0269eeeb
8 changed files with 61 additions and 21 deletions

View File

@ -1022,7 +1022,7 @@ void CheckClass::checkMemsetType(const Scope *start, const Token *tok, const Sco
const Token *tok1 = var->typeStartToken(); const Token *tok1 = var->typeStartToken();
// check for std:: type // check for std:: type
if (Token::simpleMatch(tok1, "std ::")) if (var->isStlType())
if (allocation) if (allocation)
mallocOnClassError(tok, tok->str(), type->classDef, "'std::" + tok1->strAt(2) + "'"); mallocOnClassError(tok, tok->str(), type->classDef, "'std::" + tok1->strAt(2) + "'");
else else
@ -1730,7 +1730,7 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool&
const Variable *var = end->variable(); const Variable *var = end->variable();
if (var && Token::simpleMatch(var->typeStartToken(), "std :: map")) // operator[] changes a map if (var && Token::simpleMatch(var->typeStartToken(), "std :: map")) // operator[] changes a map
return (false); return false;
} }
if (!jumpBackToken) if (!jumpBackToken)
jumpBackToken = end->next(); // Check inside the [] brackets jumpBackToken = end->next(); // Check inside the [] brackets
@ -1744,8 +1744,8 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool&
if (end->strAt(1) == "(") { if (end->strAt(1) == "(") {
const Variable *var = lastVarTok->variable(); const Variable *var = lastVarTok->variable();
if (!var) if (!var)
return (false); return false;
if (Token::simpleMatch(var->typeStartToken(), "std ::") // assume all std::*::size() and std::*::empty() are const if (var->isStlType() // assume all std::*::size() and std::*::empty() are const
&& (Token::Match(end, "size|empty|cend|crend|cbegin|crbegin|max_size|length|count|capacity|get_allocator|c_str|str ( )") || Token::Match(end, "rfind|copy"))) && (Token::Match(end, "size|empty|cend|crend|cbegin|crbegin|max_size|length|count|capacity|get_allocator|c_str|str ( )") || Token::Match(end, "rfind|copy")))
; ;
else if (!var->typeScope() || !isConstMemberFunc(var->typeScope(), end)) else if (!var->typeScope() || !isConstMemberFunc(var->typeScope(), end))

View File

@ -1446,11 +1446,20 @@ CheckIO::ArgumentInfo::~ArgumentInfo()
bool CheckIO::ArgumentInfo::isStdVectorOrString() bool CheckIO::ArgumentInfo::isStdVectorOrString()
{ {
if (Token::Match(variableInfo->typeStartToken(), "std :: vector|array <")) { // THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char* const stl_vector[] = {
"array", "vector"
};
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char* const stl_string[] = {
"string", "u16string", "u32string", "wstring"
};
if (variableInfo->isStlType(stl_vector)) {
typeToken = variableInfo->typeStartToken()->tokAt(4); typeToken = variableInfo->typeStartToken()->tokAt(4);
_template = true; _template = true;
return true; return true;
} else if (Token::Match(variableInfo->typeStartToken(), "std :: string|wstring")) { } else if (variableInfo->isStlType(stl_string)) {
tempToken = new Token(0); tempToken = new Token(0);
tempToken->fileIndex(variableInfo->typeStartToken()->fileIndex()); tempToken->fileIndex(variableInfo->typeStartToken()->fileIndex());
tempToken->linenr(variableInfo->typeStartToken()->linenr()); tempToken->linenr(variableInfo->typeStartToken()->linenr());
@ -1485,11 +1494,25 @@ bool CheckIO::ArgumentInfo::isStdVectorOrString()
bool CheckIO::ArgumentInfo::isStdContainer(const Token *tok) bool CheckIO::ArgumentInfo::isStdContainer(const Token *tok)
{ {
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char* const stl_container[] = {
"array", "bitset", "deque", "forward_list",
"hash_map", "hash_multimap", "hash_set",
"list", "map", "multimap", "multiset",
"priority_queue", "queue", "set", "stack",
"unordered_map", "unordered_multimap", "unordered_multiset", "unordered_set",
"vector"
};
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char* const stl_string[]= {
"string", "u16string", "u32string", "wstring"
};
if (tok && tok->variable()) { if (tok && tok->variable()) {
if (Token::Match(tok->variable()->typeStartToken(), "std :: vector|array|bitset|deque|list|forward_list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|unordered_map|unordered_multimap|unordered_set|unordered_multiset <")) { if (tok->variable()->isStlType(stl_container)) {
typeToken = tok->variable()->typeStartToken()->tokAt(4); typeToken = tok->variable()->typeStartToken()->tokAt(4);
return true; return true;
} else if (Token::Match(tok->variable()->typeStartToken(), "std :: string|wstring")) { } else if (tok->variable()->isStlType(stl_string)) {
typeToken = tok->variable()->typeStartToken(); typeToken = tok->variable()->typeStartToken();
return true; return true;
} else if (tok->variable()->type() && !tok->variable()->type()->derivedFrom.empty()) { } else if (tok->variable()->type() && !tok->variable()->type()->derivedFrom.empty()) {

View File

@ -320,6 +320,13 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token
*/ */
bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown) bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown)
{ {
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char* const stl_stream [] = {
"fstream", "ifstream", "iostream", "istream",
"istringstream", "ofstream", "ostream", "ostringstream",
"stringstream", "wistringstream", "wostringstream", "wstringstream"
};
const bool inconclusive = unknown; const bool inconclusive = unknown;
unknown = false; unknown = false;
@ -379,7 +386,7 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown)
return true; return true;
if (tok2 && tok2->varId() != 0) { if (tok2 && tok2->varId() != 0) {
const Variable* var2 = tok2->variable(); const Variable* var2 = tok2->variable();
if (var2 && Token::Match(var2->typeStartToken(), "std :: istream|ifstream|istringstream|wistringstream|ostream|ofstream|ostringstream|wostringstream|stringstream|wstringstream|fstream|iostream")) if (var2 && var2->isStlType(stl_stream))
return true; return true;
} }
} }
@ -821,6 +828,12 @@ void CheckNullPointer::nullConstantDereference()
{ {
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char* const stl_stream[] = {
"fstream", "ifstream", "iostream", "istream",
"istringstream", "stringstream", "wistringstream", "wstringstream"
};
const std::size_t functions = symbolDatabase->functionScopes.size(); const std::size_t functions = symbolDatabase->functionScopes.size();
for (std::size_t i = 0; i < functions; ++i) { for (std::size_t i = 0; i < functions; ++i) {
const Scope * scope = symbolDatabase->functionScopes[i]; const Scope * scope = symbolDatabase->functionScopes[i];
@ -874,7 +887,7 @@ void CheckNullPointer::nullConstantDereference()
nullPointerError(tok); nullPointerError(tok);
if (tok2 && tok2->varId() != 0) { if (tok2 && tok2->varId() != 0) {
const Variable *var = tok2->variable(); const Variable *var = tok2->variable();
if (var && Token::Match(var->typeStartToken(), "std :: istream|ifstream|istringstream|wistringstream|stringstream|wstringstream|fstream|iostream")) if (var && var->isStlType(stl_stream))
nullPointerError(tok); nullPointerError(tok);
} }
} }

View File

@ -1161,7 +1161,7 @@ void CheckOther::suspiciousEqualityComparisonError(const Token* tok)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static bool isTypeWithoutSideEffects(const Tokenizer *tokenizer, const Variable* var) static bool isTypeWithoutSideEffects(const Tokenizer *tokenizer, const Variable* var)
{ {
return ((var && (!var->isClass() || var->isPointer() || Token::simpleMatch(var->typeStartToken(), "std ::"))) || !tokenizer->isCPP()); return ((var && (!var->isClass() || var->isPointer() || var->isStlType())) || !tokenizer->isCPP());
} }
static inline const Token *findSelfAssignPattern(const Token *start) static inline const Token *findSelfAssignPattern(const Token *start)

View File

@ -294,6 +294,10 @@ void CheckStl::mismatchingContainers()
void CheckStl::stlOutOfBounds() void CheckStl::stlOutOfBounds()
{ {
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char* const stl_bounded_container [] = {
"array", "basic_string", "deque", "string", "vector", "wstring"
};
const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
// Scan through all scopes.. // Scan through all scopes..
@ -316,7 +320,7 @@ void CheckStl::stlOutOfBounds()
const Variable *container = tok->tokAt(3)->variable(); const Variable *container = tok->tokAt(3)->variable();
if (!container) if (!container)
continue; continue;
if (!Token::Match(container->typeStartToken(), "std :: vector|deque|array|string|wstring|basic_string")) if (!container->isStlType(stl_bounded_container))
continue; continue;
// variable id for loop variable. // variable id for loop variable.
@ -868,7 +872,7 @@ void CheckStl::if_find()
//pretty bad limitation.. but it is there in order to avoid //pretty bad limitation.. but it is there in order to avoid
//own implementations of 'find' or any container //own implementations of 'find' or any container
if (!Token::simpleMatch(decl, "std ::")) if (!var->isStlType())
continue; continue;
decl = decl->tokAt(2); decl = decl->tokAt(2);
@ -1199,7 +1203,7 @@ void CheckStl::string_c_str()
tok2 = tok2->previous(); tok2 = tok2->previous();
if (tok2 && Token::simpleMatch(tok2->tokAt(-4), ". c_str ( )")) { if (tok2 && Token::simpleMatch(tok2->tokAt(-4), ". c_str ( )")) {
const Variable* var = tok2->tokAt(-5)->variable(); const Variable* var = tok2->tokAt(-5)->variable();
if (var && Token::simpleMatch(var->typeStartToken(), "std ::")) if (var && var->isStlType())
string_c_strParam(tok, i->second); string_c_strParam(tok, i->second);
} }
} }
@ -1245,7 +1249,7 @@ void CheckStl::string_c_str()
tok2 = tok2->tokAt(-5); tok2 = tok2->tokAt(-5);
if (tok2->isName()) { // return var.c_str(); => check if var is a std type if (tok2->isName()) { // return var.c_str(); => check if var is a std type
const Variable *var = tok2->variable(); const Variable *var = tok2->variable();
if (var && Token::simpleMatch(var->typeStartToken(), "std ::")) if (var && var->isStlType())
string_c_strReturn(tok); string_c_strReturn(tok);
} else { } else {
// TODO: determine if a error should be written or not // TODO: determine if a error should be written or not

View File

@ -688,7 +688,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
else if (_tokenizer->isC() || else if (_tokenizer->isC() ||
i->typeEndToken()->isStandardType() || i->typeEndToken()->isStandardType() ||
isRecordTypeWithoutSideEffects(i->type()) || isRecordTypeWithoutSideEffects(i->type()) ||
(Token::simpleMatch(i->typeStartToken(), "std ::") && (i->isStlType() &&
i->typeStartToken()->strAt(2) != "lock_guard" && i->typeStartToken()->strAt(2) != "lock_guard" &&
i->typeStartToken()->strAt(2) != "unique_lock")) i->typeStartToken()->strAt(2) != "unique_lock"))
type = Variables::standard; type = Variables::standard;
@ -1118,7 +1118,7 @@ void CheckUnusedVar::checkFunctionVariableUsage()
unusedVariableError(usage._var->nameToken(), varname); unusedVariableError(usage._var->nameToken(), varname);
// variable has not been written but has been modified // variable has not been written but has been modified
else if (usage._modified && !usage._write && !usage._allocateMemory && !Token::simpleMatch(var->typeStartToken(), "std ::")) else if (usage._modified && !usage._write && !usage._allocateMemory && !var->isStlType())
unassignedVariableError(usage._var->nameToken(), varname); unassignedVariableError(usage._var->nameToken(), varname);
// variable has been written but not read // variable has been written but not read
@ -1126,7 +1126,7 @@ void CheckUnusedVar::checkFunctionVariableUsage()
unreadVariableError(usage._lastAccess, varname); unreadVariableError(usage._lastAccess, varname);
// variable has been read but not written // variable has been read but not written
else if (!usage._write && !usage._allocateMemory && !Token::simpleMatch(var->typeStartToken(), "std ::")) else if (!usage._write && !usage._allocateMemory && !var->isStlType())
unassignedVariableError(usage._var->nameToken(), varname); unassignedVariableError(usage._var->nameToken(), varname);
} }
} }

View File

@ -455,8 +455,8 @@ public:
* @return true if it is an stl type and its type matches any of the types in 'stlTypes' * @return true if it is an stl type and its type matches any of the types in 'stlTypes'
*/ */
template <std::size_t array_length> template <std::size_t array_length>
bool isStlType(const char* (&stlTypes)[array_length]) const { bool isStlType(const char* const(&stlTypes)[array_length]) const {
return _stlType && std::binary_search(stlTypes, stlTypes + array_length, typeStartToken()->strAt(2)); return _stlType && std::binary_search(stlTypes, stlTypes + array_length, _start->strAt(2));
} }
private: private:

View File

@ -707,7 +707,7 @@ static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger,
// Get function argument, and check if parameter is passed by value // Get function argument, and check if parameter is passed by value
const Function * const function = ftok->astOperand1()->function(); const Function * const function = ftok->astOperand1()->function();
const Variable * const arg = function ? function->getArgumentVar(argnr) : NULL; const Variable * const arg = function ? function->getArgumentVar(argnr) : NULL;
if (!Token::Match(arg ? arg->typeStartToken() : NULL, "const| %type% %var% ,|)")) if (!Token::Match(arg ? arg->typeStartToken() : NULL, "%type% %var% ,|)"))
continue; continue;
// Function scope.. // Function scope..