diff --git a/cfg/posix.cfg b/cfg/posix.cfg
index fbd976e4e..52d3d6f33 100644
--- a/cfg/posix.cfg
+++ b/cfg/posix.cfg
@@ -39,6 +39,30 @@
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
@@ -116,6 +140,43 @@
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
false
diff --git a/externals/simplecpp/simplecpp.cpp b/externals/simplecpp/simplecpp.cpp
index 7845cebfe..9c6299dda 100644
--- a/externals/simplecpp/simplecpp.cpp
+++ b/externals/simplecpp/simplecpp.cpp
@@ -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 getMacroParameters(const Token *nameToken, bool def) const {
+ std::vector getMacroParameters(const Token *nameToken, bool calledInDefine) const {
if (!nameToken->next || nameToken->next->op != '(' || !functionLike())
return std::vector();
std::vector 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 parametertokens1(getMacroParameters(nameToken, !expandedmacros1.empty()));
+ const bool calledInDefine = (loc.fileIndex != nameToken->location.fileIndex ||
+ loc.line < nameToken->location.line);
+
+ std::vector 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 &filedata) {
+ for (std::map::iterator it = filedata.begin(); it != filedata.end(); ++it)
+ delete it->second;
+ filedata.clear();
+}
diff --git a/externals/simplecpp/simplecpp.h b/externals/simplecpp/simplecpp.h
index d283c0c15..2fc09646b 100644
--- a/externals/simplecpp/simplecpp.h
+++ b/externals/simplecpp/simplecpp.h
@@ -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 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 &files, const std::map &filedata, const DUI &dui, OutputList *outputList = 0, std::list *macroUsage = 0);
+
+/**
+ * Deallocate data
+ */
+SIMPLECPP_LIB void cleanup(std::map &filedata);
}
#endif
diff --git a/lib/astutils.cpp b/lib/astutils.cpp
index 4defd6abd..861088d31 100644
--- a/lib/astutils.cpp
+++ b/lib/astutils.cpp
@@ -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 &constFunctions)
diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp
index cd747f8e1..5f7be4af2 100644
--- a/lib/checkbufferoverrun.cpp
+++ b/lib/checkbufferoverrun.cpp
@@ -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());
diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp
index 65eac6a33..730aad85c 100644
--- a/lib/checkclass.cpp
+++ b/lib/checkclass.cpp
@@ -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;
diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp
index e7fac6dcc..2811658cc 100644
--- a/lib/checkfunctions.cpp
+++ b/lib/checkfunctions.cpp
@@ -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);
}
}
}
diff --git a/lib/checkio.cpp b/lib/checkio.cpp
index ecbda6504..8bb531634 100644
--- a/lib/checkio.cpp
+++ b/lib/checkio.cpp
@@ -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)
diff --git a/lib/checkother.cpp b/lib/checkother.cpp
index 0d2fa2674..1e6bf5868 100644
--- a/lib/checkother.cpp
+++ b/lib/checkother.cpp
@@ -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;
diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp
index f8130d9e7..2fca0f994 100644
--- a/lib/checkstl.cpp
+++ b/lib/checkstl.cpp
@@ -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());
}
diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp
index 7fa1a827e..0c9830b81 100644
--- a/lib/checkuninitvar.cpp
+++ b/lib/checkuninitvar.cpp
@@ -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();
diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp
index 0c55b32a1..aa69badf4 100644
--- a/lib/checkunusedvar.cpp
+++ b/lib/checkunusedvar.cpp
@@ -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;
diff --git a/lib/library.cpp b/lib/library.cpp
index 25b5cdf9c..711fe44a4 100644
--- a/lib/library.cpp
+++ b/lib/library.cpp
@@ -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 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);
diff --git a/lib/library.h b/lib/library.h
index 1cc07f8fd..02c965365 100644
--- a/lib/library.h
+++ b/lib/library.h
@@ -44,6 +44,8 @@ namespace tinyxml2 {
* @brief Library definitions handling
*/
class CPPCHECKLIB Library {
+ friend class TestSymbolDatabase; // For testing only
+
public:
Library();
diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp
index 095ab627a..eab50e8bb 100644
--- a/lib/preprocessor.cpp
+++ b/lib/preprocessor.cpp
@@ -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::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::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::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 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 ¯oUsageList)
{
- const bool printInformation = _settings.isEnabled("information");
-
- // fill up "macros" with empty configuration macros
- std::set 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::const_iterator it = macros.begin(); it != macros.end(); ++it) {
- const std::string ¯o = *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 defines;
+ splitcfg(cfg, defines, std::string());
+ for (std::list::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::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::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 ¯o)
+void Preprocessor::validateCfgError(const std::string &file, const unsigned int line, const std::string &cfg, const std::string ¯o)
{
const std::string id = "ConfigurationNotChecked";
std::list 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 ..
}
diff --git a/lib/preprocessor.h b/lib/preprocessor.h
index 7bcce66b3..a1ba52978 100644
--- a/lib/preprocessor.h
+++ b/lib/preprocessor.h
@@ -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 ¯o);
+ bool validateCfg(const std::string &cfg, const std::list ¯oUsageList);
+ void validateCfgError(const std::string &file, const unsigned int line, const std::string &cfg, const std::string ¯o);
private:
diff --git a/lib/settings.h b/lib/settings.h
index 13532e351..a406dff0b 100644
--- a/lib/settings.h
+++ b/lib/settings.h
@@ -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.
diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp
index 22bc731b8..17a3db837 100644
--- a/lib/symboldatabase.cpp
+++ b/lib/symboldatabase.cpp
@@ -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::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(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::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::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(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;
diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h
index 5713c5d8a..f33f105b2 100644
--- a/lib/symboldatabase.h
+++ b/lib/symboldatabase.h
@@ -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;
};
diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp
index 2a8b81f1e..650420b87 100644
--- a/lib/tokenize.cpp
+++ b/lib/tokenize.cpp
@@ -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 notstart_c = make_container< std::set notstart_cpp = make_container< std::set > ()
<< 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[" 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
diff --git a/man/manual.docbook b/man/manual.docbook
index 2c0e2013d..81da3fd30 100644
--- a/man/manual.docbook
+++ b/man/manual.docbook
@@ -695,6 +695,10 @@ Checking test.c...
configuration files. It is available in the View
menu. All settings are not documented in this manual.
+ If you have a question about the .cfg file
+ format it is recommended you ask in the forum
+ (http://sourceforge.net/p/cppcheck/discussion/).
+
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.
@@ -1118,6 +1122,23 @@ Checking minsize.c...
+
+
+ strz
+
+ This setting is not used by Cppcheck currently. But with this
+ you can say that an argument must be a zero-terminated
+ string.
+
+ <?xml version="1.0"?>
+<def>
+ <function name="do_something">
+ <arg nr="1">
+ <strz/>
+ </arg>
+ </function>
+</def>
+
@@ -1209,11 +1230,19 @@ Checking useretval.c...
- pure
+ pure and const
- 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.
+ These correspond to the GCC function attributes pure and
+ const.
+
+ A pure function has no effects except to return a value, and its
+ return value depends only on the parameters and global
+ variables.
+
+ A const function has no effects except to return a value, and
+ its return value depends only on the parameters.
+
+ Here is an example code:
void f(int x)
{
@@ -1224,24 +1253,29 @@ Checking useretval.c...
}
}
- Cppcheck reports no warning
+ If calculate() is a const function then the
+ result of calculate(x) will be the same in both
+ conditions, since the same parameter value is used.
- # cppcheck pure.c
-Checking pure.c...
+ Cppcheck normally assumes that the result might be different,
+ and reports no warning for the code:
- If a proper lib.cfg is provided, the
+ # cppcheck const.c
+Checking const.c...
+
+ If a proper const.cfg is provided, the
unreachable code is detected:
- # 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.
+ # 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.
- Here is a minimal pure.cfg file:
+ Here is a minimal const.cfg file:
<?xml version="1.0"?>
<def>
<function name="calculate">
- <pure/>
+ <const/>
<arg nr="1"/>
</function>
</def>
diff --git a/samples/syntaxError/out.txt b/samples/syntaxError/out.txt
index 059c1c86c..8f0626044 100644
--- a/samples/syntaxError/out.txt
+++ b/samples/syntaxError/out.txt
@@ -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.
diff --git a/test/testgarbage.cpp b/test/testgarbage.cpp
index 4a1b10432..4f7087ad9 100644
--- a/test/testgarbage.cpp
+++ b/test/testgarbage.cpp
@@ -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());
}
diff --git a/test/testother.cpp b/test/testother.cpp
index e62758c93..821088a50 100644
--- a/test/testother.cpp
+++ b/test/testother.cpp
@@ -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() {
diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp
index 6c68c0766..e298c79ed 100644
--- a/test/testpreprocessor.cpp
+++ b/test/testpreprocessor.cpp
@@ -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 files;
+ std::istringstream istr(filedata);
+ simplecpp::TokenList tokens(istr,files);
+ tokens.removeComments();
+ const std::set configs = preprocessor.getConfigs(tokens);
+ std::string ret;
+ for (std::set::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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(2, static_cast(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 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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(3, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(2, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(3, static_cast(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 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(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 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(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 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(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 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(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 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(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 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 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 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 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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(2, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Expected configurations: "" and "ABC"
- ASSERT_EQUALS(2, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Expected configurations: "" and "ABC"
- ASSERT_EQUALS(2, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(1, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(1, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(3, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(3, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(1, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(3, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(3, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(3, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(4, static_cast(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 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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(3, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(1, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(3, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(1, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(2, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- TODO_ASSERT_EQUALS(2, 1, static_cast(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 actual;
- preprocess(filedata, actual);
-
- // Compare results..
- ASSERT_EQUALS(2, static_cast(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 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 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 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 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 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 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 files;
- std::istringstream istr(filedata);
- simplecpp::TokenList tokens(istr,files);
- tokens.removeComments();
- const std::set configs = preprocessor.getConfigs(tokens);
- std::string ret;
- for (std::set::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 macroUsageList;
+ std::vector 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
diff --git a/test/teststl.cpp b/test/teststl.cpp
index 1e0a5b09e..e1a12db46 100644
--- a/test/teststl.cpp
+++ b/test/teststl.cpp
@@ -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 l1;\n"
+ " list l2;\n"
+ " list::iterator it = l1.begin();\n"
+ " l2.insert(it, l1.end());\n"
+ "}");
+ ASSERT_EQUALS("", errout.str());
}
void iterator4() {
diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp
index 936ec0cd5..67ad7f565 100644
--- a/test/testsymboldatabase.cpp
+++ b/test/testsymboldatabase.cpp
@@ -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);
+ }
}
};
diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp
index 2e940887b..0294f5658 100644
--- a/test/testtokenize.cpp
+++ b/test/testtokenize.cpp
@@ -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 };";
+ 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));
diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp
index 7d96b2251..265227385 100644
--- a/test/testuninitvar.cpp
+++ b/test/testuninitvar.cpp
@@ -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"
diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp
index c6bd4dde7..8c08c8c84 100644
--- a/test/testunusedvar.cpp
+++ b/test/testunusedvar.cpp
@@ -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
diff --git a/test/testvarid.cpp b/test/testvarid.cpp
index 0d375b339..8f9958a9d 100644
--- a/test/testvarid.cpp
+++ b/test/testvarid.cpp
@@ -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 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 using X = Y;\n"
+ "X x;";
+ TODO_ASSERT_EQUALS("\nY 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(code)[0] = 0;"));
diff --git a/tools/daca2.py b/tools/daca2.py
index ef6d2d86c..80c939ad1 100644
--- a/tools/daca2.py
+++ b/tools/daca2.py
@@ -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')
diff --git a/webreport.sh b/webreport.sh
index f47269182..dcc5ef332 100755
--- a/webreport.sh
+++ b/webreport.sh
@@ -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
+