diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 2086af9c6a3..474c0bffceb 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -123,18 +123,18 @@ static bool isExecutableScope(const Token* tok) return false; } -static bool isEnumDefinition(const Token* tok) +const Token* SymbolDatabase::isEnumDefinition(const Token* tok) { - if (!Token::Match(tok, "enum class| %name% {|:")) - return false; + if (!Token::Match(tok, "enum class| %name%| {|:")) + return nullptr; while (!Token::Match(tok, "[{:]")) tok = tok->next(); if (tok->str() == "{") - return true; + return tok; tok = tok->next(); // skip ':' while (Token::Match(tok, "%name%|::")) tok = tok->next(); - return Token::simpleMatch(tok, "{"); + return Token::simpleMatch(tok, "{") ? tok : nullptr; } void SymbolDatabase::createSymbolDatabaseFindAllScopes() diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index a594c84b2ac..bba22b78b3f 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1409,6 +1409,9 @@ class CPPCHECKLIB SymbolDatabase { void clangSetVariables(const std::vector &variableList); void createSymbolDatabaseExprIds(); + /* returns the opening { if tok points to enum */ + static const Token* isEnumDefinition(const Token* tok); + private: friend class Scope; friend class Function; diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 9102c750600..02d8f5318da 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8608,8 +8608,16 @@ void Tokenizer::findGarbageCode() const syntaxError(tok2, "Unexpected token '" + (tok2 ? tok2->str() : "") + "'"); } } - if (Token::Match(tok, "enum : %num%| {")) - syntaxError(tok->tokAt(2), "Unexpected token '" + tok->strAt(2) + "'"); + if (tok->str() == "enum") { + if (Token::Match(tok->next(), ": %num%| {")) + syntaxError(tok->tokAt(2), "Unexpected token '" + tok->strAt(2) + "'"); + if (const Token* start = SymbolDatabase::isEnumDefinition(tok)) { + for (const Token* tok2 = start->next(); tok2 && tok2 != start->link(); tok2 = tok2->next()) { + if (tok2->str() == ";") + syntaxError(tok2); + } + } + } } // Keywords in global scope diff --git a/test/cli/fuzz-crash/crash-66bd8440a699d270b323367978dab020dd1da3ff b/test/cli/fuzz-crash/crash-66bd8440a699d270b323367978dab020dd1da3ff new file mode 100644 index 00000000000..bdae8e1eded --- /dev/null +++ b/test/cli/fuzz-crash/crash-66bd8440a699d270b323367978dab020dd1da3ff @@ -0,0 +1 @@ +enum{C={;}=e}; \ No newline at end of file diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index 15458a516c8..e3f8e9d83c8 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -3585,7 +3585,7 @@ class TestSimplifyTemplate : public TestFixture { "using A2 = struct B2 { void f(T){} };\n" "A2 a2;\n" "template\n" - "using A3 = enum B3 {b = 0;};\n" + "using A3 = enum B3 {b = 0};\n" "A3 a3;"; const char exp[] = "template < int N > " "using A1 = struct B1 { static auto constexpr value = N ; } ; " @@ -3594,7 +3594,7 @@ class TestSimplifyTemplate : public TestFixture { "using A2 = struct B2 { void f ( T ) { } } ; " "A2 < bool > a2 ; " "template < class T > " - "using A3 = enum B3 { b = 0 ; } ; " + "using A3 = enum B3 { b = 0 } ; " "A3 < int > a3 ;"; ASSERT_EQUALS(exp, tok(code)); } diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index d0c7a21d336..d5bfda765c1 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -3353,8 +3353,8 @@ class TestSimplifyTypedef : public TestFixture { " struct S { enum E { E0 }; };\n" "}\n" "typedef N::S T;\n" - "enum class E { a = T::E0; };\n"; - ASSERT_EQUALS("namespace N { struct S { enum E { E0 } ; } ; } enum class E { a = N :: S :: E0 ; } ;", tok(code)); + "enum class E { a = T::E0 };\n"; + ASSERT_EQUALS("namespace N { struct S { enum E { E0 } ; } ; } enum class E { a = N :: S :: E0 } ;", tok(code)); } { // #11494 const char code[] = "typedef struct S {} KEY;\n" diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 8c03bfd3136..e5f6fb22903 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -7132,6 +7132,7 @@ class TestTokenizer : public TestFixture { ASSERT_THROW_INTERNAL_EQUALS(tokenizeAndStringify("enum : { };"), SYNTAX, "syntax error: Unexpected token '{'"); ASSERT_THROW_INTERNAL_EQUALS(tokenizeAndStringify("enum : 3 { };"), SYNTAX, "syntax error: Unexpected token '3'"); + ASSERT_NO_THROW(tokenizeAndStringify("enum { E = int{} };")); ASSERT_THROW_INTERNAL_EQUALS(tokenizeAndStringify("int a() { b((c)return 0) }"), SYNTAX, "syntax error"); ASSERT_THROW_EQUALS(tokenizeAndStringify("int f() { MACRO(x) return 0; }"), diff --git a/test/testvarid.cpp b/test/testvarid.cpp index 4e5c3984631..9a27621b2f9 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -3838,11 +3838,11 @@ class TestVarID : public TestFixture { void varidenum1() { const char code[] = "const int eStart = 6;\n" "enum myEnum {\n" - " A = eStart;\n" + " A = eStart\n" "};\n"; const char expected[] = "1: const int eStart@1 = 6 ;\n" "2: enum myEnum {\n" - "3: A = eStart@1 ;\n" + "3: A = eStart@1\n" "4: } ;\n"; ASSERT_EQUALS(expected, tokenize(code)); } @@ -3850,11 +3850,11 @@ class TestVarID : public TestFixture { void varidenum2() { const char code[] = "const int eStart = 6;\n" "enum myEnum {\n" - " A = f(eStart);\n" + " A = f(eStart)\n" "};\n"; const char expected[] = "1: const int eStart@1 = 6 ;\n" "2: enum myEnum {\n" - "3: A = f ( eStart@1 ) ;\n" + "3: A = f ( eStart@1 )\n" "4: } ;\n"; ASSERT_EQUALS(expected, tokenize(code)); } @@ -3862,11 +3862,11 @@ class TestVarID : public TestFixture { void varidenum3() { const char code[] = "const int eStart = 6;\n" "enum myEnum {\n" - " A = f(eStart, x);\n" + " A = f(eStart, x)\n" "};\n"; const char expected[] = "1: const int eStart@1 = 6 ;\n" "2: enum myEnum {\n" - "3: A = f ( eStart@1 , x ) ;\n" + "3: A = f ( eStart@1 , x )\n" "4: } ;\n"; ASSERT_EQUALS(expected, tokenize(code)); } @@ -3874,11 +3874,11 @@ class TestVarID : public TestFixture { void varidenum4() { const char code[] = "const int eStart = 6;\n" "enum myEnum {\n" - " A = f(x, eStart);\n" + " A = f(x, eStart)\n" "};\n"; const char expected[] = "1: const int eStart@1 = 6 ;\n" "2: enum myEnum {\n" - "3: A = f ( x , eStart@1 ) ;\n" + "3: A = f ( x , eStart@1 )\n" "4: } ;\n"; ASSERT_EQUALS(expected, tokenize(code)); } @@ -3886,15 +3886,15 @@ class TestVarID : public TestFixture { void varidenum5() { const char code[] = "const int eStart = 6;\n" "enum myEnum {\n" - " A = f(x, eStart, y);\n" + " A = f(x, eStart, y)\n" "};\n"; const char expected[] = "1: const int eStart@1 = 6 ;\n" "2: enum myEnum {\n" - "3: A = f ( x , eStart@1 , y ) ;\n" + "3: A = f ( x , eStart@1 , y )\n" "4: } ;\n"; const char current[] = "1: const int eStart@1 = 6 ;\n" "2: enum myEnum {\n" - "3: A = f ( x , eStart , y ) ;\n" + "3: A = f ( x , eStart , y )\n" "4: } ;\n"; TODO_ASSERT_EQUALS(expected, current, tokenize(code)); }