diff --git a/test/testgarbage.cpp b/test/testgarbage.cpp
new file mode 100644
index 000000000..095ce045e
--- /dev/null
+++ b/test/testgarbage.cpp
@@ -0,0 +1,247 @@
+/*
+ * Cppcheck - A tool for static C/C++ code analysis
+ * Copyright (C) 2007-2014 Daniel Marjamäki and 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 .
+ */
+
+#include "testsuite.h"
+#include "tokenize.h"
+#include "token.h"
+#include "settings.h"
+
+extern std::ostringstream errout;
+
+
+class TestGarbage : public TestFixture {
+public:
+ TestGarbage() : TestFixture("TestGarbage") {
+ }
+
+private:
+
+ void run() {
+ // don't freak out when the syntax is wrong
+ TEST_CASE(wrong_syntax1);
+ TEST_CASE(wrong_syntax2);
+ TEST_CASE(wrong_syntax3); // #3544
+ TEST_CASE(wrong_syntax4); // #3618
+ TEST_CASE(wrong_syntax_if_macro); // #2518 - if MACRO()
+ TEST_CASE(wrong_syntax_class_x_y); // #3585 - class x y { };
+ TEST_CASE(syntax_case_default);
+ TEST_CASE(garbageCode1);
+ TEST_CASE(garbageCode2); // #4300
+ TEST_CASE(garbageCode3); // #4869
+ TEST_CASE(garbageCode4); // #4887
+ TEST_CASE(garbageCode5); // #5168
+ TEST_CASE(garbageCode6); // #5214
+ TEST_CASE(garbageCode7);
+ TEST_CASE(garbageCode8); // #5511
+ TEST_CASE(garbageCode9); // #5604
+ TEST_CASE(garbageCode10); // #6127
+
+ TEST_CASE(astGarbage);
+ }
+
+ std::string checkCode(const char code[], const char filename[] = "test.cpp") {
+ errout.str("");
+
+ Settings settings;
+ settings.debugwarnings = true;
+
+ // tokenize..
+ Tokenizer tokenizer(&settings, this);
+ std::istringstream istr(code);
+ tokenizer.tokenize(istr, filename);
+ tokenizer.simplifyTokenList2();
+
+ // TODO: Run checks
+
+ return tokenizer.tokens()->stringifyList(false, false, false, true, false, 0, 0);
+ }
+
+ void wrong_syntax1() {
+ {
+ const char code[] ="TR(kvmpio, PROTO(int rw), ARGS(rw), TP_(aa->rw;))";
+ ASSERT_EQUALS("TR ( kvmpio , PROTO ( int rw ) , ARGS ( rw ) , TP_ ( aa . rw ; ) )", checkCode(code));
+ ASSERT_EQUALS("", errout.str());
+ }
+
+ {
+ const char code[] ="struct A { template struct { }; };";
+ ASSERT_THROW(checkCode(code), InternalError);
+ }
+
+ {
+ const char code[] ="enum ABC { A,B, typedef enum { C } };";
+ ASSERT_THROW(checkCode(code), InternalError);
+ }
+
+ {
+ // #3314 - don't report syntax error.
+ const char code[] ="struct A { typedef B::C (A::*f)(); };";
+ checkCode(code);
+ ASSERT_EQUALS("[test.cpp:1]: (debug) Failed to parse 'typedef B :: C ( A :: * f ) ( ) ;'. The checking continues anyway.\n", errout.str());
+ }
+ }
+
+ void wrong_syntax2() { // #3504
+ const char code[] = "void f() {\n"
+ " X x;\n"
+ " Y y;\n"
+ "}\n"
+ "\n"
+ "void G( template class (j) ) {}";
+
+ // don't segfault..
+ checkCode(code);
+ }
+
+ void wrong_syntax3() { // #3544
+ const char code[] = "X #define\n"
+ "{\n"
+ " (\n"
+ " for( #endif typedef typedef cb[N] )\n"
+ " ca[N]; = cb[i]\n"
+ " )\n"
+ "}";
+
+ Settings settings;
+ Tokenizer tokenizer(&settings, this);
+ std::istringstream istr(code);
+ try {
+ tokenizer.tokenize(istr, "test.cpp");
+ assertThrowFail(__FILE__, __LINE__);
+ } catch (InternalError& e) {
+ ASSERT_EQUALS("Analysis failed. If the code is valid then please report this failure.", e.errorMessage);
+ ASSERT_EQUALS("cppcheckError", e.id);
+ ASSERT_EQUALS(5, e.token->linenr());
+ }
+ }
+
+ void wrong_syntax4() { // #3618
+ const char code[] = "typedef void (x) (int); return x&";
+
+ ASSERT_THROW(checkCode(code), InternalError);
+ }
+
+ void wrong_syntax_if_macro() {
+ // #2518 #4171
+ ASSERT_THROW(checkCode("void f() { if MACRO(); }"), InternalError);
+
+ // #4668 - note there is no semicolon after MACRO()
+ ASSERT_THROW(checkCode("void f() { if (x) MACRO() {} }"), InternalError);
+
+ // #4810 - note there is no semicolon after MACRO()
+ ASSERT_THROW(checkCode("void f() { if (x) MACRO() else ; }"), InternalError);
+ }
+
+ void wrong_syntax_class_x_y() {
+ // #3585
+ const char code[] = "class x y { };";
+
+ errout.str("");
+
+ Settings settings;
+ settings.addEnabled("information");
+ Tokenizer tokenizer(&settings, this);
+ std::istringstream istr(code);
+ tokenizer.tokenize(istr, "test.c");
+ tokenizer.simplifyTokenList2();
+
+ ASSERT_EQUALS("[test.c:1]: (information) The code 'class x y {' is not handled. You can use -I or --include to add handling of this code.\n", errout.str());
+ }
+
+ void syntax_case_default() {
+ ASSERT_THROW(checkCode("void f() {switch (n) { case: z(); break;}}"), InternalError);
+
+ ASSERT_THROW(checkCode("void f() {switch (n) { case;: z(); break;}}"), InternalError);
+
+ ASSERT_THROW(checkCode("void f() {switch (n) { case {}: z(); break;}}"), InternalError);
+
+ ASSERT_THROW(checkCode("void f() {switch (n) { case 0?{1}:{2} : z(); break;}}"), InternalError);
+
+ ASSERT_THROW(checkCode("void f() {switch (n) { case 0?1;:{2} : z(); break;}}"), InternalError);
+
+ ASSERT_THROW(checkCode("void f() {switch (n) { case 0?(1?{3:4}):2 : z(); break;}}"), InternalError);
+
+ //ticket #4234
+ ASSERT_THROW(checkCode("( ) { switch break ; { switch ( x ) { case } y break ; : } }"), InternalError);
+
+ //ticket #4267
+ ASSERT_THROW(checkCode("f ( ) { switch break; { switch ( x ) { case } case break; -6: ( ) ; } }"), InternalError);
+ }
+
+ void garbageCode1() {
+ checkCode("struct x foo_t; foo_t typedef y;");
+ }
+
+ void garbageCode2() { //#4300 (segmentation fault)
+ ASSERT_THROW(checkCode("enum { D = 1 struct { } ; } s.b = D;"), InternalError);
+ }
+
+ void garbageCode3() { //#4849 (segmentation fault in Tokenizer::simplifyStructDecl (invalid code))
+ ASSERT_THROW(checkCode("enum { D = 2 s ; struct y { x } ; } { s.a = C ; s.b = D ; }"), InternalError);
+ }
+
+ void garbageCode4() { // #4887
+ ASSERT_THROW(checkCode("void f ( ) { = a ; if ( 1 ) if = ( 0 ) ; }"), InternalError);
+ }
+
+ void garbageCode5() { // #5168
+ checkCode("( asm : ; void : );");
+ }
+
+ void garbageCode6() { // #5214
+ checkCode("int b = ( 0 ? ? ) 1 : 0 ;");
+ checkCode("int a = int b = ( 0 ? ? ) 1 : 0 ;");
+ }
+
+ void garbageCode7() {
+ ASSERT_THROW(checkCode("1 (int j) { return return (c) * sizeof } y[1];"), InternalError);
+ checkCode("foo(Args&&...) fn void = { } auto template { { e = T::error }; };\n"
+ "ScopedEnum1 se1; { enum class E : T { e = 0 = e ScopedEnum2 struct UnscopedEnum3 { T{ e = 4 }; };\n"
+ "arr[(int) E::e]; }; UnscopedEnum3 e2 = f()\n"
+ "{ { e = e1; T::error } int test1 ue2; g() { enum class E { e = T::error }; return E::e; } int test2 = } \n"
+ "namespace UnscopedEnum { template struct UnscopedEnum1 { E{ e = T::error }; }; UnscopedEnum1 { enum E : { e = 0 }; };\n"
+ "UnscopedEnum2 ue3; template struct UnscopedEnum3 { enum { }; }; int arr[E::e]; };\n"
+ "UnscopedEnum3 namespace template int f() { enum E { e }; T::error }; return (int) E(); } int test1 int g() { enum E { e = E };\n"
+ "E::e; } int test2 = g(); }"), InternalError);
+ }
+
+ void garbageCode9() {
+ ASSERT_THROW(checkCode("enum { e = { } } ( ) { { enum { } } } { e } "), InternalError);
+ }
+
+ void garbageCode10() { // #6127
+ checkCode("for( rl=reslist; rl!=NULL; rl=rl->next )");
+ }
+
+ void astGarbage() {
+ checkCode("--"); // don't crash
+
+ checkCode("N 1024 float a[N], b[N + 3], c[N]; void N; (void) i;\n"
+ "int #define for (i = avx_test i < c[i]; i++)\n"
+ "b[i + 3] = a[i] * {}"); // Don't hang (#5787)
+
+ checkCode("START_SECTION([EXTRA](bool isValid(const String &filename)))"); // Don't crash (#5991)
+ }
+};
+
+REGISTER_TEST(TestGarbage)
diff --git a/test/testrunner.vcxproj b/test/testrunner.vcxproj
index 672017f98..17ebba124 100644
--- a/test/testrunner.vcxproj
+++ b/test/testrunner.vcxproj
@@ -45,6 +45,7 @@
+
diff --git a/test/testrunner.vcxproj.filters b/test/testrunner.vcxproj.filters
index e75af2a1d..4c0160783 100644
--- a/test/testrunner.vcxproj.filters
+++ b/test/testrunner.vcxproj.filters
@@ -199,6 +199,9 @@
Source Files
+
+ Source Files
+
diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp
index a62d8dbc8..58da939a2 100644
--- a/test/testtokenize.cpp
+++ b/test/testtokenize.cpp
@@ -69,24 +69,7 @@ private:
TEST_CASE(tokenize33); // #5780 Various crashes on valid template code
TEST_CASE(tokenize34); // #6121 (crash upon invalid enum)
- // don't freak out when the syntax is wrong
- TEST_CASE(wrong_syntax1);
- TEST_CASE(wrong_syntax2);
- TEST_CASE(wrong_syntax3); // #3544
- TEST_CASE(wrong_syntax4); // #3618
- TEST_CASE(wrong_syntax_if_macro); // #2518 - if MACRO()
- TEST_CASE(wrong_syntax_class_x_y); // #3585 - class x y { };
TEST_CASE(syntax_case_default);
- TEST_CASE(garbageCode1);
- TEST_CASE(garbageCode2); // #4300
- TEST_CASE(garbageCode3); // #4869
- TEST_CASE(garbageCode4); // #4887
- TEST_CASE(garbageCode5); // #5168
- TEST_CASE(garbageCode6); // #5214
- TEST_CASE(garbageCode7);
- TEST_CASE(garbageCode8); // #5511
- TEST_CASE(garbageCode9); // #5604
- TEST_CASE(garbageCode10); // #6127
TEST_CASE(simplifyFileAndLineMacro); // tokenize "return - __LINE__;"
TEST_CASE(foreach); // #3690
@@ -480,7 +463,6 @@ private:
TEST_CASE(asttemplate);
TEST_CASE(astcast);
TEST_CASE(astlambda);
- TEST_CASE(astGarbage);
TEST_CASE(startOfExecutableScope);
}
@@ -801,208 +783,42 @@ private:
ASSERT_THROW(tokenizeAndStringify(code, true), InternalError);
}
- void wrong_syntax1() {
- {
- const char code[] ="TR(kvmpio, PROTO(int rw), ARGS(rw), TP_(aa->rw;))";
- ASSERT_EQUALS("TR ( kvmpio , PROTO ( int rw ) , ARGS ( rw ) , TP_ ( aa . rw ; ) )", tokenizeAndStringify(code, true));
- ASSERT_EQUALS("", errout.str());
- }
+ void syntax_case_default() { // correct syntax
+ tokenizeAndStringify("void f() {switch (n) { case 0: z(); break;}}");
+ ASSERT_EQUALS("", errout.str());
- {
- const char code[] ="struct A { template struct { }; };";
- ASSERT_THROW(tokenizeAndStringify(code, true), InternalError);
- }
+ tokenizeAndStringify("void f() {switch (n) { case 0:; break;}}");
+ ASSERT_EQUALS("", errout.str());
- {
- const char code[] ="enum ABC { A,B, typedef enum { C } };";
- ASSERT_THROW(tokenizeAndStringify(code, true), InternalError);
- }
+ tokenizeAndStringify("void f() {switch (n) { case 0?1:2 : z(); break;}}");
+ ASSERT_EQUALS("", errout.str());
- {
- // #3314 - don't report syntax error.
- const char code[] ="struct A { typedef B::C (A::*f)(); };";
- tokenizeAndStringify(code, true);
- ASSERT_EQUALS("[test.cpp:1]: (debug) Failed to parse 'typedef B :: C ( A :: * f ) ( ) ;'. The checking continues anyway.\n", errout.str());
- }
- }
+ tokenizeAndStringify("void f() {switch (n) { case 0?(1?3:4):2 : z(); break;}}");
+ ASSERT_EQUALS("", errout.str());
- void wrong_syntax2() { // #3504
- const char code[] = "void f() {\n"
- " X x;\n"
- " Y y;\n"
- "}\n"
- "\n"
- "void G( template class (j) ) {}";
+ //allow GCC '({ %var%|%num%|%bool% ; })' statement expression extension
+ tokenizeAndStringify("void f() {switch (n) { case 0?({0;}):1: z(); break;}}");
+ ASSERT_EQUALS("", errout.str());
- // don't segfault..
- tokenizeAndStringify(code);
- }
+ //'b' can be or a macro or an undefined enum
+ tokenizeAndStringify("void f() {switch (n) { case b: z(); break;}}");
+ ASSERT_EQUALS("", errout.str());
- void wrong_syntax3() { // #3544
- const char code[] = "X #define\n"
- "{\n"
- " (\n"
- " for( #endif typedef typedef cb[N] )\n"
- " ca[N]; = cb[i]\n"
- " )\n"
- "}";
+ //valid, when there's this declaration: 'constexpr int g() { return 2; }'
+ tokenizeAndStringify("void f() {switch (n) { case g(): z(); break;}}");
+ ASSERT_EQUALS("", errout.str());
- Settings settings;
- Tokenizer tokenizer(&settings, this);
- std::istringstream istr(code);
- try {
- tokenizer.tokenize(istr, "test.cpp");
- assertThrowFail(__FILE__, __LINE__);
- } catch (InternalError& e) {
- ASSERT_EQUALS("Analysis failed. If the code is valid then please report this failure.", e.errorMessage);
- ASSERT_EQUALS("cppcheckError", e.id);
- ASSERT_EQUALS(5, e.token->linenr());
- }
- }
+ //valid, when there's also this declaration: 'constexpr int g[1] = {0};'
+ tokenizeAndStringify("void f() {switch (n) { case g[0]: z(); break;}}");
+ ASSERT_EQUALS("", errout.str());
- void wrong_syntax4() { // #3618
- const char code[] = "typedef void (x) (int); return x&";
+ //valid, similar to above case
+ tokenizeAndStringify("void f() {switch (n) { case *g: z(); break;}}");
+ ASSERT_EQUALS("", errout.str());
- ASSERT_THROW(tokenizeAndStringify(code), InternalError);
- }
-
- void wrong_syntax_if_macro() {
- // #2518 #4171
- ASSERT_THROW(tokenizeAndStringify("void f() { if MACRO(); }", false), InternalError);
-
- // #4668 - note there is no semicolon after MACRO()
- ASSERT_THROW(tokenizeAndStringify("void f() { if (x) MACRO() {} }", false), InternalError);
-
- // #4810 - note there is no semicolon after MACRO()
- ASSERT_THROW(tokenizeAndStringify("void f() { if (x) MACRO() else ; }", false), InternalError);
- }
-
- void wrong_syntax_class_x_y() {
- // #3585
- const char code[] = "class x y { };";
-
- errout.str("");
-
- Settings settings;
- settings.addEnabled("information");
- Tokenizer tokenizer(&settings, this);
- std::istringstream istr(code);
- tokenizer.tokenize(istr, "test.c");
- tokenizer.simplifyTokenList2();
-
- ASSERT_EQUALS("[test.c:1]: (information) The code 'class x y {' is not handled. You can use -I or --include to add handling of this code.\n", errout.str());
- }
-
- void syntax_case_default() {
- //correct syntax
- {
- tokenizeAndStringify("void f() {switch (n) { case 0: z(); break;}}");
- ASSERT_EQUALS("", errout.str());
-
- tokenizeAndStringify("void f() {switch (n) { case 0:; break;}}");
- ASSERT_EQUALS("", errout.str());
-
- tokenizeAndStringify("void f() {switch (n) { case 0?1:2 : z(); break;}}");
- ASSERT_EQUALS("", errout.str());
-
- tokenizeAndStringify("void f() {switch (n) { case 0?(1?3:4):2 : z(); break;}}");
- ASSERT_EQUALS("", errout.str());
-
- //allow GCC '({ %var%|%num%|%bool% ; })' statement expression extension
- tokenizeAndStringify("void f() {switch (n) { case 0?({0;}):1: z(); break;}}");
- ASSERT_EQUALS("", errout.str());
-
- //'b' can be or a macro or an undefined enum
- tokenizeAndStringify("void f() {switch (n) { case b: z(); break;}}");
- ASSERT_EQUALS("", errout.str());
-
- //valid, when there's this declaration: 'constexpr int g() { return 2; }'
- tokenizeAndStringify("void f() {switch (n) { case g(): z(); break;}}");
- ASSERT_EQUALS("", errout.str());
-
- //valid, when there's also this declaration: 'constexpr int g[1] = {0};'
- tokenizeAndStringify("void f() {switch (n) { case g[0]: z(); break;}}");
- ASSERT_EQUALS("", errout.str());
-
- //valid, similar to above case
- tokenizeAndStringify("void f() {switch (n) { case *g: z(); break;}}");
- ASSERT_EQUALS("", errout.str());
-
- //valid, when 'x' and 'y' are constexpr.
- tokenizeAndStringify("void f() {switch (n) { case sqrt(x+y): z(); break;}}");
- ASSERT_EQUALS("", errout.str());
- }
-
- //wrong syntax
- {
- ASSERT_THROW(tokenizeAndStringify("void f() {switch (n) { case: z(); break;}}"), InternalError);
-
- ASSERT_THROW(tokenizeAndStringify("void f() {switch (n) { case;: z(); break;}}"), InternalError);
-
- ASSERT_THROW(tokenizeAndStringify("void f() {switch (n) { case {}: z(); break;}}"), InternalError);
-
- ASSERT_THROW(tokenizeAndStringify("void f() {switch (n) { case 0?{1}:{2} : z(); break;}}"), InternalError);
-
- ASSERT_THROW(tokenizeAndStringify("void f() {switch (n) { case 0?1;:{2} : z(); break;}}"), InternalError);
-
- ASSERT_THROW(tokenizeAndStringify("void f() {switch (n) { case 0?(1?{3:4}):2 : z(); break;}}"), InternalError);
-
- //ticket #4234
- ASSERT_THROW(tokenizeAndStringify("( ) { switch break ; { switch ( x ) { case } y break ; : } }"), InternalError);
-
- //ticket #4267
- ASSERT_THROW(tokenizeAndStringify("f ( ) { switch break; { switch ( x ) { case } case break; -6: ( ) ; } }"), InternalError);
- }
- }
-
- void garbageCode1() {
- tokenizeAndStringify("struct x foo_t; foo_t typedef y;");
- }
-
- void garbageCode2() { //#4300 (segmentation fault)
- ASSERT_THROW(tokenizeAndStringify("enum { D = 1 struct { } ; } s.b = D;"), InternalError);
- }
-
- void garbageCode3() { //#4849 (segmentation fault in Tokenizer::simplifyStructDecl (invalid code))
- ASSERT_THROW(tokenizeAndStringify("enum { D = 2 s ; struct y { x } ; } { s.a = C ; s.b = D ; }"), InternalError);
- }
-
- void garbageCode4() { // #4887
- ASSERT_THROW(tokenizeAndStringify("void f ( ) { = a ; if ( 1 ) if = ( 0 ) ; }"), InternalError);
- }
-
- void garbageCode5() { // #5168
- tokenizeAndStringify("( asm : ; void : );");
- }
-
- void garbageCode6() { // #5214
- tokenizeAndStringify("int b = ( 0 ? ? ) 1 : 0 ;", /*simplify=*/true);
- tokenizeAndStringify("int a = int b = ( 0 ? ? ) 1 : 0 ;", /*simplify=*/true);
- }
-
- void garbageCode7() {
- ASSERT_THROW(tokenizeAndStringify("1 (int j) { return return (c) * sizeof } y[1];", /*simplify=*/true), InternalError);
- tokenizeAndStringify("foo(Args&&...) fn void = { } auto template { { e = T::error }; };\n"
- "ScopedEnum1 se1; { enum class E : T { e = 0 = e ScopedEnum2 struct UnscopedEnum3 { T{ e = 4 }; };\n"
- "arr[(int) E::e]; }; UnscopedEnum3 e2 = f()\n"
- "{ { e = e1; T::error } int test1 ue2; g() { enum class E { e = T::error }; return E::e; } int test2 = } \n"
- "namespace UnscopedEnum { template struct UnscopedEnum1 { E{ e = T::error }; }; UnscopedEnum1 { enum E : { e = 0 }; };\n"
- "UnscopedEnum2 ue3; template struct UnscopedEnum3 { enum { }; }; int arr[E::e]; };\n"
- "UnscopedEnum3 namespace template int f() { enum E { e }; T::error }; return (int) E(); } int test1 int g() { enum E { e = E };\n"
- "E::e; } int test2 = g(); }", true), InternalError);
- }
-
- void garbageCode9() {
- ASSERT_THROW(tokenizeAndStringify("enum { e = { } } ( ) { { enum { } } } { e } ", true), InternalError);
- }
-
- void garbageCode10() { // #6127
- tokenizeAndStringify("for( rl=reslist; rl!=NULL; rl=rl->next )", /*simplify=*/true);
+ //valid, when 'x' and 'y' are constexpr.
+ tokenizeAndStringify("void f() {switch (n) { case sqrt(x+y): z(); break;}}");
+ ASSERT_EQUALS("", errout.str());
}
void simplifyFileAndLineMacro() { // tokenize 'return - __LINE__' correctly
@@ -8704,16 +8520,6 @@ private:
tokenizeAndStringify(code.c_str()); // just survive...
}
- void astGarbage() {
- testAst("--"); // don't crash
-
- testAst("N 1024 float a[N], b[N + 3], c[N]; void N; (void) i;\n"
- "int #define for (i = avx_test i < c[i]; i++)\n"
- "b[i + 3] = a[i] * {}"); // Don't hang (#5787)
-
- testAst("START_SECTION([EXTRA](bool isValid(const String &filename)))"); // Don't crash (#5991)
- }
-
bool isStartOfExecutableScope(int offset, const char code[]) {
const Settings settings;
Tokenizer tokenizer(&settings, this);