clarify calculation: Fixed FP for 'a = (*p ? 1 : 2)'

This commit is contained in:
Daniel Marjamäki 2013-12-28 11:02:39 +01:00
parent 4a46029ba6
commit 4b72f01e99
5 changed files with 51 additions and 42 deletions

View File

@ -180,7 +180,7 @@ void CheckOther::clarifyCalculation()
const Scope * scope = symbolDatabase->functionScopes[i]; const Scope * scope = symbolDatabase->functionScopes[i];
for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
// ? operator where lhs is arithmetical expression // ? operator where lhs is arithmetical expression
if (tok->str() != "?" || !tok->astOperand1() || !tok->astOperand1()->isArithmeticalOp()) if (tok->str() != "?" || !tok->astOperand1() || !tok->astOperand1()->isArithmeticalOp() || !tok->astOperand1()->isCalculation())
continue; continue;
// Is code clarified by parentheses already? // Is code clarified by parentheses already?

View File

@ -22,7 +22,6 @@
#include "symboldatabase.h" #include "symboldatabase.h"
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
#include <stack>
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Register this check class (by creating a static instance of it) // Register this check class (by creating a static instance of it)
@ -219,45 +218,6 @@ void CheckSizeof::sizeofsizeofError(const Token *tok)
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
static bool isCalculation(const Token *op)
{
if (!op)
return false;
if (!Token::Match(op, "%cop%|++|--"))
return false;
if (Token::Match(op, "*|&")) {
// dereference or address-of?
if (!op->astOperand2())
return false;
if (op->astOperand2()->str() == "[")
return false;
// type specification?
std::stack<const Token *> operands;
operands.push(op);
while (!operands.empty()) {
const Token *item = operands.top();
operands.pop();
if (item->isNumber() || item->varId() > 0)
return true;
if (item->astOperand1())
operands.push(item->astOperand1());
if (item->astOperand2())
operands.push(item->astOperand2());
else if (Token::Match(item, "*|&"))
return false;
}
// type specification => return false
return false;
}
return true;
}
void CheckSizeof::sizeofCalculation() void CheckSizeof::sizeofCalculation()
{ {
@ -267,7 +227,7 @@ void CheckSizeof::sizeofCalculation()
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "sizeof (")) { if (Token::simpleMatch(tok, "sizeof (")) {
const Token *argument = tok->next()->astOperand2(); const Token *argument = tok->next()->astOperand2();
if (isCalculation(argument) && (!argument->isExpandedMacro() || _settings->inconclusive)) if (argument && argument->isCalculation() && (!argument->isExpandedMacro() || _settings->inconclusive))
sizeofCalculationError(argument, argument->isExpandedMacro()); sizeofCalculationError(argument, argument->isExpandedMacro());
} }
} }

View File

@ -27,6 +27,7 @@
#include <cctype> #include <cctype>
#include <sstream> #include <sstream>
#include <map> #include <map>
#include <stack>
Token::Token(Token **t) : Token::Token(Token **t) :
tokensBack(t), tokensBack(t),
@ -1143,6 +1144,42 @@ void Token::astOperand2(Token *tok)
_astOperand2 = tok; _astOperand2 = tok;
} }
bool Token::isCalculation() const
{
if (!Token::Match(this, "%cop%|++|--"))
return false;
if (Token::Match(this, "*|&")) {
// dereference or address-of?
if (!this->astOperand2())
return false;
if (this->astOperand2()->str() == "[")
return false;
// type specification?
std::stack<const Token *> operands;
operands.push(this);
while (!operands.empty()) {
const Token *op = operands.top();
operands.pop();
if (op->isNumber() || op->varId() > 0)
return true;
if (op->astOperand1())
operands.push(op->astOperand1());
if (op->astOperand2())
operands.push(op->astOperand2());
else if (Token::Match(op, "*|&"))
return false;
}
// type specification => return false
return false;
}
return true;
}
void Token::printAst() const void Token::printAst() const
{ {
bool title = false; bool title = false;

View File

@ -672,6 +672,15 @@ public:
return ret; return ret;
} }
/**
* Is current token a calculation? Only true for operands.
* For '*' and '&' tokens it is looked up if this is a
* dereference or address-of. A dereference or address-of is not
* counted as a calculation.
* @return returns true if current token is a calculation
*/
bool isCalculation() const;
void clearAst() { void clearAst() {
_astOperand1 = _astOperand2 = _astParent = NULL; _astOperand1 = _astOperand2 = _astParent = NULL;
} }

View File

@ -4174,6 +4174,9 @@ private:
" return shift < sizeof(int64_t)*8 ? 1 : 2;\n" " return shift < sizeof(int64_t)*8 ? 1 : 2;\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("void f() { a = *p ? 1 : 2; }");
ASSERT_EQUALS("", errout.str());
} }
void clarifyStatement() { void clarifyStatement() {