Merge branch 'master' into project

This commit is contained in:
Daniel Marjamäki 2016-08-05 19:46:49 +02:00
commit 8070c536d5
33 changed files with 1163 additions and 793 deletions

View File

@ -39,6 +39,30 @@
<not-uninit/>
</arg>
</function>
<!-- http://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html -->
<!-- int access(const char *pathname, int amode); -->
<function name="access">
<use-retval/>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<arg nr="2">
<not-uninit/>
</arg>
</function>
<!-- http://man7.org/linux/man-pages/man3/adjtime.3.html -->
<!-- int adjtime(const struct timeval *delta, struct timeval *olddelta); -->
<function name="adjtime">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
</arg>
<arg nr="2"/>
</function>
<!-- struct group *getgrnam(const char *name); -->
<function name="getgrnam">
<use-retval/>
@ -116,6 +140,43 @@
<not-null/>
</arg>
</function>
<!-- http://pubs.opengroup.org/onlinepubs/009695399/functions/fdatasync.html -->
<!-- int fdatasync(int fildes); -->
<function name="fdatasync">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
</arg>
</function>
<!-- http://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html -->
<!-- int fnmatch(const char *pattern, const char *string, int flags); -->
<function name="fnmatch">
<pure/>
<use-retval/>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<arg nr="2">
<not-uninit/>
<not-null/>
</arg>
<arg nr="3">
<not-uninit/>
</arg>
</function>
<!-- http://pubs.opengroup.org/onlinepubs/009695399/functions/fsync.html -->
<!-- int fsync(int fildes); -->
<function name="fsync">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
</arg>
</function>
<!-- int truncate(const char *path, off_t length); -->
<function name="truncate">
<noreturn>false</noreturn>

View File

@ -88,6 +88,22 @@ bool endsWith(const std::string &s, const std::string &e) {
bool sameline(const simplecpp::Token *tok1, const simplecpp::Token *tok2) {
return tok1 && tok2 && tok1->location.sameline(tok2->location);
}
static bool isAlternativeBinaryOp(const simplecpp::Token *tok, const std::string &alt) {
return (tok->name &&
tok->str == alt &&
tok->previous &&
tok->next &&
(tok->previous->number || tok->previous->name || tok->previous->op == ')') &&
(tok->next->number || tok->next->name || tok->next->op == '('));
}
static bool isAlternativeUnaryOp(const simplecpp::Token *tok, const std::string &alt) {
return ((tok->name && tok->str == alt) &&
(!tok->previous || tok->previous->op == '(') &&
(tok->next && (tok->next->name || tok->next->number)));
}
}
void simplecpp::Location::adjust(const std::string &str) {
@ -533,7 +549,12 @@ void simplecpp::TokenList::combineOperators() {
}
void simplecpp::TokenList::constFoldUnaryNotPosNeg(simplecpp::Token *tok) {
const std::string NOT("not");
for (; tok && tok->op != ')'; tok = tok->next) {
// "not" might be !
if (isAlternativeUnaryOp(tok, NOT))
tok->op = '!';
if (tok->op == '!' && tok->next && tok->next->number) {
tok->setstr(tok->next->str == "0" ? "1" : "0");
deleteToken(tok->next);
@ -612,7 +633,12 @@ void simplecpp::TokenList::constFoldAddSub(Token *tok) {
}
void simplecpp::TokenList::constFoldComparison(Token *tok) {
const std::string NOTEQ("not_eq");
for (; tok && tok->op != ')'; tok = tok->next) {
if (isAlternativeBinaryOp(tok,NOTEQ))
tok->setstr("!=");
if (!tok->startsWithOneOf("<>=!"))
continue;
if (!tok->previous || !tok->previous->number)
@ -655,7 +681,7 @@ void simplecpp::TokenList::constFoldBitwise(Token *tok)
else
altop = "xor";
for (tok = tok1; tok && tok->op != ')'; tok = tok->next) {
if (tok->op != *op && tok->str != altop)
if (tok->op != *op && !isAlternativeBinaryOp(tok, altop))
continue;
if (!tok->previous || !tok->previous->number)
continue;
@ -677,8 +703,17 @@ void simplecpp::TokenList::constFoldBitwise(Token *tok)
}
void simplecpp::TokenList::constFoldLogicalOp(Token *tok) {
const std::string AND("and");
const std::string OR("or");
for (; tok && tok->op != ')'; tok = tok->next) {
if (tok->str != "&&" && tok->str != "||" && tok->str != "and" && tok->str != "or")
if (tok->name) {
if (isAlternativeBinaryOp(tok,AND))
tok->setstr("&&");
else if (isAlternativeBinaryOp(tok,OR))
tok->setstr("||");
}
if (tok->str != "&&" && tok->str != "||")
continue;
if (!tok->previous || !tok->previous->number)
continue;
@ -686,7 +721,7 @@ void simplecpp::TokenList::constFoldLogicalOp(Token *tok) {
continue;
int result;
if (tok->str == "||" || tok->str == "or")
if (tok->str == "||")
result = (stringToLL(tok->previous->str) || stringToLL(tok->next->str));
else /*if (tok->str == "&&")*/
result = (stringToLL(tok->previous->str) && stringToLL(tok->next->str));
@ -989,14 +1024,14 @@ private:
return ~0U;
}
std::vector<const Token *> getMacroParameters(const Token *nameToken, bool def) const {
std::vector<const Token *> getMacroParameters(const Token *nameToken, bool calledInDefine) const {
if (!nameToken->next || nameToken->next->op != '(' || !functionLike())
return std::vector<const Token *>();
std::vector<const Token *> parametertokens;
parametertokens.push_back(nameToken->next);
unsigned int par = 0U;
for (const Token *tok = nameToken->next->next; def ? sameline(tok,nameToken) : (tok != NULL); tok = tok->next) {
for (const Token *tok = nameToken->next->next; calledInDefine ? sameline(tok,nameToken) : (tok != NULL); tok = tok->next) {
if (tok->op == '(')
++par;
else if (tok->op == ')') {
@ -1023,16 +1058,26 @@ private:
unsigned int par = 0;
const Token *tok = lpar;
while (sameline(lpar, tok)) {
if (!expandArg(tokens, tok, tok->location, macros, expandedmacros1, expandedmacros, parametertokens))
tokens->push_back(new Token(*tok));
if (tok->op == '(')
++par;
else if (tok->op == ')') {
--par;
if (par == 0U)
break;
if (tok->op == '#' && sameline(tok,tok->next) && tok->next->op == '#' && sameline(tok,tok->next->next)) {
// A##B => AB
const std::string strB(expandArgStr(tok->next->next, parametertokens));
if (variadic && strB.empty() && tok->previous->op == ',')
tokens->deleteToken(tokens->back());
else
tokens->back()->setstr(tokens->back()->str + strB);
tok = tok->next->next->next;
} else {
if (!expandArg(tokens, tok, tok->location, macros, expandedmacros1, expandedmacros, parametertokens))
tokens->push_back(new Token(*tok));
if (tok->op == '(')
++par;
else if (tok->op == ')') {
--par;
if (par == 0U)
break;
}
tok = tok->next;
}
tok = tok->next;
}
return sameline(lpar,tok) ? tok : NULL;
}
@ -1056,7 +1101,10 @@ private:
return nameToken->next;
}
std::vector<const Token*> parametertokens1(getMacroParameters(nameToken, !expandedmacros1.empty()));
const bool calledInDefine = (loc.fileIndex != nameToken->location.fileIndex ||
loc.line < nameToken->location.line);
std::vector<const Token*> parametertokens1(getMacroParameters(nameToken, calledInDefine));
if (functionLike()) {
// No arguments => not macro expansion
@ -1144,8 +1192,6 @@ private:
if (variadic && strAB == "," && tok->previous->previous->str == "," && args.size() >= 1U && tok->next->str == args[args.size()-1U])
removeComma = true;
tok = tok->next->next;
output->deleteToken(A);
if (!removeComma) {
@ -1154,14 +1200,22 @@ private:
// TODO: For functionLike macros, push the (...)
expandToken(output, loc, tokens.cfront(), macros, expandedmacros1, expandedmacros, parametertokens2);
}
tok = tok->next->next;
} else {
// #123 => "123"
TokenList tokenListHash(files);
tok = expandToken(&tokenListHash, loc, tok, macros, expandedmacros1, expandedmacros, parametertokens2);
std::string s;
for (const Token *hashtok = tokenListHash.cfront(); hashtok; hashtok = hashtok->next)
s += hashtok->str;
output->push_back(newMacroToken('\"' + s + '\"', loc, expandedmacros1.empty()));
std::ostringstream ostr;
for (const Token *hashtok = tokenListHash.cfront(); hashtok; hashtok = hashtok->next) {
for (unsigned int i = 0; i < hashtok->str.size(); i++) {
unsigned char c = hashtok->str[i];
if (c == '\"' || c == '\\' || c == '\'')
ostr << '\\';
ostr << c;
}
}
output->push_back(newMacroToken('\"' + ostr.str() + '\"', loc, expandedmacros1.empty()));
}
}
@ -1386,15 +1440,18 @@ void simplifyName(simplecpp::TokenList &expr) {
altop.insert("or");
altop.insert("bitand");
altop.insert("bitor");
altop.insert("not");
altop.insert("not_eq");
altop.insert("xor");
for (simplecpp::Token *tok = expr.front(); tok; tok = tok->next) {
if (tok->name) {
if (altop.find(tok->str) != altop.end()) {
bool alt = true;
if (!tok->previous || !tok->next)
alt = false;
if (!(tok->previous->number || tok->previous->op == ')'))
alt = false;
bool alt;
if (tok->str == "not") {
alt = isAlternativeUnaryOp(tok,tok->str);
} else {
alt = isAlternativeBinaryOp(tok,tok->str);
}
if (alt)
continue;
}
@ -1639,20 +1696,38 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
const bool systemheader = (rawtok->next->str[0] == '<');
const std::string header(rawtok->next->str.substr(1U, rawtok->next->str.size() - 2U));
const std::string header2 = getFileName(filedata, rawtok->location.file(), header, dui, systemheader);
if (!header2.empty() && pragmaOnce.find(header2) == pragmaOnce.end()) {
includetokenstack.push(gotoNextLine(rawtok));
const TokenList *includetokens = filedata.find(header2)->second;
rawtok = includetokens ? includetokens->cfront() : 0;
continue;
} else {
if (header2.empty()) {
simplecpp::Output output(files);
output.type = Output::MISSING_INCLUDE;
output.type = Output::MISSING_HEADER;
output.location = rawtok->location;
output.msg = "Header not found: " + rawtok->next->str;
if (outputList)
outputList->push_back(output);
} else if (includetokenstack.size() >= 400) {
simplecpp::Output out(files);
out.type = Output::INCLUDE_NESTED_TOO_DEEPLY;
out.location = rawtok->location;
out.msg = "#include nested too deeply";
if (outputList)
outputList->push_back(out);
} else if (pragmaOnce.find(header2) == pragmaOnce.end()) {
includetokenstack.push(gotoNextLine(rawtok));
const TokenList *includetokens = filedata.find(header2)->second;
rawtok = includetokens ? includetokens->cfront() : 0;
continue;
}
} else if (rawtok->str == IF || rawtok->str == IFDEF || rawtok->str == IFNDEF || rawtok->str == ELIF) {
if (!sameline(rawtok,rawtok->next)) {
simplecpp::Output out(files);
out.type = Output::SYNTAX_ERROR;
out.location = rawtok->location;
out.msg = "Syntax error in #" + rawtok->str;
if (outputList)
outputList->push_back(out);
output.clear();
return;
}
bool conditionIsTrue;
if (ifstates.top() == ALWAYS_FALSE || (ifstates.top() == ELSE_IS_TRUE && rawtok->str != ELIF))
conditionIsTrue = false;
@ -1691,7 +1766,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
it->second.expand(&value, tok, macros, files);
} catch (Macro::Error &err) {
Output out(rawtok->location.files);
out.type = Output::ERROR;
out.type = Output::SYNTAX_ERROR;
out.location = err.location;
out.msg = "failed to expand \'" + tok->str + "\', " + err.what;
if (outputList)
@ -1822,3 +1897,9 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
}
}
}
void simplecpp::cleanup(std::map<std::string, TokenList*> &filedata) {
for (std::map<std::string, TokenList*>::iterator it = filedata.begin(); it != filedata.end(); ++it)
delete it->second;
filedata.clear();
}

View File

@ -156,7 +156,9 @@ struct SIMPLECPP_LIB Output {
enum Type {
ERROR, /* #error */
WARNING, /* #warning */
MISSING_INCLUDE
MISSING_HEADER,
INCLUDE_NESTED_TOO_DEEPLY,
SYNTAX_ERROR
} type;
Location location;
std::string msg;
@ -275,19 +277,21 @@ SIMPLECPP_LIB std::map<std::string, TokenList*> load(const TokenList &rawtokens,
/**
* Preprocess
*
* Preprocessing is done in two steps currently:
* const simplecpp::TokenList tokens1 = simplecpp::TokenList(f);
* const simplecpp::TokenList tokens2 = simplecpp::preprocess(tokens1, defines);
*
* The "tokens1" will contain tokens for comments and for preprocessor directives. And there is no preprocessing done.
* This "tokens1" can be used if you need to see what comments/directives there are. Or what code is hidden in #if.
*
* The "tokens2" will have normal preprocessor output. No comments nor directives are seen.
*
* @todo simplify interface
* @param output TokenList that receives the preprocessing output
* @param rawtokens Raw tokenlist for top sourcefile
* @param files internal data of simplecpp
* @param filedata output from simplecpp::load()
* @param dui defines, undefs, and include paths
* @param outputList output: list that will receive output messages
* @param macroUsage output: macro usage
*/
SIMPLECPP_LIB void preprocess(TokenList &output, const TokenList &rawtokens, std::vector<std::string> &files, const std::map<std::string, TokenList*> &filedata, const DUI &dui, OutputList *outputList = 0, std::list<MacroUsage> *macroUsage = 0);
/**
* Deallocate data
*/
SIMPLECPP_LIB void cleanup(std::map<std::string, TokenList*> &filedata);
}
#endif

View File

@ -178,35 +178,40 @@ bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2
if (tok1->str() == "(" && tok1->previous() && !tok1->previous()->isName()) { // cast => assert that the casts are equal
const Token *t1 = tok1->next();
const Token *t2 = tok2->next();
while (t1 && t2 && t1->str() == t2->str() && (t1->isName() || t1->str() == "*")) {
while (t1 && t2 &&
t1->str() == t2->str() &&
t1->isLong() == t2->isLong() &&
t1->isUnsigned() == t2->isUnsigned() &&
t1->isSigned() == t2->isSigned() &&
(t1->isName() || t1->str() == "*")) {
t1 = t1->next();
t2 = t2->next();
}
if (!t1 || !t2 || t1->str() != ")" || t2->str() != ")")
return false;
}
bool noncommuative_equals =
bool noncommutativeEquals =
isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand1(), constFunctions);
noncommuative_equals = noncommuative_equals &&
noncommutativeEquals = noncommutativeEquals &&
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand2(), constFunctions);
if (noncommuative_equals)
if (noncommutativeEquals)
return true;
const bool commutative = tok1->astOperand1() && tok1->astOperand2() && Token::Match(tok1, "%or%|%oror%|+|*|&|&&|^|==|!=");
bool commuative_equals = commutative &&
bool commutativeEquals = commutative &&
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand1(), constFunctions);
commuative_equals = commuative_equals &&
commutativeEquals = commutativeEquals &&
isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand2(), constFunctions);
// in c++, "a"+b might be different to b+"a"
if (cpp && commuative_equals && tok1->str() == "+" &&
if (cpp && commutativeEquals && tok1->str() == "+" &&
(tok1->astOperand1()->tokType() == Token::eString || tok1->astOperand2()->tokType() == Token::eString)) {
const Token * const other = tok1->astOperand1()->tokType() != Token::eString ? tok1->astOperand1() : tok1->astOperand2();
return other && astIsIntegral(other,false);
}
return commuative_equals;
return commutativeEquals;
}
bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions)

View File

@ -1777,7 +1777,7 @@ CheckBufferOverrun::ArrayInfo::ArrayInfo(const Variable *var, const SymbolDataba
_num.push_back(var->dimension(i));
if (var->typeEndToken()->str() == "*")
_element_size = symDb->sizeOfType(var->typeEndToken());
else if (var->typeStartToken()->str() == "struct")
else if (var->typeStartToken()->strAt(-1) == "struct")
_element_size = 100;
else {
_element_size = symDb->sizeOfType(var->typeEndToken());

View File

@ -1438,15 +1438,17 @@ bool CheckClass::hasAllocation(const Function *func, const Scope* scope) const
return true;
// check for deallocating memory
const Token *var = nullptr;
const Token *var;
if (Token::Match(tok, "free ( %var%"))
var = tok->tokAt(2);
else if (Token::Match(tok, "delete [ ] %var%"))
var = tok->tokAt(3);
else if (Token::Match(tok, "delete %var%"))
var = tok->next();
else
continue;
// Check for assignment to the deleted pointer (only if its a member of the class)
if (var && isMemberVar(scope, var)) {
if (isMemberVar(scope, var)) {
for (const Token *tok1 = var->next(); tok1 && (tok1 != last); tok1 = tok1->next()) {
if (Token::Match(tok1, "%varid% =", var->varId()))
return true;

View File

@ -33,7 +33,7 @@ namespace {
}
static const CWE CWE252(252U); // Unchecked Return Value
static const CWE CWE466(447U); // Use of Obsolete Functions
static const CWE CWE477(477U); // Use of Obsolete Functions
static const CWE CWE758(758U); // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior
static const CWE CWE628(628U); // Function Call with Incorrectly Specified Arguments
@ -68,7 +68,7 @@ void CheckFunctions::checkProhibitedFunctions()
const Library::WarnInfo* wi = _settings->library.getWarnInfo(tok);
if (wi) {
if (_settings->isEnabled(Severity::toString(wi->severity)) && _settings->standards.c >= wi->standards.c && _settings->standards.cpp >= wi->standards.cpp) {
reportError(tok, wi->severity, tok->str() + "Called", wi->message);
reportError(tok, wi->severity, tok->str() + "Called", wi->message, CWE477, false);
}
}
}

View File

@ -34,11 +34,13 @@ namespace {
}
// CVE ID used:
static const CWE CWE119(119U); // Improper Restriction of Operations within the Bounds of a Memory Buffer
static const CWE CWE398(398U); // Indicator of Poor Code Quality
static const CWE CWE664(664U);
static const CWE CWE685(685U);
static const CWE CWE687(687U);
static const CWE CWE910(910U);
static const CWE CWE664(664U); // Improper Control of a Resource Through its Lifetime
static const CWE CWE685(685U); // Function Call With Incorrect Number of Arguments
static const CWE CWE686(686U); // Function Call With Incorrect Argument Type
static const CWE CWE687(687U); // Function Call With Incorrectly Specified Argument Value
static const CWE CWE910(910U); // Use of Expired File Descriptor
//---------------------------------------------------------------------------
// std::cout << std::cout;
@ -426,8 +428,7 @@ void CheckIO::invalidScanfError(const Token *tok)
reportError(tok, Severity::warning,
"invalidscanf", fname + "() without field width limits can crash with huge input data.\n" +
fname + "() without field width limits can crash with huge input data. Add a field width "
"specifier to fix this problem:\n"
" %s => %20s\n"
"specifier to fix this problem.\n"
"\n"
"Sample program that can crash:\n"
"\n"
@ -443,8 +444,8 @@ void CheckIO::invalidScanfError(const Token *tok)
"here is 'scanf(\"%4s\", c);', as the maximum field width does not include the "
"terminating null byte.\n"
"Source: http://linux.die.net/man/3/scanf\n"
"Source: http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/libkern/stdio/scanf.c"
);
"Source: http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/libkern/stdio/scanf.c",
CWE119, false);
}
//---------------------------------------------------------------------------
@ -1779,7 +1780,7 @@ void CheckIO::wrongPrintfScanfPosixParameterPositionError(const Token* tok, cons
} else {
errmsg << "referencing parameter " << index << " while " << numFunction << " arguments given";
}
reportError(tok, Severity::warning, "wrongPrintfScanfParameterPositionError", errmsg.str());
reportError(tok, Severity::warning, "wrongPrintfScanfParameterPositionError", errmsg.str(), CWE685, false);
}
void CheckIO::invalidScanfArgTypeError_s(const Token* tok, unsigned int numFormat, const std::string& specifier, const ArgumentInfo* argInfo)
@ -1795,7 +1796,7 @@ void CheckIO::invalidScanfArgTypeError_s(const Token* tok, unsigned int numForma
errmsg << " *\' but the argument type is ";
argumentType(errmsg, argInfo);
errmsg << ".";
reportError(tok, Severity::warning, "invalidScanfArgType_s", errmsg.str());
reportError(tok, Severity::warning, "invalidScanfArgType_s", errmsg.str(), CWE686, false);
}
void CheckIO::invalidScanfArgTypeError_int(const Token* tok, unsigned int numFormat, const std::string& specifier, const ArgumentInfo* argInfo, bool isUnsigned)
{
@ -1839,7 +1840,7 @@ void CheckIO::invalidScanfArgTypeError_int(const Token* tok, unsigned int numFor
errmsg << " *\' but the argument type is ";
argumentType(errmsg, argInfo);
errmsg << ".";
reportError(tok, Severity::warning, "invalidScanfArgType_int", errmsg.str());
reportError(tok, Severity::warning, "invalidScanfArgType_int", errmsg.str(), CWE686, false);
}
void CheckIO::invalidScanfArgTypeError_float(const Token* tok, unsigned int numFormat, const std::string& specifier, const ArgumentInfo* argInfo)
{
@ -1856,7 +1857,7 @@ void CheckIO::invalidScanfArgTypeError_float(const Token* tok, unsigned int numF
errmsg << " *\' but the argument type is ";
argumentType(errmsg, argInfo);
errmsg << ".";
reportError(tok, Severity::warning, "invalidScanfArgType_float", errmsg.str());
reportError(tok, Severity::warning, "invalidScanfArgType_float", errmsg.str(), CWE686, false);
}
void CheckIO::invalidPrintfArgTypeError_s(const Token* tok, unsigned int numFormat, const ArgumentInfo* argInfo)
@ -1867,7 +1868,7 @@ void CheckIO::invalidPrintfArgTypeError_s(const Token* tok, unsigned int numForm
errmsg << "%s in format string (no. " << numFormat << ") requires \'char *\' but the argument type is ";
argumentType(errmsg, argInfo);
errmsg << ".";
reportError(tok, Severity::warning, "invalidPrintfArgType_s", errmsg.str());
reportError(tok, Severity::warning, "invalidPrintfArgType_s", errmsg.str(), CWE686, false);
}
void CheckIO::invalidPrintfArgTypeError_n(const Token* tok, unsigned int numFormat, const ArgumentInfo* argInfo)
{
@ -1877,7 +1878,7 @@ void CheckIO::invalidPrintfArgTypeError_n(const Token* tok, unsigned int numForm
errmsg << "%n in format string (no. " << numFormat << ") requires \'int *\' but the argument type is ";
argumentType(errmsg, argInfo);
errmsg << ".";
reportError(tok, Severity::warning, "invalidPrintfArgType_n", errmsg.str());
reportError(tok, Severity::warning, "invalidPrintfArgType_n", errmsg.str(), CWE686, false);
}
void CheckIO::invalidPrintfArgTypeError_p(const Token* tok, unsigned int numFormat, const ArgumentInfo* argInfo)
{
@ -1887,7 +1888,7 @@ void CheckIO::invalidPrintfArgTypeError_p(const Token* tok, unsigned int numForm
errmsg << "%p in format string (no. " << numFormat << ") requires an address but the argument type is ";
argumentType(errmsg, argInfo);
errmsg << ".";
reportError(tok, Severity::warning, "invalidPrintfArgType_p", errmsg.str());
reportError(tok, Severity::warning, "invalidPrintfArgType_p", errmsg.str(), CWE686, false);
}
static void printfFormatType(std::ostream& os, const std::string& specifier, bool isUnsigned)
{
@ -1944,7 +1945,7 @@ void CheckIO::invalidPrintfArgTypeError_uint(const Token* tok, unsigned int numF
errmsg << " but the argument type is ";
argumentType(errmsg, argInfo);
errmsg << ".";
reportError(tok, Severity::warning, "invalidPrintfArgType_uint", errmsg.str());
reportError(tok, Severity::warning, "invalidPrintfArgType_uint", errmsg.str(), CWE686, false);
}
void CheckIO::invalidPrintfArgTypeError_sint(const Token* tok, unsigned int numFormat, const std::string& specifier, const ArgumentInfo* argInfo)
@ -1957,7 +1958,7 @@ void CheckIO::invalidPrintfArgTypeError_sint(const Token* tok, unsigned int numF
errmsg << " but the argument type is ";
argumentType(errmsg, argInfo);
errmsg << ".";
reportError(tok, Severity::warning, "invalidPrintfArgType_sint", errmsg.str());
reportError(tok, Severity::warning, "invalidPrintfArgType_sint", errmsg.str(), CWE686, false);
}
void CheckIO::invalidPrintfArgTypeError_float(const Token* tok, unsigned int numFormat, const std::string& specifier, const ArgumentInfo* argInfo)
{
@ -1970,7 +1971,7 @@ void CheckIO::invalidPrintfArgTypeError_float(const Token* tok, unsigned int num
errmsg << "double\' but the argument type is ";
argumentType(errmsg, argInfo);
errmsg << ".";
reportError(tok, Severity::warning, "invalidPrintfArgType_float", errmsg.str());
reportError(tok, Severity::warning, "invalidPrintfArgType_float", errmsg.str(), CWE686, false);
}
void CheckIO::argumentType(std::ostream& os, const ArgumentInfo * argInfo)

View File

@ -1472,7 +1472,7 @@ void CheckOther::checkPassByReference()
while (tok3 && tok3->str() != "(") {
if (tok3->link() && Token::Match(tok3, ")|]|}|>"))
tok3 = tok3->link();
else if (tok->link())
else if (tok3->link())
break;
else if (tok3->str() == ";")
break;

View File

@ -165,6 +165,20 @@ void CheckStl::iterators()
if (itTok->previous()->str() == "*")
continue;
// inserting iterator range..
if (tok2->strAt(2) == "insert") {
const Token *par2 = itTok->nextArgument();
while (par2 && par2->str() != ")") {
if (par2->varId() == container->declarationId())
break;
if (par2->str() == "(")
par2 = par2->link();
par2 = par2->next();
}
if (par2->varId() == container->declarationId())
continue;
}
// Show error message, mismatching iterator is used.
iteratorsError(tok2, container->name(), tok2->str());
}

View File

@ -101,6 +101,10 @@ void CheckUninitVar::checkScope(const Scope* scope)
if (!tok)
continue;
if (tok->astParent() && Token::simpleMatch(tok->astParent()->previous(), "for (") &&
checkLoopBody(tok->astParent()->link()->next(), *i, i->isArray() ? ARRAY : NO_ALLOC, "", true))
continue;
if (i->isArray()) {
Alloc alloc = ARRAY;
checkScopeForVariable(tok, *i, nullptr, nullptr, &alloc, "");
@ -117,12 +121,12 @@ void CheckUninitVar::checkScope(const Scope* scope)
if (scope->function) {
for (unsigned int i = 0; i < scope->function->argCount(); i++) {
const Variable *arg = scope->function->getArgumentVar(i);
if (arg && arg->declarationId() && Token::Match(arg->typeStartToken(), "struct| %type% * %name% [,)]")) {
if (arg && arg->declarationId() && Token::Match(arg->typeStartToken(), "%type% * %name% [,)]")) {
// Treat the pointer as initialized until it is assigned by malloc
for (const Token *tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
if (Token::Match(tok, "[;{}] %varid% = %name% (", arg->declarationId()) &&
_settings->library.returnuninitdata.count(tok->strAt(3)) == 1U) {
if (arg->typeStartToken()->str() == "struct")
if (arg->typeStartToken()->strAt(-1) == "struct" || (arg->type() && arg->type()->isStructType()))
checkStruct(tok, *arg);
else if (arg->typeStartToken()->isStandardType() || arg->typeStartToken()->isEnumType()) {
Alloc alloc = NO_ALLOC;
@ -138,8 +142,6 @@ void CheckUninitVar::checkScope(const Scope* scope)
void CheckUninitVar::checkStruct(const Token *tok, const Variable &structvar)
{
const Token *typeToken = structvar.typeStartToken();
if (typeToken->str() == "struct")
typeToken = typeToken->next();
const SymbolDatabase * symbolDatabase = _tokenizer->getSymbolDatabase();
for (std::size_t j = 0U; j < symbolDatabase->classAndStructScopes.size(); ++j) {
const Scope *scope2 = symbolDatabase->classAndStructScopes[j];
@ -918,9 +920,12 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc al
if (vartok->previous()->str() != "&" || !Token::Match(vartok->tokAt(-2), "[(,=?:]")) {
if (alloc != NO_ALLOC && vartok->previous()->str() == "*") {
// TestUninitVar::isVariableUsageDeref()
const Token *parent = vartok->previous()->astParent();
if (parent && parent->str() == "=" && parent->astOperand1() == vartok->previous())
return false;
if (vartok->variable() && vartok->variable()->dimensions().size() >= 2)
return false;
return true;
}
return alloc == NO_ALLOC;
@ -1014,9 +1019,9 @@ int CheckUninitVar::isFunctionParUsage(const Token *vartok, bool pointer, Alloc
const Variable *arg = func->getArgumentVar(argumentNumber);
if (arg) {
const Token *argStart = arg->typeStartToken();
if (!address && !array && Token::Match(argStart, "struct| %type% %name%| [,)]"))
if (!address && !array && Token::Match(argStart, "%type% %name%| [,)]"))
return 1;
if (pointer && !address && alloc == NO_ALLOC && Token::Match(argStart, "struct| %type% * %name% [,)]"))
if (pointer && !address && alloc == NO_ALLOC && Token::Match(argStart, "%type% * %name% [,)]"))
return 1;
while (argStart->previous() && argStart->previous()->isName())
argStart = argStart->previous();

View File

@ -1072,6 +1072,11 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
} else if (Token::Match(tok, "[(,] (") &&
Token::Match(tok->next()->link(), ") %var% [,)]")) {
variables.use(tok->next()->link()->next()->varId(), tok); // use = read + write
} else if (Token::Match(tok, "[(,] *| %var% =")) {
tok = tok->next();
if (tok->str() == "*")
tok = tok->next();
variables.use(tok->varId(), tok);
}
// function
@ -1265,6 +1270,17 @@ void CheckUnusedVar::checkStructMemberUsage()
if (Token::findmatch(scope->classEnd, castPattern.c_str()))
continue;
// Bail out if struct is used in sizeof..
for (const Token *tok = scope->classEnd; nullptr != (tok = Token::findsimplematch(tok, "sizeof ("));) {
tok = tok->tokAt(2);
if (Token::Match(tok, ("struct| " + scope->className).c_str())) {
bailout = true;
break;
}
}
if (bailout)
continue;
// Try to prevent false positives when struct members are not used directly.
if (Token::findmatch(scope->classEnd, (scope->className + " %type%| *").c_str()))
continue;

View File

@ -74,21 +74,28 @@ Library::Error Library::load(const char exename[], const char path[])
absolute_path = Path::getAbsoluteFilePath(fullfilename);
}
if (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND) {
// Try to locate the library configuration in the installation folder..
std::list<std::string> cfgfolders;
#ifdef CFGDIR
const std::string cfgfolder(CFGDIR);
#else
if (!exename)
return Error(FILE_NOT_FOUND);
const std::string cfgfolder(Path::fromNativeSeparators(Path::getPathFromFilename(exename)) + "cfg");
cfgfolders.push_back(CFGDIR);
#endif
if (exename) {
const std::string exepath(Path::fromNativeSeparators(Path::getPathFromFilename(exename)));
cfgfolders.push_back(exepath + "cfg");
cfgfolders.push_back(exepath);
}
while (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND && !cfgfolders.empty()) {
const std::string cfgfolder(cfgfolders.front());
cfgfolders.pop_front();
const char *sep = (!cfgfolder.empty() && cfgfolder[cfgfolder.size()-1U]=='/' ? "" : "/");
const std::string filename(cfgfolder + sep + fullfilename);
error = doc.LoadFile(filename.c_str());
if (error != tinyxml2::XML_ERROR_FILE_NOT_FOUND)
absolute_path = Path::getAbsoluteFilePath(filename);
}
if (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND)
return Error(FILE_NOT_FOUND);
} else
absolute_path = Path::getAbsoluteFilePath(path);

View File

@ -44,6 +44,8 @@ namespace tinyxml2 {
* @brief Library definitions handling
*/
class CPPCHECKLIB Library {
friend class TestSymbolDatabase; // For testing only
public:
Library();

View File

@ -496,39 +496,23 @@ std::string Preprocessor::getcode(const simplecpp::TokenList &tokens1, const std
return "";
case simplecpp::Output::WARNING:
break;
case simplecpp::Output::MISSING_INCLUDE: {
case simplecpp::Output::MISSING_HEADER: {
const std::string::size_type pos1 = it->msg.find_first_of("<\"");
const std::string::size_type pos2 = it->msg.find_first_of(">\"", pos1 + 1U);
if (pos1 < pos2 && pos2 != std::string::npos)
missingInclude(it->location.file(), it->location.line, it->msg.substr(pos1+1, pos2-pos1-1), it->msg[pos1] == '\"' ? UserHeader : SystemHeader);
}
break;
case simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY:
case simplecpp::Output::SYNTAX_ERROR:
error(it->location.file(), it->location.line, it->msg);
return "";
};
}
// ensure that guessed define macros without value are not used in the code
for (std::list<std::string>::const_iterator defineIt = dui.defines.begin(); defineIt != dui.defines.end(); ++defineIt) {
if (defineIt->find("=") != std::string::npos)
continue;
const std::string macroName = defineIt->substr(0, std::min(defineIt->find("="), defineIt->find("(")));
for (std::list<simplecpp::MacroUsage>::const_iterator usageIt = macroUsage.begin(); usageIt != macroUsage.end(); ++usageIt) {
const simplecpp::MacroUsage &mu = *usageIt;
if (mu.macroName != macroName)
continue;
bool directiveLocation = false;
for (std::list<Directive>::const_iterator dirIt = directives.begin(); dirIt != directives.end(); ++dirIt) {
if (mu.useLocation.file() == dirIt->file && mu.useLocation.line == dirIt->linenr) {
directiveLocation = true;
break;
}
}
if (!directiveLocation) {
if (_settings.isEnabled("information"))
validateCfgError(cfg, macroName);
return "";
}
}
}
if (!validateCfg(cfg, macroUsage))
return "";
// assembler code locations..
std::set<simplecpp::Location> assemblerLocations;
@ -620,11 +604,13 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string
for (simplecpp::OutputList::const_iterator it = outputList.begin(); it != outputList.end(); ++it) {
switch (it->type) {
case simplecpp::Output::ERROR:
case simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY:
case simplecpp::Output::SYNTAX_ERROR:
error(it->location.file(), it->location.line, it->msg);
return "";
case simplecpp::Output::WARNING:
break;
case simplecpp::Output::MISSING_INCLUDE: {
case simplecpp::Output::MISSING_HEADER: {
const std::string::size_type pos1 = it->msg.find_first_of("<\"");
const std::string::size_type pos2 = it->msg.find_first_of(">\"", pos1 + 1U);
if (pos1 < pos2 && pos2 != std::string::npos)
@ -684,72 +670,42 @@ void Preprocessor::missingInclude(const std::string &filename, unsigned int line
}
}
bool Preprocessor::validateCfg(const std::string &code, const std::string &cfg)
bool Preprocessor::validateCfg(const std::string &cfg, const std::list<simplecpp::MacroUsage> &macroUsageList)
{
const bool printInformation = _settings.isEnabled("information");
// fill up "macros" with empty configuration macros
std::set<std::string> macros;
for (std::string::size_type pos = 0; pos < cfg.size();) {
const std::string::size_type pos2 = cfg.find_first_of(";=", pos);
if (pos2 == std::string::npos) {
macros.insert(cfg.substr(pos));
break;
}
if (cfg[pos2] == ';')
macros.insert(cfg.substr(pos, pos2-pos));
pos = cfg.find(';', pos2);
if (pos != std::string::npos)
++pos;
}
// check if any empty macros are used in code
for (std::set<std::string>::const_iterator it = macros.begin(); it != macros.end(); ++it) {
const std::string &macro = *it;
std::string::size_type pos = 0;
while ((pos = code.find_first_of(std::string("#\"'")+macro[0], pos)) != std::string::npos) {
const std::string::size_type pos1 = pos;
const std::string::size_type pos2 = pos + macro.size();
pos++;
// skip string..
if (code[pos1] == '\"' || code[pos1] == '\'') {
while (pos < code.size() && code[pos] != code[pos1]) {
if (code[pos] == '\\')
++pos;
++pos;
bool ret = true;
std::list<std::string> defines;
splitcfg(cfg, defines, std::string());
for (std::list<std::string>::const_iterator defineIt = defines.begin(); defineIt != defines.end(); ++defineIt) {
if (defineIt->find("=") != std::string::npos)
continue;
const std::string macroName(defineIt->substr(0, defineIt->find("(")));
for (std::list<simplecpp::MacroUsage>::const_iterator usageIt = macroUsageList.begin(); usageIt != macroUsageList.end(); ++usageIt) {
const simplecpp::MacroUsage &mu = *usageIt;
if (mu.macroName != macroName)
continue;
bool directiveLocation = false;
for (std::list<Directive>::const_iterator dirIt = directives.begin(); dirIt != directives.end(); ++dirIt) {
if (mu.useLocation.file() == dirIt->file && mu.useLocation.line == dirIt->linenr) {
directiveLocation = true;
break;
}
++pos;
}
// skip preprocessor statement..
else if (code[pos1] == '#') {
if (pos1 == 0 || code[pos1-1] == '\n')
pos = code.find('\n', pos);
}
// is macro used in code?
else if (code.compare(pos1,macro.size(),macro) == 0) {
if (pos1 > 0 && (std::isalnum((unsigned char)code[pos1-1U]) || code[pos1-1U] == '_'))
continue;
if (pos2 < code.size() && (std::isalnum((unsigned char)code[pos2]) || code[pos2] == '_'))
continue;
// macro is used in code, return false
if (printInformation)
validateCfgError(cfg, macro);
return false;
if (!directiveLocation) {
if (_settings.isEnabled("information"))
validateCfgError(mu.useLocation.file(), mu.useLocation.line, cfg, macroName);
ret = false;
}
}
}
return true;
return ret;
}
void Preprocessor::validateCfgError(const std::string &cfg, const std::string &macro)
void Preprocessor::validateCfgError(const std::string &file, const unsigned int line, const std::string &cfg, const std::string &macro)
{
const std::string id = "ConfigurationNotChecked";
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
ErrorLogger::ErrorMessage::FileLocation loc(file0, 1);
ErrorLogger::ErrorMessage::FileLocation loc(file, line);
locationList.push_back(loc);
ErrorLogger::ErrorMessage errmsg(locationList, file0, Severity::information, "Skipping configuration '" + cfg + "' since the value of '" + macro + "' is unknown. Use -D if you want to check it. You can use -U to skip it explicitly.", id, false);
_errorLogger->reportInfo(errmsg);
@ -762,7 +718,7 @@ void Preprocessor::getErrorMessages(ErrorLogger *errorLogger, const Settings *se
settings2.checkConfiguration=true;
preprocessor.missingInclude("", 1, "", UserHeader);
preprocessor.missingInclude("", 1, "", SystemHeader);
preprocessor.validateCfgError("X", "X");
preprocessor.validateCfgError("", 1, "X", "X");
preprocessor.error("", 1, "#error message"); // #error ..
}

View File

@ -153,12 +153,12 @@ public:
/**
* make sure empty configuration macros are not used in code. the given code must be a single configuration
* @param code The input code
* @param cfg configuration
* @param macroUsageList macro usage list
* @return true => configuration is valid
*/
bool validateCfg(const std::string &code, const std::string &cfg);
void validateCfgError(const std::string &cfg, const std::string &macro);
bool validateCfg(const std::string &cfg, const std::list<simplecpp::MacroUsage> &macroUsageList);
void validateCfgError(const std::string &file, const unsigned int line, const std::string &cfg, const std::string &macro);
private:

View File

@ -293,6 +293,23 @@ public:
platformType == Win64;
}
const char *platformString() const {
switch (platformType) {
case Unix32:
return "unix32";
case Unix64:
return "unix64";
case Win32A:
return "win32A";
case Win32W:
return "win32W";
case Win64:
return "win64";
default:
return "unknown";
}
}
/**
* @brief return true if a file is to be excluded from configuration checking
* @return true for the file to be excluded.

View File

@ -1088,19 +1088,19 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
if (start != end && start->next() != end) {
for (Token* tok = start->next(); tok != end; tok = tok->next()) {
if (tok->str() == "{") {
bool break2 = false;
bool isEndOfScope = false;
for (std::list<Scope*>::const_iterator innerScope = it->nestedList.begin(); innerScope != it->nestedList.end(); ++innerScope) {
if (tok == (*innerScope)->classStart) { // Is begin of inner scope
tok = tok->link();
if (!tok || tok->next() == end || !tok->next()) {
break2 = true;
isEndOfScope = true;
break;
}
tok = tok->next();
break;
}
}
if (break2)
if (isEndOfScope)
break;
}
tok->scope(&*it);
@ -1817,9 +1817,9 @@ bool Function::argsMatch(const Scope *scope, const Token *first, const Token *se
second = second->next();
// skip "struct"
if (first->str() == "struct")
if (first->str() == "struct" || first->str() == "enum")
first = first->next();
if (second->str() == "struct")
if (second->str() == "struct" || second->str() == "enum")
second = second->next();
// skip const on type passed by value
@ -2402,7 +2402,7 @@ void SymbolDatabase::printVariable(const Variable *var, const char *indent) cons
std::cout << indent << " isStlType: " << var->isStlType() << std::endl;
std::cout << indent << "_type: ";
if (var->type()) {
std::cout << var->type()->name();
std::cout << var->type()->type() << " " << var->type()->name();
std::cout << " " << _tokenizer->list.fileLine(var->type()->classDef);
std::cout << " " << var->type() << std::endl;
} else
@ -2466,6 +2466,7 @@ void SymbolDatabase::printOut(const char *title) const
std::cout << " isOperator: " << func->isOperator() << std::endl;
std::cout << " hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl;
std::cout << " hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl;
std::cout << " isVariadic: " << func->isVariadic() << std::endl;
std::cout << " attributes:";
if (func->isAttributeConst())
std::cout << " const ";
@ -2818,10 +2819,19 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
} while (tok->str() != "," && tok->str() != ")");
}
// skip over stuff before type
while (Token::Match(startTok, "enum|struct|const"))
startTok = startTok->next();
argumentList.push_back(Variable(nameTok, startTok, endTok, count++, Argument, argType, functionScope, &symbolDatabase->_settings->library));
if (tok->str() == ")")
if (tok->str() == ")") {
// check for a variadic function
if (Token::simpleMatch(startTok, ". . ."))
isVariadic(true);
break;
}
}
// count default arguments
@ -3177,6 +3187,10 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess, con
const_cast<Token *>(typetok)->type(vType);
}
// skip "enum" or "struct"
if (Token::Match(typestart, "enum|struct"))
typestart = typestart->next();
addVariable(vartok, typestart, vartok->previous(), varaccess, vType, this, lib);
}
@ -3462,10 +3476,17 @@ const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *ty
}
}
const Type * type = findVariableTypeInBase(scope, typeTok);
if (scope) {
const Type * type = scope->findType(typeTok->str());
if (type)
return type;
if (type)
return type;
type = findVariableTypeInBase(scope, typeTok);
if (type)
return type;
}
}
std::list<Type>::const_iterator type;
@ -3490,8 +3511,27 @@ const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *ty
break;
}
if (type->enclosingScope == parent)
return &(*type);
if (type->enclosingScope == parent) {
// check if "enum" specified and type is enum
if (typeTok->strAt(-1) == "enum") {
if (type->isEnumType())
return &(*type);
else // not an enum
continue;
}
// check if "struct" specified and type is struct
else if (typeTok->strAt(-1) == "struct") {
if (type->isStructType())
return &(*type);
else // not a struct
continue;
}
// "enum" or "struct" not specified so assume match
else
return &(*type);
}
}
// type has a namespace
@ -3584,7 +3624,9 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
const std::size_t args = arguments.size();
for (std::multimap<std::string, const Function *>::const_iterator it = functionMap.find(tok->str()); it != functionMap.end() && it->first == tok->str(); ++it) {
const Function *func = it->second;
if (args == func->argCount() || (args < func->argCount() && args >= func->minArgCount())) {
if (args == func->argCount() ||
(func->isVariadic() && args >= (func->argCount() - 1)) ||
(args < func->argCount() && args >= func->minArgCount())) {
matches.push_back(func);
}
}
@ -3598,6 +3640,10 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
const Function * func = matches[i];
size_t same = 0;
for (std::size_t j = 0; j < args; ++j) {
// don't check variadic arguments
if (func->isVariadic() && j > (func->argCount() - 1)) {
break;
}
const Variable *funcarg = func->getArgumentVar(j);
// check for a match with a variable
if (Token::Match(arguments[j], "%var% ,|)")) {
@ -3610,6 +3656,25 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
}
}
// check for a match with address of a variable
else if (Token::Match(arguments[j], "& %var% ,|)")) {
const Variable * callarg = check->getVariableFromVarId(arguments[j]->next()->varId());
if (callarg) {
if (funcarg->typeEndToken()->str() == "*" &&
(funcarg->typeStartToken()->str() == "void" ||
(callarg->typeStartToken()->str() == funcarg->typeStartToken()->str() &&
callarg->typeStartToken()->isUnsigned() == funcarg->typeStartToken()->isUnsigned() &&
callarg->typeStartToken()->isLong() == funcarg->typeStartToken()->isLong()))) {
same++;
} else {
// can't match so remove this function from possible matches
matches.erase(matches.begin() + i);
erased = true;
break;
}
}
}
// check for a match with a numeric literal
else if (Token::Match(arguments[j], "%num% ,|)")) {
if (MathLib::isInt(arguments[j]->str())) {
@ -3682,6 +3747,14 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
}
}
// check for a match with a string literal
else if (Token::Match(arguments[j], "%str% ,|)") &&
funcarg->typeStartToken() != funcarg->typeEndToken() &&
((!arguments[j]->isLong() && Token::simpleMatch(funcarg->typeStartToken(), "char *")) ||
(arguments[j]->isLong() && Token::simpleMatch(funcarg->typeStartToken(), "wchar_t *")))) {
same++;
}
// check that function argument type is not mismatching
else if (arguments[j]->str() == "&" && funcarg && funcarg->isReference()) {
// can't match so remove this function from possible matches
@ -3692,7 +3765,8 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
}
// check if all arguments matched
if (same == args) {
if ((func->isVariadic() && same == (func->argCount() - 1)) ||
(!func->isVariadic() && same == args)) {
if (requireConst && func->isConst())
return func;
@ -4099,21 +4173,21 @@ unsigned int SymbolDatabase::sizeOfType(const Token *type) const
return size;
}
static const Token * parsedecl(const Token *type, ValueType * const valuetype, ValueType::Sign defaultSignedness, const Library* lib);
static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, ValueType::Sign defaultSignedness, const Library* lib);
static const Token * parsedecl(const Token *type, ValueType * const valuetype, ValueType::Sign defaultSignedness, const Settings* settings);
static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, ValueType::Sign defaultSignedness, const Settings* settings);
static void setValueType(Token *tok, const Variable &var, bool cpp, ValueType::Sign defaultSignedness, const Library* lib)
static void setValueType(Token *tok, const Variable &var, bool cpp, ValueType::Sign defaultSignedness, const Settings* settings)
{
if (var.isStlType())
return;
ValueType valuetype;
valuetype.pointer = var.dimensions().size();
valuetype.typeScope = var.typeScope();
if (parsedecl(var.typeStartToken(), &valuetype, defaultSignedness, lib))
setValueType(tok, valuetype, cpp, defaultSignedness, lib);
if (parsedecl(var.typeStartToken(), &valuetype, defaultSignedness, settings))
setValueType(tok, valuetype, cpp, defaultSignedness, settings);
}
static void setValueType(Token *tok, const Enumerator &enumerator, bool cpp, ValueType::Sign defaultSignedness, const Library* lib)
static void setValueType(Token *tok, const Enumerator &enumerator, bool cpp, ValueType::Sign defaultSignedness, const Settings* settings)
{
ValueType valuetype;
valuetype.typeScope = enumerator.scope;
@ -4135,22 +4209,18 @@ static void setValueType(Token *tok, const Enumerator &enumerator, bool cpp, Val
else if (type->str() == "long")
valuetype.type = type->isLong() ? ValueType::Type::LONGLONG : ValueType::Type::LONG;
else if (type->isStandardType()) {
const Library::PodType* podtype = lib->podtype(type->str());
if (podtype && (podtype->sign == 's' || podtype->sign == 'u')) {
valuetype.type = ValueType::Type::UNKNOWN_INT;
valuetype.sign = (podtype->sign == 'u') ? ValueType::UNSIGNED : ValueType::SIGNED;
}
valuetype.fromLibraryType(type->str(), settings);
}
setValueType(tok, valuetype, cpp, defaultSignedness, lib);
setValueType(tok, valuetype, cpp, defaultSignedness, settings);
} else {
valuetype.sign = ValueType::SIGNED;
valuetype.type = ValueType::INT;
setValueType(tok, valuetype, cpp, defaultSignedness, lib);
setValueType(tok, valuetype, cpp, defaultSignedness, settings);
}
}
static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, ValueType::Sign defaultSignedness, const Library* lib)
static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, ValueType::Sign defaultSignedness, const Settings* settings)
{
tok->setValueType(new ValueType(valuetype));
Token *parent = const_cast<Token *>(tok->astParent());
@ -4164,32 +4234,32 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
if (vt1 && Token::Match(parent, "<<|>>")) {
if (!cpp || (vt2 && vt2->isIntegral()))
setValueType(parent, *vt1, cpp, defaultSignedness, lib);
setValueType(parent, *vt1, cpp, defaultSignedness, settings);
return;
}
if (parent->isAssignmentOp()) {
if (vt1)
setValueType(parent, *vt1, cpp, defaultSignedness, lib);
setValueType(parent, *vt1, cpp, defaultSignedness, settings);
return;
}
if (parent->str() == "[" && (!cpp || parent->astOperand1() == tok) && valuetype.pointer > 0U) {
ValueType vt(valuetype);
vt.pointer -= 1U;
setValueType(parent, vt, cpp, defaultSignedness, lib);
setValueType(parent, vt, cpp, defaultSignedness, settings);
return;
}
if (parent->str() == "*" && !parent->astOperand2() && valuetype.pointer > 0U) {
ValueType vt(valuetype);
vt.pointer -= 1U;
setValueType(parent, vt, cpp, defaultSignedness, lib);
setValueType(parent, vt, cpp, defaultSignedness, settings);
return;
}
if (parent->str() == "&" && !parent->astOperand2()) {
ValueType vt(valuetype);
vt.pointer += 1U;
setValueType(parent, vt, cpp, defaultSignedness, lib);
setValueType(parent, vt, cpp, defaultSignedness, settings);
return;
}
@ -4209,7 +4279,7 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
}
}
if (var)
setValueType(parent, *var, cpp, defaultSignedness, lib);
setValueType(parent, *var, cpp, defaultSignedness, settings);
return;
}
@ -4224,33 +4294,33 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
if (ternary || parent->isArithmeticalOp() || parent->tokType() == Token::eIncDecOp) {
if (vt1->pointer != 0U && vt2 && vt2->pointer == 0U) {
setValueType(parent, *vt1, cpp, defaultSignedness, lib);
setValueType(parent, *vt1, cpp, defaultSignedness, settings);
return;
}
if (vt1->pointer == 0U && vt2 && vt2->pointer != 0U) {
setValueType(parent, *vt2, cpp, defaultSignedness, lib);
setValueType(parent, *vt2, cpp, defaultSignedness, settings);
return;
}
if (vt1->pointer != 0U) {
if (ternary || parent->tokType() == Token::eIncDecOp) // result is pointer
setValueType(parent, *vt1, cpp, defaultSignedness, lib);
setValueType(parent, *vt1, cpp, defaultSignedness, settings);
else // result is pointer diff
setValueType(parent, ValueType(ValueType::Sign::SIGNED, ValueType::Type::INT, 0U, 0U, "ptrdiff_t"), cpp, defaultSignedness, lib);
setValueType(parent, ValueType(ValueType::Sign::SIGNED, ValueType::Type::INT, 0U, 0U, "ptrdiff_t"), cpp, defaultSignedness, settings);
return;
}
if (vt1->type == ValueType::Type::LONGDOUBLE || (vt2 && vt2->type == ValueType::Type::LONGDOUBLE)) {
setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::LONGDOUBLE, 0U), cpp, defaultSignedness, lib);
setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::LONGDOUBLE, 0U), cpp, defaultSignedness, settings);
return;
}
if (vt1->type == ValueType::Type::DOUBLE || (vt2 && vt2->type == ValueType::Type::DOUBLE)) {
setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::DOUBLE, 0U), cpp, defaultSignedness, lib);
setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::DOUBLE, 0U), cpp, defaultSignedness, settings);
return;
}
if (vt1->type == ValueType::Type::FLOAT || (vt2 && vt2->type == ValueType::Type::FLOAT)) {
setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::FLOAT, 0U), cpp, defaultSignedness, lib);
setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::FLOAT, 0U), cpp, defaultSignedness, settings);
return;
}
}
@ -4284,12 +4354,12 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
vt.originalTypeName.clear();
}
setValueType(parent, vt, cpp, defaultSignedness, lib);
setValueType(parent, vt, cpp, defaultSignedness, settings);
return;
}
}
static const Token * parsedecl(const Token *type, ValueType * const valuetype, ValueType::Sign defaultSignedness, const Library* lib)
static const Token * parsedecl(const Token *type, ValueType * const valuetype, ValueType::Sign defaultSignedness, const Settings* settings)
{
const unsigned int pointer0 = valuetype->pointer;
while (Token::Match(type->previous(), "%name%"))
@ -4333,13 +4403,8 @@ static const Token * parsedecl(const Token *type, ValueType * const valuetype, V
return nullptr;
else if (type->str() == "*")
valuetype->pointer++;
else if (type->isStandardType()) {
const Library::PodType* podtype = lib->podtype(type->str());
if (podtype && (podtype->sign == 's' || podtype->sign == 'u')) {
valuetype->type = ValueType::Type::UNKNOWN_INT;
valuetype->sign = (podtype->sign == 'u') ? ValueType::UNSIGNED : ValueType::SIGNED;
}
}
else if (type->isStandardType())
valuetype->fromLibraryType(type->str(), settings);
if (!type->originalName().empty())
valuetype->originalTypeName = type->originalName();
type = type->next();
@ -4386,12 +4451,12 @@ static const Function *getOperatorFunction(const Token * const tok)
return nullptr;
}
void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, char defaultSignedness, const Library* lib)
void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, const Settings* settings)
{
ValueType::Sign defsign;
if (defaultSignedness == 's' || defaultSignedness == 'S')
if (settings->defaultSign == 's' || settings->defaultSign == 'S')
defsign = ValueType::SIGNED;
else if (defaultSignedness == 'u' || defaultSignedness == 'U')
else if (settings->defaultSign == 'u' || settings->defaultSign == 'U')
defsign = ValueType::UNSIGNED;
else
defsign = ValueType::UNKNOWN_SIGN;
@ -4406,7 +4471,7 @@ void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, char defau
const char suffix = tok->str()[tok->str().size() - 1U];
if (suffix == 'f' || suffix == 'F')
type = ValueType::Type::FLOAT;
::setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, type, 0U), cpp, defsign, lib);
::setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, type, 0U), cpp, defsign, settings);
} else if (MathLib::isInt(tok->str())) {
ValueType::Sign sign = ValueType::Sign::SIGNED;
ValueType::Type type = ValueType::Type::INT;
@ -4423,71 +4488,117 @@ void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, char defau
pos -= 2;
} else break;
}
::setValueType(tok, ValueType(sign, type, 0U), cpp, defsign, lib);
::setValueType(tok, ValueType(sign, type, 0U), cpp, defsign, settings);
}
} else if (tok->isComparisonOp() || tok->tokType() == Token::eLogicalOp) {
if (cpp && tok->isComparisonOp() && (getClassScope(tok->astOperand1()) || getClassScope(tok->astOperand2()))) {
const Function *function = getOperatorFunction(tok);
if (function) {
ValueType vt;
parsedecl(function->retDef, &vt, defsign, lib);
::setValueType(tok, vt, cpp, defsign, lib);
parsedecl(function->retDef, &vt, defsign, settings);
::setValueType(tok, vt, cpp, defsign, settings);
continue;
}
}
::setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0U), cpp, defsign, lib);
::setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0U), cpp, defsign, settings);
} else if (tok->tokType() == Token::eChar)
::setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, 0U), cpp, defsign, lib);
::setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, 0U), cpp, defsign, settings);
else if (tok->tokType() == Token::eString) {
ValueType valuetype(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, 1U, 1U);
if (tok->isLong()) {
valuetype.originalTypeName = "wchar_t";
valuetype.type = ValueType::Type::SHORT;
}
::setValueType(tok, valuetype, cpp, defsign, lib);
::setValueType(tok, valuetype, cpp, defsign, settings);
} else if (tok->str() == "(") {
// cast
if (!tok->astOperand2() && Token::Match(tok, "( %name%")) {
ValueType valuetype;
if (Token::simpleMatch(parsedecl(tok->next(), &valuetype, defsign, lib), ")"))
::setValueType(tok, valuetype, cpp, defsign, lib);
if (Token::simpleMatch(parsedecl(tok->next(), &valuetype, defsign, settings), ")"))
::setValueType(tok, valuetype, cpp, defsign, settings);
}
// C++ cast
if (tok->astOperand2() && Token::Match(tok->astOperand1(), "static_cast|const_cast|dynamic_cast|reinterpret_cast < %name%") && tok->astOperand1()->linkAt(1)) {
ValueType valuetype;
if (Token::simpleMatch(parsedecl(tok->astOperand1()->tokAt(2), &valuetype, defsign, lib), ">"))
::setValueType(tok, valuetype, cpp, defsign, lib);
if (Token::simpleMatch(parsedecl(tok->astOperand1()->tokAt(2), &valuetype, defsign, settings), ">"))
::setValueType(tok, valuetype, cpp, defsign, settings);
}
// function
else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->retDef) {
ValueType valuetype;
if (parsedecl(tok->previous()->function()->retDef, &valuetype, defsign, lib))
::setValueType(tok, valuetype, cpp, defsign, lib);
if (parsedecl(tok->previous()->function()->retDef, &valuetype, defsign, settings))
::setValueType(tok, valuetype, cpp, defsign, settings);
}
else if (Token::simpleMatch(tok->previous(), "sizeof (")) {
// TODO: use specified size_t type
ValueType valuetype(ValueType::Sign::UNSIGNED, ValueType::Type::LONG, 0U);
valuetype.originalTypeName = "size_t";
setValueType(tok, valuetype, cpp, defsign, lib);
setValueType(tok, valuetype, cpp, defsign, settings);
if (Token::Match(tok, "( %type% %type%| *| *| )")) {
ValueType vt;
if (parsedecl(tok->next(), &vt, defsign, lib)) {
setValueType(tok->next(), vt, cpp, defsign, lib);
if (parsedecl(tok->next(), &vt, defsign, settings)) {
setValueType(tok->next(), vt, cpp, defsign, settings);
}
}
}
} else if (tok->variable()) {
setValueType(tok, *tok->variable(), cpp, defsign, lib);
setValueType(tok, *tok->variable(), cpp, defsign, settings);
} else if (tok->enumerator()) {
setValueType(tok, *tok->enumerator(), cpp, defsign, lib);
setValueType(tok, *tok->enumerator(), cpp, defsign, settings);
}
}
}
bool ValueType::fromLibraryType(const std::string &typestr, const Settings *settings)
{
const Library::PodType* podtype = settings->library.podtype(typestr);
if (podtype && (podtype->sign == 's' || podtype->sign == 'u')) {
if (podtype->size == 1)
type = ValueType::Type::CHAR;
else if (podtype->size == settings->sizeof_int)
type = ValueType::Type::INT;
else if (podtype->size == settings->sizeof_short)
type = ValueType::Type::SHORT;
else if (podtype->size == settings->sizeof_long)
type = ValueType::Type::LONG;
else if (podtype->size == settings->sizeof_long_long)
type = ValueType::Type::LONGLONG;
else
type = ValueType::Type::UNKNOWN_INT;
sign = (podtype->sign == 'u') ? ValueType::UNSIGNED : ValueType::SIGNED;
return true;
}
const Library::PlatformType *platformType = settings->library.platform_type(typestr, settings->platformString());
if (platformType) {
if (platformType->_type == "char")
type = ValueType::Type::CHAR;
else if (platformType->_type == "short")
type = ValueType::Type::SHORT;
else if (platformType->_type == "int")
type = platformType->_long ? ValueType::Type::LONG : ValueType::Type::INT;
else if (platformType->_type == "long")
type = platformType->_long ? ValueType::Type::LONGLONG : ValueType::Type::LONG;
if (platformType->_signed)
sign = ValueType::SIGNED;
else if (platformType->_unsigned)
sign = ValueType::UNSIGNED;
if (platformType->_pointer)
pointer = 1;
if (platformType->_ptr_ptr)
pointer = 2;
if (platformType->_const_ptr)
constness = 1;
return true;
}
return false;
}
std::string ValueType::str() const
{
std::string ret;

View File

@ -109,10 +109,22 @@ public:
const std::string& name() const;
const std::string& type() const {
return classDef ? classDef->str() : emptyString;
}
bool isClassType() const {
return classDef && classDef->str() == "class";
}
bool isEnumType() const {
return classDef && classDef->str() == "enum";
}
bool isStructType() const {
return classDef && classDef->str() == "struct";
}
const Token *initBaseInfo(const Token *tok, const Token *tok1);
const Function* getFunction(const std::string& funcName) const;
@ -628,7 +640,8 @@ class CPPCHECKLIB Function {
fIsThrow = (1 << 13), /** @brief is throw */
fIsOperator = (1 << 14), /** @brief is operator */
fHasLvalRefQual = (1 << 15), /** @brief has & lvalue ref-qualifier */
fHasRvalRefQual = (1 << 16) /** @brief has && rvalue ref-qualifier */
fHasRvalRefQual = (1 << 16), /** @brief has && rvalue ref-qualifier */
fIsVariadic = (1 << 17) /** @brief is variadic */
};
/**
@ -766,6 +779,9 @@ public:
bool hasRvalRefQualifier() const {
return getFlag(fHasRvalRefQual);
}
bool isVariadic() const {
return getFlag(fIsVariadic);
}
void hasBody(bool state) {
setFlag(fHasBody, state);
@ -818,6 +834,9 @@ public:
void hasRvalRefQualifier(bool state) {
setFlag(fHasRvalRefQual, state);
}
void isVariadic(bool state) {
setFlag(fIsVariadic, state);
}
const Token *tokenDef; // function name token in class definition
const Token *argDef; // function argument start '(' in class definition
@ -1071,7 +1090,7 @@ public:
void validateVariables() const;
/** Set valuetype in provided tokenlist */
static void setValueTypeInTokenList(Token *tokens, bool cpp, char defaultSignedness, const Library* lib);
static void setValueTypeInTokenList(Token *tokens, bool cpp, const Settings *settings);
/**
* Calculates sizeof value for given type.
@ -1129,6 +1148,8 @@ public:
return (type >= ValueType::Type::BOOL && type <= ValueType::Type::UNKNOWN_INT);
}
bool fromLibraryType(const std::string &typestr, const Settings *settings);
std::string str() const;
};

View File

@ -1720,7 +1720,7 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration)
}
}
SymbolDatabase::setValueTypeInTokenList(list.front(), isCPP(), _settings->defaultSign, &_settings->library);
SymbolDatabase::setValueTypeInTokenList(list.front(), isCPP(), _settings);
ValueFlow::setValues(&list, _symbolDatabase, _errorLogger, _settings);
printDebugOutput(1);
@ -2548,7 +2548,7 @@ static const std::set<std::string> notstart_c = make_container< std::set<std::st
<< "goto" << "NOT" << "return" << "sizeof"<< "typedef";
static const std::set<std::string> notstart_cpp = make_container< std::set<std::string> > ()
<< notstart_c
<< "delete" << "friend" << "new" << "throw" << "using" << "virtual" << "explicit" << "const_cast" << "dynamic_cast" << "reinterpret_cast" << "static_cast" ;
<< "delete" << "friend" << "new" << "throw" << "using" << "virtual" << "explicit" << "const_cast" << "dynamic_cast" << "reinterpret_cast" << "static_cast" << "template";
void Tokenizer::setVarIdPass1()
{
@ -3049,7 +3049,7 @@ void Tokenizer::createLinks2()
} else if (token->str() == ">") {
if (type.empty() || type.top()->str() != "<") // < and > don't match.
continue;
if (token->next() && !Token::Match(token->next(), "%name%|>|&|*|::|,|(|)|{|;|[|:"))
if (token->next() && !Token::Match(token->next(), "%name%|>|&|*|::|,|(|)|{|}|;|[|:"))
continue;
// if > is followed by [ .. "new a<b>[" is expected
@ -3767,7 +3767,7 @@ bool Tokenizer::simplifyTokenList2()
// Create symbol database and then remove const keywords
createSymbolDatabase();
SymbolDatabase::setValueTypeInTokenList(list.front(), isCPP(), _settings->defaultSign, &_settings->library);
SymbolDatabase::setValueTypeInTokenList(list.front(), isCPP(), _settings);
ValueFlow::setValues(&list, _symbolDatabase, _errorLogger, _settings);
@ -5207,6 +5207,9 @@ void Tokenizer::simplifyFunctionPointers()
else if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|,|(|public:|protected:|private:"))
continue;
if (Token::Match(tok, "delete|else|return|throw|typedef"))
continue;
while (Token::Match(tok, "%type%|:: %type%|::"))
tok = tok->next();
@ -5579,17 +5582,14 @@ void Tokenizer::simplifyPlatformTypes()
enum { isLongLong, isLong, isInt } type;
/** @todo This assumes a flat address space. Not true for segmented address space (FAR *). */
if (_settings->sizeof_size_t == 8) {
if (_settings->sizeof_long == 8)
type = isLong;
else
type = isLongLong;
} else if (_settings->sizeof_size_t == 4) {
if (_settings->sizeof_long == 4)
type = isLong;
else
type = isInt;
} else
if (_settings->sizeof_size_t == _settings->sizeof_long)
type = isLong;
else if (_settings->sizeof_size_t == _settings->sizeof_long_long)
type = isLongLong;
else if (_settings->sizeof_size_t == _settings->sizeof_int)
type = isInt;
else
return;
for (Token *tok = list.front(); tok; tok = tok->next()) {
@ -5636,53 +5636,50 @@ void Tokenizer::simplifyPlatformTypes()
}
}
if (_settings->isWindowsPlatform()) {
std::string platform_type = _settings->platformType == Settings::Win32A ? "win32A" :
_settings->platformType == Settings::Win32W ? "win32W" : "win64";
const std::string platform_type(_settings->platformString());
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->tokType() != Token::eType && tok->tokType() != Token::eName)
continue;
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->tokType() != Token::eType && tok->tokType() != Token::eName)
continue;
const Library::PlatformType * const platformtype = _settings->library.platform_type(tok->str(), platform_type);
const Library::PlatformType * const platformtype = _settings->library.platform_type(tok->str(), platform_type);
if (platformtype) {
// check for namespace
if (tok->strAt(-1) == "::") {
const Token * tok1 = tok->tokAt(-2);
// skip when non-global namespace defined
if (tok1 && tok1->tokType() == Token::eName)
continue;
tok = tok->tokAt(-1);
tok->deleteThis();
}
Token *typeToken;
if (platformtype->_const_ptr) {
tok->str("const");
tok->insertToken("*");
tok->insertToken(platformtype->_type);
typeToken = tok;
} else if (platformtype->_pointer) {
tok->str(platformtype->_type);
typeToken = tok;
tok->insertToken("*");
} else if (platformtype->_ptr_ptr) {
tok->str(platformtype->_type);
typeToken = tok;
tok->insertToken("*");
tok->insertToken("*");
} else {
tok->originalName(tok->str());
tok->str(platformtype->_type);
typeToken = tok;
}
if (platformtype->_signed)
typeToken->isSigned(true);
if (platformtype->_unsigned)
typeToken->isUnsigned(true);
if (platformtype->_long)
typeToken->isLong(true);
if (platformtype) {
// check for namespace
if (tok->strAt(-1) == "::") {
const Token * tok1 = tok->tokAt(-2);
// skip when non-global namespace defined
if (tok1 && tok1->tokType() == Token::eName)
continue;
tok = tok->tokAt(-1);
tok->deleteThis();
}
Token *typeToken;
if (platformtype->_const_ptr) {
tok->str("const");
tok->insertToken("*");
tok->insertToken(platformtype->_type);
typeToken = tok;
} else if (platformtype->_pointer) {
tok->str(platformtype->_type);
typeToken = tok;
tok->insertToken("*");
} else if (platformtype->_ptr_ptr) {
tok->str(platformtype->_type);
typeToken = tok;
tok->insertToken("*");
tok->insertToken("*");
} else {
tok->originalName(tok->str());
tok->str(platformtype->_type);
typeToken = tok;
}
if (platformtype->_signed)
typeToken->isSigned(true);
if (platformtype->_unsigned)
typeToken->isUnsigned(true);
if (platformtype->_long)
typeToken->isLong(true);
}
}
}
@ -7576,10 +7573,14 @@ void Tokenizer::syntaxError(const Token *tok) const
void Tokenizer::syntaxError(const Token *tok, char c) const
{
printDebugOutput(0);
throw InternalError(tok,
std::string("Invalid number of character '") + c + "' " +
"when these macros are defined: '" + _configuration + "'.",
InternalError::SYNTAX);
if (_configuration.empty())
throw InternalError(tok,
std::string("Invalid number of character '") + c + "' when no macros are defined.",
InternalError::SYNTAX);
else
throw InternalError(tok,
std::string("Invalid number of character '") + c + "' when these macros are defined: '" + _configuration + "'.",
InternalError::SYNTAX);
}
void Tokenizer::unhandled_macro_class_x_y(const Token *tok) const

View File

@ -695,6 +695,10 @@ Checking test.c...
configuration files. It is available in the <literal>View</literal>
menu. All settings are not documented in this manual.</para>
<para>If you have a question about the <literal>.cfg</literal> file
format it is recommended you ask in the forum
(http://sourceforge.net/p/cppcheck/discussion/).</para>
<para>The command line cppcheck will try to load custom .cfg files from
the working path - execute cppcheck from the path where the .cfg files
are.</para>
@ -1118,6 +1122,23 @@ Checking minsize.c...
</varlistentry>
</variablelist>
</section>
<section>
<title>strz</title>
<para>This setting is not used by Cppcheck currently. But with this
you can say that an argument must be a zero-terminated
string.</para>
<para><programlisting>&lt;?xml version="1.0"?&gt;
&lt;def&gt;
&lt;function name="do_something"&gt;
&lt;arg nr="1"&gt;
&lt;strz/&gt;
&lt;/arg&gt;
&lt;/function&gt;
&lt;/def&gt;</programlisting></para>
</section>
</section>
<section>
@ -1209,11 +1230,19 @@ Checking useretval.c...
</section>
<section>
<title>pure</title>
<title>pure and const</title>
<para>A function that is pure will calculate a return value and has no
side effects. If the same parameters are given twice then the same
return value will be calculated twice.</para>
<para>These correspond to the GCC function attributes pure and
const.</para>
<para>A pure function has no effects except to return a value, and its
return value depends only on the parameters and global
variables.</para>
<para>A const function has no effects except to return a value, and
its return value depends only on the parameters.</para>
<para>Here is an example code:</para>
<programlisting>void f(int x)
{
@ -1224,24 +1253,29 @@ Checking useretval.c...
}
}</programlisting>
<para>Cppcheck reports no warning</para>
<para>If <literal>calculate()</literal> is a const function then the
result of <literal>calculate(x)</literal> will be the same in both
conditions, since the same parameter value is used.</para>
<programlisting># cppcheck pure.c
Checking pure.c...</programlisting>
<para>Cppcheck normally assumes that the result might be different,
and reports no warning for the code:</para>
<para>If a proper <literal>lib.cfg</literal> is provided, the
<programlisting># cppcheck const.c
Checking const.c...</programlisting>
<para>If a proper <literal>const.cfg</literal> is provided, the
unreachable code is detected:</para>
<programlisting># cppcheck --enable=style --library=pure pure.c
Checking pure.c...
[pure.c:7]: (style) Expression is always false because 'else if' condition matches previous condition at line 5.</programlisting>
<programlisting># cppcheck --enable=style --library=const const.c
Checking const.c...
[const.c:7]: (style) Expression is always false because 'else if' condition matches previous condition at line 5.</programlisting>
<para>Here is a minimal <literal>pure.cfg</literal> file:</para>
<para>Here is a minimal <literal>const.cfg</literal> file:</para>
<programlisting>&lt;?xml version="1.0"?&gt;
&lt;def&gt;
&lt;function name="calculate"&gt;
&lt;pure/&gt;
&lt;const/&gt;
&lt;arg nr="1"/&gt;
&lt;/function&gt;
&lt;/def&gt;</programlisting>

View File

@ -1 +1 @@
[samples\syntaxError\bad.c:2]: (error) Invalid number of character '{' when these macros are defined: ''.
[samples\syntaxError\bad.c:2]: (error) Invalid number of character '{' when no macros are defined.

View File

@ -1073,7 +1073,7 @@ private:
tokenizer.tokenize(istr, "test.cpp");
assertThrowFail(__FILE__, __LINE__);
} catch (InternalError& e) {
ASSERT_EQUALS("Invalid number of character '(' when these macros are defined: ''.", e.errorMessage);
ASSERT_EQUALS("Invalid number of character '(' when no macros are defined.", e.errorMessage);
ASSERT_EQUALS("syntaxError", e.id);
ASSERT_EQUALS(2, e.token->linenr());
}

View File

@ -3815,6 +3815,11 @@ private:
" return A ? x : z;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(unsigned char c) {\n"
" x = y ? (signed char)c : (unsigned char)c;\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void checkSignOfUnsignedVariable() {

View File

@ -128,7 +128,6 @@ private:
TEST_CASE(if_cond12);
TEST_CASE(if_cond13);
TEST_CASE(if_cond14);
TEST_CASE(if_cond15); // #4456 - segfault
TEST_CASE(if_or_1);
TEST_CASE(if_or_2);
@ -267,6 +266,22 @@ private:
}
}
std::string getConfigsStr(const char filedata[], const char *u1=NULL) {
Settings settings;
if (u1)
settings.userUndefs.insert(u1);
Preprocessor preprocessor(settings, this);
std::vector<std::string> files;
std::istringstream istr(filedata);
simplecpp::TokenList tokens(istr,files);
tokens.removeComments();
const std::set<std::string> configs = preprocessor.getConfigs(tokens);
std::string ret;
for (std::set<std::string>::const_iterator it = configs.begin(); it != configs.end(); ++it)
ret += *it + '\n';
return ret;
}
void Bug2190219() {
const char filedata[] = "#ifdef __cplusplus\n"
"cpp\n"
@ -304,14 +319,7 @@ private:
" qwerty\n"
"#endif \n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\n\n\nqwerty", actual[""]);
ASSERT_EQUALS("\nabcdef", actual["WIN32"]);
ASSERT_EQUALS("\nWIN32\n", getConfigsStr(filedata));
}
void test2() {
@ -320,15 +328,7 @@ private:
" # else \n"
" qwerty\n"
" # endif \n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(2U, actual.size());
ASSERT_EQUALS("\n\" # ifdef WIN32\"", actual[""]);
ASSERT_EQUALS("\n\n\nqwerty", actual["WIN32"]);
ASSERT_EQUALS("\nWIN32\n", getConfigsStr(filedata));
}
void test3() {
@ -340,15 +340,7 @@ private:
"c\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("", actual[""]);
ASSERT_EQUALS("\na\n\n\n\nc", actual["ABC"]);
ASSERT_EQUALS("\na\n\nb\n\nc", actual["ABC;DEF"]);
ASSERT_EQUALS("\nABC\nABC;DEF\n", getConfigsStr(filedata));
}
void test4() {
@ -358,15 +350,7 @@ private:
"#ifdef ABC\n"
"A\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("", actual[""]);
ASSERT_EQUALS("\nA\n\n\nA", actual["ABC"]);
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
}
void test5() {
@ -378,16 +362,7 @@ private:
"C\n"
"#endif\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\n\n\nB", actual[""]);
ASSERT_EQUALS("\nA", actual["ABC"]);
ASSERT_EQUALS("\n\n\nB\n\nC", actual["DEF"]);
ASSERT_EQUALS("\nABC\nDEF\n", getConfigsStr(filedata));
}
void test7() {
@ -397,20 +372,7 @@ private:
"B\n"
"#endif\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Make sure an error message is written..
TODO_ASSERT_EQUALS("[file.c:3]: (error) ABC is already guaranteed to be defined\n",
"",
errout.str());
// Compare results..
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("", actual[""]);
ASSERT_EQUALS("\nA\n\nB", actual["ABC"]);
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
test7a();
test7b();
@ -425,17 +387,7 @@ private:
"B\n"
"#endif\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Make sure an error message is written..
TODO_ASSERT_EQUALS("[file.c:3]: (error) ABC is already guaranteed NOT to be defined\n",
"", errout.str());
// Compare results..
// TODO Preprocessor::getConfigs ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\n", getConfigsStr(filedata));
}
void test7b() {
@ -445,17 +397,7 @@ private:
"B\n"
"#endif\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Make sure an error message is written..
TODO_ASSERT_EQUALS("[file.c:3]: (error) ABC is already guaranteed NOT to be defined\n",
"", errout.str());
// Compare results..
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
}
void test7c() {
@ -465,18 +407,7 @@ private:
"B\n"
"#endif\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Make sure an error message is written..
TODO_ASSERT_EQUALS("[file.c:3]: (error) ABC is already guaranteed to be defined\n",
"",
errout.str());
// Compare results..
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
}
void test7d() {
@ -486,18 +417,7 @@ private:
"B\n"
"#endif\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Make sure an error message is written..
TODO_ASSERT_EQUALS("[file.c:3]: (error) ABC is already guaranteed to be defined\n",
"",
errout.str());
// Compare results..
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
}
void test7e() {
@ -510,49 +430,21 @@ private:
"#endif\n"
"#endfile\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Make sure an error message is written..
ASSERT_EQUALS("", errout.str());
// Compare results..
ASSERT_EQUALS(2U, actual.size());
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
}
void test8() {
const char filedata[] = "#if A == 1\n"
"1\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// No error..
ASSERT_EQUALS("", errout.str());
// Compare results..
ASSERT_EQUALS(2U, actual.size());
ASSERT_EQUALS("", actual[""]);
ASSERT_EQUALS("\n1", actual["A=1"]);
ASSERT_EQUALS("\nA=1\n", getConfigsStr(filedata));
}
void test9() {
const char filedata[] = "#if\n"
"#else\n"
"#endif\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Settings settings;
settings.maxConfigs = 1;
settings.userDefines = "X";
Preprocessor preprocessor(settings, this);
preprocessor.preprocess(istr, actual, "file.c"); // <- don't crash
getConfigsStr(filedata); // <- don't crash
}
void test10() { // Ticket #5139
@ -561,10 +453,7 @@ private:
"#define baz bar+0\n"
"#if 0\n"
"#endif";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
ASSERT_EQUALS("\n", getConfigsStr(filedata));
}
void error1() {
@ -573,16 +462,7 @@ private:
"#else\n"
"#error abcd\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("", actual[""]);
ASSERT_EQUALS("\n;", actual["A"]);
ASSERT_EQUALS("\nA\n", getConfigsStr(filedata));
}
void error3() {
@ -665,13 +545,7 @@ private:
"#endfile\n"
"#ifdef ABC\n"
"#endif";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Expected configurations: "" and "ABC"
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
}
void includeguard2() {
@ -682,15 +556,7 @@ private:
"\n"
"#endif\n"
"#endfile\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Expected configurations: "" and "ABC"
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS(true, actual.find("") != actual.end());
ASSERT_EQUALS(true, actual.find("ABC") != actual.end());
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
}
@ -718,28 +584,14 @@ private:
"#ifdef WIN32\n"
"#endif\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("", actual[""]);
ASSERT_EQUALS("\n", getConfigsStr(filedata));
}
void if1() {
const char filedata[] = " # if /* comment */ 1 // comment\n"
"ABC\n"
" # endif \n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\nABC", actual[""]);
ASSERT_EQUALS("\n", getConfigsStr(filedata));
}
@ -750,16 +602,7 @@ private:
"#elif DEF2\n"
"DEF\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("", actual[""]);
ASSERT_EQUALS("\nABC", actual["DEF1"]);
ASSERT_EQUALS("\n\n\nDEF", actual["DEF2"]);
ASSERT_EQUALS("\nDEF1\nDEF2\n", getConfigsStr(filedata));
}
{
@ -770,16 +613,7 @@ private:
"#else\n"
"GHI\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\n\n\n\n\nGHI", actual[""]);
ASSERT_EQUALS("\nABC", actual["DEF1"]);
ASSERT_EQUALS("\n\n\nDEF", actual["DEF2"]);
ASSERT_EQUALS("\nDEF1\nDEF2\n", getConfigsStr(filedata));
}
}
@ -789,18 +623,7 @@ private:
"#else\n"
" B\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\n"
"\n"
"\n"
"B", actual[""]);
TODO_ASSERT_EQUALS("A", "", actual["LIBVER=101"]);
TODO_ASSERT_EQUALS("\nLIBVER=101\n", "\n", getConfigsStr(filedata));
}
void if_cond2() {
@ -810,16 +633,8 @@ private:
"#if defined(A) && defined(B)\n"
"ab\n"
"#endif\n";
ASSERT_EQUALS("\nA\nA;B\n", getConfigsStr(filedata));
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("", actual[""]);
ASSERT_EQUALS("\na", actual["A"]);
ASSERT_EQUALS("\na\n\n\nab", actual["A;B"]);
if_cond2b();
if_cond2c();
if_cond2d();
@ -835,16 +650,7 @@ private:
"#else\n"
"a\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\n! a", actual[""]);
ASSERT_EQUALS("\n\n\n\n\n\na", actual["A"]);
ASSERT_EQUALS("\n! a\n\nb", actual["B"]);
TODO_ASSERT_EQUALS("\nA;B\n", "\nA\nB\n", getConfigsStr(filedata));
}
void if_cond2c() {
@ -858,16 +664,7 @@ private:
"#else\n"
"a\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\n! a\n\n\n\n! b", actual[""]);
ASSERT_EQUALS("\n\n\n\n\n\n\n\na", actual["A"]);
ASSERT_EQUALS("\n! a\n\nb", actual["B"]);
TODO_ASSERT_EQUALS("\nA\nA;B\n", "\nA\nB\n", getConfigsStr(filedata));
}
void if_cond2d() {
@ -886,17 +683,7 @@ private:
"!b\n"
"#endif\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(4, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\n! a\n\n\n\n! b", actual[""]);
ASSERT_EQUALS("\n\n\n\n\n\n\n\na\n\n\n\n! b", actual["A"]);
ASSERT_EQUALS("\n\n\n\n\n\n\n\na\n\nb", actual["A;B"]);
ASSERT_EQUALS("\n! a\n\nb", actual["B"]);
ASSERT_EQUALS("\nA\nA;B\nB\n", getConfigsStr(filedata));
}
void if_cond2e() {
@ -905,22 +692,7 @@ private:
"#elif !defined(B)\n"
"!b\n"
"#endif\n";
// Preprocess => actual result..
errout.str("");
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Settings settings;
settings.debug = settings.debugwarnings = true;
Preprocessor preprocessor(settings, this);
preprocessor.preprocess(istr, actual, "file.c");
// Compare results..
TODO_ASSERT_EQUALS(3U, 1U, actual.size());
ASSERT_EQUALS("\n! a", actual[""]);
TODO_ASSERT_EQUALS("\n\n\n! b", "", actual["A"]);
ASSERT_EQUALS("", actual["A;B"]);
ASSERT_EQUALS("", errout.str());
TODO_ASSERT_EQUALS("\nA\nA;B", "\n", getConfigsStr(filedata));
}
void if_cond3() {
@ -930,16 +702,7 @@ private:
"abc\n"
"#endif\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("", actual[""]);
ASSERT_EQUALS("\na", actual["A"]);
ASSERT_EQUALS("\na\n\nabc", actual["A;B;C"]);
ASSERT_EQUALS("\nA\nA;B;C\n", getConfigsStr(filedata));
}
void if_cond4() {
@ -949,14 +712,7 @@ private:
"#if defined A || defined B\n"
"ab\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\n\n\nab", actual[""]);
ASSERT_EQUALS("\n", getConfigsStr(filedata));
}
{
@ -967,16 +723,7 @@ private:
"#endif\n"
"}\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("", actual[""]);
ASSERT_EQUALS("\n{\n\n\n\n}", actual["A"]);
ASSERT_EQUALS("\n{\n\nfoo ( ) ;\n\n}", actual["A;B"]);
ASSERT_EQUALS("\nA\nA;B\n", getConfigsStr(filedata));
}
{
@ -985,43 +732,21 @@ private:
"#if (defined A) || defined (B)\n"
"ab\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\n\n\nab", actual[""]);
ASSERT_EQUALS("\n", getConfigsStr(filedata));
}
{
const char filedata[] = "#if (A)\n"
"foo();\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("", actual[""]);
ASSERT_EQUALS("\nfoo ( ) ;", actual["A"]);
ASSERT_EQUALS("\nA\n", getConfigsStr(filedata));
}
{
const char filedata[] = "#if! A\n"
"foo();\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
TODO_ASSERT_EQUALS(2, 1, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\nfoo ( ) ;", actual[""]);
ASSERT_EQUALS("\n", getConfigsStr(filedata));
}
}
@ -1033,41 +758,20 @@ private:
"#if defined(B) && defined(A)\n"
"ef\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\n\n\ncd", actual[""]);
ASSERT_EQUALS("\nab\n\ncd\n\nef", actual["A;B"]);
ASSERT_EQUALS("\nA;B\n", getConfigsStr(filedata));
}
void if_cond6() {
const char filedata[] = "\n"
"#if defined(A) && defined(B))\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
// TODO ASSERT_EQUALS("[file.c:2]: (error) mismatching number of '(' and ')' in this line: defined(A)&&defined(B))\n", errout.str());
ASSERT_EQUALS("\nA;B\n", getConfigsStr(filedata));
}
void if_cond8() {
const char filedata[] = "#if defined(A) + defined(B) + defined(C) != 1\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
// TODO Preprocessor::getConfig ASSERT_EQUALS(1U, actual.size());
ASSERT_EQUALS("", actual[""]);
TODO_ASSERT_EQUALS("\nA\n", "\nA;B;C\n", getConfigsStr(filedata));
}
@ -1075,14 +779,7 @@ private:
const char filedata[] = "#if !defined _A\n"
"abc\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual);
// Compare results..
ASSERT_EQUALS(1, (int)actual.size());
ASSERT_EQUALS("\nabc", actual[""]);
ASSERT_EQUALS("\n", getConfigsStr(filedata));
}
void if_cond10() {
@ -1112,32 +809,21 @@ private:
"#if A == 1\n"
";\n"
"#endif\n";
ASSERT_EQUALS("\n\n;", preprocessor0.getcode(filedata,"",""));
ASSERT_EQUALS("\n", getConfigsStr(filedata));
}
void if_cond13() {
const char filedata[] = "#if ('A' == 0x41)\n"
"123\n"
"#endif\n";
ASSERT_EQUALS("\n123", preprocessor0.getcode(filedata,"",""));
ASSERT_EQUALS("\n", getConfigsStr(filedata));
}
void if_cond14() {
const char filedata[] = "#if !(A)\n"
"123\n"
"#endif\n";
ASSERT_EQUALS("\n123", preprocessor0.getcode(filedata,"",""));
}
void if_cond15() { // #4456 - segmentation fault
const char filedata[] = "#if ((A >= B) && (C != D))\n"
"#if (E < F(1))\n"
"#endif\n"
"#endif\n";
// Preprocess => actual result..
std::map<std::string, std::string> actual;
preprocess(filedata, actual); // <- don't crash in Preprocessor::getcfgs -> Tokenize -> number of template parameters
ASSERT_EQUALS("\n", getConfigsStr(filedata));
}
@ -1146,39 +832,18 @@ private:
const char filedata[] = "#if defined(DEF_10) || defined(DEF_11)\n"
"a1;\n"
"#endif\n";
errout.str("");
output.str("");
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Settings settings;
settings.debug = settings.debugwarnings = true;
settings.addEnabled("missingInclude");
Preprocessor preprocessor(settings, this);
preprocessor.preprocess(istr, actual, "file.c");
// Compare results..
ASSERT_EQUALS(2U, actual.size());
ASSERT_EQUALS("", actual[""]);
// the "defined(DEF_10) || defined(DEF_11)" are not handled correctly..
ASSERT_EQUALS(2U, actual.size());
ASSERT_EQUALS("\na1 ;", actual["DEF_10;DEF_11"]);
ASSERT_EQUALS("\nDEF_10;DEF_11\n", getConfigsStr(filedata));
}
void if_or_2() {
const std::string code("#if X || Y\n"
"a1;\n"
"#endif\n");
ASSERT_EQUALS("\na1 ;", preprocessor0.getcode(code, "X", "test.c"));
ASSERT_EQUALS("\na1 ;", preprocessor0.getcode(code, "Y", "test.c"));
const char filedata[] = "#if X || Y\n"
"a1;\n"
"#endif\n";
TODO_ASSERT_EQUALS("\nX;Y\n", "\n", getConfigsStr(filedata));
}
void if_macro_eq_macro() {
const char* code = "#define A B\n"
const char *code = "#define A B\n"
"#define B 1\n"
"#define C 1\n"
"#if A == C\n"
@ -1186,10 +851,7 @@ private:
"#else\n"
"Betty\n"
"#endif\n";
std::map<std::string, std::string> actual;
preprocess(code, actual);
ASSERT_EQUALS("\n\n\n\nWilma", actual[""]);
ASSERT_EQUALS("\n", getConfigsStr(code));
}
void ticket_3675() {
@ -1784,7 +1446,7 @@ private:
void stringify5() const {
const char filedata[] = "#define A(x) a(#x,x)\n"
"A(foo(\"\\\"\"))\n";
ASSERT_EQUALS("\na ( \"foo(\"\\\"\")\" , foo ( \"\\\"\" ) )", OurPreprocessor::expandMacros(filedata));
ASSERT_EQUALS("\na ( \"foo(\\\"\\\\\\\"\\\")\" , foo ( \"\\\"\" ) )", OurPreprocessor::expandMacros(filedata));
}
void pragma() {
@ -2422,22 +2084,6 @@ private:
ASSERT_EQUALS("", actual);
}
std::string getConfigsStr(const char filedata[], const char *u1=NULL) {
Settings settings;
if (u1)
settings.userUndefs.insert(u1);
Preprocessor preprocessor(settings, this);
std::vector<std::string> files;
std::istringstream istr(filedata);
simplecpp::TokenList tokens(istr,files);
tokens.removeComments();
const std::set<std::string> configs = preprocessor.getConfigs(tokens);
std::string ret;
for (std::set<std::string>::const_iterator it = configs.begin(); it != configs.end(); ++it)
ret += *it + '\n';
return ret;
}
void undef1() {
const char filedata[] = "#ifdef X\n"
"#endif\n";
@ -2468,37 +2114,20 @@ private:
Settings settings;
Preprocessor preprocessor(settings, this);
ASSERT_EQUALS(true, preprocessor.validateCfg("", "X=42")); // don't hang when parsing cfg
ASSERT_EQUALS(false, preprocessor.validateCfg("int y=Y;", "X=42;Y"));
ASSERT_EQUALS(false, preprocessor.validateCfg("int x=X;", "X"));
ASSERT_EQUALS(false, preprocessor.validateCfg("X=1;", "X"));
ASSERT_EQUALS(true, preprocessor.validateCfg("int x=X;", "Y"));
ASSERT_EQUALS(true, preprocessor.validateCfg("FOO_DEBUG()", "DEBUG"));
ASSERT_EQUALS(true, preprocessor.validateCfg("\"DEBUG()\"", "DEBUG"));
ASSERT_EQUALS(true, preprocessor.validateCfg("\"\\\"DEBUG()\"", "DEBUG"));
ASSERT_EQUALS(false, preprocessor.validateCfg("\"DEBUG()\" DEBUG", "DEBUG"));
ASSERT_EQUALS(true, preprocessor.validateCfg("#undef DEBUG", "DEBUG"));
std::list<simplecpp::MacroUsage> macroUsageList;
std::vector<std::string> files;
files.push_back("test.c");
simplecpp::MacroUsage macroUsage(files);
macroUsage.useLocation.fileIndex = 0;
macroUsage.useLocation.line = 1;
macroUsage.macroName = "X";
macroUsageList.push_back(macroUsage);
// #4301:
// #ifdef A
// int a = A; // <- using macro. must use -D so "A" will get a proper value
errout.str("");
settings.addEnabled("all");
preprocessor.setFile0("test.c");
ASSERT_EQUALS(false, preprocessor.validateCfg("int a=A;", "A"));
ASSERT_EQUALS("[test.c:1]: (information) Skipping configuration 'A' since the value of 'A' is unknown. Use -D if you want to check it. You can use -U to skip it explicitly.\n", errout.str());
// #4949:
// #ifdef A
// a |= A; // <- using macro. must use -D so "A" will get a proper value
errout.str("");
Settings settings1;
settings = settings1;
ASSERT_EQUALS("", preprocessor.getcode("if (x) a|=A;", "A", "test.c"));
ASSERT_EQUALS("", errout.str());
settings.addEnabled("information");
ASSERT_EQUALS("", preprocessor.getcode("if (x) a|=A;", "A", "test.c"));
ASSERT_EQUALS("[test.c:1]: (information) Skipping configuration 'A' since the value of 'A' is unknown. Use -D if you want to check it. You can use -U to skip it explicitly.\n", errout.str());
ASSERT_EQUALS(true, preprocessor.validateCfg("", macroUsageList));
ASSERT_EQUALS(false, preprocessor.validateCfg("X",macroUsageList));
ASSERT_EQUALS(false, preprocessor.validateCfg("A=42;X", macroUsageList));
ASSERT_EQUALS(true, preprocessor.validateCfg("X=1", macroUsageList));
ASSERT_EQUALS(true, preprocessor.validateCfg("Y", macroUsageList));
}
void if_sizeof() { // #4071

View File

@ -201,6 +201,14 @@ private:
" l2.insert(it, 0);\n"
"}");
ASSERT_EQUALS("[test.cpp:6]: (error) Same iterator is used with different containers 'l1' and 'l2'.\n", errout.str());
check("void foo() {\n" // #5803
" list<int> l1;\n"
" list<int> l2;\n"
" list<int>::iterator it = l1.begin();\n"
" l2.insert(it, l1.end());\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void iterator4() {

View File

@ -182,6 +182,10 @@ private:
TEST_CASE(functionArgs2);
TEST_CASE(functionArgs3);
TEST_CASE(functionArgs4);
TEST_CASE(functionArgs5); // #7650
TEST_CASE(functionArgs6); // #7651
TEST_CASE(functionArgs7); // #7652
TEST_CASE(functionArgs8); // #7653
TEST_CASE(namespaces1);
TEST_CASE(namespaces2);
@ -294,6 +298,10 @@ private:
TEST_CASE(executableScopeWithUnknownFunction);
TEST_CASE(valuetype);
TEST_CASE(variadic1); // #7453
TEST_CASE(variadic2); // #7649
TEST_CASE(variadic3); // #7387
}
void array() {
@ -1571,6 +1579,159 @@ private:
}
}
void functionArgs5() { // #7650
GET_SYMBOL_DB("class ABC {};\n"
"class Y {\n"
" enum ABC {A,B,C};\n"
" void f(enum ABC abc) {}\n"
"};");
ASSERT_EQUALS(true, db != nullptr);
if (db) {
const Token *f = Token::findsimplematch(tokenizer.tokens(), "f ( enum");
ASSERT_EQUALS(true, f && f->function());
if (f && f->function()) {
const Function *func = f->function();
ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type());
if (func->argumentList.size() == 1 && func->argumentList.front().type()) {
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->isEnumType());
}
}
}
}
void functionArgs6() { // #7651
GET_SYMBOL_DB("class ABC {};\n"
"class Y {\n"
" enum ABC {A,B,C};\n"
" void f(ABC abc) {}\n"
"};");
ASSERT_EQUALS(true, db != nullptr);
if (db) {
const Token *f = Token::findsimplematch(tokenizer.tokens(), "f ( ABC");
ASSERT_EQUALS(true, f && f->function());
if (f && f->function()) {
const Function *func = f->function();
ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type());
if (func->argumentList.size() == 1 && func->argumentList.front().type()) {
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->isEnumType());
}
}
}
}
void functionArgs7() { // #7652
{
GET_SYMBOL_DB("struct AB { int a; int b; };\n"
"int foo(struct AB *ab);\n"
"void bar() {\n"
" struct AB ab;\n"
" foo(&ab); \n"
"};");
ASSERT_EQUALS(true, db != nullptr);
if (db) {
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab");
ASSERT_EQUALS(true, f && f->function());
if (f && f->function()) {
const Function *func = f->function();
ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type());
if (func->argumentList.size() == 1 && func->argumentList.front().type()) {
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->classDef->linenr() == 1);
}
}
}
}
{
GET_SYMBOL_DB("struct AB { int a; int b; };\n"
"int foo(AB *ab);\n"
"void bar() {\n"
" struct AB ab;\n"
" foo(&ab); \n"
"};");
ASSERT_EQUALS(true, db != nullptr);
if (db) {
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab");
ASSERT_EQUALS(true, f && f->function());
if (f && f->function()) {
const Function *func = f->function();
ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type());
if (func->argumentList.size() == 1 && func->argumentList.front().type()) {
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->classDef->linenr() == 1);
}
}
}
}
{
GET_SYMBOL_DB("struct AB { int a; int b; };\n"
"int foo(struct AB *ab);\n"
"void bar() {\n"
" AB ab;\n"
" foo(&ab); \n"
"};");
ASSERT_EQUALS(true, db != nullptr);
if (db) {
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab");
ASSERT_EQUALS(true, f && f->function());
if (f && f->function()) {
const Function *func = f->function();
ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type());
if (func->argumentList.size() == 1 && func->argumentList.front().type()) {
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->classDef->linenr() == 1);
}
}
}
}
{
GET_SYMBOL_DB("struct AB { int a; int b; };\n"
"int foo(AB *ab);\n"
"void bar() {\n"
" AB ab;\n"
" foo(&ab); \n"
"};");
ASSERT_EQUALS(true, db != nullptr);
if (db) {
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab");
ASSERT_EQUALS(true, f && f->function());
if (f && f->function()) {
const Function *func = f->function();
ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type());
if (func->argumentList.size() == 1 && func->argumentList.front().type()) {
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->classDef->linenr() == 1);
}
}
}
}
}
void functionArgs8() { // #7653
GET_SYMBOL_DB("struct A { int i; };\n"
"struct B { double d; };\n"
"int foo(struct A a);\n"
"double foo(struct B b);\n"
"void bar() {\n"
" struct B b;\n"
" foo(b);\n"
"}");
ASSERT_EQUALS(true, db != nullptr);
if (db) {
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( b");
ASSERT_EQUALS(true, f && f->function());
if (f && f->function()) {
const Function *func = f->function();
ASSERT_EQUALS(true, func->tokenDef->linenr() == 4 && func->argumentList.size() == 1 && func->argumentList.front().type());
if (func->argumentList.size() == 1 && func->argumentList.front().type()) {
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->isStructType());
}
}
}
}
void namespaces1() {
GET_SYMBOL_DB("namespace fred {\n"
" namespace barney {\n"
@ -3670,6 +3831,118 @@ private:
// Pointer to unknown type
ASSERT_EQUALS("*", typeOf("Bar* b;", "b"));
// Library types
{
// PodType
Settings s;
s.platformType = Settings::Win64;
const Library::PodType u32 = { 4, 'u' };
s.library.podtypes["u32"] = u32;
ValueType vt;
ASSERT_EQUALS(true, vt.fromLibraryType("u32", &s));
ASSERT_EQUALS(ValueType::Type::INT, vt.type);
}
{
// PlatformType
Settings s;
s.platformType = Settings::Unix32;
Library::PlatformType s32;
s32._type = "int";
s.library.platforms[s.platformString()]._platform_types["s32"] = s32;
ValueType vt;
ASSERT_EQUALS(true, vt.fromLibraryType("s32", &s));
ASSERT_EQUALS(ValueType::Type::INT, vt.type);
}
}
void variadic1() { // #7453
{
GET_SYMBOL_DB("CBase* create(const char *c1, ...);\n"
"int create(COther& ot, const char *c1, ...);\n"
"int foo(COther & ot)\n"
"{\n"
" CBase* cp1 = create(\"AAAA\", 44, (char*)0);\n"
" CBase* cp2 = create(ot, \"AAAA\", 44, (char*)0);\n"
"}");
const Token *f = Token::findsimplematch(tokenizer.tokens(), "create ( \"AAAA\"");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 1);
f = Token::findsimplematch(tokenizer.tokens(), "create ( ot");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2);
}
{
GET_SYMBOL_DB("int create(COther& ot, const char *c1, ...);\n"
"CBase* create(const char *c1, ...);\n"
"int foo(COther & ot)\n"
"{\n"
" CBase* cp1 = create(\"AAAA\", 44, (char*)0);\n"
" CBase* cp2 = create(ot, \"AAAA\", 44, (char*)0);\n"
"}");
const Token *f = Token::findsimplematch(tokenizer.tokens(), "create ( \"AAAA\"");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2);
f = Token::findsimplematch(tokenizer.tokens(), "create ( ot");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 1);
}
}
void variadic2() { // #7649
{
GET_SYMBOL_DB("CBase* create(const char *c1, ...);\n"
"CBase* create(const wchar_t *c1, ...);\n"
"int foo(COther & ot)\n"
"{\n"
" CBase* cp1 = create(\"AAAA\", 44, (char*)0);\n"
" CBase* cp2 = create(L\"AAAA\", 44, (char*)0);\n"
"}");
const Token *f = Token::findsimplematch(tokenizer.tokens(), "cp1 = create (");
ASSERT_EQUALS(true, db && f && f->tokAt(2) && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 1);
f = Token::findsimplematch(tokenizer.tokens(), "cp2 = create (");
ASSERT_EQUALS(true, db && f && f->tokAt(2) && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 2);
}
{
GET_SYMBOL_DB("CBase* create(const wchar_t *c1, ...);\n"
"CBase* create(const char *c1, ...);\n"
"int foo(COther & ot)\n"
"{\n"
" CBase* cp1 = create(\"AAAA\", 44, (char*)0);\n"
" CBase* cp2 = create(L\"AAAA\", 44, (char*)0);\n"
"}");
const Token *f = Token::findsimplematch(tokenizer.tokens(), "cp1 = create (");
ASSERT_EQUALS(true, db && f && f->tokAt(2) && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 2);
f = Token::findsimplematch(tokenizer.tokens(), "cp2 = create (");
ASSERT_EQUALS(true, db && f && f->tokAt(2) && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 1);
}
}
void variadic3() { // #7387
{
GET_SYMBOL_DB("int zdcalc(const XYZ & per, short rs = 0);\n"
"double zdcalc(long& length, const XYZ * per);\n"
"long mycalc( ) {\n"
" long length;\n"
" XYZ per;\n"
" zdcalc(length, &per);\n"
"}");
const Token *f = Token::findsimplematch(tokenizer.tokens(), "zdcalc ( length");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2);
}
{
GET_SYMBOL_DB("double zdcalc(long& length, const XYZ * per);\n"
"int zdcalc(const XYZ & per, short rs = 0);\n"
"long mycalc( ) {\n"
" long length;\n"
" XYZ per;\n"
" zdcalc(length, &per);\n"
"}");
const Token *f = Token::findsimplematch(tokenizer.tokens(), "zdcalc ( length");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 1);
}
}
};

View File

@ -292,6 +292,7 @@ private:
TEST_CASE(simplifyStdType); // #4947, #4950, #4951
TEST_CASE(createLinks);
TEST_CASE(createLinks2);
TEST_CASE(signed1);
TEST_CASE(simplifyString);
@ -307,6 +308,7 @@ private:
TEST_CASE(functionpointer6);
TEST_CASE(functionpointer7);
TEST_CASE(functionpointer8); // #7410 - throw
TEST_CASE(functionpointer9); // #6113 - function call with function pointer
TEST_CASE(removeRedundantAssignment);
@ -4523,6 +4525,20 @@ private:
}
}
void createLinks2() {
{
// #7158
const char code[] = "enum { value = boost::mpl::at_c<B, C> };";
errout.str("");
Tokenizer tokenizer(&settings0, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
const Token *tok = Token::findsimplematch(tokenizer.tokens(), "<");
ASSERT_EQUALS(true, tok->link() == tok->tokAt(4));
ASSERT_EQUALS(true, tok->linkAt(4) == tok);
}
}
void simplifyString() {
errout.str("");
Tokenizer tokenizer(&settings0, this);
@ -4681,6 +4697,20 @@ private:
ASSERT_EQUALS(expected1, tokenizeDebugListing(code1, false));
}
void functionpointer9() { // function call with function pointer
const char code1[] = "int f() { (*f)(); }";
const char expected1[] = "1: int f ( ) { ( * f ) ( ) ; }\n";
ASSERT_EQUALS(expected1, tokenizeDebugListing(code1, false));
const char code2[] = "int f() { return (*f)(); }";
const char expected2[] = "1: int f ( ) { return ( * f ) ( ) ; }\n";
ASSERT_EQUALS(expected2, tokenizeDebugListing(code2, false));
const char code3[] = "int f() { throw (*f)(); }";
const char expected3[] = "1: int f ( ) { throw ( * f ) ( ) ; }\n";
ASSERT_EQUALS(expected3, tokenizeDebugListing(code3, false));
}
void removeRedundantAssignment() {
ASSERT_EQUALS("void f ( ) { }", tokenizeAndStringify("void f() { int *p, *q; p = q; }", true));
ASSERT_EQUALS("void f ( ) { }", tokenizeAndStringify("void f() { int *p = 0, *q; p = q; }", true));

View File

@ -73,6 +73,8 @@ private:
TEST_CASE(syntax_error); // Ticket #5073
TEST_CASE(trac_5970);
TEST_CASE(isVariableUsageDeref); // *p
// dead pointer
TEST_CASE(deadPointer);
}
@ -537,13 +539,6 @@ private:
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: c\n", errout.str());
checkUninitVar("void f()\n"
"{\n"
" char *s = malloc(100);\n"
" *s += 10;\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Memory is allocated but not initialized: s\n", errout.str());
checkUninitVar("void f()\n"
"{\n"
" int a[10];\n"
@ -1236,18 +1231,6 @@ private:
"}");
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: a\n", "", errout.str());
checkUninitVar("int f() {\n"
" char a[10];\n"
" char c = *a;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str());
checkUninitVar("int f() {\n"
" char a[SIZE+10];\n"
" char c = *a;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str());
checkUninitVar("int f()\n"
"{\n"
" char a[10];\n"
@ -3558,6 +3541,19 @@ private:
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
// #6646 - init in for loop
checkUninitVar("void f() {\n" // No FP
" for (int i;;i++)\n"
" dostuff(&i);\n"
"}");
ASSERT_EQUALS("", errout.str());
checkUninitVar("void f() {\n" // No FN
" for (int i;;i++)\n"
" a=i;\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (error) Uninitialized variable: i\n", errout.str());
}
void uninitvar2_4494() {
@ -3783,6 +3779,33 @@ private:
check.deadPointer();
}
void isVariableUsageDeref() {
// *p
checkUninitVar("void f() {\n"
" char a[10];\n"
" char c = *a;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str());
checkUninitVar("void f() {\n"
" char a[SIZE+10];\n"
" char c = *a;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str());
checkUninitVar("void f() {\n"
" char a[10];\n"
" *a += 10;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str());
checkUninitVar("void f() {\n"
" int a[10][10];\n"
" dostuff(*a);\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void deadPointer() {
checkDeadPointer("void f() {\n"
" int *p = p1;\n"

View File

@ -48,6 +48,7 @@ private:
TEST_CASE(structmember10);
TEST_CASE(structmember11); // #4168 - initialization with {} / passed by address to unknown function
TEST_CASE(structmember12); // #7179 - FP unused structmember
TEST_CASE(structmember_sizeof);
TEST_CASE(localvar1);
TEST_CASE(localvar2);
@ -461,6 +462,22 @@ private:
ASSERT_EQUALS("[test.cpp:3]: (style) struct member 'AB::a' is never used.\n", errout.str());
}
void structmember_sizeof() {
checkStructMemberUsage("struct Header {\n"
" uint8_t message_type;\n"
"}\n"
"\n"
"input.skip(sizeof(Header));");
ASSERT_EQUALS("", errout.str());
checkStructMemberUsage("struct Header {\n"
" uint8_t message_type;\n"
"}\n"
"\n"
"input.skip(sizeof(struct Header));");
ASSERT_EQUALS("", errout.str());
}
void functionVariableUsage(const char code[], const char filename[]="test.cpp") {
// Clear the error buffer..
errout.str("");
@ -1779,6 +1796,25 @@ private:
" x(a, b=2);\n" // <- if param2 is passed-by-reference then b might be used in x
"}");
ASSERT_EQUALS("", errout.str());
functionVariableUsage("int foo() {\n" // ticket #6147
" int a = 0;\n"
" bar(a=a+2);\n"
"}");
ASSERT_EQUALS("", errout.str());
functionVariableUsage("int foo() {\n" // ticket #6147
" int a = 0;\n"
" bar(a=2);\n"
"}");
TODO_ASSERT_EQUALS("error", "", errout.str());
functionVariableUsage("void bar(int);\n"
"int foo() {\n"
" int a = 0;\n"
" bar(a=a+2);\n"
"}");
TODO_ASSERT_EQUALS("error", "", errout.str());
}
void localvar37() { // ticket #3078

View File

@ -134,6 +134,7 @@ private:
TEST_CASE(varid_templateNamespaceFuncPtr); // #4172
TEST_CASE(varid_templateArray);
TEST_CASE(varid_templateParameter); // #7046 set varid for "X": std::array<int,X> Y;
TEST_CASE(varid_templateUsing); // #5781 #7273
TEST_CASE(varid_cppcast); // #6190
TEST_CASE(varid_variadicFunc);
TEST_CASE(varid_typename); // #4644
@ -2026,6 +2027,15 @@ private:
tokenize(code));
}
void varid_templateUsing() { // #5781 #7273
const char code[] = "template<class T> using X = Y<T>;\n"
"X<int> x;";
TODO_ASSERT_EQUALS("\nY<int> x@1;\n",
"1: template < class T > using X ; X = Y < T > ;\n"
"2: X < int > x@1 ;\n",
tokenize(code));
}
void varid_cppcast() {
ASSERT_EQUALS("1: const_cast < int * > ( code ) [ 0 ] = 0 ;\n",
tokenize("const_cast<int *>(code)[0] = 0;"));

View File

@ -177,11 +177,17 @@ def scanarchive(filepath, jobs):
FOLDER = None
JOBS = '-j1'
REV = None
SKIP = []
WORKDIR = os.path.expanduser('~/daca2');
for arg in sys.argv[1:]:
if arg[:6] == '--rev=':
REV = arg[6:]
elif arg[:2] == '-j':
JOBS = arg
elif arg[:7] == '--skip=':
SKIP.append(arg[7:])
elif arg[:10] == '--workdir=':
WORKDIR = arg[10:]
else:
FOLDER = arg
@ -189,6 +195,10 @@ if not FOLDER:
print('no folder given')
sys.exit(1)
if not os.path.isdir(WORKDIR):
print('workdir \'' + WORKDIR + '\' is not a folder')
sys.exit(1)
archives = getpackages(FOLDER)
if len(archives) == 0:
print('failed to load packages')
@ -197,12 +207,13 @@ if len(archives) == 0:
print('Sleep for 10 seconds..')
time.sleep(10)
workdir = os.path.expanduser('~/daca2/')
if not WORKDIR.endswith('/'):
WORKDIR = WORKDIR + '/'
print('~/daca2/' + FOLDER)
if not os.path.isdir(workdir + FOLDER):
os.makedirs(workdir + FOLDER)
os.chdir(workdir + FOLDER)
if not os.path.isdir(WORKDIR + FOLDER):
os.makedirs(WORKDIR + FOLDER)
os.chdir(WORKDIR + FOLDER)
try:
results = open('results.txt', 'wt')
@ -214,6 +225,11 @@ try:
results.close()
for archive in archives:
if len(SKIP) > 0:
a = archive[:archive.rfind('/')]
a = a[a.rfind('/')+1:]
if a in SKIP:
continue
scanarchive(archive, JOBS)
results = open('results.txt', 'at')

View File

@ -17,3 +17,5 @@ cd ..
# Detect duplicate code..
~/pmd-4.2.6/bin/cpd.sh lib/ > devinfo/cpd.txt
java -jar ~/simian-2.4.0/bin/simian-2.4.0.jar -language=c++ -reportDuplicateText -threshold=10 lib/*.cpp lib/*.h > devinfo/simian.txt