Refactoring: Move isReturn() to astutils and rename it to isReturnScope()

This commit is contained in:
Daniel Marjamäki 2016-01-16 18:52:34 +01:00
parent efff2c5397
commit 522de81cc7
4 changed files with 88 additions and 36 deletions

View File

@ -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()) {

View File

@ -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);

View File

@ -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) {

49
test/testastutils.cpp Normal file
View File

@ -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)