diff --git a/cfg/std.cfg b/cfg/std.cfg
index 97f5ce0152e..52ce5899ab7 100644
--- a/cfg/std.cfg
+++ b/cfg/std.cfg
@@ -6884,6 +6884,18 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
+
+
+
+
+ false
+
+
+
+
+
+
+
diff --git a/lib/astutils.cpp b/lib/astutils.cpp
index bc85cfab931..78252680e11 100644
--- a/lib/astutils.cpp
+++ b/lib/astutils.cpp
@@ -738,7 +738,7 @@ std::vector getParentValueTypes(const Token* tok, const Settings* set
const ValueType* vtCont = contTok->valueType();
if (!vtCont->containerTypeToken)
return {};
- ValueType vtParent = ValueType::parseDecl(vtCont->containerTypeToken, *settings, true); // TODO: set isCpp
+ ValueType vtParent = ValueType::parseDecl(vtCont->containerTypeToken, *settings);
return {std::move(vtParent)};
}
if (Token::Match(tok->astParent(), "return|(|{|%assign%") && parent) {
diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp
index 497babe1d60..29a94f024bd 100644
--- a/lib/checkclass.cpp
+++ b/lib/checkclass.cpp
@@ -3228,7 +3228,7 @@ void CheckClass::checkThisUseAfterFree()
for (const Variable &var : classScope->varlist) {
// Find possible "self pointer".. pointer/smartpointer member variable of "self" type.
if (var.valueType() && var.valueType()->smartPointerType != classScope->definedType && var.valueType()->typeScope != classScope) {
- const ValueType valueType = ValueType::parseDecl(var.typeStartToken(), *mSettings, true); // this is only called for C++
+ const ValueType valueType = ValueType::parseDecl(var.typeStartToken(), *mSettings);
if (valueType.smartPointerType != classScope->definedType)
continue;
}
diff --git a/lib/checkother.cpp b/lib/checkother.cpp
index 6b94c3484b0..deaadbf7ca0 100644
--- a/lib/checkother.cpp
+++ b/lib/checkother.cpp
@@ -3647,17 +3647,23 @@ void CheckOther::checkKnownArgument()
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
for (const Scope *functionScope : symbolDatabase->functionScopes) {
for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
- if (!Token::simpleMatch(tok->astParent(), "("))
+ if (!tok->hasKnownIntValue())
continue;
- if (!Token::Match(tok->astParent()->previous(), "%name%"))
+ if (Token::Match(tok, "++|--|%assign%"))
continue;
- if (Token::Match(tok->astParent()->previous(), "if|while|switch|sizeof"))
+ if (!Token::Match(tok->astParent(), "(|{|,"))
continue;
- if (tok == tok->astParent()->previous())
+ if (tok->astParent()->isCast())
continue;
- if (!tok->hasKnownIntValue())
+ int argn = -1;
+ const Token* ftok = getTokenArgumentFunction(tok, argn);
+ if (!ftok)
continue;
- if (tok->tokType() == Token::eIncDecOp)
+ if (ftok->isCast())
+ continue;
+ if (Token::Match(ftok, "if|while|switch|sizeof"))
+ continue;
+ if (tok == tok->astParent()->previous())
continue;
if (isConstVarExpression(tok))
continue;
@@ -3668,6 +3674,10 @@ void CheckOther::checkKnownArgument()
tok2 = tok2->astOperand2();
if (isVariableExpression(tok2))
continue;
+ if (tok->isComparisonOp() &&
+ isSameExpression(
+ mTokenizer->isCPP(), true, tok->astOperand1(), tok->astOperand2(), mSettings->library, true, true))
+ continue;
// ensure that there is a integer variable in expression with unknown value
std::string varexpr;
bool isVariableExprHidden = false; // Is variable expression explicitly hidden
@@ -3706,7 +3716,7 @@ void CheckOther::checkKnownArgument()
strTolower(funcname);
if (funcname.find("assert") != std::string::npos)
continue;
- knownArgumentError(tok, tok->astParent()->previous(), &tok->values().front(), varexpr, isVariableExprHidden);
+ knownArgumentError(tok, ftok, &tok->values().front(), varexpr, isVariableExprHidden);
}
}
}
diff --git a/lib/checkstring.cpp b/lib/checkstring.cpp
index 481438815d5..c9965b53e51 100644
--- a/lib/checkstring.cpp
+++ b/lib/checkstring.cpp
@@ -288,13 +288,7 @@ void CheckString::checkIncorrectStringCompare()
incorrectStringCompareError(tok->next(), "substr", end->strAt(1));
}
}
- } else if (Token::Match(tok, "&&|%oror%|( %str%|%char% &&|%oror%|)") && !Token::Match(tok, "( %str%|%char% )")) {
- incorrectStringBooleanError(tok->next(), tok->strAt(1));
- } else if (Token::Match(tok, "if|while ( %str%|%char% )") && !tok->tokAt(2)->getValue(0)) {
- incorrectStringBooleanError(tok->tokAt(2), tok->strAt(2));
- } else if (tok->str() == "?" && Token::Match(tok->astOperand1(), "%str%|%char%")) {
- incorrectStringBooleanError(tok->astOperand1(), tok->astOperand1()->str());
- } else if (Token::Match(tok, "%str%") && isUsedAsBool(tok))
+ } else if (Token::Match(tok, "%str%|%char%") && isUsedAsBool(tok))
incorrectStringBooleanError(tok, tok->str());
}
}
diff --git a/lib/checktype.cpp b/lib/checktype.cpp
index 3384bf69b5e..a15064122c1 100644
--- a/lib/checktype.cpp
+++ b/lib/checktype.cpp
@@ -437,7 +437,7 @@ void CheckType::checkFloatToIntegerOverflow()
while (scope && scope->type != Scope::ScopeType::eLambda && scope->type != Scope::ScopeType::eFunction)
scope = scope->nestedIn;
if (scope && scope->type == Scope::ScopeType::eFunction && scope->function && scope->function->retDef) {
- const ValueType &valueType = ValueType::parseDecl(scope->function->retDef, *mSettings, mTokenizer->isCPP());
+ const ValueType &valueType = ValueType::parseDecl(scope->function->retDef, *mSettings);
vtfloat = tok->astOperand1()->valueType();
checkFloatToIntegerOverflow(tok, &valueType, vtfloat, tok->astOperand1()->values());
}
diff --git a/lib/clangimport.cpp b/lib/clangimport.cpp
index 7b91d6c4b07..2e68aaa26bd 100644
--- a/lib/clangimport.cpp
+++ b/lib/clangimport.cpp
@@ -630,7 +630,7 @@ void clangimport::AstNode::setValueType(Token *tok)
if (!decl.front())
break;
- const ValueType valueType = ValueType::parseDecl(decl.front(), *mData->mSettings, true); // TODO: set isCpp
+ const ValueType valueType = ValueType::parseDecl(decl.front(), *mData->mSettings);
if (valueType.type != ValueType::Type::UNKNOWN_TYPE) {
tok->setValueType(new ValueType(valueType));
break;
@@ -1545,7 +1545,7 @@ static void setValues(const Tokenizer *tokenizer, const SymbolDatabase *symbolDa
for (Token *tok = const_cast(tokenizer->tokens()); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "sizeof (")) {
- ValueType vt = ValueType::parseDecl(tok->tokAt(2), *settings, tokenizer->isCPP());
+ ValueType vt = ValueType::parseDecl(tok->tokAt(2), *settings);
const int sz = vt.typeSize(settings->platform, true);
if (sz <= 0)
continue;
diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp
index bfc04ae73be..f64caa82e27 100644
--- a/lib/symboldatabase.cpp
+++ b/lib/symboldatabase.cpp
@@ -2214,12 +2214,13 @@ void Variable::evaluate(const Settings* settings)
const Library * const lib = &settings->library;
+ // TODO: ValueType::parseDecl() is also performing a container lookup
bool isContainer = false;
if (mNameToken)
setFlag(fIsArray, arrayDimensions(settings, isContainer));
if (mTypeStartToken)
- setValueType(ValueType::parseDecl(mTypeStartToken,*settings, true)); // TODO: set isCpp
+ setValueType(ValueType::parseDecl(mTypeStartToken,*settings));
const Token* tok = mTypeStartToken;
while (tok && tok->previous() && tok->previous()->isName())
@@ -2275,7 +2276,7 @@ void Variable::evaluate(const Settings* settings)
setFlag(fIsClass, !lib->podtype(strtype) && !mTypeStartToken->isStandardType() && !isEnumType() && !isPointer() && !isReference() && strtype != "...");
setFlag(fIsStlType, Token::simpleMatch(mTypeStartToken, "std ::"));
setFlag(fIsStlString, ::isStlStringType(mTypeStartToken));
- setFlag(fIsSmartPointer, lib->isSmartPointer(mTypeStartToken));
+ setFlag(fIsSmartPointer, mTypeStartToken->isCpp() && lib->isSmartPointer(mTypeStartToken));
}
if (mAccess == AccessControl::Argument) {
tok = mNameToken;
@@ -3558,7 +3559,7 @@ bool Type::isDerivedFrom(const std::string & ancestor) const
bool Variable::arrayDimensions(const Settings* settings, bool& isContainer)
{
isContainer = false;
- const Library::Container* container = settings->library.detectContainer(mTypeStartToken);
+ const Library::Container* container = (mTypeStartToken && mTypeStartToken->isCpp()) ? settings->library.detectContainer(mTypeStartToken) : nullptr;
if (container && container->arrayLike_indexOp && container->size_templateArgNo > 0) {
const Token* tok = Token::findsimplematch(mTypeStartToken, "<");
if (tok) {
@@ -5653,7 +5654,7 @@ const Function* SymbolDatabase::findFunction(const Token* const tok) const
return tok1->valueType()->typeScope->findFunction(tok, tok1->valueType()->constness == 1);
if (tok1 && Token::Match(tok1->previous(), "%name% (") && tok1->previous()->function() &&
tok1->previous()->function()->retDef) {
- ValueType vt = ValueType::parseDecl(tok1->previous()->function()->retDef, mSettings, mIsCpp);
+ ValueType vt = ValueType::parseDecl(tok1->previous()->function()->retDef, mSettings);
if (vt.typeScope)
return vt.typeScope->findFunction(tok, vt.constness == 1);
} else if (Token::Match(tok1, "%var% .")) {
@@ -5667,7 +5668,7 @@ const Function* SymbolDatabase::findFunction(const Token* const tok) const
} else if (Token::simpleMatch(tok->previous()->astOperand1(), "(")) {
const Token *castTok = tok->previous()->astOperand1();
if (castTok->isCast()) {
- ValueType vt = ValueType::parseDecl(castTok->next(),mSettings, mIsCpp);
+ ValueType vt = ValueType::parseDecl(castTok->next(),mSettings);
if (vt.typeScope)
return vt.typeScope->findFunction(tok, vt.constness == 1);
}
@@ -5697,7 +5698,7 @@ const Function* SymbolDatabase::findFunction(const Token* const tok) const
}
// Check for constructor
if (Token::Match(tok, "%name% (|{")) {
- ValueType vt = ValueType::parseDecl(tok, mSettings, mIsCpp);
+ ValueType vt = ValueType::parseDecl(tok, mSettings);
if (vt.typeScope)
return vt.typeScope->findFunction(tok, false);
}
@@ -6991,7 +6992,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
}
// Construct smart pointer
- else if (mSettings.library.isSmartPointer(start)) {
+ else if (mIsCpp && mSettings.library.isSmartPointer(start)) {
ValueType valuetype;
if (parsedecl(start, &valuetype, mDefaultSignedness, mSettings, mIsCpp)) {
setValueType(tok, valuetype);
@@ -7066,7 +7067,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
}
}
}
- if (tok->astParent() && Token::Match(tok->astOperand1(), "%name%|::")) {
+ if (mIsCpp && tok->astParent() && Token::Match(tok->astOperand1(), "%name%|::")) {
const Token *typeStartToken = tok->astOperand1();
while (typeStartToken && typeStartToken->str() == "::")
typeStartToken = typeStartToken->astOperand1();
@@ -7216,7 +7217,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
functionScope = functionScope->nestedIn;
if (functionScope && functionScope->type == Scope::eFunction && functionScope->function &&
functionScope->function->retDef) {
- ValueType vt = ValueType::parseDecl(functionScope->function->retDef, mSettings, mIsCpp);
+ ValueType vt = ValueType::parseDecl(functionScope->function->retDef, mSettings);
setValueType(tok, vt);
if (Token::simpleMatch(tok, "return {"))
setValueType(tok->next(), vt);
@@ -7314,10 +7315,10 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
createSymbolDatabaseSetVariablePointers();
}
-ValueType ValueType::parseDecl(const Token *type, const Settings &settings, bool isCpp)
+ValueType ValueType::parseDecl(const Token *type, const Settings &settings)
{
ValueType vt;
- parsedecl(type, &vt, settings.platform.defaultSign == 'u' ? Sign::UNSIGNED : Sign::SIGNED, settings, isCpp);
+ parsedecl(type, &vt, settings.platform.defaultSign == 'u' ? Sign::UNSIGNED : Sign::SIGNED, settings, type->isCpp());
return vt;
}
diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h
index d7c50ee7a2a..8b988e54a02 100644
--- a/lib/symboldatabase.h
+++ b/lib/symboldatabase.h
@@ -1268,7 +1268,7 @@ class CPPCHECKLIB ValueType {
originalTypeName(std::move(otn))
{}
- static ValueType parseDecl(const Token *type, const Settings &settings, bool isCpp);
+ static ValueType parseDecl(const Token *type, const Settings &settings);
static Type typeFromString(const std::string &typestr, bool longType);
diff --git a/lib/token.cpp b/lib/token.cpp
index 618979613d1..6c832f3a741 100644
--- a/lib/token.cpp
+++ b/lib/token.cpp
@@ -424,7 +424,13 @@ const std::string &Token::strAt(int index) const
return tok ? tok->mStr : emptyString;
}
-static int multiComparePercent(const Token *tok, const char*& haystack, nonneg int varid)
+static
+#if defined(__GNUC__)
+// GCC does not inline this by itself
+// need to use the old syntax since the C++11 [[xxx:always_inline]] cannot be used here
+inline __attribute__((always_inline))
+#endif
+int multiComparePercent(const Token *tok, const char*& haystack, nonneg int varid)
{
++haystack;
// Compare only the first character of the string for optimization reasons
@@ -556,7 +562,12 @@ static int multiComparePercent(const Token *tok, const char*& haystack, nonneg i
return 0xFFFF;
}
-int Token::multiCompare(const Token *tok, const char *haystack, nonneg int varid)
+static
+#if defined(__GNUC__)
+// need to use the old syntax since the C++11 [[xxx:always_inline]] cannot be used here
+inline __attribute__((always_inline))
+#endif
+int multiCompareImpl(const Token *tok, const char *haystack, nonneg int varid)
{
const char *needle = tok->str().c_str();
const char *needlePointer = needle;
@@ -609,6 +620,12 @@ int Token::multiCompare(const Token *tok, const char *haystack, nonneg int varid
return -1;
}
+// cppcheck-suppress unusedFunction - used in tests only
+int Token::multiCompare(const Token *tok, const char *haystack, nonneg int varid)
+{
+ return multiCompareImpl(tok, haystack, varid);
+}
+
bool Token::simpleMatch(const Token *tok, const char pattern[], size_t pattern_len)
{
if (!tok)
@@ -730,7 +747,7 @@ bool Token::Match(const Token *tok, const char pattern[], nonneg int varid)
// Parse multi options, such as void|int|char (accept token which is one of these 3)
else {
- const int res = multiCompare(tok, p, varid);
+ const int res = multiCompareImpl(tok, p, varid);
if (res == 0) {
// Empty alternative matches, use the same token on next round
while (*p && *p != ' ')
@@ -2569,3 +2586,11 @@ Token* findLambdaEndScope(Token* tok)
const Token* findLambdaEndScope(const Token* tok) {
return findLambdaEndScope(const_cast(tok));
}
+
+bool Token::isCpp() const
+{
+ if (mTokensFrontBack && mTokensFrontBack->list) {
+ return mTokensFrontBack->list->isCPP();
+ }
+ return true; // assume C++ by default
+}
diff --git a/lib/token.h b/lib/token.h
index e0ca0ed9d5e..b8232638152 100644
--- a/lib/token.h
+++ b/lib/token.h
@@ -154,6 +154,8 @@ struct TokenImpl {
* The Token class also has other functions for management of token list, matching tokens, etc.
*/
class CPPCHECKLIB Token {
+ friend class TestToken;
+
private:
TokensFrontBack* mTokensFrontBack{};
@@ -788,6 +790,7 @@ class CPPCHECKLIB Token {
return const_cast(findmatch(const_cast(startTok), pattern, end, varId));
}
+private:
/**
* Needle is build from multiple alternatives. If one of
* them is equal to haystack, return value is 1. If there
@@ -804,6 +807,7 @@ class CPPCHECKLIB Token {
*/
static int multiCompare(const Token *tok, const char *haystack, nonneg int varid);
+public:
nonneg int fileIndex() const {
return mImpl->mFileIndex;
}
@@ -1480,6 +1484,9 @@ class CPPCHECKLIB Token {
void setTokenDebug(TokenDebug td) {
mImpl->mDebug = td;
}
+
+ /** defaults to C++ if it cannot be determined */
+ bool isCpp() const;
};
Token* findTypeEnd(Token* tok);
diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp
index 8ed4f29cc6c..ffd9c209517 100644
--- a/lib/valueflow.cpp
+++ b/lib/valueflow.cpp
@@ -760,7 +760,7 @@ static void setTokenValue(Token* tok,
if (contains({ValueFlow::Value::ValueType::INT, ValueFlow::Value::ValueType::SYMBOLIC}, value.valueType) &&
Token::simpleMatch(parent->astOperand1(), "dynamic_cast"))
return;
- const ValueType &valueType = ValueType::parseDecl(castType, *settings, true); // TODO: set isCpp
+ const ValueType &valueType = ValueType::parseDecl(castType, *settings);
if (value.isImpossible() && value.isIntValue() && value.intvalue < 0 && astIsUnsigned(tok) &&
valueType.sign == ValueType::SIGNED && tok->valueType() &&
ValueFlow::getSizeOf(*tok->valueType(), settings) >= ValueFlow::getSizeOf(valueType, settings))
@@ -1095,7 +1095,7 @@ static void setTokenValueCast(Token *parent, const ValueType &valueType, const V
static nonneg int getSizeOfType(const Token *typeTok, const Settings *settings)
{
- const ValueType &valueType = ValueType::parseDecl(typeTok, *settings, true); // TODO: set isCpp
+ const ValueType &valueType = ValueType::parseDecl(typeTok, *settings);
return ValueFlow::getSizeOf(valueType, settings);
}
@@ -1298,7 +1298,7 @@ static Token * valueFlowSetConstantValue(Token *tok, const Settings *settings, b
setTokenValue(tok->next(), std::move(value), settings);
}
} else if (!tok2->type()) {
- const ValueType& vt = ValueType::parseDecl(tok2, *settings, true); // TODO: set isCpp
+ const ValueType& vt = ValueType::parseDecl(tok2, *settings);
size_t sz = ValueFlow::getSizeOf(vt, settings);
const Token* brac = tok2->astParent();
while (Token::simpleMatch(brac, "[")) {
@@ -4259,10 +4259,9 @@ struct LifetimeStore {
static bool hasBorrowingVariables(const std::list& vars, const std::vector& args, int depth = 10)
{
if (depth < 0)
- return false;
+ return true;
return std::any_of(vars.cbegin(), vars.cend(), [&](const Variable& var) {
- const ValueType* vt = var.valueType();
- if (vt) {
+ if (const ValueType* vt = var.valueType()) {
if (vt->pointer > 0 &&
std::none_of(args.begin(), args.end(), [vt](const Token* arg) {
return arg->valueType() && arg->valueType()->type == vt->type;
@@ -4766,7 +4765,7 @@ static bool isContainerOfPointers(const Token* tok, const Settings* settings)
return true;
}
- ValueType vt = ValueType::parseDecl(tok, *settings, true); // TODO: set isCpp
+ ValueType vt = ValueType::parseDecl(tok, *settings);
return vt.pointer > 0;
}
@@ -8629,7 +8628,7 @@ static bool valueFlowIsSameContainerType(const ValueType& contType, const Token*
if (!tok || !tok->valueType() || !tok->valueType()->containerTypeToken)
return false;
- const ValueType tokType = ValueType::parseDecl(tok->valueType()->containerTypeToken, *settings, true);
+ const ValueType tokType = ValueType::parseDecl(tok->valueType()->containerTypeToken, *settings);
return contType.isTypeEqual(&tokType);
}
@@ -8649,7 +8648,7 @@ static std::vector getInitListSize(const Token* tok,
if (valueType->container->stdStringLike) {
initList = astIsGenericChar(args[0]) && !astIsPointer(args[0]);
} else if (containerTypeToken && settings) {
- ValueType vt = ValueType::parseDecl(containerTypeToken, *settings, true); // TODO: set isCpp
+ ValueType vt = ValueType::parseDecl(containerTypeToken, *settings);
if (vt.pointer > 0 && astIsPointer(args[0]))
initList = true;
else if (vt.type == ValueType::ITERATOR && astIsIterator(args[0]))
@@ -9109,7 +9108,7 @@ static bool getMinMaxValues(const std::string &typestr, const Settings *settings
return false;
typeTokens.simplifyPlatformTypes();
typeTokens.simplifyStdType();
- const ValueType &vt = ValueType::parseDecl(typeTokens.front(), *settings, true); // TODO: set isCpp
+ const ValueType &vt = ValueType::parseDecl(typeTokens.front(), *settings);
return getMinMaxValues(&vt, settings->platform, minvalue, maxvalue);
}
diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp
index c6a04412543..4952c79d85e 100644
--- a/test/cfg/std.cpp
+++ b/test/cfg/std.cpp
@@ -4503,6 +4503,11 @@ void stdstring()
// valid
s.assign("a");
+
+#ifdef __cpp_lib_starts_ends_with
+ // cppcheck-suppress ignoredReturnValue
+ s.starts_with("abc");
+#endif
}
void stdvector()
diff --git a/test/testother.cpp b/test/testother.cpp
index fe87e9d28e2..d789c3bb18c 100644
--- a/test/testother.cpp
+++ b/test/testother.cpp
@@ -10905,6 +10905,14 @@ class TestOther : public TestFixture {
"}");
ASSERT_EQUALS("[test.cpp:3]: (style) Argument '(int)((x&0x01)>>7)' to function g is always 0. It does not matter what value 'x' has.\n", errout.str());
+ check("void g(int, int);\n"
+ "void f(int x) {\n"
+ " g(x, (x & 0x01) >> 7);\n"
+ "}");
+ ASSERT_EQUALS(
+ "[test.cpp:3]: (style) Argument '(x&0x01)>>7' to function g is always 0. It does not matter what value 'x' has.\n",
+ errout.str());
+
check("void g(int);\n"
"void f(int x) {\n"
" g(0);\n"
diff --git a/test/teststring.cpp b/test/teststring.cpp
index c0330ee3e19..9ea166688d9 100644
--- a/test/teststring.cpp
+++ b/test/teststring.cpp
@@ -735,7 +735,9 @@ class TestString : public TestFixture {
" if('\\0'){}\n"
" if(L'\\0'){}\n"
"}");
- ASSERT_EQUALS("", errout.str());
+ ASSERT_EQUALS("[test.cpp:2]: (warning) Conversion of char literal '\\0' to bool always evaluates to false.\n"
+ "[test.cpp:3]: (warning) Conversion of char literal L'\\0' to bool always evaluates to false.\n",
+ errout.str());
check("void f() {\n"
" if('\\0' || cond){}\n"
@@ -757,6 +759,22 @@ class TestString : public TestFixture {
" g(m[\"abc\"][0] ? true : false);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
+
+ check("void g(bool);\n"
+ " void f(std::map>&m) {\n"
+ " if (m.count(\"abc\"))\n"
+ " g(m[\"abc\"][0] ? true : false);\n"
+ "}\n");
+ ASSERT_EQUALS("", errout.str());
+
+ check("void g(bool b);\n"
+ "void f() {\n"
+ " g('\\0');\n"
+ " g('a');\n"
+ "}\n");
+ ASSERT_EQUALS("[test.cpp:3]: (warning) Conversion of char literal '\\0' to bool always evaluates to false.\n"
+ "[test.cpp:4]: (warning) Conversion of char literal 'a' to bool always evaluates to true.\n",
+ errout.str());
}
void deadStrcmp() {
diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp
index 50a58464abf..f24942164fa 100644
--- a/test/testvalueflow.cpp
+++ b/test/testvalueflow.cpp
@@ -7359,6 +7359,17 @@ class TestValueFlow : public TestFixture {
" if (llabs(0x80000000ffffffffL) == 0x7fffffff00000001L) {}\n"
"}\n";
valueOfTok(code, "f");
+
+ code = "struct T {\n"
+ " T();\n"
+ " static T a[6][64];\n"
+ " static T b[2][64];\n"
+ " static T c[64][64];\n"
+ " static T d[2][64];\n"
+ " static T e[64];\n"
+ " static T f[64];\n"
+ "};\n";
+ valueOfTok(code, "(");
}
void valueFlowCrashConstructorInitialization() { // #9577