0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 8.2.2668: Vim9: omitting "call" for "confirm()" does not give an error

Problem:    Vim9: omitting "call" for "confirm()" does not give an error.
Solution:   Do not recognize a modifier followed by "(".
This commit is contained in:
Bram Moolenaar 2021-03-27 22:20:21 +01:00
parent 24f21fdfca
commit f49a1fcdb9
3 changed files with 84 additions and 53 deletions

View File

@ -2684,6 +2684,58 @@ ex_errmsg(char *msg, char_u *arg)
return ex_error_buf; return ex_error_buf;
} }
/*
* Check for an Ex command with optional tail.
* If there is a match advance "pp" to the argument and return TRUE.
* If "noparen" is TRUE do not recognize the command followed by "(".
*/
static int
checkforcmd_opt(
char_u **pp, // start of command
char *cmd, // name of command
int len, // required length
int noparen)
{
int i;
for (i = 0; cmd[i] != NUL; ++i)
if (((char_u *)cmd)[i] != (*pp)[i])
break;
if (i >= len && !isalpha((*pp)[i])
&& (*pp)[i] != '_' && (!noparen || (*pp)[i] != '('))
{
*pp = skipwhite(*pp + i);
return TRUE;
}
return FALSE;
}
/*
* Check for an Ex command with optional tail.
* If there is a match advance "pp" to the argument and return TRUE.
*/
int
checkforcmd(
char_u **pp, // start of command
char *cmd, // name of command
int len) // required length
{
return checkforcmd_opt(pp, cmd, len, FALSE);
}
/*
* Check for an Ex command with optional tail, not followed by "(".
* If there is a match advance "pp" to the argument and return TRUE.
*/
static int
checkforcmd_noparen(
char_u **pp, // start of command
char *cmd, // name of command
int len) // required length
{
return checkforcmd_opt(pp, cmd, len, TRUE);
}
/* /*
* Parse and skip over command modifiers: * Parse and skip over command modifiers:
* - update eap->cmd * - update eap->cmd
@ -2770,51 +2822,51 @@ parse_command_modifiers(
switch (*p) switch (*p)
{ {
// When adding an entry, also modify cmd_exists(). // When adding an entry, also modify cmd_exists().
case 'a': if (!checkforcmd(&eap->cmd, "aboveleft", 3)) case 'a': if (!checkforcmd_noparen(&eap->cmd, "aboveleft", 3))
break; break;
cmod->cmod_split |= WSP_ABOVE; cmod->cmod_split |= WSP_ABOVE;
continue; continue;
case 'b': if (checkforcmd(&eap->cmd, "belowright", 3)) case 'b': if (checkforcmd_noparen(&eap->cmd, "belowright", 3))
{ {
cmod->cmod_split |= WSP_BELOW; cmod->cmod_split |= WSP_BELOW;
continue; continue;
} }
if (checkforcmd(&eap->cmd, "browse", 3)) if (checkforcmd_opt(&eap->cmd, "browse", 3, TRUE))
{ {
#ifdef FEAT_BROWSE_CMD #ifdef FEAT_BROWSE_CMD
cmod->cmod_flags |= CMOD_BROWSE; cmod->cmod_flags |= CMOD_BROWSE;
#endif #endif
continue; continue;
} }
if (!checkforcmd(&eap->cmd, "botright", 2)) if (!checkforcmd_noparen(&eap->cmd, "botright", 2))
break; break;
cmod->cmod_split |= WSP_BOT; cmod->cmod_split |= WSP_BOT;
continue; continue;
case 'c': if (!checkforcmd(&eap->cmd, "confirm", 4)) case 'c': if (!checkforcmd_opt(&eap->cmd, "confirm", 4, TRUE))
break; break;
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
cmod->cmod_flags |= CMOD_CONFIRM; cmod->cmod_flags |= CMOD_CONFIRM;
#endif #endif
continue; continue;
case 'k': if (checkforcmd(&eap->cmd, "keepmarks", 3)) case 'k': if (checkforcmd_noparen(&eap->cmd, "keepmarks", 3))
{ {
cmod->cmod_flags |= CMOD_KEEPMARKS; cmod->cmod_flags |= CMOD_KEEPMARKS;
continue; continue;
} }
if (checkforcmd(&eap->cmd, "keepalt", 5)) if (checkforcmd_noparen(&eap->cmd, "keepalt", 5))
{ {
cmod->cmod_flags |= CMOD_KEEPALT; cmod->cmod_flags |= CMOD_KEEPALT;
continue; continue;
} }
if (checkforcmd(&eap->cmd, "keeppatterns", 5)) if (checkforcmd_noparen(&eap->cmd, "keeppatterns", 5))
{ {
cmod->cmod_flags |= CMOD_KEEPPATTERNS; cmod->cmod_flags |= CMOD_KEEPPATTERNS;
continue; continue;
} }
if (!checkforcmd(&eap->cmd, "keepjumps", 5)) if (!checkforcmd_noparen(&eap->cmd, "keepjumps", 5))
break; break;
cmod->cmod_flags |= CMOD_KEEPJUMPS; cmod->cmod_flags |= CMOD_KEEPJUMPS;
continue; continue;
@ -2823,7 +2875,7 @@ parse_command_modifiers(
{ {
char_u *reg_pat; char_u *reg_pat;
if (!checkforcmd(&p, "filter", 4) if (!checkforcmd_noparen(&p, "filter", 4)
|| *p == NUL || ends_excmd(*p)) || *p == NUL || ends_excmd(*p))
break; break;
if (*p == '!') if (*p == '!')
@ -2857,45 +2909,45 @@ parse_command_modifiers(
} }
// ":hide" and ":hide | cmd" are not modifiers // ":hide" and ":hide | cmd" are not modifiers
case 'h': if (p != eap->cmd || !checkforcmd(&p, "hide", 3) case 'h': if (p != eap->cmd || !checkforcmd_noparen(&p, "hide", 3)
|| *p == NUL || ends_excmd(*p)) || *p == NUL || ends_excmd(*p))
break; break;
eap->cmd = p; eap->cmd = p;
cmod->cmod_flags |= CMOD_HIDE; cmod->cmod_flags |= CMOD_HIDE;
continue; continue;
case 'l': if (checkforcmd(&eap->cmd, "lockmarks", 3)) case 'l': if (checkforcmd_noparen(&eap->cmd, "lockmarks", 3))
{ {
cmod->cmod_flags |= CMOD_LOCKMARKS; cmod->cmod_flags |= CMOD_LOCKMARKS;
continue; continue;
} }
if (!checkforcmd(&eap->cmd, "leftabove", 5)) if (!checkforcmd_noparen(&eap->cmd, "leftabove", 5))
break; break;
cmod->cmod_split |= WSP_ABOVE; cmod->cmod_split |= WSP_ABOVE;
continue; continue;
case 'n': if (checkforcmd(&eap->cmd, "noautocmd", 3)) case 'n': if (checkforcmd_noparen(&eap->cmd, "noautocmd", 3))
{ {
cmod->cmod_flags |= CMOD_NOAUTOCMD; cmod->cmod_flags |= CMOD_NOAUTOCMD;
continue; continue;
} }
if (!checkforcmd(&eap->cmd, "noswapfile", 3)) if (!checkforcmd_noparen(&eap->cmd, "noswapfile", 3))
break; break;
cmod->cmod_flags |= CMOD_NOSWAPFILE; cmod->cmod_flags |= CMOD_NOSWAPFILE;
continue; continue;
case 'r': if (!checkforcmd(&eap->cmd, "rightbelow", 6)) case 'r': if (!checkforcmd_noparen(&eap->cmd, "rightbelow", 6))
break; break;
cmod->cmod_split |= WSP_BELOW; cmod->cmod_split |= WSP_BELOW;
continue; continue;
case 's': if (checkforcmd(&eap->cmd, "sandbox", 3)) case 's': if (checkforcmd_noparen(&eap->cmd, "sandbox", 3))
{ {
cmod->cmod_flags |= CMOD_SANDBOX; cmod->cmod_flags |= CMOD_SANDBOX;
continue; continue;
} }
if (!checkforcmd(&eap->cmd, "silent", 3)) if (!checkforcmd_noparen(&eap->cmd, "silent", 3))
break; break;
cmod->cmod_flags |= CMOD_SILENT; cmod->cmod_flags |= CMOD_SILENT;
if (*eap->cmd == '!' && !VIM_ISWHITE(eap->cmd[-1])) if (*eap->cmd == '!' && !VIM_ISWHITE(eap->cmd[-1]))
@ -2906,7 +2958,7 @@ parse_command_modifiers(
} }
continue; continue;
case 't': if (checkforcmd(&p, "tab", 3)) case 't': if (checkforcmd_noparen(&p, "tab", 3))
{ {
if (!skip_only) if (!skip_only)
{ {
@ -2928,22 +2980,22 @@ parse_command_modifiers(
eap->cmd = p; eap->cmd = p;
continue; continue;
} }
if (!checkforcmd(&eap->cmd, "topleft", 2)) if (!checkforcmd_noparen(&eap->cmd, "topleft", 2))
break; break;
cmod->cmod_split |= WSP_TOP; cmod->cmod_split |= WSP_TOP;
continue; continue;
case 'u': if (!checkforcmd(&eap->cmd, "unsilent", 3)) case 'u': if (!checkforcmd_noparen(&eap->cmd, "unsilent", 3))
break; break;
cmod->cmod_flags |= CMOD_UNSILENT; cmod->cmod_flags |= CMOD_UNSILENT;
continue; continue;
case 'v': if (checkforcmd(&eap->cmd, "vertical", 4)) case 'v': if (checkforcmd_noparen(&eap->cmd, "vertical", 4))
{ {
cmod->cmod_split |= WSP_VERT; cmod->cmod_split |= WSP_VERT;
continue; continue;
} }
if (checkforcmd(&eap->cmd, "vim9cmd", 4)) if (checkforcmd_noparen(&eap->cmd, "vim9cmd", 4))
{ {
if (ends_excmd2(p, eap->cmd)) if (ends_excmd2(p, eap->cmd))
{ {
@ -2954,7 +3006,7 @@ parse_command_modifiers(
cmod->cmod_flags |= CMOD_VIM9CMD; cmod->cmod_flags |= CMOD_VIM9CMD;
continue; continue;
} }
if (!checkforcmd(&p, "verbose", 4)) if (!checkforcmd_noparen(&p, "verbose", 4))
break; break;
if (vim_isdigit(*eap->cmd)) if (vim_isdigit(*eap->cmd))
cmod->cmod_verbose = atoi((char *)eap->cmd); cmod->cmod_verbose = atoi((char *)eap->cmd);
@ -3251,29 +3303,6 @@ parse_cmd_address(exarg_T *eap, char **errormsg, int silent)
return OK; return OK;
} }
/*
* Check for an Ex command with optional tail.
* If there is a match advance "pp" to the argument and return TRUE.
*/
int
checkforcmd(
char_u **pp, // start of command
char *cmd, // name of command
int len) // required length
{
int i;
for (i = 0; cmd[i] != NUL; ++i)
if (((char_u *)cmd)[i] != (*pp)[i])
break;
if (i >= len && !isalpha((*pp)[i]) && (*pp)[i] != '_')
{
*pp = skipwhite(*pp + i);
return TRUE;
}
return FALSE;
}
/* /*
* Append "cmd" to the error message in IObuff. * Append "cmd" to the error message in IObuff.
* Takes care of limiting the length and handling 0xa0, which would be * Takes care of limiting the length and handling 0xa0, which would be

View File

@ -142,15 +142,15 @@ def Test_browse()
CheckFeature browse CheckFeature browse
var lines =<< trim END var lines =<< trim END
call browse(1, 2, 3, 4) browse(1, 2, 3, 4)
END END
CheckDefExecAndScriptFailure(lines, 'E1174: String required for argument 2') CheckDefExecAndScriptFailure(lines, 'E1174: String required for argument 2')
lines =<< trim END lines =<< trim END
call browse(1, 'title', 3, 4) browse(1, 'title', 3, 4)
END END
CheckDefExecAndScriptFailure(lines, 'E1174: String required for argument 3') CheckDefExecAndScriptFailure(lines, 'E1174: String required for argument 3')
lines =<< trim END lines =<< trim END
call browse(1, 'title', 'dir', 4) browse(1, 'title', 'dir', 4)
END END
CheckDefExecAndScriptFailure(lines, 'E1174: String required for argument 4') CheckDefExecAndScriptFailure(lines, 'E1174: String required for argument 4')
enddef enddef
@ -236,9 +236,9 @@ def Test_confirm()
CheckFeature dialog_con CheckFeature dialog_con
endif endif
assert_fails('call confirm(true)', 'E1174') assert_fails('confirm(true)', 'E1174')
assert_fails('call confirm("yes", true)', 'E1174') assert_fails('confirm("yes", true)', 'E1174')
assert_fails('call confirm("yes", "maybe", 2, true)', 'E1174') assert_fails('confirm("yes", "maybe", 2, true)', 'E1174')
enddef enddef
def Test_copy_return_type() def Test_copy_return_type()

View File

@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2668,
/**/ /**/
2667, 2667,
/**/ /**/