aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r--src/nvim/eval.c240
1 files changed, 165 insertions, 75 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 2ca621ad22..a046b2a288 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -6445,7 +6445,7 @@ void dict_free(dict_T *d) {
*/
dictitem_T *dictitem_alloc(char_u *key) FUNC_ATTR_NONNULL_RET
{
- dictitem_T *di = xmalloc(sizeof(dictitem_T) + STRLEN(key));
+ dictitem_T *di = xmalloc(offsetof(dictitem_T, di_key) + STRLEN(key) + 1);
#ifndef __clang_analyzer__
STRCPY(di->di_key, key);
#endif
@@ -9251,7 +9251,7 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
dict_T *d = NULL;
typval_T save_val;
typval_T save_key;
- int rem;
+ int rem = false;
int todo;
char_u *ermsg = (char_u *)(map ? "map()" : "filter()");
char_u *arg_errmsg = (char_u *)(map ? N_("map() argument")
@@ -19042,124 +19042,205 @@ void free_tv(typval_T *varp)
#define TYPVAL_ENCODE_ALLOW_SPECIALS false
-#define TYPVAL_ENCODE_CONV_NIL() \
+#define TYPVAL_ENCODE_CONV_NIL(tv) \
do { \
tv->vval.v_special = kSpecialVarFalse; \
tv->v_lock = VAR_UNLOCKED; \
} while (0)
-#define TYPVAL_ENCODE_CONV_BOOL(ignored) \
- TYPVAL_ENCODE_CONV_NIL()
+#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \
+ TYPVAL_ENCODE_CONV_NIL(tv)
-#define TYPVAL_ENCODE_CONV_NUMBER(ignored) \
+#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \
do { \
- (void)ignored; \
+ (void)num; \
tv->vval.v_number = 0; \
tv->v_lock = VAR_UNLOCKED; \
} while (0)
-#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(ignored) \
- assert(false)
+#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num)
-#define TYPVAL_ENCODE_CONV_FLOAT(ignored) \
+#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \
do { \
tv->vval.v_float = 0; \
tv->v_lock = VAR_UNLOCKED; \
} while (0)
-#define TYPVAL_ENCODE_CONV_STRING(str, ignored) \
+#define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \
do { \
- xfree(str); \
+ xfree(buf); \
tv->vval.v_string = NULL; \
tv->v_lock = VAR_UNLOCKED; \
} while (0)
-#define TYPVAL_ENCODE_CONV_STR_STRING(ignored1, ignored2)
+#define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len)
-#define TYPVAL_ENCODE_CONV_EXT_STRING(ignored1, ignored2, ignored3)
+#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type)
-#define TYPVAL_ENCODE_CONV_FUNC(fun) \
+static inline int _nothing_conv_func_start(typval_T *const tv,
+ char_u *const fun)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1)
+{
+ tv->v_lock = VAR_UNLOCKED;
+ if (tv->v_type == VAR_PARTIAL) {
+ partial_T *const pt_ = tv->vval.v_partial;
+ if (pt_ != NULL && pt_->pt_refcount > 1) {
+ pt_->pt_refcount--;
+ tv->vval.v_partial = NULL;
+ return OK;
+ }
+ } else {
+ func_unref(fun);
+ if (fun != empty_string) {
+ xfree(fun);
+ }
+ tv->vval.v_string = NULL;
+ }
+ return NOTDONE;
+}
+#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
do { \
- func_unref(fun); \
- if (fun != empty_string) { \
- xfree(fun); \
+ if (_nothing_conv_func_start(tv, fun) != NOTDONE) { \
+ return OK; \
} \
- tv->vval.v_string = NULL; \
- tv->v_lock = VAR_UNLOCKED; \
} while (0)
-#define TYPVAL_ENCODE_CONV_PARTIAL(pt) \
- do { \
- partial_unref(pt); \
- pt = NULL; \
- tv->v_lock = VAR_UNLOCKED; \
- } while (0)
+#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len)
+#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len)
-#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
+static inline void _nothing_conv_func_end(typval_T *const tv, const int copyID)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
+{
+ if (tv->v_type == VAR_PARTIAL) {
+ partial_T *const pt = tv->vval.v_partial;
+ if (pt == NULL) {
+ return;
+ }
+ // Dictionary should already be freed by the time.
+ // If it was not freed then it is a part of the reference cycle.
+ assert(pt->pt_dict == NULL || pt->pt_dict->dv_copyID == copyID);
+ pt->pt_dict = NULL;
+ // As well as all arguments.
+ pt->pt_argc = 0;
+ assert(pt->pt_refcount <= 1);
+ partial_unref(pt);
+ tv->vval.v_partial = NULL;
+ assert(tv->v_lock == VAR_UNLOCKED);
+ }
+}
+#define TYPVAL_ENCODE_CONV_FUNC_END(tv) _nothing_conv_func_end(tv, copyID)
+
+#define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \
do { \
list_unref(tv->vval.v_list); \
tv->vval.v_list = NULL; \
tv->v_lock = VAR_UNLOCKED; \
} while (0)
-#define TYPVAL_ENCODE_CONV_EMPTY_DICT() \
+#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \
do { \
- dict_unref(tv->vval.v_dict); \
- tv->vval.v_dict = NULL; \
- tv->v_lock = VAR_UNLOCKED; \
- } while (0)
-
-#define TYPVAL_ENCODE_CONV_LIST_START(ignored) \
- do { \
- if (tv->vval.v_list->lv_refcount > 1) { \
- tv->vval.v_list->lv_refcount--; \
- tv->vval.v_list = NULL; \
- tv->v_lock = VAR_UNLOCKED; \
- return OK; \
+ assert((void *)&dict != (void *)&TYPVAL_ENCODE_NODICT_VAR); \
+ dict_unref((dict_T *)dict); \
+ *((dict_T **)&dict) = NULL; \
+ if (tv != NULL) { \
+ ((typval_T *)tv)->v_lock = VAR_UNLOCKED; \
} \
} while (0)
-#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS()
-
-#define TYPVAL_ENCODE_CONV_LIST_END() \
- do { \
- typval_T *const cur_tv = cur_mpsv->tv; \
- assert(cur_tv->v_type == VAR_LIST); \
- list_unref(cur_tv->vval.v_list); \
- cur_tv->vval.v_list = NULL; \
- cur_tv->v_lock = VAR_UNLOCKED; \
- } while (0)
+static inline int _nothing_conv_real_list_after_start(
+ typval_T *const tv, MPConvStackVal *const mpsv)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ assert(tv != NULL);
+ tv->v_lock = VAR_UNLOCKED;
+ if (tv->vval.v_list->lv_refcount > 1) {
+ tv->vval.v_list->lv_refcount--;
+ tv->vval.v_list = NULL;
+ mpsv->data.l.li = NULL;
+ return OK;
+ }
+ return NOTDONE;
+}
+#define TYPVAL_ENCODE_CONV_LIST_START(tv, len)
-#define TYPVAL_ENCODE_CONV_DICT_START(ignored) \
+#define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) \
do { \
- if (tv->vval.v_dict->dv_refcount > 1) { \
- tv->vval.v_dict->dv_refcount--; \
- tv->vval.v_dict = NULL; \
- tv->v_lock = VAR_UNLOCKED; \
- return OK; \
+ if (_nothing_conv_real_list_after_start(tv, &mpsv) != NOTDONE) { \
+ goto typval_encode_stop_converting_one_item; \
} \
} while (0)
-#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(ignored1, ignored2)
+#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv)
-#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY()
+static inline void _nothing_conv_list_end(typval_T *const tv)
+ FUNC_ATTR_ALWAYS_INLINE
+{
+ if (tv == NULL) {
+ return;
+ }
+ assert(tv->v_type == VAR_LIST);
+ list_T *const list = tv->vval.v_list;
+ list_unref(list);
+ tv->vval.v_list = NULL;
+}
+#define TYPVAL_ENCODE_CONV_LIST_END(tv) _nothing_conv_list_end(tv)
-#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS()
+static inline int _nothing_conv_real_dict_after_start(
+ typval_T *const tv, dict_T **const dictp, const void *const nodictvar,
+ MPConvStackVal *const mpsv)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (tv != NULL) {
+ tv->v_lock = VAR_UNLOCKED;
+ }
+ if ((const void *)dictp != nodictvar && (*dictp)->dv_refcount > 1) {
+ (*dictp)->dv_refcount--;
+ *dictp = NULL;
+ mpsv->data.d.todo = 0;
+ return OK;
+ }
+ return NOTDONE;
+}
+#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len)
-#define TYPVAL_ENCODE_CONV_DICT_END() \
+#define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv) \
do { \
- typval_T *const cur_tv = cur_mpsv->tv; \
- assert(cur_tv->v_type == VAR_DICT); \
- dict_unref(cur_tv->vval.v_dict); \
- cur_tv->vval.v_dict = NULL; \
- cur_tv->v_lock = VAR_UNLOCKED; \
+ if (_nothing_conv_real_dict_after_start( \
+ tv, (dict_T **)&dict, (void *)&TYPVAL_ENCODE_NODICT_VAR, \
+ &mpsv) != NOTDONE) { \
+ goto typval_encode_stop_converting_one_item; \
+ } \
} while (0)
-#define TYPVAL_ENCODE_CONV_RECURSE(ignored1, ignored2)
+#define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(tv, dict)
+#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict)
+#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict)
-// nothing_convert_one_value()
-// encode_vim_to_nothing()
-TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, nothing, void *, ignored)
+static inline void _nothing_conv_dict_end(typval_T *const tv,
+ dict_T **const dictp,
+ const void *const nodictvar)
+ FUNC_ATTR_ALWAYS_INLINE
+{
+ if ((const void *)dictp != nodictvar) {
+ dict_unref(*dictp);
+ *dictp = NULL;
+ }
+}
+#define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \
+ _nothing_conv_dict_end(tv, (dict_T **)&dict, \
+ (void *)&TYPVAL_ENCODE_NODICT_VAR)
+
+#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type)
+
+#define TYPVAL_ENCODE_SCOPE static
+#define TYPVAL_ENCODE_NAME nothing
+#define TYPVAL_ENCODE_FIRST_ARG_TYPE const void *const
+#define TYPVAL_ENCODE_FIRST_ARG_NAME ignored
+#include "nvim/eval/typval_encode.c.h"
+#undef TYPVAL_ENCODE_SCOPE
+#undef TYPVAL_ENCODE_NAME
+#undef TYPVAL_ENCODE_FIRST_ARG_TYPE
+#undef TYPVAL_ENCODE_FIRST_ARG_NAME
#undef TYPVAL_ENCODE_ALLOW_SPECIALS
#undef TYPVAL_ENCODE_CONV_NIL
@@ -19170,15 +19251,19 @@ TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, nothing, void *, ignored)
#undef TYPVAL_ENCODE_CONV_STRING
#undef TYPVAL_ENCODE_CONV_STR_STRING
#undef TYPVAL_ENCODE_CONV_EXT_STRING
-#undef TYPVAL_ENCODE_CONV_FUNC
-#undef TYPVAL_ENCODE_CONV_PARTIAL
+#undef TYPVAL_ENCODE_CONV_FUNC_START
+#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS
+#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF
+#undef TYPVAL_ENCODE_CONV_FUNC_END
#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
#undef TYPVAL_ENCODE_CONV_LIST_START
+#undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START
#undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS
#undef TYPVAL_ENCODE_CONV_LIST_END
#undef TYPVAL_ENCODE_CONV_DICT_START
-#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK
+#undef TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START
+#undef TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK
#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY
#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS
#undef TYPVAL_ENCODE_CONV_DICT_END
@@ -19190,7 +19275,9 @@ TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, nothing, void *, ignored)
void clear_tv(typval_T *varp)
{
if (varp != NULL && varp->v_type != VAR_UNKNOWN) {
- encode_vim_to_nothing(varp, varp, "clear_tv argument");
+ const int evn_ret = encode_vim_to_nothing(varp, varp, "clear_tv argument");
+ (void)evn_ret;
+ assert(evn_ret == OK);
}
}
@@ -21578,9 +21665,12 @@ void func_unref(char_u *name)
fp = find_func(name);
if (fp == NULL) {
#ifdef EXITFREE
- if (!entered_free_all_mem) // NOLINT(readability/braces)
-#endif
+ if (!entered_free_all_mem) {
EMSG2(_(e_intern2), "func_unref()");
+ }
+#else
+ EMSG2(_(e_intern2), "func_unref()");
+#endif
} else {
user_func_unref(fp);
}