AST: Throw validation exception if ternary operator is missing operands

This commit is contained in:
Daniel Marjamäki 2020-03-07 21:46:38 +01:00
parent 91beccb304
commit 5376ba1701
8 changed files with 52 additions and 37 deletions

View File

@ -1535,8 +1535,12 @@ void TokenList::validateAst() const
throw InternalError(tok, "Syntax Error: AST broken, binary operator has only one operand.", InternalError::AST); throw InternalError(tok, "Syntax Error: AST broken, binary operator has only one operand.", InternalError::AST);
// Syntax error if we encounter "?" with operand2 that is not ":" // Syntax error if we encounter "?" with operand2 that is not ":"
if (tok->astOperand2() && tok->str() == "?" && tok->astOperand2()->str() != ":") if (tok->str() == "?") {
throw InternalError(tok, "Syntax Error: AST broken, ternary operator lacks ':'.", InternalError::AST); if (!tok->astOperand1() || !tok->astOperand2())
throw InternalError(tok, "AST broken, ternary operator missing operand(s)", InternalError::AST);
else if (tok->astOperand2()->str() != ":")
throw InternalError(tok, "Syntax Error: AST broken, ternary operator lacks ':'.", InternalError::AST);
}
// Check for endless recursion // Check for endless recursion
const Token* parent = tok->astParent(); const Token* parent = tok->astParent();

View File

@ -1238,7 +1238,7 @@ private:
} }
void garbageCode156() { // #7120 void garbageCode156() { // #7120
checkCode("struct {}a; d f() { c ? : } {}a.p"); ASSERT_THROW(checkCode("struct {}a; d f() { c ? : } {}a.p"), InternalError);
} }
void garbageCode157() { // #7131 void garbageCode157() { // #7131
@ -1482,10 +1482,10 @@ private:
} }
void garbageCode184() { // #7699 void garbageCode184() { // #7699
checkCode("unsigned int AquaSalSystem::GetDisplayScreenCount() {\n" ASSERT_THROW(checkCode("unsigned int AquaSalSystem::GetDisplayScreenCount() {\n"
" NSArray* pScreens = [NSScreen screens];\n" " NSArray* pScreens = [NSScreen screens];\n"
" return pScreens ? [pScreens count] : 1;\n" " return pScreens ? [pScreens count] : 1;\n"
"}"); "}"), InternalError);
} }
void garbageCode185() { // #6011 crash in libreoffice failure to create proper AST void garbageCode185() { // #6011 crash in libreoffice failure to create proper AST

View File

@ -3324,11 +3324,12 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
// #8261 // #8261
check("void foo() {\n" // TODO Do not throw AST validation exception
" (beat < 100) ? (void)0 : throw(0);\n" TODO_ASSERT_THROW(check("void foo() {\n"
" bar();\n" " (beat < 100) ? (void)0 : throw(0);\n"
"}", nullptr, false, false, false, false, &settings); " bar();\n"
ASSERT_EQUALS("", errout.str()); "}", nullptr, false, false, false, false, &settings), InternalError);
//ASSERT_EQUALS("", errout.str());
} }
@ -3355,13 +3356,14 @@ private:
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("void foo() {\n" // TODO Do not throw AST validation exception
" switch(a) {\n" TODO_ASSERT_THROW(check("void foo() {\n"
" case A&&B?B:A:\n" " switch(a) {\n"
" foo();\n" " case A&&B?B:A:\n"
" }\n" " foo();\n"
"}"); " }\n"
ASSERT_EQUALS("", errout.str()); "}"), InternalError);
//ASSERT_EQUALS("", errout.str());
} }
void suspiciousEqualityComparison() { void suspiciousEqualityComparison() {

View File

@ -3352,17 +3352,21 @@ private:
{ {
const char code[] = "void f () { switch(n) { case 1?0:foo(): break; }}"; const char code[] = "void f () { switch(n) { case 1?0:foo(): break; }}";
ASSERT_EQUALS("void f ( ) { switch ( n ) { case 0 : ; break ; } }", tok(code)); // TODO Do not throw AST validation exception
TODO_ASSERT_THROW(tok(code), InternalError);
//ASSERT_EQUALS("void f ( ) { switch ( n ) { case 0 : ; break ; } }", tok(code));
} }
{ {
const char code[] = "void f () { switch(n) { case 1?0?1:0:foo(): break; }}"; const char code[] = "void f () { switch(n) { case 1?0?1:0:foo(): break; }}";
TODO_ASSERT_EQUALS("void f ( ) { switch ( n ) { case 0 : ; break ; } }", "void f ( ) { switch ( n ) { case ( 0 ) : ; break ; } }", tok(code)); // TODO Do not throw AST validation exception
TODO_ASSERT_THROW(tok(code), InternalError);
} }
{ {
const char code[] = "void f () { switch(n) { case 0?foo():1: break; }}"; const char code[] = "void f () { switch(n) { case 0?foo():1: break; }}";
ASSERT_EQUALS("void f ( ) { switch ( n ) { case 1 : ; break ; } }", tok(code)); // TODO Do not throw AST validation exception
TODO_ASSERT_THROW(tok(code), InternalError);
} }
{ {
@ -3418,10 +3422,9 @@ private:
} }
{ {
ASSERT_EQUALS("; type = decay_t < decltype ( declval < T > ( ) ) > ;", // TODO Do not throw AST validation exception
tok("; type = decay_t<decltype(true ? declval<T>() : declval<U>())>;")); TODO_ASSERT_THROW(tok("; type = decay_t<decltype(true ? declval<T>() : declval<U>())>;"), InternalError);
ASSERT_EQUALS("; type = decay_t < decltype ( declval < U > ( ) ) > ;", TODO_ASSERT_THROW(tok("; type = decay_t<decltype(false ? declval<T>() : declval<U>())>;"), InternalError);
tok("; type = decay_t<decltype(false ? declval<T>() : declval<U>())>;"));
} }
} }

View File

@ -508,8 +508,8 @@ private:
"};"; "};";
// Tokenize and check output.. // Tokenize and check output..
tok(code, true, Settings::Native, false); TODO_ASSERT_THROW(tok(code, true, Settings::Native, false), InternalError); // TODO: Do not throw exception
ASSERT_EQUALS("", errout.str()); //ASSERT_EQUALS("", errout.str());
} }
void simplifyTypedef15() { void simplifyTypedef15() {
@ -2402,8 +2402,9 @@ private:
"struct bstr bstr0 ( const char * s ) { " "struct bstr bstr0 ( const char * s ) { "
"return ( struct bstr ) { ( unsigned char * ) s , s ? strlen ( s ) : 0 } ; " "return ( struct bstr ) { ( unsigned char * ) s , s ? strlen ( s ) : 0 } ; "
"}"; "}";
ASSERT_EQUALS(expected, tok(code, false)); TODO_ASSERT_THROW(tok(code, false), InternalError); // TODO: Do not produce bad AST
ASSERT_EQUALS("", errout.str()); //ASSERT_EQUALS(expected, tok(code, false));
//ASSERT_EQUALS("", errout.str());
} }
void simplifyTypedef118() { // #5749 void simplifyTypedef118() { // #5749

View File

@ -382,8 +382,8 @@ private:
" FP_M(val);" " FP_M(val);"
"};"; "};";
tok(code, true, Settings::Native, false); TODO_ASSERT_THROW(tok(code, true, Settings::Native, false), InternalError); // TODO: Do not throw AST validation exception
ASSERT_EQUALS("", errout.str()); //ASSERT_EQUALS("", errout.str());
} }
void simplifyUsing15() { void simplifyUsing15() {

View File

@ -2952,6 +2952,8 @@ private:
} }
void symboldatabase45() { void symboldatabase45() {
return; // TODO: Do not throw AST validation exception
GET_SYMBOL_DB("typedef struct {\n" GET_SYMBOL_DB("typedef struct {\n"
" unsigned long bits;\n" " unsigned long bits;\n"
"} S;\n" "} S;\n"

View File

@ -914,14 +914,17 @@ private:
tokenizeAndStringify("void f() {switch (n) { case 0:; break;}}"); tokenizeAndStringify("void f() {switch (n) { case 0:; break;}}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
tokenizeAndStringify("void f() {switch (n) { case 0?1:2 : z(); break;}}"); // TODO: Do not throw AST validation exception
ASSERT_EQUALS("", errout.str()); TODO_ASSERT_THROW(tokenizeAndStringify("void f() {switch (n) { case 0?1:2 : z(); break;}}"), InternalError);
//ASSERT_EQUALS("", errout.str());
tokenizeAndStringify("void f() {switch (n) { case 0?(1?3:4):2 : z(); break;}}"); // TODO: Do not throw AST validation exception
TODO_ASSERT_THROW(tokenizeAndStringify("void f() {switch (n) { case 0?(1?3:4):2 : z(); break;}}"), InternalError);
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
//allow GCC '({ %name%|%num%|%bool% ; })' statement expression extension //allow GCC '({ %name%|%num%|%bool% ; })' statement expression extension
tokenizeAndStringify("void f() {switch (n) { case 0?({0;}):1: z(); break;}}"); // TODO: Do not throw AST validation exception
TODO_ASSERT_THROW(tokenizeAndStringify("void f() {switch (n) { case 0?({0;}):1: z(); break;}}"), InternalError);
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
//'b' can be or a macro or an undefined enum //'b' can be or a macro or an undefined enum
@ -7581,7 +7584,7 @@ private:
" : \"\");\n" " : \"\");\n"
"}\n"; "}\n";
// Ensure that the AST is validated for the simplified token list // Ensure that the AST is validated for the simplified token list
tokenizeAndStringify(code); // this does not crash/hang TODO_ASSERT_THROW(tokenizeAndStringify(code), InternalError); // this should not crash/hang
ASSERT_THROW(tokenizeAndStringify(code,true), InternalError); // when parentheses are simplified the AST will be wrong ASSERT_THROW(tokenizeAndStringify(code,true), InternalError); // when parentheses are simplified the AST will be wrong
} }