Fix #9700 duplicateBranch false positive from missing scope operator :: in ast (#2646)

This commit is contained in:
shaneasd 2020-05-19 01:31:13 +08:00 committed by GitHub
parent f6f489ea49
commit 7bfd686f04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 63 additions and 3 deletions

View File

@ -1539,6 +1539,13 @@ std::string Token::astStringVerbose() const
return ret;
}
std::string Token::astStringZ3() const {
if (!astOperand1())
return str();
if (!astOperand2())
return "(" + str() + " " + astOperand1()->astStringZ3() + ")";
return "(" + str() + " " + astOperand1()->astStringZ3() + " " + astOperand2()->astStringZ3() + ")";
}
void Token::printValueFlow(bool xml, std::ostream &out) const
{

View File

@ -1282,6 +1282,8 @@ public:
std::string astStringVerbose() const;
std::string astStringZ3() const;
std::string expressionString() const;
void printAst(bool verbose, bool xml, std::ostream &out) const;

View File

@ -1020,6 +1020,17 @@ static void compilePrecedence3(Token *&tok, AST_state& state)
continue;
}
}
Token* leftToken = tok;
while (Token::Match(tok->next(), ":: %name%"))
{
Token* scopeToken = tok->next(); //The ::
scopeToken->astOperand1(leftToken);
scopeToken->astOperand2(scopeToken->next());
leftToken = scopeToken;
tok = scopeToken->next();
}
state.op.push(tok);
while (Token::Match(tok, "%name%|*|&|<|::")) {
if (tok->link())

View File

@ -188,6 +188,14 @@ private:
ASSERT_EQUALS(true, isSameExpression("void f() {double y = 1e1; (x + y) < (x + 10.0); } ", "+", "+"));
ASSERT_EQUALS(true, isSameExpression("void f() {double y = 1e1; (x + 10.0) < (y + x); } ", "+", "+"));
ASSERT_EQUALS(true, isSameExpression("void f() {double y = 1e1; double z = 10.0; (x + y) < (x + z); } ", "+", "+"));
ASSERT_EQUALS(true, isSameExpression("A + A", "A", "A"));
//https://trac.cppcheck.net/ticket/9700
ASSERT_EQUALS(true, isSameExpression("A::B + A::B;", "::", "::"));
ASSERT_EQUALS(false, isSameExpression("A::B + A::C;", "::", "::"));
ASSERT_EQUALS(true, isSameExpression("A::B* get() { if(x) return new A::B(true); else return new A::B(true); }", "new", "new"));
ASSERT_EQUALS(false, isSameExpression("A::B* get() { if(x) return new A::B(true); else return new A::C(true); }", "new", "new"));
ASSERT_EQUALS(true, true);
}
bool isVariableChanged(const char code[], const char startPattern[], const char endPattern[]) {

View File

@ -130,6 +130,7 @@ private:
TEST_CASE(duplicateBranch1); // tests extracted by http://www.viva64.com/en/b/0149/ ( Comparison between PVS-Studio and cppcheck ): Errors detected in Quake 3: Arena by PVS-Studio: Fragment 2
TEST_CASE(duplicateBranch2); // empty macro
TEST_CASE(duplicateBranch3);
TEST_CASE(duplicateBranch4);
TEST_CASE(duplicateExpression1);
TEST_CASE(duplicateExpression2); // ticket #2730
TEST_CASE(duplicateExpression3); // ticket #3317
@ -4101,6 +4102,17 @@ private:
ASSERT_EQUALS("", errout.str());
}
void duplicateBranch4() {
check("void* f(bool b) {\n"
" if (b) {\n"
" return new A::Y(true);\n"
" } else {\n"
" return new A::Z(true);\n"
" }\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void duplicateExpression1() {
check("void foo(int a) {\n"
" if (a == a) { }\n"

View File

@ -99,8 +99,8 @@ extern std::ostringstream errout;
extern std::ostringstream output;
#define TEST_CASE( NAME ) do { if ( prepareTest(#NAME) ) { setVerbose(false); NAME(); } } while(false)
#define ASSERT( CONDITION ) if (!assert_(__FILE__, __LINE__, CONDITION)) return
#define ASSERT_EQUALS( EXPECTED , ACTUAL ) if (!assertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL)) return
#define ASSERT( CONDITION ) if (!assert_(__FILE__, __LINE__, (CONDITION))) return
#define ASSERT_EQUALS( EXPECTED , ACTUAL ) if (!assertEquals(__FILE__, __LINE__, (EXPECTED), (ACTUAL))) return
#define ASSERT_EQUALS_WITHOUT_LINENUMBERS( EXPECTED , ACTUAL ) assertEqualsWithoutLineNumbers(__FILE__, __LINE__, EXPECTED, ACTUAL)
#define ASSERT_EQUALS_DOUBLE( EXPECTED , ACTUAL, TOLERANCE ) assertEqualsDouble(__FILE__, __LINE__, EXPECTED, ACTUAL, TOLERANCE)
#define ASSERT_EQUALS_MSG( EXPECTED , ACTUAL, MSG ) assertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL, MSG)

View File

@ -461,6 +461,7 @@ private:
TEST_CASE(astcase);
TEST_CASE(astrefqualifier);
TEST_CASE(astvardecl);
TEST_CASE(astnewscoped);
TEST_CASE(startOfExecutableScope);
@ -7376,7 +7377,7 @@ private:
ASSERT_EQUALS("a ? ( b < c ) : d > e", tokenizeAndStringify("a ? b < c : d > e"));
}
std::string testAst(const char code[],bool verbose=false) {
std::string testAst(const char code[], bool verbose = false, bool z3 = false) {
// tokenize given code..
Tokenizer tokenList(&settings0, nullptr);
std::istringstream istr(code);
@ -7408,6 +7409,8 @@ private:
}
// Return stringified AST
if (z3)
return tokenList.list.front()->astTop()->astStringZ3();
if (verbose)
return tokenList.list.front()->astTop()->astStringVerbose();
@ -7920,6 +7923,23 @@ private:
ASSERT_EQUALS("b(", testAst("class a { void b() & {} };"));
}
//Verify that returning a newly constructed object generates the correct AST even when the class name is scoped
//Addresses https://trac.cppcheck.net/ticket/9700
void astnewscoped() {
ASSERT_EQUALS("(return (new A))", testAst("return new A;", false, true));
ASSERT_EQUALS("(return (new (( A)))", testAst("return new A();", false, true));
ASSERT_EQUALS("(return (new (( A true)))", testAst("return new A(true);", false, true));
ASSERT_EQUALS("(return (new (:: A B)))", testAst("return new A::B;", false, true));
ASSERT_EQUALS("(return (new (( (:: A B))))", testAst("return new A::B();", false, true));
ASSERT_EQUALS("(return (new (( (:: A B) true)))", testAst("return new A::B(true);", false, true));
ASSERT_EQUALS("(return (new (:: (:: A B) C)))", testAst("return new A::B::C;", false, true));
ASSERT_EQUALS("(return (new (( (:: (:: A B) C))))", testAst("return new A::B::C();", false, true));
ASSERT_EQUALS("(return (new (( (:: (:: A B) C) true)))", testAst("return new A::B::C(true);", false, true));
ASSERT_EQUALS("(return (new (:: (:: (:: A B) C) D)))", testAst("return new A::B::C::D;", false, true));
ASSERT_EQUALS("(return (new (( (:: (:: (:: A B) C) D))))", testAst("return new A::B::C::D();", false, true));
ASSERT_EQUALS("(return (new (( (:: (:: (:: A B) C) D) true)))", testAst("return new A::B::C::D(true);", false, true));
}
void compileLimits() {
const char raw_code[] = "#define PTR1 (* (* (* (* (* (* (* (* (* (*\n"
"#define PTR2 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1\n"