diff options
| -rw-r--r-- | CMakeLists.txt | 5 | ||||
| -rw-r--r-- | src/nvim/buffer.c | 2 | ||||
| -rw-r--r-- | src/nvim/edit.c | 5 | ||||
| -rw-r--r-- | src/nvim/eval.c | 6 | ||||
| -rw-r--r-- | src/nvim/eval/typval.c | 2 | ||||
| -rw-r--r-- | src/nvim/ex_cmds.c | 8 | ||||
| -rw-r--r-- | src/nvim/ex_getln.c | 3 | ||||
| -rw-r--r-- | src/nvim/func_attr.h | 11 | ||||
| -rw-r--r-- | src/nvim/macros.h | 18 | ||||
| -rw-r--r-- | src/nvim/normal.c | 1 | ||||
| -rw-r--r-- | src/nvim/os_unix.c | 2 | ||||
| -rw-r--r-- | src/nvim/regexp_nfa.c | 5 | ||||
| -rw-r--r-- | src/nvim/shada.c | 2 | ||||
| -rw-r--r-- | src/nvim/testdir/runtest.vim | 2 | ||||
| -rw-r--r-- | test/functional/ex_cmds/script_spec.lua | 75 | ||||
| -rw-r--r-- | test/functional/helpers.lua | 14 | ||||
| -rw-r--r-- | test/functional/legacy/036_regexp_character_classes_spec.lua | 12 | ||||
| -rw-r--r-- | test/functional/provider/python3_spec.lua | 8 | ||||
| -rw-r--r-- | test/functional/provider/python_spec.lua | 8 | ||||
| -rw-r--r-- | test/functional/provider/ruby_spec.lua | 6 | 
20 files changed, 170 insertions, 25 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 44784b042f..b8c6c6055c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,6 +221,11 @@ else()    add_definitions(-Wall -Wextra -pedantic -Wno-unused-parameter      -Wstrict-prototypes -std=gnu99) +  check_c_compiler_flag(-Wimplicit-fallthrough HAS_WIMPLICIT_FALLTHROUGH_FLAG) +  if(HAS_WIMPLICIT_FALLTHROUGH_FLAG) +    add_definitions(-Wimplicit-fallthrough) +  endif() +    # On FreeBSD 64 math.h uses unguarded C11 extension, which taints clang    # 3.4.1 used there.    if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index f54979eb1e..e3897e3929 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -3607,6 +3607,7 @@ int build_stl_str_hl(      case STL_OFFSET_X:        base = kNumBaseHexadecimal; +      // fallthrough      case STL_OFFSET:      {        long l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL); @@ -3617,6 +3618,7 @@ int build_stl_str_hl(      }      case STL_BYTEVAL_X:        base = kNumBaseHexadecimal; +      // fallthrough      case STL_BYTEVAL:        num = byteval;        if (num == NL) diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 678fa851eb..bfdec90a32 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -4916,14 +4916,17 @@ static unsigned quote_meta(char_u *dest, char_u *src, int len)        if (ctrl_x_mode == CTRL_X_DICTIONARY            || ctrl_x_mode == CTRL_X_THESAURUS)          break; +      // fallthrough      case '~':        if (!p_magic)             /* quote these only if magic is set */          break; +      // fallthrough      case '\\':        if (ctrl_x_mode == CTRL_X_DICTIONARY            || ctrl_x_mode == CTRL_X_THESAURUS)          break; -    case '^':                   /* currently it's not needed. */ +      // fallthrough +    case '^':                   // currently it's not needed.      case '$':        m++;        if (dest != NULL) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 56a6632fad..31e5ae8806 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -9596,13 +9596,15 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)        if (from) {          break;        } -    case kCdScopeTab:         // FALLTHROUGH +      // fallthrough +    case kCdScopeTab:        assert(tp);        from = tp->tp_localdir;        if (from) {          break;        } -    case kCdScopeGlobal:      // FALLTHROUGH +      // fallthrough +    case kCdScopeGlobal:        if (globaldir) {        // `globaldir` is not always set.          from = globaldir;        } else if (os_dirname(cwd, MAXPATHL) == FAIL) {  // Get the OS CWD. diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 786b766689..19d9d56058 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1869,7 +1869,7 @@ void tv_free(typval_T *tv)        }        case VAR_FUNC: {          func_unref(tv->vval.v_string); -        // FALLTHROUGH +        FALLTHROUGH;        }        case VAR_STRING: {          xfree(tv->vval.v_string); diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 018a228843..a528a65abb 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -4878,8 +4878,9 @@ void fix_help_buffer(void)                    continue;                  e1 = vim_strrchr(t1, '.');                  e2 = vim_strrchr(path_tail(f2), '.'); -                if (e1 == NUL || e2 == NUL) +                if (e1 == NULL || e2 == NULL) {                    continue; +                }                  if (fnamecmp(e1, ".txt") != 0                      && fnamecmp(e1, fname + 4) != 0) {                    /* Not .txt and not .abx, remove it. */ @@ -5949,9 +5950,8 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg)    // :sign define {name} {args}... {last}=    //                               |     |    //                            last     p -  if (p == NUL) -  { -    /* Expand last argument name (before equal sign). */ +  if (p == NULL) { +    // Expand last argument name (before equal sign).      xp->xp_pattern = last;      switch (cmd_idx)      { diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index fe45ba4568..0c14bf4255 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1268,6 +1268,7 @@ static int command_line_handle_key(CommandLineState *s)        }        return command_line_changed(s);      } +    // fallthrough    case K_UP:    case K_DOWN: @@ -5401,7 +5402,7 @@ char *script_get(exarg_T *const eap, size_t *const lenp)    if (cmd[0] != '<' || cmd[1] != '<' || eap->getline == NULL) {      *lenp = STRLEN(eap->arg); -    return xmemdupz(eap->arg, *lenp); +    return eap->skip ? NULL : xmemdupz(eap->arg, *lenp);    }    garray_T ga = { .ga_data = NULL, .ga_len = 0 }; diff --git a/src/nvim/func_attr.h b/src/nvim/func_attr.h index 9146a1a8ea..cc94a41f80 100644 --- a/src/nvim/func_attr.h +++ b/src/nvim/func_attr.h @@ -89,6 +89,10 @@  # undef FUNC_ATTR_NONNULL_RET  #endif +#ifdef FUNC_ATTR_NORETURN +# undef FUNC_ATTR_NORETURN +#endif +  #ifndef DID_REAL_ATTR  # define DID_REAL_ATTR  # ifdef __GNUC__ @@ -107,6 +111,7 @@  #  define REAL_FATTR_UNUSED __attribute__((unused))  #  define REAL_FATTR_NONNULL_ALL __attribute__((nonnull))  #  define REAL_FATTR_NONNULL_ARG(...) __attribute__((nonnull(__VA_ARGS__))) +#  define REAL_FATTR_NORETURN __attribute__((noreturn))  #  ifdef __clang__  // clang only @@ -176,6 +181,10 @@  # ifndef REAL_FATTR_NONNULL_RET  #  define REAL_FATTR_NONNULL_RET  # endif + +# ifndef REAL_FATTR_NORETURN +#  define REAL_FATTR_NORETURN +# endif  #endif  #ifdef DEFINE_FUNC_ATTRIBUTES @@ -196,6 +205,7 @@  # define FUNC_ATTR_NONNULL_ALL REAL_FATTR_NONNULL_ALL  # define FUNC_ATTR_NONNULL_ARG(...) REAL_FATTR_NONNULL_ARG(__VA_ARGS__)  # define FUNC_ATTR_NONNULL_RET REAL_FATTR_NONNULL_RET +# define FUNC_ATTR_NORETURN REAL_FATTR_NORETURN  #elif !defined(DO_NOT_DEFINE_EMPTY_ATTRIBUTES)  # define FUNC_ATTR_MALLOC  # define FUNC_ATTR_ALLOC_SIZE(x) @@ -209,4 +219,5 @@  # define FUNC_ATTR_NONNULL_ALL  # define FUNC_ATTR_NONNULL_ARG(...)  # define FUNC_ATTR_NONNULL_RET +# define FUNC_ATTR_NORETURN  #endif diff --git a/src/nvim/macros.h b/src/nvim/macros.h index 214af82422..9ab6dc5d2b 100644 --- a/src/nvim/macros.h +++ b/src/nvim/macros.h @@ -153,4 +153,22 @@  #define STR_(x) #x  #define STR(x) STR_(x) +#ifndef __has_attribute +# define NVIM_HAS_ATTRIBUTE(x) 0 +#elif defined(__clang__) && __clang__ == 1 \ +    && (__clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ <= 5)) +// Starting in Clang 3.6, __has_attribute was fixed to only report true for +// GNU-style attributes.  Prior to that, it reported true if _any_ backend +// supported the attribute. +# define NVIM_HAS_ATTRIBUTE(x) 0 +#else +# define NVIM_HAS_ATTRIBUTE __has_attribute +#endif + +#if NVIM_HAS_ATTRIBUTE(fallthrough) +# define FALLTHROUGH __attribute__((fallthrough)) +#else +# define FALLTHROUGH +#endif +  #endif  // NVIM_MACROS_H diff --git a/src/nvim/normal.c b/src/nvim/normal.c index f73e3079b9..050020d79d 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -1861,6 +1861,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)        } else {          bangredo = true;  // do_bang() will put cmd in redo buffer.        } +      // fallthrough      case OP_INDENT:      case OP_COLON: diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c index c5a42204be..7cf0d7817c 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -133,7 +133,7 @@ void mch_free_acl(vim_acl_T aclent)  }  #endif -void mch_exit(int r) +void mch_exit(int r) FUNC_ATTR_NORETURN  {    exiting = true; diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index 85fae9d82e..24c156d2ba 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -634,6 +634,7 @@ static int nfa_recognize_char_class(char_u *start, char_u *end, int extra_newl)            config |= CLASS_o7;            break;          } +        return FAIL;        case 'a':          if (*(p + 2) == 'z') {            config |= CLASS_az; @@ -642,6 +643,7 @@ static int nfa_recognize_char_class(char_u *start, char_u *end, int extra_newl)            config |= CLASS_af;            break;          } +        return FAIL;        case 'A':          if (*(p + 2) == 'Z') {            config |= CLASS_AZ; @@ -650,7 +652,7 @@ static int nfa_recognize_char_class(char_u *start, char_u *end, int extra_newl)            config |= CLASS_AF;            break;          } -      /* FALLTHROUGH */ +        return FAIL;        default:          return FAIL;        } @@ -4194,6 +4196,7 @@ skip_add:        subs = addstate(l, state->out, subs, pim, off_arg);        break;      } +    // fallthrough    case NFA_MCLOSE1:    case NFA_MCLOSE2:    case NFA_MCLOSE3: diff --git a/src/nvim/shada.c b/src/nvim/shada.c index a6d8cb6563..e1879ca8c0 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -2047,7 +2047,7 @@ static inline ShaDaWriteResult shada_read_when_writing(        }        case kSDReadStatusNotShaDa: {          ret = kSDWriteReadNotShada; -        // fallthrough +        FALLTHROUGH;        }        case kSDReadStatusReadError: {          return ret; diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim index 64ad0f0103..6832622cdf 100644 --- a/src/nvim/testdir/runtest.vim +++ b/src/nvim/testdir/runtest.vim @@ -134,7 +134,7 @@ else  endif  " Names of flaky tests. -let s:flaky = ['Test_with_partial_callback'] +let s:flaky = ['Test_with_partial_callback()']  " Locate Test_ functions and execute them.  set nomore diff --git a/test/functional/ex_cmds/script_spec.lua b/test/functional/ex_cmds/script_spec.lua new file mode 100644 index 0000000000..4e57d2755d --- /dev/null +++ b/test/functional/ex_cmds/script_spec.lua @@ -0,0 +1,75 @@ +local helpers = require('test.functional.helpers')(after_each) + +local eq = helpers.eq +local neq = helpers.neq +local meths = helpers.meths +local clear = helpers.clear +local dedent = helpers.dedent +local source = helpers.source +local exc_exec = helpers.exc_exec +local missing_provider = helpers.missing_provider + +before_each(clear) + +describe('script_get-based command', function() +  local garbage = ')}{+*({}]*[;(+}{&[]}{*])(' + +  local function test_garbage_exec(cmd, check_neq) +    describe(cmd, function() +      it('works correctly when skipping oneline variant', function() +        eq(true, pcall(source, (dedent([[ +          if 0 +            %s %s +          endif +        ]])):format(cmd, garbage))) +        eq('', meths.command_output('messages')) +        if check_neq then +          neq(0, exc_exec(dedent([[ +            %s %s +          ]])):format(cmd, garbage)) +        end +      end) +      it('works correctly when skipping HEREdoc variant', function() +        eq(true, pcall(source, (dedent([[ +          if 0 +          %s << EOF +          %s +          EOF +          endif +        ]])):format(cmd, garbage))) +        eq('', meths.command_output('messages')) +        if check_neq then +          eq(true, pcall(source, (dedent([[ +            let g:exc = 0 +            try +            %s << EOF +            %s +            EOF +            catch +            let g:exc = v:exception +            endtry +          ]])):format(cmd, garbage))) +          neq(0, meths.get_var('exc')) +        end +      end) +    end) +  end + +  clear() + +  -- Built-in scripts +  test_garbage_exec('lua', true) + +  -- Provider-based scripts +  test_garbage_exec('ruby', not missing_provider('ruby')) +  test_garbage_exec('python', not missing_provider('python')) +  test_garbage_exec('python3', not missing_provider('python3')) + +  -- Missing scripts +  test_garbage_exec('tcl', false) +  test_garbage_exec('mzscheme', false) +  test_garbage_exec('perl', false) + +  -- Not really a script +  test_garbage_exec('xxxinvalidlanguagexxx', true) +end) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 1be70f917c..b03840b3fe 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -566,6 +566,19 @@ local function get_pathsep()    return funcs.fnamemodify('.', ':p'):sub(-1)  end +local function missing_provider(provider) +  if provider == 'ruby' then +    local prog = funcs['provider#' .. provider .. '#Detect']() +    return prog == '' and (provider .. ' not detected') or false +  elseif provider == 'python' or provider == 'python3' then +    local py_major_version = (provider == 'python3' and 3 or 2) +    local errors = funcs['provider#pythonx#Detect'](py_major_version)[2] +    return errors ~= '' and errors or false +  else +    assert(false, 'Unknown provider: ' .. provider) +  end +end +  local module = {    prepend_argv = prepend_argv,    clear = clear, @@ -632,6 +645,7 @@ local module = {    meth_pcall = meth_pcall,    NIL = mpack.NIL,    get_pathsep = get_pathsep, +  missing_provider = missing_provider,  }  return function(after_each) diff --git a/test/functional/legacy/036_regexp_character_classes_spec.lua b/test/functional/legacy/036_regexp_character_classes_spec.lua index 110f7dd852..38e8145d1c 100644 --- a/test/functional/legacy/036_regexp_character_classes_spec.lua +++ b/test/functional/legacy/036_regexp_character_classes_spec.lua @@ -275,4 +275,16 @@ describe('character classes in regexp', function()      diff(sixlines(string.sub(punct1, 1)..digits..punct2..upper..punct3..        lower..punct4..ctrl2..iso_text))    end) +  it('does not convert character class ranges to an incorrect class', function() +    source([[ +      1 s/\%#=0[0-z]//g +      2 s/\%#=1[0-z]//g +      3 s/\%#=2[0-z]//g +      4 s/\%#=0[^0-z]//g +      5 s/\%#=1[^0-z]//g +      6 s/\%#=2[^0-z]//g +    ]]) +    diff(string.rep(ctrl1..punct1..punct4..ctrl2..iso_text..'\n', 3) +      ..string.rep(digits..punct2..upper..punct3..lower..'\n', 3)) +  end)  end) diff --git a/test/functional/provider/python3_spec.lua b/test/functional/provider/python3_spec.lua index 89a546675f..aa50f53451 100644 --- a/test/functional/provider/python3_spec.lua +++ b/test/functional/provider/python3_spec.lua @@ -3,14 +3,14 @@ local eval, command, feed = helpers.eval, helpers.command, helpers.feed  local eq, clear, insert = helpers.eq, helpers.clear, helpers.insert  local expect, write_file = helpers.expect, helpers.write_file  local feed_command = helpers.feed_command +local missing_provider = helpers.missing_provider  do    clear() -  command('let [g:interp, g:errors] = provider#pythonx#Detect(3)') -  local errors = eval('g:errors') -  if errors ~= '' then +  local err = missing_provider('python3') +  if err then      pending( -      'Python 3 (or the Python 3 neovim module) is broken or missing:\n' .. errors, +      'Python 3 (or the Python 3 neovim module) is broken or missing:\n' .. err,        function() end)      return    end diff --git a/test/functional/provider/python_spec.lua b/test/functional/provider/python_spec.lua index 94dfa90ea8..25f5e0a6d0 100644 --- a/test/functional/provider/python_spec.lua +++ b/test/functional/provider/python_spec.lua @@ -12,14 +12,14 @@ local command = helpers.command  local exc_exec = helpers.exc_exec  local write_file = helpers.write_file  local curbufmeths = helpers.curbufmeths +local missing_provider = helpers.missing_provider  do    clear() -  command('let [g:interp, g:errors] = provider#pythonx#Detect(2)') -  local errors = meths.get_var('errors') -  if errors ~= '' then +  local err = missing_provider('python') +  if err then      pending( -      'Python 2 (or the Python 2 neovim module) is broken or missing:\n' .. errors, +      'Python 2 (or the Python 2 neovim module) is broken or missing:\n' .. err,        function() end)      return    end diff --git a/test/functional/provider/ruby_spec.lua b/test/functional/provider/ruby_spec.lua index 7b0e17688d..9f5ef3b3fc 100644 --- a/test/functional/provider/ruby_spec.lua +++ b/test/functional/provider/ruby_spec.lua @@ -10,13 +10,11 @@ local expect = helpers.expect  local command = helpers.command  local write_file = helpers.write_file  local curbufmeths = helpers.curbufmeths +local missing_provider = helpers.missing_provider  do    clear() -  command('let g:prog = provider#ruby#Detect()') -  local prog = meths.get_var('prog') - -  if prog == '' then +  if missing_provider('ruby') then      pending(        "Cannot find the neovim RubyGem. Try :CheckHealth",        function() end)  | 
