diff --git a/.github/workflows/CI-unixish-docker.yml b/.github/workflows/CI-unixish-docker.yml
index 118cb817f63..82439c9bbe4 100644
--- a/.github/workflows/CI-unixish-docker.yml
+++ b/.github/workflows/CI-unixish-docker.yml
@@ -53,8 +53,10 @@ jobs:
# needs to be called after the package installation since
# - it doesn't call "apt-get update"
# - it doesn't support centos
+ #
+ # needs to be to fixated on 1.2.11 so it works with older images - see https://github.com/hendrikmuhs/ccache-action/issues/178
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@v1.2.11
with:
key: ${{ github.workflow }}-${{ matrix.image }}
@@ -110,8 +112,10 @@ jobs:
# needs to be called after the package installation since
# - it doesn't call "apt-get update"
# - it doesn't support centos
+ #
+ # needs to be to fixated on 1.2.11 so it works with older images - see https://github.com/hendrikmuhs/ccache-action/issues/178
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@v1.2.11
with:
key: ${{ github.workflow }}-${{ matrix.image }}
diff --git a/cfg/windows.cfg b/cfg/windows.cfg
index ccf0a9d8f6d..eb9d382b1d5 100644
--- a/cfg/windows.cfg
+++ b/cfg/windows.cfg
@@ -17958,6 +17958,46 @@ HFONT CreateFont(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp
index c0010dbc79c..8f132c25967 100644
--- a/gui/resultstree.cpp
+++ b/gui/resultstree.cpp
@@ -421,7 +421,7 @@ void ResultsTree::loadSettings()
mSaveAllErrors = mSettings->value(SETTINGS_SAVE_ALL_ERRORS, false).toBool();
mShowFullPath = mSettings->value(SETTINGS_SHOW_FULL_PATH, false).toBool();
- showIdColumn(mSettings->value(SETTINGS_SHOW_ERROR_ID, false).toBool());
+ showIdColumn(mSettings->value(SETTINGS_SHOW_ERROR_ID, true).toBool());
showInconclusiveColumn(mSettings->value(SETTINGS_INCONCLUSIVE_ERRORS, false).toBool());
}
diff --git a/gui/settingsdialog.cpp b/gui/settingsdialog.cpp
index 7144f3793d1..f6a4b3ab22d 100644
--- a/gui/settingsdialog.cpp
+++ b/gui/settingsdialog.cpp
@@ -73,7 +73,7 @@ SettingsDialog::SettingsDialog(ApplicationList *list,
mUI->mInlineSuppressions->setCheckState(boolToCheckState(settings.value(SETTINGS_INLINE_SUPPRESSIONS, false).toBool()));
mUI->mEnableInconclusive->setCheckState(boolToCheckState(settings.value(SETTINGS_INCONCLUSIVE_ERRORS, false).toBool()));
mUI->mShowStatistics->setCheckState(boolToCheckState(settings.value(SETTINGS_SHOW_STATISTICS, false).toBool()));
- mUI->mShowErrorId->setCheckState(boolToCheckState(settings.value(SETTINGS_SHOW_ERROR_ID, false).toBool()));
+ mUI->mShowErrorId->setCheckState(boolToCheckState(settings.value(SETTINGS_SHOW_ERROR_ID, true).toBool()));
mUI->mCheckForUpdates->setCheckState(boolToCheckState(settings.value(SETTINGS_CHECK_FOR_UPDATES, false).toBool()));
mUI->mEditPythonPath->setText(settings.value(SETTINGS_PYTHON_PATH, QString()).toString());
validateEditPythonPath();
diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp
index 2d700824109..5fa03316bf8 100644
--- a/lib/checkstl.cpp
+++ b/lib/checkstl.cpp
@@ -718,7 +718,7 @@ static bool isSameIteratorContainerExpression(const Token* tok1,
});
});
}
- return false;
+ return astContainerYield(tok2) == Library::Container::Yield::ITEM;
}
static ValueFlow::Value getLifetimeIteratorValue(const Token* tok, MathLib::bigint path = 0)
@@ -884,6 +884,8 @@ void CheckStl::mismatchingContainerIterator()
continue;
if (val.lifetimeKind != ValueFlow::Value::LifetimeKind::Iterator)
continue;
+ if (iterTok->str() == "*" && iterTok->astOperand1()->valueType() && iterTok->astOperand1()->valueType()->type == ValueType::ITERATOR)
+ continue;
if (isSameIteratorContainerExpression(tok, val.tokvalue, mSettings->library))
continue;
mismatchingContainerIteratorError(tok, iterTok, val.tokvalue);
diff --git a/lib/library.cpp b/lib/library.cpp
index 3caf7e70a69..96df481171d 100644
--- a/lib/library.cpp
+++ b/lib/library.cpp
@@ -434,7 +434,9 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
const char* const startPattern = node->Attribute("startPattern");
if (startPattern) {
container.startPattern = startPattern;
- container.startPattern2 = container.startPattern + " !!::";
+ container.startPattern2 = startPattern;
+ if (!endsWith(container.startPattern, '<'))
+ container.startPattern2 += " !!::";
}
const char* const endPattern = node->Attribute("endPattern");
if (endPattern)
diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp
index 25238d797a1..a454d5c0951 100644
--- a/lib/symboldatabase.cpp
+++ b/lib/symboldatabase.cpp
@@ -2874,7 +2874,7 @@ bool Function::argsMatch(const Scope *scope, const Token *first, const Token *se
if (second)
second = second->tokAt(-2);
if (!second) { // End of argument list (second)
- return false;
+ return !first->nextArgument();
}
}
diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp
index 030b0699452..d3c6b8b2a6b 100644
--- a/lib/valueflow.cpp
+++ b/lib/valueflow.cpp
@@ -1105,6 +1105,53 @@ static void setTokenValueCast(Token *parent, const ValueType &valueType, const V
}
}
+template
+static size_t accumulateStructMembers(const Scope* scope, F f)
+{
+ size_t total = 0;
+ for (const Variable& var : scope->varlist) {
+ if (var.isStatic())
+ continue;
+ if (const ValueType* vt = var.valueType()) {
+ if (vt->type == ValueType::Type::RECORD && vt->typeScope == scope)
+ return 0;
+ total = f(total, *vt);
+ }
+ if (total == 0)
+ return 0;
+ }
+ return total;
+}
+
+static size_t bitCeil(size_t x)
+{
+ if (x <= 1)
+ return 1;
+ --x;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ x |= x >> 32;
+ return x + 1;
+}
+
+static size_t getAlignOf(const ValueType& vt, const Settings& settings)
+{
+ if (vt.pointer || vt.isPrimitive()) {
+ auto align = ValueFlow::getSizeOf(vt, settings);
+ return align == 0 ? 0 : bitCeil(align);
+ }
+ if (vt.type == ValueType::Type::RECORD && vt.typeScope) {
+ return accumulateStructMembers(vt.typeScope, [&](size_t max, const ValueType& vt2) {
+ size_t a = getAlignOf(vt2, settings);
+ return std::max(max, a);
+ });
+ }
+ return 0;
+}
+
static nonneg int getSizeOfType(const Token *typeTok, const Settings &settings)
{
const ValueType &valueType = ValueType::parseDecl(typeTok, settings);
@@ -1134,7 +1181,23 @@ size_t ValueFlow::getSizeOf(const ValueType &vt, const Settings &settings)
return settings.platform.sizeof_double;
if (vt.type == ValueType::Type::LONGDOUBLE)
return settings.platform.sizeof_long_double;
-
+ if (vt.type == ValueType::Type::RECORD && vt.typeScope) {
+ size_t total = accumulateStructMembers(vt.typeScope, [&](size_t total, const ValueType& vt2) -> size_t {
+ size_t n = ValueFlow::getSizeOf(vt2, settings);
+ size_t a = getAlignOf(vt2, settings);
+ if (n == 0 || a == 0)
+ return 0;
+ size_t padding = (a - (total % a)) % a;
+ return total + padding + n;
+ });
+ if (total == 0)
+ return 0;
+ size_t align = getAlignOf(vt, settings);
+ if (align == 0)
+ return 0;
+ total += (align - (total % align)) % align;
+ return total;
+ }
return 0;
}
diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp
index e05d43f6f92..4fab6bb6957 100644
--- a/test/cfg/std.cpp
+++ b/test/cfg/std.cpp
@@ -4925,6 +4925,13 @@ std::string global_scope_std() // #12355
return ss.str();
}
+::std::size_t global_scope_std2() // #12378
+{
+ std::vector<::std::size_t> v;
+ // cppcheck-suppress containerOutOfBounds
+ return v.front();
+}
+
void unique_lock_const_ref(std::mutex& m)
{
std::unique_lock lock(m);
diff --git a/test/testclass.cpp b/test/testclass.cpp
index 1de1e24bcef..5bf9597c40d 100644
--- a/test/testclass.cpp
+++ b/test/testclass.cpp
@@ -8530,6 +8530,16 @@ class TestClass : public TestFixture {
"};\n");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:8]: (style) The function 'operator->' overrides a function in a base class but is not marked with a 'override' specifier.\n",
errout.str());
+
+ checkOverride("class Base {\n" // #12131
+ " virtual int Calculate(int arg) = 0;\n"
+ "};\n"
+ "class Derived : public Base {\n"
+ " int Calculate(int arg = 0) {\n"
+ " return arg * 2;\n"
+ " }\n"
+ "};\n");
+ ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:5]: (style) The function 'Calculate' overrides a function in a base class but is not marked with a 'override' specifier.\n", errout.str());
}
void overrideCVRefQualifiers() {
diff --git a/test/teststl.cpp b/test/teststl.cpp
index f82e8de2833..a6ba7d900de 100644
--- a/test/teststl.cpp
+++ b/test/teststl.cpp
@@ -2180,6 +2180,32 @@ class TestStl : public TestFixture {
" }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
+
+ // #11067
+ check("struct S {\n"
+ " std::vector v;\n"
+ " std::list::const_iterator> li;\n"
+ " void f();\n"
+ "};\n"
+ "void S::f() {\n"
+ " v.erase(*li.begin());\n"
+ " li.pop_front();\n"
+ "}\n");
+ ASSERT_EQUALS("", errout.str());
+
+ check("void f(std::set& a, std::stack::iterator>& b) {\n"
+ " while (!b.empty()) {\n"
+ " a.erase(b.top());\n"
+ " b.pop();\n"
+ " }\n"
+ "}\n");
+ ASSERT_EQUALS("", errout.str());
+
+ check("void f(std::vector& a, std::vector::iterator>& b) {\n"
+ " auto it = b.begin();\n"
+ " a.erase(*it);\n"
+ "}\n");
+ ASSERT_EQUALS("", errout.str());
}
// Dereferencing invalid pointer
diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp
index 48b166972c5..f4a313171fe 100644
--- a/test/testsymboldatabase.cpp
+++ b/test/testsymboldatabase.cpp
@@ -8775,35 +8775,33 @@ class TestSymbolDatabase : public TestFixture {
}
{
// Container
- Settings sC;
- Library::Container c;
- c.startPattern = "C";
- c.startPattern2 = "C !!::";
- sC.library.containers["C"] = c;
+ constexpr char xmldata[] = "\n"
+ "\n"
+ " \n"
+ "";
+ const Settings sC = settingsBuilder().libraryxml(xmldata, sizeof(xmldata)).build();
ASSERT_EQUALS("container(C) *", typeOf("C*c=new C;","new","test.cpp",&sC));
ASSERT_EQUALS("container(C) *", typeOf("x=(C*)c;","(","test.cpp",&sC));
ASSERT_EQUALS("container(C)", typeOf("C c = C();","(","test.cpp",&sC));
}
{
// Container (vector)
- Settings set;
- Library::Container vector;
- vector.startPattern = "Vector <";
- vector.startPattern2 = "Vector !!::";
- vector.type_templateArgNo = 0;
- vector.arrayLike_indexOp = true;
- vector.functions["front"] =
- Library::Container::Function{Library::Container::Action::NO_ACTION, Library::Container::Yield::ITEM};
- vector.functions["data"] =
- Library::Container::Function{Library::Container::Action::NO_ACTION, Library::Container::Yield::BUFFER};
- vector.functions["begin"] = Library::Container::Function{Library::Container::Action::NO_ACTION,
- Library::Container::Yield::START_ITERATOR};
- set.library.containers["Vector"] = vector;
- Library::Container string;
- string.startPattern = "test :: string";
- string.startPattern2 = "test :: string !!::";
- string.arrayLike_indexOp = string.stdStringLike = true;
- set.library.containers["test::string"] = string;
+ constexpr char xmldata[] = "\n"
+ "\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "";
+ const Settings set = settingsBuilder().libraryxml(xmldata, sizeof(xmldata)).build();
ASSERT_EQUALS("signed int", typeOf("Vector v; v[0]=3;", "[", "test.cpp", &set));
ASSERT_EQUALS("container(test :: string)", typeOf("{return test::string();}", "(", "test.cpp", &set));
ASSERT_EQUALS(
@@ -8876,11 +8874,11 @@ class TestSymbolDatabase : public TestFixture {
// return
{
// Container
- Settings sC;
- Library::Container c;
- c.startPattern = "C";
- c.startPattern2 = "C !!::";
- sC.library.containers["C"] = c;
+ constexpr char xmldata[] = "\n"
+ "\n"
+ " \n"
+ "";
+ const Settings sC = settingsBuilder().libraryxml(xmldata, sizeof(xmldata)).build();
ASSERT_EQUALS("container(C)", typeOf("C f(char *p) { char data[10]; return data; }", "return", "test.cpp", &sC));
}
// Smart pointer
diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp
index bf97ca1ced3..7fb5e9c78a6 100644
--- a/test/testvalueflow.cpp
+++ b/test/testvalueflow.cpp
@@ -1394,6 +1394,63 @@ class TestValueFlow : public TestFixture {
values = tokenValues(code, "=");
ASSERT_EQUALS(1U, values.size());
ASSERT_EQUALS(sizeof(std::int32_t) * 10 * 20, values.back().intvalue);
+
+ code = "struct X { float a; float b; };\n"
+ "void f() {\n"
+ " x = sizeof(X);\n"
+ "}";
+ values = tokenValues(code, "( X )");
+ ASSERT_EQUALS(1U, values.size());
+ ASSERT_EQUALS(8, values.back().intvalue);
+
+ code = "struct X { char a; char b; };\n"
+ "void f() {\n"
+ " x = sizeof(X);\n"
+ "}";
+ values = tokenValues(code, "( X )");
+ ASSERT_EQUALS(1U, values.size());
+ ASSERT_EQUALS(2, values.back().intvalue);
+
+ code = "struct X { char a; float b; };\n"
+ "void f() {\n"
+ " x = sizeof(X);\n"
+ "}";
+ values = tokenValues(code, "( X )");
+ ASSERT_EQUALS(1U, values.size());
+ ASSERT_EQUALS(8, values.back().intvalue);
+
+ code = "struct X { char a; char b; float c; };\n"
+ "void f() {\n"
+ " x = sizeof(X);\n"
+ "}";
+ values = tokenValues(code, "( X )");
+ ASSERT_EQUALS(1U, values.size());
+ ASSERT_EQUALS(8, values.back().intvalue);
+
+ code = "struct X { float a; char b; };\n"
+ "void f() {\n"
+ " x = sizeof(X);\n"
+ "}";
+ values = tokenValues(code, "( X )");
+ ASSERT_EQUALS(1U, values.size());
+ ASSERT_EQUALS(8, values.back().intvalue);
+
+ code = "struct X { float a; char b; char c; };\n"
+ "void f() {\n"
+ " x = sizeof(X);\n"
+ "}";
+ values = tokenValues(code, "( X )");
+ ASSERT_EQUALS(1U, values.size());
+ ASSERT_EQUALS(8, values.back().intvalue);
+
+ code = "struct A { float a; char b; };\n"
+ "struct X { A a; char b; };\n"
+ "void f() {\n"
+ " x = sizeof(X);\n"
+ "}";
+ values = tokenValues(code, "( X )");
+ ASSERT_EQUALS(1U, values.size());
+ ASSERT_EQUALS(12, values.back().intvalue);
}
void valueFlowComma()