diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 56b04edb4b0..ff4320be8c1 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -991,7 +991,7 @@ static const Token * getVariableInitExpression(const Variable * var) const Token* isInLoopCondition(const Token* tok) { const Token* top = tok->astTop(); - return top && Token::Match(top->previous(), "for|while (") ? top : nullptr; + return Token::Match(top->previous(), "for|while (") ? top : nullptr; } /// If tok2 comes after tok1 diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp index a1a71c5675c..09a24157470 100644 --- a/lib/checkcondition.cpp +++ b/lib/checkcondition.cpp @@ -834,8 +834,6 @@ static std::string innerSmtString(const Token * tok) { if (!tok) return "if"; - if (!tok->astTop()) - return "if"; const Token * top = tok->astTop(); if (top->str() == "(" && top->astOperand1()) return top->astOperand1()->str(); @@ -1119,7 +1117,7 @@ static std::string conditionString(const Token * tok) static bool isIfConstexpr(const Token* tok) { const Token* const top = tok->astTop(); - return top && Token::simpleMatch(top->astOperand1(), "if") && top->astOperand1()->isConstexpr(); + return Token::simpleMatch(top->astOperand1(), "if") && top->astOperand1()->isConstexpr(); } void CheckCondition::checkIncorrectLogicOperator() diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 9fa60ae233d..b89a5918c76 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2307,8 +2307,6 @@ static const Token * getSingleExpressionInBlock(const Token * tok) if (!tok) return nullptr; const Token * top = tok->astTop(); - if (!top) - return nullptr; const Token * nextExpression = nextAfterAstRightmostLeaf(top); if (!Token::simpleMatch(nextExpression, "; }")) return nullptr; diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 07fb63ac8cb..866a450670e 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -1613,22 +1613,8 @@ static const Token* skipLocalVars(const Token* const tok) if (Token::simpleMatch(tok, "{")) return skipLocalVars(tok->next()); - const Token *top = tok->astTop(); - if (!top) { - const Token *semi = Token::findsimplematch(tok, ";"); - if (!semi) - return tok; - if (!Token::Match(semi->previous(), "%var% ;")) - return tok; - const Token *varTok = semi->previous(); - const Variable *var = varTok->variable(); - if (!var) - return tok; - if (var->nameToken() != varTok) - return tok; - return skipLocalVars(semi->next()); - } if (tok->isAssignmentOp()) { + const Token *top = tok->astTop(); const Token *varTok = top->astOperand1(); const Variable *var = varTok->variable(); if (!var) diff --git a/lib/config.h b/lib/config.h index 0aecf2c52d5..ebd2ebbbe14 100644 --- a/lib/config.h +++ b/lib/config.h @@ -121,6 +121,16 @@ # define DEPRECATED #endif +// TODO: GCC apparently also supports this but there is no documentation on it +// returns_nonnull +#if __has_cpp_attribute (gnu::returns_nonnull) +# define RET_NONNULL [[gnu::returns_nonnull]] +#elif (defined(__clang__) && ((__clang_major__ > 3) || ((__clang_major__ == 3) && (__clang_minor__ >= 7)))) +# define RET_NONNULL __attribute__((returns_nonnull)) +#else +# define RET_NONNULL +#endif + #define REQUIRES(msg, ...) class=typename std::enable_if<__VA_ARGS__::value>::type #include diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index 17e340a5014..b779aac8e87 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -585,7 +585,7 @@ namespace { return Break(Analyzer::Terminate::Bail); } else if (tok->str() == ";" && tok->astParent()) { Token* top = tok->astTop(); - if (top && Token::Match(top->previous(), "for|while (") && Token::simpleMatch(top->link(), ") {")) { + if (Token::Match(top->previous(), "for|while (") && Token::simpleMatch(top->link(), ") {")) { Token* endCond = top->link(); Token* endBlock = endCond->linkAt(1); Token* condTok = getCondTok(top); diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 97c1756a4c0..95fce1bb958 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -509,7 +509,7 @@ void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty) programMemoryParseCondition(pm, tok, nullptr, *settings, b); const Token* origin = tok; const Token* top = tok->astTop(); - if (top && Token::Match(top->previous(), "for|while|if (") && !Token::simpleMatch(tok->astParent(), "?")) { + if (Token::Match(top->previous(), "for|while|if (") && !Token::simpleMatch(tok->astParent(), "?")) { origin = top->link()->next(); if (!b && origin->link()) { origin = origin->link(); @@ -1727,8 +1727,6 @@ namespace { return {unknown()}; for (const Token* tok = scope->bodyStart->next(); precedes(tok, scope->bodyEnd); tok = tok->next()) { const Token* top = tok->astTop(); - if (!top) - return {unknown()}; if (Token::simpleMatch(top, "return") && top->astOperand1()) return {execute(top->astOperand1())}; diff --git a/lib/reverseanalyzer.cpp b/lib/reverseanalyzer.cpp index 04aba5bc203..d8b2def1216 100644 --- a/lib/reverseanalyzer.cpp +++ b/lib/reverseanalyzer.cpp @@ -295,7 +295,7 @@ namespace { if (!condTok) break; Analyzer::Action condAction = analyzeRecursive(condTok); - const bool inLoop = condTok->astTop() && Token::Match(condTok->astTop()->previous(), "for|while ("); + const bool inLoop = Token::Match(condTok->astTop()->previous(), "for|while ("); // Evaluate condition of for and while loops first if (inLoop) { if (Token::findmatch(tok->link(), "goto|break", tok)) diff --git a/lib/token.h b/lib/token.h index ca7e7ce1e03..38481ed6a99 100644 --- a/lib/token.h +++ b/lib/token.h @@ -919,9 +919,9 @@ class CPPCHECKLIB Token { * @param prepend Insert the new token before this token when it's not * the first one on the tokens list. */ - Token* insertToken(const std::string& tokenStr, const std::string& originalNameStr = emptyString, const std::string& macroNameStr = emptyString, bool prepend = false); + RET_NONNULL Token* insertToken(const std::string& tokenStr, const std::string& originalNameStr = emptyString, const std::string& macroNameStr = emptyString, bool prepend = false); - Token* insertTokenBefore(const std::string& tokenStr, const std::string& originalNameStr = emptyString, const std::string& macroNameStr = emptyString) + RET_NONNULL Token* insertTokenBefore(const std::string& tokenStr, const std::string& originalNameStr = emptyString, const std::string& macroNameStr = emptyString) { return insertToken(tokenStr, originalNameStr, macroNameStr, true); } @@ -1224,7 +1224,7 @@ class CPPCHECKLIB Token { /** * @return the first token of the next argument. Does only work on argument * lists. Requires that Tokenizer::createLinks2() has been called before. - * Returns 0, if there is no next argument. + * Returns nullptr, if there is no next argument. */ const Token* nextArgument() const; Token *nextArgument(); @@ -1232,14 +1232,14 @@ class CPPCHECKLIB Token { /** * @return the first token of the next argument. Does only work on argument * lists. Should be used only before Tokenizer::createLinks2() was called. - * Returns 0, if there is no next argument. + * Returns nullptr, if there is no next argument. */ const Token* nextArgumentBeforeCreateLinks2() const; /** * @return the first token of the next template argument. Does only work on template argument * lists. Requires that Tokenizer::createLinks2() has been called before. - * Returns 0, if there is no next argument. + * Returns nullptr, if there is no next argument. */ const Token* nextTemplateArgument() const; @@ -1477,14 +1477,14 @@ class CPPCHECKLIB Token { return nullptr; } - Token *astTop() { + RET_NONNULL Token *astTop() { Token *ret = this; while (ret->mImpl->mAstParent) ret = ret->mImpl->mAstParent; return ret; } - const Token *astTop() const { + RET_NONNULL const Token *astTop() const { const Token *ret = this; while (ret->mImpl->mAstParent) ret = ret->mImpl->mAstParent; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index c19799ea412..5f88aa01b99 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -635,7 +635,7 @@ static bool isConditionKnown(const Token* tok, bool then) while (parent && (parent->str() == op || parent->str() == "!" || parent->isCast())) parent = parent->astParent(); const Token* top = tok->astTop(); - if (top && Token::Match(top->previous(), "if|while|for (")) + if (Token::Match(top->previous(), "if|while|for (")) return parent == top || Token::simpleMatch(parent, ";"); return parent && parent->str() != op; } @@ -2372,7 +2372,7 @@ const Token* ValueFlow::getEndOfExprScope(const Token* tok, const Scope* default end = varEnd; const Token* top = var->nameToken()->astTop(); - if (top && Token::simpleMatch(top->tokAt(-1), "if (")) { // variable declared in if (...) + if (Token::simpleMatch(top->tokAt(-1), "if (")) { // variable declared in if (...) const Token* elseTok = top->link()->linkAt(1); if (Token::simpleMatch(elseTok, "} else {") && tok->scope()->isNestedIn(elseTok->tokAt(2)->scope())) end = tok->scope()->bodyEnd; @@ -4751,8 +4751,6 @@ struct ConditionHandler { continue; const Token* top = tok->astTop(); - if (!top) - continue; if (!Token::Match(top->previous(), "if|while|for (") && !Token::Match(tok->astParent(), "&&|%oror%|?|!")) continue; @@ -4927,8 +4925,6 @@ struct ConditionHandler { const Settings& settings, const std::set& skippedFunctions) const { traverseCondition(symboldatabase, settings, skippedFunctions, [&](const Condition& cond, Token* condTok, const Scope* scope) { - Token* top = condTok->astTop(); - const MathLib::bigint path = cond.getPath(); const bool allowKnown = path == 0; @@ -5003,8 +4999,7 @@ struct ConditionHandler { } } - if (!top) - return; + Token* top = condTok->astTop(); if (top->previous()->isExpandedMacro()) { for (std::list* values : {&thenValues, &elseValues}) { @@ -7086,7 +7081,7 @@ static void valueFlowContainerSize(const TokenList& tokenlist, !Token::Match(nameToken, "%name% (")) continue; } - if (nameToken->astTop() && Token::Match(nameToken->astTop()->previous(), "for|while")) + if (Token::Match(nameToken->astTop()->previous(), "for|while")) known = !isVariableChanged(var, settings); std::vector values{ValueFlow::Value{size}}; values.back().valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;