eval: Move copy_tv to eval/typval

This commit is contained in:
ZyX
2016-09-11 03:37:03 +03:00
parent 8b0fa64ed3
commit 2ad4fba46d
6 changed files with 176 additions and 139 deletions

View File

@@ -179,7 +179,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del,
} }
// Update the value // Update the value
copy_tv(&tv, &di->di_tv); tv_copy(&tv, &di->di_tv);
// Clear the temporary variable // Clear the temporary variable
tv_clear(&tv); tv_clear(&tv);
} }

View File

@@ -494,6 +494,13 @@ typedef enum
ASSERT_OTHER, ASSERT_OTHER,
} assert_type_T; } assert_type_T;
/// Type for dict_list function
typedef enum {
kDictListKeys, ///< List dictionary keys.
kDictListValues, ///< List dictionary values.
kDictListItems, ///< List dictionary contents: [keys, values].
} DictListType;
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval.c.generated.h" # include "eval.c.generated.h"
#endif #endif
@@ -2412,7 +2419,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv,
eexe_mod_op(&lp->ll_li->li_tv, &ri->li_tv, (const char *)op); eexe_mod_op(&lp->ll_li->li_tv, &ri->li_tv, (const char *)op);
} else { } else {
tv_clear(&lp->ll_li->li_tv); tv_clear(&lp->ll_li->li_tv);
copy_tv(&ri->li_tv, &lp->ll_li->li_tv); tv_copy(&ri->li_tv, &lp->ll_li->li_tv);
} }
ri = ri->li_next; ri = ri->li_next;
if (ri == NULL || (!lp->ll_empty2 && lp->ll_n2 == lp->ll_n1)) if (ri == NULL || (!lp->ll_empty2 && lp->ll_n2 == lp->ll_n1))
@@ -2452,7 +2459,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv,
lp->ll_tv = &di->di_tv; lp->ll_tv = &di->di_tv;
} else { } else {
if (watched) { if (watched) {
copy_tv(lp->ll_tv, &oldtv); tv_copy(lp->ll_tv, &oldtv);
} }
if (op != NULL && *op != '=') { if (op != NULL && *op != '=') {
@@ -2465,7 +2472,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv,
// Assign the value to the variable or list item. // Assign the value to the variable or list item.
if (copy) { if (copy) {
copy_tv(rettv, lp->ll_tv); tv_copy(rettv, lp->ll_tv);
} else { } else {
*lp->ll_tv = *rettv; *lp->ll_tv = *rettv;
lp->ll_tv->v_lock = 0; lp->ll_tv->v_lock = 0;
@@ -2926,7 +2933,7 @@ static int do_unlet_var(lval_T *const lp, char_u *const name_end, int forceit)
typval_T oldtv; typval_T oldtv;
if (watched) { if (watched) {
copy_tv(&di->di_tv, &oldtv); tv_copy(&di->di_tv, &oldtv);
// need to save key because dictitem_remove will free it // need to save key because dictitem_remove will free it
key = xstrdup((char *)di->di_key); key = xstrdup((char *)di->di_key);
} }
@@ -2998,7 +3005,7 @@ int do_unlet(char_u *name, int forceit)
bool watched = tv_dict_is_watched(dict); bool watched = tv_dict_is_watched(dict);
if (watched) { if (watched) {
copy_tv(&di->di_tv, &oldtv); tv_copy(&di->di_tv, &oldtv);
} }
delete_var(ht, hi); delete_var(ht, hi);
@@ -4532,7 +4539,7 @@ eval_index (
rettv->vval.v_list = l; rettv->vval.v_list = l;
l->lv_refcount++; l->lv_refcount++;
} else { } else {
copy_tv(&tv_list_find(rettv->vval.v_list, n1)->li_tv, &var1); tv_copy(&tv_list_find(rettv->vval.v_list, n1)->li_tv, &var1);
tv_clear(rettv); tv_clear(rettv);
*rettv = var1; *rettv = var1;
} }
@@ -4570,7 +4577,7 @@ eval_index (
return FAIL; return FAIL;
} }
copy_tv(&item->di_tv, &var1); tv_copy(&item->di_tv, &var1);
tv_clear(rettv); tv_clear(rettv);
*rettv = var1; *rettv = var1;
break; break;
@@ -6298,7 +6305,7 @@ call_func(
} }
if (error == ERROR_NONE && partial->pt_argc > 0) { if (error == ERROR_NONE && partial->pt_argc > 0) {
for (argv_clear = 0; argv_clear < partial->pt_argc; argv_clear++) { for (argv_clear = 0; argv_clear < partial->pt_argc; argv_clear++) {
copy_tv(&partial->pt_argv[argv_clear], &argv[argv_clear]); tv_copy(&partial->pt_argv[argv_clear], &argv[argv_clear]);
} }
for (int i = 0; i < argcount_in; i++) { for (int i = 0; i < argcount_in; i++) {
argv[i + argv_clear] = argvars_in[i]; argv[i + argv_clear] = argvars_in[i];
@@ -6552,7 +6559,7 @@ static void f_add(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if ((l = argvars[0].vval.v_list) != NULL if ((l = argvars[0].vval.v_list) != NULL
&& !tv_check_lock(l->lv_lock, arg_errmsg, arg_errmsg_len)) { && !tv_check_lock(l->lv_lock, arg_errmsg, arg_errmsg_len)) {
tv_list_append_tv(l, &argvars[1]); tv_list_append_tv(l, &argvars[1]);
copy_tv(&argvars[0], rettv); tv_copy(&argvars[0], rettv);
} }
} else } else
EMSG(_(e_listreq)); EMSG(_(e_listreq));
@@ -7231,7 +7238,7 @@ int func_call(char_u *name, typval_T *args, partial_T *partial,
/* Make a copy of each argument. This is needed to be able to set /* Make a copy of each argument. This is needed to be able to set
* v_lock to VAR_FIXED in the copy without changing the original list. * v_lock to VAR_FIXED in the copy without changing the original list.
*/ */
copy_tv(&item->li_tv, &argv[argc++]); tv_copy(&item->li_tv, &argv[argc++]);
} }
if (item == NULL) { if (item == NULL) {
@@ -8190,7 +8197,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
item = NULL; item = NULL;
tv_list_extend(l1, l2, item); tv_list_extend(l1, l2, item);
copy_tv(&argvars[0], rettv); tv_copy(&argvars[0], rettv);
} }
} else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == } else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type ==
VAR_DICT) { VAR_DICT) {
@@ -8224,7 +8231,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_dict_extend(d1, d2, action); tv_dict_extend(d1, d2, action);
copy_tv(&argvars[0], rettv); tv_copy(&argvars[0], rettv);
} }
} else { } else {
EMSG2(_(e_listdictarg), "extend()"); EMSG2(_(e_listdictarg), "extend()");
@@ -8441,7 +8448,7 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
did_emsg |= save_did_emsg; did_emsg |= save_did_emsg;
} }
copy_tv(&argvars[0], rettv); tv_copy(&argvars[0], rettv);
} }
static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp) static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
@@ -8451,7 +8458,7 @@ static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
int retval = FAIL; int retval = FAIL;
int dummy; int dummy;
copy_tv(tv, &vimvars[VV_VAL].vv_tv); tv_copy(tv, &vimvars[VV_VAL].vv_tv);
argv[0] = vimvars[VV_KEY].vv_tv; argv[0] = vimvars[VV_KEY].vv_tv;
argv[1] = vimvars[VV_VAL].vv_tv; argv[1] = vimvars[VV_VAL].vv_tv;
if (expr->v_type == VAR_FUNC) { if (expr->v_type == VAR_FUNC) {
@@ -8859,13 +8866,13 @@ static void common_function(typval_T *argvars, typval_T *rettv,
} }
int i = 0; int i = 0;
for (; i < arg_len; i++) { for (; i < arg_len; i++) {
copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]); tv_copy(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
} }
if (lv_len > 0) { if (lv_len > 0) {
for (listitem_T *li = list->lv_first; for (listitem_T *li = list->lv_first;
li != NULL; li != NULL;
li = li->li_next) { li = li->li_next) {
copy_tv(&li->li_tv, &pt->pt_argv[i++]); tv_copy(&li->li_tv, &pt->pt_argv[i++]);
} }
} }
} }
@@ -9012,10 +9019,12 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
if (tv == NULL) { if (tv == NULL) {
if (argvars[2].v_type != VAR_UNKNOWN) if (argvars[2].v_type != VAR_UNKNOWN) {
copy_tv(&argvars[2], rettv); tv_copy(&argvars[2], rettv);
} else }
copy_tv(tv, rettv); } else {
tv_copy(tv, rettv);
}
} }
/// Returns information about signs placed in a buffer as list of dicts. /// Returns information about signs placed in a buffer as list of dicts.
@@ -9260,7 +9269,7 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
dictitem_T *const v = find_var_in_ht(&curbuf->b_vars->dv_hashtab, 'b', dictitem_T *const v = find_var_in_ht(&curbuf->b_vars->dv_hashtab, 'b',
varname, strlen(varname), false); varname, strlen(varname), false);
if (v != NULL) { if (v != NULL) {
copy_tv(&v->di_tv, rettv); tv_copy(&v->di_tv, rettv);
done = true; done = true;
} }
} }
@@ -9273,7 +9282,7 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
f_getbufvar_end: f_getbufvar_end:
if (!done && argvars[2].v_type != VAR_UNKNOWN) { if (!done && argvars[2].v_type != VAR_UNKNOWN) {
// use the default value // use the default value
copy_tv(&argvars[2], rettv); tv_copy(&argvars[2], rettv);
} }
} }
@@ -10094,7 +10103,7 @@ static void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't',
varname, strlen(varname), false); varname, strlen(varname), false);
if (v != NULL) { if (v != NULL) {
copy_tv(&v->di_tv, rettv); tv_copy(&v->di_tv, rettv);
done = true; done = true;
} }
} }
@@ -10104,7 +10113,7 @@ static void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
if (!done && argvars[2].v_type != VAR_UNKNOWN) { if (!done && argvars[2].v_type != VAR_UNKNOWN) {
copy_tv(&argvars[2], rettv); tv_copy(&argvars[2], rettv);
} }
} }
@@ -10315,7 +10324,7 @@ getwinvar (
v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w', varname, v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w', varname,
strlen(varname), false); strlen(varname), false);
if (v != NULL) { if (v != NULL) {
copy_tv(&v->di_tv, rettv); tv_copy(&v->di_tv, rettv);
done = true; done = true;
} }
} }
@@ -10330,7 +10339,7 @@ getwinvar (
if (!done && argvars[off + 2].v_type != VAR_UNKNOWN) { if (!done && argvars[off + 2].v_type != VAR_UNKNOWN) {
// use the default return value // use the default return value
copy_tv(&argvars[off + 2], rettv); tv_copy(&argvars[off + 2], rettv);
} }
} }
@@ -11181,7 +11190,7 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
if (l != NULL) { if (l != NULL) {
tv_list_insert_tv(l, &argvars[1], item); tv_list_insert_tv(l, &argvars[1], item);
copy_tv(&argvars[0], rettv); tv_copy(&argvars[0], rettv);
} }
} }
} }
@@ -11271,31 +11280,36 @@ static void dict_list(typval_T *const tv, typval_T *const rettv,
listitem_T *const li = tv_list_item_alloc(); listitem_T *const li = tv_list_item_alloc();
tv_list_append(rettv->vval.v_list, li); tv_list_append(rettv->vval.v_list, li);
if (what == 0) { switch (what) {
// keys() case kDictListKeys: {
li->li_tv.v_type = VAR_STRING; li->li_tv.v_type = VAR_STRING;
li->li_tv.v_lock = 0; li->li_tv.v_lock = VAR_UNLOCKED;
li->li_tv.vval.v_string = vim_strsave(di->di_key); li->li_tv.vval.v_string = vim_strsave(di->di_key);
} else if (what == 1) { break;
// values() }
copy_tv(&di->di_tv, &li->li_tv); case kDictListValues: {
} else { tv_copy(&di->di_tv, &li->li_tv);
break;
}
case kDictListItems: {
// items() // items()
list_T *const l2 = tv_list_alloc(); list_T *const sub_l = tv_list_alloc();
li->li_tv.v_type = VAR_LIST; li->li_tv.v_type = VAR_LIST;
li->li_tv.v_lock = 0; li->li_tv.v_lock = VAR_UNLOCKED;
li->li_tv.vval.v_list = l2; li->li_tv.vval.v_list = sub_l;
l2->lv_refcount++; sub_l->lv_refcount++;
listitem_T *sub_li = tv_list_item_alloc(); listitem_T *sub_li = tv_list_item_alloc();
tv_list_append(l2, sub_li); tv_list_append(sub_l, sub_li);
sub_li->li_tv.v_type = VAR_STRING; sub_li->li_tv.v_type = VAR_STRING;
sub_li->li_tv.v_lock = 0; sub_li->li_tv.v_lock = VAR_UNLOCKED;
sub_li->li_tv.vval.v_string = vim_strsave(di->di_key); sub_li->li_tv.vval.v_string = vim_strsave(di->di_key);
sub_li = tv_list_item_alloc(); sub_li = tv_list_item_alloc();
tv_list_append(l2, sub_li); tv_list_append(sub_l, sub_li);
copy_tv(&di->di_tv, &sub_li->li_tv); tv_copy(&di->di_tv, &sub_li->li_tv);
break;
}
} }
}); });
} }
@@ -12256,21 +12270,24 @@ static void find_some_match(typval_T *argvars, typval_T *rettv, int type)
} }
} }
} else if (type == 2) { } else if (type == 2) {
/* return matched string */ // Return matched string.
if (l != NULL) if (l != NULL) {
copy_tv(&li->li_tv, rettv); tv_copy(&li->li_tv, rettv);
else } else {
rettv->vval.v_string = vim_strnsave(regmatch.startp[0], rettv->vval.v_string = (char_u *)xmemdupz(
(int)(regmatch.endp[0] - regmatch.startp[0])); (const char *)regmatch.startp[0],
} else if (l != NULL) (size_t)(regmatch.endp[0] - regmatch.startp[0]));
}
} else if (l != NULL) {
rettv->vval.v_number = idx; rettv->vval.v_number = idx;
else { } else {
if (type != 0) if (type != 0) {
rettv->vval.v_number = rettv->vval.v_number =
(varnumber_T)(regmatch.startp[0] - str); (varnumber_T)(regmatch.startp[0] - str);
else } else {
rettv->vval.v_number = rettv->vval.v_number =
(varnumber_T)(regmatch.endp[0] - str); (varnumber_T)(regmatch.endp[0] - str);
}
rettv->vval.v_number += (varnumber_T)(str - expr); rettv->vval.v_number += (varnumber_T)(str - expr);
} }
} }
@@ -15135,8 +15152,8 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
// Copy the values. This is needed to be able to set v_lock to VAR_FIXED // Copy the values. This is needed to be able to set v_lock to VAR_FIXED
// in the copy without changing the original list items. // in the copy without changing the original list items.
copy_tv(&si1->item->li_tv, &argv[0]); tv_copy(&si1->item->li_tv, &argv[0]);
copy_tv(&si2->item->li_tv, &argv[1]); tv_copy(&si2->item->li_tv, &argv[1]);
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
res = call_func((const char_u *)func_name, res = call_func((const char_u *)func_name,
@@ -18203,7 +18220,7 @@ static int get_var_tv(
} }
ret = FAIL; ret = FAIL;
} else if (rettv != NULL) { } else if (rettv != NULL) {
copy_tv(tv, rettv); tv_copy(tv, rettv);
} }
return ret; return ret;
@@ -18375,7 +18392,7 @@ void set_selfdict(typval_T *rettv, dict_T *selfdict)
} else { } else {
pt->pt_argc = ret_pt->pt_argc; pt->pt_argc = ret_pt->pt_argc;
for (i = 0; i < pt->pt_argc; i++) { for (i = 0; i < pt->pt_argc; i++) {
copy_tv(&ret_pt->pt_argv[i], &pt->pt_argv[i]); tv_copy(&ret_pt->pt_argv[i], &pt->pt_argv[i]);
} }
} }
} }
@@ -18852,7 +18869,7 @@ static void set_var(const char *name, typval_T *const tv, const bool copy)
} }
if (watched) { if (watched) {
copy_tv(&v->di_tv, &oldtv); tv_copy(&v->di_tv, &oldtv);
} }
tv_clear(&v->di_tv); tv_clear(&v->di_tv);
} else { // Add a new variable. } else { // Add a new variable.
@@ -18877,7 +18894,7 @@ static void set_var(const char *name, typval_T *const tv, const bool copy)
} }
if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) { if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) {
copy_tv(tv, &v->di_tv); tv_copy(tv, &v->di_tv);
} else { } else {
v->di_tv = *tv; v->di_tv = *tv;
v->di_tv.v_lock = 0; v->di_tv.v_lock = 0;
@@ -18992,56 +19009,6 @@ bool valid_varname(const char *varname)
return true; return true;
} }
/*
* Copy the values from typval_T "from" to typval_T "to".
* When needed allocates string or increases reference count.
* Does not make a copy of a list or dict but copies the reference!
* It is OK for "from" and "to" to point to the same item. This is used to
* make a copy later.
*/
void copy_tv(typval_T *from, typval_T *to)
{
to->v_type = from->v_type;
to->v_lock = 0;
memmove(&to->vval, &from->vval, sizeof(to->vval));
switch (from->v_type) {
case VAR_NUMBER:
case VAR_FLOAT:
case VAR_SPECIAL:
break;
case VAR_STRING:
case VAR_FUNC:
if (from->vval.v_string != NULL) {
to->vval.v_string = vim_strsave(from->vval.v_string);
if (from->v_type == VAR_FUNC) {
func_ref(to->vval.v_string);
}
}
break;
case VAR_PARTIAL:
if (from->vval.v_partial == NULL) {
to->vval.v_partial = NULL;
} else {
to->vval.v_partial = from->vval.v_partial;
(to->vval.v_partial->pt_refcount)++;
}
break;
case VAR_LIST:
if (from->vval.v_list != NULL) {
to->vval.v_list->lv_refcount++;
}
break;
case VAR_DICT:
if (from->vval.v_dict != NULL) {
to->vval.v_dict->dv_refcount++;
}
break;
case VAR_UNKNOWN:
EMSG2(_(e_intern2), "copy_tv(UNKNOWN)");
break;
}
}
/// Make a copy of an item /// Make a copy of an item
/// ///
/// Lists and Dictionaries are also copied. /// Lists and Dictionaries are also copied.
@@ -19080,11 +19047,11 @@ int var_item_copy(const vimconv_T *const conv,
case VAR_FUNC: case VAR_FUNC:
case VAR_PARTIAL: case VAR_PARTIAL:
case VAR_SPECIAL: case VAR_SPECIAL:
copy_tv(from, to); tv_copy(from, to);
break; break;
case VAR_STRING: case VAR_STRING:
if (conv == NULL || conv->vc_type == CONV_NONE) { if (conv == NULL || conv->vc_type == CONV_NONE) {
copy_tv(from, to); tv_copy(from, to);
} else { } else {
to->v_type = VAR_STRING; to->v_type = VAR_STRING;
to->v_lock = 0; to->v_lock = 0;
@@ -20981,7 +20948,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
if (addlocal) { if (addlocal) {
// Named arguments can be accessed without the "a:" prefix in lambda // Named arguments can be accessed without the "a:" prefix in lambda
// expressions. Add to the l: dict. // expressions. Add to the l: dict.
copy_tv(&v->di_tv, &v->di_tv); tv_copy(&v->di_tv, &v->di_tv);
tv_dict_add(&fc->l_vars, v); tv_dict_add(&fc->l_vars, v);
} else { } else {
tv_dict_add(&fc->l_avars, v); tv_dict_add(&fc->l_avars, v);
@@ -21188,13 +21155,13 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
// Make a copy of the a: variables, since we didn't do that above. // Make a copy of the a: variables, since we didn't do that above.
TV_DICT_ITER(&fc->l_avars, di, { TV_DICT_ITER(&fc->l_avars, di, {
copy_tv(&di->di_tv, &di->di_tv); tv_copy(&di->di_tv, &di->di_tv);
}); });
// Make a copy of the a:000 items, since we didn't do that above. // Make a copy of the a:000 items, since we didn't do that above.
for (listitem_T *li = fc->l_varlist.lv_first; li != NULL; for (listitem_T *li = fc->l_varlist.lv_first; li != NULL;
li = li->li_next) { li = li->li_next) {
copy_tv(&li->li_tv, &li->li_tv); tv_copy(&li->li_tv, &li->li_tv);
} }
} }
@@ -21700,7 +21667,7 @@ const void *var_shada_iter(const void *const iter, const char **const name,
hi = (const hashitem_T *) iter; hi = (const hashitem_T *) iter;
} }
*name = (char *)TV_DICT_HI2DI(hi)->di_key; *name = (char *)TV_DICT_HI2DI(hi)->di_key;
copy_tv(&TV_DICT_HI2DI(hi)->di_tv, rettv); tv_copy(&TV_DICT_HI2DI(hi)->di_tv, rettv);
while ((size_t)(++hi - hifirst) < hinum) { while ((size_t)(++hi - hifirst) < hinum) {
if (!HASHITEM_EMPTY(hi) && var_flavour(hi->hi_key) == VAR_FLAVOUR_SHADA) { if (!HASHITEM_EMPTY(hi) && var_flavour(hi->hi_key) == VAR_FLAVOUR_SHADA) {
return hi; return hi;

View File

@@ -1,6 +1,8 @@
#include <stdio.h>
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <stdbool.h>
#include "nvim/lib/queue.h" #include "nvim/lib/queue.h"
#include "nvim/eval/typval.h" #include "nvim/eval/typval.h"
@@ -276,7 +278,7 @@ void tv_list_insert(list_T *const l, listitem_T *const ni,
/// Insert VimL value into a list /// Insert VimL value into a list
/// ///
/// @param[out] l List to insert to. /// @param[out] l List to insert to.
/// @param[in,out] tv Value to insert. Is copied (@see copy_tv()) to an /// @param[in,out] tv Value to insert. Is copied (@see tv_copy()) to an
/// allocated listitem_T and inserted. /// allocated listitem_T and inserted.
/// @param[in] item Item to insert before. If NULL, inserts at the end of the /// @param[in] item Item to insert before. If NULL, inserts at the end of the
/// list. /// list.
@@ -285,7 +287,7 @@ void tv_list_insert_tv(list_T *const l, typval_T *const tv,
{ {
listitem_T *const ni = tv_list_item_alloc(); listitem_T *const ni = tv_list_item_alloc();
copy_tv(tv, &ni->li_tv); tv_copy(tv, &ni->li_tv);
tv_list_insert(l, ni, item); tv_list_insert(l, ni, item);
} }
@@ -313,13 +315,13 @@ void tv_list_append(list_T *const l, listitem_T *const item)
/// Append VimL value to the end of list /// Append VimL value to the end of list
/// ///
/// @param[out] l List to append to. /// @param[out] l List to append to.
/// @param[in,out] tv Value to append. Is copied (@see copy_tv()) to an /// @param[in,out] tv Value to append. Is copied (@see tv_copy()) to an
/// allocated listitem_T. /// allocated listitem_T.
void tv_list_append_tv(list_T *const l, typval_T *const tv) void tv_list_append_tv(list_T *const l, typval_T *const tv)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
listitem_T *const li = tv_list_item_alloc(); listitem_T *const li = tv_list_item_alloc();
copy_tv(tv, &li->li_tv); tv_copy(tv, &li->li_tv);
tv_list_append(l, li); tv_list_append(l, li);
} }
@@ -447,7 +449,7 @@ list_T *tv_list_copy(const vimconv_T *const conv, list_T *const orig,
break; break;
} }
} else { } else {
copy_tv(&item->li_tv, &ni->li_tv); tv_copy(&item->li_tv, &ni->li_tv);
} }
tv_list_append(copy, ni); tv_list_append(copy, ni);
} }
@@ -828,13 +830,13 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key,
if (newtv) { if (newtv) {
dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("new")); dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("new"));
copy_tv(newtv, &v->di_tv); tv_copy(newtv, &v->di_tv);
tv_dict_add(argv[2].vval.v_dict, v); tv_dict_add(argv[2].vval.v_dict, v);
} }
if (oldtv) { if (oldtv) {
dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("old")); dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("old"));
copy_tv(oldtv, &v->di_tv); tv_copy(oldtv, &v->di_tv);
tv_dict_add(argv[2].vval.v_dict, v); tv_dict_add(argv[2].vval.v_dict, v);
} }
@@ -926,7 +928,7 @@ static dictitem_T *tv_dict_item_copy(dictitem_T *const di)
FUNC_ATTR_MALLOC FUNC_ATTR_MALLOC
{ {
dictitem_T *const new_di = tv_dict_item_alloc((const char *)di->di_key); dictitem_T *const new_di = tv_dict_item_alloc((const char *)di->di_key);
copy_tv(&di->di_tv, &new_di->di_tv); tv_copy(&di->di_tv, &new_di->di_tv);
return new_di; return new_di;
} }
@@ -1161,7 +1163,7 @@ bool tv_dict_get_callback(dict_T *const d,
} }
typval_T tv; typval_T tv;
copy_tv(&di->di_tv, &tv); tv_copy(&di->di_tv, &tv);
set_selfdict(&tv, d); set_selfdict(&tv, d);
bool res = callback_from_typval(result, &tv); bool res = callback_from_typval(result, &tv);
tv_clear(&tv); tv_clear(&tv);
@@ -1338,11 +1340,11 @@ void tv_dict_extend(dict_T *const d1, dict_T *const d2,
} }
if (watched) { if (watched) {
copy_tv(&di1->di_tv, &oldtv); tv_copy(&di1->di_tv, &oldtv);
} }
tv_clear(&di1->di_tv); tv_clear(&di1->di_tv);
copy_tv(&di2->di_tv, &di1->di_tv); tv_copy(&di2->di_tv, &di1->di_tv);
if (watched) { if (watched) {
tv_dict_watcher_notify(d1, (const char *)di1->di_key, &di1->di_tv, tv_dict_watcher_notify(d1, (const char *)di1->di_key, &di1->di_tv,
@@ -1433,7 +1435,7 @@ dict_T *tv_dict_copy(const vimconv_T *const conv,
break; break;
} }
} else { } else {
copy_tv(&di->di_tv, &new_di->di_tv); tv_copy(&di->di_tv, &new_di->di_tv);
} }
if (tv_dict_add(copy, new_di) == FAIL) { if (tv_dict_add(copy, new_di) == FAIL) {
tv_dict_item_free(new_di); tv_dict_item_free(new_di);
@@ -1782,6 +1784,64 @@ void tv_free(typval_T *tv)
} }
} }
//{{{3 Copy
/// Copy typval from one location to another
///
/// When needed allocates string or increases reference count. Does not make
/// a copy of a container, but copies its reference!
///
/// It is OK for `from` and `to` to point to the same location; this is used to
/// make a copy later.
///
/// @param[in] from Location to copy from.
/// @param[out] to Location to copy to.
void tv_copy(typval_T *const from, typval_T *const to)
{
to->v_type = from->v_type;
to->v_lock = VAR_UNLOCKED;
memmove(&to->vval, &from->vval, sizeof(to->vval));
switch (from->v_type) {
case VAR_NUMBER:
case VAR_FLOAT:
case VAR_SPECIAL: {
break;
}
case VAR_STRING:
case VAR_FUNC: {
if (from->vval.v_string != NULL) {
to->vval.v_string = vim_strsave(from->vval.v_string);
if (from->v_type == VAR_FUNC) {
func_ref(to->vval.v_string);
}
}
break;
}
case VAR_PARTIAL: {
if (to->vval.v_partial != NULL) {
to->vval.v_partial->pt_refcount++;
}
break;
}
case VAR_LIST: {
if (from->vval.v_list != NULL) {
to->vval.v_list->lv_refcount++;
}
break;
}
case VAR_DICT: {
if (from->vval.v_dict != NULL) {
to->vval.v_dict->dv_refcount++;
}
break;
}
case VAR_UNKNOWN: {
EMSG2(_(e_intern2), "tv_copy(UNKNOWN)");
break;
}
}
}
//{{{2 Locks //{{{2 Locks
/// Lock or unlock an item /// Lock or unlock an item

View File

@@ -0,0 +1,10 @@
source-file=/home/zyx/a.a/Proj/c/neovim/src/nvim/move.c
i-file=/home/zyx/a.a/Proj/c/neovim/src/nvim/move.i
language=C
skip-cl-exe=yes
preprocessor=gcc
platform=linux64
lic-file=/home/zyx/a.a/Proj/c/neovim/build/../PVS-Studio.lic
output-file=/home/zyx/a.a/Proj/c/neovim/build/../PVS-Studio.log.x
analysis-mode=4

View File

@@ -2559,7 +2559,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
if (sd_writer->sd_conv.vc_type != CONV_NONE) { if (sd_writer->sd_conv.vc_type != CONV_NONE) {
var_item_copy(&sd_writer->sd_conv, &vartv, &tgttv, true, 0); var_item_copy(&sd_writer->sd_conv, &vartv, &tgttv, true, 0);
} else { } else {
copy_tv(&vartv, &tgttv); tv_copy(&vartv, &tgttv);
} }
ShaDaWriteResult spe_ret; ShaDaWriteResult spe_ret;
if ((spe_ret = shada_pack_entry(packer, (ShadaEntry) { if ((spe_ret = shada_pack_entry(packer, (ShadaEntry) {

View File

@@ -280,7 +280,7 @@ local lua2typvalt_type_tab = {
if type(k) == 'string' then if type(k) == 'string' then
local di = eval.tv_dict_item_alloc(to_cstr(k)) local di = eval.tv_dict_item_alloc(to_cstr(k))
local val_tv = ffi.gc(lua2typvalt(v, processed), nil) local val_tv = ffi.gc(lua2typvalt(v, processed), nil)
eval.copy_tv(val_tv, di.di_tv) eval.tv_copy(val_tv, di.di_tv)
eval.tv_clear(val_tv) eval.tv_clear(val_tv)
eval.tv_dict_add(dct, di) eval.tv_dict_add(dct, di)
end end
@@ -300,7 +300,7 @@ local lua2typvalt_type_tab = {
argv = ffi.gc(ffi.cast('typval_T*', eval.xmalloc(ffi.sizeof('typval_T') * #l.args)), nil) argv = ffi.gc(ffi.cast('typval_T*', eval.xmalloc(ffi.sizeof('typval_T') * #l.args)), nil)
for i, arg in ipairs(l.args) do for i, arg in ipairs(l.args) do
local arg_tv = ffi.gc(lua2typvalt(arg, processed), nil) local arg_tv = ffi.gc(lua2typvalt(arg, processed), nil)
eval.copy_tv(arg_tv, argv[i - 1]) eval.tv_copy(arg_tv, argv[i - 1])
eval.tv_clear(arg_tv) eval.tv_clear(arg_tv)
end end
end end