Mercurial > vim
diff src/testdir/test_tagfunc.vim @ 26518:13ba00ef7687 v8.2.3788
patch 8.2.3788: lambda for option that is a function may be freed
Commit: https://github.com/vim/vim/commit/6ae8fae8696623b527c7fb22567f6a3705b2f0dd
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Sun Dec 12 16:26:44 2021 +0000
patch 8.2.3788: lambda for option that is a function may be freed
Problem: Lambda for option that is a function may be garbage collected.
Solution: Set a reference in the funcref. (Yegappan Lakshmanan,
closes #9330)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 12 Dec 2021 17:30:04 +0100 |
parents | 7eaf61a67d18 |
children | 33d680d372aa |
line wrap: on
line diff
--- a/src/testdir/test_tagfunc.vim +++ b/src/testdir/test_tagfunc.vim @@ -132,55 +132,121 @@ func Test_tagfunc_callback() return v:null endfunc - " Test for using a function() - set tagfunc=function('MytagFunc1',[10]) - new | only - let g:MytagFunc1_args = [] - call assert_fails('tag a11', 'E433:') - call assert_equal([10, 'a11', '', {}], g:MytagFunc1_args) + let lines =<< trim END + #" Test for using a function() + set tagfunc=function('g:MytagFunc1',\ [10]) + new | only + LET g:MytagFunc1_args = [] + call assert_fails('tag a11', 'E433:') + call assert_equal([10, 'a11', '', {}], g:MytagFunc1_args) + + #" Using a funcref variable to set 'tagfunc' + VAR Fn = function('g:MytagFunc1', [11]) + LET &tagfunc = Fn + new | only + LET g:MytagFunc1_args = [] + call assert_fails('tag a12', 'E433:') + call assert_equal([11, 'a12', '', {}], g:MytagFunc1_args) + + #" Using a string(funcref_variable) to set 'tagfunc' + LET Fn = function('g:MytagFunc1', [12]) + LET &tagfunc = string(Fn) + new | only + LET g:MytagFunc1_args = [] + call assert_fails('tag a12', 'E433:') + call assert_equal([12, 'a12', '', {}], g:MytagFunc1_args) + + #" Test for using a funcref() + set tagfunc=funcref('g:MytagFunc1',\ [13]) + new | only + LET g:MytagFunc1_args = [] + call assert_fails('tag a13', 'E433:') + call assert_equal([13, 'a13', '', {}], g:MytagFunc1_args) + + #" Using a funcref variable to set 'tagfunc' + LET Fn = funcref('g:MytagFunc1', [14]) + LET &tagfunc = Fn + new | only + LET g:MytagFunc1_args = [] + call assert_fails('tag a14', 'E433:') + call assert_equal([14, 'a14', '', {}], g:MytagFunc1_args) + + #" Using a string(funcref_variable) to set 'tagfunc' + LET Fn = funcref('g:MytagFunc1', [15]) + LET &tagfunc = string(Fn) + new | only + LET g:MytagFunc1_args = [] + call assert_fails('tag a14', 'E433:') + call assert_equal([15, 'a14', '', {}], g:MytagFunc1_args) + + #" Test for using a lambda function + VAR optval = "LSTART a, b, c LMIDDLE MytagFunc1(16, a, b, c) LEND" + LET optval = substitute(optval, ' ', '\\ ', 'g') + exe "set tagfunc=" .. optval + new | only + LET g:MytagFunc1_args = [] + call assert_fails('tag a17', 'E433:') + call assert_equal([16, 'a17', '', {}], g:MytagFunc1_args) - " Using a funcref variable to set 'tagfunc' - let Fn = function('MytagFunc1', [11]) - let &tagfunc = Fn - new | only - let g:MytagFunc1_args = [] - call assert_fails('tag a12', 'E433:') - call assert_equal([11, 'a12', '', {}], g:MytagFunc1_args) + #" Set 'tagfunc' to a lambda expression + LET &tagfunc = LSTART a, b, c LMIDDLE MytagFunc1(17, a, b, c) LEND + new | only + LET g:MytagFunc1_args = [] + call assert_fails('tag a18', 'E433:') + call assert_equal([17, 'a18', '', {}], g:MytagFunc1_args) + + #" Set 'tagfunc' to a string(lambda expression) + LET &tagfunc = 'LSTART a, b, c LMIDDLE MytagFunc1(18, a, b, c) LEND' + new | only + LET g:MytagFunc1_args = [] + call assert_fails('tag a18', 'E433:') + call assert_equal([18, 'a18', '', {}], g:MytagFunc1_args) + + #" Set 'tagfunc' to a variable with a lambda expression + VAR Lambda = LSTART a, b, c LMIDDLE MytagFunc1(19, a, b, c) LEND + LET &tagfunc = Lambda + new | only + LET g:MytagFunc1_args = [] + call assert_fails("tag a19", "E433:") + call assert_equal([19, 'a19', '', {}], g:MytagFunc1_args) - " Using a string(funcref_variable) to set 'tagfunc' - let Fn = function('MytagFunc1', [12]) - let &tagfunc = string(Fn) + #" Set 'tagfunc' to a string(variable with a lambda expression) + LET Lambda = LSTART a, b, c LMIDDLE MytagFunc1(20, a, b, c) LEND + LET &tagfunc = string(Lambda) + new | only + LET g:MytagFunc1_args = [] + call assert_fails("tag a19", "E433:") + call assert_equal([20, 'a19', '', {}], g:MytagFunc1_args) + + #" Test for using a lambda function with incorrect return value + LET Lambda = LSTART a, b, c LMIDDLE strlen(a) LEND + LET &tagfunc = string(Lambda) + new | only + call assert_fails("tag a20", "E987:") + + #" Test for clearing the 'tagfunc' option + set tagfunc='' + set tagfunc& + call assert_fails("set tagfunc=function('abc')", "E700:") + call assert_fails("set tagfunc=funcref('abc')", "E700:") + + #" set 'tagfunc' to a non-existing function + LET &tagfunc = function('g:MytagFunc1', [21]) + call assert_fails("set tagfunc=function('NonExistingFunc')", 'E700:') + call assert_fails("LET &tagfunc = function('NonExistingFunc')", 'E700:') + call assert_fails("tag axb123", 'E426:') + END + call CheckLegacyAndVim9Success(lines) + + let &tagfunc = "{a -> 'abc'}" + call assert_fails("echo taglist('a')", "E987:") + + " Using Vim9 lambda expression in legacy context should fail + set tagfunc=(a,\ b,\ c)\ =>\ g:MytagFunc1(21,\ a,\ b,\ c) new | only let g:MytagFunc1_args = [] - call assert_fails('tag a12', 'E433:') - call assert_equal([12, 'a12', '', {}], g:MytagFunc1_args) - - " Test for using a funcref() - func MytagFunc2(pat, flags, info) - let g:MytagFunc2_args = [a:pat, a:flags, a:info] - return v:null - endfunc - set tagfunc=funcref('MytagFunc1',[13]) - new | only - let g:MytagFunc1_args = [] - call assert_fails('tag a13', 'E433:') - call assert_equal([13, 'a13', '', {}], g:MytagFunc1_args) - - " Using a funcref variable to set 'tagfunc' - let Fn = funcref('MytagFunc1', [14]) - let &tagfunc = Fn - new | only - let g:MytagFunc1_args = [] - call assert_fails('tag a14', 'E433:') - call assert_equal([14, 'a14', '', {}], g:MytagFunc1_args) - - " Using a string(funcref_variable) to set 'tagfunc' - let Fn = funcref('MytagFunc1', [15]) - let &tagfunc = string(Fn) - new | only - let g:MytagFunc1_args = [] - call assert_fails('tag a14', 'E433:') - call assert_equal([15, 'a14', '', {}], g:MytagFunc1_args) + call assert_fails("tag a17", "E117:") + call assert_equal([], g:MytagFunc1_args) " Test for using a script local function set tagfunc=<SID>ScriptLocalTagFunc @@ -205,70 +271,25 @@ func Test_tagfunc_callback() call assert_fails('tag a16', 'E433:') call assert_equal(['a16', '', {}], g:ScriptLocalFuncArgs) - " Test for using a lambda function - set tagfunc={a,\ b,\ c\ ->\ MytagFunc1(16,\ a,\ b,\ c)} - new | only - let g:MytagFunc1_args = [] - call assert_fails('tag a17', 'E433:') - call assert_equal([16, 'a17', '', {}], g:MytagFunc1_args) - - " Set 'tagfunc' to a lambda expression - let &tagfunc = {a, b, c -> MytagFunc1(17, a, b, c)} - new | only - let g:MytagFunc1_args = [] - call assert_fails('tag a18', 'E433:') - call assert_equal([17, 'a18', '', {}], g:MytagFunc1_args) - - " Set 'tagfunc' to a string(lambda expression) - let &tagfunc = '{a, b, c -> MytagFunc1(18, a, b, c)}' - new | only - let g:MytagFunc1_args = [] - call assert_fails('tag a18', 'E433:') - call assert_equal([18, 'a18', '', {}], g:MytagFunc1_args) - - " Set 'tagfunc' to a variable with a lambda expression - let Lambda = {a, b, c -> MytagFunc1(19, a, b, c)} - let &tagfunc = Lambda - new | only - let g:MytagFunc1_args = [] - call assert_fails("tag a19", "E433:") - call assert_equal([19, 'a19', '', {}], g:MytagFunc1_args) - - " Set 'tagfunc' to a string(variable with a lambda expression) - let Lambda = {a, b, c -> MytagFunc1(20, a, b, c)} - let &tagfunc = string(Lambda) - new | only - let g:MytagFunc1_args = [] - call assert_fails("tag a19", "E433:") - call assert_equal([20, 'a19', '', {}], g:MytagFunc1_args) - - " Test for using a lambda function with incorrect return value - let Lambda = {s -> strlen(s)} - let &tagfunc = string(Lambda) - new | only - call assert_fails("tag a20", "E987:") - - " Test for clearing the 'tagfunc' option - set tagfunc='' - set tagfunc& - - call assert_fails("set tagfunc=function('abc')", "E700:") - call assert_fails("set tagfunc=funcref('abc')", "E700:") - let &tagfunc = "{a -> 'abc'}" - call assert_fails("echo taglist('a')", "E987:") - - " Using Vim9 lambda expression in legacy context should fail - set tagfunc=(a,\ b,\ c)\ =>\ g:MytagFunc1(21,\ a,\ b,\ c) - new | only - let g:MytagFunc1_args = [] - call assert_fails("tag a17", "E117:") - call assert_equal([], g:MytagFunc1_args) - - " set 'tagfunc' to a non-existing function - call assert_fails("set tagfunc=function('NonExistingFunc')", 'E700:') - call assert_fails("let &tagfunc = function('NonExistingFunc')", 'E700:') - call assert_fails("tag axb123", 'E426:') - bw! + " set 'tagfunc' to a partial with dict. This used to cause a crash. + func SetTagFunc() + let params = {'tagfn': function('g:DictTagFunc')} + let &tagfunc = params.tagfn + endfunc + func g:DictTagFunc(_) dict + endfunc + call SetTagFunc() + new + call SetTagFunc() + bw + call test_garbagecollect_now() + new + set tagfunc= + wincmd w + set tagfunc= + :%bw! + delfunc g:DictTagFunc + delfunc SetTagFunc " Vim9 tests let lines =<< trim END @@ -284,42 +305,11 @@ func Test_tagfunc_callback() g:Vim9tagFuncArgs = [] assert_fails('tag a10', 'E433:') assert_equal([60, 'a10', '', {}], g:Vim9tagFuncArgs) - - # Test for using a lambda - &tagfunc = (a, b, c) => MytagFunc1(61, a, b, c) - new | only - g:MytagFunc1_args = [] - assert_fails('tag a20', 'E433:') - assert_equal([61, 'a20', '', {}], g:MytagFunc1_args) - - # Test for using a string(lambda) - &tagfunc = '(a, b, c) => MytagFunc1(62, a, b, c)' - new | only - g:MytagFunc1_args = [] - assert_fails('tag a20', 'E433:') - assert_equal([62, 'a20', '', {}], g:MytagFunc1_args) - - # Test for using a variable with a lambda expression - var Fn: func = (a, b, c) => MytagFunc1(63, a, b, c) - &tagfunc = Fn - new | only - g:MytagFunc1_args = [] - assert_fails('tag a30', 'E433:') - assert_equal([63, 'a30', '', {}], g:MytagFunc1_args) - - # Test for using a variable with a lambda expression - Fn = (a, b, c) => MytagFunc1(64, a, b, c) - &tagfunc = string(Fn) - new | only - g:MytagFunc1_args = [] - assert_fails('tag a30', 'E433:') - assert_equal([64, 'a30', '', {}], g:MytagFunc1_args) END call CheckScriptSuccess(lines) " cleanup delfunc MytagFunc1 - delfunc MytagFunc2 set tagfunc& %bw! endfunc