Refactoring: Distinguish between C and C++ code

Refactoring: Replace CheckNonReentrantFunctions::initNonReentrantFunctions by static initialization
This commit is contained in:
amai2012 2015-06-29 21:17:15 +02:00
parent d7aa65c1fc
commit 11538c84f6
4 changed files with 46 additions and 53 deletions

View File

@ -1090,7 +1090,7 @@ void CheckBufferOverrun::checkGlobalAndLocalVariable()
"Check (BufferOverrun::checkGlobalAndLocalVariable)",
tok->progressValue());
if (Token::Match(tok, "[*;{}] %var% = new %type% [ %num% ]")) {
if (_tokenizer->isCPP() && Token::Match(tok, "[*;{}] %var% = new %type% [ %num% ]")) {
size = MathLib::toLongNumber(tok->strAt(6));
type = tok->strAt(4);
var = tok->next()->variable();
@ -1098,7 +1098,7 @@ void CheckBufferOverrun::checkGlobalAndLocalVariable()
if (size < 0) {
negativeMemoryAllocationSizeError(tok->next()->next());
}
} else if (Token::Match(tok, "[*;{}] %var% = new %type% ( %num%|%name% )")) {
} else if (_tokenizer->isCPP() && Token::Match(tok, "[*;{}] %var% = new %type% ( %num%|%name% )")) {
size = 1;
type = tok->strAt(4);
var = tok->next()->variable();

View File

@ -31,6 +31,21 @@ namespace {
CheckNonReentrantFunctions instance;
}
namespace {
const std::set<std::string> _nonReentrantFunctions = make_container< std::set<std::string> > ()
<< "localtime" << "gmtime" << "strtok" << "gethostbyname" << "gethostbyaddr" << "getservbyname"
<< "getservbyport" << "crypt" << "ttyname" << "gethostbyname2"
<< "getprotobyname" << "getnetbyname" << "getnetbyaddr" << "getrpcbyname" << "getrpcbynumber" << "getrpcent"
<< "ctermid" << "readdir" << "getlogin" << "getpwent" << "getpwnam" << "getpwuid" << "getspent"
<< "fgetspent" << "getspnam" << "getgrnam" << "getgrgid" << "getnetgrent" << "tempnam" << "fgetpwent"
<< "fgetgrent" << "ecvt" << "gcvt" << "getservent" << "gethostent" << "getgrent" << "fcvt" ;
}
std::string CheckNonReentrantFunctions::generateErrorMessage(const std::string& function) {
return std::string("Non reentrant function '") + function + "' called. " +
"For threadsafe applications it is recommended to use the reentrant replacement function '" + function + "_r'.";
}
void CheckNonReentrantFunctions::nonReentrantFunctions()
{
if (!_settings->standards.posix || !_settings->isEnabled("portability"))
@ -46,7 +61,7 @@ void CheckNonReentrantFunctions::nonReentrantFunctions()
continue;
// Check for non-reentrant function name
std::map<std::string, std::string>::const_iterator it = _nonReentrantFunctions.find(tok->str());
std::set<std::string>::const_iterator it = _nonReentrantFunctions.find(tok->str());
if (it == _nonReentrantFunctions.end())
continue;
@ -62,8 +77,26 @@ void CheckNonReentrantFunctions::nonReentrantFunctions()
}
// Only affecting multi threaded code, therefore this is "portability"
reportError(tok, Severity::portability, "nonreentrantFunctions" + it->first, it->second);
reportError(tok, Severity::portability, "nonreentrantFunctions" + *it, generateErrorMessage(*it));
}
}
}
//---------------------------------------------------------------------------
void CheckNonReentrantFunctions::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
CheckNonReentrantFunctions c(0, settings, errorLogger);
std::set<std::string>::const_iterator it(_nonReentrantFunctions.begin()), itend(_nonReentrantFunctions.end());
for (; it!=itend; ++it) {
c.reportError(0, Severity::portability, "nonreentrantFunctions"+*it, generateErrorMessage(*it));
}
}
std::string CheckNonReentrantFunctions::classInfo() const {
std::string info = "Warn if any of these non reentrant functions are used:\n";
std::set<std::string>::const_iterator it(_nonReentrantFunctions.begin()), itend(_nonReentrantFunctions.end());
for (; it!=itend; ++it) {
info += "- " + *it + "\n";
}
return info;
}

View File

@ -38,13 +38,11 @@ class CPPCHECKLIB CheckNonReentrantFunctions : public Check {
public:
/** This constructor is used when registering the CheckNonReentrantFunctions */
CheckNonReentrantFunctions() : Check(myName()) {
initNonReentrantFunctions();
}
/** This constructor is used when running checks. */
CheckNonReentrantFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
: Check(myName(), tokenizer, settings, errorLogger) {
initNonReentrantFunctions();
}
void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) {
@ -57,52 +55,15 @@ public:
private:
/* function name / error message */
std::map<std::string,std::string> _nonReentrantFunctions;
static std::string generateErrorMessage(const std::string& function);
/** init nonreentrant functions list ' */
void initNonReentrantFunctions() {
static const char * const non_reentrant_functions_list[] = {
"localtime", "gmtime", "strtok", "gethostbyname", "gethostbyaddr", "getservbyname"
, "getservbyport", "crypt", "ttyname", "gethostbyname2"
, "getprotobyname", "getnetbyname", "getnetbyaddr", "getrpcbyname", "getrpcbynumber", "getrpcent"
, "ctermid", "readdir", "getlogin", "getpwent", "getpwnam", "getpwuid", "getspent"
, "fgetspent", "getspnam", "getgrnam", "getgrgid", "getnetgrent", "tempnam", "fgetpwent"
, "fgetgrent", "ecvt", "gcvt", "getservent", "gethostent", "getgrent", "fcvt"
};
// generate messages
for (unsigned int i = 0; i < (sizeof(non_reentrant_functions_list) / sizeof(char *)); ++i) {
std::string strMsg("Non reentrant function '");
strMsg+=non_reentrant_functions_list[i];
strMsg+= "' called. For threadsafe applications it is recommended to use the reentrant replacement function '";
strMsg+=non_reentrant_functions_list[i];
strMsg+="_r'.";
_nonReentrantFunctions[non_reentrant_functions_list[i]] = strMsg;
}
}
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
CheckNonReentrantFunctions c(0, settings, errorLogger);
std::map<std::string,std::string>::const_iterator it(_nonReentrantFunctions.begin()), itend(_nonReentrantFunctions.end());
for (; it!=itend; ++it) {
c.reportError(0, Severity::portability, "nonreentrantFunctions"+it->first, it->second);
}
}
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const;
static std::string myName() {
return "Non reentrant functions";
}
std::string classInfo() const {
std::string info = "Warn if any of these non reentrant functions are used:\n";
std::map<std::string,std::string>::const_iterator it(_nonReentrantFunctions.begin()), itend(_nonReentrantFunctions.end());
for (; it!=itend; ++it) {
info += "- " + it->first + "\n";
}
return info;
}
std::string classInfo() const;
};
/// @}
//---------------------------------------------------------------------------

View File

@ -792,7 +792,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
// C++11 std::for_each
// No warning should be written if a variable is first read and
// then written in the body.
else if (Token::simpleMatch(tok, "for_each (") && Token::simpleMatch(tok->linkAt(1), ") ;")) {
else if (_tokenizer->isCPP() && Token::simpleMatch(tok, "for_each (") && Token::simpleMatch(tok->linkAt(1), ") ;")) {
const Token *end = tok->linkAt(1);
if (end->previous()->str() == "}") {
std::set<unsigned int> readvar;
@ -829,8 +829,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
}
// Freeing memory (not considered "using" the pointer if it was also allocated in this function)
if (Token::Match(tok, "free|g_free|kfree|vfree ( %var% )") ||
Token::Match(tok, "delete %var% ;") ||
Token::Match(tok, "delete [ ] %var% ;")) {
(_tokenizer->isCPP() && (Token::Match(tok, "delete %var% ;") || Token::Match(tok, "delete [ ] %var% ;")))) {
unsigned int varid = 0;
if (tok->str() != "delete") {
varid = tok->tokAt(2)->varId();
@ -918,8 +917,8 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
const Token *type = start->tokAt(3);
// skip nothrow
if (Token::simpleMatch(type, "( nothrow )") ||
Token::simpleMatch(type, "( std :: nothrow )"))
if (_tokenizer->isCPP() && (Token::simpleMatch(type, "( nothrow )") ||
Token::simpleMatch(type, "( std :: nothrow )")))
type = type->link()->next();
// is it a user defined type?
@ -1268,7 +1267,7 @@ bool CheckUnusedVar::isRecordTypeWithoutSideEffects(const Type* type)
// a type that has no side effects (no constructors and no members with constructors)
/** @todo false negative: check constructors for side effects */
std::pair<std::map<const Type *,bool>::iterator,bool> found=isRecordTypeWithoutSideEffectsMap.insert(
const std::pair<std::map<const Type *,bool>::iterator,bool> found=isRecordTypeWithoutSideEffectsMap.insert(
std::pair<const Type *,bool>(type,false)); //Initialize with side effects for possible recursions
bool & withoutSideEffects=found.first->second;
if (!found.second)
@ -1294,7 +1293,7 @@ bool CheckUnusedVar::isEmptyType(const Type* type)
{
// a type that has no variables and no constructor
std::pair<std::map<const Type *,bool>::iterator,bool> found=isEmptyTypeMap.insert(
const std::pair<std::map<const Type *,bool>::iterator,bool> found=isEmptyTypeMap.insert(
std::pair<const Type *,bool>(type,false));
bool & emptyType=found.first->second;
if (!found.second)