From 58e524165d44e672e391cca261d9f7dd723d2c70 Mon Sep 17 00:00:00 2001 From: Brad King Date: Sat, 16 Feb 2013 20:41:47 -0500 Subject: [PATCH] Warn about arguments not separated by whitespace Teach the lexer to return tokens for whitespace. Teach the parser to tolerate the space tokens where whitespace is allowed. Also teach the parser to diagnose and warn about cases of quoted arguments followed immediately by another argument. This was accidentally allowed previously, so we only warn. Update the RunCMake.Syntax test case StringNoSpace expected stderr to include the warnings. --- Source/cmListFileCache.cxx | 40 +++++- Source/cmListFileLexer.c | 115 +++++++++--------- Source/cmListFileLexer.h | 1 + Source/cmListFileLexer.in.l | 6 +- .../RunCMake/Syntax/StringNoSpace-stderr.txt | 18 ++- 5 files changed, 117 insertions(+), 63 deletions(-) diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index f57ca2294..c499b6fb5 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -36,6 +36,7 @@ struct cmListFileParser const char* FileName; cmListFileLexer* Lexer; cmListFileFunction Function; + enum { SeparationOkay, SeparationWarning } Separation; }; //---------------------------------------------------------------------------- @@ -69,7 +70,10 @@ bool cmListFileParser::ParseFile() while(cmListFileLexer_Token* token = cmListFileLexer_Scan(this->Lexer)) { - if(token->type == cmListFileLexer_Token_Newline) + if(token->type == cmListFileLexer_Token_Space) + { + } + else if(token->type == cmListFileLexer_Token_Newline) { haveNewline = true; } @@ -244,7 +248,9 @@ bool cmListFileParser::ParseFunction(const char* name, long line) // Command name has already been parsed. Read the left paren. cmListFileLexer_Token* token; - if(!(token = cmListFileLexer_Scan(this->Lexer))) + while((token = cmListFileLexer_Scan(this->Lexer)) && + token->type == cmListFileLexer_Token_Space) {} + if(!token) { cmOStringStream error; error << "Error in cmake code at\n" << this->FileName << ":" @@ -266,14 +272,23 @@ bool cmListFileParser::ParseFunction(const char* name, long line) } // Arguments. - unsigned long lastLine = cmListFileLexer_GetCurrentLine(this->Lexer); + unsigned long lastLine; unsigned long parenDepth = 0; - while((token = cmListFileLexer_Scan(this->Lexer))) + this->Separation = SeparationOkay; + while((lastLine = cmListFileLexer_GetCurrentLine(this->Lexer), + token = cmListFileLexer_Scan(this->Lexer))) { + if(token->type == cmListFileLexer_Token_Space || + token->type == cmListFileLexer_Token_Newline) + { + this->Separation = SeparationOkay; + continue; + } if(token->type == cmListFileLexer_Token_ParenLeft) { parenDepth++; this->AddArgument(token, cmListFileArgument::Unquoted); + this->Separation = SeparationOkay; } else if(token->type == cmListFileLexer_Token_ParenRight) { @@ -282,18 +297,22 @@ bool cmListFileParser::ParseFunction(const char* name, long line) return true; } parenDepth--; + this->Separation = SeparationOkay; this->AddArgument(token, cmListFileArgument::Unquoted); + this->Separation = SeparationWarning; } else if(token->type == cmListFileLexer_Token_Identifier || token->type == cmListFileLexer_Token_ArgumentUnquoted) { this->AddArgument(token, cmListFileArgument::Unquoted); + this->Separation = SeparationWarning; } else if(token->type == cmListFileLexer_Token_ArgumentQuoted) { this->AddArgument(token, cmListFileArgument::Quoted); + this->Separation = SeparationWarning; } - else if(token->type != cmListFileLexer_Token_Newline) + else { // Error. cmOStringStream error; @@ -306,7 +325,6 @@ bool cmListFileParser::ParseFunction(const char* name, long line) cmSystemTools::Error(error.str().c_str()); return false; } - lastLine = cmListFileLexer_GetCurrentLine(this->Lexer); } cmOStringStream error; @@ -325,6 +343,16 @@ void cmListFileParser::AddArgument(cmListFileLexer_Token* token, { cmListFileArgument a(token->text, delim, this->FileName, token->line); this->Function.Arguments.push_back(a); + if(this->Separation == SeparationOkay) + { + return; + } + cmOStringStream m; + m << "Syntax Warning in cmake code at\n" + << " " << this->FileName << ":" << token->line << ":" + << token->column << "\n" + << "Argument not separated from preceding token by whitespace."; + this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, m.str().c_str()); } //---------------------------------------------------------------------------- diff --git a/Source/cmListFileLexer.c b/Source/cmListFileLexer.c index a256b9b05..09dd0118b 100644 --- a/Source/cmListFileLexer.c +++ b/Source/cmListFileLexer.c @@ -378,13 +378,13 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[44] = +static yyconst flex_int16_t yy_accept[45] = { 0, 0, 0, 0, 0, 17, 6, 14, 1, 8, 2, 6, 3, 4, 6, 15, 9, 11, 12, 13, 6, - 0, 6, 0, 2, 0, 5, 6, 9, 0, 10, - 0, 7, 0, 0, 0, 7, 0, 7, 0, 0, - 0, 0, 0 + 0, 6, 0, 14, 2, 0, 5, 6, 9, 0, + 10, 0, 7, 0, 0, 0, 7, 0, 7, 0, + 0, 0, 0, 0 } ; static yyconst flex_int32_t yy_ec[256] = @@ -421,62 +421,64 @@ static yyconst flex_int32_t yy_ec[256] = static yyconst flex_int32_t yy_meta[13] = { 0, - 1, 1, 2, 1, 3, 1, 1, 1, 4, 4, - 4, 1 + 1, 2, 3, 2, 4, 1, 1, 1, 5, 5, + 5, 1 } ; -static yyconst flex_int16_t yy_base[54] = +static yyconst flex_int16_t yy_base[56] = { 0, - 0, 0, 10, 20, 36, 32, 102, 102, 102, 0, - 27, 102, 102, 35, 0, 22, 102, 102, 44, 0, - 49, 23, 0, 0, 21, 0, 0, 17, 23, 102, - 0, 61, 19, 0, 17, 0, 15, 13, 0, 11, - 10, 9, 102, 73, 77, 81, 85, 89, 13, 93, - 12, 97, 10 + 0, 0, 10, 20, 38, 32, 0, 109, 109, 0, + 28, 109, 109, 35, 0, 23, 109, 109, 44, 0, + 49, 26, 0, 0, 0, 22, 0, 0, 18, 24, + 109, 0, 61, 20, 0, 18, 0, 17, 16, 0, + 12, 11, 10, 109, 73, 16, 78, 83, 88, 93, + 12, 98, 11, 103, 9 } ; -static yyconst flex_int16_t yy_def[54] = +static yyconst flex_int16_t yy_def[56] = { 0, - 43, 1, 44, 44, 43, 43, 43, 43, 43, 45, - 6, 43, 43, 6, 46, 47, 43, 43, 47, 6, - 43, 6, 48, 45, 49, 14, 6, 47, 47, 43, - 21, 43, 21, 50, 51, 32, 49, 32, 52, 53, - 51, 53, 0, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43 + 44, 1, 45, 45, 44, 44, 46, 44, 44, 47, + 6, 44, 44, 6, 48, 49, 44, 44, 49, 6, + 44, 6, 50, 46, 47, 51, 14, 6, 49, 49, + 44, 21, 44, 21, 52, 53, 33, 51, 33, 54, + 55, 53, 55, 0, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44 } ; -static yyconst flex_int16_t yy_nxt[115] = +static yyconst flex_int16_t yy_nxt[122] = { 0, 6, 7, 8, 7, 9, 10, 11, 12, 13, 6, - 14, 15, 17, 42, 18, 41, 37, 31, 32, 31, - 35, 19, 17, 36, 18, 32, 40, 28, 29, 36, - 35, 19, 20, 29, 25, 43, 21, 43, 22, 43, - 43, 20, 20, 23, 26, 26, 30, 43, 28, 31, - 31, 43, 43, 32, 43, 33, 43, 43, 31, 31, - 34, 32, 43, 43, 43, 21, 43, 38, 43, 43, - 32, 32, 39, 16, 16, 16, 16, 24, 43, 24, - 24, 27, 43, 27, 27, 28, 43, 43, 28, 20, - 43, 20, 20, 31, 43, 31, 31, 32, 43, 32, + 14, 15, 17, 43, 18, 42, 38, 24, 32, 33, + 32, 19, 17, 36, 18, 37, 33, 41, 29, 30, + 37, 19, 20, 36, 30, 26, 21, 44, 22, 44, + 44, 20, 20, 23, 27, 27, 31, 44, 29, 32, + 32, 44, 44, 33, 44, 34, 44, 44, 32, 32, + 35, 33, 44, 44, 44, 21, 44, 39, 44, 44, + 33, 33, 40, 16, 16, 16, 16, 16, 25, 25, + 44, 25, 25, 28, 28, 44, 28, 28, 29, 29, + 44, 44, 29, 20, 20, 44, 20, 20, 32, 32, - 32, 5, 43, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 43 + 44, 32, 32, 33, 33, 44, 33, 33, 5, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44 } ; -static yyconst flex_int16_t yy_chk[115] = +static yyconst flex_int16_t yy_chk[122] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 3, 53, 3, 51, 49, 42, 41, 40, - 38, 3, 4, 37, 4, 35, 33, 29, 28, 25, - 22, 4, 6, 16, 11, 5, 6, 0, 6, 0, + 1, 1, 3, 55, 3, 53, 51, 46, 43, 42, + 41, 3, 4, 39, 4, 38, 36, 34, 30, 29, + 26, 4, 6, 22, 16, 11, 6, 5, 6, 0, 0, 6, 6, 6, 14, 14, 19, 0, 19, 21, 21, 0, 0, 21, 0, 21, 0, 0, 21, 21, - 21, 32, 0, 0, 0, 32, 0, 32, 0, 0, - 32, 32, 32, 44, 44, 44, 44, 45, 0, 45, - 45, 46, 0, 46, 46, 47, 0, 0, 47, 48, - 0, 48, 48, 50, 0, 50, 50, 52, 0, 52, + 21, 33, 0, 0, 0, 33, 0, 33, 0, 0, + 33, 33, 33, 45, 45, 45, 45, 45, 47, 47, + 0, 47, 47, 48, 48, 0, 48, 48, 49, 49, + 0, 0, 49, 50, 50, 0, 50, 50, 52, 52, - 52, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 43 + 0, 52, 52, 54, 54, 0, 54, 54, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44 } ; /* Table of booleans, true if rule could match eol. */ @@ -561,7 +563,7 @@ static void cmListFileLexerDestroy(cmListFileLexer* lexer); /*--------------------------------------------------------------------------*/ -#line 567 "cmListFileLexer.c" +#line 569 "cmListFileLexer.c" #define INITIAL 0 #define STRING 1 @@ -793,7 +795,7 @@ YY_DECL #line 81 "cmListFileLexer.in.l" -#line 801 "cmListFileLexer.c" +#line 803 "cmListFileLexer.c" if ( !yyg->yy_init ) { @@ -846,13 +848,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 44 ) + if ( yy_current_state >= 45 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 102 ); + while ( yy_base[yy_current_state] != 109 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -1016,12 +1018,14 @@ case 14: YY_RULE_SETUP #line 171 "cmListFileLexer.in.l" { + lexer->token.type = cmListFileLexer_Token_Space; + cmListFileLexerSetToken(lexer, yytext, yyleng); lexer->column += yyleng; + return 1; } - YY_BREAK case 15: YY_RULE_SETUP -#line 175 "cmListFileLexer.in.l" +#line 178 "cmListFileLexer.in.l" { lexer->token.type = cmListFileLexer_Token_BadCharacter; cmListFileLexerSetToken(lexer, yytext, yyleng); @@ -1029,7 +1033,7 @@ YY_RULE_SETUP return 1; } case YY_STATE_EOF(INITIAL): -#line 182 "cmListFileLexer.in.l" +#line 185 "cmListFileLexer.in.l" { lexer->token.type = cmListFileLexer_Token_None; cmListFileLexerSetToken(lexer, 0, 0); @@ -1037,10 +1041,10 @@ case YY_STATE_EOF(INITIAL): } case 16: YY_RULE_SETUP -#line 188 "cmListFileLexer.in.l" +#line 191 "cmListFileLexer.in.l" ECHO; YY_BREAK -#line 1058 "cmListFileLexer.c" +#line 1063 "cmListFileLexer.c" case YY_END_OF_BUFFER: { @@ -1332,7 +1336,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 44 ) + if ( yy_current_state >= 45 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1361,11 +1365,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 44 ) + if ( yy_current_state >= 45 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 43); + yy_is_jam = (yy_current_state == 44); return yy_is_jam ? 0 : yy_current_state; } @@ -2162,7 +2166,7 @@ void cmListFileLexer_yyfree (void * ptr , yyscan_t yyscanner) #define YYTABLES_NAME "yytables" -#line 188 "cmListFileLexer.in.l" +#line 191 "cmListFileLexer.in.l" @@ -2399,6 +2403,7 @@ const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer, switch(type) { case cmListFileLexer_Token_None: return "nothing"; + case cmListFileLexer_Token_Space: return "space"; case cmListFileLexer_Token_Newline: return "newline"; case cmListFileLexer_Token_Identifier: return "identifier"; case cmListFileLexer_Token_ParenLeft: return "left paren"; diff --git a/Source/cmListFileLexer.h b/Source/cmListFileLexer.h index 5f4db33c4..cc78b5c2f 100644 --- a/Source/cmListFileLexer.h +++ b/Source/cmListFileLexer.h @@ -15,6 +15,7 @@ typedef enum cmListFileLexer_Type_e { cmListFileLexer_Token_None, + cmListFileLexer_Token_Space, cmListFileLexer_Token_Newline, cmListFileLexer_Token_Identifier, cmListFileLexer_Token_ParenLeft, diff --git a/Source/cmListFileLexer.in.l b/Source/cmListFileLexer.in.l index 45fcdd29d..e5ddb9e4a 100644 --- a/Source/cmListFileLexer.in.l +++ b/Source/cmListFileLexer.in.l @@ -168,8 +168,11 @@ LEGACY {MAKEVAR}|{UNQUOTED}|\"({MAKEVAR}|{UNQUOTED}|[ \t])*\" return 1; } -[ \t\r] { +[ \t\r]+ { + lexer->token.type = cmListFileLexer_Token_Space; + cmListFileLexerSetToken(lexer, yytext, yyleng); lexer->column += yyleng; + return 1; } . { @@ -420,6 +423,7 @@ const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer, switch(type) { case cmListFileLexer_Token_None: return "nothing"; + case cmListFileLexer_Token_Space: return "space"; case cmListFileLexer_Token_Newline: return "newline"; case cmListFileLexer_Token_Identifier: return "identifier"; case cmListFileLexer_Token_ParenLeft: return "left paren"; diff --git a/Tests/RunCMake/Syntax/StringNoSpace-stderr.txt b/Tests/RunCMake/Syntax/StringNoSpace-stderr.txt index 2d111aaa8..89c2d2ae5 100644 --- a/Tests/RunCMake/Syntax/StringNoSpace-stderr.txt +++ b/Tests/RunCMake/Syntax/StringNoSpace-stderr.txt @@ -1,3 +1,19 @@ -^\[1 \${var} \\n 4\] +CMake Warning \(dev\) at CMakeLists.txt:3 \(include\): + Syntax Warning in cmake code at + + .*/Tests/RunCMake/Syntax/StringNoSpace.cmake:2:28 + + Argument not separated from preceding token by whitespace. +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\) at CMakeLists.txt:3 \(include\): + Syntax Warning in cmake code at + + .*/Tests/RunCMake/Syntax/StringNoSpace.cmake:2:31 + + Argument not separated from preceding token by whitespace. +This warning is for project developers. Use -Wno-dev to suppress it. + +\[1 \${var} \\n 4\] \[x\] \[y\]$