void CheckCondition::oppositeInnerCondition() { if (!_settings->isEnabled("warning")) return; const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); for (std::list<Scope>::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { if (scope->type != Scope::eIf) continue; if (!Token::simpleMatch(scope->classDef->linkAt(1), ") {")) continue; bool nonlocal = false; // nonlocal variable used in condition std::set<unsigned int> vars; // variables used in condition for (const Token *cond = scope->classDef->linkAt(1); cond != scope->classDef; cond = cond->previous()) { if (cond->varId()) { vars.insert(cond->varId()); const Variable *var = cond->variable(); nonlocal |= (var && (!var->isLocal() || var->isStatic()) && !var->isArgument()); // TODO: if var is pointer check what it points at nonlocal |= (var && (var->isPointer() || var->isReference())); } else if (cond->isName()) { // varid is 0. this is possibly a nonlocal variable.. nonlocal |= Token::Match(cond->astParent(), "%cop%|("); } } // parse until inner condition is reached.. const Token *ifToken = nullptr; for (const Token *tok = scope->classStart; tok && tok != scope->classEnd; tok = tok->next()) { if (Token::simpleMatch(tok, "if (")) { ifToken = tok; break; } if (Token::Match(tok, "%type% (") && nonlocal) // function call -> bailout if there are nonlocal variables break; else if ((tok->varId() && vars.find(tok->varId()) != vars.end()) || (!tok->varId() && nonlocal)) { if (Token::Match(tok, "%name% ++|--|=")) break; if (Token::Match(tok, "%name% [")) { const Token *tok2 = tok->linkAt(1); while (Token::simpleMatch(tok2, "] [")) tok2 = tok2->linkAt(1); if (Token::simpleMatch(tok2, "] =")) break; } if (Token::Match(tok->previous(), "++|--|& %name%")) break; if (tok->variable() && Token::Match(tok, "%name% . %name% (") && !tok->variable()->isConst()) { const Function* function = tok->tokAt(2)->function(); if (!function || !function->isConst()) break; } if (Token::Match(tok->previous(), "[(,] %name% [,)]")) { // is variable unchanged? default is false.. bool unchanged = false; // locate start parentheses in function call.. unsigned int argumentNumber = 0; const Token *start = tok->previous(); while (start && start->str() == ",") { start = start->astParent(); ++argumentNumber; } start = start ? start->previous() : nullptr; if (start && start->function()) { const Variable *arg = start->function()->getArgumentVar(argumentNumber); if (arg && !arg->isPointer() && !arg->isReference()) unchanged = true; } if (!unchanged) break; } } } if (!ifToken) continue; // Condition.. const Token *cond1 = scope->classDef->next()->astOperand2(); const Token *cond2 = ifToken->next()->astOperand2(); if (isOppositeCond(false, cond1, cond2, _settings->library.functionpure)) oppositeInnerConditionError(scope->classDef, cond2); } }
void CheckCondition::oppositeInnerCondition() { if (!_settings->isEnabled(Settings::WARNING)) return; const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); for (std::list<Scope>::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { if (scope->type != Scope::eIf) continue; if (!Token::simpleMatch(scope->classDef->linkAt(1), ") {")) continue; bool nonlocal = false; // nonlocal variable used in condition std::set<unsigned int> vars; // variables used in condition for (const Token *cond = scope->classDef->linkAt(1); cond != scope->classDef; cond = cond->previous()) { if (cond->varId()) { vars.insert(cond->varId()); const Variable *var = cond->variable(); nonlocal |= (var && (!var->isLocal() || var->isStatic()) && !var->isArgument()); // TODO: if var is pointer check what it points at nonlocal |= (var && (var->isPointer() || var->isReference())); } else if (!nonlocal && cond->isName()) { // varid is 0. this is possibly a nonlocal variable.. nonlocal = Token::Match(cond->astParent(), "%cop%|("); } } // parse until inner condition is reached.. const Token *ifToken = nullptr; for (const Token *tok = scope->classStart; tok && tok != scope->classEnd; tok = tok->next()) { if (Token::simpleMatch(tok, "if (")) { ifToken = tok; break; } if (Token::Match(tok, "%type% (") && nonlocal) // function call -> bailout if there are nonlocal variables break; // bailout if loop is seen. // TODO: handle loops. if (Token::Match(tok, "for|while|do")) break; if ((tok->varId() && vars.find(tok->varId()) != vars.end()) || (!tok->varId() && nonlocal)) { if (Token::Match(tok, "%name% %assign%|++|--")) break; if (Token::Match(tok, "%name% [")) { const Token *tok2 = tok->linkAt(1); while (Token::simpleMatch(tok2, "] [")) tok2 = tok2->linkAt(1); if (Token::Match(tok2, "] %assign%|++|--")) break; } if (Token::Match(tok->previous(), "++|--|& %name%")) break; if (tok->variable() && !tok->variable()->isConst() && Token::Match(tok, "%name% . %name% (")) { const Function* function = tok->tokAt(2)->function(); if (!function || !function->isConst()) break; } if (Token::Match(tok->previous(), "[(,] %name% [,)]") && isParameterChanged(tok)) break; } } if (!ifToken) continue; // Condition.. const Token *cond1 = scope->classDef->next()->astOperand2(); const Token *cond2 = ifToken->next()->astOperand2(); if (isOppositeCond(false, _tokenizer->isCPP(), cond1, cond2, _settings->library, true)) oppositeInnerConditionError(scope->classDef, cond2); } }