]> granicus.if.org Git - vim/commitdiff
patch 8.2.0159: non-materialized range() list causes problems v8.2.0159
authorBram Moolenaar <Bram@vim.org>
Mon, 27 Jan 2020 21:09:39 +0000 (22:09 +0100)
committerBram Moolenaar <Bram@vim.org>
Mon, 27 Jan 2020 21:09:39 +0000 (22:09 +0100)
Problem:    Non-materialized range() list causes problems. (Fujiwara Takuya)
Solution:   Materialize the list where needed.

12 files changed:
src/channel.c
src/eval.c
src/evalfunc.c
src/evalvars.c
src/highlight.c
src/insexpand.c
src/json.c
src/popupmenu.c
src/testdir/test_functions.vim
src/testdir/test_python3.vim
src/userfunc.c
src/version.c

index 5f03068734e7beb12424fe33f8acb7db576864ec..3d891e823667afc2d921705c303928951c8b8613 100644 (file)
@@ -5123,6 +5123,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
                    return FAIL;
                }
 
+               range_list_materialize(item->vval.v_list);
                li = item->vval.v_list->lv_first;
                for (; li != NULL && n < 16; li = li->li_next, n++)
                {
@@ -5529,6 +5530,7 @@ win32_build_cmd(list_T *l, garray_T *gap)
     listitem_T  *li;
     char_u     *s;
 
+    range_list_materialize(l);
     for (li = l->lv_first; li != NULL; li = li->li_next)
     {
        s = tv_get_string_chk(&li->li_tv);
index a9d0c7d4c4439a4e8d50dc5a16e8f62456bdcd1a..f01724389dc1666df267b948e0715094c445e126 100644 (file)
@@ -4205,7 +4205,7 @@ set_ref_in_list_items(list_T *l, int copyID, ht_stack_T **ht_stack)
     cur_l = l;
     for (;;)
     {
-       if (!abort)
+       if (!abort && cur_l->lv_first != &range_list_item)
            // Mark each item in the list.  If the item contains a hashtab
            // it is added to ht_stack, if it contains a list it is added to
            // list_stack.
index 5365227612550cc4a10575c610730208603ce924..9cdd65afce0a4f13b8eceab854ff68383d3a359e 100644 (file)
@@ -1856,7 +1856,7 @@ f_empty(typval_T *argvars, typval_T *rettv)
 #endif
        case VAR_LIST:
            n = argvars[0].vval.v_list == NULL
-                                 || argvars[0].vval.v_list->lv_first == NULL;
+                                       || argvars[0].vval.v_list->lv_len == 0;
            break;
        case VAR_DICT:
            n = argvars[0].vval.v_dict == NULL
@@ -2064,7 +2064,7 @@ execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
     if (argvars[arg_off].v_type == VAR_LIST)
     {
        list = argvars[arg_off].vval.v_list;
-       if (list == NULL || list->lv_first == NULL)
+       if (list == NULL || list->lv_len == 0)
            // empty list, no commands, empty output
            return;
        ++list->lv_refcount;
@@ -2114,8 +2114,10 @@ execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
        do_cmdline_cmd(cmd);
     else
     {
-       listitem_T      *item = list->lv_first;
+       listitem_T      *item;
 
+       range_list_materialize(list);
+       item = list->lv_first;
        do_cmdline(NULL, get_list_line, (void *)&item,
                      DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
        --list->lv_refcount;
@@ -2643,9 +2645,12 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
                    for (i = 0; i < arg_len; i++)
                        copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
                    if (lv_len > 0)
+                   {
+                       range_list_materialize(list);
                        for (li = list->lv_first; li != NULL;
                                                         li = li->li_next)
                            copy_tv(&li->li_tv, &pt->pt_argv[i++]);
+                   }
                }
 
                // For "function(dict.func, [], dict)" and "func" is a partial
@@ -4058,6 +4063,7 @@ f_index(typval_T *argvars, typval_T *rettv)
     l = argvars[0].vval.v_list;
     if (l != NULL)
     {
+       range_list_materialize(l);
        item = l->lv_first;
        if (argvars[2].v_type != VAR_UNKNOWN)
        {
@@ -4139,6 +4145,7 @@ f_inputdialog(typval_T *argvars, typval_T *rettv)
     static void
 f_inputlist(typval_T *argvars, typval_T *rettv)
 {
+    list_T     *l;
     listitem_T *li;
     int                selected;
     int                mouse_used;
@@ -4161,7 +4168,9 @@ f_inputlist(typval_T *argvars, typval_T *rettv)
     msg_scroll = TRUE;
     msg_clr_eos();
 
-    for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
+    l = argvars[0].vval.v_list;
+    range_list_materialize(l);
+    for (li = l->lv_first; li != NULL; li = li->li_next)
     {
        msg_puts((char *)tv_get_string(&li->li_tv));
        msg_putchar('\n');
@@ -4644,6 +4653,7 @@ find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
     {
        if ((l = argvars[0].vval.v_list) == NULL)
            goto theend;
+       range_list_materialize(l);
        li = l->lv_first;
     }
     else
@@ -4873,6 +4883,7 @@ max_min(typval_T *argvars, typval_T *rettv, int domax)
        l = argvars[0].vval.v_list;
        if (l != NULL)
        {
+           range_list_materialize(l);
            li = l->lv_first;
            if (li != NULL)
            {
@@ -5322,7 +5333,7 @@ f_range(typval_T *argvars, typval_T *rettv)
        list->lv_start = start;
        list->lv_end = end;
        list->lv_stride = stride;
-       list->lv_len = (end - start + 1) / stride;
+       list->lv_len = (end - start) / stride + 1;
     }
 }
 
@@ -6790,22 +6801,25 @@ f_setreg(typval_T *argvars, typval_T *rettv)
        allocval = lstval + len + 2;
        curallocval = allocval;
 
-       for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
-                                                            li = li->li_next)
+       if (ll != NULL)
        {
-           strval = tv_get_string_buf_chk(&li->li_tv, buf);
-           if (strval == NULL)
-               goto free_lstval;
-           if (strval == buf)
+           range_list_materialize(ll);
+           for (li = ll->lv_first; li != NULL; li = li->li_next)
            {
-               // Need to make a copy, next tv_get_string_buf_chk() will
-               // overwrite the string.
-               strval = vim_strsave(buf);
+               strval = tv_get_string_buf_chk(&li->li_tv, buf);
                if (strval == NULL)
                    goto free_lstval;
-               *curallocval++ = strval;
+               if (strval == buf)
+               {
+                   // Need to make a copy, next tv_get_string_buf_chk() will
+                   // overwrite the string.
+                   strval = vim_strsave(buf);
+                   if (strval == NULL)
+                       goto free_lstval;
+                   *curallocval++ = strval;
+               }
+               *curval++ = strval;
            }
-           *curval++ = strval;
        }
        *curval++ = NULL;
 
index 38cb457e11cd3e2904b9287f40c37462b0f0d876..cc4a70f75756082a3439806b5526a5f008cc4488 100644 (file)
@@ -843,6 +843,7 @@ ex_let_vars(
        return FAIL;
     }
 
+    range_list_materialize(l);
     item = l->lv_first;
     while (*arg != ']')
     {
@@ -1699,7 +1700,7 @@ item_lock(typval_T *tv, int deep, int lock)
                    l->lv_lock |= VAR_LOCKED;
                else
                    l->lv_lock &= ~VAR_LOCKED;
-               if (deep < 0 || deep > 1)
+               if ((deep < 0 || deep > 1) && l->lv_first != &range_list_item)
                    // recursive: lock/unlock the items the List contains
                    for (li = l->lv_first; li != NULL; li = li->li_next)
                        item_lock(&li->li_tv, deep - 1, lock);
index 19aafffe5afd382c8cf428ca0605c893d16d5c89..19a9c50a20e0dbaecc3ad572196674ad28dc1ecc 100644 (file)
@@ -3739,6 +3739,7 @@ match_add(
        listitem_T      *li;
        int             i;
 
+       range_list_materialize(pos_list);
        for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH;
                                                        i++, li = li->li_next)
        {
index 0be20092ac3cffdf3ae093045d7a1aba9dcef829..0b2435f4ce55885f632992a9f824bad9823d29b2 100644 (file)
@@ -2330,6 +2330,7 @@ ins_compl_add_list(list_T *list)
     int                dir = compl_direction;
 
     // Go through the List with matches and add each of them.
+    range_list_materialize(list);
     for (li = list->lv_first; li != NULL; li = li->li_next)
     {
        if (ins_compl_add_tv(&li->li_tv, dir) == OK)
@@ -2511,6 +2512,7 @@ get_complete_info(list_T *what_list, dict_T *retdict)
     else
     {
        what_flag = 0;
+       range_list_materialize(what_list);
        for (item = what_list->lv_first; item != NULL; item = item->li_next)
        {
            char_u *what = tv_get_string(&item->li_tv);
index da0ba4bb2a4c1431f19b27d7b32d936ac18623ef..bfa5d50ddbd3787a76e042fc658edca7ae0725f7 100644 (file)
@@ -265,6 +265,7 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
 
                    l->lv_copyID = copyID;
                    ga_append(gap, '[');
+                   range_list_materialize(l);
                    for (li = l->lv_first; li != NULL && !got_int; )
                    {
                        if (json_encode_item(gap, &li->li_tv, copyID,
index 0e4f9fef076837c2e5479bd8fe5ab7f5a3cd2424..3a5e1032410bbf7748bebab0cc56ad4f2d273710 100644 (file)
@@ -1314,6 +1314,7 @@ ui_post_balloon(char_u *mesg, list_T *list)
        balloon_array = ALLOC_CLEAR_MULT(pumitem_T, list->lv_len);
        if (balloon_array == NULL)
            return;
+       range_list_materialize(list);
        for (idx = 0, li = list->lv_first; li != NULL; li = li->li_next, ++idx)
        {
            char_u *text = tv_get_string_chk(&li->li_tv);
index 6c4e81369dff878b5ef823056bf42aaa1637c958..1d18190a62be52b496e04b035a2fb728d90df85e 100644 (file)
@@ -1147,6 +1147,7 @@ func Test_balloon_show()
   if has('balloon_eval')
     " This won't do anything but must not crash either.
     call balloon_show('hi!')
+    call balloon_show(range(3))
   endif
 endfunc
 
@@ -1742,3 +1743,224 @@ func Test_state()
   call StopVimInTerminal(buf)
   call delete('XState')
 endfunc
+
+func Test_range()
+  " destructuring
+  let [x, y] = range(2)
+  call assert_equal([0, 1], [x, y])
+
+  " index
+  call assert_equal(4, range(1, 10)[3])
+
+  " add()
+  call assert_equal([0, 1, 2, 3], add(range(3), 3))
+  call assert_equal([0, 1, 2, [0, 1, 2]], add([0, 1, 2], range(3)))
+  call assert_equal([0, 1, 2, [0, 1, 2]], add(range(3), range(3)))
+
+  " append()
+  new
+  call append('.', range(5))
+  call assert_equal(['', '0', '1', '2', '3', '4'], getline(1, '$'))
+  bwipe!
+
+  " appendbufline()
+  new
+  call appendbufline(bufnr(''), '.', range(5))
+  call assert_equal(['0', '1', '2', '3', '4', ''], getline(1, '$'))
+  bwipe!
+
+  " call()
+  func TwoArgs(a, b)
+    return [a:a, a:b]
+  endfunc
+  call assert_equal([0, 1], call('TwoArgs', range(2)))
+
+  " col()
+  new
+  call setline(1, ['foo', 'bar'])
+  call assert_equal(2, col(range(1, 2)))
+  bwipe!
+
+  " complete()
+  execute "normal! a\<C-r>=[complete(col('.'), range(10)), ''][1]\<CR>"
+  " complete_info()
+  execute "normal! a\<C-r>=[complete(col('.'), range(10)), ''][1]\<CR>\<C-r>=[complete_info(range(5)), ''][1]\<CR>"
+
+  " copy()
+  call assert_equal([1, 2, 3], copy(range(1, 3)))
+
+  " count()
+  call assert_equal(0, count(range(0), 3))
+  call assert_equal(0, count(range(2), 3))
+  call assert_equal(1, count(range(5), 3))
+
+  " cursor()
+  new
+  call setline(1, ['aaa', 'bbb', 'ccc'])
+  call cursor(range(1, 2))
+  call assert_equal([2, 1], [col('.'), line('.')])
+  bwipe!
+
+  " deepcopy()
+  call assert_equal([1, 2, 3], deepcopy(range(1, 3)))
+
+  " empty()
+  call assert_true(empty(range(0)))
+  call assert_false(empty(range(2)))
+
+  " execute()
+  new
+  call setline(1, ['aaa', 'bbb', 'ccc'])
+  call execute(range(3))
+  call assert_equal(2, line('.'))
+  bwipe!
+
+  " extend()
+  call assert_equal([1, 2, 3, 4], extend([1], range(2, 4)))
+  call assert_equal([1, 2, 3, 4], extend(range(1, 1), range(2, 4)))
+  call assert_equal([1, 2, 3, 4], extend(range(1, 1), [2, 3, 4]))
+
+  " filter()
+  call assert_equal([1, 3], filter(range(5), 'v:val % 2'))
+
+  " funcref()
+  call assert_equal([0, 1], funcref('TwoArgs', range(2))())
+
+  " function()
+  call assert_equal([0, 1], function('TwoArgs', range(2))())
+
+  " garbagecollect()
+  let thelist = [1, range(2), 3]
+  let otherlist = range(3)
+  call test_garbagecollect_now()
+
+  " get()
+  call assert_equal(4, get(range(1, 10), 3))
+  call assert_equal(-1, get(range(1, 10), 42, -1))
+
+  " index()
+  call assert_equal(1, index(range(1, 5), 2))
+
+  " inputlist()
+  call test_feedinput("1\<CR>")
+  call assert_equal(1, inputlist(range(10)))
+  call test_feedinput("1\<CR>")
+  call assert_equal(1, inputlist(range(3, 10)))
+
+  call assert_equal('[0,1,2,3]', json_encode(range(4)))
+
+  " insert()
+  call assert_equal([42, 1, 2, 3, 4, 5], insert(range(1, 5), 42))
+  call assert_equal([42, 1, 2, 3, 4, 5], insert(range(1, 5), 42, 0))
+  call assert_equal([1, 42, 2, 3, 4, 5], insert(range(1, 5), 42, 1))
+  call assert_equal([1, 2, 3, 4, 42, 5], insert(range(1, 5), 42, 4))
+  call assert_equal([1, 2, 3, 4, 42, 5], insert(range(1, 5), 42, -1))
+  call assert_equal([1, 2, 3, 4, 5, 42], insert(range(1, 5), 42, 5))
+
+  " join()
+  call assert_equal('0 1 2 3 4', join(range(5)))
+
+  " len()
+  call assert_equal(0, len(range(0)))
+  call assert_equal(2, len(range(2)))
+  call assert_equal(5, len(range(0, 12, 3)))
+  call assert_equal(4, len(range(3, 0, -1)))
+
+  " list2str()
+  call assert_equal('ABC', list2str(range(65, 67)))
+
+  " lock()
+  let thelist = range(5)
+  lockvar thelist
+
+  " map()
+  call assert_equal([0, 2, 4, 6, 8], map(range(5), 'v:val * 2'))
+
+  " match()
+  call assert_equal(3, match(range(5), 3))
+
+  " matchaddpos()
+  highlight MyGreenGroup ctermbg=green guibg=green
+  call matchaddpos('MyGreenGroup', range(line('.'), line('.')))
+
+  " matchend()
+  call assert_equal(4, matchend(range(5), '4'))
+  call assert_equal(3, matchend(range(1, 5), '4'))
+  call assert_equal(-1, matchend(range(1, 5), '42'))
+
+  " matchstrpos()
+  call assert_equal(['4', 4, 0, 1], matchstrpos(range(5), '4'))
+  call assert_equal(['4', 3, 0, 1], matchstrpos(range(1, 5), '4'))
+  call assert_equal(['', -1, -1, -1], matchstrpos(range(1, 5), '42'))
+
+  " max() reverse()
+  call assert_equal(0, max(range(0)))
+  call assert_equal(0, max(range(10, 9)))
+  call assert_equal(9, max(range(10)))
+  call assert_equal(18, max(range(0, 20, 3)))
+  call assert_equal(20, max(range(20, 0, -3)))
+  call assert_equal(99999, max(range(100000)))
+  call assert_equal(99999, max(range(99999, 0, -1)))
+  call assert_equal(99999, max(reverse(range(100000))))
+  call assert_equal(99999, max(reverse(range(99999, 0, -1))))
+
+  " min() reverse()
+  call assert_equal(0, min(range(0)))
+  call assert_equal(0, min(range(10, 9)))
+  call assert_equal(5, min(range(5, 10)))
+  call assert_equal(5, min(range(5, 10, 3)))
+  call assert_equal(2, min(range(20, 0, -3)))
+  call assert_equal(0, min(range(100000)))
+  call assert_equal(0, min(range(99999, 0, -1)))
+  call assert_equal(0, min(reverse(range(100000))))
+  call assert_equal(0, min(reverse(range(99999, 0, -1))))
+
+  " remove()
+  call assert_equal(1, remove(range(1, 10), 0))
+  call assert_equal(2, remove(range(1, 10), 1))
+  call assert_equal(9, remove(range(1, 10), 8))
+  call assert_equal(10, remove(range(1, 10), 9))
+  call assert_equal(10, remove(range(1, 10), -1))
+  call assert_equal([3, 4, 5], remove(range(1, 10), 2, 4))
+
+  " repeat()
+  call assert_equal([0, 1, 2, 0, 1, 2], repeat(range(3), 2))
+  call assert_equal([0, 1, 2], repeat(range(3), 1))
+  call assert_equal([], repeat(range(3), 0))
+  call assert_equal([], repeat(range(5, 4), 2))
+  call assert_equal([], repeat(range(5, 4), 0))
+
+  " reverse()
+  call assert_equal([2, 1, 0], reverse(range(3)))
+  call assert_equal([0, 1, 2, 3], reverse(range(3, 0, -1)))
+  call assert_equal([9, 8, 7, 6, 5, 4, 3, 2, 1, 0], reverse(range(10)))
+  call assert_equal([20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10], reverse(range(10, 20)))
+  call assert_equal([16, 13, 10], reverse(range(10, 18, 3)))
+  call assert_equal([19, 16, 13, 10], reverse(range(10, 19, 3)))
+  call assert_equal([19, 16, 13, 10], reverse(range(10, 20, 3)))
+  call assert_equal([11, 14, 17, 20], reverse(range(20, 10, -3)))
+  call assert_equal([], reverse(range(0)))
+
+  " TODO: setpos()
+  " new
+  " call setline(1, repeat([''], bufnr('')))
+  " call setline(bufnr('') + 1, repeat('x', bufnr('') * 2 + 6))
+  " call setpos('x', range(bufnr(''), bufnr('') + 3))
+  " bwipe!
+
+  " setreg()
+  call setreg('a', range(3))
+  call assert_equal("0\n1\n2\n", getreg('a'))
+
+  " sort()
+  call assert_equal([0, 1, 2, 3, 4, 5], sort(range(5, 0, -1)))
+
+  " string()
+  call assert_equal('[0, 1, 2, 3, 4]', string(range(5)))
+
+  " type()
+  call assert_equal(v:t_list, type(range(5)))
+
+  " uniq()
+  call assert_equal([0, 1, 2, 3, 4], uniq(range(5)))
+endfunc
index c39515ab1f0432f0686ef733c50ad7bf6185e229..2f5e0571aa953a2e4696a660048697884a18f7d9 100644 (file)
@@ -189,7 +189,7 @@ func Test_unicode()
 endfunc
 
 " Test range objects, see :help python-range
-func Test_range()
+func Test_python3_range()
   new
   py3 b = vim.current.buffer
 
index ce776eeab32d445a390943843d0c572b96cf8c12..1878eab396e66c5f381914f30a893450ad9fef48 100644 (file)
@@ -1600,13 +1600,14 @@ func_call(
     dict_T     *selfdict,
     typval_T   *rettv)
 {
+    list_T     *l = args->vval.v_list;
     listitem_T *item;
     typval_T   argv[MAX_FUNC_ARGS + 1];
     int                argc = 0;
     int                r = 0;
 
-    for (item = args->vval.v_list->lv_first; item != NULL;
-                                                        item = item->li_next)
+    range_list_materialize(l);
+    for (item = l->lv_first; item != NULL; item = item->li_next)
     {
        if (argc == MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc))
        {
index 7447918c000d587bcbdedc8aa40134f64a89b90b..7c7e5544296c019ac711226f547f13ab98e80480 100644 (file)
@@ -742,6 +742,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    159,
 /**/
     158,
 /**/