From bb9e9137e832f8c5f5269fe6e8743d03b03ef4a1 Mon Sep 17 00:00:00 2001 From: Billie Cleek Date: Sun, 26 Apr 2020 10:06:20 -0700 Subject: [PATCH] run: capture error messages from panics Capture error messages from panic. I'm not 100% sure that this is the right course of action. It might be better to treat panics as successes, because non-zero exit status from go run are generally discarded except for compiler errors. This change is inconsistent with that fact and may lead people to expect that non-zero exit statuses from the command being run should always populate the quickfix list. Fixes #2328 --- autoload/go/cmd.vim | 35 +++++++++++++++++-- autoload/go/cmd_test.vim | 16 +++++++++ autoload/go/complete_test.vim | 20 +++++------ .../go/test-fixtures/cmd/run/panic/panic.go | 15 ++++++++ 4 files changed, 74 insertions(+), 12 deletions(-) create mode 100644 autoload/go/test-fixtures/cmd/run/panic/panic.go diff --git a/autoload/go/cmd.vim b/autoload/go/cmd.vim index 88671662b2..7f325ed2b5 100644 --- a/autoload/go/cmd.vim +++ b/autoload/go/cmd.vim @@ -349,8 +349,39 @@ function! go#cmd#Generate(bang, ...) abort endfunction function! s:runerrorformat() - let l:panicaddress = "%\\t%#%f:%l +0x%[0-9A-Fa-f]%\\+" - let l:errorformat = '%A' . l:panicaddress . "," . &errorformat + let goroot = go#util#goroot() + + let stdlibaddress = "%\\t" . goroot . "%\\f%\\+:%\\d%\\+ +0x%[0-9A-Fa-f]%\\+" + + " panicaddress and readyaddress are identical except for + " panicaddress sets the filename and line number. + let l:panicaddress = '%\\t%f:%l%\\%( +0x%[0-9A-Fa-f]%\\+%\\)%\\=' + let l:readyaddress = '%\\t%\\f%\\+:%\\d%\\+%\\%( +0x%[0-9A-Fa-f]%\\+%\\)%\\=' + " stdlib address is identical to readyaddress, except it matches files + " inside GOROOT. + let l:stdlibaddress = '%\\t' . goroot . '%\\f%\\+:%\\d%\\+%\\%( +0x%[0-9A-Fa-f]%\\+%\\)%\\=' + + let l:errorformat = '' + let l:errorformat .= '%-Cexit status 2' + let l:errorformat .= ",%-C" . stdlibaddress + " Match address lines in the first matching goroutine. This means the panic + " message will only be shown as the error message in the first address of + " the running goroutine's stack. + let l:errorformat .= ',%Z' . l:panicaddress + + " Match and ignore panic address without being part of a multi-line message. + " This is to catch those lines that come after the top most non-standard + " library line in stack traces. + let l:errorformat .= ",%-G" . l:panicaddress + + " Match and discard empty lines in a multi-line message. + let l:errorformat .= ',%-C' + " Match and ignore the goroutine lines. + let l:errorformat .= ',%-Cgoroutine %\\d%\\+%.%#:' + " Match and discard lines containing function names in multi-line messages. + let l:errorformat .= ',%-C%.%#(%\\%(%\\.%\\.%\\.%\\)%\\=)' + let l:errorformat .= ',%+Epanic: %m' + let l:errorformat .= "," . &errorformat return l:errorformat endfunction diff --git a/autoload/go/cmd_test.vim b/autoload/go/cmd_test.vim index 708a3ab9d4..4296f7e3e1 100644 --- a/autoload/go/cmd_test.vim +++ b/autoload/go/cmd_test.vim @@ -31,6 +31,22 @@ func! Test_GoBuildErrors() endtry endfunc +func! Test_GoRunPanic() + let l:filename = 'cmd/run/panic/panic.go' + let l:tmp = gotest#load_fixture(l:filename) + + let expected = [ + \ {'lnum': 9, 'bufnr': bufnr('%'), 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'E', 'pattern': '', 'text': 'panic: quux'} + \ ] + try + call go#cmd#Run(0) + let l:actual = getqflist() + call gotest#assert_quickfix(l:actual, l:expected) + finally + call delete(l:tmp, 'rf') + endtry +endfunc + " restore Vi compatibility settings let &cpo = s:cpo_save unlet s:cpo_save diff --git a/autoload/go/complete_test.vim b/autoload/go/complete_test.vim index ee00056c9d..b85a578acb 100644 --- a/autoload/go/complete_test.vim +++ b/autoload/go/complete_test.vim @@ -9,17 +9,17 @@ func! Test_GetInfo_gopls() endfunction func! s:getinfo() - let l:filename = 'complete/complete.go' - let l:tmp = gotest#load_fixture(l:filename) - try - call cursor(8, 3) + let l:filename = 'complete/complete.go' + let l:tmp = gotest#load_fixture(l:filename) + try + call cursor(8, 3) - let expected = 'func Example(s string)' - let actual = go#complete#GetInfo() - call assert_equal(expected, actual) - finally - call delete(l:tmp, 'rf') - endtry + let expected = 'func Example(s string)' + let actual = go#complete#GetInfo() + call assert_equal(expected, actual) + finally + call delete(l:tmp, 'rf') + endtry endfunction " restore Vi compatibility settings diff --git a/autoload/go/test-fixtures/cmd/run/panic/panic.go b/autoload/go/test-fixtures/cmd/run/panic/panic.go new file mode 100644 index 0000000000..e4aa1863d9 --- /dev/null +++ b/autoload/go/test-fixtures/cmd/run/panic/panic.go @@ -0,0 +1,15 @@ +package main + +import ( + "errors" + "fmt" +) + +func quux() { + panic(errors.New("quux")) +} + +func main() { + quux() + fmt.Println("vim-go") +}