Merge branch 'master' of https://github.com/danmar/cppcheck
This commit is contained in:
commit
fa04273473
2
Makefile
2
Makefile
|
@ -362,7 +362,7 @@ $(SRCDIR)/tokenize.o: lib/tokenize.cpp lib/tokenize.h lib/errorlogger.h lib/conf
|
|||
$(SRCDIR)/tokenlist.o: lib/tokenlist.cpp lib/tokenlist.h lib/config.h lib/token.h lib/valueflow.h lib/mathlib.h lib/path.h lib/preprocessor.h lib/settings.h lib/library.h lib/suppressions.h lib/standards.h lib/timer.h lib/errorlogger.h
|
||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) -c -o $(SRCDIR)/tokenlist.o $(SRCDIR)/tokenlist.cpp
|
||||
|
||||
$(SRCDIR)/valueflow.o: lib/valueflow.cpp lib/valueflow.h lib/token.h lib/config.h lib/mathlib.h
|
||||
$(SRCDIR)/valueflow.o: lib/valueflow.cpp lib/valueflow.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/mathlib.h lib/settings.h lib/library.h lib/path.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/token.h lib/tokenlist.h
|
||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) -c -o $(SRCDIR)/valueflow.o $(SRCDIR)/valueflow.cpp
|
||||
|
||||
cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlineparser.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/path.h lib/mathlib.h lib/suppressions.h lib/standards.h lib/timer.h lib/errorlogger.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h cli/filelister.h
|
||||
|
|
|
@ -112,7 +112,7 @@ the latest sources in a zip or tgz archive</a> from the github website.</p>
|
|||
</ul>
|
||||
<h2 id="other">Other</h2>
|
||||
<ul>
|
||||
<li><a href="daca2-report/daca2.html">DACA2 - Scanning Debian with latest Cppcheck</a></li>
|
||||
<li>DACA2 - Scanning Debian with Cppcheck. Version: <a href="daca2-cppcheck1.63/daca2.html">1.63</a> / <a href="daca2-report/daca2.html">head</a></li>
|
||||
<li><a href="coverage_report/">Coverage report</a></li>
|
||||
<li><a href="cpd.txt">CPD report (duplicate code)</a></li>
|
||||
</ul>
|
||||
|
|
|
@ -468,7 +468,7 @@ void CheckClass::initializeVarList(const Function &func, std::list<const Functio
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (level == 0 && Token::Match(ftok, "%var% {") && ftok->str() != "const" && Token::Match(ftok->next()->link()->next(), ",|{|%type%")) {
|
||||
} else if (level == 0 && Token::Match(ftok, "%var% {") && ftok->str() != "const" && Token::Match(ftok->next()->link()->next(), "%type%|,|{")) {
|
||||
initVar(ftok->str(), scope, usage);
|
||||
ftok = ftok->linkAt(1);
|
||||
} else if (level != 0 && Token::Match(ftok, "%var% =")) // assignment in the initializer: var(value = x)
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "symboldatabase.h"
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
|
||||
// Register this check class (by creating a static instance of it).
|
||||
// Disabled in release builds
|
||||
|
@ -48,6 +50,34 @@ void CheckInternal::checkTokenMatchPatterns()
|
|||
continue;
|
||||
}
|
||||
|
||||
const char *p = pattern.c_str();
|
||||
while (*p) {
|
||||
while (*p && std::isspace(*p))
|
||||
p++;
|
||||
const char *start = p;
|
||||
while (*p && !std::isspace(*p))
|
||||
p++;
|
||||
const char *end = p - 1;
|
||||
if (start < end && !(*start == '[' && *end == ']')) {
|
||||
bool cmd = (*start=='%' && std::isalpha(*(start+1)));
|
||||
// check multicompare pattern..
|
||||
for (const char *s = start; s != end; s++) {
|
||||
if (*s == '|') {
|
||||
if (!(*(s+1) == '%' && std::isalpha(*(s+2)))) {
|
||||
cmd = false;
|
||||
} else if (!cmd &&
|
||||
std::strncmp(s+1,"%op%",4)!=0 &&
|
||||
std::strncmp(s+1,"%or%",4)!=0 &&
|
||||
std::strncmp(s+1,"%cop%",5)!=0 &&
|
||||
std::strncmp(s+1,"%var%",5)!=0 &&
|
||||
std::strncmp(s+1,"%oror%",6)!=0) {
|
||||
multiComparePatternError(tok, pattern, funcname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for signs of complex patterns
|
||||
if (pattern.find_first_of("[|%") != std::string::npos)
|
||||
continue;
|
||||
|
@ -245,6 +275,13 @@ void CheckInternal::checkRedundantNextPrevious()
|
|||
}
|
||||
}
|
||||
|
||||
void CheckInternal::multiComparePatternError(const Token* tok, const std::string& pattern, const std::string &funcname)
|
||||
{
|
||||
reportError(tok, Severity::error, "multiComparePatternError",
|
||||
"Bad multicompare pattern (a %cmd% must be first unless it is %or%,%op%,%cop%,%var%,%oror%) inside Token::" + funcname + "() call: \"" + pattern + "\""
|
||||
);
|
||||
}
|
||||
|
||||
void CheckInternal::simplePatternError(const Token* tok, const std::string& pattern, const std::string &funcname)
|
||||
{
|
||||
reportError(tok, Severity::warning, "simplePatternError",
|
||||
|
|
|
@ -73,6 +73,7 @@ public:
|
|||
void checkRedundantNextPrevious();
|
||||
|
||||
private:
|
||||
void multiComparePatternError(const Token *tok, const std::string &pattern, const std::string &funcname);
|
||||
void simplePatternError(const Token *tok, const std::string &pattern, const std::string &funcname);
|
||||
void complexPatternError(const Token *tok, const std::string &pattern, const std::string &funcname);
|
||||
void missingPercentCharacterError(const Token *tok, const std::string &pattern, const std::string &funcname);
|
||||
|
@ -81,6 +82,7 @@ private:
|
|||
|
||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
|
||||
CheckInternal c(0, settings, errorLogger);
|
||||
c.multiComparePatternError(0, ";|%type%", "Match");
|
||||
c.simplePatternError(0, "class {", "Match");
|
||||
c.complexPatternError(0, "%type% ( )", "Match");
|
||||
c.missingPercentCharacterError(0, "%num", "Match");
|
||||
|
|
|
@ -2158,8 +2158,10 @@ void CheckOther::checkZeroDivision()
|
|||
std::list<ValueFlow::Value>::const_iterator it;
|
||||
for (it = values.begin(); it != values.end(); ++it) {
|
||||
if (it->intvalue == 0) {
|
||||
if (!it->link || _settings->isEnabled("warning"))
|
||||
if (it->condition == NULL)
|
||||
zerodivError(tok);
|
||||
else if (_settings->isEnabled("warning"))
|
||||
zerodivcondError(it->condition,tok);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2176,6 +2178,11 @@ void CheckOther::checkZeroDivisionOrUselessCondition()
|
|||
{
|
||||
if (!_settings->isEnabled("warning"))
|
||||
return;
|
||||
|
||||
// Use experimental checking instead based on value flow analysis
|
||||
if (_settings->valueFlow)
|
||||
return;
|
||||
|
||||
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||
const std::size_t numberOfFunctions = symbolDatabase->functionScopes.size();
|
||||
for (std::size_t functionIndex = 0; functionIndex < numberOfFunctions; ++functionIndex) {
|
||||
|
@ -2297,6 +2304,24 @@ void CheckOther::checkZeroDivisionOrUselessCondition()
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: this utility function should probably be moved to some common file
|
||||
static std::string astStringify(const Token *top)
|
||||
{
|
||||
const Token *start = top;
|
||||
while (start->astOperand1() && start->astOperand2())
|
||||
start = start->astOperand1();
|
||||
const Token *end = top;
|
||||
while (end->astOperand1() && end->astOperand2())
|
||||
end = end->astOperand2();
|
||||
std::string str;
|
||||
for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
|
||||
str += tok->str();
|
||||
if (Token::Match(tok, "%var%|%num% %var%|%num%"))
|
||||
str += " ";
|
||||
}
|
||||
return str + end->str();
|
||||
}
|
||||
|
||||
void CheckOther::zerodivcondError(const Token *tokcond, const Token *tokdiv)
|
||||
{
|
||||
std::list<const Token *> callstack;
|
||||
|
@ -2307,9 +2332,13 @@ void CheckOther::zerodivcondError(const Token *tokcond, const Token *tokdiv)
|
|||
callstack.push_back(tokdiv);
|
||||
}
|
||||
std::string condition;
|
||||
if (Token::Match(tokcond, "%num% <|<=")) {
|
||||
if (!tokcond) {
|
||||
// getErrorMessages
|
||||
} else if (Token::Match(tokcond, "%num% <|<=")) {
|
||||
condition = tokcond->strAt(2) + ((tokcond->strAt(1) == "<") ? ">" : ">=") + tokcond->str();
|
||||
} else if (tokcond) {
|
||||
} else if (tokcond->isComparisonOp()) {
|
||||
condition = astStringify(tokcond);
|
||||
} else {
|
||||
if (tokcond->str() == "!")
|
||||
condition = tokcond->next()->str() + "==0";
|
||||
else
|
||||
|
|
|
@ -98,8 +98,12 @@ public:
|
|||
|
||||
class ArgumentChecks {
|
||||
public:
|
||||
ArgumentChecks() {
|
||||
notbool = notnull = notuninit = formatstr = strz = false;
|
||||
ArgumentChecks() :
|
||||
notbool(false),
|
||||
notnull(false),
|
||||
notuninit(false),
|
||||
formatstr(false),
|
||||
strz(false) {
|
||||
}
|
||||
|
||||
bool notbool;
|
||||
|
|
|
@ -2023,7 +2023,7 @@ bool Function::isImplicitlyVirtual(bool defaultVal) const
|
|||
bool Function::isImplicitlyVirtual_rec(const ::Type* baseType, bool& safe) const
|
||||
{
|
||||
// check each base class
|
||||
for (unsigned int i = 0; i < baseType->derivedFrom.size(); ++i) {
|
||||
for (std::size_t i = 0; i < baseType->derivedFrom.size(); ++i) {
|
||||
// check if base class exists in database
|
||||
if (baseType->derivedFrom[i].type && baseType->derivedFrom[i].type->classScope) {
|
||||
const Scope *parent = baseType->derivedFrom[i].type->classScope;
|
||||
|
@ -2055,9 +2055,11 @@ bool Function::isImplicitlyVirtual_rec(const ::Type* baseType, bool& safe) const
|
|||
}
|
||||
}
|
||||
|
||||
if (!baseType->derivedFrom[i].type->derivedFrom.empty())
|
||||
if (isImplicitlyVirtual_rec(baseType->derivedFrom[i].type, safe))
|
||||
if (!baseType->derivedFrom[i].type->derivedFrom.empty()) {
|
||||
// avoid endless recursion, see #5289 Crash: Stack overflow in isImplicitlyVirtual_rec when checking SVN
|
||||
if ((baseType != baseType->derivedFrom[i].type) && isImplicitlyVirtual_rec(baseType->derivedFrom[i].type, safe))
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// unable to find base class so assume it has no virtual function
|
||||
safe = false;
|
||||
|
|
|
@ -65,6 +65,10 @@ public:
|
|||
} needInitialization;
|
||||
|
||||
struct BaseInfo {
|
||||
BaseInfo() :
|
||||
type(NULL), nameTok(NULL), access(Public), isVirtual(false) {
|
||||
}
|
||||
|
||||
std::string name;
|
||||
const Type* type;
|
||||
const Token* nameTok;
|
||||
|
@ -73,6 +77,10 @@ public:
|
|||
};
|
||||
|
||||
struct FriendInfo {
|
||||
FriendInfo() :
|
||||
nameStart(NULL), nameEnd(NULL), type(NULL) {
|
||||
}
|
||||
|
||||
const Token* nameStart;
|
||||
const Token* nameEnd;
|
||||
std::string name;
|
||||
|
|
|
@ -620,7 +620,7 @@ bool TemplateSimplifier::instantiateMatch(const Token *instance, const std::stri
|
|||
if (patternAfter) {
|
||||
const Token *tok = instance;
|
||||
unsigned int indentlevel = 0;
|
||||
for (tok = instance; tok && (tok->str() != ">" || indentlevel > 0); tok = tok->next()) {
|
||||
for (tok = instance; tok && (tok->str() != ">" || indentlevel > 0) && (tok->str() != ">>" || indentlevel > 1); tok = tok->next()) {
|
||||
if (Token::Match(tok, "[<,] %var% <") && templateParameters(tok->tokAt(2)) > 0)
|
||||
++indentlevel;
|
||||
if (indentlevel > 0 && tok->str() == ">")
|
||||
|
|
|
@ -206,6 +206,7 @@ void Token::deleteThis()
|
|||
_function = _next->_function;
|
||||
_variable = _next->_variable;
|
||||
_originalName = _next->_originalName;
|
||||
values = _next->values;
|
||||
if (_link)
|
||||
_link->link(this);
|
||||
|
||||
|
@ -229,6 +230,7 @@ void Token::deleteThis()
|
|||
_function = _previous->_function;
|
||||
_variable = _previous->_variable;
|
||||
_originalName = _previous->_originalName;
|
||||
values = _previous->values;
|
||||
if (_link)
|
||||
_link->link(this);
|
||||
|
||||
|
|
|
@ -370,6 +370,7 @@ Token * Tokenizer::deleteInvalidTypedef(Token *typeDef)
|
|||
}
|
||||
|
||||
struct Space {
|
||||
Space() : classEnd(NULL), isNamespace(false) { }
|
||||
std::string className;
|
||||
const Token * classEnd;
|
||||
bool isNamespace;
|
||||
|
@ -1605,7 +1606,7 @@ bool Tokenizer::tokenize(std::istream &code,
|
|||
list.createAst();
|
||||
|
||||
if (_settings->valueFlow)
|
||||
ValueFlow::setValues(list.front());
|
||||
ValueFlow::setValues(&list, _errorLogger, _settings);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -7531,23 +7532,23 @@ bool Tokenizer::duplicateDefinition(Token ** tokPtr, const Token * name) const
|
|||
|
||||
class EnumValue {
|
||||
public:
|
||||
EnumValue() {
|
||||
name = 0;
|
||||
value = 0;
|
||||
start = 0;
|
||||
end = 0;
|
||||
EnumValue() :
|
||||
name(NULL),
|
||||
value(NULL),
|
||||
start(NULL),
|
||||
end(NULL) {
|
||||
}
|
||||
EnumValue(const EnumValue &ev) {
|
||||
name = ev.name;
|
||||
value = ev.value;
|
||||
start = ev.start;
|
||||
end = ev.end;
|
||||
EnumValue(const EnumValue &ev) :
|
||||
name(ev.name),
|
||||
value(ev.value),
|
||||
start(ev.start),
|
||||
end(ev.end) {
|
||||
}
|
||||
EnumValue(Token *name_, Token *value_, Token *start_, Token *end_) {
|
||||
name = name_;
|
||||
value = value_;
|
||||
start = start_;
|
||||
end = end_;
|
||||
EnumValue(Token *name_, Token *value_, Token *start_, Token *end_) :
|
||||
name(name_),
|
||||
value(value_),
|
||||
start(start_),
|
||||
end(end_) {
|
||||
}
|
||||
|
||||
void simplify(const std::map<std::string, EnumValue> &enumValues) {
|
||||
|
|
|
@ -17,20 +17,47 @@
|
|||
*/
|
||||
|
||||
#include "valueflow.h"
|
||||
#include "token.h"
|
||||
#include "errorlogger.h"
|
||||
#include "mathlib.h"
|
||||
#include "settings.h"
|
||||
#include "symboldatabase.h"
|
||||
#include "token.h"
|
||||
#include "tokenlist.h"
|
||||
|
||||
static void valueFlowBeforeCondition(Token *tokens)
|
||||
#include <iostream>
|
||||
|
||||
|
||||
static void printvalues(const Token *tok)
|
||||
{
|
||||
for (Token *tok = tokens; tok; tok = tok->next()) {
|
||||
if (tok->values.empty())
|
||||
std::cout << "empty";
|
||||
for (std::list<ValueFlow::Value>::const_iterator it = tok->values.begin(); it != tok->values.end(); ++it)
|
||||
std::cout << " " << (it->intvalue);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
static void bailout(TokenList *tokenlist, ErrorLogger *errorLogger, const Token *tok, const std::string &what)
|
||||
{
|
||||
std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
|
||||
callstack.push_back(ErrorLogger::ErrorMessage::FileLocation(tok,tokenlist));
|
||||
ErrorLogger::ErrorMessage errmsg(callstack, Severity::debug, "ValueFlow bailout: " + what, "valueFlowBailout", false);
|
||||
errorLogger->reportErr(errmsg);
|
||||
}
|
||||
|
||||
static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
||||
{
|
||||
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||
unsigned int varid;
|
||||
MathLib::bigint num;
|
||||
const Variable *var;
|
||||
if (Token::Match(tok, "==|!=|>=|<=") && tok->astOperand1() && tok->astOperand2()) {
|
||||
if (tok->astOperand1()->isName() && tok->astOperand2()->isNumber()) {
|
||||
varid = tok->astOperand1()->varId();
|
||||
var = tok->astOperand1()->variable();
|
||||
num = MathLib::toLongNumber(tok->astOperand2()->str());
|
||||
} else if (tok->astOperand1()->isNumber() && tok->astOperand2()->isName()) {
|
||||
varid = tok->astOperand2()->varId();
|
||||
var = tok->astOperand2()->variable();
|
||||
num = MathLib::toLongNumber(tok->astOperand1()->str());
|
||||
} else {
|
||||
continue;
|
||||
|
@ -38,9 +65,11 @@ static void valueFlowBeforeCondition(Token *tokens)
|
|||
} else if (Token::Match(tok->previous(), "if|while ( %var% %oror%|&&|)") ||
|
||||
Token::Match(tok, "%oror%|&& %var% %oror%|&&|)")) {
|
||||
varid = tok->next()->varId();
|
||||
var = tok->next()->variable();
|
||||
num = 0;
|
||||
} else if (tok->str() == "!" && tok->astOperand1() && tok->astOperand1()->isName()) {
|
||||
varid = tok->astOperand1()->varId();
|
||||
var = tok->astOperand1()->variable();
|
||||
num = 0;
|
||||
} else {
|
||||
continue;
|
||||
|
@ -49,27 +78,112 @@ static void valueFlowBeforeCondition(Token *tokens)
|
|||
if (varid == 0U)
|
||||
continue;
|
||||
|
||||
// bailout: global variables
|
||||
if (var && var->isGlobal()) {
|
||||
if (settings->debugwarnings)
|
||||
bailout(tokenlist, errorLogger, tok, "global variable " + var->nameToken()->str());
|
||||
continue;
|
||||
}
|
||||
|
||||
struct ValueFlow::Value val;
|
||||
val.link = tok;
|
||||
val.condition = tok;
|
||||
val.intvalue = num;
|
||||
|
||||
for (Token *tok2 = tok->previous(); tok2; tok2 = tok2->previous()) {
|
||||
if (tok2->varId() == varid)
|
||||
tok2->values.push_back(val);
|
||||
if (tok2->str() == "{") {
|
||||
if (!Token::simpleMatch(tok2->previous(), ") {"))
|
||||
for (Token *tok2 = tok->previous(); ; tok2 = tok2->previous()) {
|
||||
if (!tok2) {
|
||||
if (settings->debugwarnings) {
|
||||
std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
|
||||
callstack.push_back(ErrorLogger::ErrorMessage::FileLocation(tok,tokenlist));
|
||||
ErrorLogger::ErrorMessage errmsg(callstack, Severity::debug, "iterated too far", "debugValueFlowBeforeCondition", false);
|
||||
errorLogger->reportErr(errmsg);
|
||||
}
|
||||
break;
|
||||
if (!Token::simpleMatch(tok2->previous()->link()->previous(), "if ("))
|
||||
}
|
||||
|
||||
if (tok2->varId() == varid) {
|
||||
// bailout: assignment
|
||||
if (Token::Match(tok2, "%var% =")) {
|
||||
if (settings->debugwarnings)
|
||||
bailout(tokenlist, errorLogger, tok2, "assignment of " + tok2->str());
|
||||
break;
|
||||
}
|
||||
|
||||
tok2->values.push_back(val);
|
||||
if (var && tok2 == var->nameToken())
|
||||
break;
|
||||
}
|
||||
|
||||
if (tok2->str() == "}") {
|
||||
if (settings->debugwarnings)
|
||||
bailout(tokenlist, errorLogger, tok2, "variable " + var->nameToken()->str() + " stopping on }");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ValueFlow::setValues(Token *tokens)
|
||||
static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
||||
{
|
||||
for (Token *tok = tokens; tok; tok = tok->next())
|
||||
std::list<ValueFlow::Value> argvalues;
|
||||
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||
if (Token::Match(tok, "[(,] %var% [,)]") && !tok->next()->values.empty())
|
||||
argvalues = tok->next()->values;
|
||||
else if (Token::Match(tok, "[(,] %num% [,)]")) {
|
||||
ValueFlow::Value val;
|
||||
val.condition = 0;
|
||||
val.intvalue = MathLib::toLongNumber(tok->next()->str());
|
||||
argvalues.clear();
|
||||
argvalues.push_back(val);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Token * const argumentToken = tok->next();
|
||||
|
||||
// is this a function call?
|
||||
const Token *ftok = tok;
|
||||
while (ftok && ftok->str() != "(")
|
||||
ftok = ftok->astParent();
|
||||
if (!ftok || !ftok->astOperand1() || !ftok->astOperand2() || !ftok->astOperand1()->function())
|
||||
continue;
|
||||
|
||||
// Get argument nr
|
||||
unsigned int argnr = 0;
|
||||
for (const Token *argtok = ftok->next(); argtok && argtok != argumentToken; argtok = argtok->nextArgument())
|
||||
++ argnr;
|
||||
|
||||
// Get function argument, and check if parameter is passed by value
|
||||
const Function * const function = ftok->astOperand1()->function();
|
||||
const Variable * const arg = function ? function->getArgumentVar(argnr) : NULL;
|
||||
if (!Token::Match(arg ? arg->typeStartToken() : NULL, "const| %type% %var% ,|)"))
|
||||
continue;
|
||||
|
||||
// Function scope..
|
||||
const Scope * const functionScope = function ? function->functionScope : NULL;
|
||||
if (!functionScope)
|
||||
continue;
|
||||
|
||||
// Set value in function scope..
|
||||
const unsigned int varid2 = arg->nameToken()->varId();
|
||||
for (const Token *tok2 = functionScope->classStart->next(); tok2 != functionScope->classEnd; tok2 = tok2->next()) {
|
||||
if (Token::Match(tok2, "%cop%|return %varid%", varid2)) {
|
||||
tok2 = tok2->next();
|
||||
std::list<ValueFlow::Value> &values = const_cast<Token*>(tok2)->values;
|
||||
values.insert(values.begin(), argvalues.begin(), argvalues.end());
|
||||
} else if (tok2->varId() == varid2 || tok2->str() == "{") {
|
||||
if (settings->debugwarnings)
|
||||
bailout(tokenlist, errorLogger, tok2, "parameter " + arg->nameToken()->str());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ValueFlow::setValues(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
||||
{
|
||||
for (Token *tok = tokenlist->front(); tok; tok = tok->next())
|
||||
tok->values.clear();
|
||||
|
||||
valueFlowBeforeCondition(tokens);
|
||||
valueFlowBeforeCondition(tokenlist, errorLogger, settings);
|
||||
valueFlowSubFunction(tokenlist, errorLogger, settings);
|
||||
}
|
||||
|
|
|
@ -22,15 +22,17 @@
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
class Token;
|
||||
class TokenList;
|
||||
class ErrorLogger;
|
||||
class Settings;
|
||||
|
||||
namespace ValueFlow {
|
||||
|
||||
struct Value {
|
||||
const Token *link;
|
||||
const Token *condition;
|
||||
long long intvalue;
|
||||
};
|
||||
|
||||
void setValues(Token *tokens);
|
||||
void setValues(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings);
|
||||
}
|
||||
|
||||
#endif // valueflowH
|
||||
|
|
|
@ -40,6 +40,7 @@ private:
|
|||
TEST_CASE(unknownPattern)
|
||||
TEST_CASE(redundantNextPrevious)
|
||||
TEST_CASE(internalError)
|
||||
TEST_CASE(invalidMultiCompare);
|
||||
}
|
||||
|
||||
void check(const char code[]) {
|
||||
|
@ -222,7 +223,9 @@ private:
|
|||
" const Token *tok;\n"
|
||||
" Token::Match(tok, \"foo|%type|bar\");\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (error) Missing percent end character in Token::Match() pattern: \"foo|%type|bar\"\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:3]: (error) Bad multicompare pattern (a %cmd% must be first unless it is %or%,%op%,%cop%,%var%,%oror%) inside Token::Match() call: \"foo|%type|bar\"\n"
|
||||
"[test.cpp:3]: (error) Missing percent end character in Token::Match() pattern: \"foo|%type|bar\"\n"
|
||||
, errout.str());
|
||||
|
||||
// Make sure we don't take %or% for a broken %oror%
|
||||
check("void f() {\n"
|
||||
|
@ -312,6 +315,27 @@ private:
|
|||
"};");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void invalidMultiCompare() {
|
||||
// #5310
|
||||
check("void f() {\n"
|
||||
" const Token *tok;\n"
|
||||
" Token::Match(tok, \";|%type%\");\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (error) Bad multicompare pattern (a %cmd% must be first unless it is %or%,%op%,%cop%,%var%,%oror%) inside Token::Match() call: \";|%type%\"\n", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" const Token *tok;\n"
|
||||
" Token::Match(tok, \";|%oror%\");\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void f() {\n" // The %var%|%num% works..
|
||||
" const Token *tok;\n"
|
||||
" Token::Match(tok, \"%var%|%num%\");\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestInternal)
|
||||
|
|
|
@ -135,6 +135,7 @@ private:
|
|||
TEST_CASE(template40); // #5055 - template specialization outside struct
|
||||
TEST_CASE(template41); // #4710 - const in instantiation not handled perfectly
|
||||
TEST_CASE(template42); // #4878 - variadic templates
|
||||
TEST_CASE(template43); // #5097 - assert due to '>>' not treated as end of template instantiation
|
||||
TEST_CASE(template_unhandled);
|
||||
TEST_CASE(template_default_parameter);
|
||||
TEST_CASE(template_default_type);
|
||||
|
@ -2367,6 +2368,19 @@ private:
|
|||
tok(code);
|
||||
}
|
||||
|
||||
void template43() { // #5097 - Assert due to '>>' in 'B<A<C>>' not being treated as end of template instantation
|
||||
const char code[] = "template <typename T> struct C { };"
|
||||
"template <typename T> struct D { static int f() { return C<T>::f(); } };"
|
||||
"template <typename T> inline int f2() { return D<T>::f(); }"
|
||||
"template <typename T> int f1(int x, T *) { int id = f2<T>(); return id; }"
|
||||
"template <> struct C < B < A >> {"
|
||||
" static int f() {"
|
||||
" return f1 < B < A >> (0, reinterpret_cast< B<A> *>(E<void *>::Int(-1)));"
|
||||
" }"
|
||||
"};";
|
||||
tok(code); // Don't assert
|
||||
}
|
||||
|
||||
|
||||
void template_default_parameter() {
|
||||
{
|
||||
|
|
|
@ -1760,6 +1760,19 @@ private:
|
|||
"};");
|
||||
ASSERT(db && db->findScopeByName("Deri") && db->findScopeByName("Deri")->functionList.front().isImplicitlyVirtual(false)); // Default false, but we saw "virtual" -> true
|
||||
}
|
||||
// #5289
|
||||
{
|
||||
GET_SYMBOL_DB("template<>\n"
|
||||
"class Bar<void, void> {\n"
|
||||
"};\n"
|
||||
"template<typename K, typename V, int KeySize>\n"
|
||||
"class Bar : private Bar<void, void> {\n"
|
||||
" void foo() {\n"
|
||||
" }\n"
|
||||
"};");
|
||||
ASSERT(db && db->findScopeByName("Bar") && !db->findScopeByName("Bar")->functionList.front().isImplicitlyVirtual(false));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void garbage() {
|
||||
|
|
|
@ -34,7 +34,8 @@ public:
|
|||
private:
|
||||
|
||||
void run() {
|
||||
valueFlowBeforeCondition();
|
||||
TEST_CASE(valueFlowBeforeCondition);
|
||||
TEST_CASE(valueFlowSubFunction);
|
||||
}
|
||||
|
||||
bool testValueOfX(const char code[], unsigned int linenr, int value) {
|
||||
|
@ -53,19 +54,71 @@ private:
|
|||
if (it->intvalue == value)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void bailout(const char code[]) {
|
||||
Settings settings;
|
||||
settings.valueFlow = true; // temporary flag
|
||||
settings.debugwarnings = true;
|
||||
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer(&settings, this);
|
||||
std::istringstream istr(code);
|
||||
errout.str("");
|
||||
tokenizer.tokenize(istr, "test.cpp");
|
||||
}
|
||||
|
||||
|
||||
void valueFlowBeforeCondition() {
|
||||
const char code[] = "void f(int x) {\n"
|
||||
" int a = x;\n"
|
||||
" if (x == 123) {}\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 2U, 123));
|
||||
|
||||
// bailout: if/else/etc
|
||||
bailout("void f(int x) {\n"
|
||||
" if (x != 123) { b = x; }\n"
|
||||
" if (x == 123) {}\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:2]: (debug) ValueFlow bailout: variable x stopping on }\n", errout.str());
|
||||
|
||||
// bailout: assignment
|
||||
bailout("void f(int x) {\n"
|
||||
" x = y;\n"
|
||||
" if (x == 123) {}\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:2]: (debug) ValueFlow bailout: assignment of x\n", errout.str());
|
||||
|
||||
// bailout: global variables
|
||||
bailout("int x;\n"
|
||||
"void f() {\n"
|
||||
" int a = x;\n"
|
||||
" if (x == 123) {}\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (debug) ValueFlow bailout: global variable x\n", errout.str());
|
||||
}
|
||||
|
||||
void valueFlowSubFunction() {
|
||||
const char *code;
|
||||
|
||||
code = "void f1(int x) { return x; }\n"
|
||||
"void f2(int x) {\n"
|
||||
" f1(123);\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 1U, 123));
|
||||
|
||||
code = "void f1(int x) { return x; }\n"
|
||||
"void f2(int x) {\n"
|
||||
" f1(x);\n"
|
||||
" if (x==0){}\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 1U, 0));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -31,13 +31,6 @@ def readdate(data):
|
|||
return None
|
||||
datepos = datepos + 1
|
||||
|
||||
if os.path.isfile(os.path.expanduser('~/aws-debian.pem')):
|
||||
subprocess.call(['scp',
|
||||
'-i',
|
||||
os.path.expanduser('~/aws-debian.pem'),
|
||||
'admin@ec2-54-201-59-232.us-west-2.compute.amazonaws.com:daca2/results-*.txt',
|
||||
os.path.expanduser('~/daca2/')])
|
||||
|
||||
path = '.'
|
||||
if len(sys.argv) == 2:
|
||||
path = sys.argv[1]
|
||||
|
|
Loading…
Reference in New Issue