代码之家  ›  专栏  ›  技术社区  ›  Matthew Hoggan

c++、cscope、ctags和vim:查找从该类继承的类

  •  5
  • Matthew Hoggan  · 技术社区  · 10 年前

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

    4 回复  |  直到 9 年前
        1
  •  3
  •   romainl    10 年前

    cscope和ctags都不允许我们直接处理继承 相当地 因为派生类也被索引,所以很容易解决这个限制。

    计算机屏幕

    在cscope中,查找“C符号” Foobar 通常列出原始类 类继承而来。由于搜索是针对数据库进行的,因此速度极快。

    或者,您可以使用cscope的egrep搜索功能,其模式如下 :.*Foobar 到列表 只有 类继承自 福巴牌手表 .

    因此,即使我们没有专用的“查找从这个类继承的类”命令,我们也可以毫不费力地完成工作。

    插件

    虽然ctags允许您将继承信息与 --fields=+i ,该信息不能直接在Vim中使用。这个 inherits 字段是由Vim解析的,所以可以使用 taglist() .

    确认,ag

    这两个程序的工作方式或多或少类似于grep,但它们的目标是在源代码中搜索,所以它们是 真正地 比grep更快。

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

    :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
    
        2
  •  2
  •   Codie CodeMonkey    9 年前

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

    就像 :tag 命令,通过在正则表达式前面加一个“\”字符来指示要使用正则表达式进行搜索,例如。 :Inherits \Foo.* .

    结果被放入窗口的位置列表中,您可以使用该列表浏览 :ll , :lne , :lp VIM似乎不允许脚本修改标记列表,这是我更喜欢的。

    如果你想知道我为什么不使用 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
  •  2
  •   Luc Hermitte    9 年前

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

    它有两个可选参数:要查找的命名空间(我还没有找到避免这种情况的方法)和父类的名称-> :Children [!] {namespace} {parent-class} .

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

        4
  •  1
  •   Chandler    10 年前

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