From 7eceac218e8c8c8e10ff2a5461870ecfaba3fd42 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 2 Apr 2018 00:07:05 +0300 Subject: [PATCH 001/103] pvscheck: Make realdir work with nonexistent directories --- scripts/pvscheck.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/pvscheck.sh b/scripts/pvscheck.sh index 314966f6aa..84b42c2bae 100755 --- a/scripts/pvscheck.sh +++ b/scripts/pvscheck.sh @@ -302,8 +302,16 @@ create_compile_commands() {( # realpath is not available in Ubuntu trusty yet. realdir() {( local dir="$1" - cd "$dir" - printf '%s\n' "$PWD" + local add="" + while ! cd "$dir" 2>/dev/null ; do + add="${dir##*/}/$add" + local new_dir="${dir%/*}" + if test "$new_dir" = "$dir" ; then + return 1 + fi + dir="$new_dir" + done + printf '%s\n' "$PWD/$add" )} patch_sources() {( From 65d0b8ed32ac0a3123d93d2f78e4c236aa76283d Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 2 Apr 2018 00:10:08 +0300 Subject: [PATCH 002/103] pvscheck: Also produce fullhtml reports --- scripts/pvscheck.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/pvscheck.sh b/scripts/pvscheck.sh index 84b42c2bae..ba7d87e983 100755 --- a/scripts/pvscheck.sh +++ b/scripts/pvscheck.sh @@ -364,6 +364,7 @@ run_analysis() {( plog-converter -t xml -o PVS-studio.xml PVS-studio.log plog-converter -t errorfile -o PVS-studio.err PVS-studio.log plog-converter -t tasklist -o PVS-studio.tsk PVS-studio.log + plog-converter -t fullhtml -o PVS-studio.html.d PVS-studio.log )} detect_url() { From 6b84f7813cc98c7dfca7e751856af0cd2bdcf1ac Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 2 Apr 2018 00:12:28 +0300 Subject: [PATCH 003/103] pvscheck: Also provide source tree root to plog-converter --- scripts/pvscheck.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/pvscheck.sh b/scripts/pvscheck.sh index ba7d87e983..54e6241d07 100755 --- a/scripts/pvscheck.sh +++ b/scripts/pvscheck.sh @@ -361,10 +361,10 @@ run_analysis() {( --file build/compile_commands.json \ --sourcetree-root . || true - plog-converter -t xml -o PVS-studio.xml PVS-studio.log - plog-converter -t errorfile -o PVS-studio.err PVS-studio.log - plog-converter -t tasklist -o PVS-studio.tsk PVS-studio.log - plog-converter -t fullhtml -o PVS-studio.html.d PVS-studio.log + plog-converter -r . -t xml -o PVS-studio.xml PVS-studio.log + plog-converter -r . -t errorfile -o PVS-studio.err PVS-studio.log + plog-converter -r . -t tasklist -o PVS-studio.tsk PVS-studio.log + plog-converter -r . -t fullhtml -o PVS-studio.html.d PVS-studio.log )} detect_url() { From bf160dd668a47854d011482b17e57f38cf3493dd Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 2 Apr 2018 00:31:29 +0300 Subject: [PATCH 004/103] quickfix: Fix PVS/V560: remove duplicate condition Condition was checked in surrounding if(). --- src/nvim/quickfix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 2d8c353f92..1ff38b573e 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -924,7 +924,7 @@ restofline: if (qfprev == NULL) { return QF_FAIL; } - if (*fields->errmsg && !qi->qf_multiignore) { + if (*fields->errmsg) { size_t len = STRLEN(qfprev->qf_text); qfprev->qf_text = xrealloc(qfprev->qf_text, len + STRLEN(fields->errmsg) + 2); From 566048240625c5ac9404dfa4c490dbe40105824d Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 2 Apr 2018 00:41:00 +0300 Subject: [PATCH 005/103] api/buffer: Fix PVS/V547: use correct border for lnum Should actually be silencing that for the sake of the case when `long` is actually not 64-bit. But it appears that Vim had already defined maximal line number. And even declared that exact value invalid, so no need in silencing. --- src/nvim/api/buffer.c | 8 ++++---- src/nvim/pos.h | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index af723639c5..6be981a18e 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -186,12 +186,12 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id, for (size_t i = 0; i < rv.size; i++) { int64_t lnum = start + (int64_t)i; - if (lnum > LONG_MAX) { + if (lnum >= MAXLNUM) { api_set_error(err, kErrorTypeValidation, "Line index is too high"); goto end; } - const char *bufstr = (char *) ml_get_buf(buf, (linenr_T) lnum, false); + const char *bufstr = (char *)ml_get_buf(buf, (linenr_T)lnum, false); Object str = STRING_OBJ(cstr_to_string(bufstr)); // Vim represents NULs as NLs, but this may confuse clients. @@ -360,7 +360,7 @@ void nvim_buf_set_lines(uint64_t channel_id, for (size_t i = 0; i < to_replace; i++) { int64_t lnum = start + (int64_t)i; - if (lnum > LONG_MAX) { + if (lnum >= MAXLNUM) { api_set_error(err, kErrorTypeValidation, "Index value is too high"); goto end; } @@ -378,7 +378,7 @@ void nvim_buf_set_lines(uint64_t channel_id, for (size_t i = to_replace; i < new_len; i++) { int64_t lnum = start + (int64_t)i - 1; - if (lnum > LONG_MAX) { + if (lnum >= MAXLNUM) { api_set_error(err, kErrorTypeValidation, "Index value is too high"); goto end; } diff --git a/src/nvim/pos.h b/src/nvim/pos.h index 966255e6a4..0a2afd5847 100644 --- a/src/nvim/pos.h +++ b/src/nvim/pos.h @@ -10,8 +10,10 @@ typedef int colnr_T; /// Format used to print values which have colnr_T type #define PRIdCOLNR "d" -#define MAXLNUM 0x7fffffff // maximum (invalid) line number -#define MAXCOL 0x7fffffff // maximum column number, 31 bits +/// Maximal (invalid) line number +enum { MAXLNUM = 0x7fffffff }; +/// Maximal column number, 31 bits +enum { MAXCOL = 0x7fffffff }; /* * position in file or buffer From 1fc09b5b984e0963b5550310dd5d614d3007ba5a Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 2 Apr 2018 00:46:18 +0300 Subject: [PATCH 006/103] eval/typval_encode: Silence PVS/V501,V547,V779 These kinds of warnings are inevitable for generic macros. --- src/nvim/eval/typval_encode.c.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index f2d0d7265f..4556ce8193 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -340,8 +340,9 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( case VAR_PARTIAL: { partial_T *const pt = tv->vval.v_partial; (void)pt; - TYPVAL_ENCODE_CONV_FUNC_START(tv, (pt == NULL ? NULL : partial_name(pt))); - _mp_push(*mpstack, ((MPConvStackVal) { + TYPVAL_ENCODE_CONV_FUNC_START( // -V547 + tv, (pt == NULL ? NULL : partial_name(pt))); + _mp_push(*mpstack, ((MPConvStackVal) { // -V779 .type = kMPConvPartial, .tv = tv, .saved_copyID = copyID - 1, @@ -541,7 +542,8 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( } list_T *const val_list = val_di->di_tv.vval.v_list; if (val_list == NULL || tv_list_len(val_list) == 0) { - TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, TYPVAL_ENCODE_NODICT_VAR); + TYPVAL_ENCODE_CONV_EMPTY_DICT( // -V501 + tv, TYPVAL_ENCODE_NODICT_VAR); break; } TV_LIST_ITER_CONST(val_list, li, { From 414ef75ee644663c16075eba062554b73d532edc Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 2 Apr 2018 11:12:05 +0300 Subject: [PATCH 007/103] buffer: Beautify code a bit --- src/nvim/buffer.c | 51 ++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 0cd6f628b5..11c3b75d70 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "nvim/api/private/handle.h" #include "nvim/api/private/helpers.h" @@ -2913,7 +2914,6 @@ void maketitle(void) } } - t_str = buf; if (*p_titlestring != NUL) { if (stl_syntax & STL_IN_TITLE) { int use_sandbox = FALSE; @@ -2921,43 +2921,48 @@ void maketitle(void) use_sandbox = was_set_insecurely((char_u *)"titlestring", 0); called_emsg = FALSE; - build_stl_str_hl(curwin, t_str, sizeof(buf), + build_stl_str_hl(curwin, buf, sizeof(buf), p_titlestring, use_sandbox, 0, maxlen, NULL, NULL); - if (called_emsg) - set_string_option_direct((char_u *)"titlestring", -1, - (char_u *)"", OPT_FREE, SID_ERROR); + t_str = buf; + if (called_emsg) { + set_string_option_direct((char_u *)"titlestring", -1, (char_u *)"", + OPT_FREE, SID_ERROR); + } called_emsg |= save_called_emsg; - } else + } else { t_str = p_titlestring; + } } else { /* format: "fname + (path) (1 of 2) - VIM" */ -#define SPACE_FOR_FNAME (IOSIZE - 100) -#define SPACE_FOR_DIR (IOSIZE - 20) -#define SPACE_FOR_ARGNR (IOSIZE - 10) /* at least room for " - VIM" */ - if (curbuf->b_fname == NULL) +#define SPACE_FOR_FNAME (sizeof(buf) - 100) +#define SPACE_FOR_DIR (sizeof(buf) - 20) +#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - VIM" + if (curbuf->b_fname == NULL) { STRLCPY(buf, _("[No Name]"), SPACE_FOR_FNAME + 1); - else { + } else { p = transstr(path_tail(curbuf->b_fname)); STRLCPY(buf, p, SPACE_FOR_FNAME + 1); xfree(p); } switch (bufIsChanged(curbuf) - + (curbuf->b_p_ro * 2) - + (!MODIFIABLE(curbuf) * 4)) { - case 1: STRCAT(buf, " +"); break; - case 2: STRCAT(buf, " ="); break; - case 3: STRCAT(buf, " =+"); break; - case 4: - case 6: STRCAT(buf, " -"); break; - case 5: - case 7: STRCAT(buf, " -+"); break; + | (curbuf->b_p_ro << 1) + | (!MODIFIABLE(curbuf) << 2)) { + case 0: break; + case 1: STRCAT(buf, " +"); break; + case 2: STRCAT(buf, " ="); break; + case 3: STRCAT(buf, " =+"); break; + case 4: + case 6: STRCAT(buf, " -"); break; + case 5: + case 7: STRCAT(buf, " -+"); break; + default: assert(false); } if (curbuf->b_fname != NULL) { - /* Get path of file, replace home dir with ~ */ + // Get path of file, replace home dir with ~. off = (int)STRLEN(buf); buf[off++] = ' '; buf[off++] = '('; @@ -2998,6 +3003,10 @@ void maketitle(void) if (vim_strsize(buf) > maxlen) trunc_string(buf, buf, maxlen, IOSIZE); } + t_str = buf; +#undef SPACE_FOR_FNAME +#undef SPACE_FOR_DIR +#undef SPACE_FOR_ARGNR } } mustset = ti_change(t_str, &lasttitle); From e67075667678a0df6f43d0600f947be91b0b1e2e Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 3 Apr 2018 01:21:12 +0300 Subject: [PATCH 008/103] memory: Fix documentation of some string copying functions --- src/nvim/memory.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/nvim/memory.c b/src/nvim/memory.c index a66ab6a3cc..bfc2f208dd 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -369,10 +369,12 @@ char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen) /// string that fits in the buffer (unless, of course, the buffer size is /// zero). It does not pad out the result like strncpy() does. /// -/// @param dst Buffer to store the result -/// @param src String to be copied -/// @param dsize Size of `dst` -/// @return strlen(src). If retval >= dstsize, truncation occurs. +/// @param[out] dst Buffer to store the result. +/// @param[in] src String to be copied. +/// @param[in] dsize Size of `dst`. +/// +/// @return Length of `src`. May be greater than `dsize - 1`, which would mean +/// that string was truncated. size_t xstrlcpy(char *restrict dst, const char *restrict src, size_t dsize) FUNC_ATTR_NONNULL_ALL { @@ -394,11 +396,13 @@ size_t xstrlcpy(char *restrict dst, const char *restrict src, size_t dsize) /// @see vim_strcat from Vim. /// @see strlcat from OpenBSD. /// -/// @param dst Buffer to be appended-to. Must have a NUL byte. -/// @param src String to put at the end of `dst` -/// @param dsize Size of `dst` including NUL byte. Must be greater than 0. -/// @return strlen(src) + strlen(initial dst) -/// If retval >= dsize, truncation occurs. +/// @param[in,out] dst Buffer to be appended-to. Must have a NUL byte. +/// @param[in] src String to put at the end of `dst`. +/// @param[in] dsize Size of `dst` including NUL byte. Must be greater than 0. +/// +/// @return Length of the resulting string as if destination size was #SIZE_MAX. +/// May be greater than `dsize - 1`, which would mean that string was +/// truncated. size_t xstrlcat(char *const dst, const char *const src, const size_t dsize) FUNC_ATTR_NONNULL_ALL { From 0d7daaad98d5874b345453073f6e21b024ee42d4 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 8 Apr 2018 16:01:19 +0300 Subject: [PATCH 009/103] charset,*: Refactor transstr() --- src/nvim/buffer.c | 77 ++++++++------- src/nvim/charset.c | 232 +++++++++++++++++++++++++++----------------- src/nvim/eval.c | 2 +- src/nvim/fold.c | 2 +- src/nvim/globals.h | 2 - src/nvim/mbyte.c | 14 +-- src/nvim/mbyte.h | 7 ++ src/nvim/popupmnu.c | 2 +- src/nvim/screen.c | 10 +- 9 files changed, 204 insertions(+), 144 deletions(-) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 11c3b75d70..02d4cd30d4 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2886,15 +2886,13 @@ static char_u *lasticon = NULL; void maketitle(void) { - char_u *p; char_u *t_str = NULL; char_u *i_name; char_u *i_str = NULL; int maxlen = 0; int len; int mustset; - char_u buf[IOSIZE]; - int off; + char buf[IOSIZE]; if (!redrawing()) { /* Postpone updating the title when 'lazyredraw' is set. */ @@ -2921,10 +2919,10 @@ void maketitle(void) use_sandbox = was_set_insecurely((char_u *)"titlestring", 0); called_emsg = FALSE; - build_stl_str_hl(curwin, buf, sizeof(buf), - p_titlestring, use_sandbox, - 0, maxlen, NULL, NULL); - t_str = buf; + build_stl_str_hl(curwin, (char_u *)buf, sizeof(buf), + p_titlestring, use_sandbox, + 0, maxlen, NULL, NULL); + t_str = (char_u *)buf; if (called_emsg) { set_string_option_direct((char_u *)"titlestring", -1, (char_u *)"", OPT_FREE, SID_ERROR); @@ -2934,76 +2932,77 @@ void maketitle(void) t_str = p_titlestring; } } else { - /* format: "fname + (path) (1 of 2) - VIM" */ + // Format: "fname + (path) (1 of 2) - VIM". #define SPACE_FOR_FNAME (sizeof(buf) - 100) #define SPACE_FOR_DIR (sizeof(buf) - 20) -#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - VIM" +#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - VIM". if (curbuf->b_fname == NULL) { - STRLCPY(buf, _("[No Name]"), SPACE_FOR_FNAME + 1); + xstrlcpy(buf, _("[No Name]"), SPACE_FOR_FNAME + 1); } else { - p = transstr(path_tail(curbuf->b_fname)); - STRLCPY(buf, p, SPACE_FOR_FNAME + 1); - xfree(p); + transstr_buf((const char *)path_tail(curbuf->b_fname), + buf, SPACE_FOR_FNAME + 1); } switch (bufIsChanged(curbuf) | (curbuf->b_p_ro << 1) | (!MODIFIABLE(curbuf) << 2)) { case 0: break; - case 1: STRCAT(buf, " +"); break; - case 2: STRCAT(buf, " ="); break; - case 3: STRCAT(buf, " =+"); break; + case 1: strcat(buf, " +"); break; + case 2: strcat(buf, " ="); break; + case 3: strcat(buf, " =+"); break; case 4: - case 6: STRCAT(buf, " -"); break; + case 6: strcat(buf, " -"); break; case 5: - case 7: STRCAT(buf, " -+"); break; + case 7: strcat(buf, " -+"); break; default: assert(false); } if (curbuf->b_fname != NULL) { // Get path of file, replace home dir with ~. - off = (int)STRLEN(buf); + size_t off = strlen(buf); buf[off++] = ' '; buf[off++] = '('; home_replace(curbuf, curbuf->b_ffname, - buf + off, (size_t)(SPACE_FOR_DIR - off), true); + (char_u *)buf + off, (size_t)(SPACE_FOR_DIR - off), true); #ifdef BACKSLASH_IN_FILENAME /* avoid "c:/name" to be reduced to "c" */ if (isalpha(buf[off]) && buf[off + 1] == ':') off += 2; #endif - /* remove the file name */ - p = path_tail_with_sep(buf + off); - if (p == buf + off) - /* must be a help buffer */ - STRLCPY(buf + off, _("help"), SPACE_FOR_DIR - off); - else + // Remove the file name. + char *p = (char *)path_tail_with_sep((char_u *)buf + off); + if (p == buf + off) { + // Must be a help buffer. + xstrlcpy(buf + off, _("help"), SPACE_FOR_DIR - off); + } else { *p = NUL; + } - /* Translate unprintable chars and concatenate. Keep some - * room for the server name. When there is no room (very long - * file name) use (...). */ + // Translate unprintable chars and concatenate. Keep some + // room for the server name. When there is no room (very long + // file name) use (...). if (off < SPACE_FOR_DIR) { p = transstr(buf + off); - STRLCPY(buf + off, p, SPACE_FOR_DIR - off + 1); + xstrlcpy(buf + off, p, SPACE_FOR_DIR - off + 1); xfree(p); } else { - STRLCPY(buf + off, "...", SPACE_FOR_ARGNR - off + 1); + xstrlcpy(buf + off, "...", SPACE_FOR_ARGNR - off + 1); } - STRCAT(buf, ")"); + strcat(buf, ")"); } - append_arg_number(curwin, buf, SPACE_FOR_ARGNR, FALSE); + append_arg_number(curwin, (char_u *)buf, SPACE_FOR_ARGNR, false); - STRCAT(buf, " - NVIM"); + strcat(buf, " - NVIM"); if (maxlen > 0) { - /* make it shorter by removing a bit in the middle */ - if (vim_strsize(buf) > maxlen) - trunc_string(buf, buf, maxlen, IOSIZE); + // Make it shorter by removing a bit in the middle. + if (vim_strsize((char_u *)buf) > maxlen) { + trunc_string((char_u *)buf, (char_u *)buf, maxlen, sizeof(buf)); + } } - t_str = buf; + t_str = (char_u *)buf; #undef SPACE_FOR_FNAME #undef SPACE_FOR_DIR #undef SPACE_FOR_ARGNR @@ -3012,7 +3011,7 @@ void maketitle(void) mustset = ti_change(t_str, &lasttitle); if (p_icon) { - i_str = buf; + i_str = (char_u *)buf; if (*p_iconstring != NUL) { if (stl_syntax & STL_IN_ICON) { int use_sandbox = FALSE; diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 980b4ed426..2604c09ca4 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -313,69 +313,110 @@ void trans_characters(char_u *buf, int bufsize) } } -/// Translate a string into allocated memory, replacing special chars with -/// printable chars. +/// Find length of a string capable of holding s with all specials replaced /// -/// @param s +/// Assumes replacing special characters with printable ones just like +/// strtrans() does. /// -/// @return translated string -char_u *transstr(char_u *s) FUNC_ATTR_NONNULL_RET +/// @param[in] s String to check. +/// +/// @return number of bytes needed to hold a translation of `s`, NUL byte not +/// included. +size_t transstr_len(const char *const s) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE { - char_u *res; - char_u *p; - int c; - size_t l; - char_u hexbuf[11]; + const char *p = s; + size_t len = 0; + while (*p) { + const size_t l = (size_t)utfc_ptr2len((const char_u *)p); + if (l > 1) { + int pcc[MAX_MCO + 2]; + pcc[0] = utfc_ptr2char((const char_u *)p, &pcc[1]); + + if (vim_isprintc(pcc[0])) { + len += l; + } else { + for (size_t i = 0; i < ARRAY_SIZE(pcc); i++) { + char hexbuf[11]; + len += transchar_hex(hexbuf, pcc[i]); + } + } + p += l; + } else { + const int b2c_l = byte2cells((uint8_t)(*p++)); + // Illegal byte sequence may occupy up to 4 characters. + len += (size_t)(b2c_l > 0 ? b2c_l : 4); + } + } + return len; +} + +/// Replace special characters with printable ones +/// +/// @param[in] s String to replace characters from. +/// @param[out] buf Buffer to which result should be saved. +/// @param[in] len Buffer length. Resulting string may not occupy more then +/// len - 1 bytes (one for trailing NUL byte). +/// +/// @return `buf` argument unchanged. +char *transstr_buf(const char *const s, char *const buf, const size_t len) + FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL +{ + const char *p = s; + char *buf_p = buf; + char *const buf_e = buf_p + len - 1; + + while (*p != NUL && buf_p < buf_e) { + const size_t l = (size_t)utfc_ptr2len((const char_u *)p); + if (l > 1) { + if (buf_p + l >= buf_e) { + break; + } + int pcc[MAX_MCO + 2]; + pcc[0] = utfc_ptr2char((const char_u *)p, &pcc[1]); + + if (vim_isprintc(pcc[0])) { + memmove(buf_p, p, l); + buf_p += l; + } else { + for (size_t i = 0; i < ARRAY_SIZE(pcc); i++) { + char hexbuf[11]; + const size_t hexlen = transchar_hex(hexbuf, pcc[i]); + if (buf_p + hexlen >= buf_e) { + break; + } + memmove(buf_p, hexbuf, hexlen); + buf_p += hexlen; + } + } + p += l; + } else { + const char *const tb = (const char *)transchar_byte((uint8_t)(*p++)); + const size_t tb_len = strlen(tb); + memmove(buf_p, tb, tb_len); + buf_p += tb_len; + } + } + *buf_p = NUL; + assert(buf_p <= buf_e); + return buf; +} + +/// Copy string and replace special characters with printable characters +/// +/// Works like `strtrans()` does, used for that and in some other places. +/// +/// @param[in] s String to replace characters from. +/// +/// @return [allocated] translated string +char *transstr(const char *const s) + FUNC_ATTR_NONNULL_RET +{ // Compute the length of the result, taking account of unprintable // multi-byte characters. - size_t len = 0; - p = s; - - while (*p != NUL) { - if ((l = (size_t)(*mb_ptr2len)(p)) > 1) { - c = (*mb_ptr2char)(p); - p += l; - - if (vim_isprintc(c)) { - len += l; - } else { - transchar_hex(hexbuf, c); - len += STRLEN(hexbuf); - } - } else { - l = (size_t)byte2cells(*p++); - - if (l > 0) { - len += l; - } else { - // illegal byte sequence - len += 4; - } - } - } - res = xmallocz(len); - - *res = NUL; - p = s; - - while (*p != NUL) { - if ((l = (size_t)(*mb_ptr2len)(p)) > 1) { - c = (*mb_ptr2char)(p); - - if (vim_isprintc(c)) { - // append printable multi-byte char - STRNCAT(res, p, l); - } else { - transchar_hex(res + STRLEN(res), c); - } - p += l; - } else { - STRCAT(res, transchar_byte(*p++)); - } - } - - return res; + const size_t len = transstr_len((const char *)s) + 1; + return transstr_buf(s, xmalloc(len), len); } /// Convert the string "str[orglen]" to do ignore-case comparing. @@ -504,13 +545,15 @@ char_u* transchar(int c) return transchar_buf; } -/// Like transchar(), but called with a byte instead of a character. Checks -/// for an illegal UTF-8 byte. +/// Like transchar(), but called with a byte instead of a character /// -/// @param c +/// Checks for an illegal UTF-8 byte. +/// +/// @param[in] c Byte to translate. /// /// @return pointer to translated character in transchar_buf. -char_u* transchar_byte(int c) +char_u *transchar_byte(const int c) + FUNC_ATTR_WARN_UNUSED_RESULT { if (c >= 0x80) { transchar_nonprint(transchar_buf, c); @@ -519,12 +562,14 @@ char_u* transchar_byte(int c) return transchar(c); } -/// Convert non-printable character to two or more printable characters in -/// "buf[]". "buf" needs to be able to hold five bytes. -/// Does NOT work for multi-byte characters, c must be <= 255. +/// Convert non-printable characters to 2..4 printable ones /// -/// @param buf -/// @param c +/// @warning Does not work for multi-byte characters, c must be <= 255. +/// +/// @param[out] buf Buffer to store result in, must be able to hold at least +/// 5 bytes (conversion result + NUL). +/// @param[in] c Character to convert. NUL is assumed to be NL according to +/// `:h NL-used-for-NUL`. void transchar_nonprint(char_u *buf, int c) { if (c == NL) { @@ -534,54 +579,63 @@ void transchar_nonprint(char_u *buf, int c) // we use CR in place of NL in this case c = NL; } + assert(c <= 0xff); - if (dy_flags & DY_UHEX) { + if (dy_flags & DY_UHEX || c > 0x7f) { // 'display' has "uhex" - transchar_hex(buf, c); - } else if (c <= 0x7f) { + transchar_hex((char *)buf, c); + } else { // 0x00 - 0x1f and 0x7f buf[0] = '^'; // DEL displayed as ^? buf[1] = (char_u)(c ^ 0x40); buf[2] = NUL; - } else { - transchar_hex(buf, c); } } -/// Convert a non-printable character to hex. +/// Convert a non-printable character to hex C string like "" /// -/// @param buf -/// @param c -void transchar_hex(char_u *buf, int c) +/// @param[out] buf Buffer to store result in. +/// @param[in] c Character to convert. +/// +/// @return Number of bytes stored in buffer, excluding trailing NUL byte. +size_t transchar_hex(char *const buf, const int c) + FUNC_ATTR_NONNULL_ALL { - int i = 0; + size_t i = 0; - buf[0] = '<'; + buf[i++] = '<'; if (c > 255) { - buf[++i] = (char_u)nr2hex((unsigned)c >> 12); - buf[++i] = (char_u)nr2hex((unsigned)c >> 8); + if (c > 255 * 256) { + buf[i++] = (char)nr2hex((unsigned)c >> 20); + buf[i++] = (char)nr2hex((unsigned)c >> 16); + } + buf[i++] = (char)nr2hex((unsigned)c >> 12); + buf[i++] = (char)nr2hex((unsigned)c >> 8); } - buf[++i] = (char_u)(nr2hex((unsigned)c >> 4)); - buf[++i] = (char_u)(nr2hex((unsigned)c)); - buf[++i] = '>'; - buf[++i] = NUL; + buf[i++] = (char)(nr2hex((unsigned)c >> 4)); + buf[i++] = (char)(nr2hex((unsigned)c)); + buf[i++] = '>'; + buf[i] = NUL; + return i; } -/// Convert the lower 4 bits of byte "c" to its hex character. +/// Convert the lower 4 bits of byte "c" to its hex character +/// /// Lower case letters are used to avoid the confusion of being 0xf1 or /// function key 1. /// -/// @param c +/// @param[in] n Number to convert. /// /// @return the hex character. -static unsigned nr2hex(unsigned c) +static inline unsigned nr2hex(unsigned n) + FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT { - if ((c & 0xf) <= 9) { - return (c & 0xf) + '0'; + if ((n & 0xf) <= 9) { + return (n & 0xf) + '0'; } - return (c & 0xf) - 10 + 'a'; + return (n & 0xf) - 10 + 'a'; } /// Return number of display cells occupied by byte "b". diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 7bdfe7c9ee..9a5b508cb4 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -16090,7 +16090,7 @@ static void f_strridx(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void f_strtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr) { rettv->v_type = VAR_STRING; - rettv->vval.v_string = transstr((char_u *)tv_get_string(&argvars[0])); + rettv->vval.v_string = (char_u *)transstr(tv_get_string(&argvars[0])); } /* diff --git a/src/nvim/fold.c b/src/nvim/fold.c index db88791967..ad9cd4d562 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -1775,7 +1775,7 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, break; } if (*p != NUL) { - p = transstr(text); + p = (char_u *)transstr((const char *)text); xfree(text); text = p; } diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 776f131437..400f46eb79 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -16,8 +16,6 @@ #define IOSIZE (1024+1) // file I/O and sprintf buffer size -#define MAX_MCO 6 // maximum value for 'maxcombine' - # define MSG_BUF_LEN 480 // length of buffer for small messages # define MSG_BUF_CLEN (MSG_BUF_LEN / 6) // cell length (worst case: utf-8 // takes 6 bytes for one cell) diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 008bce6df6..446063e33b 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -704,12 +704,14 @@ bool utf_composinglike(const char_u *p1, const char_u *p2) return arabic_combine(utf_ptr2char(p1), c2); } -/* - * Convert a UTF-8 byte string to a wide character. Also get up to MAX_MCO - * composing characters. - * - * @param [out] pcc: composing chars, last one is 0 - */ +/// Convert a UTF-8 string to a wide character +/// +/// Also gets up to #MAX_MCO composing characters. +/// +/// @param[out] pcc Location where to store composing characters. Must have +/// space at least for #MAX_MCO + 1 elements. +/// +/// @return leading character. int utfc_ptr2char(const char_u *p, int *pcc) { int len; diff --git a/src/nvim/mbyte.h b/src/nvim/mbyte.h index a5ce1b0a15..dd8e44b3f9 100644 --- a/src/nvim/mbyte.h +++ b/src/nvim/mbyte.h @@ -19,6 +19,13 @@ #define MB_BYTE2LEN(b) utf8len_tab[b] #define MB_BYTE2LEN_CHECK(b) (((b) < 0 || (b) > 255) ? 1 : utf8len_tab[b]) +/// Maximum value for 'maxcombine' +/// +/// At most that number of composing characters may be attached to the leading +/// character by various `utfc_*` functions. Note that some functions do not +/// have this limit. +enum { MAX_MCO = 6 }; + // max length of an unicode char #define MB_MAXCHAR 6 diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c index 348daf028a..4c2fc6d906 100644 --- a/src/nvim/popupmnu.c +++ b/src/nvim/popupmnu.c @@ -387,7 +387,7 @@ void pum_redraw(void) char_u saved = *p; *p = NUL; - st = transstr(s); + st = (char_u *)transstr((const char *)s); *p = saved; if (curwin->w_p_rl) { diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 05ad126fa0..e232939403 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -3213,9 +3213,9 @@ win_line ( || (mb_l > 1 && (!vim_isprintc(mb_c)))) { // Illegal UTF-8 byte: display as . // Non-BMP character : display as ? or fullwidth ?. - transchar_hex(extra, mb_c); - if (wp->w_p_rl) { // reverse - rl_mirror(extra); + transchar_hex((char *)extra, mb_c); + if (wp->w_p_rl) { // reverse + rl_mirror(extra); } p_extra = extra; @@ -5232,8 +5232,8 @@ win_redr_custom ( xfree(stl); ewp->w_p_crb = p_crb_save; - /* Make all characters printable. */ - p = transstr(buf); + // Make all characters printable. + p = (char_u *)transstr((const char *)buf); len = STRLCPY(buf, p, sizeof(buf)); len = (size_t)len < sizeof(buf) ? len : (int)sizeof(buf) - 1; xfree(p); From 2a6491cdf86709abd2a7c7920e190c1a802b4f26 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 8 Apr 2018 19:16:41 +0300 Subject: [PATCH 010/103] os/env: Refactor home_replace() to the new style and to return length --- src/nvim/os/env.c | 158 +++++++++++++++++++++++++--------------------- 1 file changed, 87 insertions(+), 71 deletions(-) diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 3fcb9415c7..096a90cb21 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -14,6 +14,7 @@ #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/path.h" +#include "nvim/macros.h" #include "nvim/strings.h" #include "nvim/eval.h" #include "nvim/ex_getln.h" @@ -176,7 +177,7 @@ void os_get_hostname(char *hostname, size_t size) /// - do os_dirname() to get the real name of that directory. /// This also works with mounts and links. /// Don't do this for Windows, it will change the "current dir" for a drive. -static char_u *homedir = NULL; +static char *homedir = NULL; void init_homedir(void) { @@ -220,7 +221,7 @@ void init_homedir(void) } } #endif - homedir = vim_strsave((char_u *)var); + homedir = xstrdup(var); } } @@ -357,7 +358,7 @@ void expand_env_esc(char_u *restrict srcp, } else if (src[1] == NUL // home directory || vim_ispathsep(src[1]) || vim_strchr((char_u *)" ,\t\n", src[1]) != NULL) { - var = homedir; + var = (char_u *)homedir; tail = src + 1; } else { // user directory #if defined(UNIX) @@ -719,108 +720,123 @@ char *vim_getenv(const char *name) /// Replace home directory by "~" in each space or comma separated file name in /// 'src'. +/// +/// Replace home directory with tilde in each file name +/// /// If anything fails (except when out of space) dst equals src. -/// @param buf When not NULL, check for help files -/// @param src Input file name -/// @param dst Where to put the result -/// @param dstlen Maximum length of the result -/// @param one If true, only replace one file name, including spaces and commas -/// in the file name -void home_replace(const buf_T *const buf, const char_u *src, - char_u *dst, size_t dstlen, bool one) +/// +/// @param[in] buf When not NULL, uses this buffer to check whether it is +/// a help file. If it is then path to file is removed +/// completely, `one` is ignored and assumed to be true. +/// @param[in] src Input file names. Assumed to be a space/comma separated +/// list unless `one` is true. +/// @param[out] dst Where to put the result. +/// @param[in] dstlen Destination length. +/// @param[in] one If true, assumes source is a single file name and not +/// a list of them. +/// +/// @return length of the string put into dst, does not include NUL byte. +size_t home_replace(const buf_T *const buf, const char_u *src, + char_u *const dst, size_t dstlen, const bool one) + FUNC_ATTR_NONNULL_ARG(3) { - size_t dirlen = 0, envlen = 0; - size_t len; + size_t dirlen = 0; + size_t envlen = 0; if (src == NULL) { *dst = NUL; - return; + return 0; } - /* - * If the file is a help file, remove the path completely. - */ if (buf != NULL && buf->b_help) { - xstrlcpy((char *)dst, (char *)path_tail(src), dstlen); - return; + const size_t dlen = xstrlcpy((char *)dst, (char *)path_tail(src), dstlen); + return MIN(dlen, dstlen - 1); } - /* - * We check both the value of the $HOME environment variable and the - * "real" home directory. - */ - if (homedir != NULL) - dirlen = STRLEN(homedir); + // We check both the value of the $HOME environment variable and the + // "real" home directory. + if (homedir != NULL) { + dirlen = strlen(homedir); + } - char_u *homedir_env = (char_u *)os_getenv("HOME"); + const char *const homedir_env = os_getenv("HOME"); + char *homedir_env_mod = (char *)homedir_env; bool must_free = false; - if (homedir_env != NULL && vim_strchr(homedir_env, '~') != NULL) { + if (homedir_env_mod != NULL && strchr(homedir_env_mod, '~') != NULL) { must_free = true; size_t usedlen = 0; - size_t flen = STRLEN(homedir_env); + size_t flen = strlen(homedir_env_mod); char_u *fbuf = NULL; - (void)modify_fname((char_u *)":p", &usedlen, &homedir_env, &fbuf, &flen); - flen = STRLEN(homedir_env); - if (flen > 0 && vim_ispathsep(homedir_env[flen - 1])) - /* Remove the trailing / that is added to a directory. */ - homedir_env[flen - 1] = NUL; + (void)modify_fname((char_u *)":p", &usedlen, (char_u **)&homedir_env_mod, + &fbuf, &flen); + flen = strlen(homedir_env_mod); + assert(homedir_env_mod != homedir_env); + if (vim_ispathsep(homedir_env_mod[flen - 1])) { + // Remove the trailing / that is added to a directory. + homedir_env_mod[flen - 1] = NUL; + } } - if (homedir_env != NULL) - envlen = STRLEN(homedir_env); + if (homedir_env_mod != NULL) { + envlen = strlen(homedir_env_mod); + } - if (!one) + if (!one) { src = skipwhite(src); + } + char *dst_p = (char *)dst; while (*src && dstlen > 0) { - /* - * Here we are at the beginning of a file name. - * First, check to see if the beginning of the file name matches - * $HOME or the "real" home directory. Check that there is a '/' - * after the match (so that if e.g. the file is "/home/pieter/bla", - * and the home directory is "/home/piet", the file does not end up - * as "~er/bla" (which would seem to indicate the file "bla" in user - * er's home directory)). - */ - char_u *p = homedir; - len = dirlen; - for (;; ) { - if ( len - && fnamencmp(src, p, len) == 0 - && (vim_ispathsep(src[len]) - || (!one && (src[len] == ',' || src[len] == ' ')) - || src[len] == NUL)) { + // Here we are at the beginning of a file name. + // First, check to see if the beginning of the file name matches + // $HOME or the "real" home directory. Check that there is a '/' + // after the match (so that if e.g. the file is "/home/pieter/bla", + // and the home directory is "/home/piet", the file does not end up + // as "~er/bla" (which would seem to indicate the file "bla" in user + // er's home directory)). + char *p = homedir; + size_t len = dirlen; + for (;;) { + if (len + && fnamencmp(src, (char_u *)p, len) == 0 + && (vim_ispathsep(src[len]) + || (!one && (src[len] == ',' || src[len] == ' ')) + || src[len] == NUL)) { src += len; - if (--dstlen > 0) - *dst++ = '~'; + if (--dstlen > 0) { + *dst_p++ = '~'; + } - /* - * If it's just the home directory, add "/". - */ - if (!vim_ispathsep(src[0]) && --dstlen > 0) - *dst++ = '/'; + // If it's just the home directory, add "/". + if (!vim_ispathsep(src[0]) && --dstlen > 0) { + *dst_p++ = '/'; + } break; } - if (p == homedir_env) + if (p == homedir_env_mod) { break; - p = homedir_env; + } + p = homedir_env_mod; len = envlen; } - /* if (!one) skip to separator: space or comma */ - while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0) - *dst++ = *src++; - /* skip separator */ - while ((*src == ' ' || *src == ',') && --dstlen > 0) - *dst++ = *src++; + // if (!one) skip to separator: space or comma. + while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0) { + *dst_p++ = (char)*src++; + } + // Skip separator. + while ((*src == ' ' || *src == ',') && --dstlen > 0) { + *dst_p++ = (char)*src++; + } } - /* if (dstlen == 0) out of space, what to do??? */ + // If (dstlen == 0) out of space, what to do??? - *dst = NUL; + *dst_p = NUL; if (must_free) { - xfree(homedir_env); + xfree(homedir_env_mod); } + return (size_t)(dst_p - (char *)dst); } /// Like home_replace, store the replaced string in allocated memory. From 58a5699a4400d1d706056e456ca641b3e4b0a5e9 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 8 Apr 2018 19:21:44 +0300 Subject: [PATCH 011/103] buffer: PVS/V557: Refactor maketitle() --- src/nvim/buffer.c | 67 +++++++++++++++++++++++++++------------------- src/nvim/charset.c | 12 +++++---- src/nvim/strings.h | 18 +++++++++++++ 3 files changed, 64 insertions(+), 33 deletions(-) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 02d4cd30d4..e7ecdb6c19 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2936,45 +2936,48 @@ void maketitle(void) #define SPACE_FOR_FNAME (sizeof(buf) - 100) #define SPACE_FOR_DIR (sizeof(buf) - 20) -#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - VIM". +#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - NVIM". + char *buf_p = buf; if (curbuf->b_fname == NULL) { - xstrlcpy(buf, _("[No Name]"), SPACE_FOR_FNAME + 1); + const size_t size = xstrlcpy(buf_p, _("[No Name]"), + SPACE_FOR_FNAME + 1); + buf_p += MIN(size, SPACE_FOR_FNAME); } else { - transstr_buf((const char *)path_tail(curbuf->b_fname), - buf, SPACE_FOR_FNAME + 1); + buf_p += transstr_buf((const char *)path_tail(curbuf->b_fname), + buf_p, SPACE_FOR_FNAME + 1); } switch (bufIsChanged(curbuf) | (curbuf->b_p_ro << 1) | (!MODIFIABLE(curbuf) << 2)) { case 0: break; - case 1: strcat(buf, " +"); break; - case 2: strcat(buf, " ="); break; - case 3: strcat(buf, " =+"); break; + case 1: buf_p = strappend(buf_p, " +"); break; + case 2: buf_p = strappend(buf_p, " ="); break; + case 3: buf_p = strappend(buf_p, " =+"); break; case 4: - case 6: strcat(buf, " -"); break; + case 6: buf_p = strappend(buf_p, " -"); break; case 5: - case 7: strcat(buf, " -+"); break; + case 7: buf_p = strappend(buf_p, " -+"); break; default: assert(false); } if (curbuf->b_fname != NULL) { // Get path of file, replace home dir with ~. - size_t off = strlen(buf); - buf[off++] = ' '; - buf[off++] = '('; - home_replace(curbuf, curbuf->b_ffname, - (char_u *)buf + off, (size_t)(SPACE_FOR_DIR - off), true); + *buf_p++ = ' '; + *buf_p++ = '('; + home_replace(curbuf, curbuf->b_ffname, (char_u *)buf_p, + (SPACE_FOR_DIR - (size_t)(buf_p - buf)), true); #ifdef BACKSLASH_IN_FILENAME - /* avoid "c:/name" to be reduced to "c" */ - if (isalpha(buf[off]) && buf[off + 1] == ':') - off += 2; + // Avoid "c:/name" to be reduced to "c". + if (isalpha((uint8_t)buf_p) && *(buf_p + 1) == ':') { + buf_p += 2; + } #endif // Remove the file name. - char *p = (char *)path_tail_with_sep((char_u *)buf + off); - if (p == buf + off) { + char *p = (char *)path_tail_with_sep((char_u *)buf_p); + if (p == buf_p) { // Must be a help buffer. - xstrlcpy(buf + off, _("help"), SPACE_FOR_DIR - off); + xstrlcpy(buf_p, _("help"), SPACE_FOR_DIR - (size_t)(buf_p - buf)); } else { *p = NUL; } @@ -2982,19 +2985,27 @@ void maketitle(void) // Translate unprintable chars and concatenate. Keep some // room for the server name. When there is no room (very long // file name) use (...). - if (off < SPACE_FOR_DIR) { - p = transstr(buf + off); - xstrlcpy(buf + off, p, SPACE_FOR_DIR - off + 1); - xfree(p); + if ((size_t)(buf_p - buf) < SPACE_FOR_DIR) { + char *const tbuf = transstr(buf_p); + const size_t free_space = SPACE_FOR_DIR - (size_t)(buf_p - buf) + 1; + const size_t dir_len = xstrlcpy(buf_p, tbuf, free_space); + buf_p += MIN(dir_len, free_space - 1); + xfree(tbuf); } else { - xstrlcpy(buf + off, "...", SPACE_FOR_ARGNR - off + 1); + const size_t free_space = SPACE_FOR_ARGNR - (size_t)(buf_p - buf) + 1; + const size_t dots_len = xstrlcpy(buf_p, "...", free_space); + buf_p += MIN(dots_len, free_space - 1); } - strcat(buf, ")"); + *buf_p++ = ')'; + *buf_p = NUL; + } else { + *buf_p = NUL; } - append_arg_number(curwin, (char_u *)buf, SPACE_FOR_ARGNR, false); + append_arg_number(curwin, (char_u *)buf_p, + (int)(SPACE_FOR_ARGNR - (size_t)(buf_p - buf)), false); - strcat(buf, " - NVIM"); + strcat(buf_p, " - NVIM"); if (maxlen > 0) { // Make it shorter by removing a bit in the middle. diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 2604c09ca4..d8d080ee8a 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -359,9 +359,9 @@ size_t transstr_len(const char *const s) /// @param[in] len Buffer length. Resulting string may not occupy more then /// len - 1 bytes (one for trailing NUL byte). /// -/// @return `buf` argument unchanged. -char *transstr_buf(const char *const s, char *const buf, const size_t len) - FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL +/// @return length of the resulting string, without the NUL byte. +size_t transstr_buf(const char *const s, char *const buf, const size_t len) + FUNC_ATTR_NONNULL_ALL { const char *p = s; char *buf_p = buf; @@ -400,7 +400,7 @@ char *transstr_buf(const char *const s, char *const buf, const size_t len) } *buf_p = NUL; assert(buf_p <= buf_e); - return buf; + return (size_t)(buf_p - buf); } /// Copy string and replace special characters with printable characters @@ -416,7 +416,9 @@ char *transstr(const char *const s) // Compute the length of the result, taking account of unprintable // multi-byte characters. const size_t len = transstr_len((const char *)s) + 1; - return transstr_buf(s, xmalloc(len), len); + char *const buf = xmalloc(len); + transstr_buf(s, buf, len); + return buf; } /// Convert the string "str[orglen]" to do ignore-case comparing. diff --git a/src/nvim/strings.h b/src/nvim/strings.h index 59b8701a3f..f2876c6307 100644 --- a/src/nvim/strings.h +++ b/src/nvim/strings.h @@ -3,10 +3,28 @@ #include #include +#include #include "nvim/types.h" #include "nvim/eval/typval.h" +/// Append string to string and return pointer to the next byte +/// +/// Unlike strcat, this one does *not* add NUL byte and returns pointer to the +/// past of the added string. +/// +/// @param[out] dst String to append to. +/// @param[in] src String to append. +/// +/// @return pointer to the byte just past the appended byte. +static inline char *strappend(char *const dst, const char *const src) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT + FUNC_ATTR_NONNULL_RET +{ + const size_t src_len = strlen(src); + return (char *)memmove(dst, src, src_len) + src_len; +} + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "strings.h.generated.h" #endif From 93be2ba5422cf08369269fe12567dea04254aa20 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 9 Apr 2018 01:12:52 +0300 Subject: [PATCH 012/103] charset: Fix transchar() with multibyte characters It appears that transchar() was working under assumption that `transchar_nonprint()` may be used for multibyte characters while its documentation stated exact opposite. It was not actually untrue though, except that longer buffer would be needed then the one stated in documentation. But it is false now with assert(). --- src/nvim/charset.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/nvim/charset.c b/src/nvim/charset.c index d8d080ee8a..aecde29ce2 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -517,14 +517,16 @@ char_u* str_foldcase(char_u *str, int orglen, char_u *buf, int buflen) // Does NOT work for multi-byte characters, c must be <= 255. // Also doesn't work for the first byte of a multi-byte, "c" must be a // character! -static char_u transchar_buf[7]; +static char_u transchar_buf[11]; -/// Translates a character +/// Translate a character into a printable one, leaving printable ASCII intact /// -/// @param c +/// All unicode characters are considered non-printable in this function. /// -/// @return translated character. -char_u* transchar(int c) +/// @param[in] c Character to translate. +/// +/// @return translated character into a static buffer. +char_u *transchar(int c) { int i = 0; if (IS_SPECIAL(c)) { @@ -537,12 +539,14 @@ char_u* transchar(int c) if ((!chartab_initialized && (((c >= ' ') && (c <= '~')) || (p_altkeymap && F_ischar(c)))) - || ((c < 256) && vim_isprintc_strict(c))) { + || ((c <= 0xFF) && vim_isprintc_strict(c))) { // printable character transchar_buf[i] = (char_u)c; transchar_buf[i + 1] = NUL; - } else { + } else if (c <= 0xFF){ transchar_nonprint(transchar_buf + i, c); + } else { + transchar_hex((char *)transchar_buf + i, c); } return transchar_buf; } From 840027c7f5720ab7c09b7b9a8aa4f3cc0c8cf777 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 9 Apr 2018 09:56:39 +0300 Subject: [PATCH 013/103] buffer: Fix PVS/V547: base is never set to octal --- src/nvim/buffer.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index e7ecdb6c19..1a5b7ec612 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -3110,7 +3110,6 @@ void free_titles(void) /// be used when printing numbers in the status line. typedef enum { kNumBaseDecimal = 10, - kNumBaseOctal = 8, kNumBaseHexadecimal = 16 } NumberBase; @@ -3908,9 +3907,7 @@ int build_stl_str_hl( // Note: The `*` means we take the width as one of the arguments *t++ = '*'; - *t++ = (char_u) (base == kNumBaseHexadecimal ? 'X' - : (base == kNumBaseOctal ? 'o' - : 'd')); + *t++ = (char_u)(base == kNumBaseHexadecimal ? 'X' : 'd'); *t = 0; // } From 92759ef34fabe8ffb81f32bdda17f999f868082d Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 9 Apr 2018 10:02:54 +0300 Subject: [PATCH 014/103] buffer: Fix PVS/V560: condition was checked three lines above --- src/nvim/buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 1a5b7ec612..a4ba30337d 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -5362,7 +5362,7 @@ void bufhl_clear_line_range(buf_T *buf, if (line > line_end) { break; } - if (line_start <= line && line <= line_end) { + if (line_start <= line) { BufhlLineStatus status = bufhl_clear_line(l, src_id, line); if (status != kBLSUnchanged) { if (line > last_changed) { From f8a44b73f012b99f3840006035b869ae82656445 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 9 Apr 2018 10:09:45 +0300 Subject: [PATCH 015/103] event/loop: Silence PVS/V547: condition is false in case of no timeout --- src/nvim/event/loop.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nvim/event/loop.h b/src/nvim/event/loop.h index d1a40d5cc9..1b288fc4cb 100644 --- a/src/nvim/event/loop.h +++ b/src/nvim/event/loop.h @@ -53,6 +53,8 @@ typedef struct loop { } \ } while (0) +// -V:LOOP_PROCESS_EVENTS_UNTIL:547 + // Poll for events until a condition or timeout #define LOOP_PROCESS_EVENTS_UNTIL(loop, multiqueue, timeout, condition) \ do { \ From 1edb4894dcb78a26337c05649828bb4a376a713a Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 9 Apr 2018 10:14:45 +0300 Subject: [PATCH 016/103] charset: Silence PVS/V785: remove switch() No idea why it thinks that pre is constant expression, but switch() may be removed. --- src/nvim/charset.c | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/src/nvim/charset.c b/src/nvim/charset.c index aecde29ce2..9ae3a10031 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1731,7 +1731,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, && !STRING_ENDED(ptr + 1) && ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') { pre = ptr[1]; - // Detect hexadecimal: 0x or 0X follwed by hex digit + // Detect hexadecimal: 0x or 0X followed by hex digit. if ((what & STR2NR_HEX) && !STRING_ENDED(ptr + 2) && (pre == 'X' || pre == 'x') @@ -1739,7 +1739,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, ptr += 2; goto vim_str2nr_hex; } - // Detect binary: 0b or 0B follwed by 0 or 1 + // Detect binary: 0b or 0B followed by 0 or 1. if ((what & STR2NR_BIN) && !STRING_ENDED(ptr + 2) && (pre == 'B' || pre == 'b') @@ -1747,7 +1747,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, ptr += 2; goto vim_str2nr_bin; } - // Detect octal number: zero followed by octal digits without '8' or '9' + // Detect octal number: zero followed by octal digits without '8' or '9'. pre = 0; if (!(what & STR2NR_OCT) || !('0' <= ptr[1] && ptr[1] <= '7')) { @@ -1778,32 +1778,21 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, ptr++; \ } \ } while (0) - switch (pre) { - case 'b': - case 'B': { vim_str2nr_bin: - PARSE_NUMBER(2, (*ptr == '0' || *ptr == '1'), (*ptr - '0')); - break; - } - case '0': { + PARSE_NUMBER(2, (*ptr == '0' || *ptr == '1'), (*ptr - '0')); + goto vim_str2nr_proceed; vim_str2nr_oct: - PARSE_NUMBER(8, ('0' <= *ptr && *ptr <= '7'), (*ptr - '0')); - break; - } - case 0: { + PARSE_NUMBER(8, ('0' <= *ptr && *ptr <= '7'), (*ptr - '0')); + goto vim_str2nr_proceed; vim_str2nr_dec: - PARSE_NUMBER(10, (ascii_isdigit(*ptr)), (*ptr - '0')); - break; - } - case 'x': - case 'X': { + PARSE_NUMBER(10, (ascii_isdigit(*ptr)), (*ptr - '0')); + goto vim_str2nr_proceed; vim_str2nr_hex: - PARSE_NUMBER(16, (ascii_isxdigit(*ptr)), (hex2nr(*ptr))); - break; - } - } + PARSE_NUMBER(16, (ascii_isxdigit(*ptr)), (hex2nr(*ptr))); + goto vim_str2nr_proceed; #undef PARSE_NUMBER +vim_str2nr_proceed: if (prep != NULL) { *prep = pre; } From db29fa816401f2d814d43ce6e4a2c585b2bd25bc Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 9 Apr 2018 10:16:09 +0300 Subject: [PATCH 017/103] charset: Fix PVS/V560: remove condition which was already checked --- src/nvim/charset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 9ae3a10031..9c1dc9f4a2 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -923,7 +923,7 @@ bool vim_isprintc(int c) if (c >= 0x100) { return utf_printable(c); } - return c >= 0x100 || (c > 0 && (g_chartab[c] & CT_PRINT_CHAR)); + return c > 0 && (g_chartab[c] & CT_PRINT_CHAR); } /// Strict version of vim_isprintc(c), don't return true if "c" is the head From 5acda0357661af0c50e4fa2b8825e9c3678ca013 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 9 Apr 2018 10:18:40 +0300 Subject: [PATCH 018/103] eval/decode: Silence PVS/V547: code written for 32-bit integers --- src/nvim/eval/decode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index 17799b500c..4d75c7bda1 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -985,7 +985,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv) break; } case MSGPACK_OBJECT_NEGATIVE_INTEGER: { - if (mobj.via.i64 >= VARNUMBER_MIN) { + if (mobj.via.i64 >= VARNUMBER_MIN) { // -V547 *rettv = (typval_T) { .v_type = VAR_NUMBER, .v_lock = VAR_UNLOCKED, From ef57cd81fe008adea7021410bb2a7ed925527cdc Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 9 Apr 2018 10:23:11 +0300 Subject: [PATCH 019/103] diff: Fix PVS/V547: remove no longer needed OOM handler --- src/nvim/diff.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 0ee1c3815d..f9e40ed06f 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -859,9 +859,9 @@ void ex_diffpatch(exarg_T *eap) char_u *esc_name = NULL; #ifdef UNIX - char_u dirbuf[MAXPATHL]; - char_u *fullname = NULL; + char *fullname = NULL; #endif + // We need two temp file names. // Name of original temp file. char_u *tmp_orig = vim_tempname(); @@ -881,21 +881,17 @@ void ex_diffpatch(exarg_T *eap) #ifdef UNIX // Get the absolute path of the patchfile, changing directory below. - fullname = (char_u *)FullName_save((char *)eap->arg, false); -#endif - + fullname = FullName_save((char *)eap->arg, false); esc_name = vim_strsave_shellescape( -#ifdef UNIX - fullname != NULL ? fullname : + (fullname != NULL ? (char_u *)fullname : eap->arg), true, true); +#else + esc_name = vim_strsave_shellescape(eap->arg, true, true); #endif - eap->arg, true, true); - if (esc_name == NULL) { - goto theend; - } size_t buflen = STRLEN(tmp_orig) + STRLEN(esc_name) + STRLEN(tmp_new) + 16; buf = xmalloc(buflen); #ifdef UNIX + char_u dirbuf[MAXPATHL]; // Temporarily chdir to /tmp, to avoid patching files in the current // directory when the patch file contains more than one patch. When we // have our own temp dir use that instead, it will be cleaned up when we @@ -918,7 +914,7 @@ void ex_diffpatch(exarg_T *eap) // Use 'patchexpr' to generate the new file. #ifdef UNIX eval_patch((char *)tmp_orig, - (char *)(fullname != NULL ? fullname : eap->arg), + (fullname != NULL ? fullname : (char *)eap->arg), (char *)tmp_new); #else eval_patch((char *)tmp_orig, (char *)eap->arg, (char *)tmp_new); From 536d9a61687206318a629701aac984d55411bf35 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 9 Apr 2018 10:27:09 +0300 Subject: [PATCH 020/103] edit: Fix PVS/V560: remove always true/false checks --- src/nvim/edit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/edit.c b/src/nvim/edit.c index b772a944f4..f9c3e5f0d5 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -5256,7 +5256,7 @@ insertchar ( // - need to check for abbreviation: A non-word char after a word-char while ((c = vpeekc()) != NUL && !ISSPECIAL(c) - && (!has_mbyte || MB_BYTE2LEN_CHECK(c) == 1) + && MB_BYTE2LEN(c) == 1 && i < INPUT_BUFLEN && !(p_fkmap && KeyTyped) // Farsi mode mapping moves cursor && (textwidth == 0 From 07b67f9eff56ff741484109e4dcea42020c5f750 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 10 Apr 2018 01:01:16 +0300 Subject: [PATCH 021/103] eval: Fix PVS/V547: ufunc_T is actually an incomplete type --- src/nvim/eval.c | 11 ++++++----- src/nvim/eval/typval.h | 5 ++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 9a5b508cb4..2fe89dba67 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -5807,8 +5807,8 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate) lambda_no++; snprintf((char *)name, sizeof(name), "%d", lambda_no); - fp = (ufunc_T *)xcalloc(1, sizeof(ufunc_T) + STRLEN(name)); - pt = (partial_T *)xcalloc(1, sizeof(partial_T)); + fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); + pt = xcalloc(1, sizeof(partial_T)); ga_init(&newlines, (int)sizeof(char_u *), 1); ga_grow(&newlines, 1); @@ -20059,7 +20059,7 @@ void ex_function(exarg_T *eap) } } - fp = xcalloc(1, sizeof(ufunc_T) + STRLEN(name)); + fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); if (fudi.fd_dict != NULL) { if (fudi.fd_di == NULL) { @@ -20814,8 +20814,9 @@ char_u *get_user_func_name(expand_T *xp, int idx) return (char_u *)""; // don't show dict and lambda functions } - if (STRLEN(fp->uf_name) + 4 >= IOSIZE) - return fp->uf_name; /* prevents overflow */ + if (STRLEN(fp->uf_name) + 4 >= IOSIZE) { + return fp->uf_name; // Prevent overflow. + } cat_func_name(IObuff, fp); if (xp->xp_context != EXPAND_USER_FUNC) { diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 2272a580d6..60bc7ff375 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -286,9 +286,8 @@ struct ufunc { ///< used for s: variables int uf_refcount; ///< reference count, see func_name_refcount() funccall_T *uf_scoped; ///< l: local variables for closure - char_u uf_name[1]; ///< name of function (actually longer); can - ///< start with 123_ ( is K_SPECIAL - ///< KS_EXTRA KE_SNR) + char_u uf_name[]; ///< Name of function; can start with 123_ + ///< ( is K_SPECIAL KS_EXTRA KE_SNR) }; /// Maximum number of function arguments From 4d1b3bf317d4827a21d1e4b1aedfacc6e892555b Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 10 Apr 2018 01:25:00 +0300 Subject: [PATCH 022/103] eval: Fix PVS/V560: unneded check for name_len It is unsigned, zero length would already cause early return and length 1 is checked earlier in the same condition. --- src/nvim/eval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 2fe89dba67..4b2e95c624 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -18728,7 +18728,7 @@ static hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, if (name_len == 0) { return NULL; } - if (name_len == 1 || (name_len >= 2 && name[1] != ':')) { + if (name_len == 1 || name[1] != ':') { // name has implicit scope if (name[0] == ':' || name[0] == AUTOLOAD_CHAR) { // The name must not start with a colon or #. From 6f19b9f4e19d12aea23ac61c889aa122bc2576eb Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 10 Apr 2018 01:34:54 +0300 Subject: [PATCH 023/103] eval: Silence PVS/V614: use of potentially uninitialized pointer It is hard to say whether it actually is uninitialized, need to go deeper into regex code. Probably analyzer did not go that far as regmatch for sure would not be initialized up until calling NFA/DFA engine functions, which is to be done by pointer. --- src/nvim/eval.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 4b2e95c624..5281e227d6 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -15627,7 +15627,6 @@ f_spellsuggest_return: static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - regmatch_T regmatch; char_u *save_cpo; int match; colnr_T col = 0; @@ -15660,9 +15659,13 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - regmatch.regprog = vim_regcomp((char_u *)pat, RE_MAGIC + RE_STRING); + regmatch_T regmatch = { + .regprog = vim_regcomp((char_u *)pat, RE_MAGIC + RE_STRING), + .startp = { NULL }, + .endp = { NULL }, + .rm_ic = false, + }; if (regmatch.regprog != NULL) { - regmatch.rm_ic = FALSE; while (*str != NUL || keepempty) { if (*str == NUL) { match = false; // Empty item at the end. @@ -15681,8 +15684,9 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr) && end < (const char *)regmatch.endp[0])) { tv_list_append_string(rettv->vval.v_list, str, end - str); } - if (!match) + if (!match) { break; + } // Advance to just after the match. if (regmatch.endp[0] > (char_u *)str) { col = 0; From f8d574225b61fc4bc0fd52990deda4825f62dc8f Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 18:45:12 +0300 Subject: [PATCH 024/103] eval: Silence PVS/V547: E882 may be triggered MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I failed to deduce why analyzer thinks E882 may not be triggered, though conditions for triggering it are strange: it would trigger E882 only in the single case “function returned non-number”. Cases “function thrown exception”, or “built-in sorter encountered error” will neither yield E882 nor stop sort()/uniq(). Note though that searching test code revealed that neither E702 nor E882 are not tested anywhere. --- src/nvim/eval.c | 2 +- test/functional/eval/sort_spec.lua | 15 +++++++++++++ test/functional/eval/uniq_spec.lua | 34 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 test/functional/eval/uniq_spec.lua diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5281e227d6..437a9dacf6 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -15453,7 +15453,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) ; li != NULL;) { listitem_T *const prev_li = TV_LIST_ITEM_PREV(l, li); if (item_compare_func_ptr(&prev_li, &li) == 0) { - if (info.item_compare_func_err) { + if (info.item_compare_func_err) { // -V547 EMSG(_("E882: Uniq compare function failed")); break; } diff --git a/test/functional/eval/sort_spec.lua b/test/functional/eval/sort_spec.lua index 4e5a0afba4..82557575ce 100644 --- a/test/functional/eval/sort_spec.lua +++ b/test/functional/eval/sort_spec.lua @@ -8,6 +8,7 @@ local meths = helpers.meths local funcs = helpers.funcs local command = helpers.command local exc_exec = helpers.exc_exec +local redir_exec = helpers.redir_exec before_each(clear) @@ -38,4 +39,18 @@ describe('sort()', function() eq('[-1.0e-4, function(\'tr\'), v:true, v:false, v:null, [], {\'a\': 42}, \'check\', 1.0e-4]', eval('string(g:list)')) end) + + it('can yield E702 and stop sorting after that', function() + command([[ + function Cmp(a, b) + if type(a:a) == type([]) || type(a:b) == type([]) + return [] + endif + return (a:a > a:b) - (a:a < a:b) + endfunction + ]]) + eq('\nE745: Using a List as a Number\nE702: Sort compare function failed', + redir_exec('let sl = sort([1, 0, [], 3, 2], "Cmp")')) + eq({1, 0, {}, 3, 2}, meths.get_var('sl')) + end) end) diff --git a/test/functional/eval/uniq_spec.lua b/test/functional/eval/uniq_spec.lua new file mode 100644 index 0000000000..5217034d81 --- /dev/null +++ b/test/functional/eval/uniq_spec.lua @@ -0,0 +1,34 @@ +local helpers = require('test.functional.helpers')(after_each) + +local eq = helpers.eq +local NIL = helpers.NIL +local eval = helpers.eval +local clear = helpers.clear +local meths = helpers.meths +local funcs = helpers.funcs +local command = helpers.command +local exc_exec = helpers.exc_exec +local redir_exec = helpers.redir_exec + +before_each(clear) + +describe('uniq()', function() + it('errors out when processing special values', function() + eq('Vim(call):E907: Using a special value as a Float', + exc_exec('call uniq([v:true, v:false], "f")')) + end) + + it('can yield E882 and stop filtering after that', function() + command([[ + function Cmp(a, b) + if type(a:a) == type([]) || type(a:b) == type([]) + return [] + endif + return (a:a > a:b) - (a:a < a:b) + endfunction + ]]) + eq('\nE745: Using a List as a Number\nE882: Uniq compare function failed', + redir_exec('let fl = uniq([0, 0, [], 1, 1], "Cmp")')) + eq({0, {}, 1, 1}, meths.get_var('fl')) + end) +end) From 1df9ac1c03f56e98f63ae320f4e48360e8ee0b26 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 18:50:02 +0300 Subject: [PATCH 025/103] eval: Fix PVS/V547: skipping is now done using eval0 --- src/nvim/eval.c | 53 ++++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 437a9dacf6..036caf6e6a 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -2684,17 +2684,19 @@ void ex_call(exarg_T *eap) tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi, &partial); if (fudi.fd_newkey != NULL) { - /* Still need to give an error message for missing key. */ + // Still need to give an error message for missing key. EMSG2(_(e_dictkey), fudi.fd_newkey); xfree(fudi.fd_newkey); } - if (tofree == NULL) + if (tofree == NULL) { return; + } - /* Increase refcount on dictionary, it could get deleted when evaluating - * the arguments. */ - if (fudi.fd_dict != NULL) - ++fudi.fd_dict->dv_refcount; + // Increase refcount on dictionary, it could get deleted when evaluating + // the arguments. + if (fudi.fd_dict != NULL) { + fudi.fd_dict->dv_refcount++; + } // If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its // contents. For VAR_PARTIAL get its partial, unless we already have one @@ -2703,8 +2705,8 @@ void ex_call(exarg_T *eap) name = deref_func_name((const char *)tofree, &len, partial != NULL ? NULL : &partial, false); - /* Skip white space to allow ":call func ()". Not good, but required for - * backward compatibility. */ + // Skip white space to allow ":call func ()". Not good, but required for + // backward compatibility. startarg = skipwhite(arg); rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this. @@ -2713,20 +2715,9 @@ void ex_call(exarg_T *eap) goto end; } - /* - * When skipping, evaluate the function once, to find the end of the - * arguments. - * When the function takes a range, this is discovered after the first - * call, and the loop is broken. - */ - if (eap->skip) { - emsg_skip++; - lnum = eap->line2; // Do it once, also with an invalid range. - } else { - lnum = eap->line1; - } + lnum = eap->line1; for (; lnum <= eap->line2; lnum++) { - if (!eap->skip && eap->addr_count > 0) { // -V560 + if (eap->addr_count > 0) { // -V560 curwin->w_cursor.lnum = lnum; curwin->w_cursor.col = 0; curwin->w_cursor.coladd = 0; @@ -2747,27 +2738,27 @@ void ex_call(exarg_T *eap) } tv_clear(&rettv); - if (doesrange || eap->skip) { // -V560 + if (doesrange) { break; } - /* Stop when immediately aborting on error, or when an interrupt - * occurred or an exception was thrown but not caught. - * get_func_tv() returned OK, so that the check for trailing - * characters below is executed. */ - if (aborting()) + // Stop when immediately aborting on error, or when an interrupt + // occurred or an exception was thrown but not caught. + // get_func_tv() returned OK, so that the check for trailing + // characters below is executed. + if (aborting()) { break; + } } - if (eap->skip) - --emsg_skip; if (!failed) { - /* Check for trailing illegal characters and a following command. */ + // Check for trailing illegal characters and a following command. if (!ends_excmd(*arg)) { emsg_severe = TRUE; EMSG(_(e_trailing)); - } else + } else { eap->nextcmd = check_nextcmd(arg); + } } end: From db7f80302be99b895495e8b7d5e07c309e3dcfe3 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 18:52:37 +0300 Subject: [PATCH 026/103] ex_cmds: Remove #ifdef USE_GUI `ag` shows that this identifier (`USE_GUI`) is found in exactly one place (zero after this commit). So I assume macros is never defined. --- src/nvim/ex_cmds.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index c396b5891a..bb00675915 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -169,12 +169,9 @@ void do_ascii(exarg_T *eap) if (len > 0) IObuff[len++] = ' '; IObuff[len++] = '<'; - if (l_enc_utf8 && utf_iscomposing(c) -# ifdef USE_GUI - && !gui.in_use -# endif - ) - IObuff[len++] = ' '; /* draw composing char on top of a space */ + if (l_enc_utf8 && utf_iscomposing(c)) { + IObuff[len++] = ' '; // Draw composing char on top of a space. + } len += (*mb_char2bytes)(c, IObuff + len); vim_snprintf((char *)IObuff + len, IOSIZE - len, c < 0x10000 ? _("> %d, Hex %04x, Octal %o") From aa5008c1f073ac3a0efce5f1bfa4a431dd2e6b46 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 19:01:58 +0300 Subject: [PATCH 027/103] ex_cmds: Simplify do_ascii Specifically apply constants like enc_utf8 (which are constants *now*) and simplify conditions after that. Also some style changes. --- src/nvim/ex_cmds.c | 86 ++++++++++++++++++---------------------------- 1 file changed, 34 insertions(+), 52 deletions(-) diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index bb00675915..aaa4e808ca 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -109,79 +109,61 @@ typedef struct { # include "ex_cmds.c.generated.h" #endif -/* - * ":ascii" and "ga". - */ -void do_ascii(exarg_T *eap) +/// ":ascii" and "ga" implementation +void do_ascii(const exarg_T *const eap) { - int c; - int cval; - char buf1[20]; - char buf2[20]; - char_u buf3[7]; int cc[MAX_MCO]; - int ci = 0; - int len; - const bool l_enc_utf8 = enc_utf8; - - if (l_enc_utf8) - c = utfc_ptr2char(get_cursor_pos_ptr(), cc); - else - c = gchar_cursor(); + int c = utfc_ptr2char(get_cursor_pos_ptr(), cc); if (c == NUL) { MSG("NUL"); return; } IObuff[0] = NUL; - if (!has_mbyte || (enc_dbcs != 0 && c < 0x100) || c < 0x80) { - if (c == NL) /* NUL is stored as NL */ + + int ci = 0; + if (c < 0x80) { + if (c == NL) { // NUL is stored as NL. c = NUL; - if (c == CAR && get_fileformat(curbuf) == EOL_MAC) - cval = NL; /* NL is stored as CR */ - else - cval = c; - if (vim_isprintc_strict(c) && (c < ' ' - || c > '~' - )) { + } + const int cval = (c == CAR && get_fileformat(curbuf) == EOL_MAC + ? NL // NL is stored as CR. + : c); + char buf1[20]; + if (vim_isprintc_strict(c) && (c < ' ' || c > '~')) { + char_u buf3[7]; transchar_nonprint(buf3, c); vim_snprintf(buf1, sizeof(buf1), " <%s>", (char *)buf3); - } else + } else { buf1[0] = NUL; - if (c >= 0x80) - vim_snprintf(buf2, sizeof(buf2), " ", - (char *)transchar(c & 0x7f)); - else - buf2[0] = NUL; + } + char buf2[20]; + buf2[0] = NUL; vim_snprintf((char *)IObuff, IOSIZE, - _("<%s>%s%s %d, Hex %02x, Octal %03o"), - transchar(c), buf1, buf2, cval, cval, cval); - if (l_enc_utf8) - c = cc[ci++]; - else - c = 0; + _("<%s>%s%s %d, Hex %02x, Octal %03o"), + transchar(c), buf1, buf2, cval, cval, cval); + c = cc[ci++]; } - /* Repeat for combining characters. */ - while (has_mbyte && (c >= 0x100 || (l_enc_utf8 && c >= 0x80))) { - len = (int)STRLEN(IObuff); - /* This assumes every multi-byte char is printable... */ - if (len > 0) + // Repeat for combining characters. + while (c >= 0x80) { + int len = (int)STRLEN(IObuff); + // This assumes every multi-byte char is printable... + if (len > 0) { IObuff[len++] = ' '; + } IObuff[len++] = '<'; - if (l_enc_utf8 && utf_iscomposing(c)) { + if (utf_iscomposing(c)) { IObuff[len++] = ' '; // Draw composing char on top of a space. } - len += (*mb_char2bytes)(c, IObuff + len); + len += utf_char2bytes(c, IObuff + len); vim_snprintf((char *)IObuff + len, IOSIZE - len, - c < 0x10000 ? _("> %d, Hex %04x, Octal %o") - : _("> %d, Hex %08x, Octal %o"), c, c, c); - if (ci == MAX_MCO) + c < 0x10000 ? _("> %d, Hex %04x, Octal %o") + : _("> %d, Hex %08x, Octal %o"), c, c, c); + if (ci == MAX_MCO) { break; - if (l_enc_utf8) - c = cc[ci++]; - else - c = 0; + } + c = cc[ci++]; } msg(IObuff); From 103be37f423ee2ec143c88b94c3a2a33d98b8a68 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 19:31:02 +0300 Subject: [PATCH 028/103] ex_cmds: Fix PVS/V557: possible array overrun in :ascii Some calculation show that with the current setup there will not be enough bytes occupied for that, barring the case of malicious translation. Still should be possible to have array overrun with specially crafted translation. --- src/nvim/ex_cmds.c | 55 +++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index aaa4e808ca..44880cb1c5 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -119,7 +119,7 @@ void do_ascii(const exarg_T *const eap) return; } - IObuff[0] = NUL; + size_t iobuff_len = 0; int ci = 0; if (c < 0x80) { @@ -139,32 +139,57 @@ void do_ascii(const exarg_T *const eap) } char buf2[20]; buf2[0] = NUL; - vim_snprintf((char *)IObuff, IOSIZE, - _("<%s>%s%s %d, Hex %02x, Octal %03o"), - transchar(c), buf1, buf2, cval, cval, cval); + iobuff_len += ( + vim_snprintf((char *)IObuff + iobuff_len, sizeof(IObuff) - iobuff_len, + _("<%s>%s%s %d, Hex %02x, Octal %03o"), + transchar(c), buf1, buf2, cval, cval, cval)); c = cc[ci++]; } - // Repeat for combining characters. - while (c >= 0x80) { - int len = (int)STRLEN(IObuff); +#define SPACE_FOR_DESC (1 + 1 + 1 + MB_MAXBYTES + 16 + 4 + 3 + 3 + 1) + // Space for description: + // - 1 byte for separator (starting from second entry) + // - 1 byte for "<" + // - 1 byte for space to draw composing character on (optional, but really + // mostly required) + // - up to MB_MAXBYTES bytes for character itself + // - 16 bytes for raw text ("> , Hex , Octal "). + // - at least 4 bytes for hexadecimal representation + // - at least 3 bytes for decimal representation + // - at least 3 bytes for octal representation + // - 1 byte for NUL + // + // Taking into account MAX_MCO and characters which need 8 bytes for + // hexadecimal representation, but not taking translation into account: + // resulting string will occupy less then 400 bytes (conservative estimate). + // + // Less then 1000 bytes if translation multiplies number of bytes needed for + // raw text by 6, so it should always fit into 1025 bytes reserved for IObuff. + + // Repeat for combining characters, also handle multiby here. + while (c >= 0x80 && iobuff_len < sizeof(IObuff) - SPACE_FOR_DESC) { // This assumes every multi-byte char is printable... - if (len > 0) { - IObuff[len++] = ' '; + if (iobuff_len > 0) { + IObuff[iobuff_len++] = ' '; } - IObuff[len++] = '<'; + IObuff[iobuff_len++] = '<'; if (utf_iscomposing(c)) { - IObuff[len++] = ' '; // Draw composing char on top of a space. + IObuff[iobuff_len++] = ' '; // Draw composing char on top of a space. } - len += utf_char2bytes(c, IObuff + len); - vim_snprintf((char *)IObuff + len, IOSIZE - len, - c < 0x10000 ? _("> %d, Hex %04x, Octal %o") - : _("> %d, Hex %08x, Octal %o"), c, c, c); + iobuff_len += utf_char2bytes(c, IObuff + iobuff_len); + iobuff_len += ( + vim_snprintf((char *)IObuff + iobuff_len, sizeof(IObuff) - iobuff_len, + (c < 0x10000 + ? _("> %d, Hex %04x, Octal %o") + : _("> %d, Hex %08x, Octal %o")), c, c, c)); if (ci == MAX_MCO) { break; } c = cc[ci++]; } + if (ci != MAX_MCO && c != 0) { + xstrlcpy((char *)IObuff + iobuff_len, " ...", sizeof(IObuff) - iobuff_len); + } msg(IObuff); } From d7e4449adbd483512580a2a9e823190b61f2aa53 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 19:33:50 +0300 Subject: [PATCH 029/103] ex_docmd: Fix PVS/V547: due to short-circuiting name_len is never > 4 --- src/nvim/ex_docmd.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 4b37abab9e..f39c996902 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5181,11 +5181,13 @@ static void ex_command(exarg_T *eap) p = skipwhite(end); } - /* Get the name (if any) and skip to the following argument */ + // Get the name (if any) and skip to the following argument. name = p; - if (ASCII_ISALPHA(*p)) - while (ASCII_ISALNUM(*p)) - ++p; + if (ASCII_ISALPHA(*p)) { + while (ASCII_ISALNUM(*p)) { + p++; + } + } if (!ends_excmd(*p) && !ascii_iswhite(*p)) { EMSG(_("E182: Invalid command name")); return; @@ -5203,8 +5205,7 @@ static void ex_command(exarg_T *eap) EMSG(_("E183: User defined commands must start with an uppercase letter")); return; } else if ((name_len == 1 && *name == 'X') - || (name_len <= 4 - && STRNCMP(name, "Next", name_len > 4 ? 4 : name_len) == 0)) { + || (name_len <= 4 && STRNCMP(name, "Next", name_len) == 0)) { EMSG(_("E841: Reserved name, cannot be used for user defined command")); return; } else From cad616c94ecf94a2abd959e3c09886c00c5afb3f Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 19:36:03 +0300 Subject: [PATCH 030/103] ex_docmd: Fix PVS/V547: condition was already checked in surr. if() --- src/nvim/ex_docmd.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index f39c996902..33e2805538 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5669,22 +5669,21 @@ static void do_ucmd(exarg_T *eap) if (start != NULL) end = vim_strchr(start + 1, '>'); if (buf != NULL) { - for (ksp = p; *ksp != NUL && *ksp != K_SPECIAL; ++ksp) - ; + for (ksp = p; *ksp != NUL && *ksp != K_SPECIAL; ksp++) { + } if (*ksp == K_SPECIAL && (start == NULL || ksp < start || end == NULL) - && ((ksp[1] == KS_SPECIAL && ksp[2] == KE_FILLER) - )) { - /* K_SPECIAL has been put in the buffer as K_SPECIAL - * KS_SPECIAL KE_FILLER, like for mappings, but - * do_cmdline() doesn't handle that, so convert it back. - * Also change K_SPECIAL KS_EXTRA KE_CSI into CSI. */ + && (ksp[1] == KS_SPECIAL && ksp[2] == KE_FILLER)) { + // K_SPECIAL has been put in the buffer as K_SPECIAL + // KS_SPECIAL KE_FILLER, like for mappings, but + // do_cmdline() doesn't handle that, so convert it back. + // Also change K_SPECIAL KS_EXTRA KE_CSI into CSI. len = ksp - p; if (len > 0) { memmove(q, p, len); q += len; } - *q++ = ksp[1] == KS_SPECIAL ? K_SPECIAL : CSI; + *q++ = K_SPECIAL; p = ksp + 3; continue; } From c90e9df5b572578a64120f95f08288e30079b861 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 19:38:22 +0300 Subject: [PATCH 031/103] ex_getln: Fix PVS/V560: there are no longer NULL returns for OOM --- src/nvim/ex_getln.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 698419405a..35454ba316 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -4856,23 +4856,27 @@ void ExpandGeneric( // copy the matching names into allocated memory count = 0; - for (i = 0;; ++i) { + for (i = 0;; i++) { str = (*func)(xp, i); - if (str == NULL) // end of list + if (str == NULL) { // end of list break; - if (*str == NUL) // skip empty strings + } + if (*str == NUL) { // skip empty strings continue; + } if (vim_regexec(regmatch, str, (colnr_T)0)) { - if (escaped) + if (escaped) { str = vim_strsave_escaped(str, (char_u *)" \t\\."); - else + } else { str = vim_strsave(str); + } (*file)[count++] = str; - if (func == get_menu_names && str != NULL) { - /* test for separator added by get_menu_names() */ + if (func == get_menu_names) { + // Test for separator added by get_menu_names(). str += STRLEN(str) - 1; - if (*str == '\001') + if (*str == '\001') { *str = '.'; + } } } } From 469ba2fb49690a0f094216fac2a832911cd995a0 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 19:41:38 +0300 Subject: [PATCH 032/103] ex_getln: Fix PVS/V547: function is stated to never return NULL --- src/nvim/ex_getln.c | 53 ++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 35454ba316..a7efe5f533 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -3590,40 +3590,33 @@ nextwild ( xp->xp_pattern_len = ccline.cmdpos - i; if (type == WILD_NEXT || type == WILD_PREV) { - /* - * Get next/previous match for a previous expanded pattern. - */ + // Get next/previous match for a previous expanded pattern. p2 = ExpandOne(xp, NULL, NULL, 0, type); } else { - /* - * Translate string into pattern and expand it. - */ - if ((p1 = addstar(xp->xp_pattern, xp->xp_pattern_len, - xp->xp_context)) == NULL) - p2 = NULL; - else { - int use_options = options | - WILD_HOME_REPLACE|WILD_ADD_SLASH|WILD_SILENT; - if (escape) - use_options |= WILD_ESCAPE; - - if (p_wic) - use_options += WILD_ICASE; - p2 = ExpandOne(xp, p1, - vim_strnsave(&ccline.cmdbuff[i], xp->xp_pattern_len), - use_options, type); - xfree(p1); - /* longest match: make sure it is not shorter, happens with :help */ - if (p2 != NULL && type == WILD_LONGEST) { - for (j = 0; j < xp->xp_pattern_len; ++j) - if (ccline.cmdbuff[i + j] == '*' - || ccline.cmdbuff[i + j] == '?') - break; - if ((int)STRLEN(p2) < j) { - xfree(p2); - p2 = NULL; + // Translate string into pattern and expand it. + p1 = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); + const int use_options = ( + options + | WILD_HOME_REPLACE + | WILD_ADD_SLASH + | WILD_SILENT + | (escape ? WILD_ESCAPE : 0) + | (p_wic ? WILD_ICASE : 0)); + p2 = ExpandOne(xp, p1, vim_strnsave(&ccline.cmdbuff[i], xp->xp_pattern_len), + use_options, type); + xfree(p1); + // Longest match: make sure it is not shorter, happens with :help. + if (p2 != NULL && type == WILD_LONGEST) { + for (j = 0; j < xp->xp_pattern_len; j++) { + if (ccline.cmdbuff[i + j] == '*' + || ccline.cmdbuff[i + j] == '?') { + break; } } + if ((int)STRLEN(p2) < j) { + xfree(p2); + p2 = NULL; + } } } From 092b4d9774c630c4e3805a3d2b6257ed5dbfc7ff Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 19:59:15 +0300 Subject: [PATCH 033/103] *: Add some PVS comments --- config/pathdef.c.in | 2 ++ src/nvim/generators/gen_api_dispatch.lua | 2 ++ 2 files changed, 4 insertions(+) diff --git a/config/pathdef.c.in b/config/pathdef.c.in index 4579fbe455..41950f5ac5 100644 --- a/config/pathdef.c.in +++ b/config/pathdef.c.in @@ -1,3 +1,5 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include "${PROJECT_SOURCE_DIR}/src/nvim/vim.h" char *default_vim_dir = "${CMAKE_INSTALL_FULL_DATAROOTDIR}/nvim"; char *default_vimruntime_dir = ""; diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index b01321e713..2ee1e5d4c5 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -324,6 +324,8 @@ end output = io.open(lua_c_bindings_outputf, 'wb') output:write([[ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include #include #include From 17e21eae24ff001eae0a74e252acab5992adb5dc Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 20:05:17 +0300 Subject: [PATCH 034/103] eval: Silence PVS/V547: PVS cannot stand `!known_val` expressions --- src/nvim/eval.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 036caf6e6a..e38f7e7dda 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -2682,7 +2682,7 @@ void ex_call(exarg_T *eap) return; } - tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi, &partial); + tofree = trans_function_name(&arg, false, TFN_INT, &fudi, &partial); if (fudi.fd_newkey != NULL) { // Still need to give an error message for missing key. EMSG2(_(e_dictkey), fudi.fd_newkey); @@ -2725,13 +2725,13 @@ void ex_call(exarg_T *eap) arg = startarg; if (get_func_tv(name, (int)STRLEN(name), &rettv, &arg, eap->line1, eap->line2, &doesrange, - !eap->skip, partial, fudi.fd_dict) == FAIL) { + true, partial, fudi.fd_dict) == FAIL) { failed = true; break; } // Handle a function returning a Funcref, Dictionary or List. - if (handle_subscript((const char **)&arg, &rettv, !eap->skip, true) + if (handle_subscript((const char **)&arg, &rettv, true, true) == FAIL) { failed = true; break; From 6196738a3bb3b6a739f23091338ae0c0934b28ae Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 20:08:32 +0300 Subject: [PATCH 035/103] ex_cmds: Fix PVS/V547: expression was already checked in outer if() --- src/nvim/ex_cmds.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 44880cb1c5..f3b1aa633d 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -2022,13 +2022,13 @@ int getfile(int fnum, char_u *ffname, char_u *sfname, int setpm, linenr_T lnum, } if (other && !forceit && curbuf->b_nwindows == 1 && !buf_hide(curbuf) && curbufIsChanged() && autowrite(curbuf, forceit) == FAIL) { - if (p_confirm && p_write) - dialog_changed(curbuf, FALSE); + if (p_confirm && p_write) { + dialog_changed(curbuf, false); + } if (curbufIsChanged()) { - if (other) - --no_wait_return; + no_wait_return--; EMSG(_(e_nowrtmsg)); - retval = 2; /* file has been changed */ + retval = 2; // File has been changed. goto theend; } } From bc235bf1f64cbed83c061ff77d09a562b6c71218 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 20:10:48 +0300 Subject: [PATCH 036/103] viml/parser/expressions: Fix PVS/V547: condition checked earlier See previous goto with the same label. --- src/nvim/viml/parser/expressions.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c index 4196ecb9d2..a72ec24535 100644 --- a/src/nvim/viml/parser/expressions.c +++ b/src/nvim/viml/parser/expressions.c @@ -2534,11 +2534,6 @@ viml_pexpr_parse_bracket_closing_error: cur_token, _("E15: Expected value, got closing figure brace: %.*s")); } - } else { - if (!kv_size(ast_stack)) { - new_top_node_p = top_node_p; - goto viml_pexpr_parse_figure_brace_closing_error; - } } do { new_top_node_p = kv_pop(ast_stack); From a20261fae7a2118eaeef394877777cca4aa4d6db Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 20:11:21 +0300 Subject: [PATCH 037/103] viml/parser/expressions: Fix PVS/V547: condition checked earlier See previous goto with the same label. --- src/nvim/viml/parser/expressions.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c index a72ec24535..90fee146ab 100644 --- a/src/nvim/viml/parser/expressions.c +++ b/src/nvim/viml/parser/expressions.c @@ -2415,11 +2415,6 @@ viml_pexpr_parse_valid_colon: cur_token, _("E15: Expected value, got closing bracket: %.*s")); } - } else { - if (!kv_size(ast_stack)) { - new_top_node_p = top_node_p; - goto viml_pexpr_parse_bracket_closing_error; - } } do { new_top_node_p = kv_pop(ast_stack); From d084628c4b0cf8644424f40ea578a1e705c771df Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 20:14:55 +0300 Subject: [PATCH 038/103] kvec: Silence PVS/V512: it is not needed to fill the whole array --- src/nvim/lib/kvec.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nvim/lib/kvec.h b/src/nvim/lib/kvec.h index ad56c9237b..6d54c7f78d 100644 --- a/src/nvim/lib/kvec.h +++ b/src/nvim/lib/kvec.h @@ -142,6 +142,8 @@ static inline void *_memcpy_free(void *const restrict dest, return dest; } +// -V:kvi_push:512 + /// Resize vector with preallocated array /// /// @note May not resize to an array smaller then init_array: if requested, From 11f64117718d2a5c94772764eb59dce4f54b2eeb Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 20:18:20 +0300 Subject: [PATCH 039/103] file_search: Silence PVS/V614: used buffer is never uninitialized --- src/nvim/file_search.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index 3272ce81bc..5b17b58781 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -1541,21 +1541,25 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope) char buf[8]; switch (scope) { - case kCdScopeGlobal: - snprintf(buf, sizeof(buf), "global"); - break; - case kCdScopeTab: - snprintf(buf, sizeof(buf), "tab"); - break; - case kCdScopeWindow: - snprintf(buf, sizeof(buf), "window"); - break; - case kCdScopeInvalid: - // Should never happen. - assert(false); + case kCdScopeGlobal: { + snprintf(buf, sizeof(buf), "global"); + break; + } + case kCdScopeTab: { + snprintf(buf, sizeof(buf), "tab"); + break; + } + case kCdScopeWindow: { + snprintf(buf, sizeof(buf), "window"); + break; + } + case kCdScopeInvalid: { + // Should never happen. + assert(false); + } } - tv_dict_add_str(dict, S_LEN("scope"), buf); + tv_dict_add_str(dict, S_LEN("scope"), buf); // -V614 tv_dict_add_str(dict, S_LEN("cwd"), new_dir); tv_dict_set_keys_readonly(dict); From 1fb4282f1cc9586c687144ce155bc0535484ff25 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 20:27:41 +0300 Subject: [PATCH 040/103] fileio: Fix PVS/V560: end was already checked See condition at line 3309. --- src/nvim/fileio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 52686f6651..31f970ef7a 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3332,9 +3332,9 @@ restore_backup: *s++ = NL; } } - if (++len == bufsize && end) { + if (++len == bufsize) { if (buf_write_bytes(&write_info) == FAIL) { - end = 0; /* write error: break loop */ + end = 0; // Write error: break loop. break; } nchars += bufsize; @@ -3343,7 +3343,7 @@ restore_backup: os_breakcheck(); if (got_int) { - end = 0; /* Interrupted, break loop */ + end = 0; // Interrupted, break loop. break; } } From cd271985267e06eab8d69abe6dd4ec25d99d0392 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 20:30:31 +0300 Subject: [PATCH 041/103] fileio: Fix PVS/V547: split is not used This is removed functionality, specifically no longer supported 16-bit integers. --- src/nvim/fileio.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 31f970ef7a..c67beeb989 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -287,7 +287,6 @@ readfile ( int skip_read = false; context_sha256_T sha_ctx; int read_undo_file = FALSE; - int split = 0; /* number of split lines */ linenr_T linecnt; int error = FALSE; /* errors encountered */ int ff_error = EOL_UNKNOWN; /* file format with errors */ @@ -1822,10 +1821,6 @@ failed: STRCAT(IObuff, _("[CR missing]")); c = TRUE; } - if (split) { - STRCAT(IObuff, _("[long lines split]")); - c = TRUE; - } if (notconverted) { STRCAT(IObuff, _("[NOT converted]")); c = TRUE; From 31898419849f9389cb47d7a26dda600fc8951eb9 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 20:32:21 +0300 Subject: [PATCH 042/103] fileio: Silence PVS/V614: buffer is initialized if conv_restlen > 0 --- src/nvim/fileio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index c67beeb989..451f924c28 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -1016,8 +1016,8 @@ retry: size = size / ICONV_MULT; /* worst case */ if (conv_restlen > 0) { - /* Insert unconverted bytes from previous line. */ - memmove(ptr, conv_rest, conv_restlen); + // Insert unconverted bytes from previous line. + memmove(ptr, conv_rest, conv_restlen); // -V614 ptr += conv_restlen; size -= conv_restlen; } From b8f69b6b9a1b5339ba580e58725b8866339c1ad7 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 20:34:27 +0300 Subject: [PATCH 043/103] os/fs: Fix PVS/V560: condition was already checked in while() It is not possible to enter while loop body with unsigned2 == 0 if loop condition requires unsigned1 < unsigned2. --- src/nvim/os/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index b7c2714296..924b3d2359 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -512,7 +512,7 @@ ptrdiff_t os_readv(int fd, bool *ret_eof, struct iovec *iov, size_t iov_size) } while (read_bytes < toread && iov_size && !*ret_eof) { ptrdiff_t cur_read_bytes = readv(fd, iov, (int)iov_size); - if (toread && cur_read_bytes == 0) { + if (cur_read_bytes == 0) { *ret_eof = true; } if (cur_read_bytes > 0) { From 24ee2613174250f9d32492c435c42daef3a44b21 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 20:36:21 +0300 Subject: [PATCH 044/103] if_cscope: Fix PVS/V560: condition would result in earlier return Previous block just checks for totmatches being zero and returns if it is. And totmatches is unsigned, so `totmatches > 0` may never be true. --- src/nvim/if_cscope.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index b78b56562c..5d7bd26a2b 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -1001,8 +1001,8 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, return FALSE; } - if (qfpos != NULL && *qfpos != '0' && totmatches > 0) { - /* fill error list */ + if (qfpos != NULL && *qfpos != '0') { + // Fill error list. FILE *f; char_u *tmp = vim_tempname(); qf_info_T *qi = NULL; From a2f91884187de00d5b96065587d3d927409af5bc Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 20:53:29 +0300 Subject: [PATCH 045/103] mbyte: Fix PVS/V557: do not do useless job I do not see how array overrun is actually possible, but still EUC encodings may do fine without a cycle. --- src/nvim/mbyte.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 446063e33b..a52ab9f5d3 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -1979,37 +1979,39 @@ char_u * enc_locale(void) return NULL; } - /* The most generic locale format is: - * language[_territory][.codeset][@modifier][+special][,[sponsor][_revision]] - * If there is a '.' remove the part before it. - * if there is something after the codeset, remove it. - * Make the name lowercase and replace '_' with '-'. - * Exception: "ja_JP.EUC" == "euc-jp", "zh_CN.EUC" = "euc-cn", - * "ko_KR.EUC" == "euc-kr" - */ + // The most generic locale format is: + // language[_territory][.codeset][@modifier][+special][,[sponsor][_revision]] + // If there is a '.' remove the part before it. + // if there is something after the codeset, remove it. + // Make the name lowercase and replace '_' with '-'. + // Exception: "ja_JP.EUC" == "euc-jp", "zh_CN.EUC" = "euc-cn", + // "ko_KR.EUC" == "euc-kr" const char *p = (char *)vim_strchr((char_u *)s, '.'); if (p != NULL) { if (p > s + 2 && !STRNICMP(p + 1, "EUC", 3) && !isalnum((int)p[4]) && p[4] != '-' && p[-3] == '_') { - /* copy "XY.EUC" to "euc-XY" to buf[10] */ - strcpy(buf + 10, "euc-"); - buf[14] = p[-2]; - buf[15] = p[-1]; - buf[16] = 0; - s = buf + 10; - } else - s = p + 1; - } - for (i = 0; i < (int)sizeof(buf) - 1 && s[i] != NUL; i++) { - if (s[i] == '_' || s[i] == '-') { - buf[i] = '-'; - } else if (isalnum((int)s[i])) { - buf[i] = TOLOWER_ASC(s[i]); + // Copy "XY.EUC" to "euc-XY" to buf[10]. + memmove(buf, "euc-", 4); + buf[4] = (ASCII_ISALNUM(p[-2]) ? TOLOWER_ASC(p[-2]) : 0); + buf[5] = (ASCII_ISALNUM(p[-1]) ? TOLOWER_ASC(p[-1]) : 0); + buf[6] = NUL; } else { - break; + s = p + 1; + goto enc_locale_copy_enc; } + } else { +enc_locale_copy_enc: + for (i = 0; i < (int)sizeof(buf) - 1 && s[i] != NUL; i++) { + if (s[i] == '_' || s[i] == '-') { + buf[i] = '-'; + } else if (ASCII_ISALNUM((uint8_t)s[i])) { + buf[i] = TOLOWER_ASC(s[i]); + } else { + break; + } + } + buf[i] = NUL; } - buf[i] = NUL; return enc_canonize((char_u *)buf); } From 2940af83214cad4c7e808eaba32758c7980af1c2 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 20:55:26 +0300 Subject: [PATCH 046/103] memline: Fix PVS/V560: allocator now never returns NULL --- src/nvim/memline.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/nvim/memline.c b/src/nvim/memline.c index c11ca74f5c..ef02bc959b 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1297,18 +1297,14 @@ recover_names ( msg_putchar('\n'); } - /* - * Do the loop for every directory in 'directory'. - * First allocate some memory to put the directory name in. - */ + // Do the loop for every directory in 'directory'. + // First allocate some memory to put the directory name in. dir_name = xmalloc(STRLEN(p_dir) + 1); dirp = p_dir; - while (dir_name != NULL && *dirp) { - /* - * Isolate a directory name from *dirp and put it in dir_name (we know - * it is large enough, so use 31000 for length). - * Advance dirp to next directory name. - */ + while (*dirp) { + // Isolate a directory name from *dirp and put it in dir_name (we know + // it is large enough, so use 31000 for length). + // Advance dirp to next directory name. (void)copy_option_part(&dirp, dir_name, 31000, ","); if (dir_name[0] == '.' && dir_name[1] == NUL) { /* check current dir */ From cb3230776e75ce6adf0ce34f6da4b139e22318a2 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 20:56:42 +0300 Subject: [PATCH 047/103] memline: Fix PVS/V547: allocator now never returns NULL --- src/nvim/memline.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/nvim/memline.c b/src/nvim/memline.c index ef02bc959b..d4708f61ff 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -843,8 +843,7 @@ void ml_recover(void) mfp = mf_open(fname_used, O_RDONLY); fname_used = p; if (mfp == NULL || mfp->mf_fd < 0) { - if (fname_used != NULL) - EMSG2(_("E306: Cannot open %s"), fname_used); + EMSG2(_("E306: Cannot open %s"), fname_used); goto theend; } buf->b_ml.ml_mfp = mfp; From 3b32e717d91934f2906c99269949efa9d88e82c8 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 21:32:26 +0300 Subject: [PATCH 048/103] message: Fix PVS/V547: c is never equal to KS_ZERO Since `c` there is a result of evaluating `TO_SPECIAL` macros it may be only one of the following three things: 1. K_SPECIAL 2. K_ZERO (note: not KS_ZERO) 3. negative integer resulting from evaluating TERMCAP2KEY macro. All variants here are negative and thus fail next !IS_SPECIAL(c) check (negative is special). If `c` was really NUL it would fall into the `!IS_SPECIAL(c)` block and use whatever character is third in `<80>{a}{b}` combo. For `` it is X (`<80>X`). --- src/nvim/message.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/nvim/message.c b/src/nvim/message.c index 04528629c7..abe21193d6 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1382,9 +1382,6 @@ const char *str2special(const char **const sp, const bool replace_spaces, if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL) { c = TO_SPECIAL((uint8_t)str[1], (uint8_t)str[2]); str += 2; - if (c == KS_ZERO) { // display as ^@ or - c = NUL; - } } if (IS_SPECIAL(c) || modifiers) { // Special key. special = true; @@ -1415,7 +1412,7 @@ const char *str2special(const char **const sp, const bool replace_spaces, || (replace_lt && c == '<')) { return (const char *)get_special_key_name(c, modifiers); } - buf[0] = c; + buf[0] = (char)c; buf[1] = NUL; return buf; } From 4a145f2036b0ff13f5db5f3aa7f35d814a1f43a5 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 21:40:30 +0300 Subject: [PATCH 049/103] ops: Silence PVS/V614: regtype is always initialized --- src/nvim/ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/ops.c b/src/nvim/ops.c index b421d81b7e..0483cc3e7a 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -5764,7 +5764,7 @@ static void set_clipboard(int name, yankreg_T *reg) list_T *args = tv_list_alloc(3); tv_list_append_list(args, lines); - tv_list_append_string(args, ®type, 1); + tv_list_append_string(args, ®type, 1); // -V614 tv_list_append_string(args, ((char[]) { (char)name }), 1); (void)eval_call_provider("clipboard", "set", args); From 2b7a8ceeb6849492b4273814f83e75adf5edd7c1 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 21:44:36 +0300 Subject: [PATCH 050/103] ops: Fix PVS/V547: did_change is almost always set Only exception is early `goto theend`. --- src/nvim/ops.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 0483cc3e7a..d67737e845 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -4610,9 +4610,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } } curwin->w_cursor.col = col; - if (!did_change) { - startpos = curwin->w_cursor; - } + startpos = curwin->w_cursor; did_change = true; (void)del_char(false); ins_char(firstdigit); @@ -4687,9 +4685,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) // Delete the old number. curwin->w_cursor.col = col; - if (!did_change) { - startpos = curwin->w_cursor; - } + startpos = curwin->w_cursor; did_change = true; todel = length; c = gchar_cursor(); @@ -4775,18 +4771,16 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) ins_str(buf1); // insert the new number xfree(buf1); endpos = curwin->w_cursor; - if (did_change && curwin->w_cursor.col) { + if (curwin->w_cursor.col) { curwin->w_cursor.col--; } } - if (did_change) { - // set the '[ and '] marks - curbuf->b_op_start = startpos; - curbuf->b_op_end = endpos; - if (curbuf->b_op_end.col > 0) { - curbuf->b_op_end.col--; - } + // set the '[ and '] marks + curbuf->b_op_start = startpos; + curbuf->b_op_end = endpos; + if (curbuf->b_op_end.col > 0) { + curbuf->b_op_end.col--; } theend: From dae1975394ba6b4b385115c3f4fa90b3ac7401d0 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 21:45:29 +0300 Subject: [PATCH 051/103] ops: Fix PVS/V547: allocator never returns NULL --- src/nvim/ops.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/nvim/ops.c b/src/nvim/ops.c index d67737e845..2828a11d6e 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -3891,9 +3891,6 @@ fex_format ( // Make a copy, the option could be changed while calling it. fex = vim_strsave(curbuf->b_p_fex); - if (fex == NULL) { - return 0; - } // Evaluate the function. if (use_sandbox) { sandbox++; @@ -4712,9 +4709,6 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) // When there are many leading zeros it could be very long. // Allocate a bit too much. buf1 = xmalloc((size_t)length + NUMBUFLEN); - if (buf1 == NULL) { - goto theend; - } ptr = buf1; if (negative && (!visual || was_positive)) { *ptr++ = '-'; From fc1ebb060e8364a947bc93ab578179a23aa9b81d Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 15 Apr 2018 21:49:47 +0300 Subject: [PATCH 052/103] ops: Fix PVS/V614: use of uninitialized variable I have actually no idea how code managed to work and not trigger ASAN/etc here. It does not look like a false positive at all. --- src/nvim/ops.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 2828a11d6e..8e272e475c 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -3568,7 +3568,7 @@ int do_join(size_t count, int *comments = NULL; int remove_comments = (use_formatoptions == TRUE) && has_format_option(FO_REMOVE_COMS); - bool prev_was_comment; + bool prev_was_comment = false; if (save_undo && u_save(curwin->w_cursor.lnum - 1, curwin->w_cursor.lnum + (linenr_T)count) == FAIL) { @@ -3592,17 +3592,17 @@ int do_join(size_t count, curwin->w_buffer->b_op_start.col = (colnr_T)STRLEN(curr); } if (remove_comments) { - /* We don't want to remove the comment leader if the - * previous line is not a comment. */ + // We don't want to remove the comment leader if the + // previous line is not a comment. if (t > 0 && prev_was_comment) { - char_u *new_curr = skip_comment(curr, TRUE, insert_space, - &prev_was_comment); + char_u *new_curr = skip_comment(curr, true, insert_space, + &prev_was_comment); comments[t] = (int)(new_curr - curr); curr = new_curr; - } else - curr = skip_comment(curr, FALSE, insert_space, - &prev_was_comment); + } else { + curr = skip_comment(curr, false, insert_space, &prev_was_comment); + } } if (insert_space && t > 0) { From 95cc2507c996f3564498382881f116899d43b000 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 16 Apr 2018 11:23:22 +0300 Subject: [PATCH 053/103] ops: Fix PVS/V560: pre may not be zero as that was already checked --- src/nvim/ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 8e272e475c..c4790653b8 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -4744,7 +4744,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIu64, (uint64_t)n); } else if (pre == '0') { vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIo64, (uint64_t)n); - } else if (pre && hexupper) { + } else if (hexupper) { vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIX64, (uint64_t)n); } else { vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIx64, (uint64_t)n); From 0eb1d7ca4ca2b1e6c5323ec39535ad238b503aff Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 16 Apr 2018 11:31:27 +0300 Subject: [PATCH 054/103] option: Silence PVS/V594: GLOBAL_WO macros is not really necessary In that case it is completely possible to just use w_allbuf_opt directly. --- src/nvim/option.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/nvim/option.c b/src/nvim/option.c index c43ba2fc4f..9dc29bbfd9 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4184,27 +4184,23 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, if (value < 0) { errmsg = e_positive; } - } else if (pp == &curwin->w_p_fdl - || pp == (long *)GLOBAL_WO(&curwin->w_p_fdl)) { + } else if (pp == &curwin->w_p_fdl || pp == &curwin->w_allbuf_opt.wo_fdl) { if (value < 0) { errmsg = e_positive; } - } else if (pp == &curwin->w_p_fdc - || pp == (long *)GLOBAL_WO(&curwin->w_p_fdc)) { + } else if (pp == &curwin->w_p_fdc || pp == &curwin->w_allbuf_opt.wo_fdc) { if (value < 0) { errmsg = e_positive; } else if (value > 12) { errmsg = e_invarg; } - } else if (pp == &curwin->w_p_cole - || pp == (long *)GLOBAL_WO(&curwin->w_p_cole)) { + } else if (pp == &curwin->w_p_cole || pp == &curwin->w_allbuf_opt.wo_cole) { if (value < 0) { errmsg = e_positive; } else if (value > 3) { errmsg = e_invarg; } - } else if (pp == &curwin->w_p_nuw - || pp == (long *)GLOBAL_WO(&curwin->w_p_nuw)) { + } else if (pp == &curwin->w_p_nuw || pp == &curwin->w_allbuf_opt.wo_nuw) { if (value < 1) { errmsg = e_positive; } else if (value > 10) { From d66217ab6dbe9c96852585634c3218647b52fba9 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 16 Apr 2018 11:32:00 +0300 Subject: [PATCH 055/103] option: Fix PVS/V517: duplicate check for titlelen --- src/nvim/option.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/nvim/option.c b/src/nvim/option.c index 9dc29bbfd9..686dc4cc46 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4160,10 +4160,6 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, if (value < 0) { errmsg = e_positive; } - } else if (pp == &p_titlelen) { - if (value < 0) { - errmsg = e_positive; - } } else if (pp == &p_so) { if (value < 0 && full_screen) { errmsg = e_scroll; From 61b6eb926df33728eeb35bcb545d3fe345f93713 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 16 Apr 2018 11:33:11 +0300 Subject: [PATCH 056/103] option: Fix PVS/V547: allocator never returns NULL now --- src/nvim/option.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/nvim/option.c b/src/nvim/option.c index 686dc4cc46..1ba77c15e2 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -5793,25 +5793,28 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_ro = FALSE; /* don't copy readonly */ buf->b_p_fenc = vim_strsave(p_fenc); switch (*p_ffs) { - case 'm': - buf->b_p_ff = vim_strsave((char_u *)FF_MAC); - break; - case 'd': - buf->b_p_ff = vim_strsave((char_u *)FF_DOS); - break; - case 'u': - buf->b_p_ff = vim_strsave((char_u *)FF_UNIX); - break; - default: - buf->b_p_ff = vim_strsave(p_ff); - } - if (buf->b_p_ff != NULL) { - buf->b_start_ffc = *buf->b_p_ff; + case 'm': { + buf->b_p_ff = vim_strsave((char_u *)FF_MAC); + break; + } + case 'd': { + buf->b_p_ff = vim_strsave((char_u *)FF_DOS); + break; + } + case 'u': { + buf->b_p_ff = vim_strsave((char_u *)FF_UNIX); + break; + } + default: { + buf->b_p_ff = vim_strsave(p_ff); + break; + } } buf->b_p_bh = empty_option; buf->b_p_bt = empty_option; - } else - free_buf_options(buf, FALSE); + } else { + free_buf_options(buf, false); + } buf->b_p_ai = p_ai; buf->b_p_ai_nopaste = p_ai_nopaste; From 6a5b9de54648175386f5ac9edc2fa591bc3023ed Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 16 Apr 2018 11:34:26 +0300 Subject: [PATCH 057/103] option: Fix PVS/V560: EXPAND_BOOL_SETTINGS already caused early return --- src/nvim/option.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/option.c b/src/nvim/option.c index 1ba77c15e2..35830b9ca5 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -6075,7 +6075,7 @@ set_context_in_set_cmd ( xp->xp_context = EXPAND_UNSUCCESSFUL; return; } - if (xp->xp_context != EXPAND_BOOL_SETTINGS && p[1] == NUL) { + if (p[1] == NUL) { xp->xp_context = EXPAND_OLD_SETTING; if (is_term_option) expand_option_idx = -1; From d0850586df3dbf738542dac55b6329d6de1ad73b Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 16 Apr 2018 11:36:06 +0300 Subject: [PATCH 058/103] option: Fix PVS/V547: var is always NULL at that point --- src/nvim/option.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/nvim/option.c b/src/nvim/option.c index 35830b9ca5..f50d735e50 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -6219,14 +6219,15 @@ void ExpandOldSetting(int *num_file, char_u ***file) } if (expand_option_idx >= 0) { - /* put string of option value in NameBuff */ + // Put string of option value in NameBuff. option_value2string(&options[expand_option_idx], expand_option_flags); var = NameBuff; - } else if (var == NULL) + } else { var = (char_u *)""; + } - /* A backslash is required before some characters. This is the reverse of - * what happens in do_set(). */ + // A backslash is required before some characters. This is the reverse of + // what happens in do_set(). char_u *buf = vim_strsave_escaped(var, escape_chars); #ifdef BACKSLASH_IN_FILENAME From fab09ea0d6e8b8bd161c24341e6cdf64e80ae871 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 16 Apr 2018 11:37:39 +0300 Subject: [PATCH 059/103] option: Silence PVS/V547: expression is true on 64-bit systems --- src/nvim/option.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/nvim/option.c b/src/nvim/option.c index f50d735e50..48fd797ee9 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -625,12 +625,12 @@ void set_init_1(void) opt_idx = findoption("maxmemtot"); if (opt_idx >= 0) { { - /* Use half of amount of memory available to Vim. */ - /* If too much to fit in uintptr_t, get uintptr_t max */ + // Use half of amount of memory available to Vim. + // If too much to fit in uintptr_t, get uintptr_t max. uint64_t available_kib = os_get_total_mem_kib(); - uintptr_t n = available_kib / 2 > UINTPTR_MAX - ? UINTPTR_MAX - : (uintptr_t)(available_kib /2); + uintptr_t n = (available_kib / 2 > UINTPTR_MAX // -V547 + ? UINTPTR_MAX + : (uintptr_t)(available_kib /2)); options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n; opt_idx = findoption("maxmem"); if (opt_idx >= 0) { From 4a1251206a7016d37a853b0c48e2b4901ef363b3 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 17 Apr 2018 01:07:16 +0300 Subject: [PATCH 060/103] path: Fix PVS/V560: condition is essentially `A && A` --- src/nvim/path.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/path.c b/src/nvim/path.c index 168d835a66..e3d87ff33e 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -673,7 +673,7 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, // Find all matching entries. char_u *name; scandir_next_with_dots(NULL); // initialize - while ((name = (char_u *) scandir_next_with_dots(&dir)) && name != NULL) { + while ((name = (char_u *)scandir_next_with_dots(&dir)) != NULL) { if ((name[0] != '.' || starts_with_dot || ((flags & EW_DODOT) From eba61fbc974da88ae43f0fc5936708ecdf91e7fa Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 17 Apr 2018 01:11:05 +0300 Subject: [PATCH 061/103] path: Silence PVS/V557: impossible to reach with NUL-terminated string --- src/nvim/path.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nvim/path.c b/src/nvim/path.c index e3d87ff33e..4f3f7c0661 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -677,7 +677,8 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, if ((name[0] != '.' || starts_with_dot || ((flags & EW_DODOT) - && name[1] != NUL && (name[1] != '.' || name[2] != NUL))) + && name[1] != NUL + && (name[1] != '.' || name[2] != NUL))) // -V557 && ((regmatch.regprog != NULL && vim_regexec(®match, name, 0)) || ((flags & EW_NOTWILD) && fnamencmp(path + (s - buf), name, e - s) == 0))) { From 57c66bc168cb30a483b9fd13cb13e35bea5491bc Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 17 Apr 2018 01:14:55 +0300 Subject: [PATCH 062/103] pvscheck: Remove outputs before running plog-converter plog-converter behaviour is not the best one when creating fullhtml report and directory already exists: it puts report inside an existing directory. Not sure what exactly it does if inside exists as well, but if I am not mistaking report will not be created. --- scripts/pvscheck.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/pvscheck.sh b/scripts/pvscheck.sh index 54e6241d07..9916a838b6 100755 --- a/scripts/pvscheck.sh +++ b/scripts/pvscheck.sh @@ -361,6 +361,7 @@ run_analysis() {( --file build/compile_commands.json \ --sourcetree-root . || true + rm -rf PVS-studio.{xml,err,tsk,html.d} plog-converter -r . -t xml -o PVS-studio.xml PVS-studio.log plog-converter -r . -t errorfile -o PVS-studio.err PVS-studio.log plog-converter -r . -t tasklist -o PVS-studio.tsk PVS-studio.log From cb3bb0becb74f46dfa88ff4be25833f55576c04e Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 17 Apr 2018 01:35:59 +0300 Subject: [PATCH 063/103] pvscheck: Add --update switch --- scripts/pvscheck.sh | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/scripts/pvscheck.sh b/scripts/pvscheck.sh index 9916a838b6..62051b191d 100755 --- a/scripts/pvscheck.sh +++ b/scripts/pvscheck.sh @@ -21,13 +21,14 @@ help() { echo 'Usage:' echo ' pvscheck.sh [--pvs URL] [--deps] [--environment-cc]' echo ' [target-directory [branch]]' - echo ' pvscheck.sh [--pvs URL] [--recheck] [--environment-cc]' + echo ' pvscheck.sh [--pvs URL] [--recheck] [--environment-cc] [--update]' echo ' [target-directory]' echo ' pvscheck.sh [--pvs URL] --only-analyse [target-directory]' echo ' pvscheck.sh [--pvs URL] --pvs-install {target-directory}' echo ' pvscheck.sh --patch [--only-build]' echo echo ' --pvs: Fetch pvs-studio from URL.' + echo echo ' --pvs detect: Auto-detect latest version (by scraping viva64.com).' echo echo ' --deps: (for regular run) Use top-level Makefile and build deps.' @@ -47,6 +48,8 @@ help() { echo echo ' --recheck: run analysis on a prepared target directory.' echo + echo ' --update: when rechecking first do a pull.' + echo echo ' --only-analyse: run analysis on a prepared target directory ' echo ' without building Neovim.' echo @@ -399,13 +402,24 @@ do_check() { install_pvs "$tgt" "$pvs_url" - do_recheck "$tgt" "$deps" "$environment_cc" + do_recheck "$tgt" "$deps" "$environment_cc" "" } do_recheck() { local tgt="$1" ; shift local deps="$1" ; shift local environment_cc="$1" ; shift + local update="$1" ; shift + + if test -n "$update" ; then + ( + cd "$tgt" + local branch="$(git rev-parse --abbrev-ref HEAD)" + git checkout --detach + git fetch -f origin "${branch}:${branch}" + git checkout -f "$branch" + ) + fi create_compile_commands "$tgt" "$deps" "$environment_cc" @@ -437,6 +451,7 @@ main() { pvs-install store_const \ deps store_const \ environment-cc store_const \ + update store_const \ -- \ 'modify realdir tgt "$PWD/../neovim-pvs"' \ 'store branch master' \ @@ -455,7 +470,7 @@ main() { elif test -n "$pvs_install" ; then install_pvs "$tgt" "$pvs_url" elif test -n "$recheck" ; then - do_recheck "$tgt" "$deps" "$environment_cc" + do_recheck "$tgt" "$deps" "$environment_cc" "$update" elif test -n "$only_analyse" ; then do_analysis "$tgt" else From 8cdaac0d80f7876f750ce8eb147c41b477409974 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 17 Apr 2018 01:49:46 +0300 Subject: [PATCH 064/103] event/process: Silence PVS/V547: assuming stream->num_bytes changes Not familiar with the code, but I assume that loop_poll_events can actually change stream->num_bytes, so condition is not always false. --- src/nvim/event/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 60650344ce..fa31024a64 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -358,7 +358,7 @@ static void flush_stream(Process *proc, Stream *stream) } // Stream can be closed if it is empty. - if (num_bytes == stream->num_bytes) { + if (num_bytes == stream->num_bytes) { // -V547 if (stream->read_cb && !stream->did_eof) { // Stream callback could miss EOF handling if a child keeps the stream // open. But only send EOF if we haven't already. From b7a46f22999ed5e1f6757b803bcab683575afb5a Mon Sep 17 00:00:00 2001 From: ZyX Date: Fri, 20 Apr 2018 00:04:25 +0300 Subject: [PATCH 065/103] eval/typval: Remove struct dictitem_S which is not used anywhere --- src/nvim/eval/typval.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 60bc7ff375..33e2aa6b61 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -197,15 +197,6 @@ typedef struct { }, \ } -// Structure to hold an item of a Dictionary. -// Also used for a variable. -// The key is copied into "di_key" to avoid an extra alloc/free for it. -struct dictitem_S { - typval_T di_tv; ///< type and value of the variable - char_u di_flags; ///< flags (only used for variable) - char_u di_key[1]; ///< key (actually longer!) -}; - #define TV_DICTITEM_STRUCT(...) \ struct { \ typval_T di_tv; /* Structure that holds scope dictionary itself. */ \ From 4d43ce85f187a9d6deed9266098dd82fec07be23 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 18:53:49 +0300 Subject: [PATCH 066/103] quickfix: Fix PVS/V547,V560: no conversion with fixed &encoding --- src/nvim/quickfix.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 1ff38b573e..a44a305f22 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -4740,14 +4740,6 @@ void ex_helpgrep(exarg_T *eap) regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING); regmatch.rm_ic = FALSE; if (regmatch.regprog != NULL) { - vimconv_T vc; - - /* Help files are in utf-8 or latin1, convert lines when 'encoding' - * differs. */ - vc.vc_type = CONV_NONE; - if (!enc_utf8) - convert_setup(&vc, (char_u *)"utf-8", p_enc); - /* create a new quickfix list */ qf_new_list(qi, *eap->cmdlinep); @@ -4780,15 +4772,6 @@ void ex_helpgrep(exarg_T *eap) lnum = 1; while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) { char_u *line = IObuff; - /* Convert a line if 'encoding' is not utf-8 and - * the line contains a non-ASCII character. */ - if (vc.vc_type != CONV_NONE - && has_non_ascii(IObuff)) { - line = string_convert(&vc, IObuff, NULL); - if (line == NULL) - line = IObuff; - } - if (vim_regexec(®match, line, (colnr_T)0)) { int l = (int)STRLEN(line); @@ -4831,8 +4814,6 @@ void ex_helpgrep(exarg_T *eap) } vim_regfree(regmatch.regprog); - if (vc.vc_type != CONV_NONE) - convert_setup(&vc, NULL, NULL); qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE; qi->qf_lists[qi->qf_curlist].qf_ptr = From 3ee187b770cd9b736b70225ac81efadc5e51962d Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 18:56:29 +0300 Subject: [PATCH 067/103] quickfix: Fix PVS/V547: allocator never returns NULL now --- src/nvim/quickfix.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index a44a305f22..1f69565403 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -3626,7 +3626,7 @@ void ex_vimgrep(exarg_T *eap) && eap->cmdidx != CMD_vimgrepadd && eap->cmdidx != CMD_lvimgrepadd) || qi->qf_curlist == qi->qf_listcount) { // make place for a new list - qf_new_list(qi, title != NULL ? title : *eap->cmdlinep); + qf_new_list(qi, title); } /* parse the list of arguments */ @@ -4205,11 +4205,9 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict) if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) { if (qi->qf_lists[qf_idx].qf_ctx != NULL) { di = tv_dict_item_alloc_len(S_LEN("context")); - if (di != NULL) { - tv_copy(qi->qf_lists[qf_idx].qf_ctx, &di->di_tv); - if (tv_dict_add(retdict, di) == FAIL) { - tv_dict_item_free(di); - } + tv_copy(qi->qf_lists[qf_idx].qf_ctx, &di->di_tv); + if (tv_dict_add(retdict, di) == FAIL) { + tv_dict_item_free(di); } } else { status = tv_dict_add_str(retdict, S_LEN("context"), ""); From 190cc43cf38c0231f4672c52b60725ba173131f8 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 18:59:23 +0300 Subject: [PATCH 068/103] quickfix: Silence PVS/V560: memory is referenced and may be changed --- src/nvim/quickfix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 1f69565403..cbab8eb05b 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2062,7 +2062,7 @@ win_found: EMSG(_("E924: Current window was closed")); is_abort = true; opened_window = false; - } else if (old_qf_curlist != qi->qf_curlist + } else if (old_qf_curlist != qi->qf_curlist // -V560 || !is_qf_entry_present(qi, qf_ptr)) { if (qi == &ql_info) { EMSG(_("E925: Current quickfix was changed")); From adfc1212b57af759af2d67db399916f13b1cc2b0 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 19:09:20 +0300 Subject: [PATCH 069/103] regexp_nfa: Silence PVS/V560: current code is more obvious MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While warning is technically true (cannot enter this case with `state->c` greater then NFA_Z…9) it makes condition less readable and relies on knownledge of enum internal structure. --- src/nvim/regexp_nfa.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index c520ef5fb9..98fae858f6 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -4117,7 +4117,7 @@ skip_add: if (state->c == NFA_ZSTART) { subidx = 0; sub = &subs->norm; - } else if (state->c >= NFA_ZOPEN && state->c <= NFA_ZOPEN9) { + } else if (state->c >= NFA_ZOPEN && state->c <= NFA_ZOPEN9) { // -V560 subidx = state->c - NFA_ZOPEN; sub = &subs->synt; } else { @@ -4169,11 +4169,12 @@ skip_add: } subs = addstate(l, state->out, subs, pim, off_arg); - /* "subs" may have changed, need to set "sub" again */ - if (state->c >= NFA_ZOPEN && state->c <= NFA_ZOPEN9) + // "subs" may have changed, need to set "sub" again. + if (state->c >= NFA_ZOPEN && state->c <= NFA_ZOPEN9) { // -V560 sub = &subs->synt; - else + } else { sub = &subs->norm; + } if (save_in_use == -1) { if (REG_MULTI) { @@ -4217,7 +4218,7 @@ skip_add: if (state->c == NFA_ZEND) { subidx = 0; sub = &subs->norm; - } else if (state->c >= NFA_ZCLOSE && state->c <= NFA_ZCLOSE9) { + } else if (state->c >= NFA_ZCLOSE && state->c <= NFA_ZCLOSE9) { // -V560 subidx = state->c - NFA_ZCLOSE; sub = &subs->synt; } else { @@ -4250,11 +4251,12 @@ skip_add: } subs = addstate(l, state->out, subs, pim, off_arg); - /* "subs" may have changed, need to set "sub" again */ - if (state->c >= NFA_ZCLOSE && state->c <= NFA_ZCLOSE9) + // "subs" may have changed, need to set "sub" again. + if (state->c >= NFA_ZCLOSE && state->c <= NFA_ZCLOSE9) { // -V560 sub = &subs->synt; - else + } else { sub = &subs->norm; + } if (REG_MULTI) { sub->list.multi[subidx] = save_multipos; From d42f934bcb3e9e876e5e7ba0ab5cd824175fd10c Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 19:32:17 +0300 Subject: [PATCH 070/103] screen: Get rid of ScreenLines2 as it is no longer used Should also fix some PVS warnings in process. --- src/nvim/globals.h | 4 - src/nvim/screen.c | 264 ++++++++++++++++----------------------------- 2 files changed, 95 insertions(+), 173 deletions(-) diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 400f46eb79..7a1ce46ba4 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -158,10 +158,6 @@ EXTERN u8char_T *ScreenLinesC[MAX_MCO]; /* composing characters */ EXTERN int Screen_mco INIT(= 0); /* value of p_mco used when allocating ScreenLinesC[] */ -/* Only used for euc-jp: Second byte of a character that starts with 0x8e. - * These are single-width. */ -EXTERN schar_T *ScreenLines2 INIT(= NULL); - EXTERN int screen_Rows INIT(= 0); /* actual size of ScreenLines[] */ EXTERN int screen_Columns INIT(= 0); /* actual size of ScreenLines[] */ diff --git a/src/nvim/screen.c b/src/nvim/screen.c index e232939403..0672187975 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -24,8 +24,6 @@ * cells the next byte in ScreenLines[] is 0. * ScreenLinesC[][] contain up to 'maxcombine' composing characters * (drawn on top of the first character). There is 0 after the last one used. - * ScreenLines2[] is only used for euc-jp to store the second byte if the - * first byte is 0x8e (single-width character). * * The screen_*() functions write to the screen and handle updating * ScreenLines[]. @@ -1918,12 +1916,10 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T } if (cells > 1) ScreenLines[idx + 1] = 0; - } else if (enc_dbcs == DBCS_JPNU && *p == 0x8e) - /* double-byte single width character */ - ScreenLines2[idx] = p[1]; - else if (cells > 1) - /* double-width character */ + } else if (cells > 1) { + // Double-width character. ScreenLines[idx + 1] = p[1]; + } col += cells; idx += cells; p += c_len; @@ -4092,24 +4088,19 @@ win_line ( --col; } ScreenLines[off] = c; - if (enc_dbcs == DBCS_JPNU) { - if ((mb_c & 0xff00) == 0x8e00) - ScreenLines[off] = 0x8e; - ScreenLines2[off] = mb_c & 0xff; - } else if (enc_utf8) { - if (mb_utf8) { - int i; - - ScreenLinesUC[off] = mb_c; - if ((c & 0xff) == 0) - ScreenLines[off] = 0x80; /* avoid storing zero */ - for (i = 0; i < Screen_mco; ++i) { - ScreenLinesC[i][off] = u8cc[i]; - if (u8cc[i] == 0) - break; + if (mb_utf8) { + ScreenLinesUC[off] = mb_c; + if ((c & 0xff) == 0) { + ScreenLines[off] = 0x80; // Avoid storing zero. + } + for (int i = 0; i < Screen_mco; i++) { + ScreenLinesC[i][off] = u8cc[i]; + if (u8cc[i] == 0) { + break; } - } else - ScreenLinesUC[off] = 0; + } + } else { + ScreenLinesUC[off] = 0; } if (multi_attr) { ScreenAttrs[off] = multi_attr; @@ -4381,23 +4372,14 @@ static int comp_char_differs(int off_from, int off_to) static int char_needs_redraw(int off_from, int off_to, int cols) { return (cols > 0 - && ((ScreenLines[off_from] != ScreenLines[off_to] - || ScreenAttrs[off_from] != ScreenAttrs[off_to]) - - || (enc_dbcs != 0 - && MB_BYTE2LEN(ScreenLines[off_from]) > 1 - && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e - ? ScreenLines2[off_from] != ScreenLines2[off_to] - : (cols > 1 && ScreenLines[off_from + 1] - != ScreenLines[off_to + 1]))) - || (enc_utf8 - && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to] - || (ScreenLinesUC[off_from] != 0 - && comp_char_differs(off_from, off_to)) - || ((*mb_off2cells)(off_from, off_from + cols) > 1 - && ScreenLines[off_from + 1] - != ScreenLines[off_to + 1]))) - || p_wd < 0)); + && (ScreenLines[off_from] != ScreenLines[off_to] + || ScreenAttrs[off_from] != ScreenAttrs[off_to] + || ScreenLinesUC[off_from] != ScreenLinesUC[off_to] + || (ScreenLinesUC[off_from] != 0 + && comp_char_differs(off_from, off_to)) + || (utf_off2cells(off_from, off_from + cols) > 1 + && ScreenLines[off_from + 1] != ScreenLines[off_to + 1]) + || p_wd < 0)); } /* @@ -4497,9 +4479,6 @@ static void screen_line(int row, int coloff, int endcol, ScreenLines[off_to + 2] = 0; redraw_next = TRUE; } - - if (enc_dbcs == DBCS_JPNU) - ScreenLines2[off_to] = ScreenLines2[off_from]; } /* When writing a single-width character over a double-width * character and at the end of the redrawn text, need to clear out @@ -5325,16 +5304,7 @@ void screen_getbytes(int row, int col, char_u *bytes, int *attrp) bytes[0] = ScreenLines[off]; bytes[1] = NUL; - if (enc_utf8 && ScreenLinesUC[off] != 0) - bytes[utfc_char2bytes(off, bytes)] = NUL; - else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e) { - bytes[0] = ScreenLines[off]; - bytes[1] = ScreenLines2[off]; - bytes[2] = NUL; - } else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1) { - bytes[1] = ScreenLines[off + 1]; - bytes[2] = NUL; - } + bytes[utfc_char2bytes(off, bytes)] = NUL; } } @@ -5524,11 +5494,9 @@ void screen_puts_len(char_u *text, int textlen, int row, int col, int attr) ScreenLines[off + 1] = ptr[1]; ScreenAttrs[off + 1] = attr; screen_char_2(off, row, col); - } else if (l_enc_dbcs == DBCS_JPNU && c == 0x8e) { - ScreenLines2[off] = ptr[1]; - screen_char(off, row, col); - } else + } else { screen_char(off, row, col); + } } if (l_has_mbyte) { off += mbyte_cells; @@ -5901,7 +5869,7 @@ static void screen_char(unsigned off, int row, int col) ui_cursor_goto(row, col); ui_set_highlight(ScreenAttrs[off]); - if (enc_utf8 && ScreenLinesUC[off] != 0) { + if (ScreenLinesUC[off] != 0) { char_u buf[MB_MAXBYTES + 1]; // Convert UTF-8 character to bytes and write it. @@ -5909,10 +5877,6 @@ static void screen_char(unsigned off, int row, int col) ui_puts(buf); } else { ui_putc(ScreenLines[off]); - // double-byte character in single-width cell - if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e) { - ui_putc(ScreenLines2[off]); - } } } @@ -6104,40 +6068,25 @@ int screen_valid(int doclear) void screenalloc(bool doclear) { int new_row, old_row; - int outofmem = FALSE; int len; - schar_T *new_ScreenLines; - u8char_T *new_ScreenLinesUC = NULL; - u8char_T *new_ScreenLinesC[MAX_MCO]; - schar_T *new_ScreenLines2 = NULL; - int i; - sattr_T *new_ScreenAttrs; - unsigned *new_LineOffset; - char_u *new_LineWraps; - StlClickDefinition *new_tab_page_click_defs; static bool entered = false; // avoid recursiveness static bool done_outofmem_msg = false; int retry_count = 0; - const bool l_enc_utf8 = enc_utf8; - const int l_enc_dbcs = enc_dbcs; retry: - /* - * Allocation of the screen buffers is done only when the size changes and - * when Rows and Columns have been set and we have started doing full - * screen stuff. - */ + // Allocation of the screen buffers is done only when the size changes and + // when Rows and Columns have been set and we have started doing full + // screen stuff. if ((ScreenLines != NULL && Rows == screen_Rows && Columns == screen_Columns - && l_enc_utf8 == (ScreenLinesUC != NULL) - && (l_enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL) - && p_mco == Screen_mco - ) + && ScreenLinesUC != NULL + && p_mco == Screen_mco) || Rows == 0 || Columns == 0 - || (!full_screen && ScreenLines == NULL)) + || (!full_screen && ScreenLines == NULL)) { return; + } /* * It's possible that we produce an out-of-memory message below, which @@ -6175,22 +6124,22 @@ retry: if (aucmd_win != NULL) win_free_lsize(aucmd_win); - new_ScreenLines = xmalloc((size_t)((Rows + 1) * Columns * sizeof(schar_T))); - memset(new_ScreenLinesC, 0, sizeof(u8char_T *) * MAX_MCO); - if (l_enc_utf8) { - new_ScreenLinesUC = xmalloc( - (size_t)((Rows + 1) * Columns * sizeof(u8char_T))); - for (i = 0; i < p_mco; ++i) - new_ScreenLinesC[i] = xcalloc((Rows + 1) * Columns, sizeof(u8char_T)); + schar_T *new_ScreenLines = xmalloc( + (size_t)((Rows + 1) * Columns * sizeof(*new_ScreenLines))); + u8char_T *new_ScreenLinesC[MAX_MCO]; + memset(new_ScreenLinesC, 0, sizeof(new_ScreenLinesC)); + u8char_T *new_ScreenLinesUC = xmalloc( + (size_t)((Rows + 1) * Columns * sizeof(*new_ScreenLinesUC))); + for (int i = 0; i < p_mco; i++) { + new_ScreenLinesC[i] = xcalloc( + (size_t)((Rows + 1) * Columns), sizeof(new_ScreenLinesC[0][0])); } - if (l_enc_dbcs == DBCS_JPNU) - new_ScreenLines2 = xmalloc( - (size_t)((Rows + 1) * Columns * sizeof(schar_T))); - new_ScreenAttrs = xmalloc((size_t)((Rows + 1) * Columns * sizeof(sattr_T))); - new_LineOffset = xmalloc((size_t)(Rows * sizeof(unsigned))); - new_LineWraps = xmalloc((size_t)(Rows * sizeof(char_u))); - new_tab_page_click_defs = xcalloc( - (size_t) Columns, sizeof(*new_tab_page_click_defs)); + sattr_T *new_ScreenAttrs = xmalloc( + (size_t)((Rows + 1) * Columns * sizeof(*new_ScreenAttrs))); + unsigned *new_LineOffset = xmalloc((size_t)(Rows * sizeof(*new_LineOffset))); + char_u *new_LineWraps = xmalloc((size_t)(Rows * sizeof(*new_LineWraps))); + StlClickDefinition *new_tab_page_click_defs = xcalloc( + (size_t)Columns, sizeof(*new_tab_page_click_defs)); FOR_ALL_TAB_WINDOWS(tp, wp) { win_alloc_lines(wp); @@ -6199,23 +6148,20 @@ retry: win_alloc_lines(aucmd_win); } - for (i = 0; i < p_mco; ++i) - if (new_ScreenLinesC[i] == NULL) + int i; + for (i = 0; i < p_mco; i++) { + if (new_ScreenLinesC[i] == NULL) { break; - if (new_ScreenLines == NULL - || (new_ScreenLinesUC == NULL || i != p_mco) - || new_ScreenAttrs == NULL - || new_LineOffset == NULL - || new_LineWraps == NULL - || new_tab_page_click_defs == NULL - || outofmem) { + } + } + if (i != p_mco) { if (ScreenLines != NULL || !done_outofmem_msg) { - /* guess the size */ + // Guess the size. do_outofmem_msg((Rows + 1) * Columns); - /* Remember we did this to avoid getting outofmem messages over - * and over again. */ - done_outofmem_msg = TRUE; + // Remember we did this to avoid getting outofmem messages over + // and over again. + done_outofmem_msg = true; } xfree(new_ScreenLines); new_ScreenLines = NULL; @@ -6225,8 +6171,6 @@ retry: xfree(new_ScreenLinesC[i]); new_ScreenLinesC[i] = NULL; } - xfree(new_ScreenLines2); - new_ScreenLines2 = NULL; xfree(new_ScreenAttrs); new_ScreenAttrs = NULL; xfree(new_LineOffset); @@ -6249,53 +6193,42 @@ retry: * executing an external command, for the GUI). */ if (!doclear) { - (void)memset(new_ScreenLines + new_row * Columns, - ' ', (size_t)Columns * sizeof(schar_T)); - if (l_enc_utf8) { - (void)memset(new_ScreenLinesUC + new_row * Columns, - 0, (size_t)Columns * sizeof(u8char_T)); - for (i = 0; i < p_mco; ++i) - (void)memset(new_ScreenLinesC[i] - + new_row * Columns, - 0, (size_t)Columns * sizeof(u8char_T)); + memset(new_ScreenLines + new_row * Columns, + ' ', (size_t)Columns * sizeof(new_ScreenLines[0])); + memset(new_ScreenLinesUC + new_row * Columns, + 0, (size_t)Columns * sizeof(new_ScreenLinesUC[0])); + for (i = 0; i < p_mco; i++) { + memset(new_ScreenLinesC[i] + new_row * Columns, + 0, (size_t)Columns * sizeof(new_ScreenLinesC[0][0])); } - if (l_enc_dbcs == DBCS_JPNU) - (void)memset(new_ScreenLines2 + new_row * Columns, - 0, (size_t)Columns * sizeof(schar_T)); - (void)memset(new_ScreenAttrs + new_row * Columns, - 0, (size_t)Columns * sizeof(sattr_T)); + memset(new_ScreenAttrs + new_row * Columns, + 0, (size_t)Columns * sizeof(new_ScreenAttrs[0])); old_row = new_row + (screen_Rows - Rows); if (old_row >= 0 && ScreenLines != NULL) { if (screen_Columns < Columns) len = screen_Columns; else len = Columns; - /* When switching to utf-8 don't copy characters, they - * may be invalid now. Also when p_mco changes. */ - if (!(l_enc_utf8 && ScreenLinesUC == NULL) - && p_mco == Screen_mco) + // When switching to utf-8 don't copy characters, they + // may be invalid now. Also when p_mco changes. + if (ScreenLinesUC != NULL && p_mco == Screen_mco) { memmove(new_ScreenLines + new_LineOffset[new_row], - ScreenLines + LineOffset[old_row], - (size_t)len * sizeof(schar_T)); - if (l_enc_utf8 && ScreenLinesUC != NULL - && p_mco == Screen_mco) { - memmove(new_ScreenLinesUC + new_LineOffset[new_row], - ScreenLinesUC + LineOffset[old_row], - (size_t)len * sizeof(u8char_T)); - for (i = 0; i < p_mco; ++i) - memmove(new_ScreenLinesC[i] - + new_LineOffset[new_row], - ScreenLinesC[i] + LineOffset[old_row], - (size_t)len * sizeof(u8char_T)); + ScreenLines + LineOffset[old_row], + (size_t)len * sizeof(new_ScreenLines[0])); } - if (ScreenLines2 != NULL) { - memmove(new_ScreenLines2 + new_LineOffset[new_row], - ScreenLines2 + LineOffset[old_row], - (size_t)len * sizeof(schar_T)); + if (ScreenLinesUC != NULL && p_mco == Screen_mco) { + memmove(new_ScreenLinesUC + new_LineOffset[new_row], + ScreenLinesUC + LineOffset[old_row], + (size_t)len * sizeof(new_ScreenLinesUC[0])); + for (i = 0; i < p_mco; i++) { + memmove(new_ScreenLinesC[i] + new_LineOffset[new_row], + ScreenLinesC[i] + LineOffset[old_row], + (size_t)len * sizeof(new_ScreenLinesC[0][0])); + } } memmove(new_ScreenAttrs + new_LineOffset[new_row], ScreenAttrs + LineOffset[old_row], - (size_t)len * sizeof(sattr_T)); + (size_t)len * sizeof(new_ScreenAttrs[0])); } } } @@ -6310,7 +6243,6 @@ retry: for (i = 0; i < p_mco; ++i) ScreenLinesC[i] = new_ScreenLinesC[i]; Screen_mco = p_mco; - ScreenLines2 = new_ScreenLines2; ScreenAttrs = new_ScreenAttrs; LineOffset = new_LineOffset; LineWraps = new_LineWraps; @@ -6344,12 +6276,10 @@ retry: void free_screenlines(void) { - int i; - xfree(ScreenLinesUC); - for (i = 0; i < Screen_mco; ++i) + for (int i = 0; i < Screen_mco; i++) { xfree(ScreenLinesC[i]); - xfree(ScreenLines2); + } xfree(ScreenLines); xfree(ScreenAttrs); xfree(LineOffset); @@ -6433,25 +6363,21 @@ static void lineclear(unsigned off, int width) */ static void linecopy(int to, int from, win_T *wp) { - unsigned off_to = LineOffset[to] + wp->w_wincol; - unsigned off_from = LineOffset[from] + wp->w_wincol; + const unsigned off_to = LineOffset[to] + wp->w_wincol; + const unsigned off_from = LineOffset[from] + wp->w_wincol; memmove(ScreenLines + off_to, ScreenLines + off_from, - wp->w_width * sizeof(schar_T)); - if (enc_utf8) { - int i; + wp->w_width * sizeof(ScreenLines[0])); - memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from, - wp->w_width * sizeof(u8char_T)); - for (i = 0; i < p_mco; ++i) - memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from, - wp->w_width * sizeof(u8char_T)); + memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from, + wp->w_width * sizeof(u8char_T)); + for (int i = 0; i < p_mco; i++) { + memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from, + wp->w_width * sizeof(ScreenLinesC[0])); } - if (enc_dbcs == DBCS_JPNU) - memmove(ScreenLines2 + off_to, ScreenLines2 + off_from, - wp->w_width * sizeof(schar_T)); + memmove(ScreenAttrs + off_to, ScreenAttrs + off_from, - wp->w_width * sizeof(sattr_T)); + wp->w_width * sizeof(ScreenAttrs[0])); } /* From e3bffa47a682362e19426b5d936a911d8b12d557 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 19:33:46 +0300 Subject: [PATCH 071/103] globals: Do not use `false` for enc_dbcs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on screen.c code this value is not a boolean, so `false` is not appropriate. It should be either 0 or one of DBCS_… values. --- src/nvim/globals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 7a1ce46ba4..4542b7f133 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -710,7 +710,7 @@ EXTERN int vr_lines_changed INIT(= 0); /* #Lines changed by "gR" so far */ // mbyte flags that used to depend on 'encoding'. These are now deprecated, as // 'encoding' is always "utf-8". Code that use them can be refactored to // remove dead code. -#define enc_dbcs false +#define enc_dbcs 0 #define enc_utf8 true #define has_mbyte true From 9c981f5a1986542dba2bdb200894baaa7780ec4a Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 19:39:39 +0300 Subject: [PATCH 072/103] screen: Fix PVS/V560: condition was checked in surrounding if --- src/nvim/screen.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 0672187975..9c3ac29250 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -3542,8 +3542,7 @@ win_line ( tab_len += vcol_off; } // boguscols before FIX_FOR_BOGUSCOLS macro from above. - if (wp->w_p_list && lcs_tab1 && old_boguscols > 0 - && n_extra > tab_len) { + if (lcs_tab1 && old_boguscols > 0 && n_extra > tab_len) { tab_len += n_extra - tab_len; } From 4ff4e66fd78e02dd8e37b00de91856082b95b0eb Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 19:40:47 +0300 Subject: [PATCH 073/103] screen: Fix PVS/V519: duplicate successive assignment --- src/nvim/screen.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 9c3ac29250..3671537751 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2761,7 +2761,6 @@ win_line ( // Draw cells with the sign value or blank. c_extra = ' '; char_attr = win_hl_attr(wp, HLF_SC); - n_extra = 2; n_extra = win_signcol_width(wp); if (row == startrow + filler_lines && filler_todo <= 0) { From 3c7cc03f345ace2cdeeb71163ad5ed2c10c59a1f Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 19:43:27 +0300 Subject: [PATCH 074/103] screen: Fix PVS/V560: col never reassigned in this part of code --- src/nvim/screen.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 3671537751..8f2b7b1f04 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2140,7 +2140,6 @@ win_line ( bool nochange /* not updating for changed text */ ) { - int col = 0; // visual column on screen unsigned off; // offset in ScreenLines/ScreenAttrs int c = 0; // init for GCC long vcol = 0; // virtual column (for tabs) @@ -2553,7 +2552,7 @@ win_line ( ptr = prev_ptr; // If the character fits on the screen, don't need to skip it. // Except for a TAB. - if (((*mb_ptr2cells)(ptr) >= c || *ptr == TAB) && col == 0) { + if (utf_ptr2cells(ptr) >= c || *ptr == TAB) { n_skip = v - vcol; } } @@ -2702,11 +2701,11 @@ win_line ( } off = (unsigned)(current_ScreenLine - ScreenLines); - col = 0; + int col = 0; // Visual column on screen. if (wp->w_p_rl) { - /* Rightleft window: process the text in the normal direction, but put - * it in current_ScreenLine[] from right to left. Start at the - * rightmost column of the window. */ + // Rightleft window: process the text in the normal direction, but put + // it in current_ScreenLine[] from right to left. Start at the + // rightmost column of the window. col = wp->w_width - 1; off += col; } From b144a77f380a8ec5d7579ee888bf051617cf3dfb Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 19:44:56 +0300 Subject: [PATCH 075/103] search: Fix PVS/V547: checking variable right after assigning it --- src/nvim/search.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/nvim/search.c b/src/nvim/search.c index 1943e2ca43..102a42fe15 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -4017,23 +4017,22 @@ current_search ( VIsual = start_pos; curwin->w_cursor = pos; - VIsual_active = TRUE; + VIsual_active = true; VIsual_mode = 'v'; - if (VIsual_active) { - redraw_curbuf_later(INVERTED); /* update the inversion */ - if (*p_sel == 'e') { - /* Correction for exclusive selection depends on the direction. */ - if (forward && ltoreq(VIsual, curwin->w_cursor)) - inc_cursor(); - else if (!forward && ltoreq(curwin->w_cursor, VIsual)) - inc(&VIsual); + redraw_curbuf_later(INVERTED); // Update the inversion. + if (*p_sel == 'e') { + // Correction for exclusive selection depends on the direction. + if (forward && ltoreq(VIsual, curwin->w_cursor)) { + inc_cursor(); + } else if (!forward && ltoreq(curwin->w_cursor, VIsual)) { + inc(&VIsual); } - } - if (fdo_flags & FDO_SEARCH && KeyTyped) + if (fdo_flags & FDO_SEARCH && KeyTyped) { foldOpenCursor(); + } may_start_select('c'); setmouse(); From db1c9b625cd200a9ed2fc8dc842eb76a329eb144 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 19:46:27 +0300 Subject: [PATCH 076/103] search: Fix PVS/V547: condition already checked in surrounding if --- src/nvim/search.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/nvim/search.c b/src/nvim/search.c index 102a42fe15..3b726b6d08 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -3944,15 +3944,15 @@ current_search ( if (VIsual_active) { orig_pos = pos = curwin->w_cursor; - /* make sure, searching further will extend the match */ - if (VIsual_active) { - if (forward) - incl(&pos); - else - decl(&pos); + // Searching further will extend the match. + if (forward) { + incl(&pos); + } else { + decl(&pos); } - } else + } else { orig_pos = pos = curwin->w_cursor; + } /* Is the pattern is zero-width? */ int one_char = is_one_char(spats[last_idx].pat, true); From 2cdf9d1388ee82dd2d326e45122f47e9d6fbc673 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 19:47:45 +0300 Subject: [PATCH 077/103] search: Fix PVS/V560: condition checked in previous if with goto --- src/nvim/search.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/nvim/search.c b/src/nvim/search.c index 3b726b6d08..b252612e5d 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -3396,11 +3396,13 @@ again: goto again; } - if (do_include || r < 1) { - /* Include up to the '>'. */ - while (*get_cursor_pos_ptr() != '>') - if (inc_cursor() < 0) + if (do_include) { + // Include up to the '>'. + while (*get_cursor_pos_ptr() != '>') { + if (inc_cursor() < 0) { break; + } + } } else { char_u *c = get_cursor_pos_ptr(); // Exclude the '<' of the end tag. From 9f3e67a8148f80532ecb70a97f6f96e7404d3ca6 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 19:50:13 +0300 Subject: [PATCH 078/103] search: Fix PVS/V547: allocator never returns NULL now --- src/nvim/search.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/nvim/search.c b/src/nvim/search.c index b252612e5d..84782497a0 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -1493,38 +1493,34 @@ static int check_prevcol(char_u *linep, int col, int ch, int *prevcol) * Raw string start is found at linep[startpos.col - 1]. * Return true if the matching end can be found between startpos and endpos. */ -static int find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos) +static bool find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos) { char_u *p; char_u *delim_copy; size_t delim_len; linenr_T lnum; - int found = false; - for (p = linep + startpos->col + 1; *p && *p != '('; ++p) {} + for (p = linep + startpos->col + 1; *p && *p != '('; p++) {} delim_len = (p - linep) - startpos->col - 1; delim_copy = vim_strnsave(linep + startpos->col + 1, delim_len); - if (delim_copy == NULL) - return false; - for (lnum = startpos->lnum; lnum <= endpos->lnum; ++lnum) - { + bool found = false; + for (lnum = startpos->lnum; lnum <= endpos->lnum; lnum++) { char_u *line = ml_get(lnum); - for (p = line + (lnum == startpos->lnum - ? startpos->col + 1 : 0); *p; ++p) - { - if (lnum == endpos->lnum && (colnr_T)(p - line) >= endpos->col) + for (p = line + (lnum == startpos->lnum ? startpos->col + 1 : 0); *p; p++) { + if (lnum == endpos->lnum && (colnr_T)(p - line) >= endpos->col) { break; + } if (*p == ')' && p[delim_len + 1] == '"' - && STRNCMP(delim_copy, p + 1, delim_len) == 0) - { + && STRNCMP(delim_copy, p + 1, delim_len) == 0) { found = true; break; } } - if (found) + if (found) { break; + } } xfree(delim_copy); return found; From 60577eeaf5b7a542e7f7004bb0cd9a48b294c37d Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 19:53:06 +0300 Subject: [PATCH 079/103] spell: Fix PVS/V512: use of sprintf() --- src/nvim/spell.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 34eb2fdf1b..84aeeda2bf 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -7368,16 +7368,24 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat, int *dir, int d if ((flags & (WF_BANNED | WF_RARE | WF_REGION)) || keepcap) { STRCPY(badword, p); STRCAT(badword, "/"); - if (keepcap) + if (keepcap) { STRCAT(badword, "="); - if (flags & WF_BANNED) + } + if (flags & WF_BANNED) { STRCAT(badword, "!"); - else if (flags & WF_RARE) + } else if (flags & WF_RARE) { STRCAT(badword, "?"); - if (flags & WF_REGION) - for (i = 0; i < 7; ++i) - if (flags & (0x10000 << i)) - sprintf((char *)badword + STRLEN(badword), "%d", i + 1); + } + if (flags & WF_REGION) { + for (i = 0; i < 7; i++) { + if (flags & (0x10000 << i)) { + const size_t badword_len = STRLEN(badword); + snprintf((char *)badword + badword_len, + sizeof(badword) - badword_len, + "%d", i + 1); + } + } + } p = badword; } From 0ba2ec0bae0653e10cd8ba2e2a7bc920b05b4849 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 19:54:40 +0300 Subject: [PATCH 080/103] spellfile: Fix PVS/V560: allocator never returns NULL now --- src/nvim/spellfile.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index f5d5d408a1..318d289ce8 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -3761,6 +3761,7 @@ static void free_blocks(sblock_T *bl) // Allocate the root of a word tree. // Returns NULL when out of memory. static wordnode_T *wordtree_alloc(spellinfo_T *spin) + FUNC_ATTR_NONNULL_RET { return (wordnode_T *)getroom(spin, sizeof(wordnode_T), true); } @@ -5183,12 +5184,6 @@ mkspell ( spin.si_foldroot = wordtree_alloc(&spin); spin.si_keeproot = wordtree_alloc(&spin); spin.si_prefroot = wordtree_alloc(&spin); - if (spin.si_foldroot == NULL - || spin.si_keeproot == NULL - || spin.si_prefroot == NULL) { - free_blocks(spin.si_blocks); - goto theend; - } // When not producing a .add.spl file clear the character table when // we encounter one in the .aff file. This means we dump the current From f45df710816a94990d77a14ee07744a88aa762d7 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 19:57:36 +0300 Subject: [PATCH 081/103] spellfile: Fix PVS/V547: allocator never returns NULL now --- src/nvim/spellfile.c | 62 ++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 318d289ce8..afedde96ac 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -1949,7 +1949,6 @@ static void spell_print_tree(wordnode_T *root) static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) { FILE *fd; - afffile_T *aff; char_u rline[MAXLINELEN]; char_u *line; char_u *pc = NULL; @@ -2006,11 +2005,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) do_mapline = GA_EMPTY(&spin->si_map); // Allocate and init the afffile_T structure. - aff = (afffile_T *)getroom(spin, sizeof(afffile_T), true); - if (aff == NULL) { - fclose(fd); - return NULL; - } + afffile_T *aff = getroom(spin, sizeof(*aff), true); hash_init(&aff->af_pref); hash_init(&aff->af_suff); hash_init(&aff->af_comp); @@ -2098,20 +2093,18 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) smsg(_("FLAG after using flags in %s line %d: %s"), fname, lnum, items[1]); } else if (spell_info_item(items[0]) && itemcnt > 1) { - p = (char_u *)getroom(spin, - (spin->si_info == NULL ? 0 : STRLEN(spin->si_info)) - + STRLEN(items[0]) - + STRLEN(items[1]) + 3, false); - if (p != NULL) { - if (spin->si_info != NULL) { - STRCPY(p, spin->si_info); - STRCAT(p, "\n"); - } - STRCAT(p, items[0]); - STRCAT(p, " "); - STRCAT(p, items[1]); - spin->si_info = p; + p = getroom(spin, + (spin->si_info == NULL ? 0 : STRLEN(spin->si_info)) + + STRLEN(items[0]) + + STRLEN(items[1]) + 3, false); + if (spin->si_info != NULL) { + STRCPY(p, spin->si_info); + STRCAT(p, "\n"); } + STRCAT(p, items[0]); + STRCAT(p, " "); + STRCAT(p, items[1]); + spin->si_info = p; } else if (is_aff_rule(items, itemcnt, "MIDWORD", 2) && midword == NULL) { midword = getroom_save(spin, items[1]); @@ -2291,14 +2284,12 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) fname, lnum, items[1]); } else { // New affix letter. - cur_aff = (affheader_T *)getroom(spin, - sizeof(affheader_T), true); - if (cur_aff == NULL) - break; + cur_aff = getroom(spin, sizeof(*cur_aff), true); cur_aff->ah_flag = affitem2flag(aff->af_flagtype, items[1], - fname, lnum); - if (cur_aff->ah_flag == 0 || STRLEN(items[1]) >= AH_KEY_LEN) + fname, lnum); + if (cur_aff->ah_flag == 0 || STRLEN(items[1]) >= AH_KEY_LEN) { break; + } if (cur_aff->ah_flag == aff->af_bad || cur_aff->ah_flag == aff->af_rare || cur_aff->ah_flag == aff->af_keepcase @@ -2306,11 +2297,12 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) || cur_aff->ah_flag == aff->af_circumfix || cur_aff->ah_flag == aff->af_nosuggest || cur_aff->ah_flag == aff->af_needcomp - || cur_aff->ah_flag == aff->af_comproot) + || cur_aff->ah_flag == aff->af_comproot) { smsg(_("Affix also used for " "BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST" "in %s line %d: %s"), - fname, lnum, items[1]); + fname, lnum, items[1]); + } STRCPY(cur_aff->ah_key, items[1]); hash_add(tp, cur_aff->ah_key); @@ -2372,11 +2364,11 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) smsg(_(e_afftrailing), fname, lnum, items[lasti]); // New item for an affix letter. - --aff_todo; - aff_entry = (affentry_T *)getroom(spin, - sizeof(affentry_T), true); - if (aff_entry == NULL) + aff_todo--; + aff_entry = getroom(spin, sizeof(*aff_entry), true); + if (aff_entry == NULL) { break; + } if (STRCMP(items[2], "0") != 0) aff_entry->ae_chop = getroom_save(spin, items[2]); @@ -3737,12 +3729,8 @@ static void *getroom(spellinfo_T *spin, size_t len, bool align) // Returns NULL when out of memory. static char_u *getroom_save(spellinfo_T *spin, char_u *s) { - char_u *sc; - - sc = (char_u *)getroom(spin, STRLEN(s) + 1, false); - if (sc != NULL) - STRCPY(sc, s); - return sc; + const size_t s_size = STRLEN(s) + 1; + return memcpy(getroom(spin, s_size, false), s, s_size); } From fb0c35105f96a9fc401a00667f899560793ba417 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:02:28 +0300 Subject: [PATCH 082/103] spellfile: Silence PVS/V547: expression may be true on other systems --- src/nvim/spellfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index afedde96ac..0eca7bbdf8 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -1644,7 +1644,7 @@ spell_read_tree ( if (len < 0) { return SP_TRUNCERROR; } - if ((size_t)len >= SIZE_MAX / sizeof(int)) { + if ((size_t)len >= SIZE_MAX / sizeof(int)) { // -V547 // Invalid length, multiply with sizeof(int) would overflow. return SP_FORMERROR; } From b9b17a58da0e57ab32302ca6c7183a7cad88c7ee Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:03:43 +0300 Subject: [PATCH 083/103] strings: Fix PVS/V779: wrong assert() position --- src/nvim/strings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/strings.c b/src/nvim/strings.c index e3f6a8cbf6..e9eeca48b8 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -1145,8 +1145,8 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap, f, uarg); break; } - assert(str_arg_l < sizeof(tmp)); } + assert(str_arg_l < sizeof(tmp)); // include the optional minus sign and possible "0x" in the region // before the zero padding insertion point From 0eaecbaf47704b8b0b108dd44ad949f3cc9cf501 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:05:32 +0300 Subject: [PATCH 084/103] strings: Fix PVS/V547: condition already checked by surrounding if --- src/nvim/strings.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/nvim/strings.c b/src/nvim/strings.c index e9eeca48b8..b3a0e4816b 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -1376,16 +1376,14 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap, } // insert zero padding as requested by precision or min field width - if (number_of_zeros_to_pad > 0) { - size_t zn = number_of_zeros_to_pad; - if (str_avail) { - size_t avail = str_m - str_l; - memset(str + str_l, '0', MIN(zn, avail)); - str_avail = zn < avail; - } - assert(zn <= SIZE_MAX - str_l); - str_l += zn; + size_t zn = number_of_zeros_to_pad; + if (str_avail) { + size_t avail = str_m - str_l; + memset(str + str_l, '0', MIN(zn, avail)); + str_avail = zn < avail; } + assert(zn <= SIZE_MAX - str_l); + str_l += zn; } // insert formatted string From 5ba267722cb99b91fedaeae28cc6054072add5c8 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:06:35 +0300 Subject: [PATCH 085/103] syntax: Fix PVS/V560: condition checked in previous if() --- src/nvim/syntax.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 2613c09c19..261952cb7c 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -5721,13 +5721,9 @@ int syn_get_id( { // When the position is not after the current position and in the same // line of the same buffer, need to restart parsing. - if (wp->w_buffer != syn_buf - || lnum != current_lnum - || col < current_col) { + if (wp->w_buffer != syn_buf || lnum != current_lnum || col < current_col) { syntax_start(wp, lnum); - } else if (wp->w_buffer == syn_buf - && lnum == current_lnum - && col > current_col) { + } else if (lnum == current_lnum && col > current_col) { // next_match may not be correct when moving around, e.g. with the // "skip" expression in searchpair() next_match_idx = -1; From 2a951d16a42216c71c78f42b2de7343b116497e0 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:08:49 +0300 Subject: [PATCH 086/103] syntax: Silence PVS/V522: retval is always non-NULL on this round --- src/nvim/syntax.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 261952cb7c..8168ace6f6 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -5321,18 +5321,19 @@ get_id_list ( for (int i = highlight_ga.ga_len; --i >= 0; ) { if (vim_regexec(®match, HL_TABLE()[i].sg_name, (colnr_T)0)) { if (round == 2) { - /* Got more items than expected; can happen - * when adding items that match: - * "contains=a.*b,axb". - * Go back to first round */ + // Got more items than expected; can happen + // when adding items that match: + // "contains=a.*b,axb". + // Go back to first round. if (count >= total_count) { xfree(retval); round = 1; - } else - retval[count] = i + 1; + } else { + retval[count] = i + 1; // -V522 + } } - ++count; - id = -1; /* remember that we found one */ + count++; + id = -1; // Remember that we found one. } } vim_regfree(regmatch.regprog); @@ -5346,12 +5347,13 @@ get_id_list ( } if (id > 0) { if (round == 2) { - /* Got more items than expected, go back to first round */ + // Got more items than expected, go back to first round. if (count >= total_count) { xfree(retval); round = 1; - } else + } else { retval[count] = id; + } } ++count; } From e724667ef47e187a1115532d866af1dada4f24ae Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:12:23 +0300 Subject: [PATCH 087/103] syntax: Silence PVS/V560: condition is always true at that point --- src/nvim/syntax.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 8168ace6f6..65ae38718e 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -4549,20 +4549,21 @@ syn_cmd_region ( ++key_end; xfree(key); key = vim_strnsave_up(rest, (int)(key_end - rest)); - if (STRCMP(key, "MATCHGROUP") == 0) + if (STRCMP(key, "MATCHGROUP") == 0) { item = ITEM_MATCHGROUP; - else if (STRCMP(key, "START") == 0) + } else if (STRCMP(key, "START") == 0) { item = ITEM_START; - else if (STRCMP(key, "END") == 0) + } else if (STRCMP(key, "END") == 0) { item = ITEM_END; - else if (STRCMP(key, "SKIP") == 0) { - if (pat_ptrs[ITEM_SKIP] != NULL) { /* one skip pattern allowed */ + } else if (STRCMP(key, "SKIP") == 0) { + if (pat_ptrs[ITEM_SKIP] != NULL) { // One skip pattern allowed. illegal = TRUE; break; } item = ITEM_SKIP; - } else + } else { break; + } rest = skipwhite(key_end); if (*rest != '=') { rest = NULL; @@ -4598,21 +4599,23 @@ syn_cmd_region ( pat_ptrs[item] = ppp; ppp->pp_synp = xcalloc(1, sizeof(synpat_T)); - /* - * Get the syntax pattern and the following offset(s). - */ - /* Enable the appropriate \z specials. */ - if (item == ITEM_START) + // Get the syntax pattern and the following offset(s). + + // Enable the appropriate \z specials. + if (item == ITEM_START) { reg_do_extmatch = REX_SET; - else if (item == ITEM_SKIP || item == ITEM_END) + } else { + assert(item == ITEM_SKIP || item == ITEM_END); reg_do_extmatch = REX_USE; + } rest = get_syn_pattern(rest, ppp->pp_synp); reg_do_extmatch = 0; if (item == ITEM_END && vim_regcomp_had_eol() - && !(syn_opt_arg.flags & HL_EXCLUDENL)) + && !(syn_opt_arg.flags & HL_EXCLUDENL)) { ppp->pp_synp->sp_flags |= HL_HAS_EOL; + } ppp->pp_matchgroup_id = matchgroup_id; - ++pat_count; + pat_count++; } } xfree(key); From 3f4ec1aed22d9088e6f300b0c760533652ab3804 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:13:55 +0300 Subject: [PATCH 088/103] syntax: Fix PVS/V547: condition was checked In surrounding if() `off` was checked for being non-zero and in previous if() it was checked for being positive. --- src/nvim/syntax.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 65ae38718e..577d9f497c 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -2825,9 +2825,10 @@ syn_add_end_off ( if (off > 0) { while (off-- > 0 && *p != NUL) mb_ptr_adv(p); - } else if (off < 0) { - while (off++ < 0 && base < p) + } else { + while (off++ < 0 && base < p) { mb_ptr_back(base, p); + } } col = (int)(p - base); } @@ -2870,11 +2871,13 @@ syn_add_start_off ( base = ml_get_buf(syn_buf, result->lnum, FALSE); p = base + col; if (off > 0) { - while (off-- && *p != NUL) + while (off-- && *p != NUL) { mb_ptr_adv(p); - } else if (off < 0) { - while (off++ && base < p) + } + } else { + while (off++ && base < p) { mb_ptr_back(base, p); + } } col = (int)(p - base); } From 9da2e7b0211d511720dacaf380280d73c705dbf3 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:15:19 +0300 Subject: [PATCH 089/103] syntax: Fix PVS/V560: condition was checked in previous if(), breaking --- src/nvim/syntax.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 577d9f497c..e229a1f428 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -451,9 +451,10 @@ void syntax_start(win_T *wp, linenr_T lnum) if (INVALID_STATE(¤t_state) && syn_block->b_sst_array != NULL) { /* Find last valid saved state before start_lnum. */ for (p = syn_block->b_sst_first; p != NULL; p = p->sst_next) { - if (p->sst_lnum > lnum) + if (p->sst_lnum > lnum) { break; - if (p->sst_lnum <= lnum && p->sst_change_lnum == 0) { + } + if (p->sst_change_lnum == 0) { last_valid = p; if (p->sst_lnum >= lnum - syn_block->b_syn_sync_minlines) last_min_valid = p; From f9b728e2f8d2c1d47325c5152f1d11a2ae22f1f8 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:16:58 +0300 Subject: [PATCH 090/103] tui: Silence PVS/V560: condition is set to true in prev-previous if() --- src/nvim/tui/tui.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index dcb1f850b7..57c7e29c1e 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1770,7 +1770,8 @@ static void flush_buf(UI *ui) bufp++; } - if (!data->busy && data->is_invisible) { + if (!data->busy) { + assert(data->is_invisible); // not busy and the cursor is invisible. Write a "cursor normal" command // after writing the buffer. bufp->base = data->norm; From f50670aeff0f9302fd4a56acef7465715c18b868 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:18:29 +0300 Subject: [PATCH 091/103] ugrid: Silence PVS/V625: UGRID_FOREACH_CELL may be used for one row --- src/nvim/ugrid.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nvim/ugrid.h b/src/nvim/ugrid.h index 60c9068eb1..035074846e 100644 --- a/src/nvim/ugrid.h +++ b/src/nvim/ugrid.h @@ -23,6 +23,8 @@ struct ugrid { UCell **cells; }; +// -V:UGRID_FOREACH_CELL:625 + #define UGRID_FOREACH_CELL(grid, top, bot, left, right, code) \ do { \ for (int row = top; row <= bot; row++) { \ From 6c2b442ee094bef944207b94fcedbc7dbd7dc166 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:20:53 +0300 Subject: [PATCH 092/103] eval/typval: Silence PVS/V576: format is correct --- src/nvim/eval/typval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index c8b550f902..7930653be0 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -2825,7 +2825,7 @@ const char *tv_get_string_buf_chk(const typval_T *const tv, char *const buf) { switch (tv->v_type) { case VAR_NUMBER: { - snprintf(buf, NUMBUFLEN, "%" PRIdVARNUMBER, tv->vval.v_number); + snprintf(buf, NUMBUFLEN, "%" PRIdVARNUMBER, tv->vval.v_number); // -V576 return buf; } case VAR_STRING: { From 43df2edd20c8f7cfb96c6d0b61a0d2e34e921133 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:21:55 +0300 Subject: [PATCH 093/103] ui_bridge: Silence PVS/V547: assuming stopped may be changed via ptr --- src/nvim/ui_bridge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c index 56e0c0c454..a8bbeea035 100644 --- a/src/nvim/ui_bridge.c +++ b/src/nvim/ui_bridge.c @@ -116,7 +116,7 @@ static void ui_bridge_stop(UI *b) uv_mutex_lock(&bridge->mutex); stopped = bridge->stopped; uv_mutex_unlock(&bridge->mutex); - if (stopped) { + if (stopped) { // -V547 break; } loop_poll_events(&main_loop, 10); // Process one event. From a90672fc3d571ce22711dd42b836faaddba0f76b Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:22:46 +0300 Subject: [PATCH 094/103] undo: Silence PVS/V547: expression may be false on other system --- src/nvim/undo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 35857510fc..e1ae4b4cc0 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -972,7 +972,7 @@ static u_entry_T *unserialize_uep(bufinfo_T * bi, bool *error, char_u **array = NULL; if (uep->ue_size > 0) { - if ((size_t)uep->ue_size < SIZE_MAX / sizeof(char_u *)) { + if ((size_t)uep->ue_size < SIZE_MAX / sizeof(char_u *)) { // -V547 array = xmalloc(sizeof(char_u *) * (size_t)uep->ue_size); memset(array, 0, sizeof(char_u *) * (size_t)uep->ue_size); } @@ -1404,7 +1404,7 @@ void u_read_undo(char *name, char_u *hash, char_u *orig_name) // sequence numbers of the headers. // When there are no headers uhp_table is NULL. if (num_head > 0) { - if ((size_t)num_head < SIZE_MAX / sizeof(*uhp_table)) { + if ((size_t)num_head < SIZE_MAX / sizeof(*uhp_table)) { // -V547 uhp_table = xmalloc((size_t)num_head * sizeof(*uhp_table)); } } From d9c010e45d5078b98bebb031a3583489c9e8bd32 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:23:50 +0300 Subject: [PATCH 095/103] =?UTF-8?q?api/vim:=20Fix=20PVS/V547:=20node=20was?= =?UTF-8?q?=20already=20dereferenced,=20so=20can=E2=80=99t=20be=20NULL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 962081cc23..86827224b7 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1198,7 +1198,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, .node_p = &node->next, .ret_node_p = cur_item.ret_node_p + 1, })); - } else if (node != NULL) { + } else { kv_drop(ast_conv_stack, 1); ret_node->items[ret_node->size++] = (KeyValuePair) { .key = STATIC_CSTR_TO_STRING("type"), From c8648daab38987aa3351fff95273cea7be7b5477 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:24:57 +0300 Subject: [PATCH 096/103] window: Silence PVS/V547: height may be changed by curwin ptr --- src/nvim/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/window.c b/src/nvim/window.c index b4ef901d94..ee55bfe0f2 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -4807,7 +4807,7 @@ void win_new_height(win_T *wp, int height) // call win_new_height() recursively. validate_cursor(); } - if (wp->w_height != prev_height) { + if (wp->w_height != prev_height) { // -V547 return; // Recursive call already changed the size, bail out. } if (wp->w_wrow != wp->w_prev_fraction_row) { From 4b41680828c8f629617d90e3c17ff229a44b32d4 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:25:44 +0300 Subject: [PATCH 097/103] window: Fix PVS/V547: expression already checked in previous if() --- src/nvim/window.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/nvim/window.c b/src/nvim/window.c index ee55bfe0f2..82fffe305c 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -4466,8 +4466,7 @@ static void frame_setwidth(frame_T *curfrp, int width) if (width <= room) break; if (run == 2 || curfrp->fr_height >= ROWS_AVAIL) { - if (width > room) - width = room; + width = room; break; } frame_setwidth(curfrp->fr_parent, width From 4bab9d34e6ec8801d36e2c8594d2122fc45e8db2 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:31:40 +0300 Subject: [PATCH 098/103] *: Fix clint errors --- src/nvim/buffer.c | 4 ++-- src/nvim/charset.c | 2 +- src/nvim/ex_cmds.c | 8 ++++---- src/nvim/ex_getln.c | 4 ++-- src/nvim/fileio.c | 2 +- src/nvim/ops.c | 1 - src/nvim/os/env.c | 4 ++-- src/nvim/quickfix.c | 2 +- src/nvim/screen.c | 2 +- src/nvim/syntax.c | 2 +- src/nvim/tui/tui.c | 3 +-- 11 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index a4ba30337d..ba63822837 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2918,7 +2918,7 @@ void maketitle(void) int save_called_emsg = called_emsg; use_sandbox = was_set_insecurely((char_u *)"titlestring", 0); - called_emsg = FALSE; + called_emsg = false; build_stl_str_hl(curwin, (char_u *)buf, sizeof(buf), p_titlestring, use_sandbox, 0, maxlen, NULL, NULL); @@ -3005,7 +3005,7 @@ void maketitle(void) append_arg_number(curwin, (char_u *)buf_p, (int)(SPACE_FOR_ARGNR - (size_t)(buf_p - buf)), false); - strcat(buf_p, " - NVIM"); + xstrlcat(buf_p, " - NVIM", (sizeof(buf) - (size_t)(buf_p - buf))); if (maxlen > 0) { // Make it shorter by removing a bit in the middle. diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 9c1dc9f4a2..7d5f80c531 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -543,7 +543,7 @@ char_u *transchar(int c) // printable character transchar_buf[i] = (char_u)c; transchar_buf[i + 1] = NUL; - } else if (c <= 0xFF){ + } else if (c <= 0xFF) { transchar_nonprint(transchar_buf + i, c); } else { transchar_hex((char *)transchar_buf + i, c); diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index f3b1aa633d..f575d58f05 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -178,10 +178,10 @@ void do_ascii(const exarg_T *const eap) } iobuff_len += utf_char2bytes(c, IObuff + iobuff_len); iobuff_len += ( - vim_snprintf((char *)IObuff + iobuff_len, sizeof(IObuff) - iobuff_len, - (c < 0x10000 - ? _("> %d, Hex %04x, Octal %o") - : _("> %d, Hex %08x, Octal %o")), c, c, c)); + vim_snprintf((char *)IObuff + iobuff_len, sizeof(IObuff) - iobuff_len, + (c < 0x10000 + ? _("> %d, Hex %04x, Octal %o") + : _("> %d, Hex %08x, Octal %o")), c, c, c)); if (ci == MAX_MCO) { break; } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index a7efe5f533..e1198d6f1c 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -4851,10 +4851,10 @@ void ExpandGeneric( count = 0; for (i = 0;; i++) { str = (*func)(xp, i); - if (str == NULL) { // end of list + if (str == NULL) { // End of list. break; } - if (*str == NUL) { // skip empty strings + if (*str == NUL) { // Skip empty strings. continue; } if (vim_regexec(regmatch, str, (colnr_T)0)) { diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 451f924c28..c34b52cf27 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -286,7 +286,7 @@ readfile ( off_T filesize = 0; int skip_read = false; context_sha256_T sha_ctx; - int read_undo_file = FALSE; + int read_undo_file = false; linenr_T linecnt; int error = FALSE; /* errors encountered */ int ff_error = EOL_UNKNOWN; /* file format with errors */ diff --git a/src/nvim/ops.c b/src/nvim/ops.c index c4790653b8..b39b139f9b 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -3595,7 +3595,6 @@ int do_join(size_t count, // We don't want to remove the comment leader if the // previous line is not a comment. if (t > 0 && prev_was_comment) { - char_u *new_curr = skip_comment(curr, true, insert_space, &prev_was_comment); comments[t] = (int)(new_curr - curr); diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 096a90cb21..7fb4a93b54 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -822,11 +822,11 @@ size_t home_replace(const buf_T *const buf, const char_u *src, // if (!one) skip to separator: space or comma. while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0) { - *dst_p++ = (char)*src++; + *dst_p++ = (char)(*src++); } // Skip separator. while ((*src == ' ' || *src == ',') && --dstlen > 0) { - *dst_p++ = (char)*src++; + *dst_p++ = (char)(*src++); } } // If (dstlen == 0) out of space, what to do??? diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index cbab8eb05b..fb7a9ecf5f 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -4738,7 +4738,7 @@ void ex_helpgrep(exarg_T *eap) regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING); regmatch.rm_ic = FALSE; if (regmatch.regprog != NULL) { - /* create a new quickfix list */ + // Create a new quickfix list. qf_new_list(qi, *eap->cmdlinep); /* Go through all directories in 'runtimepath' */ diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 8f2b7b1f04..6dbba30cf2 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -6367,7 +6367,7 @@ static void linecopy(int to, int from, win_T *wp) wp->w_width * sizeof(ScreenLines[0])); memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from, - wp->w_width * sizeof(u8char_T)); + wp->w_width * sizeof(ScreenLinesUC[0])); for (int i = 0; i < p_mco; i++) { memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from, wp->w_width * sizeof(ScreenLinesC[0])); diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index e229a1f428..55992f8785 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -4561,7 +4561,7 @@ syn_cmd_region ( item = ITEM_END; } else if (STRCMP(key, "SKIP") == 0) { if (pat_ptrs[ITEM_SKIP] != NULL) { // One skip pattern allowed. - illegal = TRUE; + illegal = true; break; } item = ITEM_SKIP; diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 57c7e29c1e..87f3cc2354 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -605,8 +605,7 @@ static void cursor_goto(UI *ui, int row, int col) int n = col - grid->col; if (n <= (row == grid->row ? 4 : 2) && cheap_to_print(ui, grid->row, grid->col, n)) { - UGRID_FOREACH_CELL(grid, grid->row, grid->row, - grid->col, col - 1, { + UGRID_FOREACH_CELL(grid, grid->row, grid->row, grid->col, col - 1, { print_cell(ui, cell); }); } From 03c2844b539179b918d7128ac78e6d42af613f2d Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:32:25 +0300 Subject: [PATCH 099/103] functests: Fix testlint errors --- test/functional/eval/uniq_spec.lua | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/functional/eval/uniq_spec.lua b/test/functional/eval/uniq_spec.lua index 5217034d81..0e7a013e32 100644 --- a/test/functional/eval/uniq_spec.lua +++ b/test/functional/eval/uniq_spec.lua @@ -1,11 +1,8 @@ local helpers = require('test.functional.helpers')(after_each) local eq = helpers.eq -local NIL = helpers.NIL -local eval = helpers.eval local clear = helpers.clear local meths = helpers.meths -local funcs = helpers.funcs local command = helpers.command local exc_exec = helpers.exc_exec local redir_exec = helpers.redir_exec From 76c2a60ff3c4befd71fa5ec0f20bed7049ff3bd9 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:33:42 +0300 Subject: [PATCH 100/103] spellfile: Fix PVS/V547: allocator now never returns NULL --- src/nvim/spellfile.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 0eca7bbdf8..4e26bfa6f8 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -2366,9 +2366,6 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) // New item for an affix letter. aff_todo--; aff_entry = getroom(spin, sizeof(*aff_entry), true); - if (aff_entry == NULL) { - break; - } if (STRCMP(items[2], "0") != 0) aff_entry->ae_chop = getroom_save(spin, items[2]); @@ -2843,9 +2840,7 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compfla if (!HASHITEM_EMPTY(hi)) id = HI2CI(hi)->ci_newID; else { - ci = (compitem_T *)getroom(spin, sizeof(compitem_T), true); - if (ci == NULL) - break; + ci = getroom(spin, sizeof(compitem_T), true); STRCPY(ci->ci_key, key); ci->ci_flag = flag; // Avoid using a flag ID that has a special meaning in a @@ -4783,8 +4778,6 @@ static int sug_filltree(spellinfo_T *spin, slang_T *slang) // We use si_foldroot for the soundfolded trie. spin->si_foldroot = wordtree_alloc(spin); - if (spin->si_foldroot == NULL) - return FAIL; // Let tree_add_word() know we're adding to the soundfolded tree spin->si_sugtree = true; From 953d167015c3346e36d8be0b181a07123af883ce Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:34:32 +0300 Subject: [PATCH 101/103] syntax: Fix PVS/V560: condition was already checked --- src/nvim/syntax.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 55992f8785..26de519f3c 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -5732,7 +5732,7 @@ int syn_get_id( // line of the same buffer, need to restart parsing. if (wp->w_buffer != syn_buf || lnum != current_lnum || col < current_col) { syntax_start(wp, lnum); - } else if (lnum == current_lnum && col > current_col) { + } else if (col > current_col) { // next_match may not be correct when moving around, e.g. with the // "skip" expression in searchpair() next_match_idx = -1; From a37819dbb1d56d002726345b84febc576b80c9f4 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:35:17 +0300 Subject: [PATCH 102/103] spellfile: Fix clint error --- src/nvim/spellfile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 4e26bfa6f8..dab9a2aacd 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -2837,9 +2837,9 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compfla // the existing ID. Otherwise add a new entry. STRLCPY(key, prevp, p - prevp + 1); hi = hash_find(&aff->af_comp, key); - if (!HASHITEM_EMPTY(hi)) + if (!HASHITEM_EMPTY(hi)) { id = HI2CI(hi)->ci_newID; - else { + } else { ci = getroom(spin, sizeof(compitem_T), true); STRCPY(ci->ci_key, key); ci->ci_flag = flag; From 4ce8521ee4a72e050bd187c2986708c5f98c7442 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 22 Apr 2018 20:54:17 +0300 Subject: [PATCH 103/103] pvscheck: Disable V011 warning --- scripts/pvscheck.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/pvscheck.sh b/scripts/pvscheck.sh index 62051b191d..11b672c515 100755 --- a/scripts/pvscheck.sh +++ b/scripts/pvscheck.sh @@ -365,10 +365,11 @@ run_analysis() {( --sourcetree-root . || true rm -rf PVS-studio.{xml,err,tsk,html.d} - plog-converter -r . -t xml -o PVS-studio.xml PVS-studio.log - plog-converter -r . -t errorfile -o PVS-studio.err PVS-studio.log - plog-converter -r . -t tasklist -o PVS-studio.tsk PVS-studio.log - plog-converter -r . -t fullhtml -o PVS-studio.html.d PVS-studio.log + local plog_args="PVS-studio.log --srcRoot . --excludedCodes V011" + plog-converter $plog_args --renderTypes xml --output PVS-studio.xml + plog-converter $plog_args --renderTypes errorfile --output PVS-studio.err + plog-converter $plog_args --renderTypes tasklist --output PVS-studio.tsk + plog-converter $plog_args --renderTypes fullhtml --output PVS-studio.html.d )} detect_url() {