gopls/internal/lsp/source: avoid panic(nil)

The previous code used panic(nil) as a longjump. However,
if a library function such as Node.Pos() were to panic(nil),
we would catch it spuriously instead of reporting the panic
by crashing the program. This change uses a new type, found,
as a sentinal for the non-local jump.

Updates golang/go#25448

Change-Id: I2439432a7ca477d0c25c9c848a98308a378b089b
Reviewed-on: https://go-review.googlesource.com/c/tools/+/452515
Reviewed-by: Russ Cox <rsc@golang.org>
Run-TryBot: Alan Donovan <adonovan@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Alan Donovan 2022-11-21 14:45:14 -05:00
parent 41c70c91bc
commit 57f56abcb0
1 changed files with 10 additions and 6 deletions

View File

@ -895,10 +895,14 @@ func anyNonEmpty(x []string) bool {
//
// It returns (nil, nil) if no Field or Decl is found at pos.
func FindDeclAndField(files []*ast.File, pos token.Pos) (decl ast.Decl, field *ast.Field) {
// panic(nil) breaks off the traversal and
// panic(found{}) breaks off the traversal and
// causes the function to return normally.
type found struct{}
defer func() {
if x := recover(); x != nil {
switch x := recover().(type) {
case nil:
case found:
default:
panic(x)
}
}()
@ -930,7 +934,7 @@ func FindDeclAndField(files []*ast.File, pos token.Pos) (decl ast.Decl, field *a
break
}
}
panic(nil) // found
panic(found{})
}
}
@ -953,7 +957,7 @@ func FindDeclAndField(files []*ast.File, pos token.Pos) (decl ast.Decl, field *a
case *ast.FuncDecl:
if n.Name.Pos() == pos {
decl = n
panic(nil) // found
panic(found{})
}
case *ast.GenDecl:
@ -962,13 +966,13 @@ func FindDeclAndField(files []*ast.File, pos token.Pos) (decl ast.Decl, field *a
case *ast.TypeSpec:
if spec.Name.Pos() == pos {
decl = n
panic(nil) // found
panic(found{})
}
case *ast.ValueSpec:
for _, id := range spec.Names {
if id.Pos() == pos {
decl = n
panic(nil) // found
panic(found{})
}
}
}