0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

patch 8.2.0088: insufficient tests for tags; bug in using extra tag field

Problem:    Insufficient tests for tags; bug in using extra tag field when
            using an ex command to position the cursor.
Solution:   Fix the bug, add more tests. (Yegappan Lakshmanan, closes #5439)
This commit is contained in:
Bram Moolenaar
2020-01-05 20:35:44 +01:00
parent 61d7c0d52c
commit 830c1afc9d
7 changed files with 448 additions and 8 deletions

View File

@@ -344,11 +344,11 @@ the same as above, with a "p" prepended.
A static tag is a tag that is defined for a specific file. In a C program
this could be a static function.
In Vi jumping to a tag sets the current search pattern. This means that
the "n" command after jumping to a tag does not search for the same pattern
that it did before jumping to the tag. Vim does not do this as we consider it
to be a bug. You can still find the tag search pattern in the search history.
If you really want the old Vi behavior, set the 't' flag in 'cpoptions'.
In Vi jumping to a tag sets the current search pattern. This means that the
"n" command after jumping to a tag does not search for the same pattern that
it did before jumping to the tag. Vim does not do this as we consider it to
be a bug. If you really want the old Vi behavior, set the 't' flag in
'cpoptions'.
*tag-binary-search*
Vim uses binary searching in the tags file to find the desired tag quickly
@@ -426,8 +426,7 @@ would otherwise go unnoticed. Example: >
In Vi the ":tag" command sets the last search pattern when the tag is searched
for. In Vim this is not done, the previous search pattern is still remembered,
unless the 't' flag is present in 'cpoptions'. The search pattern is always
put in the search history, so you can modify it if searching fails.
unless the 't' flag is present in 'cpoptions'.
*emacs-tags* *emacs_tags* *E430*
Emacs style tag files are only supported if Vim was compiled with the

View File

@@ -3808,6 +3808,7 @@ test_for_current(
find_extra(char_u **pp)
{
char_u *str = *pp;
char_u first_char = **pp;
// Repeat for addresses separated with ';'
for (;;)
@@ -3817,7 +3818,7 @@ find_extra(char_u **pp)
else if (*str == '/' || *str == '?')
{
str = skip_regexp(str + 1, *str, FALSE, NULL);
if (*str != **pp)
if (*str != first_char)
str = NULL;
else
++str;
@@ -3837,6 +3838,7 @@ find_extra(char_u **pp)
|| !(VIM_ISDIGIT(str[1]) || str[1] == '/' || str[1] == '?'))
break;
++str; // skip ';'
first_char = *str;
}
if (str != NULL && STRNCMP(str, ";\"", 2) == 0)

View File

@@ -432,3 +432,31 @@ func Test_pum_with_preview_win()
call StopVimInTerminal(buf)
call delete('Xpreviewscript')
endfunc
" Test for inserting the tag search pattern in insert mode
func Test_ins_compl_tag_sft()
call writefile([
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
\ "first\tXfoo\t/^int first() {}$/",
\ "second\tXfoo\t/^int second() {}$/",
\ "third\tXfoo\t/^int third() {}$/"],
\ 'Xtags')
set tags=Xtags
let code =<< trim [CODE]
int first() {}
int second() {}
int third() {}
[CODE]
call writefile(code, 'Xfoo')
enew
set showfulltag
exe "normal isec\<C-X>\<C-]>\<C-N>\<CR>"
call assert_equal('int second() {}', getline(1))
set noshowfulltag
call delete('Xtags')
call delete('Xfoo')
set tags&
%bwipe!
endfunc

View File

@@ -81,4 +81,28 @@ func Test_tagfunc()
call delete('Xfile1')
endfunc
" Test for modifying the tag stack from a tag function and jumping to a tag
" from a tag function
func Test_tagfunc_settagstack()
func Mytagfunc1(pat, flags, info)
call settagstack(1, {'tagname' : 'mytag', 'from' : [0, 10, 1, 0]})
return [{'name' : 'mytag', 'filename' : 'Xtest', 'cmd' : '1'}]
endfunc
set tagfunc=Mytagfunc1
call writefile([''], 'Xtest')
call assert_fails('tag xyz', 'E986:')
func Mytagfunc2(pat, flags, info)
tag test_tag
return [{'name' : 'mytag', 'filename' : 'Xtest', 'cmd' : '1'}]
endfunc
set tagfunc=Mytagfunc2
call assert_fails('tag xyz', 'E986:')
call delete('Xtest')
set tagfunc&
delfunc Mytagfunc1
delfunc Mytagfunc2
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -578,4 +578,293 @@ func Test_tagline()
set tags&
endfunc
" Test for expanding environment variable in a tag file name
func Test_tag_envvar()
call writefile(["Func1\t$FOO\t/^Func1/"], 'Xtags')
set tags=Xtags
let $FOO='TagTestEnv'
let caught_exception = v:false
try
tag Func1
catch /E429:/
call assert_match('E429:.*"TagTestEnv".*', v:exception)
let caught_exception = v:true
endtry
call assert_true(caught_exception)
set tags&
call delete('Xtags')
unlet $FOO
endfunc
" Test for :ptag
func Test_ptag()
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
\ "second\tXfile1\t2",
\ "third\tXfile1\t3",],
\ 'Xtags')
set tags=Xtags
call writefile(['first', 'second', 'third'], 'Xfile1')
enew | only
ptag third
call assert_equal(2, winnr())
call assert_equal(2, winnr('$'))
call assert_equal(1, getwinvar(1, '&previewwindow'))
call assert_equal(0, getwinvar(2, '&previewwindow'))
wincmd w
call assert_equal(3, line('.'))
" jump to the tag again
ptag third
call assert_equal(3, line('.'))
" close the preview window
pclose
call assert_equal(1, winnr('$'))
call delete('Xfile1')
call delete('Xtags')
set tags&
endfunc
" Tests for guessing the tag location
func Test_tag_guess()
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
\ "func1\tXfoo\t/^int func1(int x)/",
\ "func2\tXfoo\t/^int func2(int y)/",
\ "func3\tXfoo\t/^func3/",
\ "func4\tXfoo\t/^func4/"],
\ 'Xtags')
set tags=Xtags
let code =<< trim [CODE]
int FUNC1 (int x) { }
int
func2 (int y) { }
int * func3 () { }
[CODE]
call writefile(code, 'Xfoo')
let v:statusmsg = ''
ta func1
call assert_match('E435:', v:statusmsg)
call assert_equal(2, line('.'))
let v:statusmsg = ''
ta func2
call assert_match('E435:', v:statusmsg)
call assert_equal(4, line('.'))
let v:statusmsg = ''
ta func3
call assert_match('E435:', v:statusmsg)
call assert_equal(5, line('.'))
call assert_fails('ta func4', 'E434:')
call delete('Xtags')
call delete('Xfoo')
set tags&
endfunc
" Test for an unsorted tags file
func Test_tag_sort()
call writefile([
\ "first\tXfoo\t1",
\ "ten\tXfoo\t3",
\ "six\tXfoo\t2"],
\ 'Xtags')
set tags=Xtags
let code =<< trim [CODE]
int first() {}
int six() {}
int ten() {}
[CODE]
call writefile(code, 'Xfoo')
call assert_fails('tag first', 'E432:')
call delete('Xtags')
call delete('Xfoo')
set tags&
%bwipe
endfunc
" Test for an unsorted tags file
func Test_tag_fold()
call writefile([
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
\ "!_TAG_FILE_SORTED\t2\t/0=unsorted, 1=sorted, 2=foldcase/",
\ "first\tXfoo\t1",
\ "second\tXfoo\t2",
\ "third\tXfoo\t3"],
\ 'Xtags')
set tags=Xtags
let code =<< trim [CODE]
int first() {}
int second() {}
int third() {}
[CODE]
call writefile(code, 'Xfoo')
enew
tag second
call assert_equal('Xfoo', bufname(''))
call assert_equal(2, line('.'))
call delete('Xtags')
call delete('Xfoo')
set tags&
%bwipe
endfunc
" Test for the :ltag command
func Test_ltag()
call writefile([
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
\ "first\tXfoo\t1",
\ "second\tXfoo\t/^int second() {}$/",
\ "third\tXfoo\t3"],
\ 'Xtags')
set tags=Xtags
let code =<< trim [CODE]
int first() {}
int second() {}
int third() {}
[CODE]
call writefile(code, 'Xfoo')
enew
call setloclist(0, [], 'f')
ltag third
call assert_equal('Xfoo', bufname(''))
call assert_equal(3, line('.'))
call assert_equal([{'lnum': 3, 'bufnr': bufnr('Xfoo'), 'col': 0,
\ 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': 0, 'type': '',
\ 'module': '', 'text': 'third'}], getloclist(0))
ltag second
call assert_equal(2, line('.'))
call assert_equal([{'lnum': 0, 'bufnr': bufnr('Xfoo'), 'col': 0,
\ 'pattern': '^\Vint second() {}\$', 'valid': 1, 'vcol': 0, 'nr': 0,
\ 'type': '', 'module': '', 'text': 'second'}], getloclist(0))
call delete('Xtags')
call delete('Xfoo')
set tags&
%bwipe
endfunc
" Test for setting the last search pattern to the tag search pattern
" when cpoptions has 't'
func Test_tag_last_search_pat()
call writefile([
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
\ "first\tXfoo\t/^int first() {}/",
\ "second\tXfoo\t/^int second() {}/",
\ "third\tXfoo\t/^int third() {}/"],
\ 'Xtags')
set tags=Xtags
let code =<< trim [CODE]
int first() {}
int second() {}
int third() {}
[CODE]
call writefile(code, 'Xfoo')
enew
let save_cpo = &cpo
set cpo+=t
let @/ = ''
tag second
call assert_equal('^int second() {}', @/)
let &cpo = save_cpo
call delete('Xtags')
call delete('Xfoo')
set tags&
%bwipe
endfunc
" Test for jumping to a tag when the tag stack is full
func Test_tag_stack_full()
let l = []
for i in range(10, 31)
let l += ["var" .. i .. "\tXfoo\t/^int var" .. i .. ";$/"]
endfor
call writefile(l, 'Xtags')
set tags=Xtags
let l = []
for i in range(10, 31)
let l += ["int var" .. i .. ";"]
endfor
call writefile(l, 'Xfoo')
enew
for i in range(10, 30)
exe "tag var" .. i
endfor
let l = gettagstack()
call assert_equal(20, l.length)
call assert_equal('var11', l.items[0].tagname)
tag var31
let l = gettagstack()
call assert_equal('var12', l.items[0].tagname)
call assert_equal('var31', l.items[19].tagname)
" Jump from the top of the stack
call assert_fails('tag', 'E556:')
" Pop from an unsaved buffer
enew!
call append(1, "sample text")
call assert_fails('pop', 'E37:')
call assert_equal(21, gettagstack().curidx)
enew!
" Pop all the entries in the tag stack
call assert_fails('30pop', 'E555:')
" Pop the tag stack when it is empty
call settagstack(1, {'items' : []})
call assert_fails('pop', 'E73:')
call delete('Xtags')
call delete('Xfoo')
set tags&
%bwipe
endfunc
" Test for browsing multiple matching tags
func Test_tag_multimatch()
call writefile([
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
\ "first\tXfoo\t1",
\ "first\tXfoo\t2",
\ "first\tXfoo\t3"],
\ 'Xtags')
set tags=Xtags
let code =<< trim [CODE]
int first() {}
int first() {}
int first() {}
[CODE]
call writefile(code, 'Xfoo')
tag first
tlast
call assert_equal(3, line('.'))
call assert_fails('tnext', 'E428:')
tfirst
call assert_equal(1, line('.'))
call assert_fails('tprev', 'E425:')
call delete('Xtags')
call delete('Xfoo')
set tags&
%bwipe
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -115,3 +115,99 @@ func Test_tagsfile_without_trailing_newline()
call delete('Xtags')
set tags&
endfunc
" Test for ignoring comments in a tags file
func Test_tagfile_ignore_comments()
call writefile([
\ "!_TAG_PROGRAM_NAME /Test tags generator/",
\ "FBar\tXfoo\t2" .. ';"' .. "\textrafield\tf",
\ "!_TAG_FILE_FORMAT 2 /extended format/",
\ ], 'Xtags')
set tags=Xtags
let l = taglist('.*')
call assert_equal(1, len(l))
call assert_equal('FBar', l[0].name)
set tags&
call delete('Xtags')
endfunc
" Test for using an excmd in a tags file to position the cursor (instead of a
" search pattern or a line number)
func Test_tagfile_excmd()
call writefile([
\ "vFoo\tXfoo\tcall cursor(3, 4)" .. '|;"' .. "\tv",
\ ], 'Xtags')
set tags=Xtags
let l = taglist('.*')
call assert_equal([{
\ 'cmd' : 'call cursor(3, 4)',
\ 'static' : 0,
\ 'name' : 'vFoo',
\ 'kind' : 'v',
\ 'filename' : 'Xfoo'}], l)
set tags&
call delete('Xtags')
endfunc
" Test for duplicate fields in a tag in a tags file
func Test_duplicate_field()
call writefile([
\ "vFoo\tXfoo\t4" .. ';"' .. "\ttypename:int\ttypename:int\tv",
\ ], 'Xtags')
set tags=Xtags
let l = taglist('.*')
call assert_equal([{
\ 'cmd' : '4',
\ 'static' : 0,
\ 'name' : 'vFoo',
\ 'kind' : 'v',
\ 'typename' : 'int',
\ 'filename' : 'Xfoo'}], l)
set tags&
call delete('Xtags')
endfunc
" Test for tag address with ;
func Test_tag_addr_with_semicolon()
call writefile([
\ "Func1\tXfoo\t6;/^Func1/" .. ';"' .. "\tf"
\ ], 'Xtags')
set tags=Xtags
let l = taglist('.*')
call assert_equal([{
\ 'cmd' : '6;/^Func1/',
\ 'static' : 0,
\ 'name' : 'Func1',
\ 'kind' : 'f',
\ 'filename' : 'Xfoo'}], l)
set tags&
call delete('Xtags')
endfunc
" Test for format error in a tags file
func Test_format_error()
call writefile(['vFoo-Xfoo-4'], 'Xtags')
set tags=Xtags
let caught_exception = v:false
try
let l = taglist('.*')
catch /E431:/
" test succeeded
let caught_exception = v:true
catch
call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
endtry
call assert_true(caught_exception)
set tags&
call delete('Xtags')
endfunc

View File

@@ -742,6 +742,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
88,
/**/
87,
/**/