Tokenizer: Write syntax error if there is C++ code in C file.

This commit is contained in:
Daniel Marjamäki 2017-04-06 08:50:35 +02:00
parent fd2651909c
commit 50da7d4919
6 changed files with 48 additions and 16 deletions

View File

@ -3318,6 +3318,9 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
}
}
// Is there C++ code in C file?
validateC();
// remove MACRO in variable declaration: MACRO int x;
removeMacroInVarDecl();
@ -7617,6 +7620,12 @@ void Tokenizer::syntaxError(const Token *tok, char c) const
InternalError::SYNTAX);
}
void Tokenizer::syntaxErrorC(const Token *tok, const std::string &what) const
{
printDebugOutput(0);
throw InternalError(tok, "Code '"+what+"' is invalid C code. Use --std or --language to configure the language.", InternalError::SYNTAX);
}
void Tokenizer::unhandled_macro_class_x_y(const Token *tok) const
{
reportError(tok,
@ -7996,6 +8005,24 @@ void Tokenizer::simplifyComma()
}
void Tokenizer::validateC() const
{
if (!isC())
return;
for (const Token *tok = tokens(); tok; tok = tok->next()) {
if (tok->previous() && !Token::Match(tok->previous(), "[;{}]"))
continue;
if (Token::simpleMatch(tok, "using namespace std ;"))
syntaxErrorC(tok, "using namespace std");
if (Token::Match(tok, "template < class %name% [,>]"))
syntaxErrorC(tok, "template<...");
if (Token::Match(tok, "%name% :: %name%"))
syntaxErrorC(tok, tok->str() + tok->strAt(1) + tok->strAt(2));
if (Token::Match(tok, "class|namespace %name% [:{]"))
syntaxErrorC(tok, tok->str() + tok->strAt(1) + tok->strAt(2));
}
}
void Tokenizer::validate() const
{
std::stack<const Token *> linkTokens;

View File

@ -568,11 +568,19 @@ public:
/** Syntax error. Example: invalid number of ')' */
void syntaxError(const Token *tok, char c) const;
/** Syntax error. C++ code in C file. */
void syntaxErrorC(const Token *tok, const std::string &what) const;
private:
/** Report that there is an unhandled "class x y {" code */
void unhandled_macro_class_x_y(const Token *tok) const;
/**
* Is there C++ code in C file?
*/
void validateC() const;
/**
* assert that tokens are ok - used during debugging for example
* to catch problems in simplifyTokenList1/2.

View File

@ -130,7 +130,6 @@ private:
TEST_CASE(garbageCode90);
TEST_CASE(garbageCode91);
TEST_CASE(garbageCode92);
TEST_CASE(garbageCode93);
TEST_CASE(garbageCode94);
TEST_CASE(garbageCode95);
TEST_CASE(garbageCode96);
@ -763,10 +762,6 @@ private:
ASSERT_THROW(checkCode("template < typename _Tp ( ( ) ; _Tp ) , decltype > { } { ( ) ( ) }"), InternalError); // do not crash
}
void garbageCode93() { // #6800
checkCode(" namespace A { } class A{ { }} class A : T ;", false); // do not crash
}
void garbageCode94() { // #6803
//checkCode("typedef long __m256i __attribute__ ( ( ( ) ) )[ ; ( ) { } typedef __m256i __attribute__ ( ( ( ) ) ) < ] ( ) { ; }");
ASSERT_THROW(checkCode("typedef long __m256i __attribute__ ( ( ( ) ) )[ ; ( ) { } typedef __m256i __attribute__ ( ( ( ) ) ) < ] ( ) { ; }"), InternalError);
@ -1326,7 +1321,7 @@ private:
void garbageCode164() {
//7234
checkCode("class d{k p;}(){d::d():B<()}", false);
checkCode("class d{k p;}(){d::d():B<()}");
}
void garbageCode165() {
@ -1336,7 +1331,7 @@ private:
void garbageCode167() {
//7237
checkCode("class D00i000{:D00i000::}i", false);
ASSERT_THROW(checkCode("class D00i000{:D00i000::}i"),InternalError);
}
void garbageCode168() {

View File

@ -864,7 +864,7 @@ private:
" ::exit(0);\n"
" }"
" free(p);\n"
"}");
"}", true);
ASSERT_EQUALS("", errout.str());
check("void f() {\n"
@ -874,7 +874,7 @@ private:
" std::exit(0);\n"
" }"
" free(p);\n"
"}");
"}", true);
ASSERT_EQUALS("", errout.str());
}

View File

@ -1104,15 +1104,8 @@ private:
std::istringstream istr(code);
tokenizerCpp.tokenize(istr, "test.cpp");
Tokenizer tokenizerC(&settings, this);
std::istringstream istr2(code);
tokenizerC.tokenize(istr2, "test.c");
CheckOther checkOtherCpp(&tokenizerCpp, &settings, this);
checkOtherCpp.warningOldStylePointerCast();
CheckOther checkOtherC(&tokenizerC, &settings, this);
checkOtherC.warningOldStylePointerCast();
}
void oldStylePointerCast() {

View File

@ -64,6 +64,8 @@ private:
TEST_CASE(tokenize32); // #5884 (fsanitize=undefined: left shift of negative value -10000 in lib/templatesimplifier.cpp:852:46)
TEST_CASE(tokenize33); // #5780 Various crashes on valid template code
TEST_CASE(validate);
TEST_CASE(syntax_case_default);
TEST_CASE(foreach); // #3690
@ -780,6 +782,13 @@ private:
tokenizeAndStringify(code, true);
}
void validate() {
// C++ code in C file
ASSERT_THROW(tokenizeAndStringify(";using namespace std;",false,false,Settings::Native,"test.c"), InternalError);
ASSERT_THROW(tokenizeAndStringify(";std::map<int,int> m;",false,false,Settings::Native,"test.c"), InternalError);
ASSERT_THROW(tokenizeAndStringify(";template<class T> class X { };",false,false,Settings::Native,"test.c"), InternalError);
}
void syntax_case_default() { // correct syntax
tokenizeAndStringify("void f() {switch (n) { case 0: z(); break;}}");
ASSERT_EQUALS("", errout.str());