Vim-go: :GoCallers is broken

Created on 7 Sep 2016  ·  20Comments  ·  Source: fatih/vim-go

Actual behavior

  • Move cursor over function definition
  • Type :GoCallers
  • Error message is displayed:
vim-go: import "/Users/felix/code/go/src/github.com/some/project/mypkg": cannot import absolute path
guru: no initial packages were loaded

Expected behavior

  • Move cursor over function definition
  • Type :GoCallers
  • List with call sites should be displayed

    Steps to reproduce:

See actual behavior. I suspect the problem is https://github.com/fatih/vim-go/blob/master/autoload/go/guru.vim#L11 resolving the pkg name to an absolute path, rather than a relative one.

Configuration

$ go version
go version go1.6.3 darwin/amd64
$ uname -a
Darwin Felix-MBP-2012.local 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34 PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64
$ sw_vers -productVersion
10.11.6
$ cd ~/.vim/bundle/vim-go && git rev-parse HEAD
8575d9e3c9e23508f9b7d0c3992cb683b1e47ae6
$ vim --version
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Aug 29 2016 12:51:13)
MacOS X (unix) version
Included patches: 1-2290
Compiled by Homebrew
Huge version without GUI.  Features included (+) or not (-):
+acl             +file_in_path    +mouse_sgr       +tag_old_static
+arabic          +find_in_path    -mouse_sysmouse  -tag_any_white
+autocmd         +float           +mouse_urxvt     -tcl
-balloon_eval    +folding         +mouse_xterm     +termguicolors
-browse          -footer          +multi_byte      +terminfo
++builtin_terms  +fork()          +multi_lang      +termresponse
+byte_offset     -gettext         -mzscheme        +textobjects
+channel         -hangul_input    +netbeans_intg   +timers
+cindent         +iconv           +num64           +title
-clientserver    +insert_expand   +packages        -toolbar
+clipboard       +job             +path_extra      +user_commands
+cmdline_compl   +jumplist        +perl            +vertsplit
+cmdline_hist    +keymap          +persistent_undo +virtualedit
+cmdline_info    +lambda          +postscript      +visual
+comments        +langmap         +printer         +visualextra
+conceal         +libcall         +profile         +viminfo
+cryptv          +linebreak       +python          +vreplace
+cscope          +lispindent      -python3         +wildignore
+cursorbind      +listcmds        +quickfix        +wildmenu
+cursorshape     +localmap        +reltime         +windows
+dialog_con      -lua             +rightleft       +writebackup
+diff            +menu            +ruby            -X11
+digraphs        +mksession       +scrollbind      -xfontset
-dnd             +modify_fname    +signs           -xim
-ebcdic          +mouse           +smartindent     -xpm
+emacs_tags      -mouseshape      +startuptime     -xsmp
+eval            +mouse_dec       +statusline      -xterm_clipboard
+ex_extra        -mouse_gpm       -sun_workshop    -xterm_save
+extra_search    -mouse_jsbterm   +syntax
+farsi           +mouse_netterm   +tag_binary
   system vimrc file: "$VIM/vimrc"
     user vimrc file: "$HOME/.vimrc"
 2nd user vimrc file: "~/.vim/vimrc"
      user exrc file: "$HOME/.exrc"
       defaults file: "$VIMRUNTIME/defaults.vim"
  fall-back for $VIM: "/usr/local/share/vim"
Compilation: clang -c -I. -Iproto -DHAVE_CONFIG_H   -DMACOS_X_UNIX  -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
Linking: clang   -L. -fstack-protector -L/usr/local/lib -L/usr/local/opt/libyaml/lib -L/usr/local/opt/openssl/lib -L/usr/local/opt/readline/lib  -L/usr/local/lib -o vim        -lncurses -liconv -framework Cocoa   -mmacosx-version-min=10.11 -fstack-protector-strong -L/usr/local/lib  -L/usr/local/Cellar/perl/5.24.0_1/lib/perl5/5.24.0/darwin-thread-multi-2level/CORE -lperl -lm -lutil -lc -F/usr/local/Cellar/python/2.7.12/Frameworks -framework Python   -lruby.2.3.0 -lobjc -L/usr/local/Cellar/ruby/2.3.1/lib

Thanks for looking into this!

improvement

Most helpful comment

The option is :GoGuruScope. People already have an option, but nobody reads the manual (http://golang.org/s/using-guru) so they end up with this issue. The default is just the current package. It's good enough in most cases, for other cases everyone should use :GoGuruScope

All 20 comments

Hi @felixge

Can you please provide a source code I can test? Because locally it works for me. Please give something I can try step by step. Thanks.

Sure.

$ cat /Users/felix/code/go/src/github.com/felixge/vim-go-test/main.go
package main

func main() {
    bar()
}

func bar() {

}

I place my cursor over the word 'bar' on line 7, type ':GoCallers' and see this error:

vim-go: import "/Users/felix/code/go/src/github.com/felixge/vim-go-test": cannot import absolute path
guru: no initial packages were loaded

Come to think of it, perhaps the issue is related to my GOPATH containing multiple go paths (due to using gvm)

$ echo $GOPATH
/Users/felix/code/go:/Users/felix/.gvm/pkgsets/go1.6.3/global

Yeah, if I change my GOPATH to have only one path, the example I provided seems to work.

But for my actual project I'm now getting this error:

vim-go: guru: analysis scope has no main and no tests

Let me know if you have any ideas.

Unfortunately I can't share the code of the project.

Okay, I think I figured out the new problem.

By default, guru uses the scope: github.com/felixge/myproject. However, I'm working inside pkg foo within my project. So I think the scope should default to github.com/felixge/myproject/... instead. Manually setting :GoGuruScope github.com/felixge/myproject/... fixes the problem.

Let me know if that makes sense.

That's great to know. That's how Guru works. But vim-go tries to be helpful by choosing a simple scope so these commands work. Otherwise I receive a lot of complaints and issues that the command doesn't work.

That's great to know. That's how Guru works. But vim-go tries to be helpful by choosing a simple scope so these commands work. Otherwise I receive a lot of complaints and issues that the command doesn't work.

Does this default really work well for people? I'd assume a lot of people want to use :GoCallers within sub pkgs?

That being said, I don't mind if the default stays as is. But maybe it would be possible to have an option that allows the behavior I suggested above?

The option is :GoGuruScope. People already have an option, but nobody reads the manual (http://golang.org/s/using-guru) so they end up with this issue. The default is just the current package. It's good enough in most cases, for other cases everyone should use :GoGuruScope

Look at the scope section:

Pointer analysis scope: some queries involve pointer analysis, a technique for
answering questions of the form “what might this pointer point to?”.  It is
usually too expensive to run pointer analysis over all the packages in the
workspace, so these queries require an additional configuration parameter
called the scope, which determines the set of packages to analyze.  Set the
scope to the application (or set of applications---a client and server,
perhaps) on which you are currently working.  Pointer analysis is a
whole-program analysis, so the only packages in the scope that matter are the
main and test packages.

The scope is typically specified as a comma-separated set of packages, or
wildcarded subtrees like github.com/my/dir/...; consult the specific
documentation for your editor to find out how to set and vary the scope.

I understand how :GoGuruScope works, but how do I use it to accomplish my goal?

I don't want to hard code my project pkg in my .vimrc. I just want to append '/...' to the default guru scope.

@felixge you set the scope and then use :GoCallers. Isn't something clear here? Do you mean you shouldn't set the scope? I didn't understand your problem.

@fatih I don't want to modify the scope manually every time I need to use :GoCallers.

Adding this to my .vimrc seems to do the trick:

au FileType go silent exe "GoGuruScope " . go#package#ImportPath(expand('%:p:h')) . "..."

But IMO it's quite hacky.

Anyway, do you see what I'm trying to accomplish now?

Oh ok, so you mean we should change the current default in vim-go from current_package to current_package/... ?

Otherwise I know it's cumbersome to change it everytime.

Yes! Exactly :). If that makes sense, I propose to:

  • Close this issue as the comments / problems are all over the place.
  • Create a new issue to request this as a feature and mentioning my workaround above for anybody interested in the meantime.
  • Create a new issue for the fact that resolving the current_package doesn't work if there is more than one path in $GOPATH (which shouldn't be high priority, I can change my GOPATH for now)

I am also having the same issue, though adding the line for GoGuruScope in my .vimrc file doesn't seem to fix it. Is there any other workarounds other than having to change my GOPATH?

Thanks

@smousa you might also need to change your build tags with :GoBuildTags or let g:go_build_tags = "yourtag" (and even then, you may have to correct some errors in a project that builds just fine: guru is more sensitive to unread variables than go build, for example).

Actually just setting the guru scope to current_package/... may lead to undesired behaviour especially with vendored dependencies (inside a vendor directory). Example: My project is github.com/justsocialapps/kafkabeat and all its deps are in the vendor directory so I set GoGuruScope to github.com/justsocialapps/kafkabeat/.... Then issuing GoCallers on a function inside one of my deps led to a complete lock-up of my computer for some minutes.

Just for a reference and for someone that has found this issue with hope of solution:

I have managed to add bits and pieces and (re)create this

" from https://gist.github.com/tyru/984296
" Substitute a:from => a:to by string.
" To substitute by pattern, use substitute() instead.
function! s:substring(str, from, to)
  if a:str ==# '' || a:from ==# ''
      return a:str
  endif
  let str = a:str
  let idx = stridx(str, a:from)
  while idx !=# -1
      let left  = idx ==# 0 ? '' : str[: idx - 1]
      let right = str[idx + strlen(a:from) :]
      let str = left . a:to . right
      let idx = stridx(str, a:from)
  endwhile
  return str
endfunction

function! s:chomp(string)
  return substitute(a:string, '\n\+$', '', '')
endfunction

function! s:go_guru_scope_from_git_root()
" chomp because get rev-parse returns line with newline at the end
  return s:chomp(s:substring(system("git rev-parse --show-toplevel"),$GOPATH . "/src/","")) . "/..."
endfunction

au FileType go silent exe "GoGuruScope " . s:go_guru_scope_from_git_root()

which produces import path from current git repo's import path and sets it with GoGuruScope

So if you happen to be in $GOPATH/src/github.com/USER/PROJECT/DIRA/DIRB/ and open a .go file you will get go_guru_scope == github.com/USER/PROJECT/...

I found it useful, maybe someone else will as well.

@pmalek that script was amazingly helpful

FWIW I found it useful to use go#util#gopath() rather than $GOPATH (if GOPATH is unset then go#util#gopath() will use a default), or alternatively system(go env GOPATH) would also work. I also find it useful to ignore vendor

I did a bit of vimscript golfing as well:

function! s:go_guru_scope_from_git_root()
  let gitroot = system("git rev-parse --show-toplevel | tr -d '\n'")
  let pattern = escape(go#util#gopath() . "/src/", '\ /')
  return substitute(gitroot, pattern, "", "") . "/... -vendor/"
endfunction

au FileType go silent exe "GoGuruScope " . s:go_guru_scope_from_git_root()
Was this page helpful?
0 / 5 - 0 ratings

Related issues

cassiobotaro picture cassiobotaro  ·  3Comments

smontazeran picture smontazeran  ·  4Comments

andrejvanderzee picture andrejvanderzee  ·  3Comments

derekchiang picture derekchiang  ·  3Comments

korjavin picture korjavin  ·  4Comments