Fix #11681 FN constParameterPointer with std::vector (#5000)

This commit is contained in:
chrchr-github 2023-05-04 11:10:58 +02:00 committed by GitHub
parent e6ae312a0b
commit 100d17df4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 119 additions and 45 deletions

View File

@ -9385,7 +9385,7 @@
<!-- virtual void wxPGSpinCtrlEditor::OnFocus (wxPGProperty *property, wxWindow *wnd) const-->
<!-- virtual void wxPGTextCtrlEditor::OnFocus (wxPGProperty *property, wxWindow *wnd) const-->
<!-- virtual void wxPGTextCtrlAndButtonEditor::OnFocus (wxPGProperty *property, wxWindow *wnd) const-->
<function name="wxPGSpinCtrlEditor::OnFocus,wxPGProperty::Hide,wxPGTextCtrlAndButtonEditor::OnFocus">
<function name="wxPGSpinCtrlEditor::OnFocus,wxPGTextCtrlAndButtonEditor::OnFocus">
<noreturn>false</noreturn>
<leak-ignore/>
<const/>

View File

@ -1565,17 +1565,29 @@ void CheckOther::checkConstPointer()
continue;
pointers.emplace_back(var);
const Token* const parent = tok->astParent();
bool deref = false;
enum Deref { NONE, DEREF, MEMBER } deref = NONE;
if (parent && parent->isUnaryOp("*"))
deref = true;
deref = DEREF;
else if (Token::simpleMatch(parent, "[") && parent->astOperand1() == tok && tok != nameTok)
deref = true;
deref = DEREF;
else if (Token::Match(parent, "%op%") && Token::simpleMatch(parent->astParent(), "."))
deref = true;
deref = DEREF;
else if (Token::simpleMatch(parent, "."))
deref = MEMBER;
else if (astIsRangeBasedForDecl(tok))
continue;
if (deref) {
if (deref != NONE) {
const Token* const gparent = parent->astParent();
if (deref == MEMBER) {
if (!gparent)
continue;
if (parent->astOperand2()) {
if (parent->astOperand2()->function() && parent->astOperand2()->function()->isConst())
continue;
if (mSettings->library.isFunctionConst(parent->astOperand2()))
continue;
}
}
if (Token::Match(gparent, "%cop%") && !gparent->isUnaryOp("&") && !gparent->isUnaryOp("*"))
continue;
int argn = -1;

View File

@ -1523,7 +1523,7 @@ static void setTypes(TokenList *tokenList)
}
}
static void setValues(Tokenizer *tokenizer, SymbolDatabase *symbolDatabase)
static void setValues(const Tokenizer *tokenizer, const SymbolDatabase *symbolDatabase)
{
const Settings * const settings = tokenizer->getSettings();

View File

@ -1805,7 +1805,7 @@ void CppCheck::analyseWholeProgram(const std::string &buildDir, const std::map<s
ctuFileInfo.loadFromXml(e);
continue;
}
for (Check *check : Check::instances()) {
for (const Check *check : Check::instances()) {
if (checkClassAttr == check->name())
fileInfoList.push_back(check->loadFileInfoFromXml(e));
}

View File

@ -1390,7 +1390,7 @@ static void createAstAtTokenInner(Token * const tok1, const Token *endToken, boo
}
}
static Token * findAstTop(Token *tok1, Token *tok2)
static Token * findAstTop(Token *tok1, const Token *tok2)
{
for (Token *tok = tok1; tok && (tok != tok2); tok = tok->next()) {
if (tok->astParent() || tok->astOperand1() || tok->astOperand2()) {

View File

@ -3966,7 +3966,7 @@ struct LifetimeStore {
}
}
static LifetimeStore fromFunctionArg(const Function * f, Token *tok, const Variable *var, TokenList *tokenlist, const Settings* settings, ErrorLogger *errorLogger) {
static LifetimeStore fromFunctionArg(const Function * f, const Token *tok, const Variable *var, TokenList *tokenlist, const Settings* settings, ErrorLogger *errorLogger) {
if (!var)
return LifetimeStore{};
if (!var->isArgument())
@ -5039,7 +5039,7 @@ static const Token * findEndOfFunctionCallForParameter(const Token * parameterTo
return nextAfterAstRightmostLeaf(parent);
}
static void valueFlowAfterMove(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings)
static void valueFlowAfterMove(TokenList* tokenlist, const SymbolDatabase* symboldatabase, const Settings* settings)
{
if (!tokenlist->isCPP() || settings->standards.cpp < Standards::CPP11)
return;
@ -5178,7 +5178,7 @@ static const Scope* getLoopScope(const Token* tok)
}
//
static void valueFlowConditionExpressions(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings &settings)
static void valueFlowConditionExpressions(TokenList *tokenlist, const SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings &settings)
{
for (const Scope * scope : symboldatabase->functionScopes) {
if (const Token* incompleteTok = findIncompleteVar(scope->bodyStart, scope->bodyEnd)) {
@ -5308,7 +5308,7 @@ static std::set<nonneg int> getVarIds(const Token* tok)
return result;
}
static void valueFlowSymbolic(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings)
static void valueFlowSymbolic(const TokenList* tokenlist, const SymbolDatabase* symboldatabase, const Settings* settings)
{
for (const Scope* scope : symboldatabase->functionScopes) {
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
@ -5401,7 +5401,7 @@ static const Token* isStrlenOf(const Token* tok, const Token* expr, int depth =
static ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, MathLib::bigint val);
static void valueFlowSymbolicOperators(SymbolDatabase* symboldatabase, const Settings* settings)
static void valueFlowSymbolicOperators(const SymbolDatabase* symboldatabase, const Settings* settings)
{
for (const Scope* scope : symboldatabase->functionScopes) {
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
@ -5512,7 +5512,7 @@ struct SymbolicInferModel : InferModel {
}
};
static void valueFlowSymbolicInfer(SymbolDatabase* symboldatabase, const Settings* settings)
static void valueFlowSymbolicInfer(const SymbolDatabase* symboldatabase, const Settings* settings)
{
for (const Scope* scope : symboldatabase->functionScopes) {
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
@ -5792,7 +5792,7 @@ static bool intersects(const C1& c1, const C2& c2)
}
static void valueFlowAfterAssign(TokenList *tokenlist,
SymbolDatabase* symboldatabase,
const SymbolDatabase* symboldatabase,
ErrorLogger *errorLogger,
const Settings *settings,
const std::set<const Scope*>& skippedFunctions)
@ -5925,7 +5925,7 @@ static std::vector<const Variable*> getVariables(const Token* tok)
}
static void valueFlowAfterSwap(TokenList* tokenlist,
SymbolDatabase* symboldatabase,
const SymbolDatabase* symboldatabase,
ErrorLogger* errorLogger,
const Settings* settings)
{
@ -6098,8 +6098,8 @@ struct ConditionHandler {
return valueFlowReverse(start, endToken, exprTok, values, tokenlist, settings, loc);
}
void traverseCondition(TokenList* tokenlist,
SymbolDatabase* symboldatabase,
void traverseCondition(const TokenList* tokenlist,
const SymbolDatabase* symboldatabase,
const Settings* settings,
const std::set<const Scope*>& skippedFunctions,
const std::function<void(const Condition& cond, Token* tok, const Scope* scope)>& f) const
@ -6137,7 +6137,7 @@ struct ConditionHandler {
}
void beforeCondition(TokenList* tokenlist,
SymbolDatabase* symboldatabase,
const SymbolDatabase* symboldatabase,
ErrorLogger* errorLogger,
const Settings* settings,
const std::set<const Scope*>& skippedFunctions) const {
@ -6285,7 +6285,7 @@ struct ConditionHandler {
}
void afterCondition(TokenList* tokenlist,
SymbolDatabase* symboldatabase,
const SymbolDatabase* symboldatabase,
ErrorLogger* errorLogger,
const Settings* settings,
const std::set<const Scope*>& skippedFunctions) const {
@ -7040,7 +7040,7 @@ static void valueFlowForLoopSimplifyAfter(Token* fortok, nonneg int varid, const
}
}
static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
static void valueFlowForLoop(TokenList *tokenlist, const SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
{
for (const Scope &scope : symboldatabase->scopeList) {
if (scope.type != Scope::eFor)
@ -7363,7 +7363,7 @@ static void valueFlowInjectParameter(const TokenList* tokenlist,
settings);
}
static void valueFlowSwitchVariable(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
static void valueFlowSwitchVariable(TokenList *tokenlist, const SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
{
for (const Scope &scope : symboldatabase->scopeList) {
if (scope.type != Scope::ScopeType::eSwitch)
@ -7581,7 +7581,7 @@ static void valueFlowSubFunction(TokenList* tokenlist, SymbolDatabase* symboldat
}
}
static void valueFlowFunctionDefaultParameter(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings)
static void valueFlowFunctionDefaultParameter(const TokenList* tokenlist, const SymbolDatabase* symboldatabase, const Settings* settings)
{
if (!tokenlist->isCPP())
return;
@ -8624,7 +8624,7 @@ static const Scope* getFunctionScope(const Scope* scope) {
}
static void valueFlowContainerSize(TokenList* tokenlist,
SymbolDatabase* symboldatabase,
const SymbolDatabase* symboldatabase,
ErrorLogger* /*errorLogger*/,
const Settings* settings,
const std::set<const Scope*>& skippedFunctions)
@ -8838,7 +8838,7 @@ struct ContainerConditionHandler : ConditionHandler {
}
};
static void valueFlowDynamicBufferSize(const TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings)
static void valueFlowDynamicBufferSize(const TokenList* tokenlist, const SymbolDatabase* symboldatabase, const Settings* settings)
{
auto getBufferSizeFromAllocFunc = [&](const Token* funcTok) -> MathLib::bigint {
MathLib::bigint sizeValue = -1;
@ -9010,7 +9010,7 @@ static bool getMinMaxValues(const std::string &typestr, const Settings *settings
return getMinMaxValues(&vt, settings->platform, minvalue, maxvalue);
}
static void valueFlowSafeFunctions(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings)
static void valueFlowSafeFunctions(TokenList* tokenlist, const SymbolDatabase* symboldatabase, const Settings* settings)
{
for (const Scope *functionScope : symboldatabase->functionScopes) {
if (!functionScope->bodyStart)

View File

@ -3585,6 +3585,38 @@ private:
ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:2]: (style) Parameter 'p' can be declared as pointer to const. "
"However it seems that 'cb' is a callback function, if 'p' is declared with const you might also need to cast function pointer(s).\n",
errout.str());
check("void f1(std::vector<int>* p) {\n" // #11681
" if (p->empty()) {}\n" // warn
"}\n"
"void f2(std::vector<int>* p) {\n"
" p->resize(0);\n"
"}\n"
"struct S {\n"
" void h1() const;\n"
" void h2();\n"
" int i;\n"
"};\n"
"void k(int&);\n"
"void g1(S* s) {\n"
" s->h1();\n" // warn
"}\n"
"void g1(S* s) {\n"
" s->h2();\n"
"}\n"
"void g1(S* s) {\n"
" if (s->i) {}\n" // warn
"}\n"
"void g2(S* s) {\n"
" s->i = 0;\n"
"}\n"
"void g3(S* s) {\n"
" k(s->i);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n"
"[test.cpp:13]: (style) Parameter 's' can be declared as pointer to const\n"
"[test.cpp:19]: (style) Parameter 's' can be declared as pointer to const\n",
errout.str());
}
void switchRedundantAssignmentTest() {
@ -7180,13 +7212,19 @@ private:
" int start = x->first;\n"
" int end = x->first;\n"
"}");
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3]: (style, inconclusive) Same expression used in consecutive assignments of 'start' and 'end'.\n", errout.str());
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3]: (style, inconclusive) Same expression used in consecutive assignments of 'start' and 'end'.\n"
"[test.cpp:2]: (style) Parameter 'x' can be declared as pointer to const\n",
errout.str());
check("struct SW { int first; };\n"
"void foo(SW* x, int i, int j) {\n"
" int start = x->first;\n"
" int end = x->first;\n"
"}");
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3]: (style, inconclusive) Same expression used in consecutive assignments of 'start' and 'end'.\n", errout.str());
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3]: (style, inconclusive) Same expression used in consecutive assignments of 'start' and 'end'.\n"
"[test.cpp:2]: (style) Parameter 'x' can be declared as pointer to const\n",
errout.str());
check("struct Foo { int f() const; };\n"
"void test() {\n"
" Foo f = Foo{};\n"
@ -7738,7 +7776,9 @@ private:
"void foo(S* first) {\n"
" if (first.ptr >= 0) {}\n"
"}");
ASSERT_EQUALS("[test.cpp:5]: (style) A pointer can not be negative so it is either pointless or an error to check if it is not.\n", errout.str());
ASSERT_EQUALS("[test.cpp:5]: (style) A pointer can not be negative so it is either pointless or an error to check if it is not.\n"
"[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n",
errout.str());
check("struct S {\n"
" int* ptr;\n"
@ -7746,7 +7786,9 @@ private:
"void foo(S* first, S* second) {\n"
" if((first.ptr - second.ptr) >= 0) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n"
"[test.cpp:4]: (style) Parameter 'second' can be declared as pointer to const\n",
errout.str());
check("struct S {\n"
" int* ptr;\n"
@ -7754,7 +7796,9 @@ private:
"void foo(S* first) {\n"
" if((first.ptr) >= 0) {}\n"
"}");
ASSERT_EQUALS("[test.cpp:5]: (style) A pointer can not be negative so it is either pointless or an error to check if it is not.\n", errout.str());
ASSERT_EQUALS("[test.cpp:5]: (style) A pointer can not be negative so it is either pointless or an error to check if it is not.\n"
"[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n",
errout.str());
check("struct S {\n"
" int* ptr;\n"
@ -7762,7 +7806,9 @@ private:
"void foo(S* first, S* second) {\n"
" if(0 <= first.ptr - second.ptr) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n"
"[test.cpp:4]: (style) Parameter 'second' can be declared as pointer to const\n",
errout.str());
check("struct S {\n"
" int* ptr;\n"
@ -7770,7 +7816,9 @@ private:
"void foo(S* first, S* second) {\n"
" if(0 <= (first.ptr - second.ptr)) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n"
"[test.cpp:4]: (style) Parameter 'second' can be declared as pointer to const\n",
errout.str());
check("struct S {\n"
" int* ptr;\n"
@ -7778,7 +7826,9 @@ private:
"void foo(S* first, S* second) {\n"
" if(first.ptr - second.ptr < 0) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n"
"[test.cpp:4]: (style) Parameter 'second' can be declared as pointer to const\n",
errout.str());
check("struct S {\n"
" int* ptr;\n"
@ -7786,7 +7836,9 @@ private:
"void foo(S* first, S* second) {\n"
" if((first.ptr - second.ptr) < 0) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n"
"[test.cpp:4]: (style) Parameter 'second' can be declared as pointer to const\n",
errout.str());
check("struct S {\n"
" int* ptr;\n"
@ -7794,7 +7846,9 @@ private:
"void foo(S* first, S* second) {\n"
" if(0 > first.ptr - second.ptr) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n"
"[test.cpp:4]: (style) Parameter 'second' can be declared as pointer to const\n",
errout.str());
check("struct S {\n"
" int* ptr;\n"
@ -7802,7 +7856,9 @@ private:
"void foo(S* first, S* second) {\n"
" if(0 > (first.ptr - second.ptr)) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n"
"[test.cpp:4]: (style) Parameter 'second' can be declared as pointer to const\n",
errout.str());
check("void foo(const int* x) {\n"
" if (0 <= x[0]) {}\n"
@ -7812,17 +7868,19 @@ private:
check("void foo(Bar* x) {\n"
" if (0 <= x.y) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared as pointer to const\n", errout.str());
check("void foo(Bar* x) {\n"
" if (0 <= x->y) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared as pointer to const\n", errout.str());
check("void foo(Bar* x, Bar* y) {\n"
" if (0 <= x->y - y->y ) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared as pointer to const\n"
"[test.cpp:1]: (style) Parameter 'y' can be declared as pointer to const\n",
errout.str());
check("void foo(const Bar* x) {\n"
" if (0 > x) {}\n"
@ -7837,12 +7895,12 @@ private:
check("void foo(Bar* x) {\n"
" if (0 > x.y) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared as pointer to const\n", errout.str());
check("void foo(Bar* x) {\n"
" if (0 > x->y) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared as pointer to const\n", errout.str());
check("void foo() {\n"
" int (*t)(void *a, void *b);\n"
@ -7860,13 +7918,17 @@ private:
"void packed_object_info(struct object_info *oi) {\n"
" if (oi->typep < 0);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (style) A pointer can not be negative so it is either pointless or an error to check if it is.\n", errout.str());
ASSERT_EQUALS("[test.cpp:3]: (style) A pointer can not be negative so it is either pointless or an error to check if it is.\n"
"[test.cpp:2]: (style) Parameter 'oi' can be declared as pointer to const\n",
errout.str());
check("struct object_info { int typep[10]; };\n"
"void packed_object_info(struct object_info *oi) {\n"
" if (oi->typep < 0);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (style) A pointer can not be negative so it is either pointless or an error to check if it is.\n", errout.str());
ASSERT_EQUALS("[test.cpp:3]: (style) A pointer can not be negative so it is either pointless or an error to check if it is.\n"
"[test.cpp:2]: (style) Parameter 'oi' can be declared as pointer to const\n",
errout.str());
check("struct object_info { int *typep; };\n"
"void packed_object_info(struct object_info *oi) {\n"