Fix #10980 FN constVariable with range-based for loop (#4144)

* Fix #10980 FN constVariable with range-based for loop

* Format

* nullptr check

* Restrict scopes

* Add const

* Undo

* Add more const
This commit is contained in:
chrchr-github 2022-05-29 17:06:33 +02:00 committed by GitHub
parent e1c51940a2
commit 7fbb9c7c13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 54 additions and 26 deletions

View File

@ -915,14 +915,14 @@ static bool hasUnknownVars(const Token* startTok)
return result; return result;
} }
static bool isStructuredBindingVariable(const Variable* var) bool isStructuredBindingVariable(const Variable* var)
{ {
if (!var) if (!var)
return false; return false;
const Token* tok = var->nameToken(); const Token* tok = var->nameToken();
while (Token::Match(tok->astParent(), "[|,")) while (tok && Token::Match(tok->astParent(), "[|,|:"))
tok = tok->astParent(); tok = tok->astParent();
return Token::simpleMatch(tok, "["); return tok && (tok->str() == "[" || Token::simpleMatch(tok->previous(), "] :")); // TODO: remove workaround when #11105 is fixed
} }
/// This takes a token that refers to a variable and it will return the token /// This takes a token that refers to a variable and it will return the token

View File

@ -205,6 +205,8 @@ bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2
bool isEqualKnownValue(const Token * const tok1, const Token * const tok2); bool isEqualKnownValue(const Token * const tok1, const Token * const tok2);
bool isStructuredBindingVariable(const Variable* var);
/** /**
* Is token used a boolean, that is to say cast to a bool, or used as a condition in a if/while/for * Is token used a boolean, that is to say cast to a bool, or used as a condition in a if/while/for
*/ */

View File

@ -1407,13 +1407,13 @@ void CheckOther::checkConstVariable()
continue; continue;
if (var->isConst()) if (var->isConst())
continue; continue;
if (!var->scope()) const Scope* scope = var->scope();
if (!scope)
continue; continue;
const Scope *scope = var->scope(); const Function* function = scope->function;
if (!scope->function) if (!function && !scope->isLocal())
continue; continue;
const Function *function = scope->function; if (function && var->isArgument()) {
if (var->isArgument()) {
if (function->isImplicitlyVirtual() || function->templateDef) if (function->isImplicitlyVirtual() || function->templateDef)
continue; continue;
if (isUnusedVariable(var)) if (isUnusedVariable(var))
@ -1433,9 +1433,18 @@ void CheckOther::checkConstVariable()
continue; continue;
if (isAliased(var)) if (isAliased(var))
continue; continue;
if (isStructuredBindingVariable(var)) // TODO: check all bound variables
continue;
if (isVariableChanged(var, mSettings, mTokenizer->isCPP())) if (isVariableChanged(var, mSettings, mTokenizer->isCPP()))
continue; continue;
if (Function::returnsReference(function) && !Function::returnsConst(function)) { const bool hasFunction = function != nullptr;
if (!hasFunction) {
const Scope* functionScope = scope;
do {
functionScope = functionScope->nestedIn;
} while (functionScope && !(function = functionScope->function));
}
if (function && Function::returnsReference(function) && !Function::returnsConst(function)) {
std::vector<const Token*> returns = Function::findReturns(function); std::vector<const Token*> returns = Function::findReturns(function);
if (std::any_of(returns.begin(), returns.end(), [&](const Token* retTok) { if (std::any_of(returns.begin(), returns.end(), [&](const Token* retTok) {
if (retTok->varId() == var->declarationId()) if (retTok->varId() == var->declarationId())
@ -1531,7 +1540,7 @@ void CheckOther::checkConstVariable()
continue; continue;
} }
constVariableError(var, function); constVariableError(var, hasFunction ? function : nullptr);
} }
} }

View File

@ -1519,7 +1519,7 @@ static void setValues(Tokenizer *tokenizer, SymbolDatabase *symbolDatabase)
{ {
const Settings * const settings = tokenizer->getSettings(); const Settings * const settings = tokenizer->getSettings();
for (Scope &scope: symbolDatabase->scopeList) { for (const Scope& scope : symbolDatabase->scopeList) {
if (!scope.definedType) if (!scope.definedType)
continue; continue;

View File

@ -71,7 +71,7 @@ Preprocessor::Preprocessor(Settings& settings, ErrorLogger *errorLogger) : mSett
Preprocessor::~Preprocessor() Preprocessor::~Preprocessor()
{ {
for (std::pair<const std::string, simplecpp::TokenList *>& tokenList : mTokenLists) for (const std::pair<const std::string, simplecpp::TokenList*>& tokenList : mTokenLists)
delete tokenList.second; delete tokenList.second;
} }
@ -1043,10 +1043,10 @@ unsigned int Preprocessor::calculateChecksum(const simplecpp::TokenList &tokens1
return crc32(ostr.str()); return crc32(ostr.str());
} }
void Preprocessor::simplifyPragmaAsm(simplecpp::TokenList *tokenList) void Preprocessor::simplifyPragmaAsm(simplecpp::TokenList *tokenList) const
{ {
Preprocessor::simplifyPragmaAsmPrivate(tokenList); Preprocessor::simplifyPragmaAsmPrivate(tokenList);
for (std::pair<const std::string, simplecpp::TokenList *>& list : mTokenLists) { for (const std::pair<const std::string, simplecpp::TokenList*>& list : mTokenLists) {
Preprocessor::simplifyPragmaAsmPrivate(list.second); Preprocessor::simplifyPragmaAsmPrivate(list.second);
} }
} }

View File

@ -172,7 +172,7 @@ public:
*/ */
unsigned int calculateChecksum(const simplecpp::TokenList &tokens1, const std::string &toolinfo) const; unsigned int calculateChecksum(const simplecpp::TokenList &tokens1, const std::string &toolinfo) const;
void simplifyPragmaAsm(simplecpp::TokenList *tokenList); void simplifyPragmaAsm(simplecpp::TokenList *tokenList) const;
private: private:

View File

@ -863,7 +863,7 @@ void SymbolDatabase::createSymbolDatabaseNeedInitialization()
{ {
if (mTokenizer->isC()) { if (mTokenizer->isC()) {
// For C code it is easy, as there are no constructors and no default values // For C code it is easy, as there are no constructors and no default values
for (Scope& scope : scopeList) { for (const Scope& scope : scopeList) {
if (scope.definedType) if (scope.definedType)
scope.definedType->needInitialization = Type::NeedInitialization::True; scope.definedType->needInitialization = Type::NeedInitialization::True;
} }
@ -888,7 +888,7 @@ void SymbolDatabase::createSymbolDatabaseNeedInitialization()
// check for default constructor // check for default constructor
bool hasDefaultConstructor = false; bool hasDefaultConstructor = false;
for (Function& func: scope.functionList) { for (const Function& func : scope.functionList) {
if (func.type == Function::eConstructor) { if (func.type == Function::eConstructor) {
// check for no arguments: func ( ) // check for no arguments: func ( )
if (func.argCount() == 0) { if (func.argCount() == 0) {
@ -1452,7 +1452,7 @@ void SymbolDatabase::createSymbolDatabaseIncompleteVars()
void SymbolDatabase::createSymbolDatabaseEscapeFunctions() void SymbolDatabase::createSymbolDatabaseEscapeFunctions()
{ {
for (Scope & scope : scopeList) { for (const Scope& scope : scopeList) {
if (scope.type != Scope::eFunction) if (scope.type != Scope::eFunction)
continue; continue;
Function * function = scope.function; Function * function = scope.function;

View File

@ -3374,10 +3374,10 @@ static bool specMatch(
void TemplateSimplifier::getSpecializations() void TemplateSimplifier::getSpecializations()
{ {
// try to locate a matching declaration for each user defined specialization // try to locate a matching declaration for each user defined specialization
for (auto & spec : mTemplateDeclarations) { for (const auto& spec : mTemplateDeclarations) {
if (spec.isSpecialization()) { if (spec.isSpecialization()) {
bool found = false; bool found = false;
for (auto & decl : mTemplateDeclarations) { for (const auto& decl : mTemplateDeclarations) {
if (specMatch(spec, decl)) { if (specMatch(spec, decl)) {
mTemplateSpecializationMap[spec.token()] = decl.token(); mTemplateSpecializationMap[spec.token()] = decl.token();
found = true; found = true;
@ -3386,7 +3386,7 @@ void TemplateSimplifier::getSpecializations()
} }
if (!found) { if (!found) {
for (auto & decl : mTemplateForwardDeclarations) { for (const auto& decl : mTemplateForwardDeclarations) {
if (specMatch(spec, decl)) { if (specMatch(spec, decl)) {
mTemplateSpecializationMap[spec.token()] = decl.token(); mTemplateSpecializationMap[spec.token()] = decl.token();
break; break;
@ -3400,10 +3400,10 @@ void TemplateSimplifier::getSpecializations()
void TemplateSimplifier::getPartialSpecializations() void TemplateSimplifier::getPartialSpecializations()
{ {
// try to locate a matching declaration for each user defined partial specialization // try to locate a matching declaration for each user defined partial specialization
for (auto & spec : mTemplateDeclarations) { for (const auto& spec : mTemplateDeclarations) {
if (spec.isPartialSpecialization()) { if (spec.isPartialSpecialization()) {
bool found = false; bool found = false;
for (auto & decl : mTemplateDeclarations) { for (const auto& decl : mTemplateDeclarations) {
if (specMatch(spec, decl)) { if (specMatch(spec, decl)) {
mTemplatePartialSpecializationMap[spec.token()] = decl.token(); mTemplatePartialSpecializationMap[spec.token()] = decl.token();
found = true; found = true;
@ -3412,7 +3412,7 @@ void TemplateSimplifier::getPartialSpecializations()
} }
if (!found) { if (!found) {
for (auto & decl : mTemplateForwardDeclarations) { for (const auto& decl : mTemplateForwardDeclarations) {
if (specMatch(spec, decl)) { if (specMatch(spec, decl)) {
mTemplatePartialSpecializationMap[spec.token()] = decl.token(); mTemplatePartialSpecializationMap[spec.token()] = decl.token();
break; break;
@ -3841,7 +3841,7 @@ void TemplateSimplifier::simplifyTemplates(
} }
// remove explicit instantiations // remove explicit instantiations
for (TokenAndName & j : mExplicitInstantiationsToDelete) { for (const TokenAndName& j : mExplicitInstantiationsToDelete) {
Token * start = j.token(); Token * start = j.token();
if (start) { if (start) {
Token * end = start->next(); Token * end = start->next();

View File

@ -2181,7 +2181,24 @@ private:
check("void f(std::vector<int>& v) {\n" check("void f(std::vector<int>& v) {\n"
" for(auto& x:v) {}\n" " for(auto& x:v) {}\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared as reference to const\n", errout.str()); ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared as reference to const\n"
"[test.cpp:2]: (style) Variable 'x' can be declared as reference to const\n",
errout.str());
check("void f(std::vector<int>& v) {\n" // #10980
" for (int& i : v)\n"
" if (i == 0) {}\n"
" for (const int& i : v)\n"
" if (i == 0) {}\n"
" for (auto& i : v)\n"
" if (i == 0) {}\n"
" for (const auto& i : v)\n"
" if (i == 0) {}\n"
" v.clear();\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' can be declared as reference to const\n"
"[test.cpp:6]: (style) Variable 'i' can be declared as reference to const\n",
errout.str());
check("void f(std::vector<int>& v) {\n" check("void f(std::vector<int>& v) {\n"
" for(const auto& x:v) {}\n" " for(const auto& x:v) {}\n"