Mercurial > vim
diff src/vim9cmds.c @ 33393:016d8f863230 v9.0.1955
patch 9.0.1955: Vim9: lockvar issues with objects/classes
Commit: https://github.com/vim/vim/commit/ee865f37acab6cac2cee6a171d60e1b365f852b0
Author: Ernie Rael <errael@raelity.com>
Date: Fri Sep 29 19:53:55 2023 +0200
patch 9.0.1955: Vim9: lockvar issues with objects/classes
Problem: Vim9: lockvar issues with objects/classes
Solution: fix `get_lhs()` object/class access and avoid `SEGV`,
make error messages more accurate.
- `get_lval()` detects/returns object/class access
- `compile_lock_unlock()` generate code for bare static and obj_arg access
- `do_lock_var()` check lval for `ll_object`/`ll_class` and fail if so.
Details:
- Add `ll_object`/`ll_class`/`ll_oi` to `lval_T`.
- Add `lockunlock_T` to `isn_T` for `is_arg` to specify handling of `lval_root` in `get_lval()`.
- In `get_lval()`, fill in `ll_object`/`ll_class`/`ll_oi` as needed; when no `[idx] or .key`, check lval_root on the way out.
- In `do_lock_var()` check for `ll_object`/`ll_class`; also bullet proof ll_dict case
and give `Dictionay required` if problem. (not needed to avoid lockvar crash anymore)
- In `compile_lock_unlock()` compile for the class variable and func arg cases.
closes: #13174
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Ernie Rael <errael@raelity.com>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Fri, 29 Sep 2023 20:00:07 +0200 |
parents | 6340c608ca54 |
children | 4a62e78803db |
line wrap: on
line diff
--- a/src/vim9cmds.c +++ b/src/vim9cmds.c @@ -189,10 +189,15 @@ compile_lock_unlock( int cc = *name_end; char_u *p = lvp->ll_name; int ret = OK; - size_t len; char_u *buf; isntype_T isn = ISN_EXEC; char *cmd = eap->cmdidx == CMD_lockvar ? "lockvar" : "unlockvar"; + int is_arg = FALSE; + +#ifdef LOG_LOCKVAR + ch_log(NULL, "LKVAR: compile_lock_unlock(): cookie %p, name %s", + coookie, p); +#endif if (cctx->ctx_skip == SKIP_YES) return OK; @@ -207,20 +212,68 @@ compile_lock_unlock( if (p[1] != ':') { char_u *end = find_name_end(p, NULL, NULL, FNE_CHECK_START); + // If name is is locally accessible, except for local var, + // then put it on the stack to use with ISN_LOCKUNLOCK. + // This could be v.memb, v[idx_key]; bare class variable, + // function arg. The local variable on the stack, will be passed + // to ex_lockvar() indirectly. - if (lookup_local(p, end - p, NULL, cctx) == OK) + char_u *name = NULL; + int len = end - p; + + if (lookup_local(p, len, NULL, cctx) == OK) { - char_u *s = p; - - if (*end != '.' && *end != '[') + // Handle "this", "this.val", "anyvar[idx]" + if (*end != '.' && *end != '[' + && (len != 4 || STRNCMP("this", p, len) != 0)) { emsg(_(e_cannot_lock_unlock_local_variable)); return FAIL; } - - // For "d.member" put the local variable on the stack, it will be - // passed to ex_lockvar() indirectly. - if (compile_load(&s, end, cctx, FALSE, FALSE) == FAIL) + // Push the local on the stack, could be "this". + name = p; +#ifdef LOG_LOCKVAR + ch_log(NULL, "LKVAR: compile... lookup_local: name %s", name); +#endif + } + if (name == NULL) + { + class_T *cl; + if (cctx_class_member_idx(cctx, p, len, &cl) >= 0) + { + if (*end != '.' && *end != '[') + { + // Push the class of the bare class variable name + name = cl->class_name; + len = STRLEN(name); +#ifdef LOG_LOCKVAR + ch_log(NULL, "LKVAR: compile... cctx_class_member: name %s", + name); +#endif + } + } + } + if (name == NULL) + { + int idx; + type_T *type; + // Can lockvar any function arg. + // TODO: test arg[idx]/arg.member + if (arg_exists(p, len, &idx, &type, NULL, cctx) == OK) + { + name = p; + is_arg = TRUE; +#ifdef LOG_LOCKVAR + ch_log(NULL, "LKVAR: compile... arg_exists: name %s", name); +#endif + } + } + if (name != NULL) + { +#ifdef LOG_LOCKVAR + ch_log(NULL, "LKVAR: compile... INS_LOCKUNLOCK %s", name); +#endif + if (compile_load(&name, name + len, cctx, FALSE, FALSE) == FAIL) return FAIL; isn = ISN_LOCKUNLOCK; } @@ -228,7 +281,7 @@ compile_lock_unlock( // Checking is done at runtime. *name_end = NUL; - len = name_end - p + 20; + size_t len = name_end - p + 20; buf = alloc(len); if (buf == NULL) ret = FAIL; @@ -238,7 +291,13 @@ compile_lock_unlock( vim_snprintf((char *)buf, len, "%s! %s", cmd, p); else vim_snprintf((char *)buf, len, "%s %d %s", cmd, deep, p); - ret = generate_EXEC_copy(cctx, isn, buf); +#ifdef LOG_LOCKVAR + ch_log(NULL, "LKVAR: compile... buf %s", buf); +#endif + if (isn == ISN_LOCKUNLOCK) + ret = generate_LOCKUNLOCK(cctx, buf, is_arg); + else + ret = generate_EXEC_copy(cctx, isn, buf); vim_free(buf); *name_end = cc;