From c6f7a78ebb1a0b4094af2773cdd9fe2fde4a5979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 10 Jul 2021 08:36:54 +0200 Subject: [PATCH] missingReturn; Fixed false positives --- lib/checkfunctions.cpp | 20 ++++++++++++-------- lib/token.h | 6 ------ test/testfunctions.cpp | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp index 160652e19..25fbce3f3 100644 --- a/lib/checkfunctions.cpp +++ b/lib/checkfunctions.cpp @@ -271,21 +271,26 @@ void CheckFunctions::checkMissingReturn() static const Token *checkMissingReturnScope(const Token *tok) { - tok = tok->previous(); - while (tok) { + const Token *lastStatement = nullptr; + while ((tok = tok->previous()) != nullptr) { if (tok->str() == "{") - return tok->next(); + return lastStatement ? lastStatement : tok->next(); if (tok->str() == "}") { for (const Token *prev = tok->link()->previous(); prev && prev->scope() == tok->scope() && !Token::Match(prev, "[;{}]"); prev = prev->previous()) { if (prev->isKeyword() && Token::Match(prev, "return|throw")) return nullptr; } if (tok->scope()->type == Scope::ScopeType::eSwitch) { - // find break/default + // find reachable break / !default bool hasDefault = false; + bool reachable = false; for (const Token *switchToken = tok->link(); switchToken != tok; switchToken = switchToken->next()) { - if (Token::simpleMatch(switchToken, "break ;")) + if (reachable && Token::simpleMatch(switchToken, "break ;")) return switchToken; + if (switchToken->isKeyword() && Token::Match(switchToken, "return|throw")) + reachable = false; + if (Token::Match(switchToken, "case|default")) + reachable = true; if (Token::simpleMatch(switchToken, "default :")) hasDefault = true; else if (switchToken->str() == "{" && switchToken->scope()->isLoopScope()) @@ -309,9 +314,8 @@ static const Token *checkMissingReturnScope(const Token *tok) } if (tok->isKeyword() && Token::Match(tok, "return|throw")) return nullptr; - if (Token::Match(tok, "; !!}")) - return tok->next(); - tok = tok->previous(); + if (Token::Match(tok, "; !!}") && !lastStatement) + lastStatement = tok->next(); } return nullptr; } diff --git a/lib/token.h b/lib/token.h index 77ca6e107..751e1ae64 100644 --- a/lib/token.h +++ b/lib/token.h @@ -385,12 +385,6 @@ public: mTokType == eBoolean || mTokType == eLiteral || mTokType == eEnumerator); setFlag(fIsLiteral, memoizedIsLiteral); } - void isKeyword(const bool kwd) { - if (kwd) - tokType(eKeyword); - else if (mTokType == eKeyword) - tokType(eName); - } bool isKeyword() const { return mTokType == eKeyword; } diff --git a/test/testfunctions.cpp b/test/testfunctions.cpp index b82aba677..5422fd15b 100644 --- a/test/testfunctions.cpp +++ b/test/testfunctions.cpp @@ -1379,6 +1379,13 @@ private: check("auto foo4() -> void {}"); ASSERT_EQUALS("", errout.str()); + // unreachable code.. + check("int foo(int x) {\n" + " return 1;\n" + " (void)x;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + // switch check("int f() {\n" " switch (x) {\n" @@ -1388,6 +1395,14 @@ private: "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Found a exit path from function with non-void return type that has missing return statement\n", errout.str()); + check("int f() {\n" + " switch (x) {\n" + " case 1: return 2; break;\n" + " default: return 1;\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + // if/else check("int f(int x) {\n" " if (x) {\n"