internal/lsp/source: move completion to its own package

Completion is slowly becoming a large part of internal/lsp/source and it
makes sense to move to its own seperate package inside source to make
future refactors easier. As a part of this change, any unexported
members from source required by completion are now exported. Util
functions only required by completion are moved from
internal/lsp/source/util.go to internal/lsp/source/completion/util.go.

Change-Id: I6b7405ec598c910545e649bb0e6aa02ffa653b38
Reviewed-on: https://go-review.googlesource.com/c/tools/+/253178
Run-TryBot: Danish Dua <danishdua@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
diff --git a/internal/lsp/completion.go b/internal/lsp/completion.go
index a49f5ae..f02f915 100644
--- a/internal/lsp/completion.go
+++ b/internal/lsp/completion.go
@@ -13,6 +13,7 @@
 	"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/lsp/source/completion"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -22,11 +23,11 @@
 	if !ok {
 		return nil, err
 	}
-	var candidates []source.CompletionItem
-	var surrounding *source.Selection
+	var candidates []completion.CompletionItem
+	var surrounding *completion.Selection
 	switch fh.Kind() {
 	case source.Go:
-		candidates, surrounding, err = source.Completion(ctx, snapshot, fh, params.Position, params.Context.TriggerCharacter)
+		candidates, surrounding, err = completion.Completion(ctx, snapshot, fh, params.Position, params.Context.TriggerCharacter)
 	case source.Mod:
 		candidates, surrounding = nil, nil
 	}
@@ -103,7 +104,7 @@
 	}, nil
 }
 
-func toProtocolCompletionItems(candidates []source.CompletionItem, rng protocol.Range, options source.Options) []protocol.CompletionItem {
+func toProtocolCompletionItems(candidates []completion.CompletionItem, rng protocol.Range, options source.Options) []protocol.CompletionItem {
 	var (
 		items                  = make([]protocol.CompletionItem, 0, len(candidates))
 		numDeepCompletionsSeen int
@@ -115,7 +116,7 @@
 			if !options.DeepCompletion {
 				continue
 			}
-			if numDeepCompletionsSeen >= source.MaxDeepCompletions {
+			if numDeepCompletionsSeen >= completion.MaxDeepCompletions {
 				continue
 			}
 			numDeepCompletionsSeen++
diff --git a/internal/lsp/source/call_hierarchy.go b/internal/lsp/source/call_hierarchy.go
index 180f6b1..62de3ab 100644
--- a/internal/lsp/source/call_hierarchy.go
+++ b/internal/lsp/source/call_hierarchy.go
@@ -152,7 +152,7 @@
 		nameStart, nameEnd = funcLit.Type.Func, funcLit.Type.Params.Pos()
 		kind = protocol.Function
 	}
-	rng, err := newMappedRange(snapshot.FileSet(), pgf.Mapper, nameStart, nameEnd).Range()
+	rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, nameStart, nameEnd).Range()
 	if err != nil {
 		return protocol.CallHierarchyItem{}, err
 	}
@@ -229,7 +229,7 @@
 
 	callRanges := []protocol.Range{}
 	for _, call := range callPositions {
-		callRange, err := newMappedRange(fset, mapper, call.start, call.end).Range()
+		callRange, err := NewMappedRange(fset, mapper, call.start, call.end).Range()
 		if err != nil {
 			return nil, err
 		}
diff --git a/internal/lsp/source/code_lens.go b/internal/lsp/source/code_lens.go
index 966dcf2..427b548 100644
--- a/internal/lsp/source/code_lens.go
+++ b/internal/lsp/source/code_lens.go
@@ -40,7 +40,7 @@
 	if !strings.HasSuffix(fh.URI().Filename(), "_test.go") {
 		return nil, nil
 	}
-	pkg, pgf, err := getParsedFile(ctx, snapshot, fh, WidestPackage)
+	pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, WidestPackage)
 	if err != nil {
 		return nil, err
 	}
@@ -54,7 +54,7 @@
 		if benchmarkRe.MatchString(fn.Name.Name) {
 			benchFns = append(benchFns, fn.Name.Name)
 		}
-		rng, err := newMappedRange(snapshot.FileSet(), pgf.Mapper, d.Pos(), d.Pos()).Range()
+		rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, d.Pos(), d.Pos()).Range()
 		if err != nil {
 			return nil, err
 		}
@@ -90,7 +90,7 @@
 		}
 	}
 	// add a code lens to the top of the file which runs all benchmarks in the file
-	rng, err := newMappedRange(snapshot.FileSet(), pgf.Mapper, pgf.File.Package, pgf.File.Package).Range()
+	rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, pgf.File.Package, pgf.File.Package).Range()
 	if err != nil {
 		return nil, err
 	}
@@ -158,7 +158,7 @@
 			if !strings.HasPrefix(l.Text, ggDirective) {
 				continue
 			}
-			rng, err := newMappedRange(snapshot.FileSet(), pgf.Mapper, l.Pos(), l.Pos()+token.Pos(len(ggDirective))).Range()
+			rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, l.Pos(), l.Pos()+token.Pos(len(ggDirective))).Range()
 			if err != nil {
 				return nil, err
 			}
@@ -209,7 +209,7 @@
 	if c == nil {
 		return nil, nil
 	}
-	rng, err := newMappedRange(snapshot.FileSet(), pgf.Mapper, c.Pos(), c.EndPos).Range()
+	rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, c.Pos(), c.EndPos).Range()
 	if err != nil {
 		return nil, err
 	}
@@ -230,11 +230,11 @@
 }
 
 func toggleDetailsCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) {
-	_, pgf, err := getParsedFile(ctx, snapshot, fh, WidestPackage)
+	_, pgf, err := GetParsedFile(ctx, snapshot, fh, WidestPackage)
 	if err != nil {
 		return nil, err
 	}
-	rng, err := newMappedRange(snapshot.FileSet(), pgf.Mapper, pgf.File.Package, pgf.File.Package).Range()
+	rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, pgf.File.Package, pgf.File.Package).Range()
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/lsp/source/command.go b/internal/lsp/source/command.go
index b927aa0..66d2f1d 100644
--- a/internal/lsp/source/command.go
+++ b/internal/lsp/source/command.go
@@ -208,7 +208,7 @@
 // getAllSuggestedFixInputs is a helper function to collect all possible needed
 // inputs for an AppliesFunc or SuggestedFixFunc.
 func getAllSuggestedFixInputs(ctx context.Context, snapshot Snapshot, fh FileHandle, pRng protocol.Range) (*token.FileSet, span.Range, []byte, *ast.File, *protocol.ColumnMapper, *types.Package, *types.Info, error) {
-	pkg, pgf, err := getParsedFile(ctx, snapshot, fh, NarrowestPackage)
+	pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage)
 	if err != nil {
 		return nil, span.Range{}, nil, nil, nil, nil, nil, errors.Errorf("getting file for Identifier: %w", err)
 	}
diff --git a/internal/lsp/source/completion.go b/internal/lsp/source/completion/completion.go
similarity index 96%
rename from internal/lsp/source/completion.go
rename to internal/lsp/source/completion/completion.go
index 101d2df..edaf6f0 100644
--- a/internal/lsp/source/completion.go
+++ b/internal/lsp/source/completion/completion.go
@@ -2,7 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package source
+// Package completion provides core functionality for code completion in Go
+// editors and tools.
+package completion
 
 import (
 	"context"
@@ -25,6 +27,7 @@
 	"golang.org/x/tools/internal/lsp/fuzzy"
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/snippet"
+	"golang.org/x/tools/internal/lsp/source"
 	errors "golang.org/x/xerrors"
 )
 
@@ -84,6 +87,18 @@
 	obj types.Object
 }
 
+// completionOptions holds completion specific configuration.
+type completionOptions struct {
+	deepCompletion    bool
+	unimported        bool
+	documentation     bool
+	fullDocumentation bool
+	placeholders      bool
+	literal           bool
+	matcher           source.Matcher
+	budget            time.Duration
+}
+
 // Snippet is a convenience returns the snippet if available, otherwise
 // the InsertText.
 // used for an item, depending on if the callee wants placeholders or not.
@@ -135,8 +150,8 @@
 
 // completer contains the necessary information for a single completion request.
 type completer struct {
-	snapshot Snapshot
-	pkg      Package
+	snapshot source.Snapshot
+	pkg      source.Package
 	qf       types.Qualifier
 	opts     *completionOptions
 
@@ -228,7 +243,7 @@
 type importInfo struct {
 	importPath string
 	name       string
-	pkg        Package
+	pkg        source.Package
 }
 
 type methodSetKey struct {
@@ -240,7 +255,7 @@
 type Selection struct {
 	content string
 	cursor  token.Pos
-	mappedRange
+	source.MappedRange
 }
 
 func (p Selection) Content() string {
@@ -248,19 +263,19 @@
 }
 
 func (p Selection) Start() token.Pos {
-	return p.mappedRange.spanRange.Start
+	return p.MappedRange.SpanRange().Start
 }
 
 func (p Selection) End() token.Pos {
-	return p.mappedRange.spanRange.End
+	return p.MappedRange.SpanRange().End
 }
 
 func (p Selection) Prefix() string {
-	return p.content[:p.cursor-p.spanRange.Start]
+	return p.content[:p.cursor-p.SpanRange().Start]
 }
 
 func (p Selection) Suffix() string {
-	return p.content[p.cursor-p.spanRange.Start:]
+	return p.content[p.cursor-p.SpanRange().Start:]
 }
 
 func (c *completer) setSurrounding(ident *ast.Ident) {
@@ -275,7 +290,7 @@
 		content: ident.Name,
 		cursor:  c.pos,
 		// Overwrite the prefix only.
-		mappedRange: newMappedRange(c.snapshot.FileSet(), c.mapper, ident.Pos(), ident.End()),
+		MappedRange: source.NewMappedRange(c.snapshot.FileSet(), c.mapper, ident.Pos(), ident.End()),
 	}
 
 	c.setMatcherFromPrefix(c.surrounding.Prefix())
@@ -283,9 +298,9 @@
 
 func (c *completer) setMatcherFromPrefix(prefix string) {
 	switch c.opts.matcher {
-	case Fuzzy:
+	case source.Fuzzy:
 		c.matcher = fuzzy.NewMatcher(prefix)
-	case CaseSensitive:
+	case source.CaseSensitive:
 		c.matcher = prefixMatcher(prefix)
 	default:
 		c.matcher = insensitivePrefixMatcher(strings.ToLower(prefix))
@@ -297,7 +312,7 @@
 		c.surrounding = &Selection{
 			content:     "",
 			cursor:      c.pos,
-			mappedRange: newMappedRange(c.snapshot.FileSet(), c.mapper, c.pos, c.pos),
+			MappedRange: source.NewMappedRange(c.snapshot.FileSet(), c.mapper, c.pos, c.pos),
 		}
 	}
 	return c.surrounding
@@ -470,13 +485,13 @@
 // The selection is computed based on the preceding identifier and can be used by
 // the client to score the quality of the completion. For instance, some clients
 // may tolerate imperfect matches as valid completion results, since users may make typos.
-func Completion(ctx context.Context, snapshot Snapshot, fh FileHandle, protoPos protocol.Position, triggerCharacter string) ([]CompletionItem, *Selection, error) {
+func Completion(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, protoPos protocol.Position, triggerCharacter string) ([]CompletionItem, *Selection, error) {
 	ctx, done := event.Start(ctx, "source.Completion")
 	defer done()
 
 	startTime := time.Now()
 
-	pkg, pgf, err := getParsedFile(ctx, snapshot, fh, NarrowestPackage)
+	pkg, pgf, err := source.GetParsedFile(ctx, snapshot, fh, source.NarrowestPackage)
 	if err != nil || pgf.File.Package == token.NoPos {
 		// If we can't parse this file or find position for the package
 		// keyword, it may be missing a package declaration. Try offering
@@ -485,7 +500,7 @@
 		// present but no package name exists.
 		items, surrounding, innerErr := packageClauseCompletions(ctx, snapshot, fh, protoPos)
 		if innerErr != nil {
-			// return the error for getParsedFile since it's more relevant in this situation.
+			// return the error for GetParsedFile since it's more relevant in this situation.
 			return nil, nil, errors.Errorf("getting file for Completion: %w", err)
 
 		}
@@ -547,7 +562,7 @@
 	c := &completer{
 		pkg:                       pkg,
 		snapshot:                  snapshot,
-		qf:                        qualifier(pgf.File, pkg.GetTypes(), pkg.GetTypesInfo()),
+		qf:                        source.Qualifier(pgf.File, pkg.GetTypes(), pkg.GetTypesInfo()),
 		triggerCharacter:          triggerCharacter,
 		filename:                  fh.URI().Filename(),
 		file:                      pgf.File,
@@ -561,7 +576,7 @@
 			deepCompletion:    opts.DeepCompletion,
 			unimported:        opts.UnimportedCompletion,
 			documentation:     opts.CompletionDocumentation,
-			fullDocumentation: opts.HoverKind == FullDocumentation,
+			fullDocumentation: opts.HoverKind == source.FullDocumentation,
 			placeholders:      opts.Placeholders,
 			literal:           opts.LiteralCompletions && opts.InsertTextFormat == protocol.SnippetTextFormat,
 			budget:            opts.CompletionBudget,
@@ -777,7 +792,7 @@
 	c.surrounding = &Selection{
 		content:     searchImport.Path.Value,
 		cursor:      c.pos,
-		mappedRange: newMappedRange(c.snapshot.FileSet(), c.mapper, searchImport.Path.Pos(), searchImport.Path.End()),
+		MappedRange: source.NewMappedRange(c.snapshot.FileSet(), c.mapper, searchImport.Path.Pos(), searchImport.Path.End()),
 	}
 
 	seenImports := make(map[string]struct{})
@@ -1010,7 +1025,7 @@
 	c.surrounding = &Selection{
 		content: cursorComment.Text[start:end],
 		cursor:  c.pos,
-		mappedRange: newMappedRange(c.snapshot.FileSet(), c.mapper,
+		MappedRange: source.NewMappedRange(c.snapshot.FileSet(), c.mapper,
 			token.Pos(int(cursorComment.Slash)+start), token.Pos(int(cursorComment.Slash)+end)),
 	}
 	c.setMatcherFromPrefix(c.surrounding.Prefix())
@@ -1242,7 +1257,7 @@
 
 // lexical finds completions in the lexical environment.
 func (c *completer) lexical(ctx context.Context) error {
-	scopes := collectScopes(c.pkg.GetTypesInfo(), c.path, c.pos)
+	scopes := source.CollectScopes(c.pkg.GetTypesInfo(), c.path, c.pos)
 	scopes = append(scopes, c.pkg.GetTypes().Scope(), types.Universe)
 
 	var (
@@ -1320,7 +1335,7 @@
 	}
 
 	if c.inference.objType != nil {
-		if named, _ := deref(c.inference.objType).(*types.Named); named != nil {
+		if named, _ := source.Deref(c.inference.objType).(*types.Named); named != nil {
 			// If we expected a named type, check the type's package for
 			// completion items. This is useful when the current file hasn't
 			// imported the type's package yet.
@@ -1356,7 +1371,7 @@
 	}
 
 	if t := c.inference.objType; t != nil {
-		t = deref(t)
+		t = source.Deref(t)
 
 		// If we have an expected type and it is _not_ a named type,
 		// handle it specially. Non-named types like "[]int" will never be
@@ -1390,26 +1405,6 @@
 	return nil
 }
 
-func collectScopes(info *types.Info, path []ast.Node, pos token.Pos) []*types.Scope {
-	// scopes[i], where i<len(path), is the possibly nil Scope of path[i].
-	var scopes []*types.Scope
-	for _, n := range path {
-		// Include *FuncType scope if pos is inside the function body.
-		switch node := n.(type) {
-		case *ast.FuncDecl:
-			if node.Body != nil && nodeContains(node.Body, pos) {
-				n = node.Type
-			}
-		case *ast.FuncLit:
-			if node.Body != nil && nodeContains(node.Body, pos) {
-				n = node.Type
-			}
-		}
-		scopes = append(scopes, info.Scopes[n])
-	}
-	return scopes
-}
-
 func (c *completer) unimportedPackages(ctx context.Context, seen map[string]struct{}) error {
 	var prefix string
 	if c.surrounding != nil {
@@ -1507,27 +1502,13 @@
 // alreadyImports reports whether f has an import with the specified path.
 func alreadyImports(f *ast.File, path string) bool {
 	for _, s := range f.Imports {
-		if importPath(s) == path {
+		if source.ImportPath(s) == path {
 			return true
 		}
 	}
 	return false
 }
 
-// importPath returns the unquoted import path of s,
-// or "" if the path is not properly quoted.
-func importPath(s *ast.ImportSpec) string {
-	t, err := strconv.Unquote(s.Path.Value)
-	if err != nil {
-		return ""
-	}
-	return t
-}
-
-func nodeContains(n ast.Node, pos token.Pos) bool {
-	return n != nil && n.Pos() <= pos && pos <= n.End()
-}
-
 func (c *completer) inConstDecl() bool {
 	for _, n := range c.path {
 		if decl, ok := n.(*ast.GenDecl); ok && decl.Tok == token.CONST {
@@ -1614,7 +1595,7 @@
 
 			clInfo := compLitInfo{
 				cl:     n,
-				clType: deref(tv.Type).Underlying(),
+				clType: source.Deref(tv.Type).Underlying(),
 			}
 
 			var (
@@ -2083,7 +2064,7 @@
 			}
 			return inf
 		case *ast.RangeStmt:
-			if nodeContains(node.X, c.pos) {
+			if source.NodeContains(node.X, c.pos) {
 				inf.objKind |= kindSlice | kindArray | kindMap | kindString
 				if node.Value == nil {
 					inf.objKind |= kindChan
@@ -2239,11 +2220,11 @@
 	case *ast.CompositeLit:
 		// Doesn't break inference if pos is in type name.
 		// For example: "Foo<>{Bar: 123}"
-		return !nodeContains(n.Type, pos)
+		return !source.NodeContains(n.Type, pos)
 	case *ast.CallExpr:
 		// Doesn't break inference if pos is in func name.
 		// For example: "Foo<>(123)"
-		return !nodeContains(n.Fun, pos)
+		return !source.NodeContains(n.Fun, pos)
 	case *ast.FuncLit, *ast.IndexExpr, *ast.SliceExpr:
 		return true
 	default:
@@ -2356,7 +2337,7 @@
 		case *ast.MapType:
 			inf.wantTypeName = true
 			if n.Key != nil {
-				inf.wantComparable = nodeContains(n.Key, c.pos)
+				inf.wantComparable = source.NodeContains(n.Key, c.pos)
 			} else {
 				// If the key is empty, assume we are completing the key if
 				// pos is directly after the "map[".
@@ -2364,10 +2345,10 @@
 			}
 			break Nodes
 		case *ast.ValueSpec:
-			inf.wantTypeName = nodeContains(n.Type, c.pos)
+			inf.wantTypeName = source.NodeContains(n.Type, c.pos)
 			break Nodes
 		case *ast.TypeSpec:
-			inf.wantTypeName = nodeContains(n.Type, c.pos)
+			inf.wantTypeName = source.NodeContains(n.Type, c.pos)
 		default:
 			if breaksExpectedTypeInference(p, c.pos) {
 				return typeNameInference{}
@@ -2752,7 +2733,7 @@
 		return true
 	}
 
-	if !isInterface(t) && typeMatches(types.NewPointer(t)) {
+	if !source.IsInterface(t) && typeMatches(types.NewPointer(t)) {
 		if c.inference.typeName.compLitType {
 			// If we are completing a composite literal type as in
 			// "foo<>{}", to make a pointer we must prepend "&".
diff --git a/internal/lsp/source/completion_builtin.go b/internal/lsp/source/completion/completion_builtin.go
similarity index 99%
rename from internal/lsp/source/completion_builtin.go
rename to internal/lsp/source/completion/completion_builtin.go
index 2ddb553..f4137b3 100644
--- a/internal/lsp/source/completion_builtin.go
+++ b/internal/lsp/source/completion/completion_builtin.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package source
+package completion
 
 import (
 	"context"
diff --git a/internal/lsp/source/completion_format.go b/internal/lsp/source/completion/completion_format.go
similarity index 81%
rename from internal/lsp/source/completion_format.go
rename to internal/lsp/source/completion/completion_format.go
index 6dfa260..793f1ec 100644
--- a/internal/lsp/source/completion_format.go
+++ b/internal/lsp/source/completion/completion_format.go
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package source
+package completion
 
 import (
 	"context"
 	"fmt"
-	"go/ast"
 	"go/types"
 	"strings"
 
@@ -16,6 +15,7 @@
 	"golang.org/x/tools/internal/lsp/debug/tag"
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/snippet"
+	"golang.org/x/tools/internal/lsp/source"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -43,25 +43,25 @@
 	// expandFuncCall mutates the completion label, detail, and snippet
 	// to that of an invocation of sig.
 	expandFuncCall := func(sig *types.Signature) error {
-		s, err := newSignature(ctx, c.snapshot, c.pkg, c.file, "", sig, nil, c.qf)
+		s, err := source.NewSignature(ctx, c.snapshot, c.pkg, c.file, "", sig, nil, c.qf)
 		if err != nil {
 			return err
 		}
-		snip = c.functionCallSnippet(label, s.params)
-		detail = "func" + s.format()
+		snip = c.functionCallSnippet(label, s.Params())
+		detail = "func" + s.Format()
 		return nil
 	}
 
 	switch obj := obj.(type) {
 	case *types.TypeName:
-		detail, kind = formatType(obj.Type(), c.qf)
+		detail, kind = source.FormatType(obj.Type(), c.qf)
 	case *types.Const:
 		kind = protocol.ConstantCompletion
 	case *types.Var:
 		if _, ok := obj.Type().(*types.Struct); ok {
 			detail = "struct{...}" // for anonymous structs
 		} else if obj.IsField() {
-			detail = formatVarType(ctx, c.snapshot, c.pkg, c.file, obj, c.qf)
+			detail = source.FormatVarType(ctx, c.snapshot, c.pkg, c.file, obj, c.qf)
 		}
 		if obj.IsField() {
 			kind = protocol.FieldCompletion
@@ -184,7 +184,7 @@
 		searchPkg = cand.imp.pkg
 	}
 
-	pgf, pkg, err := findPosInPackage(c.snapshot, searchPkg, obj.Pos())
+	pgf, pkg, err := source.FindPosInPackage(c.snapshot, searchPkg, obj.Pos())
 	if err != nil {
 		return item, nil
 	}
@@ -198,7 +198,7 @@
 		return item, nil
 	}
 
-	hover, err := hoverInfo(pkg, obj, decl)
+	hover, err := source.HoverInfo(pkg, obj, decl)
 	if err != nil {
 		event.Error(ctx, "failed to find Hover", err, tag.URI.Of(uri))
 		return item, nil
@@ -221,7 +221,7 @@
 		return nil, err
 	}
 
-	return computeOneImportFixEdits(ctx, c.snapshot, pgf, &imports.ImportFix{
+	return source.ComputeOneImportFixEdits(ctx, c.snapshot, pgf, &imports.ImportFix{
 		StmtInfo: imports.ImportInfo{
 			ImportPath: imp.importPath,
 			Name:       imp.name,
@@ -243,12 +243,12 @@
 		item.Kind = protocol.ConstantCompletion
 	case *types.Builtin:
 		item.Kind = protocol.FunctionCompletion
-		sig, err := newBuiltinSignature(ctx, c.snapshot, obj.Name())
+		sig, err := source.NewBuiltinSignature(ctx, c.snapshot, obj.Name())
 		if err != nil {
 			return CompletionItem{}, err
 		}
-		item.Detail = "func" + sig.format()
-		item.snippet = c.functionCallSnippet(obj.Name(), sig.params)
+		item.Detail = "func" + sig.Format()
+		item.snippet = c.functionCallSnippet(obj.Name(), sig.Params())
 	case *types.TypeName:
 		if types.IsInterface(obj.Type()) {
 			item.Kind = protocol.InterfaceCompletion
@@ -260,31 +260,3 @@
 	}
 	return item, nil
 }
-
-// qualifier returns a function that appropriately formats a types.PkgName
-// appearing in a *ast.File.
-func qualifier(f *ast.File, pkg *types.Package, info *types.Info) types.Qualifier {
-	// Construct mapping of import paths to their defined or implicit names.
-	imports := make(map[*types.Package]string)
-	for _, imp := range f.Imports {
-		var obj types.Object
-		if imp.Name != nil {
-			obj = info.Defs[imp.Name]
-		} else {
-			obj = info.Implicits[imp]
-		}
-		if pkgname, ok := obj.(*types.PkgName); ok {
-			imports[pkgname.Imported()] = pkgname.Name()
-		}
-	}
-	// Define qualifier to replace full package paths with names of the imports.
-	return func(p *types.Package) string {
-		if p == pkg {
-			return ""
-		}
-		if name, ok := imports[p]; ok {
-			return name
-		}
-		return p.Name()
-	}
-}
diff --git a/internal/lsp/source/completion_keywords.go b/internal/lsp/source/completion/completion_keywords.go
similarity index 93%
rename from internal/lsp/source/completion_keywords.go
rename to internal/lsp/source/completion/completion_keywords.go
index 324d5bd..bbf59b0 100644
--- a/internal/lsp/source/completion_keywords.go
+++ b/internal/lsp/source/completion/completion_keywords.go
@@ -1,9 +1,14 @@
-package source
+// Copyright 2020 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 completion
 
 import (
 	"go/ast"
 
 	"golang.org/x/tools/internal/lsp/protocol"
+	"golang.org/x/tools/internal/lsp/source"
 )
 
 const (
@@ -69,7 +74,7 @@
 	if len(c.path) > 2 {
 		// Offer "range" if we are in ast.ForStmt.Init. This is what the
 		// AST looks like before "range" is typed, e.g. "for i := r<>".
-		if loop, ok := c.path[2].(*ast.ForStmt); ok && nodeContains(loop.Init, c.pos) {
+		if loop, ok := c.path[2].(*ast.ForStmt); ok && source.NodeContains(loop.Init, c.pos) {
 			c.addKeywordItems(seen, stdScore, RANGE)
 		}
 	}
diff --git a/internal/lsp/source/completion_labels.go b/internal/lsp/source/completion/completion_labels.go
similarity index 98%
rename from internal/lsp/source/completion_labels.go
rename to internal/lsp/source/completion/completion_labels.go
index abb2041..3c54412 100644
--- a/internal/lsp/source/completion_labels.go
+++ b/internal/lsp/source/completion/completion_labels.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package source
+package completion
 
 import (
 	"context"
diff --git a/internal/lsp/source/completion_literal.go b/internal/lsp/source/completion/completion_literal.go
similarity index 94%
rename from internal/lsp/source/completion_literal.go
rename to internal/lsp/source/completion/completion_literal.go
index 342306d..7582e57 100644
--- a/internal/lsp/source/completion_literal.go
+++ b/internal/lsp/source/completion/completion_literal.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package source
+package completion
 
 import (
 	"context"
@@ -17,6 +17,7 @@
 	"golang.org/x/tools/internal/lsp/diff"
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/snippet"
+	"golang.org/x/tools/internal/lsp/source"
 )
 
 // literal generates composite literal, function literal, and make()
@@ -52,7 +53,7 @@
 	// don't offer "mySlice{}" since we have already added a candidate
 	// of "[]int{}".
 	if _, named := literalType.(*types.Named); named && expType != nil {
-		if _, named := deref(expType).(*types.Named); !named {
+		if _, named := source.Deref(expType).(*types.Named); !named {
 			return
 		}
 	}
@@ -129,7 +130,7 @@
 			// Add a literal completion for a signature type that implements
 			// an interface. For example, offer "http.HandlerFunc()" when
 			// expected type is "http.Handler".
-			if isInterface(expType) {
+			if source.IsInterface(expType) {
 				c.basicLiteral(t, typeName, float64(score), addlEdits)
 			}
 		case *types.Basic:
@@ -137,7 +138,7 @@
 			// expected interface (e.g. named string type http.Dir
 			// implements http.FileSystem), or are identical to our expected
 			// type (i.e. yielding a type conversion such as "float64()").
-			if isInterface(expType) || types.Identical(expType, literalType) {
+			if source.IsInterface(expType) || types.Identical(expType, literalType) {
 				c.basicLiteral(t, typeName, float64(score), addlEdits)
 			}
 		}
@@ -159,7 +160,7 @@
 	}
 
 	// If prefix matches "func", client may want a function literal.
-	if score := c.matcher.Score("func"); !cand.takeAddress && score > 0 && !isInterface(expType) {
+	if score := c.matcher.Score("func"); !cand.takeAddress && score > 0 && !source.IsInterface(expType) {
 		switch t := literalType.Underlying().(type) {
 		case *types.Signature:
 			c.functionLiteral(ctx, t, float64(score))
@@ -170,12 +171,12 @@
 // prependEdit produces text edits that preprend the specified prefix
 // to the specified node.
 func prependEdit(fset *token.FileSet, m *protocol.ColumnMapper, node ast.Node, prefix string) ([]protocol.TextEdit, error) {
-	rng := newMappedRange(fset, m, node.Pos(), node.Pos())
+	rng := source.NewMappedRange(fset, m, node.Pos(), node.Pos())
 	spn, err := rng.Span()
 	if err != nil {
 		return nil, err
 	}
-	return ToProtocolEdits(m, []diff.TextEdit{{
+	return source.ToProtocolEdits(m, []diff.TextEdit{{
 		Span:    spn,
 		NewText: prefix,
 	}})
@@ -210,7 +211,7 @@
 			// If the param has no name in the signature, guess a name based
 			// on the type. Use an empty qualifier to ignore the package.
 			// For example, we want to name "http.Request" "r", not "hr".
-			name = formatVarType(ctx, c.snapshot, c.pkg, c.file, p, func(p *types.Package) string {
+			name = source.FormatVarType(ctx, c.snapshot, c.pkg, c.file, p, func(p *types.Package) string {
 				return ""
 			})
 			name = abbreviateTypeName(name)
@@ -264,7 +265,7 @@
 		// of "i int, j int".
 		if i == sig.Params().Len()-1 || !types.Identical(p.Type(), sig.Params().At(i+1).Type()) {
 			snip.WriteText(" ")
-			typeStr := formatVarType(ctx, c.snapshot, c.pkg, c.file, p, c.qf)
+			typeStr := source.FormatVarType(ctx, c.snapshot, c.pkg, c.file, p, c.qf)
 			if sig.Variadic() && i == sig.Params().Len()-1 {
 				typeStr = strings.Replace(typeStr, "[]", "...", 1)
 			}
@@ -292,7 +293,7 @@
 		if name := r.Name(); name != "" {
 			snip.WriteText(name + " ")
 		}
-		snip.WriteText(formatVarType(ctx, c.snapshot, c.pkg, c.file, r, c.qf))
+		snip.WriteText(source.FormatVarType(ctx, c.snapshot, c.pkg, c.file, r, c.qf))
 	}
 	if resultsNeedParens {
 		snip.WriteText(")")
diff --git a/internal/lsp/source/completion_package.go b/internal/lsp/source/completion/completion_package.go
similarity index 92%
rename from internal/lsp/source/completion_package.go
rename to internal/lsp/source/completion/completion_package.go
index 3b82a86..a6ac7af 100644
--- a/internal/lsp/source/completion_package.go
+++ b/internal/lsp/source/completion/completion_package.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package source
+package completion
 
 import (
 	"context"
@@ -17,16 +17,17 @@
 
 	"golang.org/x/tools/internal/lsp/fuzzy"
 	"golang.org/x/tools/internal/lsp/protocol"
+	"golang.org/x/tools/internal/lsp/source"
 	"golang.org/x/tools/internal/span"
 	errors "golang.org/x/xerrors"
 )
 
 // packageClauseCompletions offers completions for a package declaration when
 // one is not present in the given file.
-func packageClauseCompletions(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) ([]CompletionItem, *Selection, error) {
+func packageClauseCompletions(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, pos protocol.Position) ([]CompletionItem, *Selection, error) {
 	// We know that the AST for this file will be empty due to the missing
 	// package declaration, but parse it anyway to get a mapper.
-	pgf, err := snapshot.ParseGo(ctx, fh, ParseFull)
+	pgf, err := snapshot.ParseGo(ctx, fh, source.ParseFull)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -67,7 +68,7 @@
 // packageCompletionSurrounding returns surrounding for package completion if a
 // package completions can be suggested at a given position. A valid location
 // for package completion is above any declarations or import statements.
-func packageCompletionSurrounding(ctx context.Context, fset *token.FileSet, fh FileHandle, pgf *ParsedGoFile, pos token.Pos) (*Selection, error) {
+func packageCompletionSurrounding(ctx context.Context, fset *token.FileSet, fh source.FileHandle, pgf *source.ParsedGoFile, pos token.Pos) (*Selection, error) {
 	src, err := fh.Read()
 	if err != nil {
 		return nil, err
@@ -98,7 +99,7 @@
 			return &Selection{
 				content:     name.Name,
 				cursor:      cursor,
-				mappedRange: newMappedRange(fset, m, name.Pos(), name.End()),
+				MappedRange: source.NewMappedRange(fset, m, name.Pos(), name.End()),
 			}, nil
 		}
 	}
@@ -135,7 +136,7 @@
 				return &Selection{
 					content:     content,
 					cursor:      cursor,
-					mappedRange: newMappedRange(fset, m, start, end),
+					MappedRange: source.NewMappedRange(fset, m, start, end),
 				}, nil
 			}
 		}
@@ -162,7 +163,7 @@
 	return &Selection{
 		content:     "",
 		cursor:      cursor,
-		mappedRange: newMappedRange(fset, m, start, end),
+		MappedRange: source.NewMappedRange(fset, m, start, end),
 	}, nil
 }
 
@@ -207,7 +208,7 @@
 // have the given prefix and are used in the the same directory as the given
 // file. This also includes test packages for these packages (<pkg>_test) and
 // the directory name itself.
-func packageSuggestions(ctx context.Context, snapshot Snapshot, fileURI span.URI, prefix string) ([]candidate, error) {
+func packageSuggestions(ctx context.Context, snapshot source.Snapshot, fileURI span.URI, prefix string) ([]candidate, error) {
 	workspacePackages, err := snapshot.WorkspacePackages(ctx)
 	if err != nil {
 		return nil, err
diff --git a/internal/lsp/source/completion_printf.go b/internal/lsp/source/completion/completion_printf.go
similarity index 99%
rename from internal/lsp/source/completion_printf.go
rename to internal/lsp/source/completion/completion_printf.go
index e13a938..c90a365 100644
--- a/internal/lsp/source/completion_printf.go
+++ b/internal/lsp/source/completion/completion_printf.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package source
+package completion
 
 import (
 	"go/ast"
diff --git a/internal/lsp/source/completion_printf_test.go b/internal/lsp/source/completion/completion_printf_test.go
similarity index 98%
rename from internal/lsp/source/completion_printf_test.go
rename to internal/lsp/source/completion/completion_printf_test.go
index ab20f27..19d295b 100644
--- a/internal/lsp/source/completion_printf_test.go
+++ b/internal/lsp/source/completion/completion_printf_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package source
+package completion
 
 import (
 	"fmt"
diff --git a/internal/lsp/source/completion_snippet.go b/internal/lsp/source/completion/completion_snippet.go
similarity index 99%
rename from internal/lsp/source/completion_snippet.go
rename to internal/lsp/source/completion/completion_snippet.go
index b6efc02..c254c65 100644
--- a/internal/lsp/source/completion_snippet.go
+++ b/internal/lsp/source/completion/completion_snippet.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package source
+package completion
 
 import (
 	"go/ast"
diff --git a/internal/lsp/source/completion_statements.go b/internal/lsp/source/completion/completion_statements.go
similarity index 96%
rename from internal/lsp/source/completion_statements.go
rename to internal/lsp/source/completion/completion_statements.go
index 0badd6c..62d3cf0 100644
--- a/internal/lsp/source/completion_statements.go
+++ b/internal/lsp/source/completion/completion_statements.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package source
+package completion
 
 import (
 	"fmt"
@@ -12,6 +12,7 @@
 
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/snippet"
+	"golang.org/x/tools/internal/lsp/source"
 )
 
 // addStatementCandidates adds full statement completion candidates
@@ -79,7 +80,7 @@
 		}
 
 		// The name or our slice is whatever's in the LHS expression.
-		sliceText = formatNode(fset, n.Lhs[exprIdx])
+		sliceText = source.FormatNode(fset, n.Lhs[exprIdx])
 	case *ast.SelectorExpr:
 		// Make sure we are a selector at the beginning of a statement.
 		if _, parentIsExprtStmt := c.path[2].(*ast.ExprStmt); !parentIsExprtStmt {
@@ -89,7 +90,7 @@
 		// So far we only know the first part of our slice name. For
 		// example in "s.a<>" we only know our slice begins with "s."
 		// since the user could still be typing.
-		sliceText = formatNode(fset, n.X) + "."
+		sliceText = source.FormatNode(fset, n.X) + "."
 		needsLHS = true
 	case *ast.ExprStmt:
 		needsLHS = true
@@ -205,7 +206,7 @@
 
 	var (
 		// errText is e.g. "err" in "foo, err := bar()".
-		errText = formatNode(c.snapshot.FileSet(), lastAssignee)
+		errText = source.FormatNode(c.snapshot.FileSet(), lastAssignee)
 
 		// Whether we need to include the "if" keyword in our candidate.
 		needsIf = true
diff --git a/internal/lsp/source/deep_completion.go b/internal/lsp/source/completion/deep_completion.go
similarity index 99%
rename from internal/lsp/source/deep_completion.go
rename to internal/lsp/source/completion/deep_completion.go
index 2afff8b..3f06d13 100644
--- a/internal/lsp/source/deep_completion.go
+++ b/internal/lsp/source/completion/deep_completion.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package source
+package completion
 
 import (
 	"context"
diff --git a/internal/lsp/source/deep_completion_test.go b/internal/lsp/source/completion/deep_completion_test.go
similarity index 97%
rename from internal/lsp/source/deep_completion_test.go
rename to internal/lsp/source/completion/deep_completion_test.go
index 47d5179..27009af 100644
--- a/internal/lsp/source/deep_completion_test.go
+++ b/internal/lsp/source/completion/deep_completion_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package source
+package completion
 
 import (
 	"testing"
diff --git a/internal/lsp/source/completion/util.go b/internal/lsp/source/completion/util.go
new file mode 100644
index 0000000..def769f
--- /dev/null
+++ b/internal/lsp/source/completion/util.go
@@ -0,0 +1,295 @@
+// Copyright 2020 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 completion
+
+import (
+	"go/ast"
+	"go/token"
+	"go/types"
+
+	"golang.org/x/tools/internal/lsp/source"
+)
+
+// exprAtPos returns the index of the expression containing pos.
+func exprAtPos(pos token.Pos, args []ast.Expr) int {
+	for i, expr := range args {
+		if expr.Pos() <= pos && pos <= expr.End() {
+			return i
+		}
+	}
+	return len(args)
+}
+
+// eachField invokes fn for each field that can be selected from a
+// value of type T.
+func eachField(T types.Type, fn func(*types.Var)) {
+	// TODO(adonovan): this algorithm doesn't exclude ambiguous
+	// selections that match more than one field/method.
+	// types.NewSelectionSet should do that for us.
+
+	// for termination on recursive types
+	var seen map[*types.Struct]bool
+
+	var visit func(T types.Type)
+	visit = func(T types.Type) {
+		if T, ok := source.Deref(T).Underlying().(*types.Struct); ok {
+			if seen[T] {
+				return
+			}
+
+			for i := 0; i < T.NumFields(); i++ {
+				f := T.Field(i)
+				fn(f)
+				if f.Anonymous() {
+					if seen == nil {
+						// Lazily create "seen" since it is only needed for
+						// embedded structs.
+						seen = make(map[*types.Struct]bool)
+					}
+					seen[T] = true
+					visit(f.Type())
+				}
+			}
+		}
+	}
+	visit(T)
+}
+
+// typeIsValid reports whether typ doesn't contain any Invalid types.
+func typeIsValid(typ types.Type) bool {
+	// Check named types separately, because we don't want
+	// to call Underlying() on them to avoid problems with recursive types.
+	if _, ok := typ.(*types.Named); ok {
+		return true
+	}
+
+	switch typ := typ.Underlying().(type) {
+	case *types.Basic:
+		return typ.Kind() != types.Invalid
+	case *types.Array:
+		return typeIsValid(typ.Elem())
+	case *types.Slice:
+		return typeIsValid(typ.Elem())
+	case *types.Pointer:
+		return typeIsValid(typ.Elem())
+	case *types.Map:
+		return typeIsValid(typ.Key()) && typeIsValid(typ.Elem())
+	case *types.Chan:
+		return typeIsValid(typ.Elem())
+	case *types.Signature:
+		return typeIsValid(typ.Params()) && typeIsValid(typ.Results())
+	case *types.Tuple:
+		for i := 0; i < typ.Len(); i++ {
+			if !typeIsValid(typ.At(i).Type()) {
+				return false
+			}
+		}
+		return true
+	case *types.Struct, *types.Interface:
+		// Don't bother checking structs, interfaces for validity.
+		return true
+	default:
+		return false
+	}
+}
+
+// resolveInvalid traverses the node of the AST that defines the scope
+// containing the declaration of obj, and attempts to find a user-friendly
+// name for its invalid type. The resulting Object and its Type are fake.
+func resolveInvalid(fset *token.FileSet, obj types.Object, node ast.Node, info *types.Info) types.Object {
+	var resultExpr ast.Expr
+	ast.Inspect(node, func(node ast.Node) bool {
+		switch n := node.(type) {
+		case *ast.ValueSpec:
+			for _, name := range n.Names {
+				if info.Defs[name] == obj {
+					resultExpr = n.Type
+				}
+			}
+			return false
+		case *ast.Field: // This case handles parameters and results of a FuncDecl or FuncLit.
+			for _, name := range n.Names {
+				if info.Defs[name] == obj {
+					resultExpr = n.Type
+				}
+			}
+			return false
+		default:
+			return true
+		}
+	})
+	// Construct a fake type for the object and return a fake object with this type.
+	typename := source.FormatNode(fset, resultExpr)
+	typ := types.NewNamed(types.NewTypeName(token.NoPos, obj.Pkg(), typename, nil), types.Typ[types.Invalid], nil)
+	return types.NewVar(obj.Pos(), obj.Pkg(), obj.Name(), typ)
+}
+
+func isPointer(T types.Type) bool {
+	_, ok := T.(*types.Pointer)
+	return ok
+}
+
+func isVar(obj types.Object) bool {
+	_, ok := obj.(*types.Var)
+	return ok
+}
+
+func isTypeName(obj types.Object) bool {
+	_, ok := obj.(*types.TypeName)
+	return ok
+}
+
+func isFunc(obj types.Object) bool {
+	_, ok := obj.(*types.Func)
+	return ok
+}
+
+func isEmptyInterface(T types.Type) bool {
+	intf, _ := T.(*types.Interface)
+	return intf != nil && intf.NumMethods() == 0
+}
+
+func isUntyped(T types.Type) bool {
+	if basic, ok := T.(*types.Basic); ok {
+		return basic.Info()&types.IsUntyped > 0
+	}
+	return false
+}
+
+func isPkgName(obj types.Object) bool {
+	_, ok := obj.(*types.PkgName)
+	return ok
+}
+
+func isASTFile(n ast.Node) bool {
+	_, ok := n.(*ast.File)
+	return ok
+}
+
+func deslice(T types.Type) types.Type {
+	if slice, ok := T.Underlying().(*types.Slice); ok {
+		return slice.Elem()
+	}
+	return nil
+}
+
+// isSelector returns the enclosing *ast.SelectorExpr when pos is in the
+// selector.
+func enclosingSelector(path []ast.Node, pos token.Pos) *ast.SelectorExpr {
+	if len(path) == 0 {
+		return nil
+	}
+
+	if sel, ok := path[0].(*ast.SelectorExpr); ok {
+		return sel
+	}
+
+	if _, ok := path[0].(*ast.Ident); ok && len(path) > 1 {
+		if sel, ok := path[1].(*ast.SelectorExpr); ok && pos >= sel.Sel.Pos() {
+			return sel
+		}
+	}
+
+	return nil
+}
+
+func enclosingValueSpec(path []ast.Node) *ast.ValueSpec {
+	for _, n := range path {
+		if vs, ok := n.(*ast.ValueSpec); ok {
+			return vs
+		}
+	}
+
+	return nil
+}
+
+// exprObj returns the types.Object associated with the *ast.Ident or
+// *ast.SelectorExpr e.
+func exprObj(info *types.Info, e ast.Expr) types.Object {
+	var ident *ast.Ident
+	switch expr := e.(type) {
+	case *ast.Ident:
+		ident = expr
+	case *ast.SelectorExpr:
+		ident = expr.Sel
+	default:
+		return nil
+	}
+
+	return info.ObjectOf(ident)
+}
+
+// typeConversion returns the type being converted to if call is a type
+// conversion expression.
+func typeConversion(call *ast.CallExpr, info *types.Info) types.Type {
+	// Type conversion (e.g. "float64(foo)").
+	if fun, _ := exprObj(info, call.Fun).(*types.TypeName); fun != nil {
+		return fun.Type()
+	}
+
+	return nil
+}
+
+// fieldsAccessible returns whether s has at least one field accessible by p.
+func fieldsAccessible(s *types.Struct, p *types.Package) bool {
+	for i := 0; i < s.NumFields(); i++ {
+		f := s.Field(i)
+		if f.Exported() || f.Pkg() == p {
+			return true
+		}
+	}
+	return false
+}
+
+// prevStmt returns the statement that precedes the statement containing pos.
+// For example:
+//
+//     foo := 1
+//     bar(1 + 2<>)
+//
+// If "<>" is pos, prevStmt returns "foo := 1"
+func prevStmt(pos token.Pos, path []ast.Node) ast.Stmt {
+	var blockLines []ast.Stmt
+	for i := 0; i < len(path) && blockLines == nil; i++ {
+		switch n := path[i].(type) {
+		case *ast.BlockStmt:
+			blockLines = n.List
+		case *ast.CommClause:
+			blockLines = n.Body
+		case *ast.CaseClause:
+			blockLines = n.Body
+		}
+	}
+
+	for i := len(blockLines) - 1; i >= 0; i-- {
+		if blockLines[i].End() < pos {
+			return blockLines[i]
+		}
+	}
+
+	return nil
+}
+
+// formatZeroValue produces Go code representing the zero value of T. It
+// returns the empty string if T is invalid.
+func formatZeroValue(T types.Type, qf types.Qualifier) string {
+	switch u := T.Underlying().(type) {
+	case *types.Basic:
+		switch {
+		case u.Info()&types.IsNumeric > 0:
+			return "0"
+		case u.Info()&types.IsString > 0:
+			return `""`
+		case u.Info()&types.IsBoolean > 0:
+			return "false"
+		default:
+			return ""
+		}
+	case *types.Pointer, *types.Interface, *types.Chan, *types.Map, *types.Slice, *types.Signature:
+		return "nil"
+	default:
+		return types.TypeString(T, qf) + "{}"
+	}
+}
diff --git a/internal/lsp/source/util_test.go b/internal/lsp/source/completion/util_test.go
similarity index 96%
rename from internal/lsp/source/util_test.go
rename to internal/lsp/source/completion/util_test.go
index 0dfa0b0..c94d279 100644
--- a/internal/lsp/source/util_test.go
+++ b/internal/lsp/source/completion/util_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package source
+package completion
 
 import (
 	"go/types"
diff --git a/internal/lsp/source/diagnostics.go b/internal/lsp/source/diagnostics.go
index 583bb31..320d39b 100644
--- a/internal/lsp/source/diagnostics.go
+++ b/internal/lsp/source/diagnostics.go
@@ -129,7 +129,7 @@
 	if err != nil {
 		return VersionedFileIdentity{}, nil, err
 	}
-	pkg, _, err := getParsedFile(ctx, snapshot, fh, NarrowestPackage)
+	pkg, _, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage)
 	if err != nil {
 		return VersionedFileIdentity{}, nil, err
 	}
diff --git a/internal/lsp/source/extract.go b/internal/lsp/source/extract.go
index 0c30fd5..84679dc 100644
--- a/internal/lsp/source/extract.go
+++ b/internal/lsp/source/extract.go
@@ -135,7 +135,7 @@
 // generateAvailableIdentifier adjusts the new function name until there are no collisons in scope.
 // Possible collisions include other function and variable names.
 func generateAvailableIdentifier(pos token.Pos, file *ast.File, path []ast.Node, info *types.Info, prefix string, idx int) string {
-	scopes := collectScopes(info, path, pos)
+	scopes := CollectScopes(info, path, pos)
 	name := prefix + fmt.Sprintf("%d", idx)
 	for file.Scope.Lookup(name) != nil || !isValidName(name, scopes) {
 		idx++
diff --git a/internal/lsp/source/folding_range.go b/internal/lsp/source/folding_range.go
index fc3f886..7061017 100644
--- a/internal/lsp/source/folding_range.go
+++ b/internal/lsp/source/folding_range.go
@@ -11,7 +11,7 @@
 
 // FoldingRangeInfo holds range and kind info of folding for an ast.Node
 type FoldingRangeInfo struct {
-	mappedRange
+	MappedRange
 	Kind protocol.FoldingRangeKind
 }
 
@@ -106,7 +106,7 @@
 		return nil
 	}
 	return &FoldingRangeInfo{
-		mappedRange: newMappedRange(fset, m, start, end),
+		MappedRange: NewMappedRange(fset, m, start, end),
 		Kind:        kind,
 	}
 }
@@ -144,7 +144,7 @@
 		}
 		comments = append(comments, &FoldingRangeInfo{
 			// Fold from the end of the first line comment to the end of the comment block.
-			mappedRange: newMappedRange(fset, m, commentGrp.List[0].End(), commentGrp.End()),
+			MappedRange: NewMappedRange(fset, m, commentGrp.List[0].End(), commentGrp.End()),
 			Kind:        protocol.Comment,
 		})
 	}
diff --git a/internal/lsp/source/format.go b/internal/lsp/source/format.go
index 5114d50..310bac3 100644
--- a/internal/lsp/source/format.go
+++ b/internal/lsp/source/format.go
@@ -133,7 +133,8 @@
 	return allFixEdits, editsPerFix, nil
 }
 
-func computeOneImportFixEdits(ctx context.Context, snapshot Snapshot, pgf *ParsedGoFile, fix *imports.ImportFix) ([]protocol.TextEdit, error) {
+// ComputeOneImportFixEdits returns text edits for a single import fix.
+func ComputeOneImportFixEdits(ctx context.Context, snapshot Snapshot, pgf *ParsedGoFile, fix *imports.ImportFix) ([]protocol.TextEdit, error) {
 	options := &imports.Options{
 		LocalPrefix: snapshot.View().Options().LocalPrefix,
 		// Defaults.
diff --git a/internal/lsp/source/highlight.go b/internal/lsp/source/highlight.go
index f4f7793..d18a971 100644
--- a/internal/lsp/source/highlight.go
+++ b/internal/lsp/source/highlight.go
@@ -22,7 +22,7 @@
 	ctx, done := event.Start(ctx, "source.Highlight")
 	defer done()
 
-	pkg, pgf, err := getParsedFile(ctx, snapshot, fh, WidestPackage)
+	pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, WidestPackage)
 	if err != nil {
 		return nil, errors.Errorf("getting file for Highlight: %w", err)
 	}
diff --git a/internal/lsp/source/hover.go b/internal/lsp/source/hover.go
index 5f68a52..d331e72 100644
--- a/internal/lsp/source/hover.go
+++ b/internal/lsp/source/hover.go
@@ -158,7 +158,7 @@
 			return "", "", ""
 		}
 		if r := typ.Recv(); r != nil {
-			switch rtyp := deref(r.Type()).(type) {
+			switch rtyp := Deref(r.Type()).(type) {
 			case *types.Struct:
 				rTypeName = r.Name()
 			case *types.Named:
@@ -226,10 +226,12 @@
 	_, done := event.Start(ctx, "source.hover")
 	defer done()
 
-	return hoverInfo(pkg, d.obj, d.node)
+	return HoverInfo(pkg, d.obj, d.node)
 }
 
-func hoverInfo(pkg Package, obj types.Object, node ast.Node) (*HoverInformation, error) {
+// HoverInfo returns a HoverInformation struct for an ast node and its type
+// object.
+func HoverInfo(pkg Package, obj types.Object, node ast.Node) (*HoverInformation, error) {
 	var info *HoverInformation
 
 	switch node := node.(type) {
diff --git a/internal/lsp/source/identifier.go b/internal/lsp/source/identifier.go
index f059821..88eecc1 100644
--- a/internal/lsp/source/identifier.go
+++ b/internal/lsp/source/identifier.go
@@ -22,10 +22,10 @@
 type IdentifierInfo struct {
 	Name     string
 	Snapshot Snapshot
-	mappedRange
+	MappedRange
 
 	Type struct {
-		mappedRange
+		MappedRange
 		Object types.Object
 	}
 
@@ -42,7 +42,7 @@
 }
 
 type Declaration struct {
-	MappedRange []mappedRange
+	MappedRange []MappedRange
 	node        ast.Node
 	obj         types.Object
 
@@ -108,7 +108,7 @@
 		return nil, ErrNoIdentFound
 	}
 
-	qf := qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo())
+	qf := Qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo())
 
 	ident, _ := path[0].(*ast.Ident)
 	if ident == nil {
@@ -138,13 +138,13 @@
 		return &IdentifierInfo{
 			Name:        file.Name.Name,
 			ident:       file.Name,
-			mappedRange: rng,
+			MappedRange: rng,
 			pkg:         pkg,
 			qf:          qf,
 			Snapshot:    snapshot,
 			Declaration: Declaration{
 				node:        declAST.Name,
-				MappedRange: []mappedRange{declRng},
+				MappedRange: []MappedRange{declRng},
 			},
 		}, nil
 	}
@@ -167,7 +167,7 @@
 
 	result.Name = result.ident.Name
 	var err error
-	if result.mappedRange, err = posToMappedRange(snapshot, pkg, result.ident.Pos(), result.ident.End()); err != nil {
+	if result.MappedRange, err = posToMappedRange(snapshot, pkg, result.ident.Pos(), result.ident.End()); err != nil {
 		return nil, err
 	}
 
@@ -206,7 +206,7 @@
 
 		// The builtin package isn't in the dependency graph, so the usual utilities
 		// won't work here.
-		rng := newMappedRange(snapshot.FileSet(), builtin.ParsedFile.Mapper, decl.Pos(), decl.Pos()+token.Pos(len(result.Name)))
+		rng := NewMappedRange(snapshot.FileSet(), builtin.ParsedFile.Mapper, decl.Pos(), decl.Pos()+token.Pos(len(result.Name)))
 		result.Declaration.MappedRange = append(result.Declaration.MappedRange, rng)
 
 		return result, nil
@@ -242,7 +242,7 @@
 		if hasErrorType(result.Type.Object) {
 			return result, nil
 		}
-		if result.Type.mappedRange, err = objToMappedRange(snapshot, pkg, result.Type.Object); err != nil {
+		if result.Type.MappedRange, err = objToMappedRange(snapshot, pkg, result.Type.Object); err != nil {
 			return nil, err
 		}
 	}
@@ -254,7 +254,7 @@
 		switch n := n.(type) {
 		case *ast.SelectorExpr:
 			if sel, ok := info.Selections[n]; ok {
-				recv := deref(sel.Recv())
+				recv := Deref(sel.Recv())
 
 				// Keep track of the last exported type seen.
 				var exported types.Type
@@ -265,7 +265,7 @@
 				// method itself.
 				for _, index := range sel.Index()[:len(sel.Index())-1] {
 					if r, ok := recv.Underlying().(*types.Struct); ok {
-						recv = deref(r.Field(index).Type())
+						recv = Deref(r.Field(index).Type())
 						if named, ok := recv.(*types.Named); ok && named.Obj().Exported() {
 							exported = named
 						}
@@ -304,7 +304,7 @@
 }
 
 func objToDecl(ctx context.Context, snapshot Snapshot, srcPkg Package, obj types.Object) (ast.Decl, error) {
-	pgf, _, err := findPosInPackage(snapshot, srcPkg, obj.Pos())
+	pgf, _, err := FindPosInPackage(snapshot, srcPkg, obj.Pos())
 	if err != nil {
 		return nil, err
 	}
@@ -335,7 +335,7 @@
 		Name:     importPath,
 		pkg:      pkg,
 	}
-	if result.mappedRange, err = posToMappedRange(snapshot, pkg, imp.Path.Pos(), imp.Path.End()); err != nil {
+	if result.MappedRange, err = posToMappedRange(snapshot, pkg, imp.Path.Pos(), imp.Path.End()); err != nil {
 		return nil, err
 	}
 	// Consider the "declaration" of an import spec to be the imported package.
diff --git a/internal/lsp/source/implementation.go b/internal/lsp/source/implementation.go
index feaa848..379471f 100644
--- a/internal/lsp/source/implementation.go
+++ b/internal/lsp/source/implementation.go
@@ -165,7 +165,7 @@
 // concreteImplementsIntf returns true if a is an interface type implemented by
 // concrete type b, or vice versa.
 func concreteImplementsIntf(a, b types.Type) bool {
-	aIsIntf, bIsIntf := isInterface(a), isInterface(b)
+	aIsIntf, bIsIntf := IsInterface(a), IsInterface(b)
 
 	// Make sure exactly one is an interface type.
 	if aIsIntf == bIsIntf {
@@ -184,7 +184,7 @@
 // type. This is useful to make sure you consider a named type's full method
 // set.
 func ensurePointer(T types.Type) types.Type {
-	if _, ok := T.(*types.Named); ok && !isInterface(T) {
+	if _, ok := T.(*types.Named); ok && !IsInterface(T) {
 		return types.NewPointer(T)
 	}
 
@@ -248,7 +248,7 @@
 			// Look up the implicit *types.PkgName.
 			obj := searchpkg.GetTypesInfo().Implicits[leaf]
 			if obj == nil {
-				return nil, xerrors.Errorf("%w for import %q", errNoObjectFound, importPath(leaf))
+				return nil, xerrors.Errorf("%w for import %q", errNoObjectFound, ImportPath(leaf))
 			}
 			objs = append(objs, obj)
 		}
diff --git a/internal/lsp/source/options.go b/internal/lsp/source/options.go
index b9adbb9..dd026cb 100644
--- a/internal/lsp/source/options.go
+++ b/internal/lsp/source/options.go
@@ -250,17 +250,6 @@
 	return s == Both || s == Definition
 }
 
-type completionOptions struct {
-	deepCompletion    bool
-	unimported        bool
-	documentation     bool
-	fullDocumentation bool
-	placeholders      bool
-	literal           bool
-	matcher           Matcher
-	budget            time.Duration
-}
-
 // Hooks contains configuration that is provided to the Gopls command by the
 // main package.
 type Hooks struct {
diff --git a/internal/lsp/source/references.go b/internal/lsp/source/references.go
index 204e185..cd8a34c 100644
--- a/internal/lsp/source/references.go
+++ b/internal/lsp/source/references.go
@@ -20,7 +20,7 @@
 // ReferenceInfo holds information about reference to an identifier in Go source.
 type ReferenceInfo struct {
 	Name string
-	mappedRange
+	MappedRange
 	ident         *ast.Ident
 	obj           types.Object
 	pkg           Package
@@ -78,7 +78,7 @@
 			return nil, err
 		}
 		references = append(references, &ReferenceInfo{
-			mappedRange:   ident.mappedRange,
+			MappedRange:   ident.MappedRange,
 			Name:          qos[0].obj.Name(),
 			ident:         ident.ident,
 			obj:           qos[0].obj,
@@ -118,7 +118,7 @@
 					ident:       ident,
 					pkg:         pkg,
 					obj:         obj,
-					mappedRange: rng,
+					MappedRange: rng,
 				})
 			}
 		}
diff --git a/internal/lsp/source/rename.go b/internal/lsp/source/rename.go
index fefbf49..23e7425 100644
--- a/internal/lsp/source/rename.go
+++ b/internal/lsp/source/rename.go
@@ -111,7 +111,7 @@
 	for _, ref := range refs {
 		if obj, ok := ref.obj.(*types.Func); ok {
 			recv := obj.Type().(*types.Signature).Recv()
-			if recv != nil && isInterface(recv.Type().Underlying()) {
+			if recv != nil && IsInterface(recv.Type().Underlying()) {
 				r.changeMethods = true
 				break
 			}
diff --git a/internal/lsp/source/rename_check.go b/internal/lsp/source/rename_check.go
index 2b2088b..9cc3e5b 100644
--- a/internal/lsp/source/rename_check.go
+++ b/internal/lsp/source/rename_check.go
@@ -321,7 +321,7 @@
 			if !ok {
 				return visit(nil) // pop stack, don't descend
 			}
-			if _, ok := deref(tv.Type).Underlying().(*types.Struct); ok {
+			if _, ok := Deref(tv.Type).Underlying().(*types.Struct); ok {
 				if n.Type != nil {
 					ast.Inspect(n.Type, visit)
 				}
@@ -450,7 +450,7 @@
 	if from.Anonymous() {
 		if named, ok := from.Type().(*types.Named); ok {
 			r.check(named.Obj())
-		} else if named, ok := deref(from.Type()).(*types.Named); ok {
+		} else if named, ok := Deref(from.Type()).(*types.Named); ok {
 			r.check(named.Obj())
 		}
 	}
@@ -570,7 +570,7 @@
 	// Check for conflict at point of declaration.
 	// Check to ensure preservation of assignability requirements.
 	R := recv(from).Type()
-	if isInterface(R) {
+	if IsInterface(R) {
 		// Abstract method
 
 		// declaration
@@ -587,7 +587,7 @@
 		for _, pkg := range r.packages {
 			// Start with named interface types (better errors)
 			for _, obj := range pkg.GetTypesInfo().Defs {
-				if obj, ok := obj.(*types.TypeName); ok && isInterface(obj.Type()) {
+				if obj, ok := obj.(*types.TypeName); ok && IsInterface(obj.Type()) {
 					f, _, _ := types.LookupFieldOrMethod(
 						obj.Type(), false, from.Pkg(), from.Name())
 					if f == nil {
@@ -659,7 +659,7 @@
 			// yields abstract method I.f.  This can make error
 			// messages less than obvious.
 			//
-			if !isInterface(key.RHS) {
+			if !IsInterface(key.RHS) {
 				// The logic below was derived from checkSelections.
 
 				rtosel := rmethods.Lookup(from.Pkg(), r.to)
@@ -734,7 +734,7 @@
 		//
 		for key := range r.satisfy() {
 			// key = (lhs, rhs) where lhs is always an interface.
-			if isInterface(key.RHS) {
+			if IsInterface(key.RHS) {
 				continue
 			}
 			rsel := r.msets.MethodSet(key.RHS).Lookup(from.Pkg(), from.Name())
@@ -936,10 +936,6 @@
 	return obj.Pkg().Scope().Lookup(obj.Name()) == obj
 }
 
-func isInterface(T types.Type) bool {
-	return T != nil && types.IsInterface(T)
-}
-
 // -- Plundered from go/scanner: ---------------------------------------
 
 func isLetter(ch rune) bool {
diff --git a/internal/lsp/source/signature_help.go b/internal/lsp/source/signature_help.go
index 10aee4f..890d8e0 100644
--- a/internal/lsp/source/signature_help.go
+++ b/internal/lsp/source/signature_help.go
@@ -21,7 +21,7 @@
 	ctx, done := event.Start(ctx, "source.SignatureHelp")
 	defer done()
 
-	pkg, pgf, err := getParsedFile(ctx, snapshot, fh, NarrowestPackage)
+	pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage)
 	if err != nil {
 		return nil, 0, errors.Errorf("getting file for SignatureHelp: %w", err)
 	}
@@ -58,7 +58,7 @@
 		return nil, 0, errors.Errorf("cannot find an enclosing function")
 	}
 
-	qf := qualifier(pgf.File, pkg.GetTypes(), pkg.GetTypesInfo())
+	qf := Qualifier(pgf.File, pkg.GetTypes(), pkg.GetTypesInfo())
 
 	// Get the object representing the function, if available.
 	// There is no object in certain cases such as calling a function returned by
@@ -116,7 +116,7 @@
 	} else {
 		name = "func"
 	}
-	s, err := newSignature(ctx, snapshot, pkg, pgf.File, name, sig, comment, qf)
+	s, err := NewSignature(ctx, snapshot, pkg, pgf.File, name, sig, comment, qf)
 	if err != nil {
 		return nil, 0, err
 	}
@@ -125,14 +125,14 @@
 		paramInfo = append(paramInfo, protocol.ParameterInformation{Label: p})
 	}
 	return &protocol.SignatureInformation{
-		Label:         name + s.format(),
+		Label:         name + s.Format(),
 		Documentation: doc.Synopsis(s.doc),
 		Parameters:    paramInfo,
 	}, activeParam, nil
 }
 
 func builtinSignature(ctx context.Context, snapshot Snapshot, callExpr *ast.CallExpr, name string, pos token.Pos) (*protocol.SignatureInformation, int, error) {
-	sig, err := newBuiltinSignature(ctx, snapshot, name)
+	sig, err := NewBuiltinSignature(ctx, snapshot, name)
 	if err != nil {
 		return nil, 0, err
 	}
@@ -142,7 +142,7 @@
 	}
 	activeParam := activeParameter(callExpr, len(sig.params), sig.variadic, pos)
 	return &protocol.SignatureInformation{
-		Label:         sig.name + sig.format(),
+		Label:         sig.name + sig.Format(),
 		Documentation: doc.Synopsis(sig.doc),
 		Parameters:    paramInfo,
 	}, activeParam, nil
diff --git a/internal/lsp/source/source_test.go b/internal/lsp/source/source_test.go
index c29899a..b16dcee 100644
--- a/internal/lsp/source/source_test.go
+++ b/internal/lsp/source/source_test.go
@@ -21,6 +21,7 @@
 	"golang.org/x/tools/internal/lsp/fuzzy"
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
+	"golang.org/x/tools/internal/lsp/source/completion"
 	"golang.org/x/tools/internal/lsp/tests"
 	"golang.org/x/tools/internal/span"
 	"golang.org/x/tools/internal/testenv"
@@ -304,11 +305,11 @@
 	}
 	defer r.view.SetOptions(r.ctx, original)
 
-	list, surrounding, err := source.Completion(r.ctx, r.snapshot, fh, protocol.Position{
+	list, surrounding, err := completion.Completion(r.ctx, r.snapshot, fh, protocol.Position{
 		Line:      float64(src.Start().Line() - 1),
 		Character: float64(src.Start().Column() - 1),
 	}, "")
-	if err != nil && !errors.As(err, &source.ErrIsDefinition{}) {
+	if err != nil && !errors.As(err, &completion.ErrIsDefinition{}) {
 		t.Fatalf("failed for %v: %v", src, err)
 	}
 	var prefix string
@@ -317,14 +318,14 @@
 	}
 
 	var numDeepCompletionsSeen int
-	var items []source.CompletionItem
+	var items []completion.CompletionItem
 	// Apply deep completion filtering.
 	for _, item := range list {
 		if item.Depth > 0 {
 			if !modified.DeepCompletion {
 				continue
 			}
-			if numDeepCompletionsSeen >= source.MaxDeepCompletions {
+			if numDeepCompletionsSeen >= completion.MaxDeepCompletions {
 				continue
 			}
 			numDeepCompletionsSeen++
diff --git a/internal/lsp/source/symbols.go b/internal/lsp/source/symbols.go
index 883ef5d..0565062 100644
--- a/internal/lsp/source/symbols.go
+++ b/internal/lsp/source/symbols.go
@@ -19,13 +19,13 @@
 	ctx, done := event.Start(ctx, "source.DocumentSymbols")
 	defer done()
 
-	pkg, pgf, err := getParsedFile(ctx, snapshot, fh, NarrowestPackage)
+	pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage)
 	if err != nil {
 		return nil, errors.Errorf("getting file for DocumentSymbols: %w", err)
 	}
 
 	info := pkg.GetTypesInfo()
-	q := qualifier(pgf.File, pkg.GetTypes(), info)
+	q := Qualifier(pgf.File, pkg.GetTypes(), info)
 
 	symbolsToReceiver := make(map[types.Type]int)
 	var symbols []protocol.DocumentSymbol
@@ -113,7 +113,7 @@
 	s := protocol.DocumentSymbol{
 		Name: obj.Name(),
 	}
-	s.Detail, _ = formatType(obj.Type(), qf)
+	s.Detail, _ = FormatType(obj.Type(), qf)
 	s.Kind = typeToKind(obj.Type())
 
 	var err error
@@ -134,7 +134,7 @@
 				Name: f.Name(),
 				Kind: protocol.Field,
 			}
-			child.Detail, _ = formatType(f.Type(), qf)
+			child.Detail, _ = FormatType(f.Type(), qf)
 
 			spanNode, selectionNode := nodesForStructField(i, st)
 			if span, err := nodeToProtocolRange(snapshot, pkg, spanNode); err == nil {
diff --git a/internal/lsp/source/types_format.go b/internal/lsp/source/types_format.go
index 2bf9f26..07784c1 100644
--- a/internal/lsp/source/types_format.go
+++ b/internal/lsp/source/types_format.go
@@ -19,8 +19,8 @@
 	"golang.org/x/tools/internal/lsp/protocol"
 )
 
-// formatType returns the detail and kind for a types.Type.
-func formatType(typ types.Type, qf types.Qualifier) (detail string, kind protocol.CompletionItemKind) {
+// FormatType returns the detail and kind for a types.Type.
+func FormatType(typ types.Type, qf types.Qualifier) (detail string, kind protocol.CompletionItemKind) {
 	if types.IsInterface(typ) {
 		detail = "interface{...}"
 		kind = protocol.InterfaceCompletion
@@ -28,7 +28,7 @@
 		detail = "struct{...}"
 		kind = protocol.StructCompletion
 	} else if typ != typ.Underlying() {
-		detail, kind = formatType(typ.Underlying(), qf)
+		detail, kind = FormatType(typ.Underlying(), qf)
 	} else {
 		detail = types.TypeString(typ, qf)
 		kind = protocol.ClassCompletion
@@ -43,7 +43,7 @@
 	needResultParens bool
 }
 
-func (s *signature) format() string {
+func (s *signature) Format() string {
 	var b strings.Builder
 	b.WriteByte('(')
 	for i, p := range s.params {
@@ -73,7 +73,13 @@
 	return b.String()
 }
 
-func newBuiltinSignature(ctx context.Context, snapshot Snapshot, name string) (*signature, error) {
+func (s *signature) Params() []string {
+	return s.params
+}
+
+// NewBuiltinSignature returns signature for the builtin object with a given
+// name, if a builtin object with the name exists.
+func NewBuiltinSignature(ctx context.Context, snapshot Snapshot, name string) (*signature, error) {
 	builtin, err := snapshot.BuiltinPackage(ctx)
 	if err != nil {
 		return nil, err
@@ -153,11 +159,12 @@
 	return result, writeResultParens
 }
 
-func newSignature(ctx context.Context, s Snapshot, pkg Package, file *ast.File, name string, sig *types.Signature, comment *ast.CommentGroup, qf types.Qualifier) (*signature, error) {
+// NewSignature returns formatted signature for a types.Signature struct.
+func NewSignature(ctx context.Context, s Snapshot, pkg Package, file *ast.File, name string, sig *types.Signature, comment *ast.CommentGroup, qf types.Qualifier) (*signature, error) {
 	params := make([]string, 0, sig.Params().Len())
 	for i := 0; i < sig.Params().Len(); i++ {
 		el := sig.Params().At(i)
-		typ := formatVarType(ctx, s, pkg, file, el, qf)
+		typ := FormatVarType(ctx, s, pkg, file, el, qf)
 		p := typ
 		if el.Name() != "" {
 			p = el.Name() + " " + typ
@@ -171,7 +178,7 @@
 			needResultParens = true
 		}
 		el := sig.Results().At(i)
-		typ := formatVarType(ctx, s, pkg, file, el, qf)
+		typ := FormatVarType(ctx, s, pkg, file, el, qf)
 		if el.Name() == "" {
 			results = append(results, typ)
 		} else {
@@ -194,11 +201,11 @@
 	}, nil
 }
 
-// formatVarType formats a *types.Var, accounting for type aliases.
+// FormatVarType formats a *types.Var, accounting for type aliases.
 // To do this, it looks in the AST of the file in which the object is declared.
 // On any errors, it always fallbacks back to types.TypeString.
-func formatVarType(ctx context.Context, snapshot Snapshot, srcpkg Package, srcfile *ast.File, obj *types.Var, qf types.Qualifier) string {
-	pgf, pkg, err := findPosInPackage(snapshot, srcpkg, obj.Pos())
+func FormatVarType(ctx context.Context, snapshot Snapshot, srcpkg Package, srcfile *ast.File, obj *types.Var, qf types.Qualifier) string {
+	pgf, pkg, err := FindPosInPackage(snapshot, srcpkg, obj.Pos())
 	if err != nil {
 		return types.TypeString(obj.Type(), qf)
 	}
@@ -218,7 +225,7 @@
 	// If the request came from a different package than the one in which the
 	// types are defined, we may need to modify the qualifiers.
 	qualified = qualifyExpr(snapshot.FileSet(), qualified, srcpkg, pkg, srcfile, clonedInfo, qf)
-	fmted := formatNode(snapshot.FileSet(), qualified)
+	fmted := FormatNode(snapshot.FileSet(), qualified)
 	return fmted
 }
 
diff --git a/internal/lsp/source/util.go b/internal/lsp/source/util.go
index 63bfd4e..5cb50ec 100644
--- a/internal/lsp/source/util.go
+++ b/internal/lsp/source/util.go
@@ -15,6 +15,7 @@
 	"path/filepath"
 	"regexp"
 	"sort"
+	"strconv"
 	"strings"
 
 	"golang.org/x/tools/internal/lsp/protocol"
@@ -22,7 +23,9 @@
 	errors "golang.org/x/xerrors"
 )
 
-type mappedRange struct {
+// MappedRange provides mapped protocol.Range for a span.Range, accounting for
+// UTF-16 code points.
+type MappedRange struct {
 	spanRange span.Range
 	m         *protocol.ColumnMapper
 
@@ -31,8 +34,9 @@
 	protocolRange *protocol.Range
 }
 
-func newMappedRange(fset *token.FileSet, m *protocol.ColumnMapper, start, end token.Pos) mappedRange {
-	return mappedRange{
+// NewMappedRange returns a MappedRange for the given start and end token.Pos.
+func NewMappedRange(fset *token.FileSet, m *protocol.ColumnMapper, start, end token.Pos) MappedRange {
+	return MappedRange{
 		spanRange: span.Range{
 			FileSet:   fset,
 			Start:     start,
@@ -43,7 +47,7 @@
 	}
 }
 
-func (s mappedRange) Range() (protocol.Range, error) {
+func (s MappedRange) Range() (protocol.Range, error) {
 	if s.protocolRange == nil {
 		spn, err := s.spanRange.Span()
 		if err != nil {
@@ -58,17 +62,22 @@
 	return *s.protocolRange, nil
 }
 
-func (s mappedRange) Span() (span.Span, error) {
+func (s MappedRange) Span() (span.Span, error) {
 	return s.spanRange.Span()
 }
 
-func (s mappedRange) URI() span.URI {
+func (s MappedRange) SpanRange() span.Range {
+	return s.spanRange
+}
+
+func (s MappedRange) URI() span.URI {
 	return s.m.URI
 }
 
-// getParsedFile is a convenience function that extracts the Package and ParsedGoFile for a File in a Snapshot.
-// selectPackage is typically Narrowest/WidestPackageHandle below.
-func getParsedFile(ctx context.Context, snapshot Snapshot, fh FileHandle, selectPackage PackagePolicy) (Package, *ParsedGoFile, error) {
+// GetParsedFile is a convenience function that extracts the Package and
+// ParsedGoFile for a File in a Snapshot. selectPackage is typically
+// Narrowest/WidestPackageHandle below.
+func GetParsedFile(ctx context.Context, snapshot Snapshot, fh FileHandle, selectPackage PackagePolicy) (Package, *ParsedGoFile, error) {
 	phs, err := snapshot.PackagesForFile(ctx, fh.URI(), TypecheckWorkspace)
 	if err != nil {
 		return nil, nil, err
@@ -158,7 +167,7 @@
 	return mrng.Range()
 }
 
-func objToMappedRange(snapshot Snapshot, pkg Package, obj types.Object) (mappedRange, error) {
+func objToMappedRange(snapshot Snapshot, pkg Package, obj types.Object) (MappedRange, error) {
 	if pkgName, ok := obj.(*types.PkgName); ok {
 		// An imported Go package has a package-local, unqualified name.
 		// When the name matches the imported package name, there is no
@@ -177,23 +186,23 @@
 	return nameToMappedRange(snapshot, pkg, obj.Pos(), obj.Name())
 }
 
-func nameToMappedRange(snapshot Snapshot, pkg Package, pos token.Pos, name string) (mappedRange, error) {
+func nameToMappedRange(snapshot Snapshot, pkg Package, pos token.Pos, name string) (MappedRange, error) {
 	return posToMappedRange(snapshot, pkg, pos, pos+token.Pos(len(name)))
 }
 
-func posToMappedRange(snapshot Snapshot, pkg Package, pos, end token.Pos) (mappedRange, error) {
+func posToMappedRange(snapshot Snapshot, pkg Package, pos, end token.Pos) (MappedRange, error) {
 	logicalFilename := snapshot.FileSet().File(pos).Position(pos).Filename
 	pgf, _, err := findFileInDeps(pkg, span.URIFromPath(logicalFilename))
 	if err != nil {
-		return mappedRange{}, err
+		return MappedRange{}, err
 	}
 	if !pos.IsValid() {
-		return mappedRange{}, errors.Errorf("invalid position for %v", pos)
+		return MappedRange{}, errors.Errorf("invalid position for %v", pos)
 	}
 	if !end.IsValid() {
-		return mappedRange{}, errors.Errorf("invalid position for %v", end)
+		return MappedRange{}, errors.Errorf("invalid position for %v", end)
 	}
-	return newMappedRange(snapshot.FileSet(), pgf.Mapper, pos, end), nil
+	return NewMappedRange(snapshot.FileSet(), pgf.Mapper, pos, end), nil
 }
 
 // Matches cgo generated comment as well as the proposed standard:
@@ -231,7 +240,8 @@
 	}
 }
 
-// Returns the index and the node whose position is contained inside the node list.
+// nodeAtPos returns the index and the node whose position is contained inside
+// the node list.
 func nodeAtPos(nodes []ast.Node, pos token.Pos) (ast.Node, int) {
 	if nodes == nil {
 		return nil, -1
@@ -244,121 +254,13 @@
 	return nil, -1
 }
 
-// indexExprAtPos returns the index of the expression containing pos.
-func exprAtPos(pos token.Pos, args []ast.Expr) int {
-	for i, expr := range args {
-		if expr.Pos() <= pos && pos <= expr.End() {
-			return i
-		}
-	}
-	return len(args)
+// IsInterface returns if a types.Type is an interface
+func IsInterface(T types.Type) bool {
+	return T != nil && types.IsInterface(T)
 }
 
-// eachField invokes fn for each field that can be selected from a
-// value of type T.
-func eachField(T types.Type, fn func(*types.Var)) {
-	// TODO(adonovan): this algorithm doesn't exclude ambiguous
-	// selections that match more than one field/method.
-	// types.NewSelectionSet should do that for us.
-
-	// for termination on recursive types
-	var seen map[*types.Struct]bool
-
-	var visit func(T types.Type)
-	visit = func(T types.Type) {
-		if T, ok := deref(T).Underlying().(*types.Struct); ok {
-			if seen[T] {
-				return
-			}
-
-			for i := 0; i < T.NumFields(); i++ {
-				f := T.Field(i)
-				fn(f)
-				if f.Anonymous() {
-					if seen == nil {
-						// Lazily create "seen" since it is only needed for
-						// embedded structs.
-						seen = make(map[*types.Struct]bool)
-					}
-					seen[T] = true
-					visit(f.Type())
-				}
-			}
-		}
-	}
-	visit(T)
-}
-
-// typeIsValid reports whether typ doesn't contain any Invalid types.
-func typeIsValid(typ types.Type) bool {
-	// Check named types separately, because we don't want
-	// to call Underlying() on them to avoid problems with recursive types.
-	if _, ok := typ.(*types.Named); ok {
-		return true
-	}
-
-	switch typ := typ.Underlying().(type) {
-	case *types.Basic:
-		return typ.Kind() != types.Invalid
-	case *types.Array:
-		return typeIsValid(typ.Elem())
-	case *types.Slice:
-		return typeIsValid(typ.Elem())
-	case *types.Pointer:
-		return typeIsValid(typ.Elem())
-	case *types.Map:
-		return typeIsValid(typ.Key()) && typeIsValid(typ.Elem())
-	case *types.Chan:
-		return typeIsValid(typ.Elem())
-	case *types.Signature:
-		return typeIsValid(typ.Params()) && typeIsValid(typ.Results())
-	case *types.Tuple:
-		for i := 0; i < typ.Len(); i++ {
-			if !typeIsValid(typ.At(i).Type()) {
-				return false
-			}
-		}
-		return true
-	case *types.Struct, *types.Interface:
-		// Don't bother checking structs, interfaces for validity.
-		return true
-	default:
-		return false
-	}
-}
-
-// resolveInvalid traverses the node of the AST that defines the scope
-// containing the declaration of obj, and attempts to find a user-friendly
-// name for its invalid type. The resulting Object and its Type are fake.
-func resolveInvalid(fset *token.FileSet, obj types.Object, node ast.Node, info *types.Info) types.Object {
-	var resultExpr ast.Expr
-	ast.Inspect(node, func(node ast.Node) bool {
-		switch n := node.(type) {
-		case *ast.ValueSpec:
-			for _, name := range n.Names {
-				if info.Defs[name] == obj {
-					resultExpr = n.Type
-				}
-			}
-			return false
-		case *ast.Field: // This case handles parameters and results of a FuncDecl or FuncLit.
-			for _, name := range n.Names {
-				if info.Defs[name] == obj {
-					resultExpr = n.Type
-				}
-			}
-			return false
-		default:
-			return true
-		}
-	})
-	// Construct a fake type for the object and return a fake object with this type.
-	typename := formatNode(fset, resultExpr)
-	typ := types.NewNamed(types.NewTypeName(token.NoPos, obj.Pkg(), typename, nil), types.Typ[types.Invalid], nil)
-	return types.NewVar(obj.Pos(), obj.Pkg(), obj.Name(), typ)
-}
-
-func formatNode(fset *token.FileSet, n ast.Node) string {
+// FormatNode returns the "pretty-print" output for an ast node.
+func FormatNode(fset *token.FileSet, n ast.Node) string {
 	var buf strings.Builder
 	if err := printer.Fprint(&buf, fset, n); err != nil {
 		return ""
@@ -366,19 +268,9 @@
 	return buf.String()
 }
 
-func isPointer(T types.Type) bool {
-	_, ok := T.(*types.Pointer)
-	return ok
-}
-
-func isVar(obj types.Object) bool {
-	_, ok := obj.(*types.Var)
-	return ok
-}
-
-// deref returns a pointer's element type, traversing as many levels as needed.
+// Deref returns a pointer's element type, traversing as many levels as needed.
 // Otherwise it returns typ.
-func deref(typ types.Type) types.Type {
+func Deref(typ types.Type) types.Type {
 	for {
 		p, ok := typ.Underlying().(*types.Pointer)
 		if !ok {
@@ -388,113 +280,6 @@
 	}
 }
 
-func isTypeName(obj types.Object) bool {
-	_, ok := obj.(*types.TypeName)
-	return ok
-}
-
-func isFunc(obj types.Object) bool {
-	_, ok := obj.(*types.Func)
-	return ok
-}
-
-func isEmptyInterface(T types.Type) bool {
-	intf, _ := T.(*types.Interface)
-	return intf != nil && intf.NumMethods() == 0
-}
-
-func isUntyped(T types.Type) bool {
-	if basic, ok := T.(*types.Basic); ok {
-		return basic.Info()&types.IsUntyped > 0
-	}
-	return false
-}
-
-func isPkgName(obj types.Object) bool {
-	_, ok := obj.(*types.PkgName)
-	return ok
-}
-
-func isASTFile(n ast.Node) bool {
-	_, ok := n.(*ast.File)
-	return ok
-}
-
-func deslice(T types.Type) types.Type {
-	if slice, ok := T.Underlying().(*types.Slice); ok {
-		return slice.Elem()
-	}
-	return nil
-}
-
-// isSelector returns the enclosing *ast.SelectorExpr when pos is in the
-// selector.
-func enclosingSelector(path []ast.Node, pos token.Pos) *ast.SelectorExpr {
-	if len(path) == 0 {
-		return nil
-	}
-
-	if sel, ok := path[0].(*ast.SelectorExpr); ok {
-		return sel
-	}
-
-	if _, ok := path[0].(*ast.Ident); ok && len(path) > 1 {
-		if sel, ok := path[1].(*ast.SelectorExpr); ok && pos >= sel.Sel.Pos() {
-			return sel
-		}
-	}
-
-	return nil
-}
-
-func enclosingValueSpec(path []ast.Node) *ast.ValueSpec {
-	for _, n := range path {
-		if vs, ok := n.(*ast.ValueSpec); ok {
-			return vs
-		}
-	}
-
-	return nil
-}
-
-// exprObj returns the types.Object associated with the *ast.Ident or
-// *ast.SelectorExpr e.
-func exprObj(info *types.Info, e ast.Expr) types.Object {
-	var ident *ast.Ident
-	switch expr := e.(type) {
-	case *ast.Ident:
-		ident = expr
-	case *ast.SelectorExpr:
-		ident = expr.Sel
-	default:
-		return nil
-	}
-
-	return info.ObjectOf(ident)
-}
-
-// typeConversion returns the type being converted to if call is a type
-// conversion expression.
-func typeConversion(call *ast.CallExpr, info *types.Info) types.Type {
-	// Type conversion (e.g. "float64(foo)").
-	if fun, _ := exprObj(info, call.Fun).(*types.TypeName); fun != nil {
-		return fun.Type()
-	}
-
-	return nil
-}
-
-// fieldsAccessible returns whether s has at least one field accessible by p.
-func fieldsAccessible(s *types.Struct, p *types.Package) bool {
-	for i := 0; i < s.NumFields(); i++ {
-		f := s.Field(i)
-		if f.Exported() || f.Pkg() == p {
-			return true
-		}
-	}
-	return false
-}
-
 func SortDiagnostics(d []*Diagnostic) {
 	sort.Slice(d, func(i int, j int) bool {
 		return CompareDiagnostic(d[i], d[j]) < 0
@@ -517,7 +302,9 @@
 	return 1
 }
 
-func findPosInPackage(snapshot Snapshot, searchpkg Package, pos token.Pos) (*ParsedGoFile, Package, error) {
+// FindPosInPackage finds the parsed file for a position in a given search
+// package.
+func FindPosInPackage(snapshot Snapshot, searchpkg Package, pos token.Pos) (*ParsedGoFile, Package, error) {
 	tok := snapshot.FileSet().File(pos)
 	if tok == nil {
 		return nil, nil, errors.Errorf("no file for pos in package %s", searchpkg.ID())
@@ -553,57 +340,6 @@
 	return nil, nil, errors.Errorf("no file for %s in package %s", uri, pkg.ID())
 }
 
-// prevStmt returns the statement that precedes the statement containing pos.
-// For example:
-//
-//     foo := 1
-//     bar(1 + 2<>)
-//
-// If "<>" is pos, prevStmt returns "foo := 1"
-func prevStmt(pos token.Pos, path []ast.Node) ast.Stmt {
-	var blockLines []ast.Stmt
-	for i := 0; i < len(path) && blockLines == nil; i++ {
-		switch n := path[i].(type) {
-		case *ast.BlockStmt:
-			blockLines = n.List
-		case *ast.CommClause:
-			blockLines = n.Body
-		case *ast.CaseClause:
-			blockLines = n.Body
-		}
-	}
-
-	for i := len(blockLines) - 1; i >= 0; i-- {
-		if blockLines[i].End() < pos {
-			return blockLines[i]
-		}
-	}
-
-	return nil
-}
-
-// formatZeroValue produces Go code representing the zero value of T. It
-// returns the empty string if T is invalid.
-func formatZeroValue(T types.Type, qf types.Qualifier) string {
-	switch u := T.Underlying().(type) {
-	case *types.Basic:
-		switch {
-		case u.Info()&types.IsNumeric > 0:
-			return "0"
-		case u.Info()&types.IsString > 0:
-			return `""`
-		case u.Info()&types.IsBoolean > 0:
-			return "false"
-		default:
-			return ""
-		}
-	case *types.Pointer, *types.Interface, *types.Chan, *types.Map, *types.Slice, *types.Signature:
-		return "nil"
-	default:
-		return types.TypeString(T, qf) + "{}"
-	}
-}
-
 // MarshalArgs encodes the given arguments to json.RawMessages. This function
 // is used to construct arguments to a protocol.Command.
 //
@@ -647,3 +383,68 @@
 	}
 	return nil
 }
+
+// ImportPath returns the unquoted import path of s,
+// or "" if the path is not properly quoted.
+func ImportPath(s *ast.ImportSpec) string {
+	t, err := strconv.Unquote(s.Path.Value)
+	if err != nil {
+		return ""
+	}
+	return t
+}
+
+// NodeContains returns true if a node encloses a given position pos.
+func NodeContains(n ast.Node, pos token.Pos) bool {
+	return n != nil && n.Pos() <= pos && pos <= n.End()
+}
+
+// CollectScopes returns all scopes in an ast path, ordered as innermost scope
+// first.
+func CollectScopes(info *types.Info, path []ast.Node, pos token.Pos) []*types.Scope {
+	// scopes[i], where i<len(path), is the possibly nil Scope of path[i].
+	var scopes []*types.Scope
+	for _, n := range path {
+		// Include *FuncType scope if pos is inside the function body.
+		switch node := n.(type) {
+		case *ast.FuncDecl:
+			if node.Body != nil && NodeContains(node.Body, pos) {
+				n = node.Type
+			}
+		case *ast.FuncLit:
+			if node.Body != nil && NodeContains(node.Body, pos) {
+				n = node.Type
+			}
+		}
+		scopes = append(scopes, info.Scopes[n])
+	}
+	return scopes
+}
+
+// Qualifier returns a function that appropriately formats a types.PkgName
+// appearing in a *ast.File.
+func Qualifier(f *ast.File, pkg *types.Package, info *types.Info) types.Qualifier {
+	// Construct mapping of import paths to their defined or implicit names.
+	imports := make(map[*types.Package]string)
+	for _, imp := range f.Imports {
+		var obj types.Object
+		if imp.Name != nil {
+			obj = info.Defs[imp.Name]
+		} else {
+			obj = info.Implicits[imp]
+		}
+		if pkgname, ok := obj.(*types.PkgName); ok {
+			imports[pkgname.Imported()] = pkgname.Name()
+		}
+	}
+	// Define qualifier to replace full package paths with names of the imports.
+	return func(p *types.Package) string {
+		if p == pkg {
+			return ""
+		}
+		if name, ok := imports[p]; ok {
+			return name
+		}
+		return p.Name()
+	}
+}
diff --git a/internal/lsp/source/workspace_symbol.go b/internal/lsp/source/workspace_symbol.go
index 2b9cc91..62f6adf 100644
--- a/internal/lsp/source/workspace_symbol.go
+++ b/internal/lsp/source/workspace_symbol.go
@@ -512,7 +512,7 @@
 		return
 	}
 
-	mrng := newMappedRange(sc.current.snapshot.FileSet(), sc.curFile.Mapper, node.Pos(), node.End())
+	mrng := NewMappedRange(sc.current.snapshot.FileSet(), sc.curFile.Mapper, node.Pos(), node.End())
 	rng, err := mrng.Range()
 	if err != nil {
 		return
diff --git a/internal/lsp/tests/tests.go b/internal/lsp/tests/tests.go
index 63bed53..f358fc5 100644
--- a/internal/lsp/tests/tests.go
+++ b/internal/lsp/tests/tests.go
@@ -28,6 +28,7 @@
 	"golang.org/x/tools/go/packages/packagestest"
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
+	"golang.org/x/tools/internal/lsp/source/completion"
 	"golang.org/x/tools/internal/span"
 	"golang.org/x/tools/internal/testenv"
 	"golang.org/x/tools/txtar"
@@ -46,7 +47,7 @@
 type CallHierarchy map[span.Span]*CallHierarchyResult
 type CodeLens map[span.URI][]protocol.CodeLens
 type Diagnostics map[span.URI][]*source.Diagnostic
-type CompletionItems map[token.Pos]*source.CompletionItem
+type CompletionItems map[token.Pos]*completion.CompletionItem
 type Completions map[span.Span][]Completion
 type CompletionSnippets map[span.Span][]CompletionSnippet
 type UnimportedCompletions map[span.Span][]Completion
@@ -1037,7 +1038,7 @@
 	if len(args) == 4 {
 		documentation = args[3]
 	}
-	data.CompletionItems[pos] = &source.CompletionItem{
+	data.CompletionItems[pos] = &completion.CompletionItem{
 		Label:         label,
 		Detail:        detail,
 		Kind:          protocol.ParseCompletionItemKind(kind),
diff --git a/internal/lsp/tests/util.go b/internal/lsp/tests/util.go
index c3633a1..fbef835 100644
--- a/internal/lsp/tests/util.go
+++ b/internal/lsp/tests/util.go
@@ -18,6 +18,7 @@
 	"golang.org/x/tools/internal/lsp/diff/myers"
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
+	"golang.org/x/tools/internal/lsp/source/completion"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -332,7 +333,7 @@
 	return ""
 }
 
-func ToProtocolCompletionItems(items []source.CompletionItem) []protocol.CompletionItem {
+func ToProtocolCompletionItems(items []completion.CompletionItem) []protocol.CompletionItem {
 	var result []protocol.CompletionItem
 	for _, item := range items {
 		result = append(result, ToProtocolCompletionItem(item))
@@ -340,7 +341,7 @@
 	return result
 }
 
-func ToProtocolCompletionItem(item source.CompletionItem) protocol.CompletionItem {
+func ToProtocolCompletionItem(item completion.CompletionItem) protocol.CompletionItem {
 	pItem := protocol.CompletionItem{
 		Label:         item.Label,
 		Kind:          item.Kind,
@@ -463,7 +464,7 @@
 	return ""
 }
 
-func FindItem(list []protocol.CompletionItem, want source.CompletionItem) *protocol.CompletionItem {
+func FindItem(list []protocol.CompletionItem, want completion.CompletionItem) *protocol.CompletionItem {
 	for _, item := range list {
 		if item.Label == want.Label {
 			return &item