* Fix #11041 FN constVariable with array of pointers [regression] * Use std::vector for deterministic order of results, use helper variables
This commit is contained in:
parent
3b30cd7ea8
commit
aebc080c0f
|
@ -1540,45 +1540,47 @@ void CheckOther::checkConstPointer()
|
||||||
if (!mSettings->severity.isEnabled(Severity::style))
|
if (!mSettings->severity.isEnabled(Severity::style))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::set<const Variable *> pointers;
|
std::vector<const Variable*> pointers, nonConstPointers;
|
||||||
std::set<const Variable *> nonConstPointers;
|
|
||||||
for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
|
for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
|
||||||
if (!tok->variable())
|
const Variable* const var = tok->variable();
|
||||||
|
if (!var)
|
||||||
continue;
|
continue;
|
||||||
if (!tok->variable()->isLocal() && !tok->variable()->isArgument())
|
if (!var->isLocal() && !var->isArgument())
|
||||||
continue;
|
continue;
|
||||||
const Token* const nameTok = tok->variable()->nameToken();
|
const Token* const nameTok = var->nameToken();
|
||||||
// declarations of (static) pointers are (not) split up, array declarations are never split up
|
// declarations of (static) pointers are (not) split up, array declarations are never split up
|
||||||
if (tok == nameTok && (!tok->variable()->isStatic() || Token::simpleMatch(nameTok->next(), "[")) &&
|
if (tok == nameTok && (!var->isStatic() || Token::simpleMatch(nameTok->next(), "[")) &&
|
||||||
// range-based for loop
|
// range-based for loop
|
||||||
!(Token::simpleMatch(nameTok->astParent(), ":") && Token::simpleMatch(nameTok->astParent()->astParent(), "(")))
|
!(Token::simpleMatch(nameTok->astParent(), ":") && Token::simpleMatch(nameTok->astParent()->astParent(), "(")))
|
||||||
continue;
|
continue;
|
||||||
if (!tok->valueType())
|
const ValueType* const vt = tok->valueType();
|
||||||
|
if (!vt)
|
||||||
continue;
|
continue;
|
||||||
if (tok->valueType()->pointer != 1 || (tok->valueType()->constness & 1) || tok->valueType()->reference != Reference::None)
|
if (vt->pointer != 1 && !(vt->pointer == 2 && var->isArray()) || (vt->constness & 1) || vt->reference != Reference::None)
|
||||||
continue;
|
continue;
|
||||||
if (nonConstPointers.find(tok->variable()) != nonConstPointers.end())
|
if (std::find(nonConstPointers.begin(), nonConstPointers.end(), var) != nonConstPointers.end())
|
||||||
continue;
|
continue;
|
||||||
pointers.insert(tok->variable());
|
pointers.emplace_back(var);
|
||||||
const Token *parent = tok->astParent();
|
const Token* const parent = tok->astParent();
|
||||||
bool deref = false;
|
bool deref = false;
|
||||||
if (parent && parent->isUnaryOp("*"))
|
if (parent && parent->isUnaryOp("*"))
|
||||||
deref = true;
|
deref = true;
|
||||||
else if (Token::simpleMatch(parent, "[") && parent->astOperand1() == tok && parent->astOperand1() != nameTok)
|
else if (Token::simpleMatch(parent, "[") && parent->astOperand1() == tok && tok != nameTok)
|
||||||
deref = true;
|
deref = true;
|
||||||
if (deref) {
|
if (deref) {
|
||||||
if (Token::Match(parent->astParent(), "%cop%") && !parent->astParent()->isUnaryOp("&") && !parent->astParent()->isUnaryOp("*"))
|
const Token* const gparent = parent->astParent();
|
||||||
|
if (Token::Match(gparent, "%cop%") && !gparent->isUnaryOp("&") && !gparent->isUnaryOp("*"))
|
||||||
continue;
|
continue;
|
||||||
if (Token::simpleMatch(parent->astParent(), "return"))
|
if (Token::simpleMatch(gparent, "return"))
|
||||||
continue;
|
continue;
|
||||||
else if (Token::Match(parent->astParent(), "%assign%") && parent == parent->astParent()->astOperand2()) {
|
else if (Token::Match(gparent, "%assign%") && parent == gparent->astOperand2()) {
|
||||||
bool takingRef = false;
|
bool takingRef = false;
|
||||||
const Token *lhs = parent->astParent()->astOperand1();
|
const Token *lhs = gparent->astOperand1();
|
||||||
if (lhs && lhs->variable() && lhs->variable()->isReference() && lhs->variable()->nameToken() == lhs)
|
if (lhs && lhs->variable() && lhs->variable()->isReference() && lhs->variable()->nameToken() == lhs)
|
||||||
takingRef = true;
|
takingRef = true;
|
||||||
if (!takingRef)
|
if (!takingRef)
|
||||||
continue;
|
continue;
|
||||||
} else if (Token::simpleMatch(parent->astParent(), "[") && parent->astParent()->astOperand2() == parent)
|
} else if (Token::simpleMatch(gparent, "[") && gparent->astOperand2() == parent)
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
if (Token::Match(parent, "%oror%|%comp%|&&|?|!|-"))
|
if (Token::Match(parent, "%oror%|%comp%|&&|?|!|-"))
|
||||||
|
@ -1586,14 +1588,14 @@ void CheckOther::checkConstPointer()
|
||||||
else if (Token::simpleMatch(parent, "(") && Token::Match(parent->astOperand1(), "if|while"))
|
else if (Token::simpleMatch(parent, "(") && Token::Match(parent->astOperand1(), "if|while"))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
nonConstPointers.insert(tok->variable());
|
nonConstPointers.emplace_back(var);
|
||||||
}
|
}
|
||||||
for (const Variable *p: pointers) {
|
for (const Variable *p: pointers) {
|
||||||
if (p->isArgument()) {
|
if (p->isArgument()) {
|
||||||
if (!p->scope() || !p->scope()->function || p->scope()->function->isImplicitlyVirtual(true) || p->scope()->function->hasVirtualSpecifier())
|
if (!p->scope() || !p->scope()->function || p->scope()->function->isImplicitlyVirtual(true) || p->scope()->function->hasVirtualSpecifier())
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (nonConstPointers.find(p) == nonConstPointers.end()) {
|
if (std::find(nonConstPointers.begin(), nonConstPointers.end(), p) == nonConstPointers.end()) {
|
||||||
const Token *start = (p->isArgument()) ? p->scope()->bodyStart : p->nameToken()->next();
|
const Token *start = (p->isArgument()) ? p->scope()->bodyStart : p->nameToken()->next();
|
||||||
const int indirect = p->isArray() ? p->dimensions().size() : 1;
|
const int indirect = p->isArray() ? p->dimensions().size() : 1;
|
||||||
if (isVariableChanged(start, p->scope()->bodyEnd, indirect, p->declarationId(), false, mSettings, mTokenizer->isCPP()))
|
if (isVariableChanged(start, p->scope()->bodyEnd, indirect, p->declarationId(), false, mSettings, mTokenizer->isCPP()))
|
||||||
|
|
|
@ -3059,6 +3059,19 @@ private:
|
||||||
"};\n"
|
"};\n"
|
||||||
"S<int*> s;\n");
|
"S<int*> s;\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void f(int i) {\n"
|
||||||
|
" const char *tmp;\n"
|
||||||
|
" char* a[] = { \"a\", \"aa\" };\n"
|
||||||
|
" static char* b[] = { \"b\", \"bb\" };\n"
|
||||||
|
" tmp = a[i];\n"
|
||||||
|
" printf(\"%s\", tmp);\n"
|
||||||
|
" tmp = b[i];\n"
|
||||||
|
" printf(\"%s\", tmp);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' can be declared with const\n"
|
||||||
|
"[test.cpp:4]: (style) Variable 'b' can be declared with const\n",
|
||||||
|
errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void switchRedundantAssignmentTest() {
|
void switchRedundantAssignmentTest() {
|
||||||
|
@ -9213,7 +9226,7 @@ private:
|
||||||
" int local_argc = 0;\n"
|
" int local_argc = 0;\n"
|
||||||
" local_argv[local_argc++] = argv[0];\n"
|
" local_argv[local_argc++] = argv[0];\n"
|
||||||
"}\n", "test.c");
|
"}\n", "test.c");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("[test.c:1]: (style) Parameter 'argv' can be declared with const\n", errout.str());
|
||||||
|
|
||||||
check("void f() {\n"
|
check("void f() {\n"
|
||||||
" int x = 0;\n"
|
" int x = 0;\n"
|
||||||
|
|
Loading…
Reference in New Issue