Skip to content

Commit 7729394

Browse files
committed
Remove inconclusive warnings about reading empty stl container. We have better ValueFlow-based checking.
1 parent b3f12fc commit 7729394

3 files changed

Lines changed: 0 additions & 349 deletions

File tree

lib/checkstl.cpp

Lines changed: 0 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,126 +1706,6 @@ void CheckStl::dereferenceInvalidIteratorError(const Token* deref, const std::st
17061706
}
17071707

17081708

1709-
1710-
void CheckStl::readingEmptyStlContainer_parseUsage(const Token* tok, const Library::Container* container, std::map<unsigned int, const Library::Container*>& empty, bool noerror)
1711-
{
1712-
// Check for various conditions for the way stl containers and variables can be used
1713-
if (tok->strAt(1) == "=" || (tok->strAt(1) == "[" && Token::simpleMatch(tok->linkAt(1), "] ="))) {
1714-
// Assignment (LHS)
1715-
empty.erase(tok->varId());
1716-
} else if (Token::Match(tok, "%name% [")) {
1717-
// Access through operator[]
1718-
if (!container->arrayLike_indexOp) { // operator[] inserts an element if used on a std::map
1719-
if (!noerror && tok->strAt(-1) == "=")
1720-
readingEmptyStlContainerError(tok);
1721-
empty.erase(tok->varId());
1722-
} else if (!noerror)
1723-
readingEmptyStlContainerError(tok);
1724-
} else if (Token::Match(tok, "%name% . %type% (")) {
1725-
// Member function call
1726-
const Library::Container::Action action = container->getAction(tok->strAt(2));
1727-
if ((action == Library::Container::FIND || action == Library::Container::ERASE || action == Library::Container::POP || action == Library::Container::CLEAR) && !noerror) {
1728-
readingEmptyStlContainerError(tok);
1729-
return;
1730-
}
1731-
1732-
const Token* parent = tok->tokAt(3)->astParent();
1733-
const Library::Container::Yield yield = container->getYield(tok->strAt(2));
1734-
const bool yieldsIterator = (yield == Library::Container::ITERATOR || yield == Library::Container::START_ITERATOR || yield == Library::Container::END_ITERATOR);
1735-
if (yield != Library::Container::NO_YIELD &&
1736-
(!parent || Token::Match(parent, "%cop%|*") || parent->isAssignmentOp() || !yieldsIterator)) { // These functions read from the container
1737-
if (!noerror && (!yieldsIterator || !parent || !parent->isAssignmentOp()))
1738-
readingEmptyStlContainerError(tok);
1739-
} else
1740-
empty.erase(tok->varId());
1741-
} else if (tok->strAt(-1) == "=") {
1742-
// Assignment (RHS)
1743-
if (!noerror)
1744-
readingEmptyStlContainerError(tok);
1745-
} else {
1746-
// Unknown usage. Assume it is initialized.
1747-
empty.erase(tok->varId());
1748-
}
1749-
}
1750-
1751-
void CheckStl::readingEmptyStlContainer()
1752-
{
1753-
if (!mSettings->isEnabled(Settings::STYLE))
1754-
return;
1755-
1756-
if (!mSettings->inconclusive)
1757-
return;
1758-
1759-
std::map<unsigned int, const Library::Container*> emptyContainer;
1760-
1761-
for (const Scope &scope : mTokenizer->getSymbolDatabase()->scopeList) {
1762-
if (scope.type != Scope::eFunction)
1763-
continue;
1764-
1765-
for (const Token *tok = scope.bodyStart->next(); tok != scope.bodyEnd; tok = tok->next()) {
1766-
if (Token::Match(tok, "for|while")) { // Loops and end of scope clear the sets.
1767-
const Token* tok2 = tok->linkAt(1);
1768-
if (!tok2)
1769-
continue;
1770-
tok2 = tok2->next();
1771-
for (const Token* end2 = tok2->link(); tok2 && tok2 != end2; tok2 = tok2->next()) {
1772-
if (!tok2->varId())
1773-
continue;
1774-
1775-
const std::map<unsigned int, const Library::Container*>::const_iterator container = emptyContainer.find(tok2->varId());
1776-
if (container == emptyContainer.end())
1777-
continue;
1778-
1779-
readingEmptyStlContainer_parseUsage(tok2, container->second, emptyContainer, true);
1780-
}
1781-
} else if (Token::Match(tok, "do|}|break|case")) {
1782-
emptyContainer.clear();
1783-
} else if (tok->str() == "{" && tok->next()->scope()->type == Scope::eLambda)
1784-
tok = tok->link();
1785-
1786-
// function call
1787-
if (Token::Match(tok, "!!. %name% (") && !Token::simpleMatch(tok->linkAt(2), ") {")) {
1788-
for (std::map<unsigned int, const Library::Container*>::iterator it = emptyContainer.begin(); it != emptyContainer.end();) {
1789-
const Variable *var = mTokenizer->getSymbolDatabase()->getVariableFromVarId(it->first);
1790-
if (var && (var->isLocal() || var->isArgument()))
1791-
++it;
1792-
else
1793-
emptyContainer.erase(it++);
1794-
}
1795-
}
1796-
1797-
if (!tok->varId())
1798-
continue;
1799-
1800-
// Check whether a variable should be marked as "empty"
1801-
const Variable* var = tok->variable();
1802-
if (var && !var->isArrayOrPointer() && !var->typeStartToken()->isStandardType()) {
1803-
bool insert = false;
1804-
if (var->nameToken() == tok && var->isLocal() && !var->isStatic()) { // Local variable declared
1805-
insert = !Token::Match(tok->next(), "[(=:]"); // Only if not initialized
1806-
} else if (Token::Match(tok, "%var% . clear ( ) ;")) {
1807-
insert = true;
1808-
}
1809-
1810-
if (insert) {
1811-
const Library::Container* container = mSettings->library.detectContainer(var->typeStartToken());
1812-
if (container)
1813-
emptyContainer[var->declarationId()] = container;
1814-
continue;
1815-
}
1816-
}
1817-
1818-
const std::map<unsigned int, const Library::Container*>::const_iterator container = emptyContainer.find(tok->varId());
1819-
if (container == emptyContainer.end())
1820-
continue;
1821-
1822-
readingEmptyStlContainer_parseUsage(tok, container->second, emptyContainer, false);
1823-
}
1824-
emptyContainer.clear();
1825-
}
1826-
}
1827-
1828-
18291709
void CheckStl::readingEmptyStlContainer2()
18301710
{
18311711
for (const Scope *function : mTokenizer->getSymbolDatabase()->functionScopes) {

lib/checkstl.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ class CPPCHECKLIB CheckStl : public Check {
8888
checkStl.size();
8989
checkStl.redundantCondition();
9090
checkStl.missingComparison();
91-
checkStl.readingEmptyStlContainer();
9291
}
9392

9493
/** Accessing container out of bounds using ValueFlow */
@@ -178,15 +177,9 @@ class CPPCHECKLIB CheckStl : public Check {
178177
*/
179178
void dereferenceErasedError(const Token* erased, const Token* deref, const std::string& itername, bool inconclusive);
180179

181-
/** @brief Reading from empty stl container */
182-
void readingEmptyStlContainer();
183-
184-
185180
/** @brief Reading from empty stl container (using valueflow) */
186181
void readingEmptyStlContainer2();
187182
private:
188-
void readingEmptyStlContainer_parseUsage(const Token* tok, const Library::Container* container, std::map<unsigned int, const Library::Container*>& empty, bool noerror);
189-
190183
void missingComparisonError(const Token* incrementToken1, const Token* incrementToken2);
191184
void string_c_strThrowError(const Token* tok);
192185
void string_c_strError(const Token* tok);

test/teststl.cpp

Lines changed: 0 additions & 222 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,6 @@ class TestStl : public TestFixture {
144144
TEST_CASE(dereferenceInvalidIterator);
145145
TEST_CASE(dereferenceInvalidIterator2); // #6572
146146
TEST_CASE(dereference_auto);
147-
148-
TEST_CASE(readingEmptyStlContainer);
149147
}
150148

151149
void check(const char code[], const bool inconclusive=false, const Standards::cppstd_t cppstandard=Standards::CPP11) {
@@ -3151,226 +3149,6 @@ class TestStl : public TestFixture {
31513149
"}\n");
31523150
ASSERT_EQUALS("[test.cpp:18]: (error, inconclusive) Invalid iterator 'it' used.\n", errout.str());
31533151
}
3154-
3155-
void readingEmptyStlContainer() {
3156-
check("void f() {\n"
3157-
" std::map<int, std::string> CMap;\n"
3158-
" std::string strValue = CMap[1]; \n"
3159-
" std::cout << strValue << CMap.size() << std::endl;\n"
3160-
"}\n",true);
3161-
ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Reading from empty STL container 'CMap'\n", errout.str());
3162-
3163-
check("void f() {\n"
3164-
" std::map<int,std::string> CMap;\n"
3165-
" std::string strValue = CMap[1];"
3166-
"}\n",true);
3167-
ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Reading from empty STL container 'CMap'\n", errout.str());
3168-
3169-
check("void f() {\n"
3170-
" std::map<int,std::string> CMap;\n"
3171-
" CMap[1] = \"123\";\n"
3172-
" std::string strValue = CMap[1];"
3173-
"}\n",true);
3174-
ASSERT_EQUALS("", errout.str());
3175-
3176-
check("std::vector<std::string> f() {\n"
3177-
" try {\n"
3178-
" std::vector<std::string> Vector;\n"
3179-
" std::vector<std::string> v2 = Vector;\n"
3180-
" std::string strValue = v2[1]; \n" // Do not complain here - this is a consecutive fault of the line above.
3181-
" }\n"
3182-
" return Vector;\n"
3183-
"}\n",true);
3184-
ASSERT_EQUALS("[test.cpp:4]: (style, inconclusive) Reading from empty STL container 'Vector'\n", errout.str());
3185-
3186-
check("Vector f() {\n"
3187-
" try {\n"
3188-
" std::vector<std::string> Vector;\n"
3189-
" Vector.push_back(\"123\");\n"
3190-
" std::vector<std::string> v2 = Vector;\n"
3191-
" std::string strValue = v2[0]; \n"
3192-
" }\n"
3193-
" return Vector;\n"
3194-
"}\n", true);
3195-
ASSERT_EQUALS("", errout.str());
3196-
3197-
check("void f() {\n"
3198-
" std::map<std::string,std::string> mymap;\n"
3199-
" mymap[\"Bakery\"] = \"Barbara\";\n"
3200-
" std:string bakery_name = mymap[\"Bakery\"];\n"
3201-
"}\n", true);
3202-
ASSERT_EQUALS("", errout.str());
3203-
3204-
check("void f() {\n"
3205-
" std::vector<int> v;\n"
3206-
" v.insert(1);\n"
3207-
" int i = v[0];\n"
3208-
"}\n", true);
3209-
ASSERT_EQUALS("", errout.str());
3210-
3211-
check("void f() {\n"
3212-
" std::vector<int> v;\n"
3213-
" initialize(v);\n"
3214-
" int i = v[0];\n"
3215-
"}", true);
3216-
ASSERT_EQUALS("", errout.str());
3217-
3218-
check("char f() {\n"
3219-
" std::string s(foo);\n"
3220-
" return s[0];\n"
3221-
"}", true);
3222-
ASSERT_EQUALS("", errout.str());
3223-
3224-
check("void f() {\n"
3225-
" std::vector<int> v = foo();\n"
3226-
" if(bar) v.clear();\n"
3227-
" int i = v.find(foobar);\n"
3228-
"}", true);
3229-
ASSERT_EQUALS("", errout.str());
3230-
3231-
check("void f(std::set<int> v) {\n"
3232-
" v.clear();\n"
3233-
" int i = v.find(foobar);\n"
3234-
"}", true);
3235-
ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Reading from empty STL container 'v'\n", errout.str());
3236-
3237-
check("void f(std::set<int> v) {\n"
3238-
" v.clear();\n"
3239-
" v.begin();\n"
3240-
"}", true);
3241-
ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Reading from empty STL container 'v'\n", errout.str());
3242-
3243-
check("void f(std::set<int> v) {\n"
3244-
" v.clear();\n"
3245-
" *v.begin();\n"
3246-
"}", true);
3247-
ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Reading from empty STL container 'v'\n", errout.str());
3248-
3249-
check("void f(std::set<int> v) {\n"
3250-
" v.clear();\n"
3251-
" for(auto i = v.cbegin();\n"
3252-
" i != v.cend(); ++i) {}\n"
3253-
"}", true);
3254-
ASSERT_EQUALS("[test.cpp:4]: (style, inconclusive) Reading from empty STL container 'v'\n", errout.str());
3255-
3256-
check("void f(std::set<int> v) {\n"
3257-
" v.clear();\n"
3258-
" foo(v.begin());\n"
3259-
"}", true);
3260-
ASSERT_EQUALS("", errout.str());
3261-
3262-
check("void f() {\n"
3263-
" std::map<int, std::string> CMap;\n"
3264-
" std::string strValue = CMap[1];\n"
3265-
" std::string strValue2 = CMap[1];\n"
3266-
"}\n", true);
3267-
ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Reading from empty STL container 'CMap'\n", errout.str());
3268-
3269-
// #4306
3270-
check("void f(std::vector<int> v) {\n"
3271-
" v.clear();\n"
3272-
" for(int i = 0; i < v.size(); i++) { cout << v[i]; }\n"
3273-
"}", true);
3274-
ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Reading from empty STL container 'v'\n", errout.str());
3275-
3276-
// #7449 - nonlocal vector
3277-
check("std::vector<int> v;\n"
3278-
"void f() {\n"
3279-
" v.clear();\n"
3280-
" dostuff()\n"
3281-
" if (v.empty()) { }\n"
3282-
"}", true);
3283-
ASSERT_EQUALS("", errout.str());
3284-
3285-
check("std::vector<int> v;\n"
3286-
"void f() {\n"
3287-
" v.clear();\n"
3288-
" if (v.empty()) { }\n"
3289-
"}", true);
3290-
ASSERT_EQUALS("[test.cpp:4]: (style, inconclusive) Reading from empty STL container 'v'\n", errout.str());
3291-
3292-
// #6663
3293-
check("void foo() {\n"
3294-
" std::set<int> container;\n"
3295-
" while (container.size() < 5)\n"
3296-
" container.insert(22);\n"
3297-
"}", true);
3298-
ASSERT_EQUALS("", errout.str());
3299-
3300-
// #6679
3301-
check("class C {\n"
3302-
" C() {\n"
3303-
" switch (ret) {\n"
3304-
" case 1:\n"
3305-
" vec.clear();\n"
3306-
" break;\n"
3307-
" case 2:\n"
3308-
" if (vec.empty())\n"
3309-
" ;\n"
3310-
" break;\n"
3311-
" }\n"
3312-
" }\n"
3313-
" std::vector<int> vec;\n"
3314-
"};", true);
3315-
ASSERT_EQUALS("", errout.str());
3316-
3317-
check("class C {\n"
3318-
" C() {\n"
3319-
" switch (ret) {\n"
3320-
" case 1:\n"
3321-
" vec.clear();\n"
3322-
" case 2:\n"
3323-
" if (vec.empty())\n"
3324-
" ;\n"
3325-
" break;\n"
3326-
" }\n"
3327-
" }\n"
3328-
" std::vector<int> vec;\n"
3329-
"};", true);
3330-
ASSERT_EQUALS("", errout.str());
3331-
3332-
check("class C {\n"
3333-
" C() {\n"
3334-
" switch (ret) {\n"
3335-
" case 1:\n"
3336-
" vec.clear();\n"
3337-
" if (vec.empty())\n"
3338-
" ;\n"
3339-
" break;\n"
3340-
" }\n"
3341-
" }\n"
3342-
" std::vector<int> vec;\n"
3343-
"};", true);
3344-
ASSERT_EQUALS("[test.cpp:6]: (style, inconclusive) Reading from empty STL container 'vec'\n", errout.str());
3345-
3346-
// #7560
3347-
check("std::vector<int> test;\n"
3348-
"std::vector<int>::iterator it;\n"
3349-
"void Reset() {\n"
3350-
" test.clear();\n"
3351-
" it = test.end();\n"
3352-
"}");
3353-
ASSERT_EQUALS("", errout.str());
3354-
3355-
// #8055
3356-
check("int main() {\n"
3357-
" std::string str;\n"
3358-
" auto l = [&]() {\n"
3359-
" if (str[0] == 'A')\n"
3360-
" std::cout << \"!\";\n"
3361-
" }\n"
3362-
" str = \"A\";\n"
3363-
" l();\n"
3364-
"}");
3365-
ASSERT_EQUALS("", errout.str());
3366-
3367-
check("void f(const std::vector<std::string> &v) {\n"
3368-
" for (const std::string& s : v) {\n"
3369-
" if (s.find(x) != string::npos) {}\n"
3370-
" }\n"
3371-
"}", true);
3372-
ASSERT_EQUALS("", errout.str());
3373-
}
33743152
};
33753153

33763154
REGISTER_TEST(TestStl)

0 commit comments

Comments
 (0)