Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / internal / lsp / cache / parse.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/internal/lsp/cache/parse.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/internal/lsp/cache/parse.go
new file mode 100644 (file)
index 0000000..0a2c371
--- /dev/null
@@ -0,0 +1,1154 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cache
+
+import (
+       "bytes"
+       "context"
+       "fmt"
+       "go/ast"
+       "go/parser"
+       "go/scanner"
+       "go/token"
+       "reflect"
+       "strconv"
+
+       "golang.org/x/tools/internal/event"
+       "golang.org/x/tools/internal/lsp/debug/tag"
+       "golang.org/x/tools/internal/lsp/protocol"
+       "golang.org/x/tools/internal/lsp/source"
+       "golang.org/x/tools/internal/memoize"
+       "golang.org/x/tools/internal/span"
+       errors "golang.org/x/xerrors"
+)
+
+// parseKey uniquely identifies a parsed Go file.
+type parseKey struct {
+       file source.FileIdentity
+       mode source.ParseMode
+}
+
+// astCacheKey is similar to parseKey, but is a distinct type because
+// it is used to key a different value within the same map.
+type astCacheKey parseKey
+
+type parseGoHandle struct {
+       handle         *memoize.Handle
+       file           source.FileHandle
+       mode           source.ParseMode
+       astCacheHandle *memoize.Handle
+}
+
+type parseGoData struct {
+       parsed *source.ParsedGoFile
+
+       // If true, we adjusted the AST to make it type check better, and
+       // it may not match the source code.
+       fixed bool
+       err   error // any other errors
+}
+
+func (s *snapshot) parseGoHandle(ctx context.Context, fh source.FileHandle, mode source.ParseMode) *parseGoHandle {
+       key := parseKey{
+               file: fh.FileIdentity(),
+               mode: mode,
+       }
+       if pgh := s.getGoFile(key); pgh != nil {
+               return pgh
+       }
+       parseHandle := s.generation.Bind(key, func(ctx context.Context, arg memoize.Arg) interface{} {
+               snapshot := arg.(*snapshot)
+               return parseGo(ctx, snapshot.view.session.cache.fset, fh, mode)
+       }, nil)
+
+       astHandle := s.generation.Bind(astCacheKey(key), func(ctx context.Context, arg memoize.Arg) interface{} {
+               snapshot := arg.(*snapshot)
+               return buildASTCache(ctx, snapshot, parseHandle)
+       }, nil)
+
+       pgh := &parseGoHandle{
+               handle:         parseHandle,
+               file:           fh,
+               mode:           mode,
+               astCacheHandle: astHandle,
+       }
+       return s.addGoFile(key, pgh)
+}
+
+func (pgh *parseGoHandle) String() string {
+       return pgh.File().URI().Filename()
+}
+
+func (pgh *parseGoHandle) File() source.FileHandle {
+       return pgh.file
+}
+
+func (pgh *parseGoHandle) Mode() source.ParseMode {
+       return pgh.mode
+}
+
+func (s *snapshot) ParseGo(ctx context.Context, fh source.FileHandle, mode source.ParseMode) (*source.ParsedGoFile, error) {
+       pgh := s.parseGoHandle(ctx, fh, mode)
+       pgf, _, err := s.parseGo(ctx, pgh)
+       return pgf, err
+}
+
+func (s *snapshot) parseGo(ctx context.Context, pgh *parseGoHandle) (*source.ParsedGoFile, bool, error) {
+       d, err := pgh.handle.Get(ctx, s.generation, s)
+       if err != nil {
+               return nil, false, err
+       }
+       data := d.(*parseGoData)
+       return data.parsed, data.fixed, data.err
+}
+
+func (s *snapshot) PosToDecl(ctx context.Context, pgf *source.ParsedGoFile) (map[token.Pos]ast.Decl, error) {
+       fh, err := s.GetFile(ctx, pgf.URI)
+       if err != nil {
+               return nil, err
+       }
+
+       pgh := s.parseGoHandle(ctx, fh, pgf.Mode)
+       d, err := pgh.astCacheHandle.Get(ctx, s.generation, s)
+       if err != nil {
+               return nil, err
+       }
+
+       data := d.(*astCacheData)
+       return data.posToDecl, data.err
+}
+
+func (s *snapshot) PosToField(ctx context.Context, pgf *source.ParsedGoFile) (map[token.Pos]*ast.Field, error) {
+       fh, err := s.GetFile(ctx, pgf.URI)
+       if err != nil {
+               return nil, err
+       }
+
+       pgh := s.parseGoHandle(ctx, fh, pgf.Mode)
+       d, err := pgh.astCacheHandle.Get(ctx, s.generation, s)
+       if err != nil || d == nil {
+               return nil, err
+       }
+
+       data := d.(*astCacheData)
+       return data.posToField, data.err
+}
+
+type astCacheData struct {
+       err error
+
+       posToDecl  map[token.Pos]ast.Decl
+       posToField map[token.Pos]*ast.Field
+}
+
+// buildASTCache builds caches to aid in quickly going from the typed
+// world to the syntactic world.
+func buildASTCache(ctx context.Context, snapshot *snapshot, parseHandle *memoize.Handle) *astCacheData {
+       var (
+               // path contains all ancestors, including n.
+               path []ast.Node
+               // decls contains all ancestors that are decls.
+               decls []ast.Decl
+       )
+
+       v, err := parseHandle.Get(ctx, snapshot.generation, snapshot)
+       if err != nil {
+               return &astCacheData{err: err}
+       }
+       file := v.(*parseGoData).parsed.File
+       if err != nil {
+               return &astCacheData{err: fmt.Errorf("nil file")}
+       }
+
+       data := &astCacheData{
+               posToDecl:  make(map[token.Pos]ast.Decl),
+               posToField: make(map[token.Pos]*ast.Field),
+       }
+
+       ast.Inspect(file, func(n ast.Node) bool {
+               if n == nil {
+                       lastP := path[len(path)-1]
+                       path = path[:len(path)-1]
+                       if len(decls) > 0 && decls[len(decls)-1] == lastP {
+                               decls = decls[:len(decls)-1]
+                       }
+                       return false
+               }
+
+               path = append(path, n)
+
+               switch n := n.(type) {
+               case *ast.Field:
+                       addField := func(f ast.Node) {
+                               if f.Pos().IsValid() {
+                                       data.posToField[f.Pos()] = n
+                                       if len(decls) > 0 {
+                                               data.posToDecl[f.Pos()] = decls[len(decls)-1]
+                                       }
+                               }
+                       }
+
+                       // Add mapping for *ast.Field itself. This handles embedded
+                       // fields which have no associated *ast.Ident name.
+                       addField(n)
+
+                       // Add mapping for each field name since you can have
+                       // multiple names for the same type expression.
+                       for _, name := range n.Names {
+                               addField(name)
+                       }
+
+                       // Also map "X" in "...X" to the containing *ast.Field. This
+                       // makes it easy to format variadic signature params
+                       // properly.
+                       if elips, ok := n.Type.(*ast.Ellipsis); ok && elips.Elt != nil {
+                               addField(elips.Elt)
+                       }
+               case *ast.FuncDecl:
+                       decls = append(decls, n)
+
+                       if n.Name != nil && n.Name.Pos().IsValid() {
+                               data.posToDecl[n.Name.Pos()] = n
+                       }
+               case *ast.GenDecl:
+                       decls = append(decls, n)
+
+                       for _, spec := range n.Specs {
+                               switch spec := spec.(type) {
+                               case *ast.TypeSpec:
+                                       if spec.Name != nil && spec.Name.Pos().IsValid() {
+                                               data.posToDecl[spec.Name.Pos()] = n
+                                       }
+                               case *ast.ValueSpec:
+                                       for _, id := range spec.Names {
+                                               if id != nil && id.Pos().IsValid() {
+                                                       data.posToDecl[id.Pos()] = n
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               return true
+       })
+
+       return data
+}
+
+func parseGo(ctx context.Context, fset *token.FileSet, fh source.FileHandle, mode source.ParseMode) *parseGoData {
+       ctx, done := event.Start(ctx, "cache.parseGo", tag.File.Of(fh.URI().Filename()))
+       defer done()
+
+       if fh.Kind() != source.Go {
+               return &parseGoData{err: errors.Errorf("cannot parse non-Go file %s", fh.URI())}
+       }
+       buf, err := fh.Read()
+       if err != nil {
+               return &parseGoData{err: err}
+       }
+
+       parserMode := parser.AllErrors | parser.ParseComments
+       if mode == source.ParseHeader {
+               parserMode = parser.ImportsOnly | parser.ParseComments
+       }
+       file, parseError := parser.ParseFile(fset, fh.URI().Filename(), buf, parserMode)
+       var tok *token.File
+       var fixed bool
+       if file != nil {
+               tok = fset.File(file.Pos())
+               if tok == nil {
+                       tok = fset.AddFile(fh.URI().Filename(), -1, len(buf))
+                       tok.SetLinesForContent(buf)
+                       return &parseGoData{
+                               parsed: &source.ParsedGoFile{
+                                       URI:  fh.URI(),
+                                       Mode: mode,
+                                       Src:  buf,
+                                       File: file,
+                                       Tok:  tok,
+                                       Mapper: &protocol.ColumnMapper{
+                                               URI:       fh.URI(),
+                                               Content:   buf,
+                                               Converter: span.NewTokenConverter(fset, tok),
+                                       },
+                                       ParseErr: parseError,
+                               },
+                       }
+               }
+
+               // Fix any badly parsed parts of the AST.
+               fixed = fixAST(ctx, file, tok, buf)
+
+               // Fix certain syntax errors that render the file unparseable.
+               newSrc := fixSrc(file, tok, buf)
+               if newSrc != nil {
+                       newFile, _ := parser.ParseFile(fset, fh.URI().Filename(), newSrc, parserMode)
+                       if newFile != nil {
+                               // Maintain the original parseError so we don't try formatting the doctored file.
+                               file = newFile
+                               buf = newSrc
+                               tok = fset.File(file.Pos())
+
+                               fixed = fixAST(ctx, file, tok, buf)
+                       }
+               }
+
+               if mode == source.ParseExported {
+                       trimAST(file)
+               }
+       }
+       // A missing file is always an error; use the parse error or make one up if there isn't one.
+       if file == nil {
+               if parseError == nil {
+                       parseError = errors.Errorf("parsing %s failed with no parse error reported", fh.URI())
+               }
+               err = parseError
+       }
+       m := &protocol.ColumnMapper{
+               URI:       fh.URI(),
+               Converter: span.NewTokenConverter(fset, tok),
+               Content:   buf,
+       }
+
+       return &parseGoData{
+               parsed: &source.ParsedGoFile{
+                       URI:      fh.URI(),
+                       Mode:     mode,
+                       Src:      buf,
+                       File:     file,
+                       Tok:      tok,
+                       Mapper:   m,
+                       ParseErr: parseError,
+               },
+               fixed: fixed,
+               err:   err,
+       }
+}
+
+// trimAST clears any part of the AST not relevant to type checking
+// expressions at pos.
+func trimAST(file *ast.File) {
+       ast.Inspect(file, func(n ast.Node) bool {
+               if n == nil {
+                       return false
+               }
+               switch n := n.(type) {
+               case *ast.FuncDecl:
+                       n.Body = nil
+               case *ast.BlockStmt:
+                       n.List = nil
+               case *ast.CaseClause:
+                       n.Body = nil
+               case *ast.CommClause:
+                       n.Body = nil
+               case *ast.CompositeLit:
+                       // types.Info.Types for long slice/array literals are particularly
+                       // expensive. Try to clear them out.
+                       at, ok := n.Type.(*ast.ArrayType)
+                       if !ok {
+                               break
+                       }
+                       // Removing the elements from an ellipsis array changes its type.
+                       // Try to set the length explicitly so we can continue.
+                       if _, ok := at.Len.(*ast.Ellipsis); ok {
+                               length, ok := arrayLength(n)
+                               if !ok {
+                                       break
+                               }
+                               at.Len = &ast.BasicLit{
+                                       Kind:     token.INT,
+                                       Value:    fmt.Sprint(length),
+                                       ValuePos: at.Len.Pos(),
+                               }
+                       }
+                       n.Elts = nil
+               }
+               return true
+       })
+}
+
+// arrayLength returns the length of some simple forms of ellipsis array literal.
+// Notably, it handles the tables in golang.org/x/text.
+func arrayLength(array *ast.CompositeLit) (int, bool) {
+       litVal := func(expr ast.Expr) (int, bool) {
+               lit, ok := expr.(*ast.BasicLit)
+               if !ok {
+                       return 0, false
+               }
+               val, err := strconv.ParseInt(lit.Value, 10, 64)
+               if err != nil {
+                       return 0, false
+               }
+               return int(val), true
+       }
+       largestKey := -1
+       for _, elt := range array.Elts {
+               kve, ok := elt.(*ast.KeyValueExpr)
+               if !ok {
+                       continue
+               }
+               switch key := kve.Key.(type) {
+               case *ast.BasicLit:
+                       if val, ok := litVal(key); ok && largestKey < val {
+                               largestKey = val
+                       }
+               case *ast.BinaryExpr:
+                       // golang.org/x/text uses subtraction (and only subtraction) in its indices.
+                       if key.Op != token.SUB {
+                               break
+                       }
+                       x, ok := litVal(key.X)
+                       if !ok {
+                               break
+                       }
+                       y, ok := litVal(key.Y)
+                       if !ok {
+                               break
+                       }
+                       if val := x - y; largestKey < val {
+                               largestKey = val
+                       }
+               }
+       }
+       if largestKey != -1 {
+               return largestKey + 1, true
+       }
+       return len(array.Elts), true
+}
+
+// fixAST inspects the AST and potentially modifies any *ast.BadStmts so that it can be
+// type-checked more effectively.
+func fixAST(ctx context.Context, n ast.Node, tok *token.File, src []byte) (fixed bool) {
+       var err error
+       walkASTWithParent(n, func(n, parent ast.Node) bool {
+               switch n := n.(type) {
+               case *ast.BadStmt:
+                       if fixed = fixDeferOrGoStmt(n, parent, tok, src); fixed {
+                               // Recursively fix in our fixed node.
+                               _ = fixAST(ctx, parent, tok, src)
+                       } else {
+                               err = errors.Errorf("unable to parse defer or go from *ast.BadStmt: %v", err)
+                       }
+                       return false
+               case *ast.BadExpr:
+                       if fixed = fixArrayType(n, parent, tok, src); fixed {
+                               // Recursively fix in our fixed node.
+                               _ = fixAST(ctx, parent, tok, src)
+                               return false
+                       }
+
+                       // Fix cases where parser interprets if/for/switch "init"
+                       // statement as "cond" expression, e.g.:
+                       //
+                       //   // "i := foo" is init statement, not condition.
+                       //   for i := foo
+                       //
+                       fixInitStmt(n, parent, tok, src)
+
+                       return false
+               case *ast.SelectorExpr:
+                       // Fix cases where a keyword prefix results in a phantom "_" selector, e.g.:
+                       //
+                       //   foo.var<> // want to complete to "foo.variance"
+                       //
+                       fixPhantomSelector(n, tok, src)
+                       return true
+
+               case *ast.BlockStmt:
+                       switch parent.(type) {
+                       case *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt:
+                               // Adjust closing curly brace of empty switch/select
+                               // statements so we can complete inside them.
+                               fixEmptySwitch(n, tok, src)
+                       }
+
+                       return true
+               default:
+                       return true
+               }
+       })
+       return fixed
+}
+
+// walkASTWithParent walks the AST rooted at n. The semantics are
+// similar to ast.Inspect except it does not call f(nil).
+func walkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) {
+       var ancestors []ast.Node
+       ast.Inspect(n, func(n ast.Node) (recurse bool) {
+               defer func() {
+                       if recurse {
+                               ancestors = append(ancestors, n)
+                       }
+               }()
+
+               if n == nil {
+                       ancestors = ancestors[:len(ancestors)-1]
+                       return false
+               }
+
+               var parent ast.Node
+               if len(ancestors) > 0 {
+                       parent = ancestors[len(ancestors)-1]
+               }
+
+               return f(n, parent)
+       })
+}
+
+// fixSrc attempts to modify the file's source code to fix certain
+// syntax errors that leave the rest of the file unparsed.
+func fixSrc(f *ast.File, tok *token.File, src []byte) (newSrc []byte) {
+       walkASTWithParent(f, func(n, parent ast.Node) bool {
+               if newSrc != nil {
+                       return false
+               }
+
+               switch n := n.(type) {
+               case *ast.BlockStmt:
+                       newSrc = fixMissingCurlies(f, n, parent, tok, src)
+               case *ast.SelectorExpr:
+                       newSrc = fixDanglingSelector(n, tok, src)
+               }
+
+               return newSrc == nil
+       })
+
+       return newSrc
+}
+
+// fixMissingCurlies adds in curly braces for block statements that
+// are missing curly braces. For example:
+//
+//   if foo
+//
+// becomes
+//
+//   if foo {}
+func fixMissingCurlies(f *ast.File, b *ast.BlockStmt, parent ast.Node, tok *token.File, src []byte) []byte {
+       // If the "{" is already in the source code, there isn't anything to
+       // fix since we aren't missing curlies.
+       if b.Lbrace.IsValid() {
+               braceOffset := tok.Offset(b.Lbrace)
+               if braceOffset < len(src) && src[braceOffset] == '{' {
+                       return nil
+               }
+       }
+
+       parentLine := tok.Line(parent.Pos())
+
+       if parentLine >= tok.LineCount() {
+               // If we are the last line in the file, no need to fix anything.
+               return nil
+       }
+
+       // Insert curlies at the end of parent's starting line. The parent
+       // is the statement that contains the block, e.g. *ast.IfStmt. The
+       // block's Pos()/End() can't be relied upon because they are based
+       // on the (missing) curly braces. We assume the statement is a
+       // single line for now and try sticking the curly braces at the end.
+       insertPos := tok.LineStart(parentLine+1) - 1
+
+       // Scootch position backwards until it's not in a comment. For example:
+       //
+       // if foo<> // some amazing comment |
+       // someOtherCode()
+       //
+       // insertPos will be located at "|", so we back it out of the comment.
+       didSomething := true
+       for didSomething {
+               didSomething = false
+               for _, c := range f.Comments {
+                       if c.Pos() < insertPos && insertPos <= c.End() {
+                               insertPos = c.Pos()
+                               didSomething = true
+                       }
+               }
+       }
+
+       // Bail out if line doesn't end in an ident or ".". This is to avoid
+       // cases like below where we end up making things worse by adding
+       // curlies:
+       //
+       //   if foo &&
+       //     bar<>
+       switch precedingToken(insertPos, tok, src) {
+       case token.IDENT, token.PERIOD:
+               // ok
+       default:
+               return nil
+       }
+
+       var buf bytes.Buffer
+       buf.Grow(len(src) + 3)
+       buf.Write(src[:tok.Offset(insertPos)])
+
+       // Detect if we need to insert a semicolon to fix "for" loop situations like:
+       //
+       //   for i := foo(); foo<>
+       //
+       // Just adding curlies is not sufficient to make things parse well.
+       if fs, ok := parent.(*ast.ForStmt); ok {
+               if _, ok := fs.Cond.(*ast.BadExpr); !ok {
+                       if xs, ok := fs.Post.(*ast.ExprStmt); ok {
+                               if _, ok := xs.X.(*ast.BadExpr); ok {
+                                       buf.WriteByte(';')
+                               }
+                       }
+               }
+       }
+
+       // Insert "{}" at insertPos.
+       buf.WriteByte('{')
+       buf.WriteByte('}')
+       buf.Write(src[tok.Offset(insertPos):])
+       return buf.Bytes()
+}
+
+// fixEmptySwitch moves empty switch/select statements' closing curly
+// brace down one line. This allows us to properly detect incomplete
+// "case" and "default" keywords as inside the switch statement. For
+// example:
+//
+//   switch {
+//   def<>
+//   }
+//
+// gets parsed like:
+//
+//   switch {
+//   }
+//
+// Later we manually pull out the "def" token, but we need to detect
+// that our "<>" position is inside the switch block. To do that we
+// move the curly brace so it looks like:
+//
+//   switch {
+//
+//   }
+//
+func fixEmptySwitch(body *ast.BlockStmt, tok *token.File, src []byte) {
+       // We only care about empty switch statements.
+       if len(body.List) > 0 || !body.Rbrace.IsValid() {
+               return
+       }
+
+       // If the right brace is actually in the source code at the
+       // specified position, don't mess with it.
+       braceOffset := tok.Offset(body.Rbrace)
+       if braceOffset < len(src) && src[braceOffset] == '}' {
+               return
+       }
+
+       braceLine := tok.Line(body.Rbrace)
+       if braceLine >= tok.LineCount() {
+               // If we are the last line in the file, no need to fix anything.
+               return
+       }
+
+       // Move the right brace down one line.
+       body.Rbrace = tok.LineStart(braceLine + 1)
+}
+
+// fixDanglingSelector inserts real "_" selector expressions in place
+// of phantom "_" selectors. For example:
+//
+// func _() {
+//   x.<>
+// }
+// var x struct { i int }
+//
+// To fix completion at "<>", we insert a real "_" after the "." so the
+// following declaration of "x" can be parsed and type checked
+// normally.
+func fixDanglingSelector(s *ast.SelectorExpr, tok *token.File, src []byte) []byte {
+       if !isPhantomUnderscore(s.Sel, tok, src) {
+               return nil
+       }
+
+       if !s.X.End().IsValid() {
+               return nil
+       }
+
+       // Insert directly after the selector's ".".
+       insertOffset := tok.Offset(s.X.End()) + 1
+       if src[insertOffset-1] != '.' {
+               return nil
+       }
+
+       var buf bytes.Buffer
+       buf.Grow(len(src) + 1)
+       buf.Write(src[:insertOffset])
+       buf.WriteByte('_')
+       buf.Write(src[insertOffset:])
+       return buf.Bytes()
+}
+
+// fixPhantomSelector tries to fix selector expressions with phantom
+// "_" selectors. In particular, we check if the selector is a
+// keyword, and if so we swap in an *ast.Ident with the keyword text. For example:
+//
+// foo.var
+//
+// yields a "_" selector instead of "var" since "var" is a keyword.
+func fixPhantomSelector(sel *ast.SelectorExpr, tok *token.File, src []byte) {
+       if !isPhantomUnderscore(sel.Sel, tok, src) {
+               return
+       }
+
+       // Only consider selectors directly abutting the selector ".". This
+       // avoids false positives in cases like:
+       //
+       //   foo. // don't think "var" is our selector
+       //   var bar = 123
+       //
+       if sel.Sel.Pos() != sel.X.End()+1 {
+               return
+       }
+
+       maybeKeyword := readKeyword(sel.Sel.Pos(), tok, src)
+       if maybeKeyword == "" {
+               return
+       }
+
+       replaceNode(sel, sel.Sel, &ast.Ident{
+               Name:    maybeKeyword,
+               NamePos: sel.Sel.Pos(),
+       })
+}
+
+// isPhantomUnderscore reports whether the given ident is a phantom
+// underscore. The parser sometimes inserts phantom underscores when
+// it encounters otherwise unparseable situations.
+func isPhantomUnderscore(id *ast.Ident, tok *token.File, src []byte) bool {
+       if id == nil || id.Name != "_" {
+               return false
+       }
+
+       // Phantom underscore means the underscore is not actually in the
+       // program text.
+       offset := tok.Offset(id.Pos())
+       return len(src) <= offset || src[offset] != '_'
+}
+
+// fixInitStmt fixes cases where the parser misinterprets an
+// if/for/switch "init" statement as the "cond" conditional. In cases
+// like "if i := 0" the user hasn't typed the semicolon yet so the
+// parser is looking for the conditional expression. However, "i := 0"
+// are not valid expressions, so we get a BadExpr.
+func fixInitStmt(bad *ast.BadExpr, parent ast.Node, tok *token.File, src []byte) {
+       if !bad.Pos().IsValid() || !bad.End().IsValid() {
+               return
+       }
+
+       // Try to extract a statement from the BadExpr.
+       stmtBytes := src[tok.Offset(bad.Pos()) : tok.Offset(bad.End()-1)+1]
+       stmt, err := parseStmt(bad.Pos(), stmtBytes)
+       if err != nil {
+               return
+       }
+
+       // If the parent statement doesn't already have an "init" statement,
+       // move the extracted statement into the "init" field and insert a
+       // dummy expression into the required "cond" field.
+       switch p := parent.(type) {
+       case *ast.IfStmt:
+               if p.Init != nil {
+                       return
+               }
+               p.Init = stmt
+               p.Cond = &ast.Ident{
+                       Name:    "_",
+                       NamePos: stmt.End(),
+               }
+       case *ast.ForStmt:
+               if p.Init != nil {
+                       return
+               }
+               p.Init = stmt
+               p.Cond = &ast.Ident{
+                       Name:    "_",
+                       NamePos: stmt.End(),
+               }
+       case *ast.SwitchStmt:
+               if p.Init != nil {
+                       return
+               }
+               p.Init = stmt
+               p.Tag = nil
+       }
+}
+
+// readKeyword reads the keyword starting at pos, if any.
+func readKeyword(pos token.Pos, tok *token.File, src []byte) string {
+       var kwBytes []byte
+       for i := tok.Offset(pos); i < len(src); i++ {
+               // Use a simplified identifier check since keywords are always lowercase ASCII.
+               if src[i] < 'a' || src[i] > 'z' {
+                       break
+               }
+               kwBytes = append(kwBytes, src[i])
+
+               // Stop search at arbitrarily chosen too-long-for-a-keyword length.
+               if len(kwBytes) > 15 {
+                       return ""
+               }
+       }
+
+       if kw := string(kwBytes); token.Lookup(kw).IsKeyword() {
+               return kw
+       }
+
+       return ""
+}
+
+// fixArrayType tries to parse an *ast.BadExpr into an *ast.ArrayType.
+// go/parser often turns lone array types like "[]int" into BadExprs
+// if it isn't expecting a type.
+func fixArrayType(bad *ast.BadExpr, parent ast.Node, tok *token.File, src []byte) bool {
+       // Our expected input is a bad expression that looks like "[]someExpr".
+
+       from := bad.Pos()
+       to := bad.End()
+
+       if !from.IsValid() || !to.IsValid() {
+               return false
+       }
+
+       exprBytes := make([]byte, 0, int(to-from)+3)
+       // Avoid doing tok.Offset(to) since that panics if badExpr ends at EOF.
+       exprBytes = append(exprBytes, src[tok.Offset(from):tok.Offset(to-1)+1]...)
+       exprBytes = bytes.TrimSpace(exprBytes)
+
+       // If our expression ends in "]" (e.g. "[]"), add a phantom selector
+       // so we can complete directly after the "[]".
+       if len(exprBytes) > 0 && exprBytes[len(exprBytes)-1] == ']' {
+               exprBytes = append(exprBytes, '_')
+       }
+
+       // Add "{}" to turn our ArrayType into a CompositeLit. This is to
+       // handle the case of "[...]int" where we must make it a composite
+       // literal to be parseable.
+       exprBytes = append(exprBytes, '{', '}')
+
+       expr, err := parseExpr(from, exprBytes)
+       if err != nil {
+               return false
+       }
+
+       cl, _ := expr.(*ast.CompositeLit)
+       if cl == nil {
+               return false
+       }
+
+       at, _ := cl.Type.(*ast.ArrayType)
+       if at == nil {
+               return false
+       }
+
+       return replaceNode(parent, bad, at)
+}
+
+// precedingToken scans src to find the token preceding pos.
+func precedingToken(pos token.Pos, tok *token.File, src []byte) token.Token {
+       s := &scanner.Scanner{}
+       s.Init(tok, src, nil, 0)
+
+       var lastTok token.Token
+       for {
+               p, t, _ := s.Scan()
+               if t == token.EOF || p >= pos {
+                       break
+               }
+
+               lastTok = t
+       }
+       return lastTok
+}
+
+// fixDeferOrGoStmt tries to parse an *ast.BadStmt into a defer or a go statement.
+//
+// go/parser packages a statement of the form "defer x." as an *ast.BadStmt because
+// it does not include a call expression. This means that go/types skips type-checking
+// this statement entirely, and we can't use the type information when completing.
+// Here, we try to generate a fake *ast.DeferStmt or *ast.GoStmt to put into the AST,
+// instead of the *ast.BadStmt.
+func fixDeferOrGoStmt(bad *ast.BadStmt, parent ast.Node, tok *token.File, src []byte) bool {
+       // Check if we have a bad statement containing either a "go" or "defer".
+       s := &scanner.Scanner{}
+       s.Init(tok, src, nil, 0)
+
+       var (
+               pos token.Pos
+               tkn token.Token
+       )
+       for {
+               if tkn == token.EOF {
+                       return false
+               }
+               if pos >= bad.From {
+                       break
+               }
+               pos, tkn, _ = s.Scan()
+       }
+
+       var stmt ast.Stmt
+       switch tkn {
+       case token.DEFER:
+               stmt = &ast.DeferStmt{
+                       Defer: pos,
+               }
+       case token.GO:
+               stmt = &ast.GoStmt{
+                       Go: pos,
+               }
+       default:
+               return false
+       }
+
+       var (
+               from, to, last   token.Pos
+               lastToken        token.Token
+               braceDepth       int
+               phantomSelectors []token.Pos
+       )
+FindTo:
+       for {
+               to, tkn, _ = s.Scan()
+
+               if from == token.NoPos {
+                       from = to
+               }
+
+               switch tkn {
+               case token.EOF:
+                       break FindTo
+               case token.SEMICOLON:
+                       // If we aren't in nested braces, end of statement means
+                       // end of expression.
+                       if braceDepth == 0 {
+                               break FindTo
+                       }
+               case token.LBRACE:
+                       braceDepth++
+               }
+
+               // This handles the common dangling selector case. For example in
+               //
+               // defer fmt.
+               // y := 1
+               //
+               // we notice the dangling period and end our expression.
+               //
+               // If the previous token was a "." and we are looking at a "}",
+               // the period is likely a dangling selector and needs a phantom
+               // "_". Likewise if the current token is on a different line than
+               // the period, the period is likely a dangling selector.
+               if lastToken == token.PERIOD && (tkn == token.RBRACE || tok.Line(to) > tok.Line(last)) {
+                       // Insert phantom "_" selector after the dangling ".".
+                       phantomSelectors = append(phantomSelectors, last+1)
+                       // If we aren't in a block then end the expression after the ".".
+                       if braceDepth == 0 {
+                               to = last + 1
+                               break
+                       }
+               }
+
+               lastToken = tkn
+               last = to
+
+               switch tkn {
+               case token.RBRACE:
+                       braceDepth--
+                       if braceDepth <= 0 {
+                               if braceDepth == 0 {
+                                       // +1 to include the "}" itself.
+                                       to += 1
+                               }
+                               break FindTo
+                       }
+               }
+       }
+
+       if !from.IsValid() || tok.Offset(from) >= len(src) {
+               return false
+       }
+
+       if !to.IsValid() || tok.Offset(to) >= len(src) {
+               return false
+       }
+
+       // Insert any phantom selectors needed to prevent dangling "." from messing
+       // up the AST.
+       exprBytes := make([]byte, 0, int(to-from)+len(phantomSelectors))
+       for i, b := range src[tok.Offset(from):tok.Offset(to)] {
+               if len(phantomSelectors) > 0 && from+token.Pos(i) == phantomSelectors[0] {
+                       exprBytes = append(exprBytes, '_')
+                       phantomSelectors = phantomSelectors[1:]
+               }
+               exprBytes = append(exprBytes, b)
+       }
+
+       if len(phantomSelectors) > 0 {
+               exprBytes = append(exprBytes, '_')
+       }
+
+       expr, err := parseExpr(from, exprBytes)
+       if err != nil {
+               return false
+       }
+
+       // Package the expression into a fake *ast.CallExpr and re-insert
+       // into the function.
+       call := &ast.CallExpr{
+               Fun:    expr,
+               Lparen: to,
+               Rparen: to,
+       }
+
+       switch stmt := stmt.(type) {
+       case *ast.DeferStmt:
+               stmt.Call = call
+       case *ast.GoStmt:
+               stmt.Call = call
+       }
+
+       return replaceNode(parent, bad, stmt)
+}
+
+// parseStmt parses the statement in src and updates its position to
+// start at pos.
+func parseStmt(pos token.Pos, src []byte) (ast.Stmt, error) {
+       // Wrap our expression to make it a valid Go file we can pass to ParseFile.
+       fileSrc := bytes.Join([][]byte{
+               []byte("package fake;func _(){"),
+               src,
+               []byte("}"),
+       }, nil)
+
+       // Use ParseFile instead of ParseExpr because ParseFile has
+       // best-effort behavior, whereas ParseExpr fails hard on any error.
+       fakeFile, err := parser.ParseFile(token.NewFileSet(), "", fileSrc, 0)
+       if fakeFile == nil {
+               return nil, errors.Errorf("error reading fake file source: %v", err)
+       }
+
+       // Extract our expression node from inside the fake file.
+       if len(fakeFile.Decls) == 0 {
+               return nil, errors.Errorf("error parsing fake file: %v", err)
+       }
+
+       fakeDecl, _ := fakeFile.Decls[0].(*ast.FuncDecl)
+       if fakeDecl == nil || len(fakeDecl.Body.List) == 0 {
+               return nil, errors.Errorf("no statement in %s: %v", src, err)
+       }
+
+       stmt := fakeDecl.Body.List[0]
+
+       // parser.ParseFile returns undefined positions.
+       // Adjust them for the current file.
+       offsetPositions(stmt, pos-1-(stmt.Pos()-1))
+
+       return stmt, nil
+}
+
+// parseExpr parses the expression in src and updates its position to
+// start at pos.
+func parseExpr(pos token.Pos, src []byte) (ast.Expr, error) {
+       stmt, err := parseStmt(pos, src)
+       if err != nil {
+               return nil, err
+       }
+
+       exprStmt, ok := stmt.(*ast.ExprStmt)
+       if !ok {
+               return nil, errors.Errorf("no expr in %s: %v", src, err)
+       }
+
+       return exprStmt.X, nil
+}
+
+var tokenPosType = reflect.TypeOf(token.NoPos)
+
+// offsetPositions applies an offset to the positions in an ast.Node.
+func offsetPositions(n ast.Node, offset token.Pos) {
+       ast.Inspect(n, func(n ast.Node) bool {
+               if n == nil {
+                       return false
+               }
+
+               v := reflect.ValueOf(n).Elem()
+
+               switch v.Kind() {
+               case reflect.Struct:
+                       for i := 0; i < v.NumField(); i++ {
+                               f := v.Field(i)
+                               if f.Type() != tokenPosType {
+                                       continue
+                               }
+
+                               if !f.CanSet() {
+                                       continue
+                               }
+
+                               f.SetInt(f.Int() + int64(offset))
+                       }
+               }
+
+               return true
+       })
+}
+
+// replaceNode updates parent's child oldChild to be newChild. It
+// returns whether it replaced successfully.
+func replaceNode(parent, oldChild, newChild ast.Node) bool {
+       if parent == nil || oldChild == nil || newChild == nil {
+               return false
+       }
+
+       parentVal := reflect.ValueOf(parent).Elem()
+       if parentVal.Kind() != reflect.Struct {
+               return false
+       }
+
+       newChildVal := reflect.ValueOf(newChild)
+
+       tryReplace := func(v reflect.Value) bool {
+               if !v.CanSet() || !v.CanInterface() {
+                       return false
+               }
+
+               // If the existing value is oldChild, we found our child. Make
+               // sure our newChild is assignable and then make the swap.
+               if v.Interface() == oldChild && newChildVal.Type().AssignableTo(v.Type()) {
+                       v.Set(newChildVal)
+                       return true
+               }
+
+               return false
+       }
+
+       // Loop over parent's struct fields.
+       for i := 0; i < parentVal.NumField(); i++ {
+               f := parentVal.Field(i)
+
+               switch f.Kind() {
+               // Check interface and pointer fields.
+               case reflect.Interface, reflect.Ptr:
+                       if tryReplace(f) {
+                               return true
+                       }
+
+               // Search through any slice fields.
+               case reflect.Slice:
+                       for i := 0; i < f.Len(); i++ {
+                               if tryReplace(f.Index(i)) {
+                                       return true
+                               }
+                       }
+               }
+       }
+
+       return false
+}