"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "lib/checkclass.cpp" between
cppcheck-1.86.tar.gz and cppcheck-1.87.tar.gz

About: Cppcheck is a static analysis tool for C/C++ code. It checks for memory leaks, mismatching allocation-deallocation, buffer overrun, and many more.

checkclass.cpp  (cppcheck-1.86):checkclass.cpp  (cppcheck-1.87)
/* /*
* Cppcheck - A tool for static C/C++ code analysis * Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2018 Cppcheck team. * Copyright (C) 2007-2019 Cppcheck team.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
skipping to change at line 112 skipping to change at line 112
usedInUnion = true; usedInUnion = true;
break; break;
} }
} }
} }
// There are no constructors. // There are no constructors.
if (scope->numConstructors == 0 && printStyle && !usedInUnion) { if (scope->numConstructors == 0 && printStyle && !usedInUnion) {
// If there is a private variable, there should be a constructor.. // If there is a private variable, there should be a constructor..
for (const Variable &var : scope->varlist) { for (const Variable &var : scope->varlist) {
const Token *initTok = var.nameToken();
while (Token::simpleMatch(initTok->next(), "["))
initTok = initTok->linkAt(1);
if (var.isPrivate() && !var.isStatic() && !Token::Match(var.name Token(), "%varid% ; %varid% =", var.declarationId()) && if (var.isPrivate() && !var.isStatic() && !Token::Match(var.name Token(), "%varid% ; %varid% =", var.declarationId()) &&
!Token::Match(initTok, "%var%|] {|=") &&
(!var.isClass() || (var.type() && var.type()->needInitializa tion == Type::True))) { (!var.isClass() || (var.type() && var.type()->needInitializa tion == Type::True))) {
noConstructorError(scope->classDef, scope->className, scope- >classDef->str() == "struct"); noConstructorError(scope->classDef, scope->className, scope- >classDef->str() == "struct");
break; break;
} }
} }
} }
if (!printWarnings) if (!printWarnings)
continue; continue;
skipping to change at line 600 skipping to change at line 604
int level = 0; int level = 0;
for (; ftok && ftok != func.functionScope->bodyEnd; ftok = ftok->next()) { for (; ftok && ftok != func.functionScope->bodyEnd; ftok = ftok->next()) {
// Class constructor.. initializing variables like this // Class constructor.. initializing variables like this
// clKalle::clKalle() : var(value) { } // clKalle::clKalle() : var(value) { }
if (initList) { if (initList) {
if (level == 0 && Token::Match(ftok, "%name% {|(") && Token::Match(f tok->linkAt(1), "}|) ,|{")) { if (level == 0 && Token::Match(ftok, "%name% {|(") && Token::Match(f tok->linkAt(1), "}|) ,|{")) {
if (ftok->str() != func.name()) { if (ftok->str() != func.name()) {
initVar(ftok->varId(), scope, usage); initVar(ftok->varId(), scope, usage);
} else { // c++11 delegate constructor } else { // c++11 delegate constructor
const Function *member = ftok->function(); const Function *member = ftok->function();
// member function found // member function not found => assume it initializes all me
if (member) { mbers
// recursive call if (!member) {
// assume that all variables are initialized assignAllVar(usage);
if (std::find(callstack.begin(), callstack.end(), member return;
) != callstack.end()) { }
/** @todo false negative: just bail */
assignAllVar(usage); // recursive call
return; // assume that all variables are initialized
} if (std::find(callstack.begin(), callstack.end(), member) !=
callstack.end()) {
// member function has implementation /** @todo false negative: just bail */
if (member->hasBody()) { assignAllVar(usage);
// initialize variable use list using member functio return;
n }
callstack.push_back(member);
initializeVarList(*member, callstack, scope, usage); // member function has implementation
callstack.pop_back(); if (member->hasBody()) {
} // initialize variable use list using member function
callstack.push_back(member);
// there is a called member function, but it has no impl initializeVarList(*member, callstack, scope, usage);
ementation, so we assume it initializes everything callstack.pop_back();
else { }
assignAllVar(usage);
} // there is a called member function, but it has no implemen
tation, so we assume it initializes everything
else {
assignAllVar(usage);
} }
} }
} else if (level != 0 && Token::Match(ftok, "%name% =")) // assignme nt in the initializer: var(value = x) } else if (level != 0 && Token::Match(ftok, "%name% =")) // assignme nt in the initializer: var(value = x)
assignVar(ftok->varId(), scope, usage); assignVar(ftok->varId(), scope, usage);
// Level handling // Level handling
if (ftok->link() && Token::Match(ftok, "(|<")) if (ftok->link() && Token::Match(ftok, "(|<"))
level++; level++;
else if (ftok->str() == "{") { else if (ftok->str() == "{") {
if (level != 0 || if (level != 0 ||
skipping to change at line 932 skipping to change at line 939
// Check every constructor // Check every constructor
if (!scope->function || (!scope->function->isConstructor())) if (!scope->function || (!scope->function->isConstructor()))
continue; continue;
const Scope* owner = scope->functionOf; const Scope* owner = scope->functionOf;
for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = t ok->next()) { for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = t ok->next()) {
if (Token::Match(tok, "%name% (")) // Assignments might depend on th is function call or if/for/while/switch statement from now on. if (Token::Match(tok, "%name% (")) // Assignments might depend on th is function call or if/for/while/switch statement from now on.
break; break;
if (Token::Match(tok, "try|do {")) if (Token::Match(tok, "try|do {"))
break; break;
if (Token::Match(tok, "%var% =") && tok->strAt(-1) != "*") { if (!Token::Match(tok, "%var% =") || tok->strAt(-1) == "*")
const Variable* var = tok->variable(); continue;
if (var && var->scope() == owner && !var->isStatic()) {
if (var->isPointer() || var->isReference() || var->isEnumTyp
e() || var->valueType()->type > ValueType::Type::ITERATOR)
continue;
bool allowed = true; const Variable* var = tok->variable();
for (const Token* tok2 = tok->tokAt(2); tok2 && tok2->str() if (!var || var->scope() != owner || var->isStatic())
!= ";"; tok2 = tok2->next()) { continue;
const Variable* var2 = tok2->variable(); if (var->isPointer() || var->isReference() || var->isEnumType() || v
if (var2) { ar->valueType()->type > ValueType::Type::ITERATOR)
if (var2->scope() == owner && tok2->strAt(-1)!=".") continue;
{ // Is there a dependency between two member variables?
allowed = false; // bailout: multi line lambda in rhs => do not warn
break; if (findLambdaEndToken(tok->tokAt(2)) && tok->tokAt(2)->findExpressi
} else if (var2->isArray() && var2->isLocal()) { // onStartEndTokens().second->linenr() > tok->tokAt(2)->linenr())
Can't initialize with a local array continue;
allowed = false;
break; // Access local var member in rhs => do not warn
} bool localmember = false;
} else if (tok2->str() == "this") { // 'this' instance i visitAstNodes(tok->next()->astOperand2(),
s not completely constructed in initialization list [&](const Token *rhs) {
allowed = false; if (rhs->str() == "." && rhs->astOperand1() && rhs->astOperand1(
break; )->variable() && rhs->astOperand1()->variable()->isLocal())
} else if (Token::Match(tok2, "%name% (") && tok2->strAt localmember = true;
(-1) != "." && isMemberFunc(owner, tok2)) { // Member function called? return ChildrenToVisit::op1_and_op2;
allowed = false; });
break; if (localmember)
} continue;
}
if (!allowed)
continue;
suggestInitializationList(tok, tok->str()); bool allowed = true;
visitAstNodes(tok->next()->astOperand2(),
[&](const Token *tok2) {
const Variable* var2 = tok2->variable();
if (var2) {
if (var2->scope() == owner && tok2->strAt(-1)!=".") { // Is
there a dependency between two member variables?
allowed = false;
return ChildrenToVisit::done;
} else if (var2->isArray() && var2->isLocal()) { // Can't in
itialize with a local array
allowed = false;
return ChildrenToVisit::done;
}
} else if (tok2->str() == "this") { // 'this' instance is not co
mpletely constructed in initialization list
allowed = false;
return ChildrenToVisit::done;
} else if (Token::Match(tok2, "%name% (") && tok2->strAt(-1) !=
"." && isMemberFunc(owner, tok2)) { // Member function called?
allowed = false;
return ChildrenToVisit::done;
} }
} return ChildrenToVisit::op1_and_op2;
});
if (!allowed)
continue;
suggestInitializationList(tok, tok->str());
} }
} }
} }
void CheckClass::suggestInitializationList(const Token* tok, const std::string& varname) void CheckClass::suggestInitializationList(const Token* tok, const std::string& varname)
{ {
reportError(tok, Severity::performance, "useInitializationList", "$symbol:" + varname + "\nVariable '$symbol' is assigned in constructor body. Consider perf orming initialization in initialization list.\n" reportError(tok, Severity::performance, "useInitializationList", "$symbol:" + varname + "\nVariable '$symbol' is assigned in constructor body. Consider perf orming initialization in initialization list.\n"
"When an object of a class is created, the constructors of all m ember variables are called consecutively " "When an object of a class is created, the constructors of all m ember variables are called consecutively "
"in the order the variables are declared, even if you don't expl icitly write them to the initialization list. You " "in the order the variables are declared, even if you don't expl icitly write them to the initialization list. You "
"could avoid assigning '$symbol' a value by passing the value to the constructor in the initialization list.", CWE398, false); "could avoid assigning '$symbol' a value by passing the value to the constructor in the initialization list.", CWE398, false);
skipping to change at line 1196 skipping to change at line 1221
for (std::size_t i = 0; i < type->definedType->derivedFrom.size(); i++) { for (std::size_t i = 0; i < type->definedType->derivedFrom.size(); i++) {
const Type* derivedFrom = type->definedType->derivedFrom[i].type; const Type* derivedFrom = type->definedType->derivedFrom[i].type;
if (derivedFrom && derivedFrom->classScope) if (derivedFrom && derivedFrom->classScope)
checkMemsetType(start, tok, derivedFrom->classScope, allocation, par sedTypes); checkMemsetType(start, tok, derivedFrom->classScope, allocation, par sedTypes);
} }
// Warn if type is a class that contains any virtual functions // Warn if type is a class that contains any virtual functions
for (const Function &func : type->functionList) { for (const Function &func : type->functionList) {
if (func.isVirtual()) { if (func.isVirtual()) {
if (allocation) if (allocation)
mallocOnClassError(tok, tok->str(), type->classDef, "virtual met hod"); mallocOnClassError(tok, tok->str(), type->classDef, "virtual fun ction");
else else
memsetError(tok, tok->str(), "virtual method", type->classDef->s tr()); memsetError(tok, tok->str(), "virtual function", type->classDef- >str());
} }
} }
// Warn if type is a class or struct that contains any std::* variables // Warn if type is a class or struct that contains any std::* variables
for (const Variable &var : type->varlist) { for (const Variable &var : type->varlist) {
if (var.isReference() && !var.isStatic()) { if (var.isReference() && !var.isStatic()) {
memsetErrorReference(tok, tok->str(), type->classDef->str()); memsetErrorReference(tok, tok->str(), type->classDef->str());
continue; continue;
} }
// don't warn if variable static or const, pointer or array of pointers // don't warn if variable static or const, pointer or array of pointers
skipping to change at line 1774 skipping to change at line 1799
return; return;
if (!mSettings->isEnabled(Settings::STYLE)) if (!mSettings->isEnabled(Settings::STYLE))
return; return;
for (const Scope * scope : mSymbolDatabase->classAndStructScopes) { for (const Scope * scope : mSymbolDatabase->classAndStructScopes) {
for (const Function &func : scope->functionList) { for (const Function &func : scope->functionList) {
// does the function have a body? // does the function have a body?
if (func.type != Function::eFunction || !func.hasBody()) if (func.type != Function::eFunction || !func.hasBody())
continue; continue;
// don't warn for friend/static/virtual methods // don't warn for friend/static/virtual functions
if (func.isFriend() || func.isStatic() || func.isVirtual()) if (func.isFriend() || func.isStatic() || func.isVirtual())
continue; continue;
// get last token of return type // get last token of return type
const Token *previous = func.tokenDef->previous(); const Token *previous = func.tokenDef->previous();
// does the function return a pointer or reference? // does the function return a pointer or reference?
if (Token::Match(previous, "*|&")) { if (Token::Match(previous, "*|&")) {
if (func.retDef->str() != "const") if (func.retDef->str() != "const")
continue; continue;
} else if (Token::Match(previous->previous(), "*|& >")) { } else if (Token::Match(previous->previous(), "*|& >")) {
skipping to change at line 2360 skipping to change at line 2385
const std::string &funcname) const std::string &funcname)
{ {
const char * scopeFunctionTypeName = scopeFunction ? getFunctionTypeName(sco peFunction->type) : "constructor"; const char * scopeFunctionTypeName = scopeFunction ? getFunctionTypeName(sco peFunction->type) : "constructor";
ErrorPath errorPath; ErrorPath errorPath;
int lineNumber = 1; int lineNumber = 1;
for (const Token *tok : tokStack) for (const Token *tok : tokStack)
errorPath.emplace_back(tok, "Calling " + tok->str()); errorPath.emplace_back(tok, "Calling " + tok->str());
if (!errorPath.empty()) { if (!errorPath.empty()) {
lineNumber = errorPath.front().first->linenr(); lineNumber = errorPath.front().first->linenr();
errorPath.back().second = funcname + " is a virtual method"; errorPath.back().second = funcname + " is a virtual function";
} }
std::string constructorName; std::string constructorName;
if (scopeFunction) { if (scopeFunction) {
const Token *endToken = scopeFunction->argDef->link()->next(); const Token *endToken = scopeFunction->argDef->link()->next();
if (scopeFunction->type == Function::Type::eDestructor) if (scopeFunction->type == Function::Type::eDestructor)
constructorName = "~"; constructorName = "~";
for (const Token *tok = scopeFunction->tokenDef; tok != endToken; tok = tok->next()) { for (const Token *tok = scopeFunction->tokenDef; tok != endToken; tok = tok->next()) {
if (!constructorName.empty() && Token::Match(tok->previous(), "%name %|%num% %name%|%num%")) if (!constructorName.empty() && Token::Match(tok->previous(), "%name %|%num% %name%|%num%"))
constructorName += ' '; constructorName += ' ';
skipping to change at line 2392 skipping to change at line 2417
const Function * scopeFunction, const Function * scopeFunction,
const std::list<const Token *> & tokStack, const std::list<const Token *> & tokStack,
const std::string &purefuncname) const std::string &purefuncname)
{ {
const char * scopeFunctionTypeName = scopeFunction ? getFunctionTypeName(sco peFunction->type) : "constructor"; const char * scopeFunctionTypeName = scopeFunction ? getFunctionTypeName(sco peFunction->type) : "constructor";
ErrorPath errorPath; ErrorPath errorPath;
for (const Token *tok : tokStack) for (const Token *tok : tokStack)
errorPath.emplace_back(tok, "Calling " + tok->str()); errorPath.emplace_back(tok, "Calling " + tok->str());
if (!errorPath.empty()) if (!errorPath.empty())
errorPath.back().second = purefuncname + " is a pure virtual method with out body"; errorPath.back().second = purefuncname + " is a pure virtual function wi thout body";
reportError(tokStack, Severity::warning, "pureVirtualCall", reportError(errorPath, Severity::warning, "pureVirtualCall",
"$symbol:" + purefuncname +"\n" "$symbol:" + purefuncname +"\n"
"Call of pure virtual function '$symbol' in " + scopeFunctionTyp eName + ".\n" "Call of pure virtual function '$symbol' in " + scopeFunctionTyp eName + ".\n"
"Call of pure virtual function '$symbol' in " + scopeFunctionTyp eName + ". The call will fail during runtime.", CWE(0U), false); "Call of pure virtual function '$symbol' in " + scopeFunctionTyp eName + ". The call will fail during runtime.", CWE(0U), false);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Check for members hiding inherited members with the same name // Check for members hiding inherited members with the same name
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CheckClass::checkDuplInheritedMembers() void CheckClass::checkDuplInheritedMembers()
skipping to change at line 2579 skipping to change at line 2604
if (!mSettings->isEnabled(Settings::STYLE)) if (!mSettings->isEnabled(Settings::STYLE))
return; return;
if (mSettings->standards.cpp < Standards::CPP11) if (mSettings->standards.cpp < Standards::CPP11)
return; return;
for (const Scope * classScope : mSymbolDatabase->classAndStructScopes) { for (const Scope * classScope : mSymbolDatabase->classAndStructScopes) {
if (!classScope->definedType || classScope->definedType->derivedFrom.emp ty()) if (!classScope->definedType || classScope->definedType->derivedFrom.emp ty())
continue; continue;
for (const Function &func : classScope->functionList) { for (const Function &func : classScope->functionList) {
if (func.hasOverrideSpecifier() || func.hasFinalSpecifier()) if (func.hasOverrideSpecifier() || func.hasFinalSpecifier())
continue; continue;
const Function *baseFunc = func.getOverridenFunction(); const Function *baseFunc = func.getOverriddenFunction();
if (baseFunc) if (baseFunc)
overrideError(baseFunc, &func); overrideError(baseFunc, &func);
} }
} }
} }
void CheckClass::overrideError(const Function *funcInBase, const Function *funcI nDerived) void CheckClass::overrideError(const Function *funcInBase, const Function *funcI nDerived)
{ {
const std::string functionName = funcInDerived ? funcInDerived->name() : ""; const std::string functionName = funcInDerived ? funcInDerived->name() : "";
 End of changes. 15 change blocks. 
67 lines changed or deleted 93 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)