Refactoring: Move isReturn() to astutils and rename it to isReturnScope()
This commit is contained in:
parent
efff2c5397
commit
522de81cc7
|
@ -269,6 +269,36 @@ bool isWithoutSideEffects(bool cpp, const Token* tok)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool isReturnScope(const Token * const endToken)
|
||||
{
|
||||
if (!endToken || endToken->str() != "}")
|
||||
return false;
|
||||
|
||||
const Token *prev = endToken->previous();
|
||||
if (prev && Token::simpleMatch(prev->previous(), "} ;"))
|
||||
prev = prev->previous();
|
||||
|
||||
if (Token::simpleMatch(prev, "}")) {
|
||||
if (Token::simpleMatch(prev->link()->tokAt(-2), "} else {"))
|
||||
return isReturnScope(prev) && isReturnScope(prev->link()->tokAt(-2));
|
||||
if (Token::simpleMatch(prev->link()->previous(), ") {") &&
|
||||
Token::simpleMatch(prev->link()->linkAt(-1)->previous(), "switch (") &&
|
||||
!Token::findsimplematch(prev->link(), "break", prev)) {
|
||||
return true;
|
||||
}
|
||||
} else if (Token::simpleMatch(prev, ";")) {
|
||||
// noreturn function
|
||||
if (Token::simpleMatch(prev->previous(), ") ;") && Token::Match(prev->linkAt(-1)->tokAt(-2), "[;{}] %name% ("))
|
||||
return true;
|
||||
// return/goto statement
|
||||
prev = prev->previous();
|
||||
while (prev && !Token::Match(prev, ";|{|}|return|goto|throw|continue|break"))
|
||||
prev = prev->previous();
|
||||
return prev && prev->isName();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isVariableChanged(const Token *start, const Token *end, const unsigned int varid)
|
||||
{
|
||||
for (const Token *tok = start; tok != end; tok = tok->next()) {
|
||||
|
|
|
@ -64,6 +64,9 @@ bool isConstExpression(const Token *tok, const std::set<std::string> &constFunct
|
|||
|
||||
bool isWithoutSideEffects(bool cpp, const Token* tok);
|
||||
|
||||
/** Is scope a return scope (scope will unconditionally return) */
|
||||
bool isReturnScope(const Token *endToken);
|
||||
|
||||
/** Is variable changed in block of code? */
|
||||
bool isVariableChanged(const Token *start, const Token *end, const unsigned int varid);
|
||||
|
||||
|
|
|
@ -292,36 +292,6 @@ static bool bailoutSelfAssignment(const Token * const tok)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool isReturn(const Token *tok)
|
||||
{
|
||||
if (!tok)
|
||||
return false;
|
||||
|
||||
const Token *prev = tok->previous();
|
||||
if (prev && Token::simpleMatch(prev->previous(), "} ;"))
|
||||
prev = prev->previous();
|
||||
|
||||
if (Token::simpleMatch(prev, "}")) {
|
||||
if (Token::simpleMatch(prev->link()->tokAt(-2), "} else {"))
|
||||
return isReturn(prev) && isReturn(prev->link()->tokAt(-2));
|
||||
if (Token::simpleMatch(prev->link()->previous(), ") {") &&
|
||||
Token::simpleMatch(prev->link()->linkAt(-1)->previous(), "switch (") &&
|
||||
!Token::findsimplematch(prev->link(), "break", prev)) {
|
||||
return true;
|
||||
}
|
||||
} else if (Token::simpleMatch(prev, ";")) {
|
||||
// noreturn function
|
||||
if (Token::simpleMatch(prev->previous(), ") ;") && Token::Match(prev->linkAt(-1)->tokAt(-2), "[;{}] %name% ("))
|
||||
return true;
|
||||
// return/goto statement
|
||||
prev = prev->previous();
|
||||
while (prev && !Token::Match(prev, ";|{|}|return|goto|throw|continue|break"))
|
||||
prev = prev->previous();
|
||||
return prev && prev->isName();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Add token value. Return true if value is added. */
|
||||
static bool addValue(Token *tok, const ValueFlow::Value &value)
|
||||
{
|
||||
|
@ -1052,7 +1022,7 @@ static bool valueFlowForward(Token * const startToken,
|
|||
++indentlevel;
|
||||
else if (indentlevel >= 0 && tok2->str() == "}") {
|
||||
--indentlevel;
|
||||
if (indentlevel <= 0 && isReturn(tok2) && Token::Match(tok2->link()->previous(), "else|) {")) {
|
||||
if (indentlevel <= 0 && isReturnScope(tok2) && Token::Match(tok2->link()->previous(), "else|) {")) {
|
||||
const Token *condition = tok2->link();
|
||||
const bool iselse = Token::simpleMatch(condition->tokAt(-2), "} else {");
|
||||
if (iselse)
|
||||
|
@ -1173,7 +1143,7 @@ static bool valueFlowForward(Token * const startToken,
|
|||
// goto '}'
|
||||
tok2 = startToken1->link();
|
||||
|
||||
if (condAlwaysTrue && isReturn(tok2))
|
||||
if (condAlwaysTrue && isReturnScope(tok2))
|
||||
return false;
|
||||
|
||||
continue;
|
||||
|
@ -1229,8 +1199,8 @@ static bool valueFlowForward(Token * const startToken,
|
|||
}
|
||||
}
|
||||
|
||||
// stop after conditional noreturn scopes that are executed
|
||||
if (isReturn(end)) {
|
||||
// stop after conditional return scopes that are executed
|
||||
if (isReturnScope(end)) {
|
||||
std::list<ValueFlow::Value>::iterator it;
|
||||
for (it = values.begin(); it != values.end();) {
|
||||
if (conditionIsTrue(tok2->next()->astOperand2(), getProgramMemory(tok2, varid, *it)))
|
||||
|
@ -1697,7 +1667,7 @@ static void valueFlowAfterCondition(TokenList *tokenlist, SymbolDatabase* symbol
|
|||
continue;
|
||||
}
|
||||
|
||||
bool isreturn = (codeblock == 1 && isReturn(after));
|
||||
bool isreturn = (codeblock == 1 && isReturnScope(after));
|
||||
|
||||
if (Token::simpleMatch(after, "} else {")) {
|
||||
after = after->linkAt(2);
|
||||
|
@ -1706,7 +1676,7 @@ static void valueFlowAfterCondition(TokenList *tokenlist, SymbolDatabase* symbol
|
|||
bailout(tokenlist, errorLogger, after, "possible noreturn scope");
|
||||
continue;
|
||||
}
|
||||
isreturn |= (codeblock == 2 && isReturn(after));
|
||||
isreturn |= (codeblock == 2 && isReturnScope(after));
|
||||
}
|
||||
|
||||
if (!isreturn) {
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Cppcheck - A tool for static C/C++ code analysis
|
||||
* Copyright (C) 2007-2016 Cppcheck team.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "astutils.h"
|
||||
#include "tokenizer.h"
|
||||
#include "testsuite.h"
|
||||
|
||||
|
||||
class TestAstUtils : public TestFixture {
|
||||
public:
|
||||
TestAstUtils() : TestFixture("TestAstUtils") {
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void run() {
|
||||
TEST_CASE(isReturnScope);
|
||||
}
|
||||
|
||||
Tokenizer tokenize(const char code[], const char filename[]) {
|
||||
Tokenizer tokenizer(&settings0, this);
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize(istr, "test.cpp");
|
||||
return tokenizer;
|
||||
}
|
||||
|
||||
void isReturnScope() const {
|
||||
const Tokenizer &t1 = tokenize("void f() { if (a) { return; } }");
|
||||
ASSERT_EQUALS(true, ::isReturnScope(Token::findsimplematch(t1.tokens(),"} }")));
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestAstUtils)
|
Loading…
Reference in New Issue