Merge branch 'master' into project
This commit is contained in:
commit
8070c536d5
|
@ -39,6 +39,30 @@
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
</function>
|
</function>
|
||||||
|
<!-- http://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html -->
|
||||||
|
<!-- int access(const char *pathname, int amode); -->
|
||||||
|
<function name="access">
|
||||||
|
<use-retval/>
|
||||||
|
<noreturn>false</noreturn>
|
||||||
|
<leak-ignore/>
|
||||||
|
<arg nr="1">
|
||||||
|
<not-uninit/>
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2">
|
||||||
|
<not-uninit/>
|
||||||
|
</arg>
|
||||||
|
</function>
|
||||||
|
<!-- http://man7.org/linux/man-pages/man3/adjtime.3.html -->
|
||||||
|
<!-- int adjtime(const struct timeval *delta, struct timeval *olddelta); -->
|
||||||
|
<function name="adjtime">
|
||||||
|
<noreturn>false</noreturn>
|
||||||
|
<leak-ignore/>
|
||||||
|
<arg nr="1">
|
||||||
|
<not-uninit/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2"/>
|
||||||
|
</function>
|
||||||
<!-- struct group *getgrnam(const char *name); -->
|
<!-- struct group *getgrnam(const char *name); -->
|
||||||
<function name="getgrnam">
|
<function name="getgrnam">
|
||||||
<use-retval/>
|
<use-retval/>
|
||||||
|
@ -116,6 +140,43 @@
|
||||||
<not-null/>
|
<not-null/>
|
||||||
</arg>
|
</arg>
|
||||||
</function>
|
</function>
|
||||||
|
<!-- http://pubs.opengroup.org/onlinepubs/009695399/functions/fdatasync.html -->
|
||||||
|
<!-- int fdatasync(int fildes); -->
|
||||||
|
<function name="fdatasync">
|
||||||
|
<noreturn>false</noreturn>
|
||||||
|
<leak-ignore/>
|
||||||
|
<arg nr="1">
|
||||||
|
<not-uninit/>
|
||||||
|
</arg>
|
||||||
|
</function>
|
||||||
|
<!-- http://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html -->
|
||||||
|
<!-- int fnmatch(const char *pattern, const char *string, int flags); -->
|
||||||
|
<function name="fnmatch">
|
||||||
|
<pure/>
|
||||||
|
<use-retval/>
|
||||||
|
<noreturn>false</noreturn>
|
||||||
|
<leak-ignore/>
|
||||||
|
<arg nr="1">
|
||||||
|
<not-uninit/>
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2">
|
||||||
|
<not-uninit/>
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3">
|
||||||
|
<not-uninit/>
|
||||||
|
</arg>
|
||||||
|
</function>
|
||||||
|
<!-- http://pubs.opengroup.org/onlinepubs/009695399/functions/fsync.html -->
|
||||||
|
<!-- int fsync(int fildes); -->
|
||||||
|
<function name="fsync">
|
||||||
|
<noreturn>false</noreturn>
|
||||||
|
<leak-ignore/>
|
||||||
|
<arg nr="1">
|
||||||
|
<not-uninit/>
|
||||||
|
</arg>
|
||||||
|
</function>
|
||||||
<!-- int truncate(const char *path, off_t length); -->
|
<!-- int truncate(const char *path, off_t length); -->
|
||||||
<function name="truncate">
|
<function name="truncate">
|
||||||
<noreturn>false</noreturn>
|
<noreturn>false</noreturn>
|
||||||
|
|
|
@ -88,6 +88,22 @@ bool endsWith(const std::string &s, const std::string &e) {
|
||||||
bool sameline(const simplecpp::Token *tok1, const simplecpp::Token *tok2) {
|
bool sameline(const simplecpp::Token *tok1, const simplecpp::Token *tok2) {
|
||||||
return tok1 && tok2 && tok1->location.sameline(tok2->location);
|
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) {
|
void simplecpp::Location::adjust(const std::string &str) {
|
||||||
|
@ -533,7 +549,12 @@ void simplecpp::TokenList::combineOperators() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void simplecpp::TokenList::constFoldUnaryNotPosNeg(simplecpp::Token *tok) {
|
void simplecpp::TokenList::constFoldUnaryNotPosNeg(simplecpp::Token *tok) {
|
||||||
|
const std::string NOT("not");
|
||||||
for (; tok && tok->op != ')'; tok = tok->next) {
|
for (; tok && tok->op != ')'; tok = tok->next) {
|
||||||
|
// "not" might be !
|
||||||
|
if (isAlternativeUnaryOp(tok, NOT))
|
||||||
|
tok->op = '!';
|
||||||
|
|
||||||
if (tok->op == '!' && tok->next && tok->next->number) {
|
if (tok->op == '!' && tok->next && tok->next->number) {
|
||||||
tok->setstr(tok->next->str == "0" ? "1" : "0");
|
tok->setstr(tok->next->str == "0" ? "1" : "0");
|
||||||
deleteToken(tok->next);
|
deleteToken(tok->next);
|
||||||
|
@ -612,7 +633,12 @@ void simplecpp::TokenList::constFoldAddSub(Token *tok) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void simplecpp::TokenList::constFoldComparison(Token *tok) {
|
void simplecpp::TokenList::constFoldComparison(Token *tok) {
|
||||||
|
const std::string NOTEQ("not_eq");
|
||||||
|
|
||||||
for (; tok && tok->op != ')'; tok = tok->next) {
|
for (; tok && tok->op != ')'; tok = tok->next) {
|
||||||
|
if (isAlternativeBinaryOp(tok,NOTEQ))
|
||||||
|
tok->setstr("!=");
|
||||||
|
|
||||||
if (!tok->startsWithOneOf("<>=!"))
|
if (!tok->startsWithOneOf("<>=!"))
|
||||||
continue;
|
continue;
|
||||||
if (!tok->previous || !tok->previous->number)
|
if (!tok->previous || !tok->previous->number)
|
||||||
|
@ -655,7 +681,7 @@ void simplecpp::TokenList::constFoldBitwise(Token *tok)
|
||||||
else
|
else
|
||||||
altop = "xor";
|
altop = "xor";
|
||||||
for (tok = tok1; tok && tok->op != ')'; tok = tok->next) {
|
for (tok = tok1; tok && tok->op != ')'; tok = tok->next) {
|
||||||
if (tok->op != *op && tok->str != altop)
|
if (tok->op != *op && !isAlternativeBinaryOp(tok, altop))
|
||||||
continue;
|
continue;
|
||||||
if (!tok->previous || !tok->previous->number)
|
if (!tok->previous || !tok->previous->number)
|
||||||
continue;
|
continue;
|
||||||
|
@ -677,8 +703,17 @@ void simplecpp::TokenList::constFoldBitwise(Token *tok)
|
||||||
}
|
}
|
||||||
|
|
||||||
void simplecpp::TokenList::constFoldLogicalOp(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) {
|
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;
|
continue;
|
||||||
if (!tok->previous || !tok->previous->number)
|
if (!tok->previous || !tok->previous->number)
|
||||||
continue;
|
continue;
|
||||||
|
@ -686,7 +721,7 @@ void simplecpp::TokenList::constFoldLogicalOp(Token *tok) {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int result;
|
int result;
|
||||||
if (tok->str == "||" || tok->str == "or")
|
if (tok->str == "||")
|
||||||
result = (stringToLL(tok->previous->str) || stringToLL(tok->next->str));
|
result = (stringToLL(tok->previous->str) || stringToLL(tok->next->str));
|
||||||
else /*if (tok->str == "&&")*/
|
else /*if (tok->str == "&&")*/
|
||||||
result = (stringToLL(tok->previous->str) && stringToLL(tok->next->str));
|
result = (stringToLL(tok->previous->str) && stringToLL(tok->next->str));
|
||||||
|
@ -989,14 +1024,14 @@ private:
|
||||||
return ~0U;
|
return ~0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const Token *> getMacroParameters(const Token *nameToken, bool def) const {
|
std::vector<const Token *> getMacroParameters(const Token *nameToken, bool calledInDefine) const {
|
||||||
if (!nameToken->next || nameToken->next->op != '(' || !functionLike())
|
if (!nameToken->next || nameToken->next->op != '(' || !functionLike())
|
||||||
return std::vector<const Token *>();
|
return std::vector<const Token *>();
|
||||||
|
|
||||||
std::vector<const Token *> parametertokens;
|
std::vector<const Token *> parametertokens;
|
||||||
parametertokens.push_back(nameToken->next);
|
parametertokens.push_back(nameToken->next);
|
||||||
unsigned int par = 0U;
|
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 == '(')
|
if (tok->op == '(')
|
||||||
++par;
|
++par;
|
||||||
else if (tok->op == ')') {
|
else if (tok->op == ')') {
|
||||||
|
@ -1023,6 +1058,15 @@ private:
|
||||||
unsigned int par = 0;
|
unsigned int par = 0;
|
||||||
const Token *tok = lpar;
|
const Token *tok = lpar;
|
||||||
while (sameline(lpar, tok)) {
|
while (sameline(lpar, tok)) {
|
||||||
|
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))
|
if (!expandArg(tokens, tok, tok->location, macros, expandedmacros1, expandedmacros, parametertokens))
|
||||||
tokens->push_back(new Token(*tok));
|
tokens->push_back(new Token(*tok));
|
||||||
if (tok->op == '(')
|
if (tok->op == '(')
|
||||||
|
@ -1034,6 +1078,7 @@ private:
|
||||||
}
|
}
|
||||||
tok = tok->next;
|
tok = tok->next;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return sameline(lpar,tok) ? tok : NULL;
|
return sameline(lpar,tok) ? tok : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1056,7 +1101,10 @@ private:
|
||||||
return nameToken->next;
|
return nameToken->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const Token*> parametertokens1(getMacroParameters(nameToken, !expandedmacros1.empty()));
|
const bool calledInDefine = (loc.fileIndex != nameToken->location.fileIndex ||
|
||||||
|
loc.line < nameToken->location.line);
|
||||||
|
|
||||||
|
std::vector<const Token*> parametertokens1(getMacroParameters(nameToken, calledInDefine));
|
||||||
|
|
||||||
if (functionLike()) {
|
if (functionLike()) {
|
||||||
// No arguments => not macro expansion
|
// 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])
|
if (variadic && strAB == "," && tok->previous->previous->str == "," && args.size() >= 1U && tok->next->str == args[args.size()-1U])
|
||||||
removeComma = true;
|
removeComma = true;
|
||||||
|
|
||||||
tok = tok->next->next;
|
|
||||||
|
|
||||||
output->deleteToken(A);
|
output->deleteToken(A);
|
||||||
|
|
||||||
if (!removeComma) {
|
if (!removeComma) {
|
||||||
|
@ -1154,14 +1200,22 @@ private:
|
||||||
// TODO: For functionLike macros, push the (...)
|
// TODO: For functionLike macros, push the (...)
|
||||||
expandToken(output, loc, tokens.cfront(), macros, expandedmacros1, expandedmacros, parametertokens2);
|
expandToken(output, loc, tokens.cfront(), macros, expandedmacros1, expandedmacros, parametertokens2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tok = tok->next->next;
|
||||||
} else {
|
} else {
|
||||||
// #123 => "123"
|
// #123 => "123"
|
||||||
TokenList tokenListHash(files);
|
TokenList tokenListHash(files);
|
||||||
tok = expandToken(&tokenListHash, loc, tok, macros, expandedmacros1, expandedmacros, parametertokens2);
|
tok = expandToken(&tokenListHash, loc, tok, macros, expandedmacros1, expandedmacros, parametertokens2);
|
||||||
std::string s;
|
std::ostringstream ostr;
|
||||||
for (const Token *hashtok = tokenListHash.cfront(); hashtok; hashtok = hashtok->next)
|
for (const Token *hashtok = tokenListHash.cfront(); hashtok; hashtok = hashtok->next) {
|
||||||
s += hashtok->str;
|
for (unsigned int i = 0; i < hashtok->str.size(); i++) {
|
||||||
output->push_back(newMacroToken('\"' + s + '\"', loc, expandedmacros1.empty()));
|
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("or");
|
||||||
altop.insert("bitand");
|
altop.insert("bitand");
|
||||||
altop.insert("bitor");
|
altop.insert("bitor");
|
||||||
|
altop.insert("not");
|
||||||
|
altop.insert("not_eq");
|
||||||
altop.insert("xor");
|
altop.insert("xor");
|
||||||
for (simplecpp::Token *tok = expr.front(); tok; tok = tok->next) {
|
for (simplecpp::Token *tok = expr.front(); tok; tok = tok->next) {
|
||||||
if (tok->name) {
|
if (tok->name) {
|
||||||
if (altop.find(tok->str) != altop.end()) {
|
if (altop.find(tok->str) != altop.end()) {
|
||||||
bool alt = true;
|
bool alt;
|
||||||
if (!tok->previous || !tok->next)
|
if (tok->str == "not") {
|
||||||
alt = false;
|
alt = isAlternativeUnaryOp(tok,tok->str);
|
||||||
if (!(tok->previous->number || tok->previous->op == ')'))
|
} else {
|
||||||
alt = false;
|
alt = isAlternativeBinaryOp(tok,tok->str);
|
||||||
|
}
|
||||||
if (alt)
|
if (alt)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1639,20 +1696,38 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
const bool systemheader = (rawtok->next->str[0] == '<');
|
const bool systemheader = (rawtok->next->str[0] == '<');
|
||||||
const std::string header(rawtok->next->str.substr(1U, rawtok->next->str.size() - 2U));
|
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);
|
const std::string header2 = getFileName(filedata, rawtok->location.file(), header, dui, systemheader);
|
||||||
if (!header2.empty() && pragmaOnce.find(header2) == pragmaOnce.end()) {
|
if (header2.empty()) {
|
||||||
includetokenstack.push(gotoNextLine(rawtok));
|
|
||||||
const TokenList *includetokens = filedata.find(header2)->second;
|
|
||||||
rawtok = includetokens ? includetokens->cfront() : 0;
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
simplecpp::Output output(files);
|
simplecpp::Output output(files);
|
||||||
output.type = Output::MISSING_INCLUDE;
|
output.type = Output::MISSING_HEADER;
|
||||||
output.location = rawtok->location;
|
output.location = rawtok->location;
|
||||||
output.msg = "Header not found: " + rawtok->next->str;
|
output.msg = "Header not found: " + rawtok->next->str;
|
||||||
if (outputList)
|
if (outputList)
|
||||||
outputList->push_back(output);
|
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) {
|
} 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;
|
bool conditionIsTrue;
|
||||||
if (ifstates.top() == ALWAYS_FALSE || (ifstates.top() == ELSE_IS_TRUE && rawtok->str != ELIF))
|
if (ifstates.top() == ALWAYS_FALSE || (ifstates.top() == ELSE_IS_TRUE && rawtok->str != ELIF))
|
||||||
conditionIsTrue = false;
|
conditionIsTrue = false;
|
||||||
|
@ -1691,7 +1766,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
it->second.expand(&value, tok, macros, files);
|
it->second.expand(&value, tok, macros, files);
|
||||||
} catch (Macro::Error &err) {
|
} catch (Macro::Error &err) {
|
||||||
Output out(rawtok->location.files);
|
Output out(rawtok->location.files);
|
||||||
out.type = Output::ERROR;
|
out.type = Output::SYNTAX_ERROR;
|
||||||
out.location = err.location;
|
out.location = err.location;
|
||||||
out.msg = "failed to expand \'" + tok->str + "\', " + err.what;
|
out.msg = "failed to expand \'" + tok->str + "\', " + err.what;
|
||||||
if (outputList)
|
if (outputList)
|
||||||
|
@ -1822,3 +1897,9 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void simplecpp::cleanup(std::map<std::string, TokenList*> &filedata) {
|
||||||
|
for (std::map<std::string, TokenList*>::iterator it = filedata.begin(); it != filedata.end(); ++it)
|
||||||
|
delete it->second;
|
||||||
|
filedata.clear();
|
||||||
|
}
|
||||||
|
|
|
@ -156,7 +156,9 @@ struct SIMPLECPP_LIB Output {
|
||||||
enum Type {
|
enum Type {
|
||||||
ERROR, /* #error */
|
ERROR, /* #error */
|
||||||
WARNING, /* #warning */
|
WARNING, /* #warning */
|
||||||
MISSING_INCLUDE
|
MISSING_HEADER,
|
||||||
|
INCLUDE_NESTED_TOO_DEEPLY,
|
||||||
|
SYNTAX_ERROR
|
||||||
} type;
|
} type;
|
||||||
Location location;
|
Location location;
|
||||||
std::string msg;
|
std::string msg;
|
||||||
|
@ -275,19 +277,21 @@ SIMPLECPP_LIB std::map<std::string, TokenList*> load(const TokenList &rawtokens,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preprocess
|
* 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
|
* @todo simplify interface
|
||||||
|
* @param output TokenList that receives the preprocessing output
|
||||||
|
* @param rawtokens Raw tokenlist for top sourcefile
|
||||||
|
* @param files internal data of simplecpp
|
||||||
|
* @param filedata output from simplecpp::load()
|
||||||
|
* @param dui defines, undefs, and include paths
|
||||||
|
* @param outputList output: list that will receive output messages
|
||||||
|
* @param macroUsage output: macro usage
|
||||||
*/
|
*/
|
||||||
SIMPLECPP_LIB void preprocess(TokenList &output, const TokenList &rawtokens, std::vector<std::string> &files, const std::map<std::string, TokenList*> &filedata, const DUI &dui, OutputList *outputList = 0, std::list<MacroUsage> *macroUsage = 0);
|
SIMPLECPP_LIB void preprocess(TokenList &output, const TokenList &rawtokens, std::vector<std::string> &files, const std::map<std::string, TokenList*> &filedata, const DUI &dui, OutputList *outputList = 0, std::list<MacroUsage> *macroUsage = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deallocate data
|
||||||
|
*/
|
||||||
|
SIMPLECPP_LIB void cleanup(std::map<std::string, TokenList*> &filedata);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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
|
if (tok1->str() == "(" && tok1->previous() && !tok1->previous()->isName()) { // cast => assert that the casts are equal
|
||||||
const Token *t1 = tok1->next();
|
const Token *t1 = tok1->next();
|
||||||
const Token *t2 = tok2->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();
|
t1 = t1->next();
|
||||||
t2 = t2->next();
|
t2 = t2->next();
|
||||||
}
|
}
|
||||||
if (!t1 || !t2 || t1->str() != ")" || t2->str() != ")")
|
if (!t1 || !t2 || t1->str() != ")" || t2->str() != ")")
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool noncommuative_equals =
|
bool noncommutativeEquals =
|
||||||
isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand1(), constFunctions);
|
isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand1(), constFunctions);
|
||||||
noncommuative_equals = noncommuative_equals &&
|
noncommutativeEquals = noncommutativeEquals &&
|
||||||
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand2(), constFunctions);
|
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand2(), constFunctions);
|
||||||
|
|
||||||
if (noncommuative_equals)
|
if (noncommutativeEquals)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const bool commutative = tok1->astOperand1() && tok1->astOperand2() && Token::Match(tok1, "%or%|%oror%|+|*|&|&&|^|==|!=");
|
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);
|
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand1(), constFunctions);
|
||||||
commuative_equals = commuative_equals &&
|
commutativeEquals = commutativeEquals &&
|
||||||
isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand2(), constFunctions);
|
isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand2(), constFunctions);
|
||||||
|
|
||||||
// in c++, "a"+b might be different to b+"a"
|
// 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)) {
|
(tok1->astOperand1()->tokType() == Token::eString || tok1->astOperand2()->tokType() == Token::eString)) {
|
||||||
const Token * const other = tok1->astOperand1()->tokType() != Token::eString ? tok1->astOperand1() : tok1->astOperand2();
|
const Token * const other = tok1->astOperand1()->tokType() != Token::eString ? tok1->astOperand1() : tok1->astOperand2();
|
||||||
return other && astIsIntegral(other,false);
|
return other && astIsIntegral(other,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return commuative_equals;
|
return commutativeEquals;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions)
|
bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions)
|
||||||
|
|
|
@ -1777,7 +1777,7 @@ CheckBufferOverrun::ArrayInfo::ArrayInfo(const Variable *var, const SymbolDataba
|
||||||
_num.push_back(var->dimension(i));
|
_num.push_back(var->dimension(i));
|
||||||
if (var->typeEndToken()->str() == "*")
|
if (var->typeEndToken()->str() == "*")
|
||||||
_element_size = symDb->sizeOfType(var->typeEndToken());
|
_element_size = symDb->sizeOfType(var->typeEndToken());
|
||||||
else if (var->typeStartToken()->str() == "struct")
|
else if (var->typeStartToken()->strAt(-1) == "struct")
|
||||||
_element_size = 100;
|
_element_size = 100;
|
||||||
else {
|
else {
|
||||||
_element_size = symDb->sizeOfType(var->typeEndToken());
|
_element_size = symDb->sizeOfType(var->typeEndToken());
|
||||||
|
|
|
@ -1438,15 +1438,17 @@ bool CheckClass::hasAllocation(const Function *func, const Scope* scope) const
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// check for deallocating memory
|
// check for deallocating memory
|
||||||
const Token *var = nullptr;
|
const Token *var;
|
||||||
if (Token::Match(tok, "free ( %var%"))
|
if (Token::Match(tok, "free ( %var%"))
|
||||||
var = tok->tokAt(2);
|
var = tok->tokAt(2);
|
||||||
else if (Token::Match(tok, "delete [ ] %var%"))
|
else if (Token::Match(tok, "delete [ ] %var%"))
|
||||||
var = tok->tokAt(3);
|
var = tok->tokAt(3);
|
||||||
else if (Token::Match(tok, "delete %var%"))
|
else if (Token::Match(tok, "delete %var%"))
|
||||||
var = tok->next();
|
var = tok->next();
|
||||||
|
else
|
||||||
|
continue;
|
||||||
// Check for assignment to the deleted pointer (only if its a member of the class)
|
// 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()) {
|
for (const Token *tok1 = var->next(); tok1 && (tok1 != last); tok1 = tok1->next()) {
|
||||||
if (Token::Match(tok1, "%varid% =", var->varId()))
|
if (Token::Match(tok1, "%varid% =", var->varId()))
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
static const CWE CWE252(252U); // Unchecked Return Value
|
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 CWE758(758U); // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior
|
||||||
static const CWE CWE628(628U); // Function Call with Incorrectly Specified Arguments
|
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);
|
const Library::WarnInfo* wi = _settings->library.getWarnInfo(tok);
|
||||||
if (wi) {
|
if (wi) {
|
||||||
if (_settings->isEnabled(Severity::toString(wi->severity)) && _settings->standards.c >= wi->standards.c && _settings->standards.cpp >= wi->standards.cpp) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,11 +34,13 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CVE ID used:
|
// 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 CWE398(398U); // Indicator of Poor Code Quality
|
||||||
static const CWE CWE664(664U);
|
static const CWE CWE664(664U); // Improper Control of a Resource Through its Lifetime
|
||||||
static const CWE CWE685(685U);
|
static const CWE CWE685(685U); // Function Call With Incorrect Number of Arguments
|
||||||
static const CWE CWE687(687U);
|
static const CWE CWE686(686U); // Function Call With Incorrect Argument Type
|
||||||
static const CWE CWE910(910U);
|
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;
|
// std::cout << std::cout;
|
||||||
|
@ -426,8 +428,7 @@ void CheckIO::invalidScanfError(const Token *tok)
|
||||||
reportError(tok, Severity::warning,
|
reportError(tok, Severity::warning,
|
||||||
"invalidscanf", fname + "() without field width limits can crash with huge input data.\n" +
|
"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 "
|
fname + "() without field width limits can crash with huge input data. Add a field width "
|
||||||
"specifier to fix this problem:\n"
|
"specifier to fix this problem.\n"
|
||||||
" %s => %20s\n"
|
|
||||||
"\n"
|
"\n"
|
||||||
"Sample program that can crash:\n"
|
"Sample program that can crash:\n"
|
||||||
"\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 "
|
"here is 'scanf(\"%4s\", c);', as the maximum field width does not include the "
|
||||||
"terminating null byte.\n"
|
"terminating null byte.\n"
|
||||||
"Source: http://linux.die.net/man/3/scanf\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 {
|
} else {
|
||||||
errmsg << "referencing parameter " << index << " while " << numFunction << " arguments given";
|
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)
|
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 ";
|
errmsg << " *\' but the argument type is ";
|
||||||
argumentType(errmsg, argInfo);
|
argumentType(errmsg, argInfo);
|
||||||
errmsg << ".";
|
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)
|
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 ";
|
errmsg << " *\' but the argument type is ";
|
||||||
argumentType(errmsg, argInfo);
|
argumentType(errmsg, argInfo);
|
||||||
errmsg << ".";
|
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)
|
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 ";
|
errmsg << " *\' but the argument type is ";
|
||||||
argumentType(errmsg, argInfo);
|
argumentType(errmsg, argInfo);
|
||||||
errmsg << ".";
|
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)
|
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 ";
|
errmsg << "%s in format string (no. " << numFormat << ") requires \'char *\' but the argument type is ";
|
||||||
argumentType(errmsg, argInfo);
|
argumentType(errmsg, argInfo);
|
||||||
errmsg << ".";
|
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)
|
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 ";
|
errmsg << "%n in format string (no. " << numFormat << ") requires \'int *\' but the argument type is ";
|
||||||
argumentType(errmsg, argInfo);
|
argumentType(errmsg, argInfo);
|
||||||
errmsg << ".";
|
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)
|
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 ";
|
errmsg << "%p in format string (no. " << numFormat << ") requires an address but the argument type is ";
|
||||||
argumentType(errmsg, argInfo);
|
argumentType(errmsg, argInfo);
|
||||||
errmsg << ".";
|
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)
|
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 ";
|
errmsg << " but the argument type is ";
|
||||||
argumentType(errmsg, argInfo);
|
argumentType(errmsg, argInfo);
|
||||||
errmsg << ".";
|
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)
|
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 ";
|
errmsg << " but the argument type is ";
|
||||||
argumentType(errmsg, argInfo);
|
argumentType(errmsg, argInfo);
|
||||||
errmsg << ".";
|
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)
|
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 ";
|
errmsg << "double\' but the argument type is ";
|
||||||
argumentType(errmsg, argInfo);
|
argumentType(errmsg, argInfo);
|
||||||
errmsg << ".";
|
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)
|
void CheckIO::argumentType(std::ostream& os, const ArgumentInfo * argInfo)
|
||||||
|
|
|
@ -1472,7 +1472,7 @@ void CheckOther::checkPassByReference()
|
||||||
while (tok3 && tok3->str() != "(") {
|
while (tok3 && tok3->str() != "(") {
|
||||||
if (tok3->link() && Token::Match(tok3, ")|]|}|>"))
|
if (tok3->link() && Token::Match(tok3, ")|]|}|>"))
|
||||||
tok3 = tok3->link();
|
tok3 = tok3->link();
|
||||||
else if (tok->link())
|
else if (tok3->link())
|
||||||
break;
|
break;
|
||||||
else if (tok3->str() == ";")
|
else if (tok3->str() == ";")
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -165,6 +165,20 @@ void CheckStl::iterators()
|
||||||
if (itTok->previous()->str() == "*")
|
if (itTok->previous()->str() == "*")
|
||||||
continue;
|
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.
|
// Show error message, mismatching iterator is used.
|
||||||
iteratorsError(tok2, container->name(), tok2->str());
|
iteratorsError(tok2, container->name(), tok2->str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,10 @@ void CheckUninitVar::checkScope(const Scope* scope)
|
||||||
if (!tok)
|
if (!tok)
|
||||||
continue;
|
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()) {
|
if (i->isArray()) {
|
||||||
Alloc alloc = ARRAY;
|
Alloc alloc = ARRAY;
|
||||||
checkScopeForVariable(tok, *i, nullptr, nullptr, &alloc, "");
|
checkScopeForVariable(tok, *i, nullptr, nullptr, &alloc, "");
|
||||||
|
@ -117,12 +121,12 @@ void CheckUninitVar::checkScope(const Scope* scope)
|
||||||
if (scope->function) {
|
if (scope->function) {
|
||||||
for (unsigned int i = 0; i < scope->function->argCount(); i++) {
|
for (unsigned int i = 0; i < scope->function->argCount(); i++) {
|
||||||
const Variable *arg = scope->function->getArgumentVar(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
|
// Treat the pointer as initialized until it is assigned by malloc
|
||||||
for (const Token *tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
|
for (const Token *tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
|
||||||
if (Token::Match(tok, "[;{}] %varid% = %name% (", arg->declarationId()) &&
|
if (Token::Match(tok, "[;{}] %varid% = %name% (", arg->declarationId()) &&
|
||||||
_settings->library.returnuninitdata.count(tok->strAt(3)) == 1U) {
|
_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);
|
checkStruct(tok, *arg);
|
||||||
else if (arg->typeStartToken()->isStandardType() || arg->typeStartToken()->isEnumType()) {
|
else if (arg->typeStartToken()->isStandardType() || arg->typeStartToken()->isEnumType()) {
|
||||||
Alloc alloc = NO_ALLOC;
|
Alloc alloc = NO_ALLOC;
|
||||||
|
@ -138,8 +142,6 @@ void CheckUninitVar::checkScope(const Scope* scope)
|
||||||
void CheckUninitVar::checkStruct(const Token *tok, const Variable &structvar)
|
void CheckUninitVar::checkStruct(const Token *tok, const Variable &structvar)
|
||||||
{
|
{
|
||||||
const Token *typeToken = structvar.typeStartToken();
|
const Token *typeToken = structvar.typeStartToken();
|
||||||
if (typeToken->str() == "struct")
|
|
||||||
typeToken = typeToken->next();
|
|
||||||
const SymbolDatabase * symbolDatabase = _tokenizer->getSymbolDatabase();
|
const SymbolDatabase * symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||||
for (std::size_t j = 0U; j < symbolDatabase->classAndStructScopes.size(); ++j) {
|
for (std::size_t j = 0U; j < symbolDatabase->classAndStructScopes.size(); ++j) {
|
||||||
const Scope *scope2 = symbolDatabase->classAndStructScopes[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 (vartok->previous()->str() != "&" || !Token::Match(vartok->tokAt(-2), "[(,=?:]")) {
|
||||||
if (alloc != NO_ALLOC && vartok->previous()->str() == "*") {
|
if (alloc != NO_ALLOC && vartok->previous()->str() == "*") {
|
||||||
|
// TestUninitVar::isVariableUsageDeref()
|
||||||
const Token *parent = vartok->previous()->astParent();
|
const Token *parent = vartok->previous()->astParent();
|
||||||
if (parent && parent->str() == "=" && parent->astOperand1() == vartok->previous())
|
if (parent && parent->str() == "=" && parent->astOperand1() == vartok->previous())
|
||||||
return false;
|
return false;
|
||||||
|
if (vartok->variable() && vartok->variable()->dimensions().size() >= 2)
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return alloc == NO_ALLOC;
|
return alloc == NO_ALLOC;
|
||||||
|
@ -1014,9 +1019,9 @@ int CheckUninitVar::isFunctionParUsage(const Token *vartok, bool pointer, Alloc
|
||||||
const Variable *arg = func->getArgumentVar(argumentNumber);
|
const Variable *arg = func->getArgumentVar(argumentNumber);
|
||||||
if (arg) {
|
if (arg) {
|
||||||
const Token *argStart = arg->typeStartToken();
|
const Token *argStart = arg->typeStartToken();
|
||||||
if (!address && !array && Token::Match(argStart, "struct| %type% %name%| [,)]"))
|
if (!address && !array && Token::Match(argStart, "%type% %name%| [,)]"))
|
||||||
return 1;
|
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;
|
return 1;
|
||||||
while (argStart->previous() && argStart->previous()->isName())
|
while (argStart->previous() && argStart->previous()->isName())
|
||||||
argStart = argStart->previous();
|
argStart = argStart->previous();
|
||||||
|
|
|
@ -1072,6 +1072,11 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
|
||||||
} else if (Token::Match(tok, "[(,] (") &&
|
} else if (Token::Match(tok, "[(,] (") &&
|
||||||
Token::Match(tok->next()->link(), ") %var% [,)]")) {
|
Token::Match(tok->next()->link(), ") %var% [,)]")) {
|
||||||
variables.use(tok->next()->link()->next()->varId(), tok); // use = read + write
|
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
|
// function
|
||||||
|
@ -1265,6 +1270,17 @@ void CheckUnusedVar::checkStructMemberUsage()
|
||||||
if (Token::findmatch(scope->classEnd, castPattern.c_str()))
|
if (Token::findmatch(scope->classEnd, castPattern.c_str()))
|
||||||
continue;
|
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.
|
// Try to prevent false positives when struct members are not used directly.
|
||||||
if (Token::findmatch(scope->classEnd, (scope->className + " %type%| *").c_str()))
|
if (Token::findmatch(scope->classEnd, (scope->className + " %type%| *").c_str()))
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -74,21 +74,28 @@ Library::Error Library::load(const char exename[], const char path[])
|
||||||
absolute_path = Path::getAbsoluteFilePath(fullfilename);
|
absolute_path = Path::getAbsoluteFilePath(fullfilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND) {
|
std::list<std::string> cfgfolders;
|
||||||
// Try to locate the library configuration in the installation folder..
|
|
||||||
#ifdef CFGDIR
|
#ifdef CFGDIR
|
||||||
const std::string cfgfolder(CFGDIR);
|
cfgfolders.push_back(CFGDIR);
|
||||||
#else
|
|
||||||
if (!exename)
|
|
||||||
return Error(FILE_NOT_FOUND);
|
|
||||||
const std::string cfgfolder(Path::fromNativeSeparators(Path::getPathFromFilename(exename)) + "cfg");
|
|
||||||
#endif
|
#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 char *sep = (!cfgfolder.empty() && cfgfolder[cfgfolder.size()-1U]=='/' ? "" : "/");
|
||||||
const std::string filename(cfgfolder + sep + fullfilename);
|
const std::string filename(cfgfolder + sep + fullfilename);
|
||||||
error = doc.LoadFile(filename.c_str());
|
error = doc.LoadFile(filename.c_str());
|
||||||
if (error != tinyxml2::XML_ERROR_FILE_NOT_FOUND)
|
if (error != tinyxml2::XML_ERROR_FILE_NOT_FOUND)
|
||||||
absolute_path = Path::getAbsoluteFilePath(filename);
|
absolute_path = Path::getAbsoluteFilePath(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND)
|
||||||
|
return Error(FILE_NOT_FOUND);
|
||||||
} else
|
} else
|
||||||
absolute_path = Path::getAbsoluteFilePath(path);
|
absolute_path = Path::getAbsoluteFilePath(path);
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,8 @@ namespace tinyxml2 {
|
||||||
* @brief Library definitions handling
|
* @brief Library definitions handling
|
||||||
*/
|
*/
|
||||||
class CPPCHECKLIB Library {
|
class CPPCHECKLIB Library {
|
||||||
|
friend class TestSymbolDatabase; // For testing only
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Library();
|
Library();
|
||||||
|
|
||||||
|
|
|
@ -496,39 +496,23 @@ std::string Preprocessor::getcode(const simplecpp::TokenList &tokens1, const std
|
||||||
return "";
|
return "";
|
||||||
case simplecpp::Output::WARNING:
|
case simplecpp::Output::WARNING:
|
||||||
break;
|
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 pos1 = it->msg.find_first_of("<\"");
|
||||||
const std::string::size_type pos2 = it->msg.find_first_of(">\"", pos1 + 1U);
|
const std::string::size_type pos2 = it->msg.find_first_of(">\"", pos1 + 1U);
|
||||||
if (pos1 < pos2 && pos2 != std::string::npos)
|
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);
|
missingInclude(it->location.file(), it->location.line, it->msg.substr(pos1+1, pos2-pos1-1), it->msg[pos1] == '\"' ? UserHeader : SystemHeader);
|
||||||
}
|
}
|
||||||
break;
|
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
|
// ensure that guessed define macros without value are not used in the code
|
||||||
for (std::list<std::string>::const_iterator defineIt = dui.defines.begin(); defineIt != dui.defines.end(); ++defineIt) {
|
if (!validateCfg(cfg, macroUsage))
|
||||||
if (defineIt->find("=") != std::string::npos)
|
|
||||||
continue;
|
|
||||||
const std::string macroName = defineIt->substr(0, std::min(defineIt->find("="), defineIt->find("(")));
|
|
||||||
for (std::list<simplecpp::MacroUsage>::const_iterator usageIt = macroUsage.begin(); usageIt != macroUsage.end(); ++usageIt) {
|
|
||||||
const simplecpp::MacroUsage &mu = *usageIt;
|
|
||||||
if (mu.macroName != macroName)
|
|
||||||
continue;
|
|
||||||
bool directiveLocation = false;
|
|
||||||
for (std::list<Directive>::const_iterator dirIt = directives.begin(); dirIt != directives.end(); ++dirIt) {
|
|
||||||
if (mu.useLocation.file() == dirIt->file && mu.useLocation.line == dirIt->linenr) {
|
|
||||||
directiveLocation = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!directiveLocation) {
|
|
||||||
if (_settings.isEnabled("information"))
|
|
||||||
validateCfgError(cfg, macroName);
|
|
||||||
return "";
|
return "";
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// assembler code locations..
|
// assembler code locations..
|
||||||
std::set<simplecpp::Location> assemblerLocations;
|
std::set<simplecpp::Location> assemblerLocations;
|
||||||
|
@ -620,11 +604,13 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string
|
||||||
for (simplecpp::OutputList::const_iterator it = outputList.begin(); it != outputList.end(); ++it) {
|
for (simplecpp::OutputList::const_iterator it = outputList.begin(); it != outputList.end(); ++it) {
|
||||||
switch (it->type) {
|
switch (it->type) {
|
||||||
case simplecpp::Output::ERROR:
|
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);
|
error(it->location.file(), it->location.line, it->msg);
|
||||||
return "";
|
return "";
|
||||||
case simplecpp::Output::WARNING:
|
case simplecpp::Output::WARNING:
|
||||||
break;
|
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 pos1 = it->msg.find_first_of("<\"");
|
||||||
const std::string::size_type pos2 = it->msg.find_first_of(">\"", pos1 + 1U);
|
const std::string::size_type pos2 = it->msg.find_first_of(">\"", pos1 + 1U);
|
||||||
if (pos1 < pos2 && pos2 != std::string::npos)
|
if (pos1 < pos2 && pos2 != std::string::npos)
|
||||||
|
@ -684,72 +670,42 @@ void Preprocessor::missingInclude(const std::string &filename, unsigned int line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Preprocessor::validateCfg(const std::string &code, const std::string &cfg)
|
bool Preprocessor::validateCfg(const std::string &cfg, const std::list<simplecpp::MacroUsage> ¯oUsageList)
|
||||||
{
|
{
|
||||||
const bool printInformation = _settings.isEnabled("information");
|
bool ret = true;
|
||||||
|
std::list<std::string> defines;
|
||||||
// fill up "macros" with empty configuration macros
|
splitcfg(cfg, defines, std::string());
|
||||||
std::set<std::string> macros;
|
for (std::list<std::string>::const_iterator defineIt = defines.begin(); defineIt != defines.end(); ++defineIt) {
|
||||||
for (std::string::size_type pos = 0; pos < cfg.size();) {
|
if (defineIt->find("=") != std::string::npos)
|
||||||
const std::string::size_type pos2 = cfg.find_first_of(";=", pos);
|
continue;
|
||||||
if (pos2 == std::string::npos) {
|
const std::string macroName(defineIt->substr(0, defineIt->find("(")));
|
||||||
macros.insert(cfg.substr(pos));
|
for (std::list<simplecpp::MacroUsage>::const_iterator usageIt = macroUsageList.begin(); usageIt != macroUsageList.end(); ++usageIt) {
|
||||||
|
const simplecpp::MacroUsage &mu = *usageIt;
|
||||||
|
if (mu.macroName != macroName)
|
||||||
|
continue;
|
||||||
|
bool directiveLocation = false;
|
||||||
|
for (std::list<Directive>::const_iterator dirIt = directives.begin(); dirIt != directives.end(); ++dirIt) {
|
||||||
|
if (mu.useLocation.file() == dirIt->file && mu.useLocation.line == dirIt->linenr) {
|
||||||
|
directiveLocation = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (cfg[pos2] == ';')
|
|
||||||
macros.insert(cfg.substr(pos, pos2-pos));
|
|
||||||
pos = cfg.find(';', pos2);
|
|
||||||
if (pos != std::string::npos)
|
|
||||||
++pos;
|
|
||||||
}
|
}
|
||||||
|
if (!directiveLocation) {
|
||||||
// check if any empty macros are used in code
|
if (_settings.isEnabled("information"))
|
||||||
for (std::set<std::string>::const_iterator it = macros.begin(); it != macros.end(); ++it) {
|
validateCfgError(mu.useLocation.file(), mu.useLocation.line, cfg, macroName);
|
||||||
const std::string ¯o = *it;
|
ret = false;
|
||||||
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;
|
|
||||||
}
|
|
||||||
++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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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";
|
const std::string id = "ConfigurationNotChecked";
|
||||||
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
||||||
ErrorLogger::ErrorMessage::FileLocation loc(file0, 1);
|
ErrorLogger::ErrorMessage::FileLocation loc(file, line);
|
||||||
locationList.push_back(loc);
|
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::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);
|
_errorLogger->reportInfo(errmsg);
|
||||||
|
@ -762,7 +718,7 @@ void Preprocessor::getErrorMessages(ErrorLogger *errorLogger, const Settings *se
|
||||||
settings2.checkConfiguration=true;
|
settings2.checkConfiguration=true;
|
||||||
preprocessor.missingInclude("", 1, "", UserHeader);
|
preprocessor.missingInclude("", 1, "", UserHeader);
|
||||||
preprocessor.missingInclude("", 1, "", SystemHeader);
|
preprocessor.missingInclude("", 1, "", SystemHeader);
|
||||||
preprocessor.validateCfgError("X", "X");
|
preprocessor.validateCfgError("", 1, "X", "X");
|
||||||
preprocessor.error("", 1, "#error message"); // #error ..
|
preprocessor.error("", 1, "#error message"); // #error ..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -153,12 +153,12 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* make sure empty configuration macros are not used in code. the given code must be a single configuration
|
* 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 cfg configuration
|
||||||
|
* @param macroUsageList macro usage list
|
||||||
* @return true => configuration is valid
|
* @return true => configuration is valid
|
||||||
*/
|
*/
|
||||||
bool validateCfg(const std::string &code, const std::string &cfg);
|
bool validateCfg(const std::string &cfg, const std::list<simplecpp::MacroUsage> ¯oUsageList);
|
||||||
void validateCfgError(const std::string &cfg, const std::string ¯o);
|
void validateCfgError(const std::string &file, const unsigned int line, const std::string &cfg, const std::string ¯o);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -293,6 +293,23 @@ public:
|
||||||
platformType == Win64;
|
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
|
* @brief return true if a file is to be excluded from configuration checking
|
||||||
* @return true for the file to be excluded.
|
* @return true for the file to be excluded.
|
||||||
|
|
|
@ -1088,19 +1088,19 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
if (start != end && start->next() != end) {
|
if (start != end && start->next() != end) {
|
||||||
for (Token* tok = start->next(); tok != end; tok = tok->next()) {
|
for (Token* tok = start->next(); tok != end; tok = tok->next()) {
|
||||||
if (tok->str() == "{") {
|
if (tok->str() == "{") {
|
||||||
bool break2 = false;
|
bool isEndOfScope = false;
|
||||||
for (std::list<Scope*>::const_iterator innerScope = it->nestedList.begin(); innerScope != it->nestedList.end(); ++innerScope) {
|
for (std::list<Scope*>::const_iterator innerScope = it->nestedList.begin(); innerScope != it->nestedList.end(); ++innerScope) {
|
||||||
if (tok == (*innerScope)->classStart) { // Is begin of inner scope
|
if (tok == (*innerScope)->classStart) { // Is begin of inner scope
|
||||||
tok = tok->link();
|
tok = tok->link();
|
||||||
if (!tok || tok->next() == end || !tok->next()) {
|
if (!tok || tok->next() == end || !tok->next()) {
|
||||||
break2 = true;
|
isEndOfScope = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (break2)
|
if (isEndOfScope)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tok->scope(&*it);
|
tok->scope(&*it);
|
||||||
|
@ -1817,9 +1817,9 @@ bool Function::argsMatch(const Scope *scope, const Token *first, const Token *se
|
||||||
second = second->next();
|
second = second->next();
|
||||||
|
|
||||||
// skip "struct"
|
// skip "struct"
|
||||||
if (first->str() == "struct")
|
if (first->str() == "struct" || first->str() == "enum")
|
||||||
first = first->next();
|
first = first->next();
|
||||||
if (second->str() == "struct")
|
if (second->str() == "struct" || second->str() == "enum")
|
||||||
second = second->next();
|
second = second->next();
|
||||||
|
|
||||||
// skip const on type passed by value
|
// 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 << " isStlType: " << var->isStlType() << std::endl;
|
||||||
std::cout << indent << "_type: ";
|
std::cout << indent << "_type: ";
|
||||||
if (var->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 << " " << _tokenizer->list.fileLine(var->type()->classDef);
|
||||||
std::cout << " " << var->type() << std::endl;
|
std::cout << " " << var->type() << std::endl;
|
||||||
} else
|
} else
|
||||||
|
@ -2466,6 +2466,7 @@ void SymbolDatabase::printOut(const char *title) const
|
||||||
std::cout << " isOperator: " << func->isOperator() << std::endl;
|
std::cout << " isOperator: " << func->isOperator() << std::endl;
|
||||||
std::cout << " hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl;
|
std::cout << " hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl;
|
||||||
std::cout << " hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl;
|
std::cout << " hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl;
|
||||||
|
std::cout << " isVariadic: " << func->isVariadic() << std::endl;
|
||||||
std::cout << " attributes:";
|
std::cout << " attributes:";
|
||||||
if (func->isAttributeConst())
|
if (func->isAttributeConst())
|
||||||
std::cout << " const ";
|
std::cout << " const ";
|
||||||
|
@ -2818,11 +2819,20 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
|
||||||
} while (tok->str() != "," && tok->str() != ")");
|
} 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));
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// count default arguments
|
// count default arguments
|
||||||
for (const Token* tok = argDef->next(); tok && tok != argDef->link(); tok = tok->next()) {
|
for (const Token* tok = argDef->next(); tok && tok != argDef->link(); tok = tok->next()) {
|
||||||
|
@ -3177,6 +3187,10 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess, con
|
||||||
const_cast<Token *>(typetok)->type(vType);
|
const_cast<Token *>(typetok)->type(vType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// skip "enum" or "struct"
|
||||||
|
if (Token::Match(typestart, "enum|struct"))
|
||||||
|
typestart = typestart->next();
|
||||||
|
|
||||||
addVariable(vartok, typestart, vartok->previous(), varaccess, vType, this, lib);
|
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)
|
if (type)
|
||||||
return type;
|
return type;
|
||||||
|
|
||||||
|
type = findVariableTypeInBase(scope, typeTok);
|
||||||
|
|
||||||
|
if (type)
|
||||||
|
return type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<Type>::const_iterator type;
|
std::list<Type>::const_iterator type;
|
||||||
|
@ -3490,8 +3511,27 @@ const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *ty
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type->enclosingScope == parent)
|
if (type->enclosingScope == parent) {
|
||||||
|
// check if "enum" specified and type is enum
|
||||||
|
if (typeTok->strAt(-1) == "enum") {
|
||||||
|
if (type->isEnumType())
|
||||||
return &(*type);
|
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
|
// 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();
|
const std::size_t args = arguments.size();
|
||||||
for (std::multimap<std::string, const Function *>::const_iterator it = functionMap.find(tok->str()); it != functionMap.end() && it->first == tok->str(); ++it) {
|
for (std::multimap<std::string, const Function *>::const_iterator it = functionMap.find(tok->str()); it != functionMap.end() && it->first == tok->str(); ++it) {
|
||||||
const Function *func = it->second;
|
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);
|
matches.push_back(func);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3598,6 +3640,10 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
|
||||||
const Function * func = matches[i];
|
const Function * func = matches[i];
|
||||||
size_t same = 0;
|
size_t same = 0;
|
||||||
for (std::size_t j = 0; j < args; ++j) {
|
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);
|
const Variable *funcarg = func->getArgumentVar(j);
|
||||||
// check for a match with a variable
|
// check for a match with a variable
|
||||||
if (Token::Match(arguments[j], "%var% ,|)")) {
|
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
|
// check for a match with a numeric literal
|
||||||
else if (Token::Match(arguments[j], "%num% ,|)")) {
|
else if (Token::Match(arguments[j], "%num% ,|)")) {
|
||||||
if (MathLib::isInt(arguments[j]->str())) {
|
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
|
// check that function argument type is not mismatching
|
||||||
else if (arguments[j]->str() == "&" && funcarg && funcarg->isReference()) {
|
else if (arguments[j]->str() == "&" && funcarg && funcarg->isReference()) {
|
||||||
// can't match so remove this function from possible matches
|
// 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
|
// check if all arguments matched
|
||||||
if (same == args) {
|
if ((func->isVariadic() && same == (func->argCount() - 1)) ||
|
||||||
|
(!func->isVariadic() && same == args)) {
|
||||||
if (requireConst && func->isConst())
|
if (requireConst && func->isConst())
|
||||||
return func;
|
return func;
|
||||||
|
|
||||||
|
@ -4099,21 +4173,21 @@ unsigned int SymbolDatabase::sizeOfType(const Token *type) const
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
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);
|
||||||
|
|
||||||
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())
|
if (var.isStlType())
|
||||||
return;
|
return;
|
||||||
ValueType valuetype;
|
ValueType valuetype;
|
||||||
valuetype.pointer = var.dimensions().size();
|
valuetype.pointer = var.dimensions().size();
|
||||||
valuetype.typeScope = var.typeScope();
|
valuetype.typeScope = var.typeScope();
|
||||||
if (parsedecl(var.typeStartToken(), &valuetype, defaultSignedness, lib))
|
if (parsedecl(var.typeStartToken(), &valuetype, defaultSignedness, settings))
|
||||||
setValueType(tok, valuetype, cpp, defaultSignedness, lib);
|
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 valuetype;
|
||||||
valuetype.typeScope = enumerator.scope;
|
valuetype.typeScope = enumerator.scope;
|
||||||
|
@ -4135,22 +4209,18 @@ static void setValueType(Token *tok, const Enumerator &enumerator, bool cpp, Val
|
||||||
else if (type->str() == "long")
|
else if (type->str() == "long")
|
||||||
valuetype.type = type->isLong() ? ValueType::Type::LONGLONG : ValueType::Type::LONG;
|
valuetype.type = type->isLong() ? ValueType::Type::LONGLONG : ValueType::Type::LONG;
|
||||||
else if (type->isStandardType()) {
|
else if (type->isStandardType()) {
|
||||||
const Library::PodType* podtype = lib->podtype(type->str());
|
valuetype.fromLibraryType(type->str(), settings);
|
||||||
if (podtype && (podtype->sign == 's' || podtype->sign == 'u')) {
|
|
||||||
valuetype.type = ValueType::Type::UNKNOWN_INT;
|
|
||||||
valuetype.sign = (podtype->sign == 'u') ? ValueType::UNSIGNED : ValueType::SIGNED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setValueType(tok, valuetype, cpp, defaultSignedness, lib);
|
setValueType(tok, valuetype, cpp, defaultSignedness, settings);
|
||||||
} else {
|
} else {
|
||||||
valuetype.sign = ValueType::SIGNED;
|
valuetype.sign = ValueType::SIGNED;
|
||||||
valuetype.type = ValueType::INT;
|
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));
|
tok->setValueType(new ValueType(valuetype));
|
||||||
Token *parent = const_cast<Token *>(tok->astParent());
|
Token *parent = const_cast<Token *>(tok->astParent());
|
||||||
|
@ -4164,32 +4234,32 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
|
||||||
|
|
||||||
if (vt1 && Token::Match(parent, "<<|>>")) {
|
if (vt1 && Token::Match(parent, "<<|>>")) {
|
||||||
if (!cpp || (vt2 && vt2->isIntegral()))
|
if (!cpp || (vt2 && vt2->isIntegral()))
|
||||||
setValueType(parent, *vt1, cpp, defaultSignedness, lib);
|
setValueType(parent, *vt1, cpp, defaultSignedness, settings);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent->isAssignmentOp()) {
|
if (parent->isAssignmentOp()) {
|
||||||
if (vt1)
|
if (vt1)
|
||||||
setValueType(parent, *vt1, cpp, defaultSignedness, lib);
|
setValueType(parent, *vt1, cpp, defaultSignedness, settings);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent->str() == "[" && (!cpp || parent->astOperand1() == tok) && valuetype.pointer > 0U) {
|
if (parent->str() == "[" && (!cpp || parent->astOperand1() == tok) && valuetype.pointer > 0U) {
|
||||||
ValueType vt(valuetype);
|
ValueType vt(valuetype);
|
||||||
vt.pointer -= 1U;
|
vt.pointer -= 1U;
|
||||||
setValueType(parent, vt, cpp, defaultSignedness, lib);
|
setValueType(parent, vt, cpp, defaultSignedness, settings);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (parent->str() == "*" && !parent->astOperand2() && valuetype.pointer > 0U) {
|
if (parent->str() == "*" && !parent->astOperand2() && valuetype.pointer > 0U) {
|
||||||
ValueType vt(valuetype);
|
ValueType vt(valuetype);
|
||||||
vt.pointer -= 1U;
|
vt.pointer -= 1U;
|
||||||
setValueType(parent, vt, cpp, defaultSignedness, lib);
|
setValueType(parent, vt, cpp, defaultSignedness, settings);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (parent->str() == "&" && !parent->astOperand2()) {
|
if (parent->str() == "&" && !parent->astOperand2()) {
|
||||||
ValueType vt(valuetype);
|
ValueType vt(valuetype);
|
||||||
vt.pointer += 1U;
|
vt.pointer += 1U;
|
||||||
setValueType(parent, vt, cpp, defaultSignedness, lib);
|
setValueType(parent, vt, cpp, defaultSignedness, settings);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4209,7 +4279,7 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (var)
|
if (var)
|
||||||
setValueType(parent, *var, cpp, defaultSignedness, lib);
|
setValueType(parent, *var, cpp, defaultSignedness, settings);
|
||||||
return;
|
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 (ternary || parent->isArithmeticalOp() || parent->tokType() == Token::eIncDecOp) {
|
||||||
if (vt1->pointer != 0U && vt2 && vt2->pointer == 0U) {
|
if (vt1->pointer != 0U && vt2 && vt2->pointer == 0U) {
|
||||||
setValueType(parent, *vt1, cpp, defaultSignedness, lib);
|
setValueType(parent, *vt1, cpp, defaultSignedness, settings);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vt1->pointer == 0U && vt2 && vt2->pointer != 0U) {
|
if (vt1->pointer == 0U && vt2 && vt2->pointer != 0U) {
|
||||||
setValueType(parent, *vt2, cpp, defaultSignedness, lib);
|
setValueType(parent, *vt2, cpp, defaultSignedness, settings);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vt1->pointer != 0U) {
|
if (vt1->pointer != 0U) {
|
||||||
if (ternary || parent->tokType() == Token::eIncDecOp) // result is pointer
|
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
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vt1->type == ValueType::Type::LONGDOUBLE || (vt2 && vt2->type == ValueType::Type::LONGDOUBLE)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (vt1->type == ValueType::Type::DOUBLE || (vt2 && vt2->type == ValueType::Type::DOUBLE)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (vt1->type == ValueType::Type::FLOAT || (vt2 && vt2->type == ValueType::Type::FLOAT)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4284,12 +4354,12 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
|
||||||
vt.originalTypeName.clear();
|
vt.originalTypeName.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
setValueType(parent, vt, cpp, defaultSignedness, lib);
|
setValueType(parent, vt, cpp, defaultSignedness, settings);
|
||||||
return;
|
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;
|
const unsigned int pointer0 = valuetype->pointer;
|
||||||
while (Token::Match(type->previous(), "%name%"))
|
while (Token::Match(type->previous(), "%name%"))
|
||||||
|
@ -4333,13 +4403,8 @@ static const Token * parsedecl(const Token *type, ValueType * const valuetype, V
|
||||||
return nullptr;
|
return nullptr;
|
||||||
else if (type->str() == "*")
|
else if (type->str() == "*")
|
||||||
valuetype->pointer++;
|
valuetype->pointer++;
|
||||||
else if (type->isStandardType()) {
|
else if (type->isStandardType())
|
||||||
const Library::PodType* podtype = lib->podtype(type->str());
|
valuetype->fromLibraryType(type->str(), settings);
|
||||||
if (podtype && (podtype->sign == 's' || podtype->sign == 'u')) {
|
|
||||||
valuetype->type = ValueType::Type::UNKNOWN_INT;
|
|
||||||
valuetype->sign = (podtype->sign == 'u') ? ValueType::UNSIGNED : ValueType::SIGNED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!type->originalName().empty())
|
if (!type->originalName().empty())
|
||||||
valuetype->originalTypeName = type->originalName();
|
valuetype->originalTypeName = type->originalName();
|
||||||
type = type->next();
|
type = type->next();
|
||||||
|
@ -4386,12 +4451,12 @@ static const Function *getOperatorFunction(const Token * const tok)
|
||||||
return nullptr;
|
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;
|
ValueType::Sign defsign;
|
||||||
if (defaultSignedness == 's' || defaultSignedness == 'S')
|
if (settings->defaultSign == 's' || settings->defaultSign == 'S')
|
||||||
defsign = ValueType::SIGNED;
|
defsign = ValueType::SIGNED;
|
||||||
else if (defaultSignedness == 'u' || defaultSignedness == 'U')
|
else if (settings->defaultSign == 'u' || settings->defaultSign == 'U')
|
||||||
defsign = ValueType::UNSIGNED;
|
defsign = ValueType::UNSIGNED;
|
||||||
else
|
else
|
||||||
defsign = ValueType::UNKNOWN_SIGN;
|
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];
|
const char suffix = tok->str()[tok->str().size() - 1U];
|
||||||
if (suffix == 'f' || suffix == 'F')
|
if (suffix == 'f' || suffix == 'F')
|
||||||
type = ValueType::Type::FLOAT;
|
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())) {
|
} else if (MathLib::isInt(tok->str())) {
|
||||||
ValueType::Sign sign = ValueType::Sign::SIGNED;
|
ValueType::Sign sign = ValueType::Sign::SIGNED;
|
||||||
ValueType::Type type = ValueType::Type::INT;
|
ValueType::Type type = ValueType::Type::INT;
|
||||||
|
@ -4423,71 +4488,117 @@ void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, char defau
|
||||||
pos -= 2;
|
pos -= 2;
|
||||||
} else break;
|
} 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) {
|
} else if (tok->isComparisonOp() || tok->tokType() == Token::eLogicalOp) {
|
||||||
if (cpp && tok->isComparisonOp() && (getClassScope(tok->astOperand1()) || getClassScope(tok->astOperand2()))) {
|
if (cpp && tok->isComparisonOp() && (getClassScope(tok->astOperand1()) || getClassScope(tok->astOperand2()))) {
|
||||||
const Function *function = getOperatorFunction(tok);
|
const Function *function = getOperatorFunction(tok);
|
||||||
if (function) {
|
if (function) {
|
||||||
ValueType vt;
|
ValueType vt;
|
||||||
parsedecl(function->retDef, &vt, defsign, lib);
|
parsedecl(function->retDef, &vt, defsign, settings);
|
||||||
::setValueType(tok, vt, cpp, defsign, lib);
|
::setValueType(tok, vt, cpp, defsign, settings);
|
||||||
continue;
|
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)
|
} 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) {
|
else if (tok->tokType() == Token::eString) {
|
||||||
ValueType valuetype(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, 1U, 1U);
|
ValueType valuetype(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, 1U, 1U);
|
||||||
if (tok->isLong()) {
|
if (tok->isLong()) {
|
||||||
valuetype.originalTypeName = "wchar_t";
|
valuetype.originalTypeName = "wchar_t";
|
||||||
valuetype.type = ValueType::Type::SHORT;
|
valuetype.type = ValueType::Type::SHORT;
|
||||||
}
|
}
|
||||||
::setValueType(tok, valuetype, cpp, defsign, lib);
|
::setValueType(tok, valuetype, cpp, defsign, settings);
|
||||||
} else if (tok->str() == "(") {
|
} else if (tok->str() == "(") {
|
||||||
// cast
|
// cast
|
||||||
if (!tok->astOperand2() && Token::Match(tok, "( %name%")) {
|
if (!tok->astOperand2() && Token::Match(tok, "( %name%")) {
|
||||||
ValueType valuetype;
|
ValueType valuetype;
|
||||||
if (Token::simpleMatch(parsedecl(tok->next(), &valuetype, defsign, lib), ")"))
|
if (Token::simpleMatch(parsedecl(tok->next(), &valuetype, defsign, settings), ")"))
|
||||||
::setValueType(tok, valuetype, cpp, defsign, lib);
|
::setValueType(tok, valuetype, cpp, defsign, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// C++ cast
|
// C++ cast
|
||||||
if (tok->astOperand2() && Token::Match(tok->astOperand1(), "static_cast|const_cast|dynamic_cast|reinterpret_cast < %name%") && tok->astOperand1()->linkAt(1)) {
|
if (tok->astOperand2() && Token::Match(tok->astOperand1(), "static_cast|const_cast|dynamic_cast|reinterpret_cast < %name%") && tok->astOperand1()->linkAt(1)) {
|
||||||
ValueType valuetype;
|
ValueType valuetype;
|
||||||
if (Token::simpleMatch(parsedecl(tok->astOperand1()->tokAt(2), &valuetype, defsign, lib), ">"))
|
if (Token::simpleMatch(parsedecl(tok->astOperand1()->tokAt(2), &valuetype, defsign, settings), ">"))
|
||||||
::setValueType(tok, valuetype, cpp, defsign, lib);
|
::setValueType(tok, valuetype, cpp, defsign, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// function
|
// function
|
||||||
else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->retDef) {
|
else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->retDef) {
|
||||||
ValueType valuetype;
|
ValueType valuetype;
|
||||||
if (parsedecl(tok->previous()->function()->retDef, &valuetype, defsign, lib))
|
if (parsedecl(tok->previous()->function()->retDef, &valuetype, defsign, settings))
|
||||||
::setValueType(tok, valuetype, cpp, defsign, lib);
|
::setValueType(tok, valuetype, cpp, defsign, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Token::simpleMatch(tok->previous(), "sizeof (")) {
|
else if (Token::simpleMatch(tok->previous(), "sizeof (")) {
|
||||||
// TODO: use specified size_t type
|
// TODO: use specified size_t type
|
||||||
ValueType valuetype(ValueType::Sign::UNSIGNED, ValueType::Type::LONG, 0U);
|
ValueType valuetype(ValueType::Sign::UNSIGNED, ValueType::Type::LONG, 0U);
|
||||||
valuetype.originalTypeName = "size_t";
|
valuetype.originalTypeName = "size_t";
|
||||||
setValueType(tok, valuetype, cpp, defsign, lib);
|
setValueType(tok, valuetype, cpp, defsign, settings);
|
||||||
|
|
||||||
if (Token::Match(tok, "( %type% %type%| *| *| )")) {
|
if (Token::Match(tok, "( %type% %type%| *| *| )")) {
|
||||||
ValueType vt;
|
ValueType vt;
|
||||||
if (parsedecl(tok->next(), &vt, defsign, lib)) {
|
if (parsedecl(tok->next(), &vt, defsign, settings)) {
|
||||||
setValueType(tok->next(), vt, cpp, defsign, lib);
|
setValueType(tok->next(), vt, cpp, defsign, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (tok->variable()) {
|
} else if (tok->variable()) {
|
||||||
setValueType(tok, *tok->variable(), cpp, defsign, lib);
|
setValueType(tok, *tok->variable(), cpp, defsign, settings);
|
||||||
} else if (tok->enumerator()) {
|
} 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 ValueType::str() const
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
|
@ -109,10 +109,22 @@ public:
|
||||||
|
|
||||||
const std::string& name() const;
|
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 {
|
bool isEnumType() const {
|
||||||
return classDef && classDef->str() == "enum";
|
return classDef && classDef->str() == "enum";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isStructType() const {
|
||||||
|
return classDef && classDef->str() == "struct";
|
||||||
|
}
|
||||||
|
|
||||||
const Token *initBaseInfo(const Token *tok, const Token *tok1);
|
const Token *initBaseInfo(const Token *tok, const Token *tok1);
|
||||||
|
|
||||||
const Function* getFunction(const std::string& funcName) const;
|
const Function* getFunction(const std::string& funcName) const;
|
||||||
|
@ -628,7 +640,8 @@ class CPPCHECKLIB Function {
|
||||||
fIsThrow = (1 << 13), /** @brief is throw */
|
fIsThrow = (1 << 13), /** @brief is throw */
|
||||||
fIsOperator = (1 << 14), /** @brief is operator */
|
fIsOperator = (1 << 14), /** @brief is operator */
|
||||||
fHasLvalRefQual = (1 << 15), /** @brief has & lvalue ref-qualifier */
|
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 {
|
bool hasRvalRefQualifier() const {
|
||||||
return getFlag(fHasRvalRefQual);
|
return getFlag(fHasRvalRefQual);
|
||||||
}
|
}
|
||||||
|
bool isVariadic() const {
|
||||||
|
return getFlag(fIsVariadic);
|
||||||
|
}
|
||||||
|
|
||||||
void hasBody(bool state) {
|
void hasBody(bool state) {
|
||||||
setFlag(fHasBody, state);
|
setFlag(fHasBody, state);
|
||||||
|
@ -818,6 +834,9 @@ public:
|
||||||
void hasRvalRefQualifier(bool state) {
|
void hasRvalRefQualifier(bool state) {
|
||||||
setFlag(fHasRvalRefQual, state);
|
setFlag(fHasRvalRefQual, state);
|
||||||
}
|
}
|
||||||
|
void isVariadic(bool state) {
|
||||||
|
setFlag(fIsVariadic, state);
|
||||||
|
}
|
||||||
|
|
||||||
const Token *tokenDef; // function name token in class definition
|
const Token *tokenDef; // function name token in class definition
|
||||||
const Token *argDef; // function argument start '(' in class definition
|
const Token *argDef; // function argument start '(' in class definition
|
||||||
|
@ -1071,7 +1090,7 @@ public:
|
||||||
void validateVariables() const;
|
void validateVariables() const;
|
||||||
|
|
||||||
/** Set valuetype in provided tokenlist */
|
/** 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.
|
* Calculates sizeof value for given type.
|
||||||
|
@ -1129,6 +1148,8 @@ public:
|
||||||
return (type >= ValueType::Type::BOOL && type <= ValueType::Type::UNKNOWN_INT);
|
return (type >= ValueType::Type::BOOL && type <= ValueType::Type::UNKNOWN_INT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool fromLibraryType(const std::string &typestr, const Settings *settings);
|
||||||
|
|
||||||
std::string str() const;
|
std::string str() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
ValueFlow::setValues(&list, _symbolDatabase, _errorLogger, _settings);
|
||||||
|
|
||||||
printDebugOutput(1);
|
printDebugOutput(1);
|
||||||
|
@ -2548,7 +2548,7 @@ static const std::set<std::string> notstart_c = make_container< std::set<std::st
|
||||||
<< "goto" << "NOT" << "return" << "sizeof"<< "typedef";
|
<< "goto" << "NOT" << "return" << "sizeof"<< "typedef";
|
||||||
static const std::set<std::string> notstart_cpp = make_container< std::set<std::string> > ()
|
static const std::set<std::string> notstart_cpp = make_container< std::set<std::string> > ()
|
||||||
<< notstart_c
|
<< 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()
|
void Tokenizer::setVarIdPass1()
|
||||||
{
|
{
|
||||||
|
@ -3049,7 +3049,7 @@ void Tokenizer::createLinks2()
|
||||||
} else if (token->str() == ">") {
|
} else if (token->str() == ">") {
|
||||||
if (type.empty() || type.top()->str() != "<") // < and > don't match.
|
if (type.empty() || type.top()->str() != "<") // < and > don't match.
|
||||||
continue;
|
continue;
|
||||||
if (token->next() && !Token::Match(token->next(), "%name%|>|&|*|::|,|(|)|{|;|[|:"))
|
if (token->next() && !Token::Match(token->next(), "%name%|>|&|*|::|,|(|)|{|}|;|[|:"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// if > is followed by [ .. "new a<b>[" is expected
|
// if > is followed by [ .. "new a<b>[" is expected
|
||||||
|
@ -3767,7 +3767,7 @@ bool Tokenizer::simplifyTokenList2()
|
||||||
|
|
||||||
// Create symbol database and then remove const keywords
|
// Create symbol database and then remove const keywords
|
||||||
createSymbolDatabase();
|
createSymbolDatabase();
|
||||||
SymbolDatabase::setValueTypeInTokenList(list.front(), isCPP(), _settings->defaultSign, &_settings->library);
|
SymbolDatabase::setValueTypeInTokenList(list.front(), isCPP(), _settings);
|
||||||
|
|
||||||
ValueFlow::setValues(&list, _symbolDatabase, _errorLogger, _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:"))
|
else if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|,|(|public:|protected:|private:"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (Token::Match(tok, "delete|else|return|throw|typedef"))
|
||||||
|
continue;
|
||||||
|
|
||||||
while (Token::Match(tok, "%type%|:: %type%|::"))
|
while (Token::Match(tok, "%type%|:: %type%|::"))
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
|
|
||||||
|
@ -5579,17 +5582,14 @@ void Tokenizer::simplifyPlatformTypes()
|
||||||
enum { isLongLong, isLong, isInt } type;
|
enum { isLongLong, isLong, isInt } type;
|
||||||
|
|
||||||
/** @todo This assumes a flat address space. Not true for segmented address space (FAR *). */
|
/** @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)
|
if (_settings->sizeof_size_t == _settings->sizeof_long)
|
||||||
type = isLong;
|
type = isLong;
|
||||||
else
|
else if (_settings->sizeof_size_t == _settings->sizeof_long_long)
|
||||||
type = isLongLong;
|
type = isLongLong;
|
||||||
} else if (_settings->sizeof_size_t == 4) {
|
else if (_settings->sizeof_size_t == _settings->sizeof_int)
|
||||||
if (_settings->sizeof_long == 4)
|
|
||||||
type = isLong;
|
|
||||||
else
|
|
||||||
type = isInt;
|
type = isInt;
|
||||||
} else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||||
|
@ -5636,9 +5636,7 @@ void Tokenizer::simplifyPlatformTypes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_settings->isWindowsPlatform()) {
|
const std::string platform_type(_settings->platformString());
|
||||||
std::string platform_type = _settings->platformType == Settings::Win32A ? "win32A" :
|
|
||||||
_settings->platformType == Settings::Win32W ? "win32W" : "win64";
|
|
||||||
|
|
||||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||||
if (tok->tokType() != Token::eType && tok->tokType() != Token::eName)
|
if (tok->tokType() != Token::eType && tok->tokType() != Token::eName)
|
||||||
|
@ -5685,7 +5683,6 @@ void Tokenizer::simplifyPlatformTypes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Tokenizer::simplifyStdType()
|
void Tokenizer::simplifyStdType()
|
||||||
{
|
{
|
||||||
|
@ -7576,9 +7573,13 @@ void Tokenizer::syntaxError(const Token *tok) const
|
||||||
void Tokenizer::syntaxError(const Token *tok, char c) const
|
void Tokenizer::syntaxError(const Token *tok, char c) const
|
||||||
{
|
{
|
||||||
printDebugOutput(0);
|
printDebugOutput(0);
|
||||||
|
if (_configuration.empty())
|
||||||
throw InternalError(tok,
|
throw InternalError(tok,
|
||||||
std::string("Invalid number of character '") + c + "' " +
|
std::string("Invalid number of character '") + c + "' when no macros are defined.",
|
||||||
"when these macros are defined: '" + _configuration + "'.",
|
InternalError::SYNTAX);
|
||||||
|
else
|
||||||
|
throw InternalError(tok,
|
||||||
|
std::string("Invalid number of character '") + c + "' when these macros are defined: '" + _configuration + "'.",
|
||||||
InternalError::SYNTAX);
|
InternalError::SYNTAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -695,6 +695,10 @@ Checking test.c...
|
||||||
configuration files. It is available in the <literal>View</literal>
|
configuration files. It is available in the <literal>View</literal>
|
||||||
menu. All settings are not documented in this manual.</para>
|
menu. All settings are not documented in this manual.</para>
|
||||||
|
|
||||||
|
<para>If you have a question about the <literal>.cfg</literal> file
|
||||||
|
format it is recommended you ask in the forum
|
||||||
|
(http://sourceforge.net/p/cppcheck/discussion/).</para>
|
||||||
|
|
||||||
<para>The command line cppcheck will try to load custom .cfg files from
|
<para>The command line cppcheck will try to load custom .cfg files from
|
||||||
the working path - execute cppcheck from the path where the .cfg files
|
the working path - execute cppcheck from the path where the .cfg files
|
||||||
are.</para>
|
are.</para>
|
||||||
|
@ -1118,6 +1122,23 @@ Checking minsize.c...
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>strz</title>
|
||||||
|
|
||||||
|
<para>This setting is not used by Cppcheck currently. But with this
|
||||||
|
you can say that an argument must be a zero-terminated
|
||||||
|
string.</para>
|
||||||
|
|
||||||
|
<para><programlisting><?xml version="1.0"?>
|
||||||
|
<def>
|
||||||
|
<function name="do_something">
|
||||||
|
<arg nr="1">
|
||||||
|
<strz/>
|
||||||
|
</arg>
|
||||||
|
</function>
|
||||||
|
</def></programlisting></para>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
@ -1209,11 +1230,19 @@ Checking useretval.c...
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title>pure</title>
|
<title>pure and const</title>
|
||||||
|
|
||||||
<para>A function that is pure will calculate a return value and has no
|
<para>These correspond to the GCC function attributes pure and
|
||||||
side effects. If the same parameters are given twice then the same
|
const.</para>
|
||||||
return value will be calculated twice.</para>
|
|
||||||
|
<para>A pure function has no effects except to return a value, and its
|
||||||
|
return value depends only on the parameters and global
|
||||||
|
variables.</para>
|
||||||
|
|
||||||
|
<para>A const function has no effects except to return a value, and
|
||||||
|
its return value depends only on the parameters.</para>
|
||||||
|
|
||||||
|
<para>Here is an example code:</para>
|
||||||
|
|
||||||
<programlisting>void f(int x)
|
<programlisting>void f(int x)
|
||||||
{
|
{
|
||||||
|
@ -1224,24 +1253,29 @@ Checking useretval.c...
|
||||||
}
|
}
|
||||||
}</programlisting>
|
}</programlisting>
|
||||||
|
|
||||||
<para>Cppcheck reports no warning</para>
|
<para>If <literal>calculate()</literal> is a const function then the
|
||||||
|
result of <literal>calculate(x)</literal> will be the same in both
|
||||||
|
conditions, since the same parameter value is used.</para>
|
||||||
|
|
||||||
<programlisting># cppcheck pure.c
|
<para>Cppcheck normally assumes that the result might be different,
|
||||||
Checking pure.c...</programlisting>
|
and reports no warning for the code:</para>
|
||||||
|
|
||||||
<para>If a proper <literal>lib.cfg</literal> is provided, the
|
<programlisting># cppcheck const.c
|
||||||
|
Checking const.c...</programlisting>
|
||||||
|
|
||||||
|
<para>If a proper <literal>const.cfg</literal> is provided, the
|
||||||
unreachable code is detected:</para>
|
unreachable code is detected:</para>
|
||||||
|
|
||||||
<programlisting># cppcheck --enable=style --library=pure pure.c
|
<programlisting># cppcheck --enable=style --library=const const.c
|
||||||
Checking pure.c...
|
Checking const.c...
|
||||||
[pure.c:7]: (style) Expression is always false because 'else if' condition matches previous condition at line 5.</programlisting>
|
[const.c:7]: (style) Expression is always false because 'else if' condition matches previous condition at line 5.</programlisting>
|
||||||
|
|
||||||
<para>Here is a minimal <literal>pure.cfg</literal> file:</para>
|
<para>Here is a minimal <literal>const.cfg</literal> file:</para>
|
||||||
|
|
||||||
<programlisting><?xml version="1.0"?>
|
<programlisting><?xml version="1.0"?>
|
||||||
<def>
|
<def>
|
||||||
<function name="calculate">
|
<function name="calculate">
|
||||||
<pure/>
|
<const/>
|
||||||
<arg nr="1"/>
|
<arg nr="1"/>
|
||||||
</function>
|
</function>
|
||||||
</def></programlisting>
|
</def></programlisting>
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -1073,7 +1073,7 @@ private:
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
assertThrowFail(__FILE__, __LINE__);
|
assertThrowFail(__FILE__, __LINE__);
|
||||||
} catch (InternalError& e) {
|
} 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("syntaxError", e.id);
|
||||||
ASSERT_EQUALS(2, e.token->linenr());
|
ASSERT_EQUALS(2, e.token->linenr());
|
||||||
}
|
}
|
||||||
|
|
|
@ -3815,6 +3815,11 @@ private:
|
||||||
" return A ? x : z;\n"
|
" return A ? x : z;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
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() {
|
void checkSignOfUnsignedVariable() {
|
||||||
|
|
|
@ -128,7 +128,6 @@ private:
|
||||||
TEST_CASE(if_cond12);
|
TEST_CASE(if_cond12);
|
||||||
TEST_CASE(if_cond13);
|
TEST_CASE(if_cond13);
|
||||||
TEST_CASE(if_cond14);
|
TEST_CASE(if_cond14);
|
||||||
TEST_CASE(if_cond15); // #4456 - segfault
|
|
||||||
|
|
||||||
TEST_CASE(if_or_1);
|
TEST_CASE(if_or_1);
|
||||||
TEST_CASE(if_or_2);
|
TEST_CASE(if_or_2);
|
||||||
|
@ -267,6 +266,22 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string getConfigsStr(const char filedata[], const char *u1=NULL) {
|
||||||
|
Settings settings;
|
||||||
|
if (u1)
|
||||||
|
settings.userUndefs.insert(u1);
|
||||||
|
Preprocessor preprocessor(settings, this);
|
||||||
|
std::vector<std::string> files;
|
||||||
|
std::istringstream istr(filedata);
|
||||||
|
simplecpp::TokenList tokens(istr,files);
|
||||||
|
tokens.removeComments();
|
||||||
|
const std::set<std::string> configs = preprocessor.getConfigs(tokens);
|
||||||
|
std::string ret;
|
||||||
|
for (std::set<std::string>::const_iterator it = configs.begin(); it != configs.end(); ++it)
|
||||||
|
ret += *it + '\n';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void Bug2190219() {
|
void Bug2190219() {
|
||||||
const char filedata[] = "#ifdef __cplusplus\n"
|
const char filedata[] = "#ifdef __cplusplus\n"
|
||||||
"cpp\n"
|
"cpp\n"
|
||||||
|
@ -304,14 +319,7 @@ private:
|
||||||
" qwerty\n"
|
" qwerty\n"
|
||||||
"#endif \n";
|
"#endif \n";
|
||||||
|
|
||||||
// Preprocess => actual result..
|
ASSERT_EQUALS("\nWIN32\n", getConfigsStr(filedata));
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("\n\n\nqwerty", actual[""]);
|
|
||||||
ASSERT_EQUALS("\nabcdef", actual["WIN32"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test2() {
|
void test2() {
|
||||||
|
@ -320,15 +328,7 @@ private:
|
||||||
" # else \n"
|
" # else \n"
|
||||||
" qwerty\n"
|
" qwerty\n"
|
||||||
" # endif \n";
|
" # endif \n";
|
||||||
|
ASSERT_EQUALS("\nWIN32\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(2U, actual.size());
|
|
||||||
ASSERT_EQUALS("\n\" # ifdef WIN32\"", actual[""]);
|
|
||||||
ASSERT_EQUALS("\n\n\nqwerty", actual["WIN32"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test3() {
|
void test3() {
|
||||||
|
@ -340,15 +340,7 @@ private:
|
||||||
"c\n"
|
"c\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
|
||||||
// Preprocess => actual result..
|
ASSERT_EQUALS("\nABC\nABC;DEF\n", getConfigsStr(filedata));
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("", actual[""]);
|
|
||||||
ASSERT_EQUALS("\na\n\n\n\nc", actual["ABC"]);
|
|
||||||
ASSERT_EQUALS("\na\n\nb\n\nc", actual["ABC;DEF"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test4() {
|
void test4() {
|
||||||
|
@ -358,15 +350,7 @@ private:
|
||||||
"#ifdef ABC\n"
|
"#ifdef ABC\n"
|
||||||
"A\n"
|
"A\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("", actual[""]);
|
|
||||||
ASSERT_EQUALS("\nA\n\n\nA", actual["ABC"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test5() {
|
void test5() {
|
||||||
|
@ -378,16 +362,7 @@ private:
|
||||||
"C\n"
|
"C\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nABC\nDEF\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("\n\n\nB", actual[""]);
|
|
||||||
ASSERT_EQUALS("\nA", actual["ABC"]);
|
|
||||||
ASSERT_EQUALS("\n\n\nB\n\nC", actual["DEF"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test7() {
|
void test7() {
|
||||||
|
@ -397,20 +372,7 @@ private:
|
||||||
"B\n"
|
"B\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Make sure an error message is written..
|
|
||||||
TODO_ASSERT_EQUALS("[file.c:3]: (error) ABC is already guaranteed to be defined\n",
|
|
||||||
"",
|
|
||||||
errout.str());
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("", actual[""]);
|
|
||||||
ASSERT_EQUALS("\nA\n\nB", actual["ABC"]);
|
|
||||||
|
|
||||||
test7a();
|
test7a();
|
||||||
test7b();
|
test7b();
|
||||||
|
@ -425,17 +387,7 @@ private:
|
||||||
"B\n"
|
"B\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Make sure an error message is written..
|
|
||||||
TODO_ASSERT_EQUALS("[file.c:3]: (error) ABC is already guaranteed NOT to be defined\n",
|
|
||||||
"", errout.str());
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
// TODO Preprocessor::getConfigs ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test7b() {
|
void test7b() {
|
||||||
|
@ -445,17 +397,7 @@ private:
|
||||||
"B\n"
|
"B\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Make sure an error message is written..
|
|
||||||
TODO_ASSERT_EQUALS("[file.c:3]: (error) ABC is already guaranteed NOT to be defined\n",
|
|
||||||
"", errout.str());
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test7c() {
|
void test7c() {
|
||||||
|
@ -465,18 +407,7 @@ private:
|
||||||
"B\n"
|
"B\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Make sure an error message is written..
|
|
||||||
TODO_ASSERT_EQUALS("[file.c:3]: (error) ABC is already guaranteed to be defined\n",
|
|
||||||
"",
|
|
||||||
errout.str());
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test7d() {
|
void test7d() {
|
||||||
|
@ -486,18 +417,7 @@ private:
|
||||||
"B\n"
|
"B\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Make sure an error message is written..
|
|
||||||
TODO_ASSERT_EQUALS("[file.c:3]: (error) ABC is already guaranteed to be defined\n",
|
|
||||||
"",
|
|
||||||
errout.str());
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test7e() {
|
void test7e() {
|
||||||
|
@ -510,49 +430,21 @@ private:
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"#endfile\n"
|
"#endfile\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Make sure an error message is written..
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(2U, actual.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test8() {
|
void test8() {
|
||||||
const char filedata[] = "#if A == 1\n"
|
const char filedata[] = "#if A == 1\n"
|
||||||
"1\n"
|
"1\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nA=1\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// No error..
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(2U, actual.size());
|
|
||||||
ASSERT_EQUALS("", actual[""]);
|
|
||||||
ASSERT_EQUALS("\n1", actual["A=1"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test9() {
|
void test9() {
|
||||||
const char filedata[] = "#if\n"
|
const char filedata[] = "#if\n"
|
||||||
"#else\n"
|
"#else\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
getConfigsStr(filedata); // <- don't crash
|
||||||
// Preprocess => actual result..
|
|
||||||
std::istringstream istr(filedata);
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
Settings settings;
|
|
||||||
settings.maxConfigs = 1;
|
|
||||||
settings.userDefines = "X";
|
|
||||||
Preprocessor preprocessor(settings, this);
|
|
||||||
preprocessor.preprocess(istr, actual, "file.c"); // <- don't crash
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test10() { // Ticket #5139
|
void test10() { // Ticket #5139
|
||||||
|
@ -561,10 +453,7 @@ private:
|
||||||
"#define baz bar+0\n"
|
"#define baz bar+0\n"
|
||||||
"#if 0\n"
|
"#if 0\n"
|
||||||
"#endif";
|
"#endif";
|
||||||
|
ASSERT_EQUALS("\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void error1() {
|
void error1() {
|
||||||
|
@ -573,16 +462,7 @@ private:
|
||||||
"#else\n"
|
"#else\n"
|
||||||
"#error abcd\n"
|
"#error abcd\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nA\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("", actual[""]);
|
|
||||||
ASSERT_EQUALS("\n;", actual["A"]);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void error3() {
|
void error3() {
|
||||||
|
@ -665,13 +545,7 @@ private:
|
||||||
"#endfile\n"
|
"#endfile\n"
|
||||||
"#ifdef ABC\n"
|
"#ifdef ABC\n"
|
||||||
"#endif";
|
"#endif";
|
||||||
|
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Expected configurations: "" and "ABC"
|
|
||||||
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void includeguard2() {
|
void includeguard2() {
|
||||||
|
@ -682,15 +556,7 @@ private:
|
||||||
"\n"
|
"\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"#endfile\n";
|
"#endfile\n";
|
||||||
|
ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Expected configurations: "" and "ABC"
|
|
||||||
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS(true, actual.find("") != actual.end());
|
|
||||||
ASSERT_EQUALS(true, actual.find("ABC") != actual.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -718,28 +584,14 @@ private:
|
||||||
"#ifdef WIN32\n"
|
"#ifdef WIN32\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("", actual[""]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if1() {
|
void if1() {
|
||||||
const char filedata[] = " # if /* comment */ 1 // comment\n"
|
const char filedata[] = " # if /* comment */ 1 // comment\n"
|
||||||
"ABC\n"
|
"ABC\n"
|
||||||
" # endif \n";
|
" # endif \n";
|
||||||
|
ASSERT_EQUALS("\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("\nABC", actual[""]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -750,16 +602,7 @@ private:
|
||||||
"#elif DEF2\n"
|
"#elif DEF2\n"
|
||||||
"DEF\n"
|
"DEF\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nDEF1\nDEF2\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("", actual[""]);
|
|
||||||
ASSERT_EQUALS("\nABC", actual["DEF1"]);
|
|
||||||
ASSERT_EQUALS("\n\n\nDEF", actual["DEF2"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -770,16 +613,7 @@ private:
|
||||||
"#else\n"
|
"#else\n"
|
||||||
"GHI\n"
|
"GHI\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nDEF1\nDEF2\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("\n\n\n\n\nGHI", actual[""]);
|
|
||||||
ASSERT_EQUALS("\nABC", actual["DEF1"]);
|
|
||||||
ASSERT_EQUALS("\n\n\nDEF", actual["DEF2"]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -789,18 +623,7 @@ private:
|
||||||
"#else\n"
|
"#else\n"
|
||||||
" B\n"
|
" B\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
TODO_ASSERT_EQUALS("\nLIBVER=101\n", "\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("\n"
|
|
||||||
"\n"
|
|
||||||
"\n"
|
|
||||||
"B", actual[""]);
|
|
||||||
TODO_ASSERT_EQUALS("A", "", actual["LIBVER=101"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_cond2() {
|
void if_cond2() {
|
||||||
|
@ -810,16 +633,8 @@ private:
|
||||||
"#if defined(A) && defined(B)\n"
|
"#if defined(A) && defined(B)\n"
|
||||||
"ab\n"
|
"ab\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nA\nA;B\n", getConfigsStr(filedata));
|
||||||
|
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("", actual[""]);
|
|
||||||
ASSERT_EQUALS("\na", actual["A"]);
|
|
||||||
ASSERT_EQUALS("\na\n\n\nab", actual["A;B"]);
|
|
||||||
if_cond2b();
|
if_cond2b();
|
||||||
if_cond2c();
|
if_cond2c();
|
||||||
if_cond2d();
|
if_cond2d();
|
||||||
|
@ -835,16 +650,7 @@ private:
|
||||||
"#else\n"
|
"#else\n"
|
||||||
"a\n"
|
"a\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
TODO_ASSERT_EQUALS("\nA;B\n", "\nA\nB\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("\n! a", actual[""]);
|
|
||||||
ASSERT_EQUALS("\n\n\n\n\n\na", actual["A"]);
|
|
||||||
ASSERT_EQUALS("\n! a\n\nb", actual["B"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_cond2c() {
|
void if_cond2c() {
|
||||||
|
@ -858,16 +664,7 @@ private:
|
||||||
"#else\n"
|
"#else\n"
|
||||||
"a\n"
|
"a\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
TODO_ASSERT_EQUALS("\nA\nA;B\n", "\nA\nB\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("\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"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_cond2d() {
|
void if_cond2d() {
|
||||||
|
@ -886,17 +683,7 @@ private:
|
||||||
"!b\n"
|
"!b\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nA\nA;B\nB\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(4, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("\n! a\n\n\n\n! b", actual[""]);
|
|
||||||
ASSERT_EQUALS("\n\n\n\n\n\n\n\na\n\n\n\n! b", actual["A"]);
|
|
||||||
ASSERT_EQUALS("\n\n\n\n\n\n\n\na\n\nb", actual["A;B"]);
|
|
||||||
ASSERT_EQUALS("\n! a\n\nb", actual["B"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_cond2e() {
|
void if_cond2e() {
|
||||||
|
@ -905,22 +692,7 @@ private:
|
||||||
"#elif !defined(B)\n"
|
"#elif !defined(B)\n"
|
||||||
"!b\n"
|
"!b\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
TODO_ASSERT_EQUALS("\nA\nA;B", "\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
errout.str("");
|
|
||||||
std::istringstream istr(filedata);
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
Settings settings;
|
|
||||||
settings.debug = settings.debugwarnings = true;
|
|
||||||
Preprocessor preprocessor(settings, this);
|
|
||||||
preprocessor.preprocess(istr, actual, "file.c");
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
TODO_ASSERT_EQUALS(3U, 1U, actual.size());
|
|
||||||
ASSERT_EQUALS("\n! a", actual[""]);
|
|
||||||
TODO_ASSERT_EQUALS("\n\n\n! b", "", actual["A"]);
|
|
||||||
ASSERT_EQUALS("", actual["A;B"]);
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_cond3() {
|
void if_cond3() {
|
||||||
|
@ -930,16 +702,7 @@ private:
|
||||||
"abc\n"
|
"abc\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nA\nA;B;C\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("", actual[""]);
|
|
||||||
ASSERT_EQUALS("\na", actual["A"]);
|
|
||||||
ASSERT_EQUALS("\na\n\nabc", actual["A;B;C"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_cond4() {
|
void if_cond4() {
|
||||||
|
@ -949,14 +712,7 @@ private:
|
||||||
"#if defined A || defined B\n"
|
"#if defined A || defined B\n"
|
||||||
"ab\n"
|
"ab\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("\n\n\nab", actual[""]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -967,16 +723,7 @@ private:
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nA\nA;B\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("", actual[""]);
|
|
||||||
ASSERT_EQUALS("\n{\n\n\n\n}", actual["A"]);
|
|
||||||
ASSERT_EQUALS("\n{\n\nfoo ( ) ;\n\n}", actual["A;B"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -985,43 +732,21 @@ private:
|
||||||
"#if (defined A) || defined (B)\n"
|
"#if (defined A) || defined (B)\n"
|
||||||
"ab\n"
|
"ab\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("\n\n\nab", actual[""]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const char filedata[] = "#if (A)\n"
|
const char filedata[] = "#if (A)\n"
|
||||||
"foo();\n"
|
"foo();\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nA\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("", actual[""]);
|
|
||||||
ASSERT_EQUALS("\nfoo ( ) ;", actual["A"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const char filedata[] = "#if! A\n"
|
const char filedata[] = "#if! A\n"
|
||||||
"foo();\n"
|
"foo();\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
TODO_ASSERT_EQUALS(2, 1, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("\nfoo ( ) ;", actual[""]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1033,41 +758,20 @@ private:
|
||||||
"#if defined(B) && defined(A)\n"
|
"#if defined(B) && defined(A)\n"
|
||||||
"ef\n"
|
"ef\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nA;B\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
|
||||||
ASSERT_EQUALS("\n\n\ncd", actual[""]);
|
|
||||||
ASSERT_EQUALS("\nab\n\ncd\n\nef", actual["A;B"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_cond6() {
|
void if_cond6() {
|
||||||
const char filedata[] = "\n"
|
const char filedata[] = "\n"
|
||||||
"#if defined(A) && defined(B))\n"
|
"#if defined(A) && defined(B))\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nA;B\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
// TODO ASSERT_EQUALS("[file.c:2]: (error) mismatching number of '(' and ')' in this line: defined(A)&&defined(B))\n", errout.str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_cond8() {
|
void if_cond8() {
|
||||||
const char filedata[] = "#if defined(A) + defined(B) + defined(C) != 1\n"
|
const char filedata[] = "#if defined(A) + defined(B) + defined(C) != 1\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
TODO_ASSERT_EQUALS("\nA\n", "\nA;B;C\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
// TODO Preprocessor::getConfig ASSERT_EQUALS(1U, actual.size());
|
|
||||||
ASSERT_EQUALS("", actual[""]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1075,14 +779,7 @@ private:
|
||||||
const char filedata[] = "#if !defined _A\n"
|
const char filedata[] = "#if !defined _A\n"
|
||||||
"abc\n"
|
"abc\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\n", getConfigsStr(filedata));
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual);
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(1, (int)actual.size());
|
|
||||||
ASSERT_EQUALS("\nabc", actual[""]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_cond10() {
|
void if_cond10() {
|
||||||
|
@ -1112,32 +809,21 @@ private:
|
||||||
"#if A == 1\n"
|
"#if A == 1\n"
|
||||||
";\n"
|
";\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
ASSERT_EQUALS("\n\n;", preprocessor0.getcode(filedata,"",""));
|
ASSERT_EQUALS("\n", getConfigsStr(filedata));
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_cond13() {
|
void if_cond13() {
|
||||||
const char filedata[] = "#if ('A' == 0x41)\n"
|
const char filedata[] = "#if ('A' == 0x41)\n"
|
||||||
"123\n"
|
"123\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
ASSERT_EQUALS("\n123", preprocessor0.getcode(filedata,"",""));
|
ASSERT_EQUALS("\n", getConfigsStr(filedata));
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_cond14() {
|
void if_cond14() {
|
||||||
const char filedata[] = "#if !(A)\n"
|
const char filedata[] = "#if !(A)\n"
|
||||||
"123\n"
|
"123\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
ASSERT_EQUALS("\n123", preprocessor0.getcode(filedata,"",""));
|
ASSERT_EQUALS("\n", getConfigsStr(filedata));
|
||||||
}
|
|
||||||
|
|
||||||
void if_cond15() { // #4456 - segmentation fault
|
|
||||||
const char filedata[] = "#if ((A >= B) && (C != D))\n"
|
|
||||||
"#if (E < F(1))\n"
|
|
||||||
"#endif\n"
|
|
||||||
"#endif\n";
|
|
||||||
|
|
||||||
// Preprocess => actual result..
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
preprocess(filedata, actual); // <- don't crash in Preprocessor::getcfgs -> Tokenize -> number of template parameters
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1146,35 +832,14 @@ private:
|
||||||
const char filedata[] = "#if defined(DEF_10) || defined(DEF_11)\n"
|
const char filedata[] = "#if defined(DEF_10) || defined(DEF_11)\n"
|
||||||
"a1;\n"
|
"a1;\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
ASSERT_EQUALS("\nDEF_10;DEF_11\n", getConfigsStr(filedata));
|
||||||
errout.str("");
|
|
||||||
output.str("");
|
|
||||||
|
|
||||||
// Preprocess => actual result..
|
|
||||||
std::istringstream istr(filedata);
|
|
||||||
std::map<std::string, std::string> actual;
|
|
||||||
Settings settings;
|
|
||||||
settings.debug = settings.debugwarnings = true;
|
|
||||||
settings.addEnabled("missingInclude");
|
|
||||||
Preprocessor preprocessor(settings, this);
|
|
||||||
preprocessor.preprocess(istr, actual, "file.c");
|
|
||||||
|
|
||||||
// Compare results..
|
|
||||||
ASSERT_EQUALS(2U, actual.size());
|
|
||||||
ASSERT_EQUALS("", actual[""]);
|
|
||||||
|
|
||||||
// the "defined(DEF_10) || defined(DEF_11)" are not handled correctly..
|
|
||||||
ASSERT_EQUALS(2U, actual.size());
|
|
||||||
ASSERT_EQUALS("\na1 ;", actual["DEF_10;DEF_11"]);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_or_2() {
|
void if_or_2() {
|
||||||
const std::string code("#if X || Y\n"
|
const char filedata[] = "#if X || Y\n"
|
||||||
"a1;\n"
|
"a1;\n"
|
||||||
"#endif\n");
|
"#endif\n";
|
||||||
ASSERT_EQUALS("\na1 ;", preprocessor0.getcode(code, "X", "test.c"));
|
TODO_ASSERT_EQUALS("\nX;Y\n", "\n", getConfigsStr(filedata));
|
||||||
ASSERT_EQUALS("\na1 ;", preprocessor0.getcode(code, "Y", "test.c"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_macro_eq_macro() {
|
void if_macro_eq_macro() {
|
||||||
|
@ -1186,10 +851,7 @@ private:
|
||||||
"#else\n"
|
"#else\n"
|
||||||
"Betty\n"
|
"Betty\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
std::map<std::string, std::string> actual;
|
ASSERT_EQUALS("\n", getConfigsStr(code));
|
||||||
preprocess(code, actual);
|
|
||||||
|
|
||||||
ASSERT_EQUALS("\n\n\n\nWilma", actual[""]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ticket_3675() {
|
void ticket_3675() {
|
||||||
|
@ -1784,7 +1446,7 @@ private:
|
||||||
void stringify5() const {
|
void stringify5() const {
|
||||||
const char filedata[] = "#define A(x) a(#x,x)\n"
|
const char filedata[] = "#define A(x) a(#x,x)\n"
|
||||||
"A(foo(\"\\\"\"))\n";
|
"A(foo(\"\\\"\"))\n";
|
||||||
ASSERT_EQUALS("\na ( \"foo(\"\\\"\")\" , foo ( \"\\\"\" ) )", OurPreprocessor::expandMacros(filedata));
|
ASSERT_EQUALS("\na ( \"foo(\\\"\\\\\\\"\\\")\" , foo ( \"\\\"\" ) )", OurPreprocessor::expandMacros(filedata));
|
||||||
}
|
}
|
||||||
|
|
||||||
void pragma() {
|
void pragma() {
|
||||||
|
@ -2422,22 +2084,6 @@ private:
|
||||||
ASSERT_EQUALS("", actual);
|
ASSERT_EQUALS("", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getConfigsStr(const char filedata[], const char *u1=NULL) {
|
|
||||||
Settings settings;
|
|
||||||
if (u1)
|
|
||||||
settings.userUndefs.insert(u1);
|
|
||||||
Preprocessor preprocessor(settings, this);
|
|
||||||
std::vector<std::string> files;
|
|
||||||
std::istringstream istr(filedata);
|
|
||||||
simplecpp::TokenList tokens(istr,files);
|
|
||||||
tokens.removeComments();
|
|
||||||
const std::set<std::string> configs = preprocessor.getConfigs(tokens);
|
|
||||||
std::string ret;
|
|
||||||
for (std::set<std::string>::const_iterator it = configs.begin(); it != configs.end(); ++it)
|
|
||||||
ret += *it + '\n';
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void undef1() {
|
void undef1() {
|
||||||
const char filedata[] = "#ifdef X\n"
|
const char filedata[] = "#ifdef X\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
@ -2468,37 +2114,20 @@ private:
|
||||||
Settings settings;
|
Settings settings;
|
||||||
Preprocessor preprocessor(settings, this);
|
Preprocessor preprocessor(settings, this);
|
||||||
|
|
||||||
ASSERT_EQUALS(true, preprocessor.validateCfg("", "X=42")); // don't hang when parsing cfg
|
std::list<simplecpp::MacroUsage> macroUsageList;
|
||||||
ASSERT_EQUALS(false, preprocessor.validateCfg("int y=Y;", "X=42;Y"));
|
std::vector<std::string> files;
|
||||||
ASSERT_EQUALS(false, preprocessor.validateCfg("int x=X;", "X"));
|
files.push_back("test.c");
|
||||||
ASSERT_EQUALS(false, preprocessor.validateCfg("X=1;", "X"));
|
simplecpp::MacroUsage macroUsage(files);
|
||||||
ASSERT_EQUALS(true, preprocessor.validateCfg("int x=X;", "Y"));
|
macroUsage.useLocation.fileIndex = 0;
|
||||||
ASSERT_EQUALS(true, preprocessor.validateCfg("FOO_DEBUG()", "DEBUG"));
|
macroUsage.useLocation.line = 1;
|
||||||
ASSERT_EQUALS(true, preprocessor.validateCfg("\"DEBUG()\"", "DEBUG"));
|
macroUsage.macroName = "X";
|
||||||
ASSERT_EQUALS(true, preprocessor.validateCfg("\"\\\"DEBUG()\"", "DEBUG"));
|
macroUsageList.push_back(macroUsage);
|
||||||
ASSERT_EQUALS(false, preprocessor.validateCfg("\"DEBUG()\" DEBUG", "DEBUG"));
|
|
||||||
ASSERT_EQUALS(true, preprocessor.validateCfg("#undef DEBUG", "DEBUG"));
|
|
||||||
|
|
||||||
// #4301:
|
ASSERT_EQUALS(true, preprocessor.validateCfg("", macroUsageList));
|
||||||
// #ifdef A
|
ASSERT_EQUALS(false, preprocessor.validateCfg("X",macroUsageList));
|
||||||
// int a = A; // <- using macro. must use -D so "A" will get a proper value
|
ASSERT_EQUALS(false, preprocessor.validateCfg("A=42;X", macroUsageList));
|
||||||
errout.str("");
|
ASSERT_EQUALS(true, preprocessor.validateCfg("X=1", macroUsageList));
|
||||||
settings.addEnabled("all");
|
ASSERT_EQUALS(true, preprocessor.validateCfg("Y", macroUsageList));
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_sizeof() { // #4071
|
void if_sizeof() { // #4071
|
||||||
|
|
|
@ -201,6 +201,14 @@ private:
|
||||||
" l2.insert(it, 0);\n"
|
" l2.insert(it, 0);\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:6]: (error) Same iterator is used with different containers 'l1' and 'l2'.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:6]: (error) Same iterator is used with different containers 'l1' and 'l2'.\n", errout.str());
|
||||||
|
|
||||||
|
check("void foo() {\n" // #5803
|
||||||
|
" list<int> l1;\n"
|
||||||
|
" list<int> l2;\n"
|
||||||
|
" list<int>::iterator it = l1.begin();\n"
|
||||||
|
" l2.insert(it, l1.end());\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void iterator4() {
|
void iterator4() {
|
||||||
|
|
|
@ -182,6 +182,10 @@ private:
|
||||||
TEST_CASE(functionArgs2);
|
TEST_CASE(functionArgs2);
|
||||||
TEST_CASE(functionArgs3);
|
TEST_CASE(functionArgs3);
|
||||||
TEST_CASE(functionArgs4);
|
TEST_CASE(functionArgs4);
|
||||||
|
TEST_CASE(functionArgs5); // #7650
|
||||||
|
TEST_CASE(functionArgs6); // #7651
|
||||||
|
TEST_CASE(functionArgs7); // #7652
|
||||||
|
TEST_CASE(functionArgs8); // #7653
|
||||||
|
|
||||||
TEST_CASE(namespaces1);
|
TEST_CASE(namespaces1);
|
||||||
TEST_CASE(namespaces2);
|
TEST_CASE(namespaces2);
|
||||||
|
@ -294,6 +298,10 @@ private:
|
||||||
TEST_CASE(executableScopeWithUnknownFunction);
|
TEST_CASE(executableScopeWithUnknownFunction);
|
||||||
|
|
||||||
TEST_CASE(valuetype);
|
TEST_CASE(valuetype);
|
||||||
|
|
||||||
|
TEST_CASE(variadic1); // #7453
|
||||||
|
TEST_CASE(variadic2); // #7649
|
||||||
|
TEST_CASE(variadic3); // #7387
|
||||||
}
|
}
|
||||||
|
|
||||||
void array() {
|
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() {
|
void namespaces1() {
|
||||||
GET_SYMBOL_DB("namespace fred {\n"
|
GET_SYMBOL_DB("namespace fred {\n"
|
||||||
" namespace barney {\n"
|
" namespace barney {\n"
|
||||||
|
@ -3670,6 +3831,118 @@ private:
|
||||||
|
|
||||||
// Pointer to unknown type
|
// Pointer to unknown type
|
||||||
ASSERT_EQUALS("*", typeOf("Bar* b;", "b"));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -292,6 +292,7 @@ private:
|
||||||
TEST_CASE(simplifyStdType); // #4947, #4950, #4951
|
TEST_CASE(simplifyStdType); // #4947, #4950, #4951
|
||||||
|
|
||||||
TEST_CASE(createLinks);
|
TEST_CASE(createLinks);
|
||||||
|
TEST_CASE(createLinks2);
|
||||||
TEST_CASE(signed1);
|
TEST_CASE(signed1);
|
||||||
|
|
||||||
TEST_CASE(simplifyString);
|
TEST_CASE(simplifyString);
|
||||||
|
@ -307,6 +308,7 @@ private:
|
||||||
TEST_CASE(functionpointer6);
|
TEST_CASE(functionpointer6);
|
||||||
TEST_CASE(functionpointer7);
|
TEST_CASE(functionpointer7);
|
||||||
TEST_CASE(functionpointer8); // #7410 - throw
|
TEST_CASE(functionpointer8); // #7410 - throw
|
||||||
|
TEST_CASE(functionpointer9); // #6113 - function call with function pointer
|
||||||
|
|
||||||
TEST_CASE(removeRedundantAssignment);
|
TEST_CASE(removeRedundantAssignment);
|
||||||
|
|
||||||
|
@ -4523,6 +4525,20 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void createLinks2() {
|
||||||
|
{
|
||||||
|
// #7158
|
||||||
|
const char code[] = "enum { value = boost::mpl::at_c<B, C> };";
|
||||||
|
errout.str("");
|
||||||
|
Tokenizer tokenizer(&settings0, this);
|
||||||
|
std::istringstream istr(code);
|
||||||
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
const Token *tok = Token::findsimplematch(tokenizer.tokens(), "<");
|
||||||
|
ASSERT_EQUALS(true, tok->link() == tok->tokAt(4));
|
||||||
|
ASSERT_EQUALS(true, tok->linkAt(4) == tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void simplifyString() {
|
void simplifyString() {
|
||||||
errout.str("");
|
errout.str("");
|
||||||
Tokenizer tokenizer(&settings0, this);
|
Tokenizer tokenizer(&settings0, this);
|
||||||
|
@ -4681,6 +4697,20 @@ private:
|
||||||
ASSERT_EQUALS(expected1, tokenizeDebugListing(code1, false));
|
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() {
|
void removeRedundantAssignment() {
|
||||||
ASSERT_EQUALS("void f ( ) { }", tokenizeAndStringify("void f() { int *p, *q; p = q; }", true));
|
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));
|
ASSERT_EQUALS("void f ( ) { }", tokenizeAndStringify("void f() { int *p = 0, *q; p = q; }", true));
|
||||||
|
|
|
@ -73,6 +73,8 @@ private:
|
||||||
TEST_CASE(syntax_error); // Ticket #5073
|
TEST_CASE(syntax_error); // Ticket #5073
|
||||||
TEST_CASE(trac_5970);
|
TEST_CASE(trac_5970);
|
||||||
|
|
||||||
|
TEST_CASE(isVariableUsageDeref); // *p
|
||||||
|
|
||||||
// dead pointer
|
// dead pointer
|
||||||
TEST_CASE(deadPointer);
|
TEST_CASE(deadPointer);
|
||||||
}
|
}
|
||||||
|
@ -537,13 +539,6 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: c\n", errout.str());
|
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"
|
checkUninitVar("void f()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int a[10];\n"
|
" int a[10];\n"
|
||||||
|
@ -1236,18 +1231,6 @@ private:
|
||||||
"}");
|
"}");
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: a\n", "", errout.str());
|
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"
|
checkUninitVar("int f()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" char a[10];\n"
|
" char a[10];\n"
|
||||||
|
@ -3558,6 +3541,19 @@ private:
|
||||||
" }\n"
|
" }\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
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() {
|
void uninitvar2_4494() {
|
||||||
|
@ -3783,6 +3779,33 @@ private:
|
||||||
check.deadPointer();
|
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() {
|
void deadPointer() {
|
||||||
checkDeadPointer("void f() {\n"
|
checkDeadPointer("void f() {\n"
|
||||||
" int *p = p1;\n"
|
" int *p = p1;\n"
|
||||||
|
|
|
@ -48,6 +48,7 @@ private:
|
||||||
TEST_CASE(structmember10);
|
TEST_CASE(structmember10);
|
||||||
TEST_CASE(structmember11); // #4168 - initialization with {} / passed by address to unknown function
|
TEST_CASE(structmember11); // #4168 - initialization with {} / passed by address to unknown function
|
||||||
TEST_CASE(structmember12); // #7179 - FP unused structmember
|
TEST_CASE(structmember12); // #7179 - FP unused structmember
|
||||||
|
TEST_CASE(structmember_sizeof);
|
||||||
|
|
||||||
TEST_CASE(localvar1);
|
TEST_CASE(localvar1);
|
||||||
TEST_CASE(localvar2);
|
TEST_CASE(localvar2);
|
||||||
|
@ -461,6 +462,22 @@ private:
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (style) struct member 'AB::a' is never used.\n", errout.str());
|
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") {
|
void functionVariableUsage(const char code[], const char filename[]="test.cpp") {
|
||||||
// Clear the error buffer..
|
// Clear the error buffer..
|
||||||
errout.str("");
|
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
|
" x(a, b=2);\n" // <- if param2 is passed-by-reference then b might be used in x
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
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
|
void localvar37() { // ticket #3078
|
||||||
|
|
|
@ -134,6 +134,7 @@ private:
|
||||||
TEST_CASE(varid_templateNamespaceFuncPtr); // #4172
|
TEST_CASE(varid_templateNamespaceFuncPtr); // #4172
|
||||||
TEST_CASE(varid_templateArray);
|
TEST_CASE(varid_templateArray);
|
||||||
TEST_CASE(varid_templateParameter); // #7046 set varid for "X": std::array<int,X> Y;
|
TEST_CASE(varid_templateParameter); // #7046 set varid for "X": std::array<int,X> Y;
|
||||||
|
TEST_CASE(varid_templateUsing); // #5781 #7273
|
||||||
TEST_CASE(varid_cppcast); // #6190
|
TEST_CASE(varid_cppcast); // #6190
|
||||||
TEST_CASE(varid_variadicFunc);
|
TEST_CASE(varid_variadicFunc);
|
||||||
TEST_CASE(varid_typename); // #4644
|
TEST_CASE(varid_typename); // #4644
|
||||||
|
@ -2026,6 +2027,15 @@ private:
|
||||||
tokenize(code));
|
tokenize(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void varid_templateUsing() { // #5781 #7273
|
||||||
|
const char code[] = "template<class T> using X = Y<T>;\n"
|
||||||
|
"X<int> x;";
|
||||||
|
TODO_ASSERT_EQUALS("\nY<int> x@1;\n",
|
||||||
|
"1: template < class T > using X ; X = Y < T > ;\n"
|
||||||
|
"2: X < int > x@1 ;\n",
|
||||||
|
tokenize(code));
|
||||||
|
}
|
||||||
|
|
||||||
void varid_cppcast() {
|
void varid_cppcast() {
|
||||||
ASSERT_EQUALS("1: const_cast < int * > ( code ) [ 0 ] = 0 ;\n",
|
ASSERT_EQUALS("1: const_cast < int * > ( code ) [ 0 ] = 0 ;\n",
|
||||||
tokenize("const_cast<int *>(code)[0] = 0;"));
|
tokenize("const_cast<int *>(code)[0] = 0;"));
|
||||||
|
|
|
@ -177,11 +177,17 @@ def scanarchive(filepath, jobs):
|
||||||
FOLDER = None
|
FOLDER = None
|
||||||
JOBS = '-j1'
|
JOBS = '-j1'
|
||||||
REV = None
|
REV = None
|
||||||
|
SKIP = []
|
||||||
|
WORKDIR = os.path.expanduser('~/daca2');
|
||||||
for arg in sys.argv[1:]:
|
for arg in sys.argv[1:]:
|
||||||
if arg[:6] == '--rev=':
|
if arg[:6] == '--rev=':
|
||||||
REV = arg[6:]
|
REV = arg[6:]
|
||||||
elif arg[:2] == '-j':
|
elif arg[:2] == '-j':
|
||||||
JOBS = arg
|
JOBS = arg
|
||||||
|
elif arg[:7] == '--skip=':
|
||||||
|
SKIP.append(arg[7:])
|
||||||
|
elif arg[:10] == '--workdir=':
|
||||||
|
WORKDIR = arg[10:]
|
||||||
else:
|
else:
|
||||||
FOLDER = arg
|
FOLDER = arg
|
||||||
|
|
||||||
|
@ -189,6 +195,10 @@ if not FOLDER:
|
||||||
print('no folder given')
|
print('no folder given')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not os.path.isdir(WORKDIR):
|
||||||
|
print('workdir \'' + WORKDIR + '\' is not a folder')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
archives = getpackages(FOLDER)
|
archives = getpackages(FOLDER)
|
||||||
if len(archives) == 0:
|
if len(archives) == 0:
|
||||||
print('failed to load packages')
|
print('failed to load packages')
|
||||||
|
@ -197,12 +207,13 @@ if len(archives) == 0:
|
||||||
print('Sleep for 10 seconds..')
|
print('Sleep for 10 seconds..')
|
||||||
time.sleep(10)
|
time.sleep(10)
|
||||||
|
|
||||||
workdir = os.path.expanduser('~/daca2/')
|
if not WORKDIR.endswith('/'):
|
||||||
|
WORKDIR = WORKDIR + '/'
|
||||||
|
|
||||||
print('~/daca2/' + FOLDER)
|
print('~/daca2/' + FOLDER)
|
||||||
if not os.path.isdir(workdir + FOLDER):
|
if not os.path.isdir(WORKDIR + FOLDER):
|
||||||
os.makedirs(workdir + FOLDER)
|
os.makedirs(WORKDIR + FOLDER)
|
||||||
os.chdir(workdir + FOLDER)
|
os.chdir(WORKDIR + FOLDER)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
results = open('results.txt', 'wt')
|
results = open('results.txt', 'wt')
|
||||||
|
@ -214,6 +225,11 @@ try:
|
||||||
results.close()
|
results.close()
|
||||||
|
|
||||||
for archive in archives:
|
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)
|
scanarchive(archive, JOBS)
|
||||||
|
|
||||||
results = open('results.txt', 'at')
|
results = open('results.txt', 'at')
|
||||||
|
|
|
@ -17,3 +17,5 @@ cd ..
|
||||||
|
|
||||||
# Detect duplicate code..
|
# Detect duplicate code..
|
||||||
~/pmd-4.2.6/bin/cpd.sh lib/ > devinfo/cpd.txt
|
~/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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue