Improved cast detection in AST:

-> Make use of it in checkother.cpp

Use tokenizer simplification instead of reimplementation for test suite
This commit is contained in:
PKEuS 2014-05-24 11:28:43 +02:00
parent b0b0562247
commit b78131cfcf
3 changed files with 27 additions and 53 deletions

View File

@ -185,22 +185,6 @@ static bool isOppositeCond(const Token * const cond1, const Token * const cond2,
(comp1 == ">=" && comp2 == "<")); (comp1 == ">=" && comp2 == "<"));
} }
static bool isPossibleCast(const Token * const startPar)
{
if (!Token::Match(startPar, "( %type%"))
return false;
const Token *tok;
for (tok = startPar->tokAt(2); tok; tok = tok->next()) {
if (tok->str() == ")")
return true;
if (tok->varId()>0)
return false;
if (!Token::Match(tok,"%type%|*|&"))
return false;
}
return tok != nullptr;
}
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// The return value of fgetc(), getc(), ungetc(), getchar() etc. is an integer value. // The return value of fgetc(), getc(), ungetc(), getchar() etc. is an integer value.
// If this return value is stored in a character variable and then compared // If this return value is stored in a character variable and then compared
@ -2068,8 +2052,8 @@ void CheckOther::checkCharVariable()
else else
continue; continue;
// (x) & y => if x is a possible type then assume & is a address-of operator // Don't care about address-of operator
if (Token::simpleMatch(tok->previous(), ") &") && isPossibleCast(tok->linkAt(-1))) if (!tok->astOperand2())
continue; continue;
// it's ok with a bitwise and where the other operand is 0xff or less.. // it's ok with a bitwise and where the other operand is 0xff or less..

View File

@ -382,12 +382,18 @@ static bool iscast(const Token *tok)
return true; return true;
for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) { for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
if (tok2->link() && tok2->str() == "<")
tok2 = tok2->link()->next();
if (tok2->str() == ")") if (tok2->str() == ")")
return tok2->previous()->str() == "*" || return tok2->previous()->str() == "*" ||
(Token::Match(tok2, ") %any%") && (Token::Match(tok2, ") %any%") &&
(!tok2->next()->isOp() && !Token::Match(tok2->next(), "[[]);,?:.]"))); (tok2->strAt(1) == "&" || (!tok2->next()->isOp() && !Token::Match(tok2->next(), "[[]);,?:.]"))));
if (!Token::Match(tok2, "%var%|*|&|::")) if (!Token::Match(tok2, "%var%|*|&|::"))
return false; return false;
if (tok2->isStandardType())
return true;
} }
return false; return false;

View File

@ -585,6 +585,7 @@ private:
TEST_CASE(astunaryop); TEST_CASE(astunaryop);
TEST_CASE(astfunction); TEST_CASE(astfunction);
TEST_CASE(asttemplate); TEST_CASE(asttemplate);
TEST_CASE(astcast);
TEST_CASE(startOfExecutableScope); TEST_CASE(startOfExecutableScope);
} }
@ -10384,55 +10385,31 @@ private:
static std::string testAst(const char code[],bool verbose=false) { static std::string testAst(const char code[],bool verbose=false) {
// tokenize given code.. // tokenize given code..
const Settings settings; const Settings settings;
TokenList tokenList(&settings); Tokenizer tokenList(&settings, nullptr);
std::istringstream istr(code); std::istringstream istr(code);
if (!tokenList.createTokens(istr,"test.cpp")) if (!tokenList.list.createTokens(istr,"test.cpp"))
return "ERROR"; return "ERROR";
for (Token *tok = tokenList.front(); tok; tok = tok->next()) { tokenList.combineOperators();
if (Token::Match(tok, "%or%|<<|>>|+|-|*|/|%|&|^ =")) { tokenList.createLinks();
tok->str(tok->str() + "="); tokenList.createLinks2();
tok->deleteNext();
} else if (Token::simpleMatch(tok, ": :")) {
tok->str("::");
tok->deleteNext();
} else if (Token::Match(tok, ">|<|= =")) {
tok->str(tok->str() + tok->strAt(1));
tok->deleteNext();
}
}
// Set links..
std::stack<Token *> links;
for (Token *tok = tokenList.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "(|[|{"))
links.push(tok);
else if (!links.empty() && Token::Match(tok,")|]|}")) {
Token::createMutualLinks(links.top(), tok);
links.pop();
} else if (Token::Match(tok, "< %type% >")) {
Token::createMutualLinks(tok, tok->tokAt(2));
} else if (Token::Match(tok, "< %type% * >")) {
Token::createMutualLinks(tok, tok->tokAt(3));
}
}
// Create AST.. // Create AST..
tokenList.createAst(); tokenList.list.createAst();
// Basic AST validation // Basic AST validation
for (const Token *tok = tokenList.front(); tok; tok = tok->next()) { for (const Token *tok = tokenList.list.front(); tok; tok = tok->next()) {
if (tok->astOperand2() && !tok->astOperand1() && tok->str() != ";" && tok->str() != ":") if (tok->astOperand2() && !tok->astOperand1() && tok->str() != ";" && tok->str() != ":")
return "Op2 but no Op1 for token: " + tok->str(); return "Op2 but no Op1 for token: " + tok->str();
} }
// Return stringified AST // Return stringified AST
if (verbose) if (verbose)
return tokenList.front()->astTop()->astStringVerbose(0,0); return tokenList.list.front()->astTop()->astStringVerbose(0, 0);
std::string ret; std::string ret;
std::set<const Token *> astTop; std::set<const Token *> astTop;
for (const Token *tok = tokenList.front(); tok; tok = tok->next()) { for (const Token *tok = tokenList.list.front(); tok; tok = tok->next()) {
if (tok->astOperand1() && astTop.find(tok->astTop()) == astTop.end()) { if (tok->astOperand1() && astTop.find(tok->astTop()) == astTop.end()) {
astTop.insert(tok->astTop()); astTop.insert(tok->astTop());
if (!ret.empty()) if (!ret.empty())
@ -10504,7 +10481,7 @@ private:
ASSERT_EQUALS("ax( whilex(", testAst("a(x) while (x)")); ASSERT_EQUALS("ax( whilex(", testAst("a(x) while (x)"));
ASSERT_EQUALS("ifx( i0= whilei(", testAst("if (x) { ({ int i = 0; while(i); }) };")); ASSERT_EQUALS("ifx( i0= whilei(", testAst("if (x) { ({ int i = 0; while(i); }) };"));
ASSERT_EQUALS("ifx( BUG_ON{!( i0= whilei(", testAst("if (x) { BUG_ON(!({int i=0; while(i);})); }")); ASSERT_EQUALS("ifx( BUG_ON{!( i0= whilei(", testAst("if (x) { BUG_ON(!({int i=0; while(i);})); }"));
ASSERT_EQUALS("v0= while{( v0= while{( v0=", testAst("({ v = 0; }); while (({ v = 0; }) != 0); while (({ v = 0; }) != 0);")); ASSERT_EQUALS("v0= while{0!=( v0= while{0!=( v0=", testAst("({ v = 0; }); while (({ v = 0; }) != 0); while (({ v = 0; }) != 0);"));
ASSERT_EQUALS("abc.1:?1+bd.1:?+=", testAst("a =(b.c ? : 1) + 1 + (b.d ? : 1);")); ASSERT_EQUALS("abc.1:?1+bd.1:?+=", testAst("a =(b.c ? : 1) + 1 + (b.d ? : 1);"));
@ -10607,6 +10584,13 @@ private:
ASSERT_EQUALS("AB: f( abc+=", testAst("struct A : public B<C*> { void f() { a=b+c; } };")); ASSERT_EQUALS("AB: f( abc+=", testAst("struct A : public B<C*> { void f() { a=b+c; } };"));
} }
void astcast() const {
ASSERT_EQUALS("ac&(=", testAst("a = (long)&c;"));
ASSERT_EQUALS("ac*(=", testAst("a = (Foo*)*c;"));
ASSERT_EQUALS("ac-(=", testAst("a = (long)-c;"));
ASSERT_EQUALS("ac(=", testAst("a = (some<strange, type>)c;"));
}
void compileLimits() { void compileLimits() {
const char raw_code[] = "#define PTR1 (* (* (* (* (* (* (* (* (* (*\n" const char raw_code[] = "#define PTR1 (* (* (* (* (* (* (* (* (* (*\n"
"#define PTR2 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1\n" "#define PTR2 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1\n"