diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp index 324b81581..e556f1461 100644 --- a/lib/checkfunctions.cpp +++ b/lib/checkfunctions.cpp @@ -252,6 +252,7 @@ static const Token *checkMissingReturnScope(const Token *tok, const Library &lib void CheckFunctions::checkMissingReturn() { + const bool inconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope *scope : symbolDatabase->functionScopes) { const Function *function = scope->function; @@ -266,8 +267,20 @@ void CheckFunctions::checkMissingReturn() if (Function::returnsVoid(function, true)) continue; const Token *errorToken = checkMissingReturnScope(scope->bodyEnd, mSettings->library); - if (errorToken) + if (errorToken) { missingReturnError(errorToken); + continue; + } + if (inconclusive && Token::simpleMatch(scope->bodyEnd->tokAt(-2), ") ; }")) { + const Token *ftok = scope->bodyEnd->linkAt(-2)->previous(); + if (mSettings->library.isNotLibraryFunction(ftok)) { + const Token *tok = ftok; + while (Token::Match(tok->tokAt(-2), "%name% :: %name%")) + tok = tok->tokAt(-2); + if (Token::Match(tok->previous(), "[;{}] %name% (|::")) + missingReturnError(tok, Certainty::inconclusive); + } + } } } @@ -338,8 +351,13 @@ static const Token *checkMissingReturnScope(const Token *tok, const Library &lib return nullptr; if (tok->str() == "goto" && !isForwardJump(tok)) return nullptr; - if (Token::Match(tok, "%name% (") && !library.isnotnoreturn(tok)) - return nullptr; + if (Token::Match(tok, "%name% (") && !library.isnotnoreturn(tok)) { + const Token *start = tok; + while (Token::Match(start->tokAt(-2), "%name% :: %name%")) + start = start->tokAt(-2); + if (Token::Match(start->previous(), "[;{}] %name% ::|(")) + return nullptr; + } if (Token::Match(tok, "[;{}] %name% :")) return tok; if (Token::Match(tok, "; !!}") && !lastStatement) @@ -348,10 +366,10 @@ static const Token *checkMissingReturnScope(const Token *tok, const Library &lib return nullptr; } -void CheckFunctions::missingReturnError(const Token* tok) +void CheckFunctions::missingReturnError(const Token* tok, Certainty::CertaintyLevel certainty) { reportError(tok, Severity::error, "missingReturn", - "Found a exit path from function with non-void return type that has missing return statement", CWE758, Certainty::normal); + "Found a exit path from function with non-void return type that has missing return statement", CWE758, certainty); } //--------------------------------------------------------------------------- // Detect passing wrong values to functions like atan(0, x); diff --git a/lib/checkfunctions.h b/lib/checkfunctions.h index 30dd816bd..4e1623b18 100644 --- a/lib/checkfunctions.h +++ b/lib/checkfunctions.h @@ -122,7 +122,7 @@ private: void memsetZeroBytesError(const Token *tok); void memsetFloatError(const Token *tok, const std::string &var_value); void memsetValueOutOfRangeError(const Token *tok, const std::string &value); - void missingReturnError(const Token *tok); + void missingReturnError(const Token *tok, Certainty::CertaintyLevel certainty=Certainty::normal); void copyElisionError(const Token *tok); void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const OVERRIDE { diff --git a/test/testfunctions.cpp b/test/testfunctions.cpp index f9a2ee003..9b37f8786 100644 --- a/test/testfunctions.cpp +++ b/test/testfunctions.cpp @@ -39,6 +39,7 @@ private: settings.severity.enable(Severity::warning); settings.severity.enable(Severity::performance); settings.severity.enable(Severity::portability); + settings.certainty.enable(Certainty::inconclusive); settings.libraries.emplace_back("posix"); settings.standards.c = Standards::C11; settings.standards.cpp = Standards::CPP11; @@ -1490,7 +1491,11 @@ private: check("int f(int x) { assert(0); }"); ASSERT_EQUALS("", errout.str()); + + check("int f(int x) { RETURN(0); }"); + ASSERT_EQUALS("[test.cpp:1]: (error, inconclusive) Found a exit path from function with non-void return type that has missing return statement\n", errout.str()); } + // NRVO check void returnLocalStdMove1() { check("struct A{}; A f() { A var; return std::move(var); }");