diff --git a/Makefile b/Makefile
index 161c1461c..ca92f981f 100644
--- a/Makefile
+++ b/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
diff --git a/htdocs/devinfo/index.php b/htdocs/devinfo/index.php
index c9000fae5..04754b447 100644
--- a/htdocs/devinfo/index.php
+++ b/htdocs/devinfo/index.php
@@ -112,7 +112,7 @@ the latest sources in a zip or tgz archive from the github website.
Other
diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp
index 8abfa8bb0..0283f81b2 100644
--- a/lib/checkclass.cpp
+++ b/lib/checkclass.cpp
@@ -468,7 +468,7 @@ void CheckClass::initializeVarList(const Function &func, std::liststr() != "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)
diff --git a/lib/checkinternal.cpp b/lib/checkinternal.cpp
index ca780cd07..b4e13eb40 100644
--- a/lib/checkinternal.cpp
+++ b/lib/checkinternal.cpp
@@ -22,6 +22,8 @@
#include "symboldatabase.h"
#include
#include
+#include
+#include
// 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",
diff --git a/lib/checkinternal.h b/lib/checkinternal.h
index a49336c1a..805b64c60 100644
--- a/lib/checkinternal.h
+++ b/lib/checkinternal.h
@@ -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");
diff --git a/lib/checkother.cpp b/lib/checkother.cpp
index be5ef24c0..7dd067319 100644
--- a/lib/checkother.cpp
+++ b/lib/checkother.cpp
@@ -2158,8 +2158,10 @@ void CheckOther::checkZeroDivision()
std::list::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 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
diff --git a/lib/library.h b/lib/library.h
index ea146bf80..b2429480b 100644
--- a/lib/library.h
+++ b/lib/library.h
@@ -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;
diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp
index cb0fa41ca..b459ea849 100644
--- a/lib/symboldatabase.cpp
+++ b/lib/symboldatabase.cpp
@@ -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;
diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h
index 953d4a4bb..2a2cfd7ff 100644
--- a/lib/symboldatabase.h
+++ b/lib/symboldatabase.h
@@ -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;
diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp
index 54462f93c..c0fdcaf9b 100644
--- a/lib/templatesimplifier.cpp
+++ b/lib/templatesimplifier.cpp
@@ -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() == ">")
diff --git a/lib/token.cpp b/lib/token.cpp
index a069f73dd..77774cc5d 100644
--- a/lib/token.cpp
+++ b/lib/token.cpp
@@ -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);
diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp
index 54a7a7e53..bdb7500a0 100644
--- a/lib/tokenize.cpp
+++ b/lib/tokenize.cpp
@@ -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 &enumValues) {
diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp
index a6fe9d104..3f33825cf 100644
--- a/lib/valueflow.cpp
+++ b/lib/valueflow.cpp
@@ -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
+
+
+static void printvalues(const Token *tok)
{
- for (Token *tok = tokens; tok; tok = tok->next()) {
+ if (tok->values.empty())
+ std::cout << "empty";
+ for (std::list::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 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)
+ for (Token *tok2 = tok->previous(); ; tok2 = tok2->previous()) {
+ if (!tok2) {
+ if (settings->debugwarnings) {
+ std::list 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 (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 (tok2->str() == "{") {
- if (!Token::simpleMatch(tok2->previous(), ") {"))
- break;
- if (!Token::simpleMatch(tok2->previous()->link()->previous(), "if ("))
+ 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 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 &values = const_cast(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);
}
diff --git a/lib/valueflow.h b/lib/valueflow.h
index e707270ea..7e5474b66 100644
--- a/lib/valueflow.h
+++ b/lib/valueflow.h
@@ -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
diff --git a/test/testinternal.cpp b/test/testinternal.cpp
index dcaafced4..cc8604df9 100644
--- a/test/testinternal.cpp
+++ b/test/testinternal.cpp
@@ -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)
diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp
index d076cd44a..ea773fa3f 100644
--- a/test/testsimplifytokens.cpp
+++ b/test/testsimplifytokens.cpp
@@ -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>' not being treated as end of template instantation
+ const char code[] = "template struct C { };"
+ "template struct D { static int f() { return C::f(); } };"
+ "template inline int f2() { return D::f(); }"
+ "template int f1(int x, T *) { int id = f2(); return id; }"
+ "template <> struct C < B < A >> {"
+ " static int f() {"
+ " return f1 < B < A >> (0, reinterpret_cast< B *>(E::Int(-1)));"
+ " }"
+ "};";
+ tok(code); // Don't assert
+ }
+
void template_default_parameter() {
{
diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp
index 3cd5cbe43..ba10d8b2e 100644
--- a/test/testsymboldatabase.cpp
+++ b/test/testsymboldatabase.cpp
@@ -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 {\n"
+ "};\n"
+ "template\n"
+ "class Bar : private Bar {\n"
+ " void foo() {\n"
+ " }\n"
+ "};");
+ ASSERT(db && db->findScopeByName("Bar") && !db->findScopeByName("Bar")->functionList.front().isImplicitlyVirtual(false));
+ }
+
}
void garbage() {
diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp
index b12e4eefd..d33a0cc98 100644
--- a/test/testvalueflow.cpp
+++ b/test/testvalueflow.cpp
@@ -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));
}
};
diff --git a/tools/daca2-report.py b/tools/daca2-report.py
index a2c4efa8d..783edbe3d 100644
--- a/tools/daca2-report.py
+++ b/tools/daca2-report.py
@@ -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]
diff --git a/tools/times-tags.sh b/tools/times-tags.sh
old mode 100644
new mode 100755
diff --git a/tools/times.sh b/tools/times.sh
old mode 100644
new mode 100755