]> granicus.if.org Git - vim/commitdiff
patch 8.1.1044: no way to check the reference count of objects v8.1.1044
authorBram Moolenaar <Bram@vim.org>
Sat, 23 Mar 2019 13:23:07 +0000 (14:23 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 23 Mar 2019 13:23:07 +0000 (14:23 +0100)
Problem:    No way to check the reference count of objects.
Solution:   Add test_refcount(). (Ozaki Kiichi, closes #4124)

runtime/doc/eval.txt
src/evalfunc.c
src/testdir/test_vimscript.vim
src/version.c

index fe10e34466c27fd76bdc5fd6db45990c7c57b8a0..62387232685014e434b920ad594becc3201ca7b6 100644 (file)
@@ -2672,6 +2672,7 @@ test_null_partial()               Funcref null value for testing
 test_null_string()             String  null value for testing
 test_option_not_set({name})    none    reset flag indicating option was set
 test_override({expr}, {val})   none    test with Vim internal overrides
+test_refcount({expr})          Number  get the reference count of {expr}
 test_scrollbar({which}, {value}, {dragging})
                                none    scroll in the GUI for testing
 test_settime({expr})           none    set current time for testing
@@ -9589,6 +9590,11 @@ test_override({name}, {val})                             *test_override()*
 <              The value of "starting" is saved.  It is restored by: >
                        call test_override('starting', 0)
 
+test_refcount({expr})                                  *test_refcount()*
+               Return the reference count of {expr}.  When {expr} is of a
+               type that does not have a reference count, returns -1.  Only
+               to be used for testing.
+
 test_scrollbar({which}, {value}, {dragging})           *test_scrollbar()*
                Pretend using scrollbar {which} to move it to position
                {value}.  {which} can be:
index 2f75cbf222e4755f6a9d58301936356843959c52..733d45aa505f913bfd3d77e0853cd81b69c4f241 100644 (file)
@@ -428,6 +428,7 @@ static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
 static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
 static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
 static void f_test_override(typval_T *argvars, typval_T *rettv);
+static void f_test_refcount(typval_T *argvars, typval_T *rettv);
 static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
 static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
 static void f_test_null_blob(typval_T *argvars, typval_T *rettv);
@@ -952,7 +953,7 @@ static struct fst
     {"test_feedinput", 1, 1, f_test_feedinput},
     {"test_garbagecollect_now",        0, 0, f_test_garbagecollect_now},
     {"test_ignore_error",      1, 1, f_test_ignore_error},
-    {"test_null_blob", 0, 0, f_test_null_blob},
+    {"test_null_blob", 0, 0, f_test_null_blob},
 #ifdef FEAT_JOB_CHANNEL
     {"test_null_channel", 0, 0, f_test_null_channel},
 #endif
@@ -964,7 +965,8 @@ static struct fst
     {"test_null_partial", 0, 0, f_test_null_partial},
     {"test_null_string", 0, 0, f_test_null_string},
     {"test_option_not_set", 1, 1, f_test_option_not_set},
-    {"test_override",    2, 2, f_test_override},
+    {"test_override",  2, 2, f_test_override},
+    {"test_refcount",  1, 1, f_test_refcount},
 #ifdef FEAT_GUI
     {"test_scrollbar", 3, 3, f_test_scrollbar},
 #endif
@@ -13846,6 +13848,67 @@ f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
     }
 }
 
+/*
+ * "test_refcount({expr})" function
+ */
+    static void
+f_test_refcount(typval_T *argvars, typval_T *rettv)
+{
+    int retval = -1;
+
+    switch (argvars[0].v_type)
+    {
+       case VAR_UNKNOWN:
+       case VAR_NUMBER:
+       case VAR_FLOAT:
+       case VAR_SPECIAL:
+       case VAR_STRING:
+           break;
+       case VAR_JOB:
+#ifdef FEAT_JOB_CHANNEL
+           if (argvars[0].vval.v_job != NULL)
+               retval = argvars[0].vval.v_job->jv_refcount - 1;
+#endif
+           break;
+       case VAR_CHANNEL:
+#ifdef FEAT_JOB_CHANNEL
+           if (argvars[0].vval.v_channel != NULL)
+               retval = argvars[0].vval.v_channel->ch_refcount - 1;
+#endif
+           break;
+       case VAR_FUNC:
+           if (argvars[0].vval.v_string != NULL)
+           {
+               ufunc_T *fp;
+
+               fp = find_func(argvars[0].vval.v_string);
+               if (fp != NULL)
+                   retval = fp->uf_refcount;
+           }
+           break;
+       case VAR_PARTIAL:
+           if (argvars[0].vval.v_partial != NULL)
+               retval = argvars[0].vval.v_partial->pt_refcount - 1;
+           break;
+       case VAR_BLOB:
+           if (argvars[0].vval.v_blob != NULL)
+               retval = argvars[0].vval.v_blob->bv_refcount - 1;
+           break;
+       case VAR_LIST:
+           if (argvars[0].vval.v_list != NULL)
+               retval = argvars[0].vval.v_list->lv_refcount - 1;
+           break;
+       case VAR_DICT:
+           if (argvars[0].vval.v_dict != NULL)
+               retval = argvars[0].vval.v_dict->dv_refcount - 1;
+           break;
+    }
+
+    rettv->v_type = VAR_NUMBER;
+    rettv->vval.v_number = retval;
+
+}
+
 /*
  * "test_garbagecollect_now()" function
  */
index 57e673f3ab83654722142b136d7d753418670111..3eb47a8ab4a2bf020cb70fb3aad67cc5666bbc89 100644 (file)
@@ -1556,6 +1556,115 @@ func Test_compound_assignment_operators()
     let @/ = ''
 endfunc
 
+func Test_refcount()
+    " Immediate values
+    call assert_equal(-1, test_refcount(1))
+    call assert_equal(-1, test_refcount('s'))
+    call assert_equal(-1, test_refcount(v:true))
+    call assert_equal(0, test_refcount([]))
+    call assert_equal(0, test_refcount({}))
+    call assert_equal(0, test_refcount(0zff))
+    call assert_equal(0, test_refcount({-> line('.')}))
+    if has('float')
+        call assert_equal(-1, test_refcount(0.1))
+    endif
+    if has('job')
+        call assert_equal(0, test_refcount(job_start([&shell, &shellcmdflag, 'echo .'])))
+    endif
+
+    " No refcount types
+    let x = 1
+    call assert_equal(-1, test_refcount(x))
+    let x = 's'
+    call assert_equal(-1, test_refcount(x))
+    let x = v:true
+    call assert_equal(-1, test_refcount(x))
+    if has('float')
+        let x = 0.1
+        call assert_equal(-1, test_refcount(x))
+    endif
+
+    " Check refcount
+    let x = []
+    call assert_equal(1, test_refcount(x))
+
+    let x = {}
+    call assert_equal(1, test_refcount(x))
+
+    let x = 0zff
+    call assert_equal(1, test_refcount(x))
+
+    let X = {-> line('.')}
+    call assert_equal(1, test_refcount(X))
+    let Y = X
+    call assert_equal(2, test_refcount(X))
+
+    if has('job')
+        let job = job_start([&shell, &shellcmdflag, 'echo .'])
+        call assert_equal(1, test_refcount(job))
+        call assert_equal(1, test_refcount(job_getchannel(job)))
+        call assert_equal(1, test_refcount(job))
+    endif
+
+    " Function arguments, copying and unassigning
+    func ExprCheck(x, i)
+        let i = a:i + 1
+        call assert_equal(i, test_refcount(a:x))
+        let Y = a:x
+        call assert_equal(i + 1, test_refcount(a:x))
+        call assert_equal(test_refcount(a:x), test_refcount(Y))
+        let Y = 0
+        call assert_equal(i, test_refcount(a:x))
+    endfunc
+    call ExprCheck([], 0)
+    call ExprCheck({}, 0)
+    call ExprCheck(0zff, 0)
+    call ExprCheck({-> line('.')}, 0)
+    if has('job')
+       call ExprCheck(job, 1)
+       call ExprCheck(job_getchannel(job), 1)
+       call job_stop(job)
+    endif
+    delfunc ExprCheck
+
+    " Regarding function
+    func Func(x) abort
+        call assert_equal(2, test_refcount(function('Func')))
+        call assert_equal(0, test_refcount(funcref('Func')))
+    endfunc
+    call assert_equal(1, test_refcount(function('Func')))
+    call assert_equal(0, test_refcount(function('Func', [1])))
+    call assert_equal(0, test_refcount(funcref('Func')))
+    call assert_equal(0, test_refcount(funcref('Func', [1])))
+    let X = function('Func')
+    let Y = X
+    call assert_equal(1, test_refcount(X))
+    let X = function('Func', [1])
+    let Y = X
+    call assert_equal(2, test_refcount(X))
+    let X = funcref('Func')
+    let Y = X
+    call assert_equal(2, test_refcount(X))
+    let X = funcref('Func', [1])
+    let Y = X
+    call assert_equal(2, test_refcount(X))
+    unlet X
+    unlet Y
+    call Func(1)
+    delfunc Func
+
+    " Function with dict
+    func DictFunc() dict
+        call assert_equal(3, test_refcount(self))
+    endfunc
+    let d = {'Func': function('DictFunc')}
+    call assert_equal(1, test_refcount(d))
+    call assert_equal(0, test_refcount(d.Func))
+    call d.Func()
+    unlet d
+    delfunc DictFunc
+endfunc
+
 "-------------------------------------------------------------------------------
 " Modelines                                                                {{{1
 " vim: ts=8 sw=4 tw=80 fdm=marker
index f6b37243def6ca0fa767d8d8eee3603a99be1ed5..d0f63efae7577a64935a4e736bd89750134a8da7 100644 (file)
@@ -775,6 +775,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1044,
 /**/
     1043,
 /**/