changeset 23442:f00d6ff51046 v8.2.2264

patch 8.2.2264: Vim9: no error for mismatched :endfunc or :enddef Commit: https://github.com/vim/vim/commit/5178b1b02fc96f42d62199a4be9184c2aea8a49a Author: Bram Moolenaar <Bram@vim.org> Date: Fri Jan 1 18:43:51 2021 +0100 patch 8.2.2264: Vim9: no error for mismatched :endfunc or :enddef Problem: Vim9: no error for mismatched :endfunc or :enddef. Solution: Check for the mismatch. (issue https://github.com/vim/vim/issues/7582)
author Bram Moolenaar <Bram@vim.org>
date Fri, 01 Jan 2021 18:45:03 +0100
parents 74b8875277fb
children 99a660a781a7
files src/errors.h src/testdir/test_vim9_func.vim src/userfunc.c src/version.c
diffstat 4 files changed, 63 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/src/errors.h
+++ b/src/errors.h
@@ -335,3 +335,7 @@ EXTERN char e_script_variable_invalid_af
 	INIT(= N_("E1149: Script variable is invalid after reload in function %s"));
 EXTERN char e_script_variable_type_changed[]
 	INIT(= N_("E1150: Script variable type changed"));
+EXTERN char e_mismatched_endfunction[]
+	INIT(= N_("E1151: Mismatched endfunction"));
+EXTERN char e_mismatched_enddef[]
+	INIT(= N_("E1152: Mismatched enddef"));
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -79,6 +79,25 @@ def Test_funcdepth_error()
   set maxfuncdepth&
 enddef
 
+def Test_endfunc_enddef()
+  var lines =<< trim END
+    def Test()
+      echo 'test'
+      endfunc
+    enddef
+  END
+  CheckScriptFailure(lines, 'E1151:', 3)
+
+  lines =<< trim END
+    def Test()
+      func Nested()
+        echo 'test'
+      enddef
+    enddef
+  END
+  CheckScriptFailure(lines, 'E1152:', 4)
+enddef
+
 def ReturnString(): string
   return 'string'
 enddef
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -3404,35 +3404,51 @@ define_function(exarg_T *eap, char_u *na
 
 	    // Check for "endfunction" or "enddef".
 	    if (checkforcmd(&p, nesting_def[nesting]
-			     ? "enddef" : "endfunction", 4) && nesting-- == 0)
+						? "enddef" : "endfunction", 4))
 	    {
-		char_u *nextcmd = NULL;
-
-		if (*p == '|')
-		    nextcmd = p + 1;
-		else if (line_arg != NULL && *skipwhite(line_arg) != NUL)
-		    nextcmd = line_arg;
-		else if (*p != NUL && *p != '"' && p_verbose > 0)
-		    give_warning2(eap->cmdidx == CMD_def
-			? (char_u *)_("W1001: Text found after :enddef: %s")
-			: (char_u *)_("W22: Text found after :endfunction: %s"),
-			 p, TRUE);
-		if (nextcmd != NULL)
+		if (nesting-- == 0)
 		{
-		    // Another command follows. If the line came from "eap" we
-		    // can simply point into it, otherwise we need to change
-		    // "eap->cmdlinep".
-		    eap->nextcmd = nextcmd;
-		    if (line_to_free != NULL)
+		    char_u *nextcmd = NULL;
+
+		    if (*p == '|')
+			nextcmd = p + 1;
+		    else if (line_arg != NULL && *skipwhite(line_arg) != NUL)
+			nextcmd = line_arg;
+		    else if (*p != NUL && *p != '"' && p_verbose > 0)
+			give_warning2(eap->cmdidx == CMD_def
+			    ? (char_u *)_("W1001: Text found after :enddef: %s")
+			    : (char_u *)_("W22: Text found after :endfunction: %s"),
+			     p, TRUE);
+		    if (nextcmd != NULL)
 		    {
-			vim_free(*eap->cmdlinep);
-			*eap->cmdlinep = line_to_free;
-			line_to_free = NULL;
+			// Another command follows. If the line came from "eap"
+			// we can simply point into it, otherwise we need to
+			// change "eap->cmdlinep".
+			eap->nextcmd = nextcmd;
+			if (line_to_free != NULL)
+			{
+			    vim_free(*eap->cmdlinep);
+			    *eap->cmdlinep = line_to_free;
+			    line_to_free = NULL;
+			}
 		    }
+		    break;
 		}
-		break;
 	    }
 
+	    // Check for mismatched "endfunc" or "enddef".
+	    // We don't check for "def" inside "func" thus we also can't check
+	    // for "enddef".
+	    // We continue to find the end of the function, although we might
+	    // not find it.
+	    else if (nesting_def[nesting])
+	    {
+		if (checkforcmd(&p, "endfunction", 4))
+		    emsg(_(e_mismatched_endfunction));
+	    }
+	    else if (eap->cmdidx == CMD_def && checkforcmd(&p, "enddef", 4))
+		emsg(_(e_mismatched_enddef));
+
 	    // Increase indent inside "if", "while", "for" and "try", decrease
 	    // at "end".
 	    if (indent > 2 && (*p == '}' || STRNCMP(p, "end", 3) == 0))
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2264,
+/**/
     2263,
 /**/
     2262,