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.
This commit is contained in:
Brad King 2013-02-16 20:41:47 -05:00
parent e75b69f55b
commit 58e524165d
5 changed files with 117 additions and 63 deletions

View File

@ -36,6 +36,7 @@ struct cmListFileParser
const char* FileName; const char* FileName;
cmListFileLexer* Lexer; cmListFileLexer* Lexer;
cmListFileFunction Function; cmListFileFunction Function;
enum { SeparationOkay, SeparationWarning } Separation;
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -69,7 +70,10 @@ bool cmListFileParser::ParseFile()
while(cmListFileLexer_Token* token = while(cmListFileLexer_Token* token =
cmListFileLexer_Scan(this->Lexer)) 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; haveNewline = true;
} }
@ -244,7 +248,9 @@ bool cmListFileParser::ParseFunction(const char* name, long line)
// Command name has already been parsed. Read the left paren. // Command name has already been parsed. Read the left paren.
cmListFileLexer_Token* token; cmListFileLexer_Token* token;
if(!(token = cmListFileLexer_Scan(this->Lexer))) while((token = cmListFileLexer_Scan(this->Lexer)) &&
token->type == cmListFileLexer_Token_Space) {}
if(!token)
{ {
cmOStringStream error; cmOStringStream error;
error << "Error in cmake code at\n" << this->FileName << ":" error << "Error in cmake code at\n" << this->FileName << ":"
@ -266,14 +272,23 @@ bool cmListFileParser::ParseFunction(const char* name, long line)
} }
// Arguments. // Arguments.
unsigned long lastLine = cmListFileLexer_GetCurrentLine(this->Lexer); unsigned long lastLine;
unsigned long parenDepth = 0; 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) if(token->type == cmListFileLexer_Token_ParenLeft)
{ {
parenDepth++; parenDepth++;
this->AddArgument(token, cmListFileArgument::Unquoted); this->AddArgument(token, cmListFileArgument::Unquoted);
this->Separation = SeparationOkay;
} }
else if(token->type == cmListFileLexer_Token_ParenRight) else if(token->type == cmListFileLexer_Token_ParenRight)
{ {
@ -282,18 +297,22 @@ bool cmListFileParser::ParseFunction(const char* name, long line)
return true; return true;
} }
parenDepth--; parenDepth--;
this->Separation = SeparationOkay;
this->AddArgument(token, cmListFileArgument::Unquoted); this->AddArgument(token, cmListFileArgument::Unquoted);
this->Separation = SeparationWarning;
} }
else if(token->type == cmListFileLexer_Token_Identifier || else if(token->type == cmListFileLexer_Token_Identifier ||
token->type == cmListFileLexer_Token_ArgumentUnquoted) token->type == cmListFileLexer_Token_ArgumentUnquoted)
{ {
this->AddArgument(token, cmListFileArgument::Unquoted); this->AddArgument(token, cmListFileArgument::Unquoted);
this->Separation = SeparationWarning;
} }
else if(token->type == cmListFileLexer_Token_ArgumentQuoted) else if(token->type == cmListFileLexer_Token_ArgumentQuoted)
{ {
this->AddArgument(token, cmListFileArgument::Quoted); this->AddArgument(token, cmListFileArgument::Quoted);
this->Separation = SeparationWarning;
} }
else if(token->type != cmListFileLexer_Token_Newline) else
{ {
// Error. // Error.
cmOStringStream error; cmOStringStream error;
@ -306,7 +325,6 @@ bool cmListFileParser::ParseFunction(const char* name, long line)
cmSystemTools::Error(error.str().c_str()); cmSystemTools::Error(error.str().c_str());
return false; return false;
} }
lastLine = cmListFileLexer_GetCurrentLine(this->Lexer);
} }
cmOStringStream error; cmOStringStream error;
@ -325,6 +343,16 @@ void cmListFileParser::AddArgument(cmListFileLexer_Token* token,
{ {
cmListFileArgument a(token->text, delim, this->FileName, token->line); cmListFileArgument a(token->text, delim, this->FileName, token->line);
this->Function.Arguments.push_back(a); 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());
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------

View File

@ -378,13 +378,13 @@ struct yy_trans_info
flex_int32_t yy_verify; flex_int32_t yy_verify;
flex_int32_t yy_nxt; 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, 0, 17, 6, 14, 1, 8, 2, 0, 0, 0, 0, 17, 6, 14, 1, 8, 2,
6, 3, 4, 6, 15, 9, 11, 12, 13, 6, 6, 3, 4, 6, 15, 9, 11, 12, 13, 6,
0, 6, 0, 2, 0, 5, 6, 9, 0, 10, 0, 6, 0, 14, 2, 0, 5, 6, 9, 0,
0, 7, 0, 0, 0, 7, 0, 7, 0, 0, 10, 0, 7, 0, 0, 0, 7, 0, 7, 0,
0, 0, 0 0, 0, 0, 0
} ; } ;
static yyconst flex_int32_t yy_ec[256] = 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] = static yyconst flex_int32_t yy_meta[13] =
{ 0, { 0,
1, 1, 2, 1, 3, 1, 1, 1, 4, 4, 1, 2, 3, 2, 4, 1, 1, 1, 5, 5,
4, 1 5, 1
} ; } ;
static yyconst flex_int16_t yy_base[54] = static yyconst flex_int16_t yy_base[56] =
{ 0, { 0,
0, 0, 10, 20, 36, 32, 102, 102, 102, 0, 0, 0, 10, 20, 38, 32, 0, 109, 109, 0,
27, 102, 102, 35, 0, 22, 102, 102, 44, 0, 28, 109, 109, 35, 0, 23, 109, 109, 44, 0,
49, 23, 0, 0, 21, 0, 0, 17, 23, 102, 49, 26, 0, 0, 0, 22, 0, 0, 18, 24,
0, 61, 19, 0, 17, 0, 15, 13, 0, 11, 109, 0, 61, 20, 0, 18, 0, 17, 16, 0,
10, 9, 102, 73, 77, 81, 85, 89, 13, 93, 12, 11, 10, 109, 73, 16, 78, 83, 88, 93,
12, 97, 10 12, 98, 11, 103, 9
} ; } ;
static yyconst flex_int16_t yy_def[54] = static yyconst flex_int16_t yy_def[56] =
{ 0, { 0,
43, 1, 44, 44, 43, 43, 43, 43, 43, 45, 44, 1, 45, 45, 44, 44, 46, 44, 44, 47,
6, 43, 43, 6, 46, 47, 43, 43, 47, 6, 6, 44, 44, 6, 48, 49, 44, 44, 49, 6,
43, 6, 48, 45, 49, 14, 6, 47, 47, 43, 44, 6, 50, 46, 47, 51, 14, 6, 49, 49,
21, 43, 21, 50, 51, 32, 49, 32, 52, 53, 44, 21, 44, 21, 52, 53, 33, 51, 33, 54,
51, 53, 0, 43, 43, 43, 43, 43, 43, 43, 55, 53, 55, 0, 44, 44, 44, 44, 44, 44,
43, 43, 43 44, 44, 44, 44, 44
} ; } ;
static yyconst flex_int16_t yy_nxt[115] = static yyconst flex_int16_t yy_nxt[122] =
{ 0, { 0,
6, 7, 8, 7, 9, 10, 11, 12, 13, 6, 6, 7, 8, 7, 9, 10, 11, 12, 13, 6,
14, 15, 17, 42, 18, 41, 37, 31, 32, 31, 14, 15, 17, 43, 18, 42, 38, 24, 32, 33,
35, 19, 17, 36, 18, 32, 40, 28, 29, 36, 32, 19, 17, 36, 18, 37, 33, 41, 29, 30,
35, 19, 20, 29, 25, 43, 21, 43, 22, 43, 37, 19, 20, 36, 30, 26, 21, 44, 22, 44,
43, 20, 20, 23, 26, 26, 30, 43, 28, 31, 44, 20, 20, 23, 27, 27, 31, 44, 29, 32,
31, 43, 43, 32, 43, 33, 43, 43, 31, 31, 32, 44, 44, 33, 44, 34, 44, 44, 32, 32,
34, 32, 43, 43, 43, 21, 43, 38, 43, 43, 35, 33, 44, 44, 44, 21, 44, 39, 44, 44,
32, 32, 39, 16, 16, 16, 16, 24, 43, 24, 33, 33, 40, 16, 16, 16, 16, 16, 25, 25,
24, 27, 43, 27, 27, 28, 43, 43, 28, 20, 44, 25, 25, 28, 28, 44, 28, 28, 29, 29,
43, 20, 20, 31, 43, 31, 31, 32, 43, 32, 44, 44, 29, 20, 20, 44, 20, 20, 32, 32,
32, 5, 43, 43, 43, 43, 43, 43, 43, 43, 44, 32, 32, 33, 33, 44, 33, 33, 5, 44,
43, 43, 43, 43 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, { 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 3, 53, 3, 51, 49, 42, 41, 40, 1, 1, 3, 55, 3, 53, 51, 46, 43, 42,
38, 3, 4, 37, 4, 35, 33, 29, 28, 25, 41, 3, 4, 39, 4, 38, 36, 34, 30, 29,
22, 4, 6, 16, 11, 5, 6, 0, 6, 0, 26, 4, 6, 22, 16, 11, 6, 5, 6, 0,
0, 6, 6, 6, 14, 14, 19, 0, 19, 21, 0, 6, 6, 6, 14, 14, 19, 0, 19, 21,
21, 0, 0, 21, 0, 21, 0, 0, 21, 21, 21, 0, 0, 21, 0, 21, 0, 0, 21, 21,
21, 32, 0, 0, 0, 32, 0, 32, 0, 0, 21, 33, 0, 0, 0, 33, 0, 33, 0, 0,
32, 32, 32, 44, 44, 44, 44, 45, 0, 45, 33, 33, 33, 45, 45, 45, 45, 45, 47, 47,
45, 46, 0, 46, 46, 47, 0, 0, 47, 48, 0, 47, 47, 48, 48, 0, 48, 48, 49, 49,
0, 48, 48, 50, 0, 50, 50, 52, 0, 52, 0, 0, 49, 50, 50, 0, 50, 50, 52, 52,
52, 43, 43, 43, 43, 43, 43, 43, 43, 43, 0, 52, 52, 54, 54, 0, 54, 54, 44, 44,
43, 43, 43, 43 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
44
} ; } ;
/* Table of booleans, true if rule could match eol. */ /* 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 INITIAL 0
#define STRING 1 #define STRING 1
@ -793,7 +795,7 @@ YY_DECL
#line 81 "cmListFileLexer.in.l" #line 81 "cmListFileLexer.in.l"
#line 801 "cmListFileLexer.c" #line 803 "cmListFileLexer.c"
if ( !yyg->yy_init ) if ( !yyg->yy_init )
{ {
@ -846,13 +848,13 @@ yy_match:
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{ {
yy_current_state = (int) yy_def[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_c = yy_meta[(unsigned int) yy_c];
} }
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
++yy_cp; ++yy_cp;
} }
while ( yy_base[yy_current_state] != 102 ); while ( yy_base[yy_current_state] != 109 );
yy_find_action: yy_find_action:
yy_act = yy_accept[yy_current_state]; yy_act = yy_accept[yy_current_state];
@ -1016,12 +1018,14 @@ case 14:
YY_RULE_SETUP YY_RULE_SETUP
#line 171 "cmListFileLexer.in.l" #line 171 "cmListFileLexer.in.l"
{ {
lexer->token.type = cmListFileLexer_Token_Space;
cmListFileLexerSetToken(lexer, yytext, yyleng);
lexer->column += yyleng; lexer->column += yyleng;
return 1;
} }
YY_BREAK
case 15: case 15:
YY_RULE_SETUP YY_RULE_SETUP
#line 175 "cmListFileLexer.in.l" #line 178 "cmListFileLexer.in.l"
{ {
lexer->token.type = cmListFileLexer_Token_BadCharacter; lexer->token.type = cmListFileLexer_Token_BadCharacter;
cmListFileLexerSetToken(lexer, yytext, yyleng); cmListFileLexerSetToken(lexer, yytext, yyleng);
@ -1029,7 +1033,7 @@ YY_RULE_SETUP
return 1; return 1;
} }
case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(INITIAL):
#line 182 "cmListFileLexer.in.l" #line 185 "cmListFileLexer.in.l"
{ {
lexer->token.type = cmListFileLexer_Token_None; lexer->token.type = cmListFileLexer_Token_None;
cmListFileLexerSetToken(lexer, 0, 0); cmListFileLexerSetToken(lexer, 0, 0);
@ -1037,10 +1041,10 @@ case YY_STATE_EOF(INITIAL):
} }
case 16: case 16:
YY_RULE_SETUP YY_RULE_SETUP
#line 188 "cmListFileLexer.in.l" #line 191 "cmListFileLexer.in.l"
ECHO; ECHO;
YY_BREAK YY_BREAK
#line 1058 "cmListFileLexer.c" #line 1063 "cmListFileLexer.c"
case YY_END_OF_BUFFER: 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 ) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{ {
yy_current_state = (int) yy_def[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_c = yy_meta[(unsigned int) yy_c];
} }
yy_current_state = yy_nxt[yy_base[yy_current_state] + (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 ) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{ {
yy_current_state = (int) yy_def[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_c = yy_meta[(unsigned int) yy_c];
} }
yy_current_state = yy_nxt[yy_base[yy_current_state] + (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; return yy_is_jam ? 0 : yy_current_state;
} }
@ -2162,7 +2166,7 @@ void cmListFileLexer_yyfree (void * ptr , yyscan_t yyscanner)
#define YYTABLES_NAME "yytables" #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) switch(type)
{ {
case cmListFileLexer_Token_None: return "nothing"; case cmListFileLexer_Token_None: return "nothing";
case cmListFileLexer_Token_Space: return "space";
case cmListFileLexer_Token_Newline: return "newline"; case cmListFileLexer_Token_Newline: return "newline";
case cmListFileLexer_Token_Identifier: return "identifier"; case cmListFileLexer_Token_Identifier: return "identifier";
case cmListFileLexer_Token_ParenLeft: return "left paren"; case cmListFileLexer_Token_ParenLeft: return "left paren";

View File

@ -15,6 +15,7 @@
typedef enum cmListFileLexer_Type_e typedef enum cmListFileLexer_Type_e
{ {
cmListFileLexer_Token_None, cmListFileLexer_Token_None,
cmListFileLexer_Token_Space,
cmListFileLexer_Token_Newline, cmListFileLexer_Token_Newline,
cmListFileLexer_Token_Identifier, cmListFileLexer_Token_Identifier,
cmListFileLexer_Token_ParenLeft, cmListFileLexer_Token_ParenLeft,

View File

@ -168,8 +168,11 @@ LEGACY {MAKEVAR}|{UNQUOTED}|\"({MAKEVAR}|{UNQUOTED}|[ \t])*\"
return 1; return 1;
} }
[ \t\r] { [ \t\r]+ {
lexer->token.type = cmListFileLexer_Token_Space;
cmListFileLexerSetToken(lexer, yytext, yyleng);
lexer->column += yyleng; lexer->column += yyleng;
return 1;
} }
. { . {
@ -420,6 +423,7 @@ const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer,
switch(type) switch(type)
{ {
case cmListFileLexer_Token_None: return "nothing"; case cmListFileLexer_Token_None: return "nothing";
case cmListFileLexer_Token_Space: return "space";
case cmListFileLexer_Token_Newline: return "newline"; case cmListFileLexer_Token_Newline: return "newline";
case cmListFileLexer_Token_Identifier: return "identifier"; case cmListFileLexer_Token_Identifier: return "identifier";
case cmListFileLexer_Token_ParenLeft: return "left paren"; case cmListFileLexer_Token_ParenLeft: return "left paren";

View File

@ -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\] \[x\]
\[y\]$ \[y\]$