c ++,cscope,ctags和vim:查找从这个继承的类

时间:2014-09-04 00:39:00

标签: c++ vim ctags cscope

在一个包含几层的相当大的代码库中,是否有一种方法可以在vim中或从命令行中找到从基类派生的所有类? grep是一个选项,但由于grep没有索引,因此可能很慢。

4 个答案:

答案 0 :(得分:3)

cscope和ctags都不允许我们直接处理继承,但它的相对很容易解决这个限制,因为派生类也被编入索引。

<强> cscope的

在cscope中,寻找&#34; C符号&#34; Foobar通常会列出从中继承的原始类类。由于搜索是针对数据库完成的,因此速度很快。

或者,您可以使用cscope的egrep搜索功能,使用类似:.*Foobar的模式来列出仅继承自Foobar 类。

所以,即使我们没有专门的&#34; Find类继承自这个类&#34;命令,我们可以毫不费力地完成工作。

<强>的ctags

虽然ctags允许您使用--fields=+i包含继承信息,但该信息无法直接在Vim中使用。但是,inherits字段由Vim解析,因此可以使用taglist()构建快速而肮脏的解决方案。

ack,ag

这两个程序或多或少像grep一样工作,但是它们的目标是在源代码中搜索,因此它们真的比grep更快。

在我的Vim配置中,:grep设置为运行ag程序而不是默认的grep,因此,搜索从光标下的类派生的类将如下所示: / p>

:grep :.*<C-r><C-w><CR>

以下是我~/.vimrc的相关行:

if executable("ag")
  set grepprg=ag\ --nogroup\ --nocolor\ --ignore-case\ --column
  set grepformat=%f:%l:%c:%m,%f:%l:%m
endif

答案 1 :(得分:2)

lh-cpp中,我定义了命令:Children。它依赖于ctags数据库,因此它非常有限。

它需要两个可选参数:要查找的命名空间(我没有找到避免这种情况的方法),以及父类的名称 - &gt; :Children [!] {namespace} {parent-class}

该命令尝试尽可能多地缓存信息。因此,当ctags数据库中的相关信息发生变化时,必须更新缓存。它是通过敲击命令来完成的 - &gt; :Children!

答案 2 :(得分:2)

如果使用继承信息(see the --fields option)使用Exuberant CTags构建标记文件,则以下脚本将起作用。它添加了一个:Inherits命令,该命令可以使用类的名称(例如:Inherits Foo)或正则表达式。

:tag命令一样,您通过在其前面添加&#39; \&#39;来指示您希望使用正则表达式进行搜索。字符,例如:Inherits \Foo.*

结果会显示在窗口的位置列表中,您可以使用:ll:lne:lp等进行浏览.VIM似乎不允许用于修改标签列表的脚本,这是我喜欢的。

如果您想知道我为什么不使用taglist(),那么因为taglist()在大型标记文件上的速度非常慢。原帖有一个使用taglist()的版本,如果您有点好奇,可以浏览编辑记录。

" Parse an Exuberant Ctags record using the same format as taglist()
"
" Throws CtagsParseErr if there is a general problem parsing the record
function! ParseCtagsRec(record, tag_dir)
    let tag = {}

    " Parse the standard fields
    let sep_pos = stridx(a:record, "\t")
    if sep_pos < 1
        throw 'CtagsParseErr'
    endif
    let tag['name'] = a:record[:sep_pos - 1]
    let tail = a:record[sep_pos + 1:]
    let sep_pos = stridx(tail, "\t")
    if sep_pos < 1
        throw 'CtagsParseErr'
    endif
    " '/' will work as a path separator on most OS's, but there
    " should really be an OS independent way to build paths.
    let tag['filename'] = a:tag_dir.'/'.tail[:sep_pos - 1]
    let tail = tail[sep_pos + 1:]
    let sep_pos = stridx(tail, ";\"\t")
    if sep_pos < 1
        throw 'CtagsParseErr'
    endif
    let tag['cmd'] = tail[:sep_pos - 1]

    " Parse the Exuberant Ctags extension fields
    let extensions = tail[sep_pos + 3:]
    for extension in split(extensions, '\t')
        let sep_pos = stridx(extension, ':')
        if sep_pos < 1
            if has_key(tag, 'kind')
                throw 'CtagsParseErr'
            endif
            let tag['kind'] = extension
        else
            let tag[extension[:sep_pos - 1]] = extension[sep_pos + 1:]
        endif
    endfor

    return tag
endfunction

" Find all classes derived from a given class, or a regex (preceded by a '/')
" The results are placed in the current windows location list.
function! Inherits(cls_or_regex)
    if a:cls_or_regex[0] == '/'
        let regex = a:cls_or_regex[1:]
    else
        let regex = '\<'.a:cls_or_regex.'\>$'
    endif
    let loc_list = []
    let tfiles = tagfiles()
    let tag_count = 0
    let found_count = 0
    for file in tfiles
        let tag_dir = fnamemodify(file, ':p:h')
        try
            for line in readfile(file)
                let tag_count += 1
                if tag_count % 10000 == 0
                    echo tag_count 'tags scanned,' found_count 'matching classes found. Still searching...'
                    redraw
                endif
                if line[0] == '!'
                    continue
                endif

                let tag = ParseCtagsRec(line, tag_dir)

                if has_key(tag, 'inherits')
                    let baselist = split(tag['inherits'], ',\s*')
                    for base in baselist
                        if match(base, regex) != -1
                            let location = {}
                            let location['filename'] = tag['filename']

                            let cmd = tag['cmd']
                            if cmd[0] == '/' || cmd[0] == '?'
                                let location['pattern'] = cmd[1:-2]
                            else
                                let location['lnum'] = str2nr(cmd)
                            endif

                            call add(loc_list, location)
                            let found_count += 1
                        endif
                    endfor
                endif
            endfor
        catch /^OptionErr$/
            echo 'Parsing error: Failed to parse an option.'
            return
        catch /^CtagsParseErr$/
            echo 'Parsing error: Tags files does not appear to be an Exuberant Ctags file.'
            return
        catch
            echo 'Could not read tag file:' file
            return
        endtry
    endfor
    call setloclist(0, loc_list)
    echo tag_count 'tags scanned,' found_count 'matching classes found.'
endfunction

command! -nargs=1 -complete=tag Inherits call Inherits('<args>')

答案 3 :(得分:1)

我不认为vim是列出所有子类的正确工具。相反,我们最好使用doxygen来生成源代码的文档。虽然doxygen需要一些时间,但我们可以使用所有类的文档/图表,这是清晰而快速的。