PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/checkclass.cpp

https://github.com/toralf/cppcheck
C++ | 2176 lines | 1606 code | 284 blank | 286 comment | 895 complexity | 13d8f48107fe58632eb3097737fd9d82 MD5 | raw file
Possible License(s): GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Cppcheck - A tool for static C/C++ code analysis
  3. * Copyright (C) 2007-2014 Daniel Marjam채ki and Cppcheck team.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. //---------------------------------------------------------------------------
  19. #include "checkclass.h"
  20. #include "tokenize.h"
  21. #include "token.h"
  22. #include "errorlogger.h"
  23. #include "symboldatabase.h"
  24. #include <string>
  25. #include <algorithm>
  26. #include <cctype>
  27. //---------------------------------------------------------------------------
  28. // Register CheckClass..
  29. namespace {
  30. CheckClass instance;
  31. const char * getFunctionTypeName(
  32. Function::Type type)
  33. {
  34. switch (type) {
  35. case Function::eConstructor:
  36. return "constructor";
  37. case Function::eCopyConstructor:
  38. return "copy constructor";
  39. case Function::eMoveConstructor:
  40. return "move constructor";
  41. case Function::eDestructor:
  42. return "destructor";
  43. case Function::eFunction:
  44. return "function";
  45. case Function::eOperatorEqual:
  46. return "operator=";
  47. }
  48. return "";
  49. }
  50. inline bool isPureWithoutBody(Function const & func)
  51. {
  52. return func.isPure && !func.hasBody;
  53. }
  54. }
  55. //---------------------------------------------------------------------------
  56. CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
  57. : Check(myName(), tokenizer, settings, errorLogger),
  58. symbolDatabase(tokenizer?tokenizer->getSymbolDatabase():nullptr)
  59. {
  60. }
  61. //---------------------------------------------------------------------------
  62. // ClassCheck: Check that all class constructors are ok.
  63. //---------------------------------------------------------------------------
  64. void CheckClass::constructors()
  65. {
  66. const bool style = _settings->isEnabled("style");
  67. const bool warnings = _settings->isEnabled("warning");
  68. if (!style && !warnings)
  69. return;
  70. const std::size_t classes = symbolDatabase->classAndStructScopes.size();
  71. for (std::size_t i = 0; i < classes; ++i) {
  72. const Scope * scope = symbolDatabase->classAndStructScopes[i];
  73. // There are no constructors.
  74. if (scope->numConstructors == 0 && style) {
  75. // If there is a private variable, there should be a constructor..
  76. std::list<Variable>::const_iterator var;
  77. for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) {
  78. if (var->isPrivate() && !var->isStatic() && !Token::Match(var->nameToken(), "%varid% ; %varid% =", var->declarationId()) &&
  79. (!var->isClass() || (var->type() && var->type()->needInitialization == Type::True))) {
  80. noConstructorError(scope->classDef, scope->className, scope->classDef->str() == "struct");
  81. break;
  82. }
  83. }
  84. }
  85. if (!warnings)
  86. continue;
  87. // #3196 => bailout if there are nested unions
  88. // TODO: handle union variables better
  89. {
  90. bool bailout = false;
  91. for (std::list<Scope *>::const_iterator it = scope->nestedList.begin(); it != scope->nestedList.end(); ++it) {
  92. const Scope * const nestedScope = *it;
  93. if (nestedScope->type == Scope::eUnion) {
  94. bailout = true;
  95. break;
  96. }
  97. }
  98. if (bailout)
  99. continue;
  100. }
  101. std::list<Function>::const_iterator func;
  102. std::vector<Usage> usage(scope->varlist.size());
  103. for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
  104. if (!func->hasBody || !(func->isConstructor() ||
  105. func->type == Function::eOperatorEqual))
  106. continue;
  107. // Mark all variables not used
  108. clearAllVar(usage);
  109. std::list<const Function *> callstack;
  110. initializeVarList(*func, callstack, &(*scope), usage);
  111. // Check if any variables are uninitialized
  112. std::list<Variable>::const_iterator var;
  113. unsigned int count = 0;
  114. for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var, ++count) {
  115. // check for C++11 initializer
  116. if (var->hasDefault()) {
  117. usage[count].init = true;
  118. continue;
  119. }
  120. if (usage[count].assign || usage[count].init || var->isStatic())
  121. continue;
  122. if (var->isConst() && func->isOperator) // We can't set const members in assignment operator
  123. continue;
  124. // Check if this is a class constructor
  125. if (!var->isPointer() && var->isClass() && func->type == Function::eConstructor) {
  126. // Unknown type so assume it is initialized
  127. if (!var->type())
  128. continue;
  129. // Known type that doesn't need initialization or
  130. // known type that has member variables of an unknown type
  131. else if (var->type()->needInitialization != Type::True)
  132. continue;
  133. }
  134. // Check if type can't be copied
  135. if (!var->isPointer() && var->typeScope()) {
  136. if (func->type == Function::eMoveConstructor) {
  137. if (canNotMove(var->typeScope()))
  138. continue;
  139. } else {
  140. if (canNotCopy(var->typeScope()))
  141. continue;
  142. }
  143. }
  144. bool inconclusive = false;
  145. // Don't warn about unknown types in copy constructors since we
  146. // don't know if they can be copied or not..
  147. if (!var->isPointer() &&
  148. !(var->type() && var->type()->needInitialization != Type::True) &&
  149. (func->type == Function::eCopyConstructor || func->type == Function::eOperatorEqual)) {
  150. if (!var->typeStartToken()->isStandardType()) {
  151. if (_settings->inconclusive)
  152. inconclusive = true;
  153. else
  154. continue;
  155. }
  156. }
  157. // It's non-static and it's not initialized => error
  158. if (func->type == Function::eOperatorEqual) {
  159. const Token *operStart = func->arg;
  160. bool classNameUsed = false;
  161. for (const Token *operTok = operStart; operTok != operStart->link(); operTok = operTok->next()) {
  162. if (operTok->str() == scope->className) {
  163. classNameUsed = true;
  164. break;
  165. }
  166. }
  167. if (classNameUsed)
  168. operatorEqVarError(func->token, scope->className, var->name(), inconclusive);
  169. } else if (func->access != Private) {
  170. const Scope *varType = var->typeScope();
  171. if (!varType || varType->type != Scope::eUnion) {
  172. if (func->type == Function::eConstructor &&
  173. func->nestedIn && (func->nestedIn->numConstructors - func->nestedIn->numCopyOrMoveConstructors) > 1 &&
  174. func->argCount() == 0 && func->functionScope &&
  175. func->arg && func->arg->link()->next() == func->functionScope->classStart &&
  176. func->functionScope->classStart->link() == func->functionScope->classStart->next()) {
  177. // don't warn about user defined default constructor when there are other constructors
  178. if (_settings->inconclusive)
  179. uninitVarError(func->token, scope->className, var->name(), true);
  180. } else
  181. uninitVarError(func->token, scope->className, var->name(), inconclusive);
  182. }
  183. }
  184. }
  185. }
  186. }
  187. }
  188. void CheckClass::copyconstructors()
  189. {
  190. if (!_settings->isEnabled("style"))
  191. return;
  192. const std::size_t classes = symbolDatabase->classAndStructScopes.size();
  193. for (std::size_t i = 0; i < classes; ++i) {
  194. const Scope * scope = symbolDatabase->classAndStructScopes[i];
  195. std::map<unsigned int, const Token*> allocatedVars;
  196. for (std::list<Function>::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
  197. if (func->type == Function::eConstructor && func->functionScope) {
  198. const Token* tok = func->functionScope->classDef->linkAt(1);
  199. for (const Token* const end = func->functionScope->classStart; tok != end; tok = tok->next()) {
  200. if (Token::Match(tok, "%var% ( new|malloc|g_malloc|g_try_malloc|realloc|g_realloc|g_try_realloc")) {
  201. const Variable* var = tok->variable();
  202. if (var && var->isPointer() && var->scope() == &*scope)
  203. allocatedVars[tok->varId()] = tok;
  204. }
  205. }
  206. for (const Token* const end = func->functionScope->classEnd; tok != end; tok = tok->next()) {
  207. if (Token::Match(tok, "%var% = new|malloc|g_malloc|g_try_malloc|realloc|g_realloc|g_try_realloc")) {
  208. const Variable* var = tok->variable();
  209. if (var && var->isPointer() && var->scope() == &*scope)
  210. allocatedVars[tok->varId()] = tok;
  211. }
  212. }
  213. }
  214. }
  215. std::set<const Token*> copiedVars;
  216. const Token* copyCtor = 0;
  217. for (std::list<Function>::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
  218. if (func->type == Function::eCopyConstructor) {
  219. copyCtor = func->tokenDef;
  220. if (func->functionScope) {
  221. const Token* tok = func->tokenDef->linkAt(1)->next();
  222. if (tok->str()==":") {
  223. tok=tok->next();
  224. while (Token::Match(tok, "%var% (")) {
  225. if (allocatedVars.find(tok->varId()) != allocatedVars.end()) {
  226. if (tok->varId() && Token::Match(tok->tokAt(2), "%var% . %var% )"))
  227. copiedVars.insert(tok);
  228. else if (!Token::Match(tok->tokAt(2), "%any% )"))
  229. allocatedVars.erase(tok->varId()); // Assume memory is allocated
  230. }
  231. tok = tok->linkAt(1)->tokAt(2);
  232. }
  233. }
  234. for (tok=func->functionScope->classStart; tok!=func->functionScope->classEnd; tok=tok->next()) {
  235. if (Token::Match(tok, "%var% = new|malloc|g_malloc|g_try_malloc|realloc|g_realloc|g_try_realloc")) {
  236. allocatedVars.erase(tok->varId());
  237. } else if (Token::Match(tok, "%var% = %var% . %var% ;") && allocatedVars.find(tok->varId()) != allocatedVars.end()) {
  238. copiedVars.insert(tok);
  239. }
  240. }
  241. } else // non-copyable or implementation not seen
  242. allocatedVars.clear();
  243. break;
  244. }
  245. }
  246. if (!copyCtor) {
  247. if (!allocatedVars.empty() && scope->definedType->derivedFrom.empty()) // TODO: Check if base class is non-copyable
  248. noCopyConstructorError(scope->classDef, scope->className, scope->type == Scope::eStruct);
  249. } else {
  250. if (!copiedVars.empty()) {
  251. for (std::set<const Token*>::const_iterator it = copiedVars.begin(); it != copiedVars.end(); ++it) {
  252. copyConstructorShallowCopyError(*it, (*it)->str());
  253. }
  254. }
  255. // throw error if count mismatch
  256. /* FIXME: This doesn't work. See #4154
  257. for (std::map<unsigned int, const Token*>::const_iterator i = allocatedVars.begin(); i != allocatedVars.end(); ++i) {
  258. copyConstructorMallocError(copyCtor, i->second, i->second->str());
  259. }
  260. */
  261. }
  262. }
  263. }
  264. /* This doesn't work. See #4154
  265. void CheckClass::copyConstructorMallocError(const Token *cctor, const Token *alloc, const std::string& varname)
  266. {
  267. std::list<const Token*> callstack;
  268. callstack.push_back(cctor);
  269. callstack.push_back(alloc);
  270. reportError(callstack, Severity::warning, "copyCtorNoAllocation", "Copy constructor does not allocate memory for member '" + varname + "' although memory has been allocated in other constructors.");
  271. }
  272. */
  273. void CheckClass::copyConstructorShallowCopyError(const Token *tok, const std::string& varname)
  274. {
  275. reportError(tok, Severity::style, "copyCtorPointerCopying", "Value of pointer '" + varname + "', which points to allocated memory, is copied in copy constructor instead of allocating new memory.");
  276. }
  277. void CheckClass::noCopyConstructorError(const Token *tok, const std::string &classname, bool isStruct)
  278. {
  279. // The constructor might be intentionally missing. Therefore this is not a "warning"
  280. reportError(tok, Severity::style, "noCopyConstructor",
  281. "'" + std::string(isStruct ? "struct" : "class") + " " + classname +
  282. "' does not have a copy constructor which is recommended since the class contains a pointer to allocated memory.");
  283. }
  284. bool CheckClass::canNotCopy(const Scope *scope)
  285. {
  286. std::list<Function>::const_iterator func;
  287. bool constructor = false;
  288. bool publicAssign = false;
  289. bool publicCopy = false;
  290. for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
  291. if (func->isConstructor())
  292. constructor = true;
  293. if ((func->type == Function::eCopyConstructor) &&
  294. func->access == Public)
  295. publicCopy = true;
  296. else if (func->type == Function::eOperatorEqual && func->access == Public)
  297. publicAssign = true;
  298. }
  299. return constructor && !(publicAssign || publicCopy);
  300. }
  301. bool CheckClass::canNotMove(const Scope *scope)
  302. {
  303. std::list<Function>::const_iterator func;
  304. bool constructor = false;
  305. bool publicAssign = false;
  306. bool publicCopy = false;
  307. bool publicMove = false;
  308. for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
  309. if (func->isConstructor())
  310. constructor = true;
  311. if ((func->type == Function::eCopyConstructor) &&
  312. func->access == Public)
  313. publicCopy = true;
  314. else if ((func->type == Function::eMoveConstructor) &&
  315. func->access == Public)
  316. publicMove = true;
  317. else if (func->type == Function::eOperatorEqual && func->access == Public)
  318. publicAssign = true;
  319. }
  320. return constructor && !(publicAssign || publicCopy || publicMove);
  321. }
  322. void CheckClass::assignVar(const std::string &varname, const Scope *scope, std::vector<Usage> &usage)
  323. {
  324. std::list<Variable>::const_iterator var;
  325. unsigned int count = 0;
  326. for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var, ++count) {
  327. if (var->name() == varname) {
  328. usage[count].assign = true;
  329. return;
  330. }
  331. }
  332. }
  333. void CheckClass::initVar(const std::string &varname, const Scope *scope, std::vector<Usage> &usage)
  334. {
  335. std::list<Variable>::const_iterator var;
  336. unsigned int count = 0;
  337. for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var, ++count) {
  338. if (var->name() == varname) {
  339. usage[count].init = true;
  340. return;
  341. }
  342. }
  343. }
  344. void CheckClass::assignAllVar(std::vector<Usage> &usage)
  345. {
  346. for (std::size_t i = 0; i < usage.size(); ++i)
  347. usage[i].assign = true;
  348. }
  349. void CheckClass::clearAllVar(std::vector<Usage> &usage)
  350. {
  351. for (std::size_t i = 0; i < usage.size(); ++i) {
  352. usage[i].assign = false;
  353. usage[i].init = false;
  354. }
  355. }
  356. bool CheckClass::isBaseClassFunc(const Token *tok, const Scope *scope)
  357. {
  358. // Iterate through each base class...
  359. for (std::size_t i = 0; i < scope->definedType->derivedFrom.size(); ++i) {
  360. const Type *derivedFrom = scope->definedType->derivedFrom[i].type;
  361. // Check if base class exists in database
  362. if (derivedFrom && derivedFrom->classScope) {
  363. const std::list<Function>& functionList = derivedFrom->classScope->functionList;
  364. std::list<Function>::const_iterator func;
  365. for (func = functionList.begin(); func != functionList.end(); ++func) {
  366. if (func->tokenDef->str() == tok->str())
  367. return true;
  368. }
  369. }
  370. // Base class not found so assume it is in it.
  371. else
  372. return true;
  373. }
  374. return false;
  375. }
  376. void CheckClass::initializeVarList(const Function &func, std::list<const Function *> &callstack, const Scope *scope, std::vector<Usage> &usage)
  377. {
  378. if (!func.functionScope)
  379. throw InternalError(0, "Internal Error: Invalid syntax"); // #5702
  380. bool initList = func.isConstructor();
  381. const Token *ftok = func.arg->link()->next();
  382. int level = 0;
  383. for (; ftok && ftok != func.functionScope->classEnd; ftok = ftok->next()) {
  384. // Class constructor.. initializing variables like this
  385. // clKalle::clKalle() : var(value) { }
  386. if (initList) {
  387. if (level == 0 && Token::Match(ftok, "%var% {|(")) {
  388. if (ftok->str() != func.name()) {
  389. initVar(ftok->str(), scope, usage);
  390. } else { // c++11 delegate constructor
  391. const Function *member = ftok->function();
  392. // member function found
  393. if (member) {
  394. // recursive call
  395. // assume that all variables are initialized
  396. if (std::find(callstack.begin(), callstack.end(), member) != callstack.end()) {
  397. /** @todo false negative: just bail */
  398. assignAllVar(usage);
  399. return;
  400. }
  401. // member function has implementation
  402. if (member->hasBody) {
  403. // initialize variable use list using member function
  404. callstack.push_back(member);
  405. initializeVarList(*member, callstack, scope, usage);
  406. callstack.pop_back();
  407. }
  408. // there is a called member function, but it has no implementation, so we assume it initializes everything
  409. else {
  410. assignAllVar(usage);
  411. }
  412. }
  413. }
  414. ftok = ftok->next();
  415. level++;
  416. } else if (level != 0 && Token::Match(ftok, "%var% =")) // assignment in the initializer: var(value = x)
  417. assignVar(ftok->str(), scope, usage);
  418. else if (ftok->str() == "(")
  419. level++;
  420. else if (ftok->str() == ")" || ftok->str() == "}")
  421. level--;
  422. else if (ftok->str() == "{") {
  423. if (level == 0)
  424. initList = false;
  425. else
  426. ftok = ftok->link();
  427. }
  428. }
  429. if (initList)
  430. continue;
  431. // Variable getting value from stream?
  432. if (Token::Match(ftok, ">> %var%")) {
  433. assignVar(ftok->strAt(1), scope, usage);
  434. }
  435. // Before a new statement there is "[{};()=[]"
  436. if (! Token::Match(ftok, "[{};()=[]"))
  437. continue;
  438. if (Token::simpleMatch(ftok, "( !"))
  439. ftok = ftok->next();
  440. // Using the operator= function to initialize all variables..
  441. if (Token::Match(ftok->next(), "return| (| * this )| =")) {
  442. assignAllVar(usage);
  443. break;
  444. }
  445. // Using swap to assign all variables..
  446. if (func.type == Function::eOperatorEqual && Token::Match(ftok, "[;{}] %var% (") && Token::Match(ftok->linkAt(2), ") . %var% ( *| this ) ;")) {
  447. assignAllVar(usage);
  448. break;
  449. }
  450. // Calling member variable function?
  451. if (Token::Match(ftok->next(), "%var% . %var% (")) {
  452. std::list<Variable>::const_iterator var;
  453. for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) {
  454. if (var->declarationId() == ftok->next()->varId()) {
  455. /** @todo false negative: we assume function changes variable state */
  456. assignVar(ftok->next()->str(), scope, usage);
  457. break;
  458. }
  459. }
  460. ftok = ftok->tokAt(2);
  461. }
  462. if (!Token::Match(ftok->next(), "::| %var%") &&
  463. !Token::Match(ftok->next(), "*| this . %var%") &&
  464. !Token::Match(ftok->next(), "* %var% =") &&
  465. !Token::Match(ftok->next(), "( * this ) . %var%"))
  466. continue;
  467. // Goto the first token in this statement..
  468. ftok = ftok->next();
  469. // skip "return"
  470. if (ftok->str() == "return")
  471. ftok = ftok->next();
  472. // Skip "( * this )"
  473. if (Token::simpleMatch(ftok, "( * this ) .")) {
  474. ftok = ftok->tokAt(5);
  475. }
  476. // Skip "this->"
  477. if (Token::simpleMatch(ftok, "this ."))
  478. ftok = ftok->tokAt(2);
  479. // Skip "classname :: "
  480. if (Token::Match(ftok, ":: %var%"))
  481. ftok = ftok->next();
  482. while (Token::Match(ftok, "%var% ::"))
  483. ftok = ftok->tokAt(2);
  484. // Clearing all variables..
  485. if (Token::Match(ftok, "::| memset ( this ,")) {
  486. assignAllVar(usage);
  487. return;
  488. }
  489. // Clearing array..
  490. else if (Token::Match(ftok, "::| memset ( %var% ,")) {
  491. if (ftok->str() == "::")
  492. ftok = ftok->next();
  493. assignVar(ftok->strAt(2), scope, usage);
  494. ftok = ftok->linkAt(1);
  495. continue;
  496. }
  497. // Calling member function?
  498. else if (Token::simpleMatch(ftok, "operator= (") &&
  499. ftok->previous()->str() != "::") {
  500. if (ftok->function() && ftok->function()->nestedIn == scope) {
  501. const Function *member = ftok->function();
  502. // recursive call
  503. // assume that all variables are initialized
  504. if (std::find(callstack.begin(), callstack.end(), member) != callstack.end()) {
  505. /** @todo false negative: just bail */
  506. assignAllVar(usage);
  507. return;
  508. }
  509. // member function has implementation
  510. if (member->hasBody) {
  511. // initialize variable use list using member function
  512. callstack.push_back(member);
  513. initializeVarList(*member, callstack, scope, usage);
  514. callstack.pop_back();
  515. }
  516. // there is a called member function, but it has no implementation, so we assume it initializes everything
  517. else {
  518. assignAllVar(usage);
  519. }
  520. }
  521. // using default operator =, assume everything initialized
  522. else {
  523. assignAllVar(usage);
  524. }
  525. } else if (Token::Match(ftok, "::| %var% (") && ftok->str() != "if") {
  526. if (ftok->str() == "::")
  527. ftok = ftok->next();
  528. // Passing "this" => assume that everything is initialized
  529. for (const Token *tok2 = ftok->next()->link(); tok2 && tok2 != ftok; tok2 = tok2->previous()) {
  530. if (tok2->str() == "this") {
  531. assignAllVar(usage);
  532. return;
  533. }
  534. }
  535. // check if member function
  536. if (ftok->function() && ftok->function()->nestedIn == scope &&
  537. !ftok->function()->isConstructor()) {
  538. const Function *member = ftok->function();
  539. // recursive call
  540. // assume that all variables are initialized
  541. if (std::find(callstack.begin(), callstack.end(), member) != callstack.end()) {
  542. assignAllVar(usage);
  543. return;
  544. }
  545. // member function has implementation
  546. if (member->hasBody) {
  547. // initialize variable use list using member function
  548. callstack.push_back(member);
  549. initializeVarList(*member, callstack, scope, usage);
  550. callstack.pop_back();
  551. // Assume that variables that are passed to it are initialized..
  552. for (const Token *tok2 = ftok; tok2; tok2 = tok2->next()) {
  553. if (Token::Match(tok2, "[;{}]"))
  554. break;
  555. if (Token::Match(tok2, "[(,] &| %var% [,)]")) {
  556. tok2 = tok2->next();
  557. if (tok2->str() == "&")
  558. tok2 = tok2->next();
  559. assignVar(tok2->str(), scope, usage);
  560. }
  561. }
  562. }
  563. // there is a called member function, but it has no implementation, so we assume it initializes everything
  564. else {
  565. assignAllVar(usage);
  566. }
  567. }
  568. // not member function
  569. else {
  570. // could be a base class virtual function, so we assume it initializes everything
  571. if (!func.isConstructor() && isBaseClassFunc(ftok, scope)) {
  572. /** @todo False Negative: we should look at the base class functions to see if they
  573. * call any derived class virtual functions that change the derived class state
  574. */
  575. assignAllVar(usage);
  576. }
  577. // has friends, so we assume it initializes everything
  578. if (!scope->definedType->friendList.empty())
  579. assignAllVar(usage);
  580. // the function is external and it's neither friend nor inherited virtual function.
  581. // assume all variables that are passed to it are initialized..
  582. else {
  583. for (const Token *tok = ftok->tokAt(2); tok && tok != ftok->next()->link(); tok = tok->next()) {
  584. if (tok->isName()) {
  585. assignVar(tok->str(), scope, usage);
  586. }
  587. }
  588. }
  589. }
  590. }
  591. // Assignment of member variable?
  592. else if (Token::Match(ftok, "%var% =")) {
  593. assignVar(ftok->str(), scope, usage);
  594. }
  595. // Assignment of array item of member variable?
  596. else if (Token::Match(ftok, "%var% [|.")) {
  597. const Token *tok2 = ftok;
  598. while (tok2) {
  599. if (tok2->strAt(1) == "[")
  600. tok2 = tok2->next()->link();
  601. else if (Token::Match(tok2->next(), ". %var%"))
  602. tok2 = tok2->tokAt(2);
  603. else
  604. break;
  605. }
  606. if (tok2 && tok2->strAt(1) == "=")
  607. assignVar(ftok->str(), scope, usage);
  608. }
  609. // Assignment of array item of member variable?
  610. else if (Token::Match(ftok, "* %var% =")) {
  611. assignVar(ftok->next()->str(), scope, usage);
  612. } else if (Token::Match(ftok, "* this . %var% =")) {
  613. assignVar(ftok->strAt(3), scope, usage);
  614. }
  615. // The functions 'clear' and 'Clear' are supposed to initialize variable.
  616. if (Token::Match(ftok, "%var% . clear|Clear (")) {
  617. assignVar(ftok->str(), scope, usage);
  618. }
  619. }
  620. }
  621. void CheckClass::noConstructorError(const Token *tok, const std::string &classname, bool isStruct)
  622. {
  623. // For performance reasons the constructor might be intentionally missing. Therefore this is not a "warning"
  624. reportError(tok, Severity::style, "noConstructor",
  625. "The " + std::string(isStruct ? "struct" : "class") + " '" + classname +
  626. "' does not have a constructor.\n"
  627. "The " + std::string(isStruct ? "struct" : "class") + " '" + classname +
  628. "' does not have a constructor although it has private member variables. "
  629. "Member variables of builtin types are left uninitialized when the class is "
  630. "instantiated. That may cause bugs or undefined behavior.");
  631. }
  632. void CheckClass::uninitVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive)
  633. {
  634. reportError(tok, Severity::warning, "uninitMemberVar", "Member variable '" + classname + "::" + varname + "' is not initialized in the constructor.", inconclusive);
  635. }
  636. void CheckClass::operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive)
  637. {
  638. reportError(tok, Severity::warning, "operatorEqVarError", "Member variable '" + classname + "::" + varname + "' is not assigned a value in '" + classname + "::operator='.", inconclusive);
  639. }
  640. //---------------------------------------------------------------------------
  641. // ClassCheck: Use initialization list instead of assignment
  642. //---------------------------------------------------------------------------
  643. void CheckClass::initializationListUsage()
  644. {
  645. if (!_settings->isEnabled("performance"))
  646. return;
  647. const std::size_t functions = symbolDatabase->functionScopes.size();
  648. for (std::size_t i = 0; i < functions; ++i) {
  649. const Scope * scope = symbolDatabase->functionScopes[i];
  650. // Check every constructor
  651. if (!scope->function || (!scope->function->isConstructor()))
  652. continue;
  653. const Scope* owner = scope->functionOf;
  654. for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
  655. if (Token::Match(tok, "%var% (")) // Assignments might depend on this function call or if/for/while/switch statement from now on.
  656. break;
  657. if (Token::Match(tok, "try|do {"))
  658. break;
  659. if (tok->varId() && Token::Match(tok, "%var% = %any%")) {
  660. const Variable* var = tok->variable();
  661. if (var && var->scope() == owner && !var->isStatic()) {
  662. bool allowed = true;
  663. for (const Token* tok2 = tok->tokAt(2); tok2->str() != ";"; tok2 = tok2->next()) {
  664. if (tok2->varId()) {
  665. const Variable* var2 = tok2->variable();
  666. if (var2 && var2->scope() == owner &&
  667. tok2->strAt(-1)!=".") { // Is there a dependency between two member variables?
  668. allowed = false;
  669. break;
  670. } else if (var2 && (var2->isArray() && var2->isLocal())) { // Can't initialize with a local array
  671. allowed = false;
  672. break;
  673. }
  674. } else if (tok2->str() == "this") { // 'this' instance is not completely constructed in initialization list
  675. allowed = false;
  676. break;
  677. } else if (Token::Match(tok2, "%var% (") && tok2->strAt(-1) != "." && isMemberFunc(owner, tok2)) { // Member function called?
  678. allowed = false;
  679. break;
  680. }
  681. }
  682. if (!allowed)
  683. continue;
  684. if (!var->isPointer() && !var->isReference() && (var->type() || var->isStlStringType() || (Token::Match(var->typeStartToken(), "std :: %type% <") && !Token::simpleMatch(var->typeStartToken()->linkAt(3), "> ::"))))
  685. suggestInitializationList(tok, tok->str());
  686. }
  687. }
  688. }
  689. }
  690. }
  691. void CheckClass::suggestInitializationList(const Token* tok, const std::string& varname)
  692. {
  693. reportError(tok, Severity::performance, "useInitializationList", "Variable '" + varname + "' is assigned in constructor body. Consider performing initialization in initialization list.\n"
  694. "When an object of a class is created, the constructors of all member variables are called consecutively "
  695. "in the order the variables are declared, even if you don't explicitly write them to the initialization list. You "
  696. "could avoid assigning '" + varname + "' a value by passing the value to the constructor in the initialization list.");
  697. }
  698. //---------------------------------------------------------------------------
  699. // ClassCheck: Unused private functions
  700. //---------------------------------------------------------------------------
  701. static bool checkFunctionUsage(const std::string& name, const Scope* scope)
  702. {
  703. if (!scope)
  704. return true; // Assume it is used, if scope is not seen
  705. for (std::list<Function>::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
  706. if (func->functionScope) {
  707. if (Token::Match(func->tokenDef, "%var% (")) {
  708. for (const Token *ftok = func->tokenDef->tokAt(2); ftok && ftok->str() != ")"; ftok = ftok->next()) {
  709. if (Token::Match(ftok, "= %var% [(,)]") && ftok->strAt(1) == name)
  710. return true;
  711. if (ftok->str() == "(")
  712. ftok = ftok->link();
  713. }
  714. }
  715. for (const Token *ftok = func->functionScope->classDef->linkAt(1); ftok != func->functionScope->classEnd; ftok = ftok->next()) {
  716. if (ftok->str() == name) // Function used. TODO: Handle overloads
  717. return true;
  718. }
  719. } else if ((func->type != Function::eCopyConstructor &&
  720. func->type != Function::eOperatorEqual) ||
  721. func->access != Private) // Assume it is used, if a function implementation isn't seen, but empty private copy constructors and assignment operators are OK
  722. return true;
  723. }
  724. for (std::list<Scope*>::const_iterator i = scope->nestedList.begin(); i != scope->nestedList.end(); ++i) {
  725. if ((*i)->isClassOrStruct())
  726. if (checkFunctionUsage(name, *i)) // Check nested classes, which can access private functions of their base
  727. return true;
  728. }
  729. for (std::list<Variable>::const_iterator i = scope->varlist.begin(); i != scope->varlist.end(); ++i) {
  730. if (i->isStatic()) {
  731. const Token* tok = Token::findmatch(scope->classEnd, "%varid% =|(|{", i->declarationId());
  732. if (tok)
  733. tok = tok->tokAt(2);
  734. while (tok && tok->str() != ";") {
  735. if (tok->str() == name && (tok->strAt(-1) == "." || tok->strAt(-2) == scope->className))
  736. return true;
  737. tok = tok->next();
  738. }
  739. }
  740. }
  741. return false; // Unused in this scope
  742. }
  743. void CheckClass::privateFunctions()
  744. {
  745. if (!_settings->isEnabled("style"))
  746. return;
  747. const std::size_t classes = symbolDatabase->classAndStructScopes.size();
  748. for (std::size_t i = 0; i < classes; ++i) {
  749. const Scope * scope = symbolDatabase->classAndStructScopes[i];
  750. // do not check borland classes with properties..
  751. if (Token::findsimplematch(scope->classStart, "; __property ;", scope->classEnd))
  752. continue;
  753. std::list<const Function*> privateFuncs;
  754. for (std::list<Function>::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
  755. // Get private functions..
  756. if (func->type == Function::eFunction && func->access == Private && !func->isOperator) // TODO: There are smarter ways to check private operator usage
  757. privateFuncs.push_back(&*func);
  758. }
  759. // Bailout for overridden virtual functions of base classes
  760. if (!scope->definedType->derivedFrom.empty()) {
  761. // Check virtual functions
  762. for (std::list<const Function*>::iterator it = privateFuncs.begin(); it != privateFuncs.end();) {
  763. if ((*it)->isImplicitlyVirtual(true)) // Give true as default value to be returned if we don't see all base classes
  764. privateFuncs.erase(it++);
  765. else
  766. ++it;
  767. }
  768. }
  769. while (!privateFuncs.empty()) {
  770. const std::string& funcName = privateFuncs.front()->tokenDef->str();
  771. // Check that all private functions are used
  772. bool used = checkFunctionUsage(funcName, &*scope); // Usage in this class
  773. // Check in friend classes
  774. const std::list<Type::FriendInfo>& friendList = scope->definedType->friendList;
  775. for (std::list<Type::FriendInfo>::const_iterator it = friendList.begin(); !used && it != friendList.end(); ++it) {
  776. if (it->type)
  777. used = checkFunctionUsage(funcName, it->type->classScope);
  778. else
  779. used = true; // Assume, it is used if we do not see friend class
  780. }
  781. if (!used)
  782. unusedPrivateFunctionError(privateFuncs.front()->tokenDef, scope->className, funcName);
  783. privateFuncs.pop_front();
  784. }
  785. }
  786. }
  787. void CheckClass::unusedPrivateFunctionError(const Token *tok, const std::string &classname, const std::string &funcname)
  788. {
  789. reportError(tok, Severity::style, "unusedPrivateFunction", "Unused private function: '" + classname + "::" + funcname + "'");
  790. }
  791. //---------------------------------------------------------------------------
  792. // ClassCheck: Check that memset is not used on classes
  793. //---------------------------------------------------------------------------
  794. static const Scope* findFunctionOf(const Scope* scope)
  795. {
  796. while (scope) {
  797. if (scope->type == Scope::eFunction)
  798. return scope->functionOf;
  799. scope = scope->nestedIn;
  800. }
  801. return 0;
  802. }
  803. void CheckClass::checkMemset()
  804. {
  805. const std::size_t functions = symbolDatabase->functionScopes.size();
  806. for (std::size_t i = 0; i < functions; ++i) {
  807. const Scope * scope = symbolDatabase->functionScopes[i];
  808. for (const Token *tok = scope->classStart; tok && tok != scope->classEnd; tok = tok->next()) {
  809. if (Token::Match(tok, "memset|memcpy|memmove ( %any%")) {
  810. const Token* arg1 = tok->tokAt(2);
  811. const Token* arg3 = arg1->nextArgument();
  812. if (arg3)
  813. arg3 = arg3->nextArgument();
  814. if (!arg3)
  815. // weird, shouldn't happen: memset etc should have
  816. // 3 arguments.
  817. continue;
  818. const Token *typeTok = nullptr;
  819. const Scope *type = nullptr;
  820. if (Token::Match(arg3, "sizeof ( %type% ) )"))
  821. typeTok = arg3->tokAt(2);
  822. else if (Token::Match(arg3, "sizeof ( %type% :: %type% ) )"))
  823. typeTok = arg3->tokAt(4);
  824. else if (Token::Match(arg3, "sizeof ( struct %type% ) )"))
  825. typeTok = arg3->tokAt(3);
  826. else if (Token::simpleMatch(arg3, "sizeof ( * this ) )") || Token::simpleMatch(arg1, "this ,")) {
  827. type = findFunctionOf(arg3->scope());
  828. } else if (Token::Match(arg1, "&|*|%var%")) {
  829. int derefs = 1;
  830. for (;; arg1 = arg1->next()) {
  831. if (arg1->str() == "&")
  832. derefs--;
  833. else if (arg1->str() == "*")
  834. derefs++;
  835. else
  836. break;
  837. }
  838. const Variable *var = arg1->variable();
  839. if (var && arg1->strAt(1) == ",") {
  840. if (var->isPointer()) {
  841. derefs--;
  842. if (var->typeEndToken() && Token::simpleMatch(var->typeEndToken()->previous(), "* *")) // Check if it's a pointer to pointer
  843. derefs--;
  844. }
  845. if (var->isArray())
  846. derefs -= (int)var->dimensions().size();
  847. if (derefs == 0)
  848. type = var->typeScope();
  849. }
  850. }
  851. // No type defined => The tokens didn't match
  852. if (!typeTok && !type)
  853. continue;
  854. if (typeTok && typeTok->str() == "(")
  855. typeTok = typeTok->next();
  856. if (!type) {
  857. const Type* t = symbolDatabase->findVariableType(&(*scope), typeTok);
  858. if (t)
  859. type = t->classScope;
  860. }
  861. if (type) {
  862. std::list<const Scope *> parsedTypes;
  863. checkMemsetType(&(*scope), tok, type, false, parsedTypes);
  864. }
  865. } else if (tok->variable() && tok->variable()->typeScope() && Token::Match(tok, "%var% = calloc|malloc|realloc|g_malloc|g_try_malloc|g_realloc|g_try_realloc (")) {
  866. std::list<const Scope *> parsedTypes;
  867. checkMemsetType(&(*scope), tok->tokAt(2), tok->variable()->typeScope(), true, parsedTypes);
  868. if (tok->variable()->typeScope()->numConstructors > 0 && _settings->isEnabled("warning"))
  869. mallocOnClassWarning(tok, tok->strAt(2), tok->variable()->typeScope()->classDef);
  870. }
  871. }
  872. }
  873. }
  874. void CheckClass::checkMemsetType(const Scope *start, const Token *tok, const Scope *type, bool allocation, std::list<const Scope *> parsedTypes)
  875. {
  876. // If type has been checked there is no need to check it again
  877. if (std::find(parsedTypes.begin(), parsedTypes.end(), type) != parsedTypes.end())
  878. return;
  879. parsedTypes.push_back(type);
  880. // recursively check all parent classes
  881. for (std::size_t i = 0; i < type->definedType->derivedFrom.size(); i++) {
  882. const Type* derivedFrom = type->definedType->derivedFrom[i].type;
  883. if (derivedFrom && derivedFrom->classScope)
  884. checkMemsetType(start, tok, derivedFrom->classScope, allocation, parsedTypes);
  885. }
  886. // Warn if type is a class that contains any virtual functions
  887. std::list<Function>::const_iterator func;
  888. for (func = type->functionList.begin(); func != type->functionList.end(); ++func) {
  889. if (func->isVirtual) {
  890. if (allocation)
  891. mallocOnClassError(tok, tok->str(), type->classDef, "virtual method");
  892. else
  893. memsetError(tok, tok->str(), "virtual method", type->classDef->str());
  894. }
  895. }
  896. // Warn if type is a class or struct that contains any std::* variables
  897. std::list<Variable>::const_iterator var;
  898. for (var = type->varlist.begin(); var != type->varlist.end(); ++var) {
  899. if (var->isReference() && !var->isStatic()) {
  900. memsetErrorReference(tok, tok->str(), type->classDef->str());
  901. continue;
  902. }
  903. // don't warn if variable static or const, pointer or reference
  904. if (!var->isStatic() && !var->isConst() && !var->isPointer()) {
  905. const Token *tok1 = var->typeStartToken();
  906. const Scope *typeScope = var->typeScope();
  907. // check for std:: type
  908. if (var->isStlType() && tok1->strAt(2) != "array" && !_settings->library.podtype(tok1->strAt(2)))
  909. if (allocation)
  910. mallocOnClassError(tok, tok->str(), type->classDef, "'std::" + tok1->strAt(2) + "'");
  911. else
  912. memsetError(tok, tok->str(), "'std::" + tok1->strAt(2) + "'", type->classDef->str());
  913. // check for known type
  914. else if (typeScope && typeScope != type)
  915. checkMemsetType(start, tok, typeScope, allocation, parsedTypes);
  916. // check for float
  917. else if (tok->str() == "memset" && var->isFloatingType() && _settings->isEnabled("portability"))
  918. memsetErrorFloat(tok, type->classDef->str());
  919. }
  920. }
  921. }
  922. void CheckClass::mallocOnClassWarning(const Token* tok, const std::string &memfunc, const Token* classTok)
  923. {
  924. std::list<const Token *> toks;
  925. toks.push_back(tok);
  926. toks.push_back(classTok);
  927. reportError(toks, Severity::warning, "mallocOnClassWarning",
  928. "Memory for class instance allocated with " + memfunc + "(), but class provides constructors.\n"
  929. "Memory for class instance allocated with " + memfunc + "(), but class provides constructors. This is unsafe, "
  930. "since no constructor is called and class members remain uninitialized. Consider using 'new' instead.");
  931. }
  932. void CheckClass::mallocOnClassError(const Token* tok, const std::string &memfunc, const Token* classTok, const std::string &classname)
  933. {
  934. std::list<const Token *> toks;
  935. toks.push_back(tok);
  936. toks.push_back(classTok);
  937. reportError(toks, Severity::error, "mallocOnClassError",
  938. "Memory for class instance allocated with " + memfunc + "(), but class contains a " + classname + ".\n"
  939. "Memory for class instance allocated with " + memfunc + "(), but class a " + classname + ". This is unsafe, "
  940. "since no constructor is called and class members remain uninitialized. Consider using 'new' instead.");
  941. }
  942. void CheckClass::memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type)
  943. {
  944. reportError(tok, Severity::error, "memsetClass",
  945. "Using '" + memfunc + "' on " + type + " that contains a " + classname + ".\n"
  946. "Using '" + memfunc + "' on " + type + " that contains a " + classname + " is unsafe, because constructor, destructor "
  947. "and copy operator calls are omitted. These are necessary for this non-POD type to ensure that a valid object "
  948. "is created.");
  949. }
  950. void CheckClass::memsetErrorReference(const Token *tok, const std::string &memfunc, const std::string &type)
  951. {
  952. reportError(tok, Severity::error, "memsetClassReference", "Using '" + memfunc + "' on " + type + " that contains a reference.");
  953. }
  954. void CheckClass::memsetErrorFloat(const Token *tok, const std::string &type)
  955. {
  956. reportError(tok, Severity::portability, "memsetClassFloat", "Using memset() on " + type + " which contains a floating point number.\n"
  957. "Using memset() on " + type + " which contains a floating point number. This is not portable because memset() sets each byte of a block of memory to a specific value and"
  958. " the actual representation of a floating-point value is implementation defined.");
  959. }
  960. //---------------------------------------------------------------------------
  961. // ClassCheck: "void operator=(" and "const type & operator=("
  962. //---------------------------------------------------------------------------
  963. void CheckClass::operatorEq()
  964. {
  965. if (!_settings->isEnabled("style"))
  966. return;
  967. const std::size_t classes = symbolDatabase->classAndStructScopes.size();
  968. for (std::size_t i = 0; i < classes; ++i) {
  969. const Scope * scope = symbolDatabase->classAndStructScopes[i];
  970. std::list<Function>::const_iterator func;
  971. for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
  972. if (func->type == Function::eOperatorEqual && func->access != Private) {
  973. // skip "deleted" functions - cannot be called anyway
  974. if (func->isDelete)
  975. continue;
  976. // use definition for check so we don't have to deal with qualification
  977. if (!(Token::Match(func->retDef, "%type% &") && func->retDef->str() == scope->className)) {
  978. // make sure we really have a copy assignment operator
  979. if (Token::Match(func->tokenDef->tokAt(2), "const| %var% &")) {
  980. if (func->tokenDef->strAt(2) == "const" &&
  981. func->tokenDef->strAt(3) == scope->className)
  982. operatorEqReturnError(func->retDef, scope->className);
  983. else if (func->tokenDef->strAt(2) == scope->c

Large files files are truncated, but you can click here to view the full file