aboutsummaryrefslogtreecommitdiff
path: root/gopls/internal/lsp/testdata
diff options
context:
space:
mode:
Diffstat (limited to 'gopls/internal/lsp/testdata')
-rw-r--r--gopls/internal/lsp/testdata/%percent/perc%ent.go1
-rw-r--r--gopls/internal/lsp/testdata/addimport/addimport.go.golden7
-rw-r--r--gopls/internal/lsp/testdata/addimport/addimport.go.in3
-rw-r--r--gopls/internal/lsp/testdata/address/address.go78
-rw-r--r--gopls/internal/lsp/testdata/analyzer/bad_test.go24
-rw-r--r--gopls/internal/lsp/testdata/anon/anon.go.in23
-rw-r--r--gopls/internal/lsp/testdata/append/append.go38
-rw-r--r--gopls/internal/lsp/testdata/append/append2.go.in5
-rw-r--r--gopls/internal/lsp/testdata/arraytype/array_type.go.in50
-rw-r--r--gopls/internal/lsp/testdata/assign/assign.go.in26
-rw-r--r--gopls/internal/lsp/testdata/assign/internal/secret/secret.go3
-rw-r--r--gopls/internal/lsp/testdata/bad/bad0.go24
-rw-r--r--gopls/internal/lsp/testdata/bad/bad1.go34
-rw-r--r--gopls/internal/lsp/testdata/badstmt/badstmt.go.in29
-rw-r--r--gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in9
-rw-r--r--gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in9
-rw-r--r--gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in11
-rw-r--r--gopls/internal/lsp/testdata/bar/bar.go.in47
-rw-r--r--gopls/internal/lsp/testdata/basiclit/basiclit.go13
-rw-r--r--gopls/internal/lsp/testdata/baz/baz.go.in33
-rw-r--r--gopls/internal/lsp/testdata/builtins/builtin_args.go62
-rw-r--r--gopls/internal/lsp/testdata/builtins/builtin_go117.go8
-rw-r--r--gopls/internal/lsp/testdata/builtins/builtin_go118.go8
-rw-r--r--gopls/internal/lsp/testdata/builtins/builtin_go121.go8
-rw-r--r--gopls/internal/lsp/testdata/builtins/builtin_types.go11
-rw-r--r--gopls/internal/lsp/testdata/builtins/builtins.go47
-rw-r--r--gopls/internal/lsp/testdata/builtins/constants.go19
-rw-r--r--gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go70
-rw-r--r--gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go12
-rw-r--r--gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go9
-rw-r--r--gopls/internal/lsp/testdata/casesensitive/casesensitive.go16
-rw-r--r--gopls/internal/lsp/testdata/cast/cast.go.in11
-rw-r--r--gopls/internal/lsp/testdata/cgo/declarecgo.go27
-rw-r--r--gopls/internal/lsp/testdata/cgo/declarecgo.go.golden30
-rw-r--r--gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go6
-rw-r--r--gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden30
-rw-r--r--gopls/internal/lsp/testdata/cgoimport/usecgo.go.in9
-rw-r--r--gopls/internal/lsp/testdata/channel/channel.go25
-rw-r--r--gopls/internal/lsp/testdata/codelens/codelens_test.go16
-rw-r--r--gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in70
-rw-r--r--gopls/internal/lsp/testdata/complit/complit.go.in90
-rw-r--r--gopls/internal/lsp/testdata/constant/constant.go14
-rw-r--r--gopls/internal/lsp/testdata/danglingstmt/dangling_for.go9
-rw-r--r--gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go9
-rw-r--r--gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go9
-rw-r--r--gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go9
-rw-r--r--gopls/internal/lsp/testdata/danglingstmt/dangling_if.go9
-rw-r--r--gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go8
-rw-r--r--gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go9
-rw-r--r--gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go9
-rw-r--r--gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go10
-rw-r--r--gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go7
-rw-r--r--gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go8
-rw-r--r--gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go9
-rw-r--r--gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go9
-rw-r--r--gopls/internal/lsp/testdata/deep/deep.go142
-rw-r--r--gopls/internal/lsp/testdata/errors/errors.go10
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go11
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden37
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go8
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden30
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go12
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden57
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go13
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden21
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go11
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden18
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go10
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden21
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go10
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden17
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go17
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden28
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go17
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden24
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go13
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden24
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go13
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden20
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go12
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden23
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go12
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden19
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go10
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden16
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go9
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden17
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go11
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden19
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go14
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden22
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go24
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden364
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go6
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden18
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go9
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden24
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go13
-rw-r--r--gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden32
-rw-r--r--gopls/internal/lsp/testdata/fieldlist/field_list.go27
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/a.go27
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/a.go.golden126
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/a2.go29
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/a2.go.golden139
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/a3.go42
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/a3.go.golden243
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/a4.go39
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/a4.go.golden174
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/data/a.go6
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/fill_struct.go26
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden124
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go14
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden20
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go15
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden19
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go12
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden36
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go24
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden52
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go9
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden13
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go12
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden17
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/typeparams.go37
-rw-r--r--gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden206
-rw-r--r--gopls/internal/lsp/testdata/folding/a.go75
-rw-r--r--gopls/internal/lsp/testdata/folding/a.go.golden722
-rw-r--r--gopls/internal/lsp/testdata/folding/bad.go.golden81
-rw-r--r--gopls/internal/lsp/testdata/folding/bad.go.in18
-rw-r--r--gopls/internal/lsp/testdata/foo/foo.go30
-rw-r--r--gopls/internal/lsp/testdata/format/bad_format.go.golden21
-rw-r--r--gopls/internal/lsp/testdata/format/bad_format.go.in22
-rw-r--r--gopls/internal/lsp/testdata/format/good_format.go9
-rw-r--r--gopls/internal/lsp/testdata/format/good_format.go.golden11
-rw-r--r--gopls/internal/lsp/testdata/format/newline_format.go.golden4
-rw-r--r--gopls/internal/lsp/testdata/format/newline_format.go.in2
-rw-r--r--gopls/internal/lsp/testdata/format/one_line.go.golden3
-rw-r--r--gopls/internal/lsp/testdata/format/one_line.go.in1
-rw-r--r--gopls/internal/lsp/testdata/func_rank/func_rank.go.in70
-rw-r--r--gopls/internal/lsp/testdata/funcsig/func_sig.go9
-rw-r--r--gopls/internal/lsp/testdata/funcvalue/func_value.go27
-rw-r--r--gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go48
-rw-r--r--gopls/internal/lsp/testdata/generate/generate.go4
-rw-r--r--gopls/internal/lsp/testdata/generated/generated.go7
-rw-r--r--gopls/internal/lsp/testdata/generated/generator.go5
-rw-r--r--gopls/internal/lsp/testdata/godef/a/a_x_test.go9
-rw-r--r--gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden26
-rw-r--r--gopls/internal/lsp/testdata/godef/a/d.go69
-rw-r--r--gopls/internal/lsp/testdata/godef/a/d.go.golden191
-rw-r--r--gopls/internal/lsp/testdata/godef/a/f.go16
-rw-r--r--gopls/internal/lsp/testdata/godef/a/f.go.golden34
-rw-r--r--gopls/internal/lsp/testdata/godef/a/g.go6
-rw-r--r--gopls/internal/lsp/testdata/godef/a/g.go.golden7
-rw-r--r--gopls/internal/lsp/testdata/godef/a/h.go147
-rw-r--r--gopls/internal/lsp/testdata/godef/a/h.go.golden161
-rw-r--r--gopls/internal/lsp/testdata/godef/b/e.go31
-rw-r--r--gopls/internal/lsp/testdata/godef/b/e.go.golden156
-rw-r--r--gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden31
-rw-r--r--gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in9
-rw-r--r--gopls/internal/lsp/testdata/good/good0.go6
-rw-r--r--gopls/internal/lsp/testdata/good/good1.go21
-rw-r--r--gopls/internal/lsp/testdata/highlights/highlights.go151
-rw-r--r--gopls/internal/lsp/testdata/implementation/implementation.go37
-rw-r--r--gopls/internal/lsp/testdata/implementation/implementation_generics.go16
-rw-r--r--gopls/internal/lsp/testdata/implementation/other/other.go27
-rw-r--r--gopls/internal/lsp/testdata/implementation/other/other_generics.go16
-rw-r--r--gopls/internal/lsp/testdata/implementation/other/other_test.go10
-rw-r--r--gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in42
-rw-r--r--gopls/internal/lsp/testdata/imports/add_import.go.golden13
-rw-r--r--gopls/internal/lsp/testdata/imports/add_import.go.in10
-rw-r--r--gopls/internal/lsp/testdata/imports/good_imports.go.golden9
-rw-r--r--gopls/internal/lsp/testdata/imports/good_imports.go.in7
-rw-r--r--gopls/internal/lsp/testdata/imports/issue35458.go.golden20
-rw-r--r--gopls/internal/lsp/testdata/imports/issue35458.go.in23
-rw-r--r--gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden9
-rw-r--r--gopls/internal/lsp/testdata/imports/multiple_blocks.go.in9
-rw-r--r--gopls/internal/lsp/testdata/imports/needs_imports.go.golden13
-rw-r--r--gopls/internal/lsp/testdata/imports/needs_imports.go.in6
-rw-r--r--gopls/internal/lsp/testdata/imports/remove_import.go.golden11
-rw-r--r--gopls/internal/lsp/testdata/imports/remove_import.go.in10
-rw-r--r--gopls/internal/lsp/testdata/imports/remove_imports.go.golden6
-rw-r--r--gopls/internal/lsp/testdata/imports/remove_imports.go.in9
-rw-r--r--gopls/internal/lsp/testdata/imports/two_lines.go.golden4
-rw-r--r--gopls/internal/lsp/testdata/imports/two_lines.go.in2
-rw-r--r--gopls/internal/lsp/testdata/index/index.go25
-rw-r--r--gopls/internal/lsp/testdata/inlay_hint/composite_literals.go27
-rw-r--r--gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden29
-rw-r--r--gopls/internal/lsp/testdata/inlay_hint/constant_values.go45
-rw-r--r--gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden47
-rw-r--r--gopls/internal/lsp/testdata/inlay_hint/parameter_names.go50
-rw-r--r--gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden52
-rw-r--r--gopls/internal/lsp/testdata/inlay_hint/type_params.go45
-rw-r--r--gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden47
-rw-r--r--gopls/internal/lsp/testdata/inlay_hint/variable_types.go20
-rw-r--r--gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden22
-rw-r--r--gopls/internal/lsp/testdata/interfacerank/interface_rank.go23
-rw-r--r--gopls/internal/lsp/testdata/issues/issue56505.go8
-rw-r--r--gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in31
-rw-r--r--gopls/internal/lsp/testdata/keywords/empty_select.go7
-rw-r--r--gopls/internal/lsp/testdata/keywords/empty_switch.go11
-rw-r--r--gopls/internal/lsp/testdata/keywords/keywords.go100
-rw-r--r--gopls/internal/lsp/testdata/labels/labels.go49
-rw-r--r--gopls/internal/lsp/testdata/links/links.go26
-rw-r--r--gopls/internal/lsp/testdata/maps/maps.go.in18
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/channels.go9
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/channels.go.golden15
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/consecutive_params.go6
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden12
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/error_param.go6
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/error_param.go.golden12
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/literals.go7
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/literals.go.golden13
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/operation.go7
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/operation.go.golden13
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/selector.go6
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/selector.go.golden12
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/slice.go5
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/slice.go.golden11
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/tuple.go9
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/tuple.go.golden15
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/unique_params.go7
-rw-r--r--gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden13
-rw-r--r--gopls/internal/lsp/testdata/multireturn/multi_return.go.in48
-rw-r--r--gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in15
-rw-r--r--gopls/internal/lsp/testdata/nodisk/empty1
-rw-r--r--gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go9
-rw-r--r--gopls/internal/lsp/testdata/noparse/noparse.go.in24
-rw-r--r--gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden2
-rw-r--r--gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in14
-rw-r--r--gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden7
-rw-r--r--gopls/internal/lsp/testdata/noparse_format/parse_format.go.in5
-rw-r--r--gopls/internal/lsp/testdata/printf/printf.go33
-rw-r--r--gopls/internal/lsp/testdata/rank/assign_rank.go.in19
-rw-r--r--gopls/internal/lsp/testdata/rank/binexpr_rank.go.in8
-rw-r--r--gopls/internal/lsp/testdata/rank/boolexpr_rank.go11
-rw-r--r--gopls/internal/lsp/testdata/rank/convert_rank.go.in54
-rw-r--r--gopls/internal/lsp/testdata/rank/struct/struct_rank.go11
-rw-r--r--gopls/internal/lsp/testdata/rank/switch_rank.go.in29
-rw-r--r--gopls/internal/lsp/testdata/rank/type_assert_rank.go.in8
-rw-r--r--gopls/internal/lsp/testdata/rank/type_switch_rank.go.in31
-rw-r--r--gopls/internal/lsp/testdata/references/another/another.go13
-rw-r--r--gopls/internal/lsp/testdata/references/interfaces/interfaces.go34
-rw-r--r--gopls/internal/lsp/testdata/references/other/other.go19
-rw-r--r--gopls/internal/lsp/testdata/references/refs.go53
-rw-r--r--gopls/internal/lsp/testdata/references/refs_test.go10
-rw-r--r--gopls/internal/lsp/testdata/rename/a/random.go.golden616
-rw-r--r--gopls/internal/lsp/testdata/rename/a/random.go.in42
-rw-r--r--gopls/internal/lsp/testdata/rename/b/b.go20
-rw-r--r--gopls/internal/lsp/testdata/rename/b/b.go.golden78
-rw-r--r--gopls/internal/lsp/testdata/rename/bad/bad.go.golden2
-rw-r--r--gopls/internal/lsp/testdata/rename/bad/bad.go.in8
-rw-r--r--gopls/internal/lsp/testdata/rename/bad/bad_test.go.in1
-rw-r--r--gopls/internal/lsp/testdata/rename/c/c.go7
-rw-r--r--gopls/internal/lsp/testdata/rename/c/c.go.golden32
-rw-r--r--gopls/internal/lsp/testdata/rename/c/c2.go4
-rw-r--r--gopls/internal/lsp/testdata/rename/c/c2.go.golden5
-rw-r--r--gopls/internal/lsp/testdata/rename/crosspkg/another/another.go13
-rw-r--r--gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden15
-rw-r--r--gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go7
-rw-r--r--gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden40
-rw-r--r--gopls/internal/lsp/testdata/rename/crosspkg/other/other.go8
-rw-r--r--gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden20
-rw-r--r--gopls/internal/lsp/testdata/rename/generics/embedded.go10
-rw-r--r--gopls/internal/lsp/testdata/rename/generics/embedded.go.golden12
-rw-r--r--gopls/internal/lsp/testdata/rename/generics/generics.go25
-rw-r--r--gopls/internal/lsp/testdata/rename/generics/generics.go.golden108
-rw-r--r--gopls/internal/lsp/testdata/rename/generics/unions.go10
-rw-r--r--gopls/internal/lsp/testdata/rename/generics/unions.go.golden24
-rw-r--r--gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden10
-rw-r--r--gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in8
-rw-r--r--gopls/internal/lsp/testdata/rename/issue42134/1.go8
-rw-r--r--gopls/internal/lsp/testdata/rename/issue42134/1.go.golden10
-rw-r--r--gopls/internal/lsp/testdata/rename/issue42134/2.go12
-rw-r--r--gopls/internal/lsp/testdata/rename/issue42134/2.go.golden14
-rw-r--r--gopls/internal/lsp/testdata/rename/issue42134/3.go11
-rw-r--r--gopls/internal/lsp/testdata/rename/issue42134/3.go.golden13
-rw-r--r--gopls/internal/lsp/testdata/rename/issue42134/4.go8
-rw-r--r--gopls/internal/lsp/testdata/rename/issue42134/4.go.golden10
-rw-r--r--gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden13
-rw-r--r--gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in7
-rw-r--r--gopls/internal/lsp/testdata/rename/shadow/shadow.go20
-rw-r--r--gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden51
-rw-r--r--gopls/internal/lsp/testdata/rename/testy/testy.go7
-rw-r--r--gopls/internal/lsp/testdata/rename/testy/testy.go.golden18
-rw-r--r--gopls/internal/lsp/testdata/rename/testy/testy_test.go8
-rw-r--r--gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden30
-rw-r--r--gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go14
-rw-r--r--gopls/internal/lsp/testdata/selectionrange/foo.go13
-rw-r--r--gopls/internal/lsp/testdata/selectionrange/foo.go.golden29
-rw-r--r--gopls/internal/lsp/testdata/selector/selector.go.in66
-rw-r--r--gopls/internal/lsp/testdata/semantic/README.md2
-rw-r--r--gopls/internal/lsp/testdata/semantic/a.go81
-rw-r--r--gopls/internal/lsp/testdata/semantic/a.go.golden83
-rw-r--r--gopls/internal/lsp/testdata/semantic/b.go38
-rw-r--r--gopls/internal/lsp/testdata/semantic/b.go.golden40
-rw-r--r--gopls/internal/lsp/testdata/semantic/semantic_test.go13
-rw-r--r--gopls/internal/lsp/testdata/signature/signature.go85
-rw-r--r--gopls/internal/lsp/testdata/signature/signature.go.golden53
-rw-r--r--gopls/internal/lsp/testdata/signature/signature2.go.golden3
-rw-r--r--gopls/internal/lsp/testdata/signature/signature2.go.in5
-rw-r--r--gopls/internal/lsp/testdata/signature/signature3.go.golden3
-rw-r--r--gopls/internal/lsp/testdata/signature/signature3.go.in5
-rw-r--r--gopls/internal/lsp/testdata/signature/signature_test.go13
-rw-r--r--gopls/internal/lsp/testdata/signature/signature_test.go.golden9
-rw-r--r--gopls/internal/lsp/testdata/snippets/func_snippets118.go.in19
-rw-r--r--gopls/internal/lsp/testdata/snippets/literal.go22
-rw-r--r--gopls/internal/lsp/testdata/snippets/literal.go.golden3
-rw-r--r--gopls/internal/lsp/testdata/snippets/literal_snippets.go.in233
-rw-r--r--gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in14
-rw-r--r--gopls/internal/lsp/testdata/snippets/postfix.go42
-rw-r--r--gopls/internal/lsp/testdata/snippets/snippets.go.golden3
-rw-r--r--gopls/internal/lsp/testdata/snippets/snippets.go.in61
-rw-r--r--gopls/internal/lsp/testdata/statements/append.go42
-rw-r--r--gopls/internal/lsp/testdata/statements/if_err_check_return.go27
-rw-r--r--gopls/internal/lsp/testdata/statements/if_err_check_return_2.go12
-rw-r--r--gopls/internal/lsp/testdata/statements/if_err_check_test.go20
-rw-r--r--gopls/internal/lsp/testdata/stub/other/other.go10
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_add_selector.go12
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden19
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_assign.go10
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_assign.go.golden17
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_assign_multivars.go11
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden18
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_call_expr.go13
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden20
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_embedded.go15
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_embedded.go.golden37
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_err.go7
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_err.go.golden14
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_function_return.go11
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_function_return.go.golden18
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_generic_receiver.go15
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden22
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_ignored_imports.go18
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden25
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_issue2606.go7
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden14
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_multi_var.go11
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden18
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_pointer.go9
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_pointer.go.golden16
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_renamed_import.go11
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden18
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go13
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden22
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_stdlib.go9
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden16
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_typedecl_group.go27
-rw-r--r--gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden39
-rw-r--r--gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go11
-rw-r--r--gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden13
-rw-r--r--gopls/internal/lsp/testdata/summary.txt.golden32
-rw-r--r--gopls/internal/lsp/testdata/summary_go1.18.txt.golden32
-rw-r--r--gopls/internal/lsp/testdata/symbols/go1.18.go16
-rw-r--r--gopls/internal/lsp/testdata/symbols/go1.18.go.golden7
-rw-r--r--gopls/internal/lsp/testdata/symbols/main.go91
-rw-r--r--gopls/internal/lsp/testdata/symbols/main.go.golden36
-rw-r--r--gopls/internal/lsp/testdata/testy/testy.go5
-rw-r--r--gopls/internal/lsp/testdata/testy/testy_test.go18
-rw-r--r--gopls/internal/lsp/testdata/testy/testy_test.go.golden3
-rw-r--r--gopls/internal/lsp/testdata/typdef/typdef.go65
-rw-r--r--gopls/internal/lsp/testdata/typeassert/type_assert.go24
-rw-r--r--gopls/internal/lsp/testdata/typeerrors/noresultvalues.go5
-rw-r--r--gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden14
-rw-r--r--gopls/internal/lsp/testdata/typemods/type_mods.go21
-rw-r--r--gopls/internal/lsp/testdata/typeparams/type_params.go61
-rw-r--r--gopls/internal/lsp/testdata/types/types.go18
-rw-r--r--gopls/internal/lsp/testdata/undeclared/var.go14
-rw-r--r--gopls/internal/lsp/testdata/undeclared/var.go.golden51
-rw-r--r--gopls/internal/lsp/testdata/unimported/export_test.go3
-rw-r--r--gopls/internal/lsp/testdata/unimported/unimported.go.in23
-rw-r--r--gopls/internal/lsp/testdata/unimported/unimported_cand_type.go16
-rw-r--r--gopls/internal/lsp/testdata/unimported/x_test.go9
-rw-r--r--gopls/internal/lsp/testdata/unresolved/unresolved.go.in6
-rw-r--r--gopls/internal/lsp/testdata/unsafe/unsafe.go13
-rw-r--r--gopls/internal/lsp/testdata/variadic/variadic.go.in38
-rw-r--r--gopls/internal/lsp/testdata/variadic/variadic_intf.go21
-rw-r--r--gopls/internal/lsp/testdata/workspacesymbol/a/a.go9
-rw-r--r--gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go3
-rw-r--r--gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go3
-rw-r--r--gopls/internal/lsp/testdata/workspacesymbol/b/b.go7
-rw-r--r--gopls/internal/lsp/testdata/workspacesymbol/issue44806.go10
-rw-r--r--gopls/internal/lsp/testdata/workspacesymbol/main.go47
-rw-r--r--gopls/internal/lsp/testdata/workspacesymbol/p/p.go3
-rw-r--r--gopls/internal/lsp/testdata/workspacesymbol/query.go29
-rw-r--r--gopls/internal/lsp/testdata/workspacesymbol/query.go.golden83
386 files changed, 11612 insertions, 0 deletions
diff --git a/gopls/internal/lsp/testdata/%percent/perc%ent.go b/gopls/internal/lsp/testdata/%percent/perc%ent.go
new file mode 100644
index 000000000..93b5e5570
--- /dev/null
+++ b/gopls/internal/lsp/testdata/%percent/perc%ent.go
@@ -0,0 +1 @@
+package percent
diff --git a/gopls/internal/lsp/testdata/addimport/addimport.go.golden b/gopls/internal/lsp/testdata/addimport/addimport.go.golden
new file mode 100644
index 000000000..9605aa6f9
--- /dev/null
+++ b/gopls/internal/lsp/testdata/addimport/addimport.go.golden
@@ -0,0 +1,7 @@
+-- addimport --
+package addimport //@addimport("", "bytes")
+
+import "bytes"
+
+func main() {}
+
diff --git a/gopls/internal/lsp/testdata/addimport/addimport.go.in b/gopls/internal/lsp/testdata/addimport/addimport.go.in
new file mode 100644
index 000000000..07b454f52
--- /dev/null
+++ b/gopls/internal/lsp/testdata/addimport/addimport.go.in
@@ -0,0 +1,3 @@
+package addimport //@addimport("", "bytes")
+
+func main() {}
diff --git a/gopls/internal/lsp/testdata/address/address.go b/gopls/internal/lsp/testdata/address/address.go
new file mode 100644
index 000000000..3f1c2fa8d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/address/address.go
@@ -0,0 +1,78 @@
+package address
+
+func wantsPtr(*int) {}
+func wantsVariadicPtr(...*int) {}
+
+func wantsVariadic(...int) {}
+
+type foo struct{ c int } //@item(addrFieldC, "c", "int", "field")
+
+func _() {
+ var (
+ a string //@item(addrA, "a", "string", "var")
+ b int //@item(addrB, "b", "int", "var")
+ )
+
+ wantsPtr() //@rank(")", addrB, addrA),snippet(")", addrB, "&b", "&b")
+ wantsPtr(&b) //@snippet(")", addrB, "b", "b")
+
+ wantsVariadicPtr() //@rank(")", addrB, addrA),snippet(")", addrB, "&b", "&b")
+
+ var s foo
+ s.c //@item(addrDeepC, "s.c", "int", "field")
+ wantsPtr() //@snippet(")", addrDeepC, "&s.c", "&s.c")
+ wantsPtr(s) //@snippet(")", addrDeepC, "&s.c", "&s.c")
+ wantsPtr(&s) //@snippet(")", addrDeepC, "s.c", "s.c")
+
+ // don't add "&" in item (it gets added as an additional edit)
+ wantsPtr(&s.c) //@snippet(")", addrFieldC, "c", "c")
+
+ // check dereferencing as well
+ var c *int //@item(addrCPtr, "c", "*int", "var")
+ var _ int = _ //@rank("_ //", addrCPtr, addrA),snippet("_ //", addrCPtr, "*c", "*c")
+
+ wantsVariadic() //@rank(")", addrCPtr, addrA),snippet(")", addrCPtr, "*c", "*c")
+
+ var d **int //@item(addrDPtr, "d", "**int", "var")
+ var _ int = _ //@rank("_ //", addrDPtr, addrA),snippet("_ //", addrDPtr, "**d", "**d")
+
+ type namedPtr *int
+ var np namedPtr //@item(addrNamedPtr, "np", "namedPtr", "var")
+
+ var _ int = _ //@rank("_ //", addrNamedPtr, addrA)
+
+ // don't get tripped up by recursive pointer type
+ type dontMessUp *dontMessUp
+ var dmu *dontMessUp //@item(addrDMU, "dmu", "*dontMessUp", "var")
+
+ var _ int = dmu //@complete(" //", addrDMU)
+}
+
+func (f foo) ptr() *foo { return &f }
+
+func _() {
+ getFoo := func() foo { return foo{} }
+
+ // not addressable
+ getFoo().c //@item(addrGetFooC, "getFoo().c", "int", "field")
+
+ // addressable
+ getFoo().ptr().c //@item(addrGetFooPtrC, "getFoo().ptr().c", "int", "field")
+
+ wantsPtr() //@rank(addrGetFooPtrC, addrGetFooC),snippet(")", addrGetFooPtrC, "&getFoo().ptr().c", "&getFoo().ptr().c")
+ wantsPtr(&g) //@rank(addrGetFooPtrC, addrGetFooC),snippet(")", addrGetFooPtrC, "getFoo().ptr().c", "getFoo().ptr().c")
+}
+
+type nested struct {
+ f foo
+}
+
+func _() {
+ getNested := func() nested { return nested{} }
+
+ getNested().f.c //@item(addrNestedC, "getNested().f.c", "int", "field")
+ getNested().f.ptr().c //@item(addrNestedPtrC, "getNested().f.ptr().c", "int", "field")
+
+ // addrNestedC is not addressable, so rank lower
+ wantsPtr(getNestedfc) //@fuzzy(")", addrNestedPtrC, addrNestedC)
+}
diff --git a/gopls/internal/lsp/testdata/analyzer/bad_test.go b/gopls/internal/lsp/testdata/analyzer/bad_test.go
new file mode 100644
index 000000000..b1724c666
--- /dev/null
+++ b/gopls/internal/lsp/testdata/analyzer/bad_test.go
@@ -0,0 +1,24 @@
+package analyzer
+
+import (
+ "fmt"
+ "sync"
+ "testing"
+ "time"
+)
+
+func Testbad(t *testing.T) { //@diag("", "tests", "Testbad has malformed name: first letter after 'Test' must not be lowercase", "warning")
+ var x sync.Mutex
+ _ = x //@diag("x", "copylocks", "assignment copies lock value to _: sync.Mutex", "warning")
+
+ printfWrapper("%s") //@diag(re`printfWrapper\(.*\)`, "printf", "golang.org/lsptests/analyzer.printfWrapper format %s reads arg #1, but call has 0 args", "warning")
+}
+
+func printfWrapper(format string, args ...interface{}) {
+ fmt.Printf(format, args...)
+}
+
+func _() {
+ now := time.Now()
+ fmt.Println(now.Format("2006-02-01")) //@diag("2006-02-01", "timeformat", "2006-02-01 should be 2006-01-02", "warning")
+}
diff --git a/gopls/internal/lsp/testdata/anon/anon.go.in b/gopls/internal/lsp/testdata/anon/anon.go.in
new file mode 100644
index 000000000..36611b268
--- /dev/null
+++ b/gopls/internal/lsp/testdata/anon/anon.go.in
@@ -0,0 +1,23 @@
+package anon
+
+func _() {
+ for _, _ := range []struct {
+ i, j int //@item(anonI, "i", "int", "field"),item(anonJ, "j", "int", "field")
+ }{
+ {
+ i: 1,
+ //@complete("", anonJ)
+ },
+ {
+ //@complete("", anonI, anonJ)
+ },
+ } {
+ continue
+ }
+
+ s := struct{ f int }{ } //@item(anonF, "f", "int", "field"),item(structS, "s", "struct{...}", "var"),complete(" }", anonF)
+
+ _ = map[struct{ x int }]int{ //@item(anonX, "x", "int", "field")
+ struct{ x int }{ }: 1, //@complete(" }", anonX, structS)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/append/append.go b/gopls/internal/lsp/testdata/append/append.go
new file mode 100644
index 000000000..2880e59db
--- /dev/null
+++ b/gopls/internal/lsp/testdata/append/append.go
@@ -0,0 +1,38 @@
+package append
+
+func foo([]string) {}
+func bar(...string) {}
+
+func _() {
+ var (
+ aInt []int //@item(appendInt, "aInt", "[]int", "var")
+ aStrings []string //@item(appendStrings, "aStrings", "[]string", "var")
+ aString string //@item(appendString, "aString", "string", "var")
+ )
+
+ append(aStrings, a) //@rank(")", appendString, appendInt)
+ var _ interface{} = append(aStrings, a) //@rank(")", appendString, appendInt)
+ var _ []string = append(oops, a) //@rank(")", appendString, appendInt)
+
+ foo(append()) //@rank("))", appendStrings, appendInt),rank("))", appendStrings, appendString)
+ foo(append([]string{}, a)) //@rank("))", appendStrings, appendInt),rank("))", appendString, appendInt),snippet("))", appendStrings, "aStrings...", "aStrings...")
+ foo(append([]string{}, "", a)) //@rank("))", appendString, appendInt),rank("))", appendString, appendStrings)
+
+ // Don't add "..." to append() argument.
+ bar(append()) //@snippet("))", appendStrings, "aStrings", "aStrings")
+
+ type baz struct{}
+ baz{} //@item(appendBazLiteral, "baz{}", "", "var")
+ var bazzes []baz //@item(appendBazzes, "bazzes", "[]baz", "var")
+ var bazzy baz //@item(appendBazzy, "bazzy", "baz", "var")
+ bazzes = append(bazzes, ba) //@rank(")", appendBazzy, appendBazLiteral, appendBazzes)
+
+ var b struct{ b []baz }
+ b.b //@item(appendNestedBaz, "b.b", "[]baz", "field")
+ b.b = append(b.b, b) //@rank(")", appendBazzy, appendBazLiteral, appendNestedBaz)
+
+ var aStringsPtr *[]string //@item(appendStringsPtr, "aStringsPtr", "*[]string", "var")
+ foo(append([]string{}, a)) //@snippet("))", appendStringsPtr, "*aStringsPtr...", "*aStringsPtr...")
+
+ foo(append([]string{}, *a)) //@snippet("))", appendStringsPtr, "aStringsPtr...", "aStringsPtr...")
+}
diff --git a/gopls/internal/lsp/testdata/append/append2.go.in b/gopls/internal/lsp/testdata/append/append2.go.in
new file mode 100644
index 000000000..15bd357b2
--- /dev/null
+++ b/gopls/internal/lsp/testdata/append/append2.go.in
@@ -0,0 +1,5 @@
+package append
+
+func _() {
+ _ = append(a, struct) //@complete(")")
+} \ No newline at end of file
diff --git a/gopls/internal/lsp/testdata/arraytype/array_type.go.in b/gopls/internal/lsp/testdata/arraytype/array_type.go.in
new file mode 100644
index 000000000..ac1a3e782
--- /dev/null
+++ b/gopls/internal/lsp/testdata/arraytype/array_type.go.in
@@ -0,0 +1,50 @@
+package arraytype
+
+import (
+ "golang.org/lsptests/foo"
+)
+
+func _() {
+ var (
+ val string //@item(atVal, "val", "string", "var")
+ )
+
+ // disabled - see issue #54822
+ [] // complete(" //", PackageFoo)
+
+ []val //@complete(" //")
+
+ []foo.StructFoo //@complete(" //", StructFoo)
+
+ []foo.StructFoo(nil) //@complete("(", StructFoo)
+
+ []*foo.StructFoo //@complete(" //", StructFoo)
+
+ [...]foo.StructFoo //@complete(" //", StructFoo)
+
+ [2][][4]foo.StructFoo //@complete(" //", StructFoo)
+
+ []struct { f []foo.StructFoo } //@complete(" }", StructFoo)
+}
+
+func _() {
+ type myInt int //@item(atMyInt, "myInt", "int", "type")
+
+ var mark []myInt //@item(atMark, "mark", "[]myInt", "var")
+
+ var s []myInt //@item(atS, "s", "[]myInt", "var")
+ s = []m //@complete(" //", atMyInt)
+ // disabled - see issue #54822
+ s = [] // complete(" //", atMyInt, PackageFoo)
+
+ var a [1]myInt
+ a = [1]m //@complete(" //", atMyInt)
+
+ var ds [][]myInt
+ ds = [][]m //@complete(" //", atMyInt)
+}
+
+func _() {
+ var b [0]byte //@item(atByte, "b", "[0]byte", "var")
+ var _ []byte = b //@snippet(" //", atByte, "b[:]", "b[:]")
+}
diff --git a/gopls/internal/lsp/testdata/assign/assign.go.in b/gopls/internal/lsp/testdata/assign/assign.go.in
new file mode 100644
index 000000000..93a622c83
--- /dev/null
+++ b/gopls/internal/lsp/testdata/assign/assign.go.in
@@ -0,0 +1,26 @@
+package assign
+
+import "golang.org/lsptests/assign/internal/secret"
+
+func _() {
+ secret.Hello()
+ var (
+ myInt int //@item(assignInt, "myInt", "int", "var")
+ myStr string //@item(assignStr, "myStr", "string", "var")
+ )
+
+ var _ string = my //@rank(" //", assignStr, assignInt)
+ var _ string = //@rank(" //", assignStr, assignInt)
+}
+
+func _() {
+ var a string = a //@complete(" //")
+}
+
+func _() {
+ fooBar := fooBa //@complete(" //"),item(assignFooBar, "fooBar", "", "var")
+ abc, fooBar := 123, fooBa //@complete(" //", assignFooBar)
+ {
+ fooBar := fooBa //@complete(" //", assignFooBar)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/assign/internal/secret/secret.go b/gopls/internal/lsp/testdata/assign/internal/secret/secret.go
new file mode 100644
index 000000000..5ee1554df
--- /dev/null
+++ b/gopls/internal/lsp/testdata/assign/internal/secret/secret.go
@@ -0,0 +1,3 @@
+package secret
+
+func Hello() {} \ No newline at end of file
diff --git a/gopls/internal/lsp/testdata/bad/bad0.go b/gopls/internal/lsp/testdata/bad/bad0.go
new file mode 100644
index 000000000..0f23a3911
--- /dev/null
+++ b/gopls/internal/lsp/testdata/bad/bad0.go
@@ -0,0 +1,24 @@
+//go:build go1.11
+// +build go1.11
+
+package bad
+
+import _ "golang.org/lsptests/assign/internal/secret" //@diag("\"golang.org/lsptests/assign/internal/secret\"", "compiler", "could not import golang.org/lsptests/assign/internal/secret \\(invalid use of internal package \"golang.org/lsptests/assign/internal/secret\"\\)", "error")
+
+func stuff() { //@item(stuff, "stuff", "func()", "func")
+ x := "heeeeyyyy"
+ random2(x) //@diag("x", "compiler", "cannot use x \\(variable of type string\\) as int value in argument to random2", "error")
+ random2(1) //@complete("dom", random, random2, random3)
+ y := 3 //@diag("y", "compiler", "y declared (and|but) not used", "error")
+}
+
+type bob struct { //@item(bob, "bob", "struct{...}", "struct")
+ x int
+}
+
+func _() {
+ var q int
+ _ = &bob{
+ f: q, //@diag("f: q", "compiler", "unknown field f in struct literal", "error")
+ }
+}
diff --git a/gopls/internal/lsp/testdata/bad/bad1.go b/gopls/internal/lsp/testdata/bad/bad1.go
new file mode 100644
index 000000000..13b3d0af6
--- /dev/null
+++ b/gopls/internal/lsp/testdata/bad/bad1.go
@@ -0,0 +1,34 @@
+//go:build go1.11
+// +build go1.11
+
+package bad
+
+// See #36637
+type stateFunc func() stateFunc //@item(stateFunc, "stateFunc", "func() stateFunc", "type")
+
+var a unknown //@item(global_a, "a", "unknown", "var"),diag("unknown", "compiler", "(undeclared name|undefined): unknown", "error")
+
+func random() int { //@item(random, "random", "func() int", "func")
+ //@complete("", global_a, bob, random, random2, random3, stateFunc, stuff)
+ return 0
+}
+
+func random2(y int) int { //@item(random2, "random2", "func(y int) int", "func"),item(bad_y_param, "y", "int", "var")
+ x := 6 //@item(x, "x", "int", "var"),diag("x", "compiler", "x declared (and|but) not used", "error")
+ var q blah //@item(q, "q", "blah", "var"),diag("q", "compiler", "q declared (and|but) not used", "error"),diag("blah", "compiler", "(undeclared name|undefined): blah", "error")
+ var t **blob //@item(t, "t", "**blob", "var"),diag("t", "compiler", "t declared (and|but) not used", "error"),diag("blob", "compiler", "(undeclared name|undefined): blob", "error")
+ //@complete("", q, t, x, bad_y_param, global_a, bob, random, random2, random3, stateFunc, stuff)
+
+ return y
+}
+
+func random3(y ...int) { //@item(random3, "random3", "func(y ...int)", "func"),item(y_variadic_param, "y", "[]int", "var")
+ //@complete("", y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff)
+
+ var ch chan (favType1) //@item(ch, "ch", "chan (favType1)", "var"),diag("ch", "compiler", "ch declared (and|but) not used", "error"),diag("favType1", "compiler", "(undeclared name|undefined): favType1", "error")
+ var m map[keyType]int //@item(m, "m", "map[keyType]int", "var"),diag("m", "compiler", "m declared (and|but) not used", "error"),diag("keyType", "compiler", "(undeclared name|undefined): keyType", "error")
+ var arr []favType2 //@item(arr, "arr", "[]favType2", "var"),diag("arr", "compiler", "arr declared (and|but) not used", "error"),diag("favType2", "compiler", "(undeclared name|undefined): favType2", "error")
+ var fn1 func() badResult //@item(fn1, "fn1", "func() badResult", "var"),diag("fn1", "compiler", "fn1 declared (and|but) not used", "error"),diag("badResult", "compiler", "(undeclared name|undefined): badResult", "error")
+ var fn2 func(badParam) //@item(fn2, "fn2", "func(badParam)", "var"),diag("fn2", "compiler", "fn2 declared (and|but) not used", "error"),diag("badParam", "compiler", "(undeclared name|undefined): badParam", "error")
+ //@complete("", arr, ch, fn1, fn2, m, y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff)
+}
diff --git a/gopls/internal/lsp/testdata/badstmt/badstmt.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt.go.in
new file mode 100644
index 000000000..81aee201d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/badstmt/badstmt.go.in
@@ -0,0 +1,29 @@
+package badstmt
+
+import (
+ "golang.org/lsptests/foo"
+)
+
+// The nonewvars expectation asserts that the go/analysis framework ran.
+// See comments in noparse.
+
+func _(x int) {
+ defer foo.F //@complete(" //", Foo),diag(" //", "syntax", "function must be invoked in defer statement|expression in defer must be function call", "error")
+ defer foo.F //@complete(" //", Foo)
+ x := 123 //@diag(":=", "nonewvars", "no new variables", "warning")
+}
+
+func _() {
+ switch true {
+ case true:
+ go foo.F //@complete(" //", Foo)
+ }
+}
+
+func _() {
+ defer func() {
+ foo.F //@complete(" //", Foo),snippet(" //", Foo, "Foo()", "Foo()")
+
+ foo. //@rank(" //", Foo)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in
new file mode 100644
index 000000000..6af9c35e3
--- /dev/null
+++ b/gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in
@@ -0,0 +1,9 @@
+package badstmt
+
+import (
+ "golang.org/lsptests/foo"
+)
+
+func _() {
+ defer func() { foo. } //@rank(" }", Foo)
+}
diff --git a/gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in
new file mode 100644
index 000000000..d135e2015
--- /dev/null
+++ b/gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in
@@ -0,0 +1,9 @@
+package badstmt
+
+import (
+ "golang.org/lsptests/foo"
+)
+
+func _() {
+ go foo. //@rank(" //", Foo, IntFoo),snippet(" //", Foo, "Foo()", "Foo()")
+}
diff --git a/gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in
new file mode 100644
index 000000000..6afd635ec
--- /dev/null
+++ b/gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in
@@ -0,0 +1,11 @@
+package badstmt
+
+import (
+ "golang.org/lsptests/foo"
+)
+
+func _() {
+ go func() {
+ defer foo. //@rank(" //", Foo, IntFoo)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/bar/bar.go.in b/gopls/internal/lsp/testdata/bar/bar.go.in
new file mode 100644
index 000000000..502bdf740
--- /dev/null
+++ b/gopls/internal/lsp/testdata/bar/bar.go.in
@@ -0,0 +1,47 @@
+// +build go1.11
+
+package bar
+
+import (
+ "golang.org/lsptests/foo" //@item(foo, "foo", "\"golang.org/lsptests/foo\"", "package")
+)
+
+func helper(i foo.IntFoo) {} //@item(helper, "helper", "func(i foo.IntFoo)", "func")
+
+func _() {
+ help //@complete("l", helper)
+ _ = foo.StructFoo{} //@complete("S", IntFoo, StructFoo)
+}
+
+// Bar is a function.
+func Bar() { //@item(Bar, "Bar", "func()", "func", "Bar is a function.")
+ foo.Foo() //@complete("F", Foo, IntFoo, StructFoo)
+ var _ foo.IntFoo //@complete("I", IntFoo, StructFoo)
+ foo.() //@complete("(", Foo, IntFoo, StructFoo)
+}
+
+func _() {
+ var Valentine int //@item(Valentine, "Valentine", "int", "var")
+
+ _ = foo.StructFoo{
+ Valu //@complete(" //", Value)
+ }
+ _ = foo.StructFoo{
+ Va //@complete("a", Value, Valentine)
+ }
+ _ = foo.StructFoo{
+ Value: 5, //@complete("a", Value)
+ }
+ _ = foo.StructFoo{
+ //@complete("", Value, Valentine, foo, helper, Bar)
+ }
+ _ = foo.StructFoo{
+ Value: Valen //@complete("le", Valentine)
+ }
+ _ = foo.StructFoo{
+ Value: //@complete(" //", Valentine, foo, helper, Bar)
+ }
+ _ = foo.StructFoo{
+ Value: //@complete(" ", Valentine, foo, helper, Bar)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/basiclit/basiclit.go b/gopls/internal/lsp/testdata/basiclit/basiclit.go
new file mode 100644
index 000000000..ab895dc01
--- /dev/null
+++ b/gopls/internal/lsp/testdata/basiclit/basiclit.go
@@ -0,0 +1,13 @@
+package basiclit
+
+func _() {
+ var a int // something for lexical completions
+
+ _ = "hello." //@complete(".")
+
+ _ = 1 //@complete(" //")
+
+ _ = 1. //@complete(".")
+
+ _ = 'a' //@complete("' ")
+}
diff --git a/gopls/internal/lsp/testdata/baz/baz.go.in b/gopls/internal/lsp/testdata/baz/baz.go.in
new file mode 100644
index 000000000..94952e126
--- /dev/null
+++ b/gopls/internal/lsp/testdata/baz/baz.go.in
@@ -0,0 +1,33 @@
+// +build go1.11
+
+package baz
+
+import (
+ "golang.org/lsptests/bar"
+
+ f "golang.org/lsptests/foo"
+)
+
+var FooStruct f.StructFoo
+
+func Baz() {
+ defer bar.Bar() //@complete("B", Bar)
+ // TODO(rstambler): Test completion here.
+ defer bar.B
+ var x f.IntFoo //@complete("n", IntFoo),typdef("x", IntFoo)
+ bar.Bar() //@complete("B", Bar)
+}
+
+func _() {
+ bob := f.StructFoo{Value: 5}
+ if x := bob. //@complete(" //", Value)
+ switch true == false {
+ case true:
+ if x := bob. //@complete(" //", Value)
+ case false:
+ }
+ if x := bob.Va //@complete("a", Value)
+ switch true == true {
+ default:
+ }
+}
diff --git a/gopls/internal/lsp/testdata/builtins/builtin_args.go b/gopls/internal/lsp/testdata/builtins/builtin_args.go
new file mode 100644
index 000000000..052777fe9
--- /dev/null
+++ b/gopls/internal/lsp/testdata/builtins/builtin_args.go
@@ -0,0 +1,62 @@
+package builtins
+
+func _() {
+ var (
+ aSlice []int //@item(builtinSlice, "aSlice", "[]int", "var")
+ aMap map[string]int //@item(builtinMap, "aMap", "map[string]int", "var")
+ aString string //@item(builtinString, "aString", "string", "var")
+ aArray [0]int //@item(builtinArray, "aArray", "[0]int", "var")
+ aArrayPtr *[0]int //@item(builtinArrayPtr, "aArrayPtr", "*[0]int", "var")
+ aChan chan int //@item(builtinChan, "aChan", "chan int", "var")
+ aPtr *int //@item(builtinPtr, "aPtr", "*int", "var")
+ aInt int //@item(builtinInt, "aInt", "int", "var")
+ )
+
+ type (
+ aSliceType []int //@item(builtinSliceType, "aSliceType", "[]int", "type")
+ aChanType chan int //@item(builtinChanType, "aChanType", "chan int", "type")
+ aMapType map[string]int //@item(builtinMapType, "aMapType", "map[string]int", "type")
+ )
+
+ close() //@rank(")", builtinChan, builtinSlice)
+
+ append() //@rank(")", builtinSlice, builtinChan)
+
+ var _ []byte = append([]byte(nil), ""...) //@rank(") //")
+
+ copy() //@rank(")", builtinSlice, builtinChan)
+ copy(aSlice, aS) //@rank(")", builtinSlice, builtinString)
+ copy(aS, aSlice) //@rank(",", builtinSlice, builtinString)
+
+ delete() //@rank(")", builtinMap, builtinChan)
+ delete(aMap, aS) //@rank(")", builtinString, builtinSlice)
+
+ aMapFunc := func() map[int]int { //@item(builtinMapFunc, "aMapFunc", "func() map[int]int", "var")
+ return nil
+ }
+ delete() //@rank(")", builtinMapFunc, builtinSlice)
+
+ len() //@rank(")", builtinSlice, builtinInt),rank(")", builtinMap, builtinInt),rank(")", builtinString, builtinInt),rank(")", builtinArray, builtinInt),rank(")", builtinArrayPtr, builtinPtr),rank(")", builtinChan, builtinInt)
+
+ cap() //@rank(")", builtinSlice, builtinMap),rank(")", builtinArray, builtinString),rank(")", builtinArrayPtr, builtinPtr),rank(")", builtinChan, builtinInt)
+
+ make() //@rank(")", builtinMapType, int),rank(")", builtinChanType, int),rank(")", builtinSliceType, int),rank(")", builtinMapType, int)
+ make(aSliceType, a) //@rank(")", builtinInt, builtinSlice)
+
+ type myInt int
+ var mi myInt //@item(builtinMyInt, "mi", "myInt", "var")
+ make(aSliceType, m) //@snippet(")", builtinMyInt, "mi", "mi")
+
+ var _ []int = make() //@rank(")", builtinSliceType, builtinMapType)
+
+ type myStruct struct{} //@item(builtinStructType, "myStruct", "struct{...}", "struct")
+ var _ *myStruct = new() //@rank(")", builtinStructType, int)
+
+ for k := range a { //@rank(" {", builtinSlice, builtinInt),rank(" {", builtinString, builtinInt),rank(" {", builtinChan, builtinInt),rank(" {", builtinArray, builtinInt),rank(" {", builtinArrayPtr, builtinInt),rank(" {", builtinMap, builtinInt),
+ }
+
+ for k, v := range a { //@rank(" {", builtinSlice, builtinChan)
+ }
+
+ <-a //@rank(" //", builtinChan, builtinInt)
+}
diff --git a/gopls/internal/lsp/testdata/builtins/builtin_go117.go b/gopls/internal/lsp/testdata/builtins/builtin_go117.go
new file mode 100644
index 000000000..57abcde15
--- /dev/null
+++ b/gopls/internal/lsp/testdata/builtins/builtin_go117.go
@@ -0,0 +1,8 @@
+//go:build !go1.18
+// +build !go1.18
+
+package builtins
+
+func _() {
+ //@complete("", append, bool, byte, cap, close, complex, complex128, complex64, copy, delete, error, _false, float32, float64, imag, int, int16, int32, int64, int8, len, make, new, panic, print, println, real, recover, rune, string, _true, uint, uint16, uint32, uint64, uint8, uintptr, _nil)
+}
diff --git a/gopls/internal/lsp/testdata/builtins/builtin_go118.go b/gopls/internal/lsp/testdata/builtins/builtin_go118.go
new file mode 100644
index 000000000..dabffcc67
--- /dev/null
+++ b/gopls/internal/lsp/testdata/builtins/builtin_go118.go
@@ -0,0 +1,8 @@
+//go:build go1.18 && !go1.21
+// +build go1.18,!go1.21
+
+package builtins
+
+func _() {
+ //@complete("", any, append, bool, byte, cap, close, comparable, complex, complex128, complex64, copy, delete, error, _false, float32, float64, imag, int, int16, int32, int64, int8, len, make, new, panic, print, println, real, recover, rune, string, _true, uint, uint16, uint32, uint64, uint8, uintptr, _nil)
+}
diff --git a/gopls/internal/lsp/testdata/builtins/builtin_go121.go b/gopls/internal/lsp/testdata/builtins/builtin_go121.go
new file mode 100644
index 000000000..cb8e8fae3
--- /dev/null
+++ b/gopls/internal/lsp/testdata/builtins/builtin_go121.go
@@ -0,0 +1,8 @@
+//go:build go1.21
+// +build go1.21
+
+package builtins
+
+func _() {
+ //@complete("", any, append, bool, byte, cap, clear, close, comparable, complex, complex128, complex64, copy, delete, error, _false, float32, float64, imag, int, int16, int32, int64, int8, len, make, new, panic, print, println, real, recover, rune, string, _true, uint, uint16, uint32, uint64, uint8, uintptr, _nil)
+}
diff --git a/gopls/internal/lsp/testdata/builtins/builtin_types.go b/gopls/internal/lsp/testdata/builtins/builtin_types.go
new file mode 100644
index 000000000..93a4a7095
--- /dev/null
+++ b/gopls/internal/lsp/testdata/builtins/builtin_types.go
@@ -0,0 +1,11 @@
+package builtins
+
+func _() {
+ var _ []bool //@item(builtinBoolSliceType, "[]bool", "[]bool", "type")
+
+ var _ []bool = make() //@rank(")", builtinBoolSliceType, int)
+
+ var _ []bool = make([], 0) //@rank(",", bool, int)
+
+ var _ [][]bool = make([][], 0) //@rank(",", bool, int)
+}
diff --git a/gopls/internal/lsp/testdata/builtins/builtins.go b/gopls/internal/lsp/testdata/builtins/builtins.go
new file mode 100644
index 000000000..75c6e4183
--- /dev/null
+++ b/gopls/internal/lsp/testdata/builtins/builtins.go
@@ -0,0 +1,47 @@
+package builtins
+
+// Definitions of builtin completion items.
+
+/* any */ //@item(any, "any", "", "interface")
+/* Create markers for builtin types. Only for use by this test.
+/* append(slice []Type, elems ...Type) []Type */ //@item(append, "append", "func(slice []Type, elems ...Type) []Type", "func")
+/* bool */ //@item(bool, "bool", "", "type")
+/* byte */ //@item(byte, "byte", "", "type")
+/* cap(v Type) int */ //@item(cap, "cap", "func(v Type) int", "func")
+/* clear[T interface{ ~[]Type | ~map[Type]Type1 }](t T) */ //@item(clear, "clear", "func(t T)", "func")
+/* close(c chan<- Type) */ //@item(close, "close", "func(c chan<- Type)", "func")
+/* comparable */ //@item(comparable, "comparable", "", "interface")
+/* complex(r float64, i float64) */ //@item(complex, "complex", "func(r float64, i float64) complex128", "func")
+/* complex128 */ //@item(complex128, "complex128", "", "type")
+/* complex64 */ //@item(complex64, "complex64", "", "type")
+/* copy(dst []Type, src []Type) int */ //@item(copy, "copy", "func(dst []Type, src []Type) int", "func")
+/* delete(m map[Type]Type1, key Type) */ //@item(delete, "delete", "func(m map[Type]Type1, key Type)", "func")
+/* error */ //@item(error, "error", "", "interface")
+/* false */ //@item(_false, "false", "", "const")
+/* float32 */ //@item(float32, "float32", "", "type")
+/* float64 */ //@item(float64, "float64", "", "type")
+/* imag(c complex128) float64 */ //@item(imag, "imag", "func(c complex128) float64", "func")
+/* int */ //@item(int, "int", "", "type")
+/* int16 */ //@item(int16, "int16", "", "type")
+/* int32 */ //@item(int32, "int32", "", "type")
+/* int64 */ //@item(int64, "int64", "", "type")
+/* int8 */ //@item(int8, "int8", "", "type")
+/* iota */ //@item(iota, "iota", "", "const")
+/* len(v Type) int */ //@item(len, "len", "func(v Type) int", "func")
+/* make(t Type, size ...int) Type */ //@item(make, "make", "func(t Type, size ...int) Type", "func")
+/* new(Type) *Type */ //@item(new, "new", "func(Type) *Type", "func")
+/* nil */ //@item(_nil, "nil", "", "var")
+/* panic(v interface{}) */ //@item(panic, "panic", "func(v interface{})", "func")
+/* print(args ...Type) */ //@item(print, "print", "func(args ...Type)", "func")
+/* println(args ...Type) */ //@item(println, "println", "func(args ...Type)", "func")
+/* real(c complex128) float64 */ //@item(real, "real", "func(c complex128) float64", "func")
+/* recover() interface{} */ //@item(recover, "recover", "func() interface{}", "func")
+/* rune */ //@item(rune, "rune", "", "type")
+/* string */ //@item(string, "string", "", "type")
+/* true */ //@item(_true, "true", "", "const")
+/* uint */ //@item(uint, "uint", "", "type")
+/* uint16 */ //@item(uint16, "uint16", "", "type")
+/* uint32 */ //@item(uint32, "uint32", "", "type")
+/* uint64 */ //@item(uint64, "uint64", "", "type")
+/* uint8 */ //@item(uint8, "uint8", "", "type")
+/* uintptr */ //@item(uintptr, "uintptr", "", "type")
diff --git a/gopls/internal/lsp/testdata/builtins/constants.go b/gopls/internal/lsp/testdata/builtins/constants.go
new file mode 100644
index 000000000..7ad07bd1f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/builtins/constants.go
@@ -0,0 +1,19 @@
+package builtins
+
+func _() {
+ const (
+ foo = iota //@complete(" //", iota)
+ )
+
+ iota //@complete(" //")
+
+ var iota int //@item(iotaVar, "iota", "int", "var")
+
+ iota //@complete(" //", iotaVar)
+}
+
+func _() {
+ var twoRedUpEnd bool //@item(TRUEVar, "twoRedUpEnd", "bool", "var")
+
+ var _ bool = true //@rank(" //", _true, TRUEVar)
+}
diff --git a/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go b/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go
new file mode 100644
index 000000000..252e8054f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go
@@ -0,0 +1,70 @@
+// 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 callhierarchy
+
+import "golang.org/lsptests/callhierarchy/outgoing"
+
+func a() { //@mark(hierarchyA, "a")
+ D()
+}
+
+func b() { //@mark(hierarchyB, "b")
+ D()
+}
+
+// C is an exported function
+func C() { //@mark(hierarchyC, "C")
+ D()
+ D()
+}
+
+// To test hierarchy across function literals
+var x = func() { //@mark(hierarchyLiteral, "func"),mark(hierarchyLiteralOut, "x")
+ D()
+}
+
+// D is exported to test incoming/outgoing calls across packages
+func D() { //@mark(hierarchyD, "D"),incomingcalls(hierarchyD, hierarchyA, hierarchyB, hierarchyC, hierarchyLiteral, incomingA),outgoingcalls(hierarchyD, hierarchyE, hierarchyF, hierarchyG, hierarchyLiteralOut, outgoingB, hierarchyFoo, hierarchyH, hierarchyI, hierarchyJ, hierarchyK)
+ e()
+ x()
+ F()
+ outgoing.B()
+ foo := func() {} //@mark(hierarchyFoo, "foo"),incomingcalls(hierarchyFoo, hierarchyD),outgoingcalls(hierarchyFoo)
+ foo()
+
+ func() {
+ g()
+ }()
+
+ var i Interface = impl{}
+ i.H()
+ i.I()
+
+ s := Struct{}
+ s.J()
+ s.K()
+}
+
+func e() {} //@mark(hierarchyE, "e")
+
+// F is an exported function
+func F() {} //@mark(hierarchyF, "F")
+
+func g() {} //@mark(hierarchyG, "g")
+
+type Interface interface {
+ H() //@mark(hierarchyH, "H")
+ I() //@mark(hierarchyI, "I")
+}
+
+type impl struct{}
+
+func (i impl) H() {}
+func (i impl) I() {}
+
+type Struct struct {
+ J func() //@mark(hierarchyJ, "J")
+ K func() //@mark(hierarchyK, "K")
+}
diff --git a/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go b/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go
new file mode 100644
index 000000000..c629aa879
--- /dev/null
+++ b/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go
@@ -0,0 +1,12 @@
+// 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 incoming
+
+import "golang.org/lsptests/callhierarchy"
+
+// A is exported to test incoming calls across packages
+func A() { //@mark(incomingA, "A")
+ callhierarchy.D()
+}
diff --git a/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go b/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go
new file mode 100644
index 000000000..74362d419
--- /dev/null
+++ b/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go
@@ -0,0 +1,9 @@
+// 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 outgoing
+
+// B is exported to test outgoing calls across packages
+func B() { //@mark(outgoingB, "B")
+}
diff --git a/gopls/internal/lsp/testdata/casesensitive/casesensitive.go b/gopls/internal/lsp/testdata/casesensitive/casesensitive.go
new file mode 100644
index 000000000..6f49d36ff
--- /dev/null
+++ b/gopls/internal/lsp/testdata/casesensitive/casesensitive.go
@@ -0,0 +1,16 @@
+// 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 casesensitive
+
+func _() {
+ var lower int //@item(lower, "lower", "int", "var")
+ var Upper int //@item(upper, "Upper", "int", "var")
+
+ l //@casesensitive(" //", lower)
+ U //@casesensitive(" //", upper)
+
+ L //@casesensitive(" //")
+ u //@casesensitive(" //")
+}
diff --git a/gopls/internal/lsp/testdata/cast/cast.go.in b/gopls/internal/lsp/testdata/cast/cast.go.in
new file mode 100644
index 000000000..7fe21903c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/cast/cast.go.in
@@ -0,0 +1,11 @@
+package cast
+
+func _() {
+ foo := struct{x int}{x: 1} //@item(x_field, "x", "int", "field")
+ _ = float64(foo.x) //@complete("x", x_field)
+}
+
+func _() {
+ foo := struct{x int}{x: 1}
+ _ = float64(foo. //@complete(" /", x_field)
+} \ No newline at end of file
diff --git a/gopls/internal/lsp/testdata/cgo/declarecgo.go b/gopls/internal/lsp/testdata/cgo/declarecgo.go
new file mode 100644
index 000000000..c283cdfb2
--- /dev/null
+++ b/gopls/internal/lsp/testdata/cgo/declarecgo.go
@@ -0,0 +1,27 @@
+package cgo
+
+/*
+#include <stdio.h>
+#include <stdlib.h>
+
+void myprint(char* s) {
+ printf("%s\n", s);
+}
+*/
+import "C"
+
+import (
+ "fmt"
+ "unsafe"
+)
+
+func Example() { //@mark(funccgoexample, "Example"),item(funccgoexample, "Example", "func()", "func")
+ fmt.Println()
+ cs := C.CString("Hello from stdio\n")
+ C.myprint(cs)
+ C.free(unsafe.Pointer(cs))
+}
+
+func _() {
+ Example() //@godef("ample", funccgoexample),complete("ample", funccgoexample)
+}
diff --git a/gopls/internal/lsp/testdata/cgo/declarecgo.go.golden b/gopls/internal/lsp/testdata/cgo/declarecgo.go.golden
new file mode 100644
index 000000000..0d6fbb0ff
--- /dev/null
+++ b/gopls/internal/lsp/testdata/cgo/declarecgo.go.golden
@@ -0,0 +1,30 @@
+-- funccgoexample-definition --
+cgo/declarecgo.go:18:6-13: defined here as ```go
+func Example()
+```
+
+[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)
+-- funccgoexample-definition-json --
+{
+ "span": {
+ "uri": "file://cgo/declarecgo.go",
+ "start": {
+ "line": 18,
+ "column": 6,
+ "offset": 151
+ },
+ "end": {
+ "line": 18,
+ "column": 13,
+ "offset": 158
+ }
+ },
+ "description": "```go\nfunc Example()\n```\n\n[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)"
+}
+
+-- funccgoexample-hoverdef --
+```go
+func Example()
+```
+
+[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)
diff --git a/gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go b/gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go
new file mode 100644
index 000000000..a05c01257
--- /dev/null
+++ b/gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go
@@ -0,0 +1,6 @@
+//+build !cgo
+
+package cgo
+
+// Set a dummy marker to keep the test framework happy. The tests should be skipped.
+var _ = "Example" //@mark(funccgoexample, "Example"),godef("ample", funccgoexample),complete("ample", funccgoexample)
diff --git a/gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden
new file mode 100644
index 000000000..03fc22468
--- /dev/null
+++ b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden
@@ -0,0 +1,30 @@
+-- funccgoexample-definition --
+cgo/declarecgo.go:18:6-13: defined here as ```go
+func cgo.Example()
+```
+
+[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)
+-- funccgoexample-definition-json --
+{
+ "span": {
+ "uri": "file://cgo/declarecgo.go",
+ "start": {
+ "line": 18,
+ "column": 6,
+ "offset": 151
+ },
+ "end": {
+ "line": 18,
+ "column": 13,
+ "offset": 158
+ }
+ },
+ "description": "```go\nfunc cgo.Example()\n```\n\n[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)"
+}
+
+-- funccgoexample-hoverdef --
+```go
+func cgo.Example()
+```
+
+[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)
diff --git a/gopls/internal/lsp/testdata/cgoimport/usecgo.go.in b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.in
new file mode 100644
index 000000000..414a739da
--- /dev/null
+++ b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.in
@@ -0,0 +1,9 @@
+package cgoimport
+
+import (
+ "golang.org/lsptests/cgo"
+)
+
+func _() {
+ cgo.Example() //@godef("ample", funccgoexample),complete("ample", funccgoexample)
+}
diff --git a/gopls/internal/lsp/testdata/channel/channel.go b/gopls/internal/lsp/testdata/channel/channel.go
new file mode 100644
index 000000000..d6bd311e3
--- /dev/null
+++ b/gopls/internal/lsp/testdata/channel/channel.go
@@ -0,0 +1,25 @@
+package channel
+
+func _() {
+ var (
+ aa = "123" //@item(channelAA, "aa", "string", "var")
+ ab = 123 //@item(channelAB, "ab", "int", "var")
+ )
+
+ {
+ type myChan chan int
+ var mc myChan
+ mc <- a //@complete(" //", channelAB, channelAA)
+ }
+
+ {
+ var ac chan int //@item(channelAC, "ac", "chan int", "var")
+ a <- a //@complete(" <-", channelAC, channelAA, channelAB)
+ }
+
+ {
+ var foo chan int //@item(channelFoo, "foo", "chan int", "var")
+ wantsInt := func(int) {} //@item(channelWantsInt, "wantsInt", "func(int)", "var")
+ wantsInt(<-) //@rank(")", channelFoo, channelAB)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/codelens/codelens_test.go b/gopls/internal/lsp/testdata/codelens/codelens_test.go
new file mode 100644
index 000000000..f6c696416
--- /dev/null
+++ b/gopls/internal/lsp/testdata/codelens/codelens_test.go
@@ -0,0 +1,16 @@
+package codelens //@codelens("package codelens", "run file benchmarks", "test")
+
+import "testing"
+
+func TestMain(m *testing.M) {} // no code lens for TestMain
+
+func TestFuncWithCodeLens(t *testing.T) { //@codelens("func", "run test", "test")
+}
+
+func thisShouldNotHaveACodeLens(t *testing.T) {
+}
+
+func BenchmarkFuncWithCodeLens(b *testing.B) { //@codelens("func", "run benchmark", "test")
+}
+
+func helper() {} // expect no code lens
diff --git a/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in b/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in
new file mode 100644
index 000000000..dbca0ff17
--- /dev/null
+++ b/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in
@@ -0,0 +1,70 @@
+package comment_completion
+
+var p bool
+
+//@complete(re"$")
+
+func _() {
+ var a int
+
+ switch a {
+ case 1:
+ //@complete(re"$")
+ _ = a
+ }
+
+ var b chan int
+ select {
+ case <-b:
+ //@complete(re"$")
+ _ = b
+ }
+
+ var (
+ //@complete(re"$")
+ _ = a
+ )
+}
+
+// //@complete(" ", variableC)
+var C string //@item(variableC, "C", "string", "var") //@complete(" ", variableC)
+
+// //@complete(" ", constant)
+const Constant = "example" //@item(constant, "Constant", "string", "const") //@complete(" ", constant)
+
+// //@complete(" ", structType, fieldB, fieldA)
+type StructType struct { //@item(structType, "StructType", "struct{...}", "struct") //@complete(" ", structType, fieldA, fieldB)
+ // //@complete(" ", fieldA, structType, fieldB)
+ A string //@item(fieldA, "A", "string", "field") //@complete(" ", fieldA, structType, fieldB)
+ b int //@item(fieldB, "b", "int", "field") //@complete(" ", fieldB, structType, fieldA)
+}
+
+// //@complete(" ", method, structRecv, paramX, resultY, fieldB, fieldA)
+func (structType *StructType) Method(X int) (Y int) { //@item(structRecv, "structType", "*StructType", "var"),item(method, "Method", "func(X int) (Y int)", "method"),item(paramX, "X", "int", "var"),item(resultY, "Y", "int", "var")
+ // //@complete(" ", method, structRecv, paramX, resultY, fieldB, fieldA)
+ return
+}
+
+// //@complete(" ", newType)
+type NewType string //@item(newType, "NewType", "string", "type") //@complete(" ", newType)
+
+// //@complete(" ", testInterface, testA, testB)
+type TestInterface interface { //@item(testInterface, "TestInterface", "interface{...}", "interface")
+ // //@complete(" ", testA, testInterface, testB)
+ TestA(L string) (M int) //@item(testA, "TestA", "func(L string) (M int)", "method"),item(paramL, "L", "var", "string"),item(resM, "M", "var", "int") //@complete(" ", testA, testInterface, testB)
+ TestB(N int) bool //@item(testB, "TestB", "func(N int) bool", "method"),item(paramN, "N", "var", "int") //@complete(" ", testB, testInterface, testA)
+}
+
+// //@complete(" ", function)
+func Function() int { //@item(function, "Function", "func() int", "func") //@complete(" ", function)
+ // //@complete(" ", function)
+ return 0
+}
+
+// This tests multiline block comments and completion with prefix
+// Lorem Ipsum Multili//@complete("Multi", multiline)
+// Lorem ipsum dolor sit ametom
+func Multiline() int { //@item(multiline, "Multiline", "func() int", "func")
+ // //@complete(" ", multiline)
+ return 0
+}
diff --git a/gopls/internal/lsp/testdata/complit/complit.go.in b/gopls/internal/lsp/testdata/complit/complit.go.in
new file mode 100644
index 000000000..e819810d8
--- /dev/null
+++ b/gopls/internal/lsp/testdata/complit/complit.go.in
@@ -0,0 +1,90 @@
+package complit
+
+// general completions
+
+type position struct { //@item(structPosition, "position", "struct{...}", "struct")
+ X, Y int //@item(fieldX, "X", "int", "field"),item(fieldY, "Y", "int", "field")
+}
+
+func _() {
+ _ = position{
+ //@complete("", fieldX, fieldY, structPosition)
+ }
+ _ = position{
+ X: 1,
+ //@complete("", fieldY)
+ }
+ _ = position{
+ //@complete("", fieldX)
+ Y: 1,
+ }
+ _ = []*position{
+ {
+ //@complete("", fieldX, fieldY, structPosition)
+ },
+ }
+}
+
+func _() {
+ var (
+ aa string //@item(aaVar, "aa", "string", "var")
+ ab int //@item(abVar, "ab", "int", "var")
+ )
+
+ _ = map[int]int{
+ a: a, //@complete(":", abVar, aaVar),complete(",", abVar, aaVar)
+ }
+
+ _ = map[int]int{
+ //@complete("", abVar, aaVar, structPosition)
+ }
+
+ _ = []string{a: ""} //@complete(":", abVar, aaVar)
+ _ = [1]string{a: ""} //@complete(":", abVar, aaVar)
+
+ _ = position{X: a} //@complete("}", abVar, aaVar)
+ _ = position{a} //@complete("}", abVar, aaVar)
+ _ = position{a, } //@complete("}", abVar, aaVar, structPosition)
+
+ _ = []int{a} //@complete("}", abVar, aaVar)
+ _ = [1]int{a} //@complete("}", abVar, aaVar)
+
+ type myStruct struct {
+ AA int //@item(fieldAA, "AA", "int", "field")
+ AB string //@item(fieldAB, "AB", "string", "field")
+ }
+
+ _ = myStruct{
+ AB: a, //@complete(",", aaVar, abVar)
+ }
+
+ var s myStruct
+
+ _ = map[int]string{1: "" + s.A} //@complete("}", fieldAB, fieldAA)
+ _ = map[int]string{1: (func(i int) string { return "" })(s.A)} //@complete(")}", fieldAA, fieldAB)
+ _ = map[int]string{1: func() string { s.A }} //@complete(" }", fieldAA, fieldAB)
+
+ _ = position{s.A} //@complete("}", fieldAA, fieldAB)
+
+ var X int //@item(varX, "X", "int", "var")
+ _ = position{X} //@complete("}", fieldX, varX)
+}
+
+func _() {
+ type foo struct{} //@item(complitFoo, "foo", "struct{...}", "struct")
+
+ var _ *foo = &fo{} //@snippet("{", complitFoo, "foo", "foo")
+ var _ *foo = fo{} //@snippet("{", complitFoo, "&foo", "&foo")
+
+ struct { a, b *foo }{
+ a: &fo{}, //@rank("{", complitFoo)
+ b: fo{}, //@snippet("{", complitFoo, "&foo", "&foo")
+ }
+}
+
+func _() {
+ _ := position{
+ X: 1, //@complete("X", fieldX),complete(" 1", structPosition)
+ Y: , //@complete(":", fieldY),complete(" ,", structPosition)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/constant/constant.go b/gopls/internal/lsp/testdata/constant/constant.go
new file mode 100644
index 000000000..c1c88e16e
--- /dev/null
+++ b/gopls/internal/lsp/testdata/constant/constant.go
@@ -0,0 +1,14 @@
+package constant
+
+const x = 1 //@item(constX, "x", "int", "const")
+
+const (
+ a int = iota << 2 //@item(constA, "a", "int", "const")
+ b //@item(constB, "b", "int", "const")
+ c //@item(constC, "c", "int", "const")
+)
+
+func _() {
+ const y = "hi" //@item(constY, "y", "string", "const")
+ //@complete("", constY, constA, constB, constC, constX)
+}
diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go
new file mode 100644
index 000000000..a16d3bd88
--- /dev/null
+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go
@@ -0,0 +1,9 @@
+package danglingstmt
+
+func _() {
+ for bar //@rank(" //", danglingBar)
+}
+
+func bar() bool { //@item(danglingBar, "bar", "func() bool", "func")
+ return true
+}
diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go
new file mode 100644
index 000000000..e1130bc23
--- /dev/null
+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go
@@ -0,0 +1,9 @@
+package danglingstmt
+
+func _() {
+ for i := bar //@rank(" //", danglingBar2)
+}
+
+func bar2() int { //@item(danglingBar2, "bar2", "func() int", "func")
+ return 0
+}
diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go
new file mode 100644
index 000000000..fb0269f16
--- /dev/null
+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go
@@ -0,0 +1,9 @@
+package danglingstmt
+
+func _() {
+ for i := bar3(); i > bar //@rank(" //", danglingBar3)
+}
+
+func bar3() int { //@item(danglingBar3, "bar3", "func() int", "func")
+ return 0
+}
diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go
new file mode 100644
index 000000000..14f78d392
--- /dev/null
+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go
@@ -0,0 +1,9 @@
+package danglingstmt
+
+func _() {
+ for i := bar4(); i > bar4(); i += bar //@rank(" //", danglingBar4)
+}
+
+func bar4() int { //@item(danglingBar4, "bar4", "func() int", "func")
+ return 0
+}
diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go
new file mode 100644
index 000000000..91f145ada
--- /dev/null
+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go
@@ -0,0 +1,9 @@
+package danglingstmt
+
+func _() {
+ if foo //@rank(" //", danglingFoo)
+}
+
+func foo() bool { //@item(danglingFoo, "foo", "func() bool", "func")
+ return true
+}
diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go
new file mode 100644
index 000000000..3454c9fa6
--- /dev/null
+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go
@@ -0,0 +1,8 @@
+package danglingstmt
+
+func bar5() bool { //@item(danglingBar5, "bar5", "func() bool", "func")
+ return true
+}
+
+func _() {
+ if b //@rank(" //", danglingBar5)
diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go
new file mode 100644
index 000000000..887c31860
--- /dev/null
+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go
@@ -0,0 +1,9 @@
+package danglingstmt
+
+func _() {
+ if i := foo //@rank(" //", danglingFoo2)
+}
+
+func foo2() bool { //@item(danglingFoo2, "foo2", "func() bool", "func")
+ return true
+}
diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go
new file mode 100644
index 000000000..5371283e9
--- /dev/null
+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go
@@ -0,0 +1,9 @@
+package danglingstmt
+
+func _() {
+ if i := 123; foo //@rank(" //", danglingFoo3)
+}
+
+func foo3() bool { //@item(danglingFoo3, "foo3", "func() bool", "func")
+ return true
+}
diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go
new file mode 100644
index 000000000..2213777e1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go
@@ -0,0 +1,10 @@
+package danglingstmt
+
+func walrus() bool { //@item(danglingWalrus, "walrus", "func() bool", "func")
+ return true
+}
+
+func _() {
+ if true &&
+ walrus //@complete(" //", danglingWalrus)
+}
diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go
new file mode 100644
index 000000000..772152f7b
--- /dev/null
+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go
@@ -0,0 +1,7 @@
+package danglingstmt
+
+func _() {
+ x. //@rank(" //", danglingI)
+}
+
+var x struct { i int } //@item(danglingI, "i", "int", "field")
diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go
new file mode 100644
index 000000000..8d4b15bff
--- /dev/null
+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go
@@ -0,0 +1,8 @@
+package danglingstmt
+
+import "golang.org/lsptests/foo"
+
+func _() {
+ foo. //@rank(" //", Foo)
+ var _ = []string{foo.} //@rank("}", Foo)
+}
diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go
new file mode 100644
index 000000000..15da3ce10
--- /dev/null
+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go
@@ -0,0 +1,9 @@
+package danglingstmt
+
+func _() {
+ switch i := baz //@rank(" //", danglingBaz)
+}
+
+func baz() int { //@item(danglingBaz, "baz", "func() int", "func")
+ return 0
+}
diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go
new file mode 100644
index 000000000..20b825b2e
--- /dev/null
+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go
@@ -0,0 +1,9 @@
+package danglingstmt
+
+func _() {
+ switch i := 0; baz //@rank(" //", danglingBaz2)
+}
+
+func baz2() int { //@item(danglingBaz2, "baz2", "func() int", "func")
+ return 0
+}
diff --git a/gopls/internal/lsp/testdata/deep/deep.go b/gopls/internal/lsp/testdata/deep/deep.go
new file mode 100644
index 000000000..6908824f8
--- /dev/null
+++ b/gopls/internal/lsp/testdata/deep/deep.go
@@ -0,0 +1,142 @@
+package deep
+
+import "context"
+
+type deepA struct {
+ b deepB //@item(deepBField, "b", "deepB", "field")
+}
+
+type deepB struct {
+}
+
+func wantsDeepB(deepB) {}
+
+func _() {
+ var a deepA //@item(deepAVar, "a", "deepA", "var")
+ a.b //@item(deepABField, "a.b", "deepB", "field")
+ wantsDeepB(a) //@deep(")", deepABField, deepAVar)
+
+ deepA{a} //@snippet("}", deepABField, "a.b", "a.b")
+}
+
+func wantsContext(context.Context) {}
+
+func _() {
+ context.Background() //@item(ctxBackground, "context.Background", "func() context.Context", "func", "Background returns a non-nil, empty Context.")
+ context.TODO() //@item(ctxTODO, "context.TODO", "func() context.Context", "func", "TODO returns a non-nil, empty Context.")
+
+ wantsContext(c) //@rank(")", ctxBackground),rank(")", ctxTODO)
+}
+
+func _() {
+ var cork struct{ err error }
+ cork.err //@item(deepCorkErr, "cork.err", "error", "field")
+ context //@item(deepContextPkg, "context", "\"context\"", "package")
+ var _ error = co //@rank(" //", deepCorkErr, deepContextPkg)
+}
+
+func _() {
+ // deepCircle is circular.
+ type deepCircle struct {
+ *deepCircle
+ }
+ var circle deepCircle //@item(deepCircle, "circle", "deepCircle", "var")
+ circle.deepCircle //@item(deepCircleField, "circle.deepCircle", "*deepCircle", "field")
+ var _ deepCircle = circ //@deep(" //", deepCircle, deepCircleField),snippet(" //", deepCircleField, "*circle.deepCircle", "*circle.deepCircle")
+}
+
+func _() {
+ type deepEmbedC struct {
+ }
+ type deepEmbedB struct {
+ deepEmbedC
+ }
+ type deepEmbedA struct {
+ deepEmbedB
+ }
+
+ wantsC := func(deepEmbedC) {}
+
+ var a deepEmbedA //@item(deepEmbedA, "a", "deepEmbedA", "var")
+ a.deepEmbedB //@item(deepEmbedB, "a.deepEmbedB", "deepEmbedB", "field")
+ a.deepEmbedC //@item(deepEmbedC, "a.deepEmbedC", "deepEmbedC", "field")
+ wantsC(a) //@deep(")", deepEmbedC, deepEmbedA, deepEmbedB)
+}
+
+func _() {
+ type nested struct {
+ a int
+ n *nested //@item(deepNestedField, "n", "*nested", "field")
+ }
+
+ nested{
+ a: 123, //@deep(" //", deepNestedField)
+ }
+}
+
+func _() {
+ var a struct {
+ b struct {
+ c int
+ }
+ d int
+ }
+
+ a.d //@item(deepAD, "a.d", "int", "field")
+ a.b.c //@item(deepABC, "a.b.c", "int", "field")
+ a.b //@item(deepAB, "a.b", "struct{...}", "field")
+ a //@item(deepA, "a", "struct{...}", "var")
+
+ // "a.d" should be ranked above the deeper "a.b.c"
+ var i int
+ i = a //@deep(" //", deepAD, deepABC, deepA, deepAB)
+}
+
+type foo struct {
+ b bar
+}
+
+func (f foo) bar() bar {
+ return f.b
+}
+
+func (f foo) barPtr() *bar {
+ return &f.b
+}
+
+type bar struct{}
+
+func (b bar) valueReceiver() int {
+ return 0
+}
+
+func (b *bar) ptrReceiver() int {
+ return 0
+}
+
+func _() {
+ var (
+ i int
+ f foo
+ )
+
+ f.bar().valueReceiver //@item(deepBarValue, "f.bar().valueReceiver", "func() int", "method")
+ f.barPtr().ptrReceiver //@item(deepBarPtrPtr, "f.barPtr().ptrReceiver", "func() int", "method")
+ f.barPtr().valueReceiver //@item(deepBarPtrValue, "f.barPtr().valueReceiver", "func() int", "method")
+
+ i = fbar //@fuzzy(" //", deepBarValue, deepBarPtrPtr, deepBarPtrValue)
+}
+
+func (b baz) Thing() struct{ val int } {
+ return b.thing
+}
+
+type baz struct {
+ thing struct{ val int }
+}
+
+func (b baz) _() {
+ b.Thing().val //@item(deepBazMethVal, "b.Thing().val", "int", "field")
+ b.thing.val //@item(deepBazFieldVal, "b.thing.val", "int", "field")
+ var _ int = bval //@rank(" //", deepBazFieldVal, deepBazMethVal)
+}
diff --git a/gopls/internal/lsp/testdata/errors/errors.go b/gopls/internal/lsp/testdata/errors/errors.go
new file mode 100644
index 000000000..e14cde69e
--- /dev/null
+++ b/gopls/internal/lsp/testdata/errors/errors.go
@@ -0,0 +1,10 @@
+package errors
+
+import (
+ "golang.org/lsptests/types"
+)
+
+func _() {
+ bob.Bob() //@complete(".")
+ types.b //@complete(" //", Bob_interface)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go
new file mode 100644
index 000000000..63d24df00
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go
@@ -0,0 +1,11 @@
+package extract
+
+func _() {
+ a := 1
+ a = 5 //@mark(exSt0, "a")
+ a = a + 2 //@mark(exEn0, "2")
+ //@extractfunc(exSt0, exEn0)
+ b := a * 2 //@mark(exB, " b")
+ _ = 3 + 4 //@mark(exEnd, "4")
+ //@extractfunc(exB, exEnd)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden
new file mode 100644
index 000000000..b15345e23
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden
@@ -0,0 +1,37 @@
+-- functionextraction_extract_args_returns_5_2 --
+package extract
+
+func _() {
+ a := 1
+ //@mark(exSt0, "a")
+ a = newFunction(a) //@mark(exEn0, "2")
+ //@extractfunc(exSt0, exEn0)
+ b := a * 2 //@mark(exB, " b")
+ _ = 3 + 4 //@mark(exEnd, "4")
+ //@extractfunc(exB, exEnd)
+}
+
+func newFunction(a int) int {
+ a = 5
+ a = a + 2
+ return a
+}
+
+-- functionextraction_extract_args_returns_8_1 --
+package extract
+
+func _() {
+ a := 1
+ a = 5 //@mark(exSt0, "a")
+ a = a + 2 //@mark(exEn0, "2")
+ //@extractfunc(exSt0, exEn0)
+ //@mark(exB, " b")
+ newFunction(a) //@mark(exEnd, "4")
+ //@extractfunc(exB, exEnd)
+}
+
+func newFunction(a int) {
+ b := a * 2
+ _ = 3 + 4
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go
new file mode 100644
index 000000000..5e44de26f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go
@@ -0,0 +1,8 @@
+package extract
+
+func _() { //@mark(exSt25, "{")
+ a := 1 //@mark(exSt1, "a")
+ _ = 3 + 4 //@mark(exEn1, "4")
+ //@extractfunc(exSt1, exEn1)
+ //@extractfunc(exSt25, exEn25)
+} //@mark(exEn25, "}")
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden
new file mode 100644
index 000000000..18adc4db4
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden
@@ -0,0 +1,30 @@
+-- functionextraction_extract_basic_3_10 --
+package extract
+
+func _() { //@mark(exSt25, "{")
+ //@mark(exSt1, "a")
+ newFunction() //@mark(exEn1, "4")
+ //@extractfunc(exSt1, exEn1)
+ //@extractfunc(exSt25, exEn25)
+}
+
+func newFunction() {
+ a := 1
+ _ = 3 + 4
+} //@mark(exEn25, "}")
+
+-- functionextraction_extract_basic_4_2 --
+package extract
+
+func _() { //@mark(exSt25, "{")
+ //@mark(exSt1, "a")
+ newFunction() //@mark(exEn1, "4")
+ //@extractfunc(exSt1, exEn1)
+ //@extractfunc(exSt25, exEn25)
+}
+
+func newFunction() {
+ a := 1
+ _ = 3 + 4
+} //@mark(exEn25, "}")
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go
new file mode 100644
index 000000000..71f969e48
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go
@@ -0,0 +1,12 @@
+package extract
+
+func _() {
+ a := /* comment in the middle of a line */ 1 //@mark(exSt18, "a")
+ // Comment on its own line //@mark(exSt19, "Comment")
+ _ = 3 + 4 //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_")
+ // Comment right after 3 + 4
+
+ // Comment after with space //@mark(exEn20, "Comment")
+
+ //@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden
new file mode 100644
index 000000000..1b2869ef7
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden
@@ -0,0 +1,57 @@
+-- functionextraction_extract_basic_comment_4_2 --
+package extract
+
+func _() {
+ /* comment in the middle of a line */
+ //@mark(exSt18, "a")
+ // Comment on its own line //@mark(exSt19, "Comment")
+ newFunction() //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_")
+ // Comment right after 3 + 4
+
+ // Comment after with space //@mark(exEn20, "Comment")
+
+ //@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20)
+}
+
+func newFunction() {
+ a := 1
+
+ _ = 3 + 4
+}
+
+-- functionextraction_extract_basic_comment_5_5 --
+package extract
+
+func _() {
+ a := /* comment in the middle of a line */ 1 //@mark(exSt18, "a")
+ // Comment on its own line //@mark(exSt19, "Comment")
+ newFunction() //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_")
+ // Comment right after 3 + 4
+
+ // Comment after with space //@mark(exEn20, "Comment")
+
+ //@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20)
+}
+
+func newFunction() {
+ _ = 3 + 4
+}
+
+-- functionextraction_extract_basic_comment_6_2 --
+package extract
+
+func _() {
+ a := /* comment in the middle of a line */ 1 //@mark(exSt18, "a")
+ // Comment on its own line //@mark(exSt19, "Comment")
+ newFunction() //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_")
+ // Comment right after 3 + 4
+
+ // Comment after with space //@mark(exEn20, "Comment")
+
+ //@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20)
+}
+
+func newFunction() {
+ _ = 3 + 4
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go
new file mode 100644
index 000000000..9713b9101
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go
@@ -0,0 +1,13 @@
+package extract
+
+import "fmt"
+
+func main() {
+ x := []rune{} //@mark(exSt9, "x")
+ s := "HELLO"
+ for _, c := range s {
+ x = append(x, c)
+ } //@mark(exEn9, "}")
+ //@extractfunc(exSt9, exEn9)
+ fmt.Printf("%x\n", x)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden
new file mode 100644
index 000000000..3198c9fa2
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden
@@ -0,0 +1,21 @@
+-- functionextraction_extract_issue_44813_6_2 --
+package extract
+
+import "fmt"
+
+func main() {
+ //@mark(exSt9, "x")
+ x := newFunction() //@mark(exEn9, "}")
+ //@extractfunc(exSt9, exEn9)
+ fmt.Printf("%x\n", x)
+}
+
+func newFunction() []rune {
+ x := []rune{}
+ s := "HELLO"
+ for _, c := range s {
+ x = append(x, c)
+ }
+ return x
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go
new file mode 100644
index 000000000..604f4757c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go
@@ -0,0 +1,11 @@
+package extract
+
+import "strconv"
+
+func _() {
+ i, err := strconv.Atoi("1")
+ u, err := strconv.Atoi("2") //@extractfunc("u", ")")
+ if i == u || err == nil {
+ return
+ }
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden
new file mode 100644
index 000000000..e2ee217d1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden
@@ -0,0 +1,18 @@
+-- functionextraction_extract_redefine_7_2 --
+package extract
+
+import "strconv"
+
+func _() {
+ i, err := strconv.Atoi("1")
+ u, err := newFunction() //@extractfunc("u", ")")
+ if i == u || err == nil {
+ return
+ }
+}
+
+func newFunction() (int, error) {
+ u, err := strconv.Atoi("2")
+ return u, err
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go
new file mode 100644
index 000000000..1ff24daeb
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go
@@ -0,0 +1,10 @@
+package extract
+
+func _() bool {
+ x := 1
+ if x == 0 { //@mark(exSt2, "if")
+ return true
+ } //@mark(exEn2, "}")
+ return false
+ //@extractfunc(exSt2, exEn2)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden
new file mode 100644
index 000000000..6103d1ee9
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden
@@ -0,0 +1,21 @@
+-- functionextraction_extract_return_basic_5_2 --
+package extract
+
+func _() bool {
+ x := 1
+ //@mark(exSt2, "if")
+ shouldReturn, returnValue := newFunction(x)
+ if shouldReturn {
+ return returnValue
+ } //@mark(exEn2, "}")
+ return false
+ //@extractfunc(exSt2, exEn2)
+}
+
+func newFunction(x int) (bool, bool) {
+ if x == 0 {
+ return true, true
+ }
+ return false, false
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go
new file mode 100644
index 000000000..08573acdd
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go
@@ -0,0 +1,10 @@
+package extract
+
+func _() bool {
+ x := 1 //@mark(exSt13, "x")
+ if x == 0 {
+ return true
+ }
+ return false //@mark(exEn13, "false")
+ //@extractfunc(exSt13, exEn13)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden
new file mode 100644
index 000000000..19e48da01
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden
@@ -0,0 +1,17 @@
+-- functionextraction_extract_return_basic_nonnested_4_2 --
+package extract
+
+func _() bool {
+ //@mark(exSt13, "x")
+ return newFunction() //@mark(exEn13, "false")
+ //@extractfunc(exSt13, exEn13)
+}
+
+func newFunction() bool {
+ x := 1
+ if x == 0 {
+ return true
+ }
+ return false
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go
new file mode 100644
index 000000000..605c5ec2e
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go
@@ -0,0 +1,17 @@
+package extract
+
+import "fmt"
+
+func _() (int, string, error) {
+ x := 1
+ y := "hello"
+ z := "bye" //@mark(exSt3, "z")
+ if y == z {
+ return x, y, fmt.Errorf("same")
+ } else {
+ z = "hi"
+ return x, z, nil
+ } //@mark(exEn3, "}")
+ return x, z, nil
+ //@extractfunc(exSt3, exEn3)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden
new file mode 100644
index 000000000..4d201227a
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden
@@ -0,0 +1,28 @@
+-- functionextraction_extract_return_complex_8_2 --
+package extract
+
+import "fmt"
+
+func _() (int, string, error) {
+ x := 1
+ y := "hello"
+ //@mark(exSt3, "z")
+ z, shouldReturn, returnValue, returnValue1, returnValue2 := newFunction(y, x)
+ if shouldReturn {
+ return returnValue, returnValue1, returnValue2
+ } //@mark(exEn3, "}")
+ return x, z, nil
+ //@extractfunc(exSt3, exEn3)
+}
+
+func newFunction(y string, x int) (string, bool, int, string, error) {
+ z := "bye"
+ if y == z {
+ return "", true, x, y, fmt.Errorf("same")
+ } else {
+ z = "hi"
+ return "", true, x, z, nil
+ }
+ return z, false, 0, "", nil
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go
new file mode 100644
index 000000000..6b2a4d8c0
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go
@@ -0,0 +1,17 @@
+package extract
+
+import "fmt"
+
+func _() (int, string, error) {
+ x := 1
+ y := "hello"
+ z := "bye" //@mark(exSt10, "z")
+ if y == z {
+ return x, y, fmt.Errorf("same")
+ } else {
+ z = "hi"
+ return x, z, nil
+ }
+ return x, z, nil //@mark(exEn10, "nil")
+ //@extractfunc(exSt10, exEn10)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden
new file mode 100644
index 000000000..de54b1534
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden
@@ -0,0 +1,24 @@
+-- functionextraction_extract_return_complex_nonnested_8_2 --
+package extract
+
+import "fmt"
+
+func _() (int, string, error) {
+ x := 1
+ y := "hello"
+ //@mark(exSt10, "z")
+ return newFunction(y, x) //@mark(exEn10, "nil")
+ //@extractfunc(exSt10, exEn10)
+}
+
+func newFunction(y string, x int) (int, string, error) {
+ z := "bye"
+ if y == z {
+ return x, y, fmt.Errorf("same")
+ } else {
+ z = "hi"
+ return x, z, nil
+ }
+ return x, z, nil
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go
new file mode 100644
index 000000000..b3fb4fd21
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go
@@ -0,0 +1,13 @@
+package extract
+
+import "go/ast"
+
+func _() {
+ ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool {
+ if n == nil { //@mark(exSt4, "if")
+ return true
+ } //@mark(exEn4, "}")
+ return false
+ })
+ //@extractfunc(exSt4, exEn4)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden
new file mode 100644
index 000000000..3af747c22
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden
@@ -0,0 +1,24 @@
+-- functionextraction_extract_return_func_lit_7_3 --
+package extract
+
+import "go/ast"
+
+func _() {
+ ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool {
+ //@mark(exSt4, "if")
+ shouldReturn, returnValue := newFunction(n)
+ if shouldReturn {
+ return returnValue
+ } //@mark(exEn4, "}")
+ return false
+ })
+ //@extractfunc(exSt4, exEn4)
+}
+
+func newFunction(n ast.Node) (bool, bool) {
+ if n == nil {
+ return true, true
+ }
+ return false, false
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go
new file mode 100644
index 000000000..c22db2a6d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go
@@ -0,0 +1,13 @@
+package extract
+
+import "go/ast"
+
+func _() {
+ ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool {
+ if n == nil { //@mark(exSt11, "if")
+ return true
+ }
+ return false //@mark(exEn11, "false")
+ })
+ //@extractfunc(exSt11, exEn11)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden
new file mode 100644
index 000000000..efa22ba2b
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden
@@ -0,0 +1,20 @@
+-- functionextraction_extract_return_func_lit_nonnested_7_3 --
+package extract
+
+import "go/ast"
+
+func _() {
+ ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool {
+ //@mark(exSt11, "if")
+ return newFunction(n) //@mark(exEn11, "false")
+ })
+ //@extractfunc(exSt11, exEn11)
+}
+
+func newFunction(n ast.Node) bool {
+ if n == nil {
+ return true
+ }
+ return false
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go
new file mode 100644
index 000000000..c1994c1c1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go
@@ -0,0 +1,12 @@
+package extract
+
+func _() string {
+ x := 1
+ if x == 0 { //@mark(exSt5, "if")
+ x = 3
+ return "a"
+ } //@mark(exEn5, "}")
+ x = 2
+ return "b"
+ //@extractfunc(exSt5, exEn5)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden
new file mode 100644
index 000000000..31d1b2ddf
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden
@@ -0,0 +1,23 @@
+-- functionextraction_extract_return_init_5_2 --
+package extract
+
+func _() string {
+ x := 1
+ //@mark(exSt5, "if")
+ shouldReturn, returnValue := newFunction(x)
+ if shouldReturn {
+ return returnValue
+ } //@mark(exEn5, "}")
+ x = 2
+ return "b"
+ //@extractfunc(exSt5, exEn5)
+}
+
+func newFunction(x int) (bool, string) {
+ if x == 0 {
+ x = 3
+ return true, "a"
+ }
+ return false, ""
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go
new file mode 100644
index 000000000..bb5ed083c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go
@@ -0,0 +1,12 @@
+package extract
+
+func _() string {
+ x := 1
+ if x == 0 { //@mark(exSt12, "if")
+ x = 3
+ return "a"
+ }
+ x = 2
+ return "b" //@mark(exEn12, "\"b\"")
+ //@extractfunc(exSt12, exEn12)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden
new file mode 100644
index 000000000..58bb57325
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden
@@ -0,0 +1,19 @@
+-- functionextraction_extract_return_init_nonnested_5_2 --
+package extract
+
+func _() string {
+ x := 1
+ //@mark(exSt12, "if")
+ return newFunction(x) //@mark(exEn12, "\"b\"")
+ //@extractfunc(exSt12, exEn12)
+}
+
+func newFunction(x int) string {
+ if x == 0 {
+ x = 3
+ return "a"
+ }
+ x = 2
+ return "b"
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go
new file mode 100644
index 000000000..6cc141fd1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go
@@ -0,0 +1,10 @@
+package extract
+
+func _() {
+ newFunction := 1
+ a := newFunction //@extractfunc("a", "newFunction")
+}
+
+func newFunction1() int {
+ return 1
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden
new file mode 100644
index 000000000..a4803b4fe
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden
@@ -0,0 +1,16 @@
+-- functionextraction_extract_scope_5_2 --
+package extract
+
+func _() {
+ newFunction := 1
+ newFunction2(newFunction) //@extractfunc("a", "newFunction")
+}
+
+func newFunction2(newFunction int) {
+ a := newFunction
+}
+
+func newFunction1() int {
+ return 1
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go
new file mode 100644
index 000000000..da2c669a8
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go
@@ -0,0 +1,9 @@
+package extract
+
+func _() {
+ var a []int
+ a = append(a, 2) //@mark(exSt6, "a")
+ b := 4 //@mark(exEn6, "4")
+ //@extractfunc(exSt6, exEn6)
+ a = append(a, b)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden
new file mode 100644
index 000000000..8be5040c4
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden
@@ -0,0 +1,17 @@
+-- functionextraction_extract_smart_initialization_5_2 --
+package extract
+
+func _() {
+ var a []int
+ //@mark(exSt6, "a")
+ a, b := newFunction(a) //@mark(exEn6, "4")
+ //@extractfunc(exSt6, exEn6)
+ a = append(a, b)
+}
+
+func newFunction(a []int) ([]int, int) {
+ a = append(a, 2)
+ b := 4
+ return a, b
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go
new file mode 100644
index 000000000..264d680e2
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go
@@ -0,0 +1,11 @@
+package extract
+
+func _() {
+ var b []int
+ var a int
+ a = 2 //@mark(exSt7, "a")
+ b = []int{}
+ b = append(b, a) //@mark(exEn7, ")")
+ b[0] = 1
+ //@extractfunc(exSt7, exEn7)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden
new file mode 100644
index 000000000..fdf55ae6d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden
@@ -0,0 +1,19 @@
+-- functionextraction_extract_smart_return_6_2 --
+package extract
+
+func _() {
+ var b []int
+ var a int
+ //@mark(exSt7, "a")
+ b = newFunction(a, b) //@mark(exEn7, ")")
+ b[0] = 1
+ //@extractfunc(exSt7, exEn7)
+}
+
+func newFunction(a int, b []int) []int {
+ a = 2
+ b = []int{}
+ b = append(b, a)
+ return b
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go
new file mode 100644
index 000000000..a6eb1f872
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go
@@ -0,0 +1,14 @@
+package extract
+
+func _() {
+ var b []int
+ var a int
+ a := 2 //@mark(exSt8, "a")
+ b = []int{}
+ b = append(b, a) //@mark(exEn8, ")")
+ b[0] = 1
+ if a == 2 {
+ return
+ }
+ //@extractfunc(exSt8, exEn8)
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden
new file mode 100644
index 000000000..4374f3728
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden
@@ -0,0 +1,22 @@
+-- functionextraction_extract_unnecessary_param_6_2 --
+package extract
+
+func _() {
+ var b []int
+ var a int
+ //@mark(exSt8, "a")
+ a, b = newFunction(b) //@mark(exEn8, ")")
+ b[0] = 1
+ if a == 2 {
+ return
+ }
+ //@extractfunc(exSt8, exEn8)
+}
+
+func newFunction(b []int) (int, []int) {
+ a := 2
+ b = []int{}
+ b = append(b, a)
+ return a, b
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go
new file mode 100644
index 000000000..c9a8d9dce
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go
@@ -0,0 +1,24 @@
+package extract
+
+type A struct {
+ x int
+ y int
+}
+
+func (a *A) XLessThanYP() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a *A) AddP() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func (a A) XLessThanY() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a A) Add() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden
new file mode 100644
index 000000000..3310d973e
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden
@@ -0,0 +1,364 @@
+-- functionextraction_extract_basic_13_2 --
+package extract
+
+type A struct {
+ x int
+ y int
+}
+
+func (a *A) XLessThanYP() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a *A) AddP() int {
+ sum := newFunction(a) //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func newFunction(a *A) int {
+ sum := a.x + a.y
+ return sum
+}
+
+func (a A) XLessThanY() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a A) Add() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+-- functionextraction_extract_basic_14_2 --
+package extract
+
+type A struct {
+ x int
+ y int
+}
+
+func (a *A) XLessThanYP() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a *A) AddP() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return newFunction(sum) //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func newFunction(sum int) int {
+ return sum
+}
+
+func (a A) XLessThanY() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a A) Add() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+-- functionextraction_extract_basic_18_2 --
+package extract
+
+type A struct {
+ x int
+ y int
+}
+
+func (a *A) XLessThanYP() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a *A) AddP() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func (a A) XLessThanY() bool {
+ return newFunction(a) //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func newFunction(a A) bool {
+ return a.x < a.y
+}
+
+func (a A) Add() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+-- functionextraction_extract_basic_22_2 --
+package extract
+
+type A struct {
+ x int
+ y int
+}
+
+func (a *A) XLessThanYP() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a *A) AddP() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func (a A) XLessThanY() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a A) Add() int {
+ sum := newFunction(a) //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func newFunction(a A) int {
+ sum := a.x + a.y
+ return sum
+}
+
+-- functionextraction_extract_basic_23_2 --
+package extract
+
+type A struct {
+ x int
+ y int
+}
+
+func (a *A) XLessThanYP() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a *A) AddP() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func (a A) XLessThanY() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a A) Add() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return newFunction(sum) //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func newFunction(sum int) int {
+ return sum
+}
+
+-- functionextraction_extract_basic_9_2 --
+package extract
+
+type A struct {
+ x int
+ y int
+}
+
+func (a *A) XLessThanYP() bool {
+ return newFunction(a) //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func newFunction(a *A) bool {
+ return a.x < a.y
+}
+
+func (a *A) AddP() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func (a A) XLessThanY() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a A) Add() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+-- methodextraction_extract_basic_13_2 --
+package extract
+
+type A struct {
+ x int
+ y int
+}
+
+func (a *A) XLessThanYP() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a *A) AddP() int {
+ sum := a.newMethod() //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func (a *A) newMethod() int {
+ sum := a.x + a.y
+ return sum
+}
+
+func (a A) XLessThanY() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a A) Add() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+-- methodextraction_extract_basic_14_2 --
+package extract
+
+type A struct {
+ x int
+ y int
+}
+
+func (a *A) XLessThanYP() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a *A) AddP() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return a.newMethod(sum) //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func (*A) newMethod(sum int) int {
+ return sum
+}
+
+func (a A) XLessThanY() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a A) Add() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+-- methodextraction_extract_basic_18_2 --
+package extract
+
+type A struct {
+ x int
+ y int
+}
+
+func (a *A) XLessThanYP() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a *A) AddP() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func (a A) XLessThanY() bool {
+ return a.newMethod() //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a A) newMethod() bool {
+ return a.x < a.y
+}
+
+func (a A) Add() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+-- methodextraction_extract_basic_22_2 --
+package extract
+
+type A struct {
+ x int
+ y int
+}
+
+func (a *A) XLessThanYP() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a *A) AddP() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func (a A) XLessThanY() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a A) Add() int {
+ sum := a.newMethod() //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func (a A) newMethod() int {
+ sum := a.x + a.y
+ return sum
+}
+
+-- methodextraction_extract_basic_23_2 --
+package extract
+
+type A struct {
+ x int
+ y int
+}
+
+func (a *A) XLessThanYP() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a *A) AddP() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func (a A) XLessThanY() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a A) Add() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return a.newMethod(sum) //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func (A) newMethod(sum int) int {
+ return sum
+}
+
+-- methodextraction_extract_basic_9_2 --
+package extract
+
+type A struct {
+ x int
+ y int
+}
+
+func (a *A) XLessThanYP() bool {
+ return a.newMethod() //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a *A) newMethod() bool {
+ return a.x < a.y
+}
+
+func (a *A) AddP() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
+func (a A) XLessThanY() bool {
+ return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y")
+}
+
+func (a A) Add() int {
+ sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y")
+ return sum //@extractmethod("return", "sum"),extractfunc("return", "sum")
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go
new file mode 100644
index 000000000..cbb70a04c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go
@@ -0,0 +1,6 @@
+package extract
+
+func _() {
+ var _ = 1 + 2 //@suggestedfix("1", "refactor.extract", "")
+ var _ = 3 + 4 //@suggestedfix("3 + 4", "refactor.extract", "")
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden
new file mode 100644
index 000000000..3fd9b3287
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden
@@ -0,0 +1,18 @@
+-- suggestedfix_extract_basic_lit_4_10 --
+package extract
+
+func _() {
+ x := 1
+ var _ = x + 2 //@suggestedfix("1", "refactor.extract", "")
+ var _ = 3 + 4 //@suggestedfix("3 + 4", "refactor.extract", "")
+}
+
+-- suggestedfix_extract_basic_lit_5_10 --
+package extract
+
+func _() {
+ var _ = 1 + 2 //@suggestedfix("1", "refactor.extract", "")
+ x := 3 + 4
+ var _ = x //@suggestedfix("3 + 4", "refactor.extract", "")
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go
new file mode 100644
index 000000000..a20b45f58
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go
@@ -0,0 +1,9 @@
+package extract
+
+import "strconv"
+
+func _() {
+ x0 := append([]int{}, 1) //@suggestedfix("append([]int{}, 1)", "refactor.extract", "")
+ str := "1"
+ b, err := strconv.Atoi(str) //@suggestedfix("strconv.Atoi(str)", "refactor.extract", "")
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden
new file mode 100644
index 000000000..d59c0ee99
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden
@@ -0,0 +1,24 @@
+-- suggestedfix_extract_func_call_6_8 --
+package extract
+
+import "strconv"
+
+func _() {
+ x := append([]int{}, 1)
+ x0 := x //@suggestedfix("append([]int{}, 1)", "refactor.extract", "")
+ str := "1"
+ b, err := strconv.Atoi(str) //@suggestedfix("strconv.Atoi(str)", "refactor.extract", "")
+}
+
+-- suggestedfix_extract_func_call_8_12 --
+package extract
+
+import "strconv"
+
+func _() {
+ x0 := append([]int{}, 1) //@suggestedfix("append([]int{}, 1)", "refactor.extract", "")
+ str := "1"
+ x, x1 := strconv.Atoi(str)
+ b, err := x, x1 //@suggestedfix("strconv.Atoi(str)", "refactor.extract", "")
+}
+
diff --git a/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go
new file mode 100644
index 000000000..c14ad7092
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go
@@ -0,0 +1,13 @@
+package extract
+
+import "go/ast"
+
+func _() {
+ x0 := 0
+ if true {
+ y := ast.CompositeLit{} //@suggestedfix("ast.CompositeLit{}", "refactor.extract", "")
+ }
+ if true {
+ x1 := !false //@suggestedfix("!false", "refactor.extract", "")
+ }
+}
diff --git a/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden
new file mode 100644
index 000000000..1c2f64b7d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden
@@ -0,0 +1,32 @@
+-- suggestedfix_extract_scope_11_9 --
+package extract
+
+import "go/ast"
+
+func _() {
+ x0 := 0
+ if true {
+ y := ast.CompositeLit{} //@suggestedfix("ast.CompositeLit{}", "refactor.extract", "")
+ }
+ if true {
+ x := !false
+ x1 := x //@suggestedfix("!false", "refactor.extract", "")
+ }
+}
+
+-- suggestedfix_extract_scope_8_8 --
+package extract
+
+import "go/ast"
+
+func _() {
+ x0 := 0
+ if true {
+ x := ast.CompositeLit{}
+ y := x //@suggestedfix("ast.CompositeLit{}", "refactor.extract", "")
+ }
+ if true {
+ x1 := !false //@suggestedfix("!false", "refactor.extract", "")
+ }
+}
+
diff --git a/gopls/internal/lsp/testdata/fieldlist/field_list.go b/gopls/internal/lsp/testdata/fieldlist/field_list.go
new file mode 100644
index 000000000..e687defb1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fieldlist/field_list.go
@@ -0,0 +1,27 @@
+package fieldlist
+
+var myInt int //@item(flVar, "myInt", "int", "var")
+type myType int //@item(flType, "myType", "int", "type")
+
+func (my) _() {} //@complete(") _", flType)
+func (my my) _() {} //@complete(" my)"),complete(") _", flType)
+
+func (myType) _() {} //@complete(") {", flType)
+
+func (myType) _(my my) {} //@complete(" my)"),complete(") {", flType)
+
+func (myType) _() my {} //@complete(" {", flType)
+
+func (myType) _() (my my) {} //@complete(" my"),complete(") {", flType)
+
+func _() {
+ var _ struct {
+ //@complete("", flType)
+ m my //@complete(" my"),complete(" //", flType)
+ }
+
+ var _ interface {
+ //@complete("", flType)
+ m() my //@complete("("),complete(" //", flType)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/fillstruct/a.go b/gopls/internal/lsp/testdata/fillstruct/a.go
new file mode 100644
index 000000000..e1add2d47
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/a.go
@@ -0,0 +1,27 @@
+package fillstruct
+
+import (
+ "golang.org/lsptests/fillstruct/data"
+)
+
+type basicStruct struct {
+ foo int
+}
+
+var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type twoArgStruct struct {
+ foo int
+ bar string
+}
+
+var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type nestedStruct struct {
+ bar string
+ basic basicStruct
+}
+
+var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill")
diff --git a/gopls/internal/lsp/testdata/fillstruct/a.go.golden b/gopls/internal/lsp/testdata/fillstruct/a.go.golden
new file mode 100644
index 000000000..ca1db04ea
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/a.go.golden
@@ -0,0 +1,126 @@
+-- suggestedfix_a_11_21 --
+package fillstruct
+
+import (
+ "golang.org/lsptests/fillstruct/data"
+)
+
+type basicStruct struct {
+ foo int
+}
+
+var _ = basicStruct{
+ foo: 0,
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type twoArgStruct struct {
+ foo int
+ bar string
+}
+
+var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type nestedStruct struct {
+ bar string
+ basic basicStruct
+}
+
+var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+-- suggestedfix_a_18_22 --
+package fillstruct
+
+import (
+ "golang.org/lsptests/fillstruct/data"
+)
+
+type basicStruct struct {
+ foo int
+}
+
+var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type twoArgStruct struct {
+ foo int
+ bar string
+}
+
+var _ = twoArgStruct{
+ foo: 0,
+ bar: "",
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type nestedStruct struct {
+ bar string
+ basic basicStruct
+}
+
+var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+-- suggestedfix_a_25_22 --
+package fillstruct
+
+import (
+ "golang.org/lsptests/fillstruct/data"
+)
+
+type basicStruct struct {
+ foo int
+}
+
+var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type twoArgStruct struct {
+ foo int
+ bar string
+}
+
+var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type nestedStruct struct {
+ bar string
+ basic basicStruct
+}
+
+var _ = nestedStruct{
+ bar: "",
+ basic: basicStruct{},
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+-- suggestedfix_a_27_16 --
+package fillstruct
+
+import (
+ "golang.org/lsptests/fillstruct/data"
+)
+
+type basicStruct struct {
+ foo int
+}
+
+var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type twoArgStruct struct {
+ foo int
+ bar string
+}
+
+var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type nestedStruct struct {
+ bar string
+ basic basicStruct
+}
+
+var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = data.B{
+ ExportedInt: 0,
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
diff --git a/gopls/internal/lsp/testdata/fillstruct/a2.go b/gopls/internal/lsp/testdata/fillstruct/a2.go
new file mode 100644
index 000000000..b5e30a84f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/a2.go
@@ -0,0 +1,29 @@
+package fillstruct
+
+type typedStruct struct {
+ m map[string]int
+ s []int
+ c chan int
+ c1 <-chan int
+ a [2]string
+}
+
+var _ = typedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStruct struct {
+ fn func(i int) int
+}
+
+var _ = funStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStructCompex struct {
+ fn func(i int, s string) (string, int)
+}
+
+var _ = funStructCompex{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStructEmpty struct {
+ fn func()
+}
+
+var _ = funStructEmpty{} //@suggestedfix("}", "refactor.rewrite", "Fill")
diff --git a/gopls/internal/lsp/testdata/fillstruct/a2.go.golden b/gopls/internal/lsp/testdata/fillstruct/a2.go.golden
new file mode 100644
index 000000000..2eca3e349
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/a2.go.golden
@@ -0,0 +1,139 @@
+-- suggestedfix_a2_11_21 --
+package fillstruct
+
+type typedStruct struct {
+ m map[string]int
+ s []int
+ c chan int
+ c1 <-chan int
+ a [2]string
+}
+
+var _ = typedStruct{
+ m: map[string]int{},
+ s: []int{},
+ c: make(chan int),
+ c1: make(<-chan int),
+ a: [2]string{},
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStruct struct {
+ fn func(i int) int
+}
+
+var _ = funStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStructCompex struct {
+ fn func(i int, s string) (string, int)
+}
+
+var _ = funStructCompex{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStructEmpty struct {
+ fn func()
+}
+
+var _ = funStructEmpty{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+-- suggestedfix_a2_17_19 --
+package fillstruct
+
+type typedStruct struct {
+ m map[string]int
+ s []int
+ c chan int
+ c1 <-chan int
+ a [2]string
+}
+
+var _ = typedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStruct struct {
+ fn func(i int) int
+}
+
+var _ = funStruct{
+ fn: func(i int) int {
+ },
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStructCompex struct {
+ fn func(i int, s string) (string, int)
+}
+
+var _ = funStructCompex{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStructEmpty struct {
+ fn func()
+}
+
+var _ = funStructEmpty{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+-- suggestedfix_a2_23_25 --
+package fillstruct
+
+type typedStruct struct {
+ m map[string]int
+ s []int
+ c chan int
+ c1 <-chan int
+ a [2]string
+}
+
+var _ = typedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStruct struct {
+ fn func(i int) int
+}
+
+var _ = funStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStructCompex struct {
+ fn func(i int, s string) (string, int)
+}
+
+var _ = funStructCompex{
+ fn: func(i int, s string) (string, int) {
+ },
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStructEmpty struct {
+ fn func()
+}
+
+var _ = funStructEmpty{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+-- suggestedfix_a2_29_24 --
+package fillstruct
+
+type typedStruct struct {
+ m map[string]int
+ s []int
+ c chan int
+ c1 <-chan int
+ a [2]string
+}
+
+var _ = typedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStruct struct {
+ fn func(i int) int
+}
+
+var _ = funStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStructCompex struct {
+ fn func(i int, s string) (string, int)
+}
+
+var _ = funStructCompex{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type funStructEmpty struct {
+ fn func()
+}
+
+var _ = funStructEmpty{
+ fn: func() {
+ },
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
diff --git a/gopls/internal/lsp/testdata/fillstruct/a3.go b/gopls/internal/lsp/testdata/fillstruct/a3.go
new file mode 100644
index 000000000..59cd9fa28
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/a3.go
@@ -0,0 +1,42 @@
+package fillstruct
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+type Foo struct {
+ A int
+}
+
+type Bar struct {
+ X *Foo
+ Y *Foo
+}
+
+var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type importedStruct struct {
+ m map[*ast.CompositeLit]ast.Field
+ s []ast.BadExpr
+ a [3]token.Token
+ c chan ast.EmptyStmt
+ fn func(ast_decl ast.DeclStmt) ast.Ellipsis
+ st ast.CompositeLit
+}
+
+var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type pointerBuiltinStruct struct {
+ b *bool
+ s *string
+ i *int
+}
+
+var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = []ast.BasicLit{
+ {}, //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill")
diff --git a/gopls/internal/lsp/testdata/fillstruct/a3.go.golden b/gopls/internal/lsp/testdata/fillstruct/a3.go.golden
new file mode 100644
index 000000000..a7c7baa8d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/a3.go.golden
@@ -0,0 +1,243 @@
+-- suggestedfix_a3_17_13 --
+package fillstruct
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+type Foo struct {
+ A int
+}
+
+type Bar struct {
+ X *Foo
+ Y *Foo
+}
+
+var _ = Bar{
+ X: &Foo{},
+ Y: &Foo{},
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type importedStruct struct {
+ m map[*ast.CompositeLit]ast.Field
+ s []ast.BadExpr
+ a [3]token.Token
+ c chan ast.EmptyStmt
+ fn func(ast_decl ast.DeclStmt) ast.Ellipsis
+ st ast.CompositeLit
+}
+
+var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type pointerBuiltinStruct struct {
+ b *bool
+ s *string
+ i *int
+}
+
+var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = []ast.BasicLit{
+ {}, //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+-- suggestedfix_a3_28_24 --
+package fillstruct
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+type Foo struct {
+ A int
+}
+
+type Bar struct {
+ X *Foo
+ Y *Foo
+}
+
+var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type importedStruct struct {
+ m map[*ast.CompositeLit]ast.Field
+ s []ast.BadExpr
+ a [3]token.Token
+ c chan ast.EmptyStmt
+ fn func(ast_decl ast.DeclStmt) ast.Ellipsis
+ st ast.CompositeLit
+}
+
+var _ = importedStruct{
+ m: map[*ast.CompositeLit]ast.Field{},
+ s: []ast.BadExpr{},
+ a: [3]token.Token{},
+ c: make(chan ast.EmptyStmt),
+ fn: func(ast_decl ast.DeclStmt) ast.Ellipsis {
+ },
+ st: ast.CompositeLit{},
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type pointerBuiltinStruct struct {
+ b *bool
+ s *string
+ i *int
+}
+
+var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = []ast.BasicLit{
+ {}, //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+-- suggestedfix_a3_36_30 --
+package fillstruct
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+type Foo struct {
+ A int
+}
+
+type Bar struct {
+ X *Foo
+ Y *Foo
+}
+
+var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type importedStruct struct {
+ m map[*ast.CompositeLit]ast.Field
+ s []ast.BadExpr
+ a [3]token.Token
+ c chan ast.EmptyStmt
+ fn func(ast_decl ast.DeclStmt) ast.Ellipsis
+ st ast.CompositeLit
+}
+
+var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type pointerBuiltinStruct struct {
+ b *bool
+ s *string
+ i *int
+}
+
+var _ = pointerBuiltinStruct{
+ b: new(bool),
+ s: new(string),
+ i: new(int),
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = []ast.BasicLit{
+ {}, //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+-- suggestedfix_a3_39_3 --
+package fillstruct
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+type Foo struct {
+ A int
+}
+
+type Bar struct {
+ X *Foo
+ Y *Foo
+}
+
+var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type importedStruct struct {
+ m map[*ast.CompositeLit]ast.Field
+ s []ast.BadExpr
+ a [3]token.Token
+ c chan ast.EmptyStmt
+ fn func(ast_decl ast.DeclStmt) ast.Ellipsis
+ st ast.CompositeLit
+}
+
+var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type pointerBuiltinStruct struct {
+ b *bool
+ s *string
+ i *int
+}
+
+var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = []ast.BasicLit{
+ {
+ ValuePos: 0,
+ Kind: 0,
+ Value: "",
+ }, //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+-- suggestedfix_a3_42_25 --
+package fillstruct
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+type Foo struct {
+ A int
+}
+
+type Bar struct {
+ X *Foo
+ Y *Foo
+}
+
+var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type importedStruct struct {
+ m map[*ast.CompositeLit]ast.Field
+ s []ast.BadExpr
+ a [3]token.Token
+ c chan ast.EmptyStmt
+ fn func(ast_decl ast.DeclStmt) ast.Ellipsis
+ st ast.CompositeLit
+}
+
+var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type pointerBuiltinStruct struct {
+ b *bool
+ s *string
+ i *int
+}
+
+var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = []ast.BasicLit{
+ {}, //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+var _ = []ast.BasicLit{{
+ ValuePos: 0,
+ Kind: 0,
+ Value: "",
+}} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
diff --git a/gopls/internal/lsp/testdata/fillstruct/a4.go b/gopls/internal/lsp/testdata/fillstruct/a4.go
new file mode 100644
index 000000000..5f52a55fa
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/a4.go
@@ -0,0 +1,39 @@
+package fillstruct
+
+import "go/ast"
+
+type iStruct struct {
+ X int
+}
+
+type sStruct struct {
+ str string
+}
+
+type multiFill struct {
+ num int
+ strin string
+ arr []int
+}
+
+type assignStruct struct {
+ n ast.Node
+}
+
+func fill() {
+ var x int
+ var _ = iStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var s string
+ var _ = sStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var n int
+ _ = []int{}
+ if true {
+ arr := []int{1, 2}
+ }
+ var _ = multiFill{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var node *ast.CompositeLit
+ var _ = assignStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
diff --git a/gopls/internal/lsp/testdata/fillstruct/a4.go.golden b/gopls/internal/lsp/testdata/fillstruct/a4.go.golden
new file mode 100644
index 000000000..b1e376f05
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/a4.go.golden
@@ -0,0 +1,174 @@
+-- suggestedfix_a4_25_18 --
+package fillstruct
+
+import "go/ast"
+
+type iStruct struct {
+ X int
+}
+
+type sStruct struct {
+ str string
+}
+
+type multiFill struct {
+ num int
+ strin string
+ arr []int
+}
+
+type assignStruct struct {
+ n ast.Node
+}
+
+func fill() {
+ var x int
+ var _ = iStruct{
+ X: x,
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var s string
+ var _ = sStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var n int
+ _ = []int{}
+ if true {
+ arr := []int{1, 2}
+ }
+ var _ = multiFill{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var node *ast.CompositeLit
+ var _ = assignStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+-- suggestedfix_a4_28_18 --
+package fillstruct
+
+import "go/ast"
+
+type iStruct struct {
+ X int
+}
+
+type sStruct struct {
+ str string
+}
+
+type multiFill struct {
+ num int
+ strin string
+ arr []int
+}
+
+type assignStruct struct {
+ n ast.Node
+}
+
+func fill() {
+ var x int
+ var _ = iStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var s string
+ var _ = sStruct{
+ str: s,
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var n int
+ _ = []int{}
+ if true {
+ arr := []int{1, 2}
+ }
+ var _ = multiFill{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var node *ast.CompositeLit
+ var _ = assignStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+-- suggestedfix_a4_35_20 --
+package fillstruct
+
+import "go/ast"
+
+type iStruct struct {
+ X int
+}
+
+type sStruct struct {
+ str string
+}
+
+type multiFill struct {
+ num int
+ strin string
+ arr []int
+}
+
+type assignStruct struct {
+ n ast.Node
+}
+
+func fill() {
+ var x int
+ var _ = iStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var s string
+ var _ = sStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var n int
+ _ = []int{}
+ if true {
+ arr := []int{1, 2}
+ }
+ var _ = multiFill{
+ num: n,
+ strin: s,
+ arr: []int{},
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var node *ast.CompositeLit
+ var _ = assignStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+-- suggestedfix_a4_38_23 --
+package fillstruct
+
+import "go/ast"
+
+type iStruct struct {
+ X int
+}
+
+type sStruct struct {
+ str string
+}
+
+type multiFill struct {
+ num int
+ strin string
+ arr []int
+}
+
+type assignStruct struct {
+ n ast.Node
+}
+
+func fill() {
+ var x int
+ var _ = iStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var s string
+ var _ = sStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var n int
+ _ = []int{}
+ if true {
+ arr := []int{1, 2}
+ }
+ var _ = multiFill{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+ var node *ast.CompositeLit
+ var _ = assignStruct{
+ n: node,
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
diff --git a/gopls/internal/lsp/testdata/fillstruct/data/a.go b/gopls/internal/lsp/testdata/fillstruct/data/a.go
new file mode 100644
index 000000000..7ca37736b
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/data/a.go
@@ -0,0 +1,6 @@
+package data
+
+type B struct {
+ ExportedInt int
+ unexportedInt int
+}
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go
new file mode 100644
index 000000000..3da904741
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go
@@ -0,0 +1,26 @@
+package fillstruct
+
+type StructA struct {
+ unexportedIntField int
+ ExportedIntField int
+ MapA map[int]string
+ Array []int
+ StructB
+}
+
+type StructA2 struct {
+ B *StructB
+}
+
+type StructA3 struct {
+ B StructB
+}
+
+func fill() {
+ a := StructA{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ b := StructA2{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ c := StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ if true {
+ _ = StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ }
+}
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden
new file mode 100644
index 000000000..de01a40f0
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden
@@ -0,0 +1,124 @@
+-- suggestedfix_fill_struct_20_15 --
+package fillstruct
+
+type StructA struct {
+ unexportedIntField int
+ ExportedIntField int
+ MapA map[int]string
+ Array []int
+ StructB
+}
+
+type StructA2 struct {
+ B *StructB
+}
+
+type StructA3 struct {
+ B StructB
+}
+
+func fill() {
+ a := StructA{
+ unexportedIntField: 0,
+ ExportedIntField: 0,
+ MapA: map[int]string{},
+ Array: []int{},
+ StructB: StructB{},
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+ b := StructA2{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ c := StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ if true {
+ _ = StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ }
+}
+
+-- suggestedfix_fill_struct_21_16 --
+package fillstruct
+
+type StructA struct {
+ unexportedIntField int
+ ExportedIntField int
+ MapA map[int]string
+ Array []int
+ StructB
+}
+
+type StructA2 struct {
+ B *StructB
+}
+
+type StructA3 struct {
+ B StructB
+}
+
+func fill() {
+ a := StructA{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ b := StructA2{
+ B: &StructB{},
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+ c := StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ if true {
+ _ = StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ }
+}
+
+-- suggestedfix_fill_struct_22_16 --
+package fillstruct
+
+type StructA struct {
+ unexportedIntField int
+ ExportedIntField int
+ MapA map[int]string
+ Array []int
+ StructB
+}
+
+type StructA2 struct {
+ B *StructB
+}
+
+type StructA3 struct {
+ B StructB
+}
+
+func fill() {
+ a := StructA{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ b := StructA2{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ c := StructA3{
+ B: StructB{},
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+ if true {
+ _ = StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ }
+}
+
+-- suggestedfix_fill_struct_24_16 --
+package fillstruct
+
+type StructA struct {
+ unexportedIntField int
+ ExportedIntField int
+ MapA map[int]string
+ Array []int
+ StructB
+}
+
+type StructA2 struct {
+ B *StructB
+}
+
+type StructA3 struct {
+ B StructB
+}
+
+func fill() {
+ a := StructA{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ b := StructA2{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ c := StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ if true {
+ _ = StructA3{
+ B: StructB{},
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+ }
+}
+
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go
new file mode 100644
index 000000000..2c099a80e
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go
@@ -0,0 +1,14 @@
+package fillstruct
+
+type StructAnon struct {
+ a struct{}
+ b map[string]interface{}
+ c map[string]struct {
+ d int
+ e bool
+ }
+}
+
+func fill() {
+ _ := StructAnon{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden
new file mode 100644
index 000000000..7cc9ac23d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden
@@ -0,0 +1,20 @@
+-- suggestedfix_fill_struct_anon_13_18 --
+package fillstruct
+
+type StructAnon struct {
+ a struct{}
+ b map[string]interface{}
+ c map[string]struct {
+ d int
+ e bool
+ }
+}
+
+func fill() {
+ _ := StructAnon{
+ a: struct{}{},
+ b: map[string]interface{}{},
+ c: map[string]struct{d int; e bool}{},
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go
new file mode 100644
index 000000000..ab7be5a7b
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go
@@ -0,0 +1,15 @@
+package fillstruct
+
+type StructB struct {
+ StructC
+}
+
+type StructC struct {
+ unexportedInt int
+}
+
+func nested() {
+ c := StructB{
+ StructC: StructC{}, //@suggestedfix("}", "refactor.rewrite", "Fill")
+ }
+}
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden
new file mode 100644
index 000000000..c902ee7f1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden
@@ -0,0 +1,19 @@
+-- suggestedfix_fill_struct_nested_13_20 --
+package fillstruct
+
+type StructB struct {
+ StructC
+}
+
+type StructC struct {
+ unexportedInt int
+}
+
+func nested() {
+ c := StructB{
+ StructC: StructC{
+ unexportedInt: 0,
+ }, //@suggestedfix("}", "refactor.rewrite", "Fill")
+ }
+}
+
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go
new file mode 100644
index 000000000..ef35627c8
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go
@@ -0,0 +1,12 @@
+package fillstruct
+
+import (
+ h2 "net/http"
+
+ "golang.org/lsptests/fillstruct/data"
+)
+
+func unexported() {
+ a := data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ _ = h2.Client{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden
new file mode 100644
index 000000000..0cdbfc820
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden
@@ -0,0 +1,36 @@
+-- suggestedfix_fill_struct_package_10_14 --
+package fillstruct
+
+import (
+ h2 "net/http"
+
+ "golang.org/lsptests/fillstruct/data"
+)
+
+func unexported() {
+ a := data.B{
+ ExportedInt: 0,
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+ _ = h2.Client{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+-- suggestedfix_fill_struct_package_11_16 --
+package fillstruct
+
+import (
+ h2 "net/http"
+
+ "golang.org/lsptests/fillstruct/data"
+)
+
+func unexported() {
+ a := data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+ _ = h2.Client{
+ Transport: nil,
+ CheckRedirect: func(req *h2.Request, via []*h2.Request) error {
+ },
+ Jar: nil,
+ Timeout: 0,
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go
new file mode 100644
index 000000000..5de1722c7
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go
@@ -0,0 +1,24 @@
+package fillstruct
+
+type StructPartialA struct {
+ PrefilledInt int
+ UnfilledInt int
+ StructPartialB
+}
+
+type StructPartialB struct {
+ PrefilledInt int
+ UnfilledInt int
+}
+
+func fill() {
+ a := StructPartialA{
+ PrefilledInt: 5,
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+ b := StructPartialB{
+ /* this comment should disappear */
+ PrefilledInt: 7, // This comment should be blown away.
+ /* As should
+ this one */
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden
new file mode 100644
index 000000000..3aa437a03
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden
@@ -0,0 +1,52 @@
+-- suggestedfix_fill_struct_partial_17_2 --
+package fillstruct
+
+type StructPartialA struct {
+ PrefilledInt int
+ UnfilledInt int
+ StructPartialB
+}
+
+type StructPartialB struct {
+ PrefilledInt int
+ UnfilledInt int
+}
+
+func fill() {
+ a := StructPartialA{
+ PrefilledInt: 5,
+ UnfilledInt: 0,
+ StructPartialB: StructPartialB{},
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+ b := StructPartialB{
+ /* this comment should disappear */
+ PrefilledInt: 7, // This comment should be blown away.
+ /* As should
+ this one */
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+-- suggestedfix_fill_struct_partial_23_2 --
+package fillstruct
+
+type StructPartialA struct {
+ PrefilledInt int
+ UnfilledInt int
+ StructPartialB
+}
+
+type StructPartialB struct {
+ PrefilledInt int
+ UnfilledInt int
+}
+
+func fill() {
+ a := StructPartialA{
+ PrefilledInt: 5,
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+ b := StructPartialB{
+ PrefilledInt: 7,
+ UnfilledInt: 0,
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go
new file mode 100644
index 000000000..6a468cd54
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go
@@ -0,0 +1,9 @@
+package fillstruct
+
+type StructD struct {
+ ExportedIntField int
+}
+
+func spaces() {
+ d := StructD{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden
new file mode 100644
index 000000000..590c91611
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden
@@ -0,0 +1,13 @@
+-- suggestedfix_fill_struct_spaces_8_15 --
+package fillstruct
+
+type StructD struct {
+ ExportedIntField int
+}
+
+func spaces() {
+ d := StructD{
+ ExportedIntField: 0,
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go
new file mode 100644
index 000000000..f5e42a4f2
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go
@@ -0,0 +1,12 @@
+package fillstruct
+
+import "unsafe"
+
+type unsafeStruct struct {
+ x int
+ p unsafe.Pointer
+}
+
+func fill() {
+ _ := unsafeStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden
new file mode 100644
index 000000000..7e8e1952f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden
@@ -0,0 +1,17 @@
+-- suggestedfix_fill_struct_unsafe_11_20 --
+package fillstruct
+
+import "unsafe"
+
+type unsafeStruct struct {
+ x int
+ p unsafe.Pointer
+}
+
+func fill() {
+ _ := unsafeStruct{
+ x: 0,
+ p: nil,
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
diff --git a/gopls/internal/lsp/testdata/fillstruct/typeparams.go b/gopls/internal/lsp/testdata/fillstruct/typeparams.go
new file mode 100644
index 000000000..c0b702f57
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/typeparams.go
@@ -0,0 +1,37 @@
+//go:build go1.18
+// +build go1.18
+
+package fillstruct
+
+type emptyStructWithTypeParams[A any] struct{}
+
+var _ = emptyStructWithTypeParams[int]{} // no suggested fix
+
+type basicStructWithTypeParams[T any] struct {
+ foo T
+}
+
+var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type twoArgStructWithTypeParams[F, B any] struct {
+ foo F
+ bar B
+}
+
+var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = twoArgStructWithTypeParams[int, string]{
+ bar: "bar",
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type nestedStructWithTypeParams struct {
+ bar string
+ basic basicStructWithTypeParams[int]
+}
+
+var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+func _[T any]() {
+ type S struct{ t T }
+ _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
diff --git a/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden b/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden
new file mode 100644
index 000000000..625df7577
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden
@@ -0,0 +1,206 @@
+-- suggestedfix_typeparams_14_40 --
+//go:build go1.18
+// +build go1.18
+
+package fillstruct
+
+type emptyStructWithTypeParams[A any] struct{}
+
+var _ = emptyStructWithTypeParams[int]{} // no suggested fix
+
+type basicStructWithTypeParams[T any] struct {
+ foo T
+}
+
+var _ = basicStructWithTypeParams[int]{
+ foo: 0,
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type twoArgStructWithTypeParams[F, B any] struct {
+ foo F
+ bar B
+}
+
+var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = twoArgStructWithTypeParams[int, string]{
+ bar: "bar",
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type nestedStructWithTypeParams struct {
+ bar string
+ basic basicStructWithTypeParams[int]
+}
+
+var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+func _[T any]() {
+ type S struct{ t T }
+ _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+-- suggestedfix_typeparams_21_49 --
+//go:build go1.18
+// +build go1.18
+
+package fillstruct
+
+type emptyStructWithTypeParams[A any] struct{}
+
+var _ = emptyStructWithTypeParams[int]{} // no suggested fix
+
+type basicStructWithTypeParams[T any] struct {
+ foo T
+}
+
+var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type twoArgStructWithTypeParams[F, B any] struct {
+ foo F
+ bar B
+}
+
+var _ = twoArgStructWithTypeParams[string, int]{
+ foo: "",
+ bar: 0,
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = twoArgStructWithTypeParams[int, string]{
+ bar: "bar",
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type nestedStructWithTypeParams struct {
+ bar string
+ basic basicStructWithTypeParams[int]
+}
+
+var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+func _[T any]() {
+ type S struct{ t T }
+ _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+-- suggestedfix_typeparams_25_1 --
+//go:build go1.18
+// +build go1.18
+
+package fillstruct
+
+type emptyStructWithTypeParams[A any] struct{}
+
+var _ = emptyStructWithTypeParams[int]{} // no suggested fix
+
+type basicStructWithTypeParams[T any] struct {
+ foo T
+}
+
+var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type twoArgStructWithTypeParams[F, B any] struct {
+ foo F
+ bar B
+}
+
+var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = twoArgStructWithTypeParams[int, string]{
+ foo: 0,
+ bar: "bar",
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type nestedStructWithTypeParams struct {
+ bar string
+ basic basicStructWithTypeParams[int]
+}
+
+var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+func _[T any]() {
+ type S struct{ t T }
+ _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+-- suggestedfix_typeparams_32_36 --
+//go:build go1.18
+// +build go1.18
+
+package fillstruct
+
+type emptyStructWithTypeParams[A any] struct{}
+
+var _ = emptyStructWithTypeParams[int]{} // no suggested fix
+
+type basicStructWithTypeParams[T any] struct {
+ foo T
+}
+
+var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type twoArgStructWithTypeParams[F, B any] struct {
+ foo F
+ bar B
+}
+
+var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = twoArgStructWithTypeParams[int, string]{
+ bar: "bar",
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type nestedStructWithTypeParams struct {
+ bar string
+ basic basicStructWithTypeParams[int]
+}
+
+var _ = nestedStructWithTypeParams{
+ bar: "",
+ basic: basicStructWithTypeParams{},
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+func _[T any]() {
+ type S struct{ t T }
+ _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
+-- suggestedfix_typeparams_36_8 --
+//go:build go1.18
+// +build go1.18
+
+package fillstruct
+
+type emptyStructWithTypeParams[A any] struct{}
+
+var _ = emptyStructWithTypeParams[int]{} // no suggested fix
+
+type basicStructWithTypeParams[T any] struct {
+ foo T
+}
+
+var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type twoArgStructWithTypeParams[F, B any] struct {
+ foo F
+ bar B
+}
+
+var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+var _ = twoArgStructWithTypeParams[int, string]{
+ bar: "bar",
+} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+type nestedStructWithTypeParams struct {
+ bar string
+ basic basicStructWithTypeParams[int]
+}
+
+var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+
+func _[T any]() {
+ type S struct{ t T }
+ _ = S{
+ t: *new(T),
+ } //@suggestedfix("}", "refactor.rewrite", "Fill")
+}
+
diff --git a/gopls/internal/lsp/testdata/folding/a.go b/gopls/internal/lsp/testdata/folding/a.go
new file mode 100644
index 000000000..e07d7e0bf
--- /dev/null
+++ b/gopls/internal/lsp/testdata/folding/a.go
@@ -0,0 +1,75 @@
+package folding //@fold("package")
+
+import (
+ "fmt"
+ _ "log"
+)
+
+import _ "os"
+
+// bar is a function.
+// With a multiline doc comment.
+func bar() string {
+ /* This is a single line comment */
+ switch {
+ case true:
+ if true {
+ fmt.Println("true")
+ } else {
+ fmt.Println("false")
+ }
+ case false:
+ fmt.Println("false")
+ default:
+ fmt.Println("default")
+ }
+ /* This is a multiline
+ block
+ comment */
+
+ /* This is a multiline
+ block
+ comment */
+ // Followed by another comment.
+ _ = []int{
+ 1,
+ 2,
+ 3,
+ }
+ _ = [2]string{"d",
+ "e",
+ }
+ _ = map[string]int{
+ "a": 1,
+ "b": 2,
+ "c": 3,
+ }
+ type T struct {
+ f string
+ g int
+ h string
+ }
+ _ = T{
+ f: "j",
+ g: 4,
+ h: "i",
+ }
+ x, y := make(chan bool), make(chan bool)
+ select {
+ case val := <-x:
+ if val {
+ fmt.Println("true from x")
+ } else {
+ fmt.Println("false from x")
+ }
+ case <-y:
+ fmt.Println("y")
+ default:
+ fmt.Println("default")
+ }
+ // This is a multiline comment
+ // that is not a doc comment.
+ return `
+this string
+is not indented`
+}
diff --git a/gopls/internal/lsp/testdata/folding/a.go.golden b/gopls/internal/lsp/testdata/folding/a.go.golden
new file mode 100644
index 000000000..b04ca4dab
--- /dev/null
+++ b/gopls/internal/lsp/testdata/folding/a.go.golden
@@ -0,0 +1,722 @@
+-- foldingRange-0 --
+package folding //@fold("package")
+
+import (<>)
+
+import _ "os"
+
+// bar is a function.<>
+func bar(<>) string {<>}
+
+-- foldingRange-1 --
+package folding //@fold("package")
+
+import (
+ "fmt"
+ _ "log"
+)
+
+import _ "os"
+
+// bar is a function.
+// With a multiline doc comment.
+func bar() string {
+ /* This is a single line comment */
+ switch {<>}
+ /* This is a multiline<>
+
+ /* This is a multiline<>
+ _ = []int{<>}
+ _ = [2]string{<>}
+ _ = map[string]int{<>}
+ type T struct {<>}
+ _ = T{<>}
+ x, y := make(<>), make(<>)
+ select {<>}
+ // This is a multiline comment<>
+ return <>
+}
+
+-- foldingRange-2 --
+package folding //@fold("package")
+
+import (
+ "fmt"
+ _ "log"
+)
+
+import _ "os"
+
+// bar is a function.
+// With a multiline doc comment.
+func bar() string {
+ /* This is a single line comment */
+ switch {
+ case true:<>
+ case false:<>
+ default:<>
+ }
+ /* This is a multiline
+ block
+ comment */
+
+ /* This is a multiline
+ block
+ comment */
+ // Followed by another comment.
+ _ = []int{
+ 1,
+ 2,
+ 3,
+ }
+ _ = [2]string{"d",
+ "e",
+ }
+ _ = map[string]int{
+ "a": 1,
+ "b": 2,
+ "c": 3,
+ }
+ type T struct {
+ f string
+ g int
+ h string
+ }
+ _ = T{
+ f: "j",
+ g: 4,
+ h: "i",
+ }
+ x, y := make(chan bool), make(chan bool)
+ select {
+ case val := <-x:<>
+ case <-y:<>
+ default:<>
+ }
+ // This is a multiline comment
+ // that is not a doc comment.
+ return `
+this string
+is not indented`
+}
+
+-- foldingRange-3 --
+package folding //@fold("package")
+
+import (
+ "fmt"
+ _ "log"
+)
+
+import _ "os"
+
+// bar is a function.
+// With a multiline doc comment.
+func bar() string {
+ /* This is a single line comment */
+ switch {
+ case true:
+ if true {<>} else {<>}
+ case false:
+ fmt.Println(<>)
+ default:
+ fmt.Println(<>)
+ }
+ /* This is a multiline
+ block
+ comment */
+
+ /* This is a multiline
+ block
+ comment */
+ // Followed by another comment.
+ _ = []int{
+ 1,
+ 2,
+ 3,
+ }
+ _ = [2]string{"d",
+ "e",
+ }
+ _ = map[string]int{
+ "a": 1,
+ "b": 2,
+ "c": 3,
+ }
+ type T struct {
+ f string
+ g int
+ h string
+ }
+ _ = T{
+ f: "j",
+ g: 4,
+ h: "i",
+ }
+ x, y := make(chan bool), make(chan bool)
+ select {
+ case val := <-x:
+ if val {<>} else {<>}
+ case <-y:
+ fmt.Println(<>)
+ default:
+ fmt.Println(<>)
+ }
+ // This is a multiline comment
+ // that is not a doc comment.
+ return `
+this string
+is not indented`
+}
+
+-- foldingRange-4 --
+package folding //@fold("package")
+
+import (
+ "fmt"
+ _ "log"
+)
+
+import _ "os"
+
+// bar is a function.
+// With a multiline doc comment.
+func bar() string {
+ /* This is a single line comment */
+ switch {
+ case true:
+ if true {
+ fmt.Println(<>)
+ } else {
+ fmt.Println(<>)
+ }
+ case false:
+ fmt.Println("false")
+ default:
+ fmt.Println("default")
+ }
+ /* This is a multiline
+ block
+ comment */
+
+ /* This is a multiline
+ block
+ comment */
+ // Followed by another comment.
+ _ = []int{
+ 1,
+ 2,
+ 3,
+ }
+ _ = [2]string{"d",
+ "e",
+ }
+ _ = map[string]int{
+ "a": 1,
+ "b": 2,
+ "c": 3,
+ }
+ type T struct {
+ f string
+ g int
+ h string
+ }
+ _ = T{
+ f: "j",
+ g: 4,
+ h: "i",
+ }
+ x, y := make(chan bool), make(chan bool)
+ select {
+ case val := <-x:
+ if val {
+ fmt.Println(<>)
+ } else {
+ fmt.Println(<>)
+ }
+ case <-y:
+ fmt.Println("y")
+ default:
+ fmt.Println("default")
+ }
+ // This is a multiline comment
+ // that is not a doc comment.
+ return `
+this string
+is not indented`
+}
+
+-- foldingRange-comment-0 --
+package folding //@fold("package")
+
+import (
+ "fmt"
+ _ "log"
+)
+
+import _ "os"
+
+// bar is a function.<>
+func bar() string {
+ /* This is a single line comment */
+ switch {
+ case true:
+ if true {
+ fmt.Println("true")
+ } else {
+ fmt.Println("false")
+ }
+ case false:
+ fmt.Println("false")
+ default:
+ fmt.Println("default")
+ }
+ /* This is a multiline<>
+
+ /* This is a multiline<>
+ _ = []int{
+ 1,
+ 2,
+ 3,
+ }
+ _ = [2]string{"d",
+ "e",
+ }
+ _ = map[string]int{
+ "a": 1,
+ "b": 2,
+ "c": 3,
+ }
+ type T struct {
+ f string
+ g int
+ h string
+ }
+ _ = T{
+ f: "j",
+ g: 4,
+ h: "i",
+ }
+ x, y := make(chan bool), make(chan bool)
+ select {
+ case val := <-x:
+ if val {
+ fmt.Println("true from x")
+ } else {
+ fmt.Println("false from x")
+ }
+ case <-y:
+ fmt.Println("y")
+ default:
+ fmt.Println("default")
+ }
+ // This is a multiline comment<>
+ return `
+this string
+is not indented`
+}
+
+-- foldingRange-imports-0 --
+package folding //@fold("package")
+
+import (<>)
+
+import _ "os"
+
+// bar is a function.
+// With a multiline doc comment.
+func bar() string {
+ /* This is a single line comment */
+ switch {
+ case true:
+ if true {
+ fmt.Println("true")
+ } else {
+ fmt.Println("false")
+ }
+ case false:
+ fmt.Println("false")
+ default:
+ fmt.Println("default")
+ }
+ /* This is a multiline
+ block
+ comment */
+
+ /* This is a multiline
+ block
+ comment */
+ // Followed by another comment.
+ _ = []int{
+ 1,
+ 2,
+ 3,
+ }
+ _ = [2]string{"d",
+ "e",
+ }
+ _ = map[string]int{
+ "a": 1,
+ "b": 2,
+ "c": 3,
+ }
+ type T struct {
+ f string
+ g int
+ h string
+ }
+ _ = T{
+ f: "j",
+ g: 4,
+ h: "i",
+ }
+ x, y := make(chan bool), make(chan bool)
+ select {
+ case val := <-x:
+ if val {
+ fmt.Println("true from x")
+ } else {
+ fmt.Println("false from x")
+ }
+ case <-y:
+ fmt.Println("y")
+ default:
+ fmt.Println("default")
+ }
+ // This is a multiline comment
+ // that is not a doc comment.
+ return `
+this string
+is not indented`
+}
+
+-- foldingRange-lineFolding-0 --
+package folding //@fold("package")
+
+import (<>
+)
+
+import _ "os"
+
+// bar is a function.<>
+func bar() string {<>
+}
+
+-- foldingRange-lineFolding-1 --
+package folding //@fold("package")
+
+import (
+ "fmt"
+ _ "log"
+)
+
+import _ "os"
+
+// bar is a function.
+// With a multiline doc comment.
+func bar() string {
+ /* This is a single line comment */
+ switch {<>
+ }
+ /* This is a multiline<>
+
+ /* This is a multiline<>
+ _ = []int{<>,
+ }
+ _ = [2]string{"d",
+ "e",
+ }
+ _ = map[string]int{<>,
+ }
+ type T struct {<>
+ }
+ _ = T{<>,
+ }
+ x, y := make(chan bool), make(chan bool)
+ select {<>
+ }
+ // This is a multiline comment<>
+ return <>
+}
+
+-- foldingRange-lineFolding-2 --
+package folding //@fold("package")
+
+import (
+ "fmt"
+ _ "log"
+)
+
+import _ "os"
+
+// bar is a function.
+// With a multiline doc comment.
+func bar() string {
+ /* This is a single line comment */
+ switch {
+ case true:<>
+ case false:<>
+ default:<>
+ }
+ /* This is a multiline
+ block
+ comment */
+
+ /* This is a multiline
+ block
+ comment */
+ // Followed by another comment.
+ _ = []int{
+ 1,
+ 2,
+ 3,
+ }
+ _ = [2]string{"d",
+ "e",
+ }
+ _ = map[string]int{
+ "a": 1,
+ "b": 2,
+ "c": 3,
+ }
+ type T struct {
+ f string
+ g int
+ h string
+ }
+ _ = T{
+ f: "j",
+ g: 4,
+ h: "i",
+ }
+ x, y := make(chan bool), make(chan bool)
+ select {
+ case val := <-x:<>
+ case <-y:<>
+ default:<>
+ }
+ // This is a multiline comment
+ // that is not a doc comment.
+ return `
+this string
+is not indented`
+}
+
+-- foldingRange-lineFolding-3 --
+package folding //@fold("package")
+
+import (
+ "fmt"
+ _ "log"
+)
+
+import _ "os"
+
+// bar is a function.
+// With a multiline doc comment.
+func bar() string {
+ /* This is a single line comment */
+ switch {
+ case true:
+ if true {<>
+ } else {<>
+ }
+ case false:
+ fmt.Println("false")
+ default:
+ fmt.Println("default")
+ }
+ /* This is a multiline
+ block
+ comment */
+
+ /* This is a multiline
+ block
+ comment */
+ // Followed by another comment.
+ _ = []int{
+ 1,
+ 2,
+ 3,
+ }
+ _ = [2]string{"d",
+ "e",
+ }
+ _ = map[string]int{
+ "a": 1,
+ "b": 2,
+ "c": 3,
+ }
+ type T struct {
+ f string
+ g int
+ h string
+ }
+ _ = T{
+ f: "j",
+ g: 4,
+ h: "i",
+ }
+ x, y := make(chan bool), make(chan bool)
+ select {
+ case val := <-x:
+ if val {<>
+ } else {<>
+ }
+ case <-y:
+ fmt.Println("y")
+ default:
+ fmt.Println("default")
+ }
+ // This is a multiline comment
+ // that is not a doc comment.
+ return `
+this string
+is not indented`
+}
+
+-- foldingRange-lineFolding-comment-0 --
+package folding //@fold("package")
+
+import (
+ "fmt"
+ _ "log"
+)
+
+import _ "os"
+
+// bar is a function.<>
+func bar() string {
+ /* This is a single line comment */
+ switch {
+ case true:
+ if true {
+ fmt.Println("true")
+ } else {
+ fmt.Println("false")
+ }
+ case false:
+ fmt.Println("false")
+ default:
+ fmt.Println("default")
+ }
+ /* This is a multiline<>
+
+ /* This is a multiline<>
+ _ = []int{
+ 1,
+ 2,
+ 3,
+ }
+ _ = [2]string{"d",
+ "e",
+ }
+ _ = map[string]int{
+ "a": 1,
+ "b": 2,
+ "c": 3,
+ }
+ type T struct {
+ f string
+ g int
+ h string
+ }
+ _ = T{
+ f: "j",
+ g: 4,
+ h: "i",
+ }
+ x, y := make(chan bool), make(chan bool)
+ select {
+ case val := <-x:
+ if val {
+ fmt.Println("true from x")
+ } else {
+ fmt.Println("false from x")
+ }
+ case <-y:
+ fmt.Println("y")
+ default:
+ fmt.Println("default")
+ }
+ // This is a multiline comment<>
+ return `
+this string
+is not indented`
+}
+
+-- foldingRange-lineFolding-imports-0 --
+package folding //@fold("package")
+
+import (<>
+)
+
+import _ "os"
+
+// bar is a function.
+// With a multiline doc comment.
+func bar() string {
+ /* This is a single line comment */
+ switch {
+ case true:
+ if true {
+ fmt.Println("true")
+ } else {
+ fmt.Println("false")
+ }
+ case false:
+ fmt.Println("false")
+ default:
+ fmt.Println("default")
+ }
+ /* This is a multiline
+ block
+ comment */
+
+ /* This is a multiline
+ block
+ comment */
+ // Followed by another comment.
+ _ = []int{
+ 1,
+ 2,
+ 3,
+ }
+ _ = [2]string{"d",
+ "e",
+ }
+ _ = map[string]int{
+ "a": 1,
+ "b": 2,
+ "c": 3,
+ }
+ type T struct {
+ f string
+ g int
+ h string
+ }
+ _ = T{
+ f: "j",
+ g: 4,
+ h: "i",
+ }
+ x, y := make(chan bool), make(chan bool)
+ select {
+ case val := <-x:
+ if val {
+ fmt.Println("true from x")
+ } else {
+ fmt.Println("false from x")
+ }
+ case <-y:
+ fmt.Println("y")
+ default:
+ fmt.Println("default")
+ }
+ // This is a multiline comment
+ // that is not a doc comment.
+ return `
+this string
+is not indented`
+}
+
diff --git a/gopls/internal/lsp/testdata/folding/bad.go.golden b/gopls/internal/lsp/testdata/folding/bad.go.golden
new file mode 100644
index 000000000..ab274f75a
--- /dev/null
+++ b/gopls/internal/lsp/testdata/folding/bad.go.golden
@@ -0,0 +1,81 @@
+-- foldingRange-0 --
+package folding //@fold("package")
+
+import (<>)
+
+import (<>)
+
+// badBar is a function.
+func badBar(<>) string {<>}
+
+-- foldingRange-1 --
+package folding //@fold("package")
+
+import ( "fmt"
+ _ "log"
+)
+
+import (
+ _ "os" )
+
+// badBar is a function.
+func badBar() string { x := true
+ if x {<>} else {<>}
+ return
+}
+
+-- foldingRange-2 --
+package folding //@fold("package")
+
+import ( "fmt"
+ _ "log"
+)
+
+import (
+ _ "os" )
+
+// badBar is a function.
+func badBar() string { x := true
+ if x {
+ // This is the only foldable thing in this file when lineFoldingOnly
+ fmt.Println(<>)
+ } else {
+ fmt.Println(<>) }
+ return
+}
+
+-- foldingRange-imports-0 --
+package folding //@fold("package")
+
+import (<>)
+
+import (<>)
+
+// badBar is a function.
+func badBar() string { x := true
+ if x {
+ // This is the only foldable thing in this file when lineFoldingOnly
+ fmt.Println("true")
+ } else {
+ fmt.Println("false") }
+ return
+}
+
+-- foldingRange-lineFolding-0 --
+package folding //@fold("package")
+
+import ( "fmt"
+ _ "log"
+)
+
+import (
+ _ "os" )
+
+// badBar is a function.
+func badBar() string { x := true
+ if x {<>
+ } else {
+ fmt.Println("false") }
+ return
+}
+
diff --git a/gopls/internal/lsp/testdata/folding/bad.go.in b/gopls/internal/lsp/testdata/folding/bad.go.in
new file mode 100644
index 000000000..84fcb740f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/folding/bad.go.in
@@ -0,0 +1,18 @@
+package folding //@fold("package")
+
+import ( "fmt"
+ _ "log"
+)
+
+import (
+ _ "os" )
+
+// badBar is a function.
+func badBar() string { x := true
+ if x {
+ // This is the only foldable thing in this file when lineFoldingOnly
+ fmt.Println("true")
+ } else {
+ fmt.Println("false") }
+ return
+}
diff --git a/gopls/internal/lsp/testdata/foo/foo.go b/gopls/internal/lsp/testdata/foo/foo.go
new file mode 100644
index 000000000..66631c58c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/foo/foo.go
@@ -0,0 +1,30 @@
+package foo //@mark(PackageFoo, "foo"),item(PackageFoo, "foo", "\"golang.org/lsptests/foo\"", "package")
+
+type StructFoo struct { //@item(StructFoo, "StructFoo", "struct{...}", "struct")
+ Value int //@item(Value, "Value", "int", "field")
+}
+
+// Pre-set this marker, as we don't have a "source" for it in this package.
+/* Error() */ //@item(Error, "Error", "func() string", "method")
+
+func Foo() { //@item(Foo, "Foo", "func()", "func")
+ var err error
+ err.Error() //@complete("E", Error)
+}
+
+func _() {
+ var sFoo StructFoo //@mark(sFoo1, "sFoo"),complete("t", StructFoo)
+ if x := sFoo; x.Value == 1 { //@mark(sFoo2, "sFoo"),complete("V", Value),typdef("sFoo", StructFoo),refs("sFo", sFoo1, sFoo2)
+ return
+ }
+}
+
+func _() {
+ shadowed := 123
+ {
+ shadowed := "hi" //@item(shadowed, "shadowed", "string", "var"),refs("shadowed", shadowed)
+ sha //@complete("a", shadowed)
+ }
+}
+
+type IntFoo int //@item(IntFoo, "IntFoo", "int", "type")
diff --git a/gopls/internal/lsp/testdata/format/bad_format.go.golden b/gopls/internal/lsp/testdata/format/bad_format.go.golden
new file mode 100644
index 000000000..f0c24d635
--- /dev/null
+++ b/gopls/internal/lsp/testdata/format/bad_format.go.golden
@@ -0,0 +1,21 @@
+-- gofmt --
+package format //@format("package")
+
+import (
+ "fmt"
+ "log"
+ "runtime"
+)
+
+func hello() {
+
+ var x int //@diag("x", "compiler", "x declared (and|but) not used", "error")
+}
+
+func hi() {
+ runtime.GOROOT()
+ fmt.Printf("")
+
+ log.Printf("")
+}
+
diff --git a/gopls/internal/lsp/testdata/format/bad_format.go.in b/gopls/internal/lsp/testdata/format/bad_format.go.in
new file mode 100644
index 000000000..995ec399a
--- /dev/null
+++ b/gopls/internal/lsp/testdata/format/bad_format.go.in
@@ -0,0 +1,22 @@
+package format //@format("package")
+
+import (
+ "runtime"
+ "fmt"
+ "log"
+)
+
+func hello() {
+
+
+
+
+ var x int //@diag("x", "compiler", "x declared (and|but) not used", "error")
+}
+
+func hi() {
+ runtime.GOROOT()
+ fmt.Printf("")
+
+ log.Printf("")
+}
diff --git a/gopls/internal/lsp/testdata/format/good_format.go b/gopls/internal/lsp/testdata/format/good_format.go
new file mode 100644
index 000000000..01cb1610c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/format/good_format.go
@@ -0,0 +1,9 @@
+package format //@format("package")
+
+import (
+ "log"
+)
+
+func goodbye() {
+ log.Printf("byeeeee")
+}
diff --git a/gopls/internal/lsp/testdata/format/good_format.go.golden b/gopls/internal/lsp/testdata/format/good_format.go.golden
new file mode 100644
index 000000000..99f47e2e8
--- /dev/null
+++ b/gopls/internal/lsp/testdata/format/good_format.go.golden
@@ -0,0 +1,11 @@
+-- gofmt --
+package format //@format("package")
+
+import (
+ "log"
+)
+
+func goodbye() {
+ log.Printf("byeeeee")
+}
+
diff --git a/gopls/internal/lsp/testdata/format/newline_format.go.golden b/gopls/internal/lsp/testdata/format/newline_format.go.golden
new file mode 100644
index 000000000..7c76afdd5
--- /dev/null
+++ b/gopls/internal/lsp/testdata/format/newline_format.go.golden
@@ -0,0 +1,4 @@
+-- gofmt --
+package format //@format("package")
+func _() {}
+
diff --git a/gopls/internal/lsp/testdata/format/newline_format.go.in b/gopls/internal/lsp/testdata/format/newline_format.go.in
new file mode 100644
index 000000000..fe597b90b
--- /dev/null
+++ b/gopls/internal/lsp/testdata/format/newline_format.go.in
@@ -0,0 +1,2 @@
+package format //@format("package")
+func _() {} \ No newline at end of file
diff --git a/gopls/internal/lsp/testdata/format/one_line.go.golden b/gopls/internal/lsp/testdata/format/one_line.go.golden
new file mode 100644
index 000000000..4d11f84cb
--- /dev/null
+++ b/gopls/internal/lsp/testdata/format/one_line.go.golden
@@ -0,0 +1,3 @@
+-- gofmt --
+package format //@format("package")
+
diff --git a/gopls/internal/lsp/testdata/format/one_line.go.in b/gopls/internal/lsp/testdata/format/one_line.go.in
new file mode 100644
index 000000000..30f413755
--- /dev/null
+++ b/gopls/internal/lsp/testdata/format/one_line.go.in
@@ -0,0 +1 @@
+package format //@format("package") \ No newline at end of file
diff --git a/gopls/internal/lsp/testdata/func_rank/func_rank.go.in b/gopls/internal/lsp/testdata/func_rank/func_rank.go.in
new file mode 100644
index 000000000..905010b3d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/func_rank/func_rank.go.in
@@ -0,0 +1,70 @@
+package func_rank
+
+import "net/http"
+
+var stringAVar = "var" //@item(stringAVar, "stringAVar", "string", "var")
+func stringBFunc() string { return "str" } //@item(stringBFunc, "stringBFunc", "func() string", "func")
+type stringer struct{} //@item(stringer, "stringer", "struct{...}", "struct")
+
+func _() stringer //@complete("tr", stringer)
+
+func _(val stringer) {} //@complete("tr", stringer)
+
+func (stringer) _() {} //@complete("tr", stringer)
+
+func _() {
+ var s struct {
+ AA int //@item(rankAA, "AA", "int", "field")
+ AB string //@item(rankAB, "AB", "string", "field")
+ AC int //@item(rankAC, "AC", "int", "field")
+ }
+ fnStr := func(string) {}
+ fnStr(s.A) //@complete(")", rankAB, rankAA, rankAC)
+ fnStr("" + s.A) //@complete(")", rankAB, rankAA, rankAC)
+
+ fnInt := func(int) {}
+ fnInt(-s.A) //@complete(")", rankAA, rankAC, rankAB)
+
+ // no expected type
+ fnInt(func() int { s.A }) //@complete(" }", rankAA, rankAB, rankAC)
+ fnInt(s.A()) //@complete("()", rankAA, rankAC, rankAB)
+ fnInt([]int{}[s.A]) //@complete("])", rankAA, rankAC, rankAB)
+ fnInt([]int{}[:s.A]) //@complete("])", rankAA, rankAC, rankAB)
+
+ fnInt(s.A.(int)) //@complete(".(", rankAA, rankAC, rankAB)
+
+ fnPtr := func(*string) {}
+ fnPtr(&s.A) //@complete(")", rankAB, rankAA, rankAC)
+
+ var aaPtr *string //@item(rankAAPtr, "aaPtr", "*string", "var")
+ var abPtr *int //@item(rankABPtr, "abPtr", "*int", "var")
+ fnInt(*a) //@complete(")", rankABPtr, rankAAPtr)
+
+ _ = func() string {
+ return s.A //@complete(" //", rankAB, rankAA, rankAC)
+ }
+}
+
+type foo struct {
+ fooPrivateField int //@item(rankFooPrivField, "fooPrivateField", "int", "field")
+ FooPublicField int //@item(rankFooPubField, "FooPublicField", "int", "field")
+}
+
+func (foo) fooPrivateMethod() int { //@item(rankFooPrivMeth, "fooPrivateMethod", "func() int", "method")
+ return 0
+}
+
+func (foo) FooPublicMethod() int { //@item(rankFooPubMeth, "FooPublicMethod", "func() int", "method")
+ return 0
+}
+
+func _() {
+ var _ int = foo{}. //@rank(" //", rankFooPrivField, rankFooPubField),rank(" //", rankFooPrivMeth, rankFooPubMeth),rank(" //", rankFooPrivField, rankFooPrivMeth)
+}
+
+func _() {
+ HandleFunc //@item(httpHandleFunc, "HandleFunc", "func(pattern string, handler func(http.ResponseWriter, *http.Request))", "func")
+ HandlerFunc //@item(httpHandlerFunc, "HandlerFunc", "func(http.ResponseWriter, *http.Request)", "type")
+
+ http.HandleFunc //@rank(" //", httpHandleFunc, httpHandlerFunc)
+}
diff --git a/gopls/internal/lsp/testdata/funcsig/func_sig.go b/gopls/internal/lsp/testdata/funcsig/func_sig.go
new file mode 100644
index 000000000..00f9b575d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/funcsig/func_sig.go
@@ -0,0 +1,9 @@
+package funcsig
+
+type someType int //@item(sigSomeType, "someType", "int", "type")
+
+// Don't complete "foo" in signature.
+func (foo someType) _() { //@item(sigFoo, "foo", "someType", "var"),complete(") {", sigSomeType)
+
+ //@complete("", sigFoo, sigSomeType)
+}
diff --git a/gopls/internal/lsp/testdata/funcvalue/func_value.go b/gopls/internal/lsp/testdata/funcvalue/func_value.go
new file mode 100644
index 000000000..913fcbcfe
--- /dev/null
+++ b/gopls/internal/lsp/testdata/funcvalue/func_value.go
@@ -0,0 +1,27 @@
+package funcvalue
+
+func fooFunc() int { //@item(fvFooFunc, "fooFunc", "func() int", "func")
+ return 0
+}
+
+var _ = fooFunc() //@item(fvFooFuncCall, "fooFunc", "func() int", "func")
+
+var fooVar = func() int { //@item(fvFooVar, "fooVar", "func() int", "var")
+ return 0
+}
+
+var _ = fooVar() //@item(fvFooVarCall, "fooVar", "func() int", "var")
+
+type myFunc func() int
+
+var fooType myFunc = fooVar //@item(fvFooType, "fooType", "myFunc", "var")
+
+var _ = fooType() //@item(fvFooTypeCall, "fooType", "func() int", "var")
+
+func _() {
+ var f func() int
+ f = foo //@complete(" //", fvFooFunc, fvFooType, fvFooVar)
+
+ var i int
+ i = foo //@complete(" //", fvFooFuncCall, fvFooTypeCall, fvFooVarCall)
+}
diff --git a/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go b/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go
new file mode 100644
index 000000000..73268f553
--- /dev/null
+++ b/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go
@@ -0,0 +1,48 @@
+// 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 fuzzy
+
+func _() {
+ var a struct {
+ fabar int
+ fooBar string
+ }
+
+ a.fabar //@item(fuzzFabarField, "a.fabar", "int", "field")
+ a.fooBar //@item(fuzzFooBarField, "a.fooBar", "string", "field")
+
+ afa //@fuzzy(" //", fuzzFabarField, fuzzFooBarField)
+ afb //@fuzzy(" //", fuzzFooBarField, fuzzFabarField)
+
+ fab //@fuzzy(" //", fuzzFabarField)
+
+ var myString string
+ myString = af //@fuzzy(" //", fuzzFooBarField, fuzzFabarField)
+
+ var b struct {
+ c struct {
+ d struct {
+ e struct {
+ abc string
+ }
+ abc float32
+ }
+ abc bool
+ }
+ abc int
+ }
+
+ b.abc //@item(fuzzABCInt, "b.abc", "int", "field")
+ b.c.abc //@item(fuzzABCbool, "b.c.abc", "bool", "field")
+ b.c.d.abc //@item(fuzzABCfloat, "b.c.d.abc", "float32", "field")
+ b.c.d.e.abc //@item(fuzzABCstring, "b.c.d.e.abc", "string", "field")
+
+ // in depth order by default
+ abc //@fuzzy(" //", fuzzABCInt, fuzzABCbool, fuzzABCfloat)
+
+ // deep candidate that matches expected type should still ranked first
+ var s string
+ s = abc //@fuzzy(" //", fuzzABCstring, fuzzABCInt, fuzzABCbool)
+}
diff --git a/gopls/internal/lsp/testdata/generate/generate.go b/gopls/internal/lsp/testdata/generate/generate.go
new file mode 100644
index 000000000..ae5e90d1a
--- /dev/null
+++ b/gopls/internal/lsp/testdata/generate/generate.go
@@ -0,0 +1,4 @@
+package generate
+
+//go:generate echo Hi //@ codelens("//go:generate", "run go generate", "generate"), codelens("//go:generate", "run go generate ./...", "generate")
+//go:generate echo I shall have no CodeLens
diff --git a/gopls/internal/lsp/testdata/generated/generated.go b/gopls/internal/lsp/testdata/generated/generated.go
new file mode 100644
index 000000000..c7adc1804
--- /dev/null
+++ b/gopls/internal/lsp/testdata/generated/generated.go
@@ -0,0 +1,7 @@
+package generated
+
+// Code generated by generator.go. DO NOT EDIT.
+
+func _() {
+ var y int //@diag("y", "compiler", "y declared (and|but) not used", "error")
+}
diff --git a/gopls/internal/lsp/testdata/generated/generator.go b/gopls/internal/lsp/testdata/generated/generator.go
new file mode 100644
index 000000000..8e2a4fab7
--- /dev/null
+++ b/gopls/internal/lsp/testdata/generated/generator.go
@@ -0,0 +1,5 @@
+package generated
+
+func _() {
+ var x int //@diag("x", "compiler", "x declared (and|but) not used", "error")
+}
diff --git a/gopls/internal/lsp/testdata/godef/a/a_x_test.go b/gopls/internal/lsp/testdata/godef/a/a_x_test.go
new file mode 100644
index 000000000..f166f0550
--- /dev/null
+++ b/gopls/internal/lsp/testdata/godef/a/a_x_test.go
@@ -0,0 +1,9 @@
+package a_test
+
+import (
+ "testing"
+)
+
+func TestA2(t *testing.T) { //@TestA2,godef(TestA2, TestA2)
+ Nonexistant() //@diag("Nonexistant", "compiler", "(undeclared name|undefined): Nonexistant", "error")
+}
diff --git a/gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden b/gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden
new file mode 100644
index 000000000..2e3064794
--- /dev/null
+++ b/gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden
@@ -0,0 +1,26 @@
+-- TestA2-definition --
+godef/a/a_x_test.go:7:6-12: defined here as ```go
+func TestA2(t *testing.T)
+```
+-- TestA2-definition-json --
+{
+ "span": {
+ "uri": "file://godef/a/a_x_test.go",
+ "start": {
+ "line": 7,
+ "column": 6,
+ "offset": 44
+ },
+ "end": {
+ "line": 7,
+ "column": 12,
+ "offset": 50
+ }
+ },
+ "description": "```go\nfunc TestA2(t *testing.T)\n```"
+}
+
+-- TestA2-hoverdef --
+```go
+func TestA2(t *testing.T)
+```
diff --git a/gopls/internal/lsp/testdata/godef/a/d.go b/gopls/internal/lsp/testdata/godef/a/d.go
new file mode 100644
index 000000000..a1d17ad0d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/godef/a/d.go
@@ -0,0 +1,69 @@
+package a //@mark(a, "a "),hoverdef("a ", a)
+
+import "fmt"
+
+type Thing struct { //@Thing
+ Member string //@Member
+}
+
+var Other Thing //@Other
+
+func Things(val []string) []Thing { //@Things
+ return nil
+}
+
+func (t Thing) Method(i int) string { //@Method
+ return t.Member
+}
+
+func (t Thing) Method3() {
+}
+
+func (t *Thing) Method2(i int, j int) (error, string) {
+ return nil, t.Member
+}
+
+func (t *Thing) private() {
+}
+
+func useThings() {
+ t := Thing{ //@mark(aStructType, "ing")
+ Member: "string", //@mark(fMember, "ember")
+ }
+ fmt.Print(t.Member) //@mark(aMember, "ember")
+ fmt.Print(Other) //@mark(aVar, "ther")
+ Things() //@mark(aFunc, "ings")
+ t.Method() //@mark(aMethod, "eth")
+}
+
+type NextThing struct { //@NextThing
+ Thing
+ Value int
+}
+
+func (n NextThing) another() string {
+ return n.Member
+}
+
+// Shadows Thing.Method3
+func (n *NextThing) Method3() int {
+ return n.Value
+}
+
+var nextThing NextThing //@hoverdef("NextThing", NextThing)
+
+/*@
+godef(aStructType, Thing)
+godef(aMember, Member)
+godef(aVar, Other)
+godef(aFunc, Things)
+godef(aMethod, Method)
+godef(fMember, Member)
+godef(Member, Member)
+
+//param
+//package name
+//const
+//anon field
+
+*/
diff --git a/gopls/internal/lsp/testdata/godef/a/d.go.golden b/gopls/internal/lsp/testdata/godef/a/d.go.golden
new file mode 100644
index 000000000..ee687750c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/godef/a/d.go.golden
@@ -0,0 +1,191 @@
+-- Member-definition --
+godef/a/d.go:6:2-8: defined here as ```go
+field Member string
+```
+
+@Member
+
+
+[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)
+-- Member-definition-json --
+{
+ "span": {
+ "uri": "file://godef/a/d.go",
+ "start": {
+ "line": 6,
+ "column": 2,
+ "offset": 90
+ },
+ "end": {
+ "line": 6,
+ "column": 8,
+ "offset": 96
+ }
+ },
+ "description": "```go\nfield Member string\n```\n\n@Member\n\n\n[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)"
+}
+
+-- Member-hoverdef --
+```go
+field Member string
+```
+
+@Member
+
+
+[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)
+-- Method-definition --
+godef/a/d.go:15:16-22: defined here as ```go
+func (Thing).Method(i int) string
+```
+
+[`(a.Thing).Method` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Method)
+-- Method-definition-json --
+{
+ "span": {
+ "uri": "file://godef/a/d.go",
+ "start": {
+ "line": 15,
+ "column": 16,
+ "offset": 219
+ },
+ "end": {
+ "line": 15,
+ "column": 22,
+ "offset": 225
+ }
+ },
+ "description": "```go\nfunc (Thing).Method(i int) string\n```\n\n[`(a.Thing).Method` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Method)"
+}
+
+-- Method-hoverdef --
+```go
+func (Thing).Method(i int) string
+```
+
+[`(a.Thing).Method` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Method)
+-- NextThing-hoverdef --
+```go
+type NextThing struct {
+ Thing
+ Value int
+}
+
+func (*NextThing).Method3() int
+func (NextThing).another() string
+```
+
+[`a.NextThing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#NextThing)
+-- Other-definition --
+godef/a/d.go:9:5-10: defined here as ```go
+var Other Thing
+```
+
+@Other
+
+
+[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)
+-- Other-definition-json --
+{
+ "span": {
+ "uri": "file://godef/a/d.go",
+ "start": {
+ "line": 9,
+ "column": 5,
+ "offset": 121
+ },
+ "end": {
+ "line": 9,
+ "column": 10,
+ "offset": 126
+ }
+ },
+ "description": "```go\nvar Other Thing\n```\n\n@Other\n\n\n[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)"
+}
+
+-- Other-hoverdef --
+```go
+var Other Thing
+```
+
+@Other
+
+
+[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)
+-- Thing-definition --
+godef/a/d.go:5:6-11: defined here as ```go
+type Thing struct {
+ Member string //@Member
+}
+
+func (Thing).Method(i int) string
+func (*Thing).Method2(i int, j int) (error, string)
+func (Thing).Method3()
+func (*Thing).private()
+```
+
+[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)
+-- Thing-definition-json --
+{
+ "span": {
+ "uri": "file://godef/a/d.go",
+ "start": {
+ "line": 5,
+ "column": 6,
+ "offset": 65
+ },
+ "end": {
+ "line": 5,
+ "column": 11,
+ "offset": 70
+ }
+ },
+ "description": "```go\ntype Thing struct {\n\tMember string //@Member\n}\n\nfunc (Thing).Method(i int) string\nfunc (*Thing).Method2(i int, j int) (error, string)\nfunc (Thing).Method3()\nfunc (*Thing).private()\n```\n\n[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)"
+}
+
+-- Thing-hoverdef --
+```go
+type Thing struct {
+ Member string //@Member
+}
+
+func (Thing).Method(i int) string
+func (*Thing).Method2(i int, j int) (error, string)
+func (Thing).Method3()
+func (*Thing).private()
+```
+
+[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)
+-- Things-definition --
+godef/a/d.go:11:6-12: defined here as ```go
+func Things(val []string) []Thing
+```
+
+[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)
+-- Things-definition-json --
+{
+ "span": {
+ "uri": "file://godef/a/d.go",
+ "start": {
+ "line": 11,
+ "column": 6,
+ "offset": 148
+ },
+ "end": {
+ "line": 11,
+ "column": 12,
+ "offset": 154
+ }
+ },
+ "description": "```go\nfunc Things(val []string) []Thing\n```\n\n[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)"
+}
+
+-- Things-hoverdef --
+```go
+func Things(val []string) []Thing
+```
+
+[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)
+-- a-hoverdef --
+Package a is a package for testing go to definition.
+
diff --git a/gopls/internal/lsp/testdata/godef/a/f.go b/gopls/internal/lsp/testdata/godef/a/f.go
new file mode 100644
index 000000000..10f88262a
--- /dev/null
+++ b/gopls/internal/lsp/testdata/godef/a/f.go
@@ -0,0 +1,16 @@
+// Package a is a package for testing go to definition.
+package a
+
+import "fmt"
+
+func TypeStuff() { //@Stuff
+ var x string
+
+ switch y := interface{}(x).(type) { //@mark(switchY, "y"),godef("y", switchY)
+ case int: //@mark(intY, "int")
+ fmt.Printf("%v", y) //@hoverdef("y", intY)
+ case string: //@mark(stringY, "string")
+ fmt.Printf("%v", y) //@hoverdef("y", stringY)
+ }
+
+}
diff --git a/gopls/internal/lsp/testdata/godef/a/f.go.golden b/gopls/internal/lsp/testdata/godef/a/f.go.golden
new file mode 100644
index 000000000..a084356c0
--- /dev/null
+++ b/gopls/internal/lsp/testdata/godef/a/f.go.golden
@@ -0,0 +1,34 @@
+-- intY-hoverdef --
+```go
+var y int
+```
+-- stringY-hoverdef --
+```go
+var y string
+```
+-- switchY-definition --
+godef/a/f.go:8:9-10: defined here as ```go
+var y interface{}
+```
+-- switchY-definition-json --
+{
+ "span": {
+ "uri": "file://godef/a/f.go",
+ "start": {
+ "line": 8,
+ "column": 9,
+ "offset": 76
+ },
+ "end": {
+ "line": 8,
+ "column": 10,
+ "offset": 77
+ }
+ },
+ "description": "```go\nvar y interface{}\n```"
+}
+
+-- switchY-hoverdef --
+```go
+var y interface{}
+```
diff --git a/gopls/internal/lsp/testdata/godef/a/g.go b/gopls/internal/lsp/testdata/godef/a/g.go
new file mode 100644
index 000000000..dfef2fb80
--- /dev/null
+++ b/gopls/internal/lsp/testdata/godef/a/g.go
@@ -0,0 +1,6 @@
+package a
+
+import "time"
+
+// dur is a constant of type time.Duration.
+const dur = 15*time.Minute + 10*time.Second + 350*time.Millisecond //@dur,hoverdef("dur", dur)
diff --git a/gopls/internal/lsp/testdata/godef/a/g.go.golden b/gopls/internal/lsp/testdata/godef/a/g.go.golden
new file mode 100644
index 000000000..f7a2e1b07
--- /dev/null
+++ b/gopls/internal/lsp/testdata/godef/a/g.go.golden
@@ -0,0 +1,7 @@
+-- dur-hoverdef --
+```go
+const dur time.Duration = 910350000000 // 15m10.35s
+```
+
+dur is a constant of type time.Duration.
+
diff --git a/gopls/internal/lsp/testdata/godef/a/h.go b/gopls/internal/lsp/testdata/godef/a/h.go
new file mode 100644
index 000000000..5a5dcc678
--- /dev/null
+++ b/gopls/internal/lsp/testdata/godef/a/h.go
@@ -0,0 +1,147 @@
+package a
+
+func _() {
+ type s struct {
+ nested struct {
+ // nested number
+ number int64 //@mark(nestedNumber, "number")
+ }
+ nested2 []struct {
+ // nested string
+ str string //@mark(nestedString, "str")
+ }
+ x struct {
+ x struct {
+ x struct {
+ x struct {
+ x struct {
+ // nested map
+ m map[string]float64 //@mark(nestedMap, "m")
+ }
+ }
+ }
+ }
+ }
+ }
+
+ var t s
+ _ = t.nested.number //@hoverdef("number", nestedNumber)
+ _ = t.nested2[0].str //@hoverdef("str", nestedString)
+ _ = t.x.x.x.x.x.m //@hoverdef("m", nestedMap)
+}
+
+func _() {
+ var s struct {
+ // a field
+ a int //@mark(structA, "a")
+ // b nested struct
+ b struct { //@mark(structB, "b")
+ // c field of nested struct
+ c int //@mark(structC, "c")
+ }
+ }
+ _ = s.a //@hoverdef("a", structA)
+ _ = s.b //@hoverdef("b", structB)
+ _ = s.b.c //@hoverdef("c", structC)
+
+ var arr []struct {
+ // d field
+ d int //@mark(arrD, "d")
+ // e nested struct
+ e struct { //@mark(arrE, "e")
+ // f field of nested struct
+ f int //@mark(arrF, "f")
+ }
+ }
+ _ = arr[0].d //@hoverdef("d", arrD)
+ _ = arr[0].e //@hoverdef("e", arrE)
+ _ = arr[0].e.f //@hoverdef("f", arrF)
+
+ var complex []struct {
+ c <-chan map[string][]struct {
+ // h field
+ h int //@mark(complexH, "h")
+ // i nested struct
+ i struct { //@mark(complexI, "i")
+ // j field of nested struct
+ j int //@mark(complexJ, "j")
+ }
+ }
+ }
+ _ = (<-complex[0].c)["0"][0].h //@hoverdef("h", complexH)
+ _ = (<-complex[0].c)["0"][0].i //@hoverdef("i", complexI)
+ _ = (<-complex[0].c)["0"][0].i.j //@hoverdef("j", complexJ)
+
+ var mapWithStructKey map[struct {
+ // X key field
+ x []string //@mark(mapStructKeyX, "x")
+ }]int
+ for k := range mapWithStructKey {
+ _ = k.x //@hoverdef("x", mapStructKeyX)
+ }
+
+ var mapWithStructKeyAndValue map[struct {
+ // Y key field
+ y string //@mark(mapStructKeyY, "y")
+ }]struct {
+ // X value field
+ x string //@mark(mapStructValueX, "x")
+ }
+ for k, v := range mapWithStructKeyAndValue {
+ // TODO: we don't show docs for y field because both map key and value
+ // are structs. And in this case, we parse only map value
+ _ = k.y //@hoverdef("y", mapStructKeyY)
+ _ = v.x //@hoverdef("x", mapStructValueX)
+ }
+
+ var i []map[string]interface {
+ // open method comment
+ open() error //@mark(openMethod, "open")
+ }
+ i[0]["1"].open() //@hoverdef("open", openMethod)
+}
+
+func _() {
+ test := struct {
+ // test description
+ desc string //@mark(testDescription, "desc")
+ }{}
+ _ = test.desc //@hoverdef("desc", testDescription)
+
+ for _, tt := range []struct {
+ // test input
+ in map[string][]struct { //@mark(testInput, "in")
+ // test key
+ key string //@mark(testInputKey, "key")
+ // test value
+ value interface{} //@mark(testInputValue, "value")
+ }
+ result struct {
+ v <-chan struct {
+ // expected test value
+ value int //@mark(testResultValue, "value")
+ }
+ }
+ }{} {
+ _ = tt.in //@hoverdef("in", testInput)
+ _ = tt.in["0"][0].key //@hoverdef("key", testInputKey)
+ _ = tt.in["0"][0].value //@hoverdef("value", testInputValue)
+
+ _ = (<-tt.result.v).value //@hoverdef("value", testResultValue)
+ }
+}
+
+func _() {
+ getPoints := func() []struct {
+ // X coord
+ x int //@mark(returnX, "x")
+ // Y coord
+ y int //@mark(returnY, "y")
+ } {
+ return nil
+ }
+
+ r := getPoints()
+ r[0].x //@hoverdef("x", returnX)
+ r[0].y //@hoverdef("y", returnY)
+}
diff --git a/gopls/internal/lsp/testdata/godef/a/h.go.golden b/gopls/internal/lsp/testdata/godef/a/h.go.golden
new file mode 100644
index 000000000..7cef9ee96
--- /dev/null
+++ b/gopls/internal/lsp/testdata/godef/a/h.go.golden
@@ -0,0 +1,161 @@
+-- arrD-hoverdef --
+```go
+field d int
+```
+
+d field
+
+-- arrE-hoverdef --
+```go
+field e struct{f int}
+```
+
+e nested struct
+
+-- arrF-hoverdef --
+```go
+field f int
+```
+
+f field of nested struct
+
+-- complexH-hoverdef --
+```go
+field h int
+```
+
+h field
+
+-- complexI-hoverdef --
+```go
+field i struct{j int}
+```
+
+i nested struct
+
+-- complexJ-hoverdef --
+```go
+field j int
+```
+
+j field of nested struct
+
+-- mapStructKeyX-hoverdef --
+```go
+field x []string
+```
+
+X key field
+
+-- mapStructKeyY-hoverdef --
+```go
+field y string
+```
+
+Y key field
+
+-- mapStructValueX-hoverdef --
+```go
+field x string
+```
+
+X value field
+
+-- nestedMap-hoverdef --
+```go
+field m map[string]float64
+```
+
+nested map
+
+-- nestedNumber-hoverdef --
+```go
+field number int64
+```
+
+nested number
+
+-- nestedString-hoverdef --
+```go
+field str string
+```
+
+nested string
+
+-- openMethod-hoverdef --
+```go
+func (interface).open() error
+```
+
+open method comment
+
+-- returnX-hoverdef --
+```go
+field x int
+```
+
+X coord
+
+-- returnY-hoverdef --
+```go
+field y int
+```
+
+Y coord
+
+-- structA-hoverdef --
+```go
+field a int
+```
+
+a field
+
+-- structB-hoverdef --
+```go
+field b struct{c int}
+```
+
+b nested struct
+
+-- structC-hoverdef --
+```go
+field c int
+```
+
+c field of nested struct
+
+-- testDescription-hoverdef --
+```go
+field desc string
+```
+
+test description
+
+-- testInput-hoverdef --
+```go
+field in map[string][]struct{key string; value interface{}}
+```
+
+test input
+
+-- testInputKey-hoverdef --
+```go
+field key string
+```
+
+test key
+
+-- testInputValue-hoverdef --
+```go
+field value interface{}
+```
+
+test value
+
+-- testResultValue-hoverdef --
+```go
+field value int
+```
+
+expected test value
+
diff --git a/gopls/internal/lsp/testdata/godef/b/e.go b/gopls/internal/lsp/testdata/godef/b/e.go
new file mode 100644
index 000000000..9c81cad31
--- /dev/null
+++ b/gopls/internal/lsp/testdata/godef/b/e.go
@@ -0,0 +1,31 @@
+package b
+
+import (
+ "fmt"
+
+ "golang.org/lsptests/godef/a"
+)
+
+func useThings() {
+ t := a.Thing{} //@mark(bStructType, "ing")
+ fmt.Print(t.Member) //@mark(bMember, "ember")
+ fmt.Print(a.Other) //@mark(bVar, "ther")
+ a.Things() //@mark(bFunc, "ings")
+}
+
+/*@
+godef(bStructType, Thing)
+godef(bMember, Member)
+godef(bVar, Other)
+godef(bFunc, Things)
+*/
+
+func _() {
+ var x interface{} //@mark(eInterface, "interface{}")
+ switch x := x.(type) { //@hoverdef("x", eInterface)
+ case string: //@mark(eString, "string")
+ fmt.Println(x) //@hoverdef("x", eString)
+ case int: //@mark(eInt, "int")
+ fmt.Println(x) //@hoverdef("x", eInt)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/godef/b/e.go.golden b/gopls/internal/lsp/testdata/godef/b/e.go.golden
new file mode 100644
index 000000000..3d7d89797
--- /dev/null
+++ b/gopls/internal/lsp/testdata/godef/b/e.go.golden
@@ -0,0 +1,156 @@
+-- Member-definition --
+godef/a/d.go:6:2-8: defined here as ```go
+field Member string
+```
+
+@Member
+
+
+[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)
+-- Member-definition-json --
+{
+ "span": {
+ "uri": "file://godef/a/d.go",
+ "start": {
+ "line": 6,
+ "column": 2,
+ "offset": 90
+ },
+ "end": {
+ "line": 6,
+ "column": 8,
+ "offset": 96
+ }
+ },
+ "description": "```go\nfield Member string\n```\n\n@Member\n\n\n[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)"
+}
+
+-- Member-hoverdef --
+```go
+field Member string
+```
+
+@Member
+
+
+[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)
+-- Other-definition --
+godef/a/d.go:9:5-10: defined here as ```go
+var a.Other a.Thing
+```
+
+@Other
+
+
+[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)
+-- Other-definition-json --
+{
+ "span": {
+ "uri": "file://godef/a/d.go",
+ "start": {
+ "line": 9,
+ "column": 5,
+ "offset": 121
+ },
+ "end": {
+ "line": 9,
+ "column": 10,
+ "offset": 126
+ }
+ },
+ "description": "```go\nvar a.Other a.Thing\n```\n\n@Other\n\n\n[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)"
+}
+
+-- Other-hoverdef --
+```go
+var a.Other a.Thing
+```
+
+@Other
+
+
+[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)
+-- Thing-definition --
+godef/a/d.go:5:6-11: defined here as ```go
+type Thing struct {
+ Member string //@Member
+}
+
+func (a.Thing).Method(i int) string
+func (*a.Thing).Method2(i int, j int) (error, string)
+func (a.Thing).Method3()
+```
+
+[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)
+-- Thing-definition-json --
+{
+ "span": {
+ "uri": "file://godef/a/d.go",
+ "start": {
+ "line": 5,
+ "column": 6,
+ "offset": 65
+ },
+ "end": {
+ "line": 5,
+ "column": 11,
+ "offset": 70
+ }
+ },
+ "description": "```go\ntype Thing struct {\n\tMember string //@Member\n}\n\nfunc (a.Thing).Method(i int) string\nfunc (*a.Thing).Method2(i int, j int) (error, string)\nfunc (a.Thing).Method3()\n```\n\n[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)"
+}
+
+-- Thing-hoverdef --
+```go
+type Thing struct {
+ Member string //@Member
+}
+
+func (a.Thing).Method(i int) string
+func (*a.Thing).Method2(i int, j int) (error, string)
+func (a.Thing).Method3()
+```
+
+[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)
+-- Things-definition --
+godef/a/d.go:11:6-12: defined here as ```go
+func a.Things(val []string) []a.Thing
+```
+
+[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)
+-- Things-definition-json --
+{
+ "span": {
+ "uri": "file://godef/a/d.go",
+ "start": {
+ "line": 11,
+ "column": 6,
+ "offset": 148
+ },
+ "end": {
+ "line": 11,
+ "column": 12,
+ "offset": 154
+ }
+ },
+ "description": "```go\nfunc a.Things(val []string) []a.Thing\n```\n\n[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)"
+}
+
+-- Things-hoverdef --
+```go
+func a.Things(val []string) []a.Thing
+```
+
+[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)
+-- eInt-hoverdef --
+```go
+var x int
+```
+-- eInterface-hoverdef --
+```go
+var x interface{}
+```
+-- eString-hoverdef --
+```go
+var x string
+```
diff --git a/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden
new file mode 100644
index 000000000..9ce869848
--- /dev/null
+++ b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden
@@ -0,0 +1,31 @@
+-- myUnclosedIf-definition --
+godef/broken/unclosedIf.go:7:7-19: defined here as ```go
+var myUnclosedIf string
+```
+
+@myUnclosedIf
+-- myUnclosedIf-definition-json --
+{
+ "span": {
+ "uri": "file://godef/broken/unclosedIf.go",
+ "start": {
+ "line": 7,
+ "column": 7,
+ "offset": 68
+ },
+ "end": {
+ "line": 7,
+ "column": 19,
+ "offset": 80
+ }
+ },
+ "description": "```go\nvar myUnclosedIf string\n```\n\n@myUnclosedIf"
+}
+
+-- myUnclosedIf-hoverdef --
+```go
+var myUnclosedIf string
+```
+
+@myUnclosedIf
+
diff --git a/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in
new file mode 100644
index 000000000..0f2cf1b1e
--- /dev/null
+++ b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in
@@ -0,0 +1,9 @@
+package broken
+
+import "fmt"
+
+func unclosedIf() {
+ if false {
+ var myUnclosedIf string //@myUnclosedIf
+ fmt.Printf("s = %v\n", myUnclosedIf) //@godef("my", myUnclosedIf)
+}
diff --git a/gopls/internal/lsp/testdata/good/good0.go b/gopls/internal/lsp/testdata/good/good0.go
new file mode 100644
index 000000000..89450a845
--- /dev/null
+++ b/gopls/internal/lsp/testdata/good/good0.go
@@ -0,0 +1,6 @@
+package good //@diag("package", "no_diagnostics", "", "error")
+
+func stuff() { //@item(good_stuff, "stuff", "func()", "func"),prepare("stu", "stuff", "stuff")
+ x := 5
+ random2(x) //@prepare("dom", "random2", "random2")
+}
diff --git a/gopls/internal/lsp/testdata/good/good1.go b/gopls/internal/lsp/testdata/good/good1.go
new file mode 100644
index 000000000..624d8147a
--- /dev/null
+++ b/gopls/internal/lsp/testdata/good/good1.go
@@ -0,0 +1,21 @@
+package good //@diag("package", "no_diagnostics", "", "error")
+
+import (
+ "golang.org/lsptests/types" //@item(types_import, "types", "\"golang.org/lsptests/types\"", "package")
+)
+
+func random() int { //@item(good_random, "random", "func() int", "func")
+ _ = "random() int" //@prepare("random", "", "")
+ y := 6 + 7 //@prepare("7", "", "")
+ return y //@prepare("return", "","")
+}
+
+func random2(y int) int { //@item(good_random2, "random2", "func(y int) int", "func"),item(good_y_param, "y", "int", "var")
+ //@complete("", good_y_param, types_import, good_random, good_random2, good_stuff)
+ var b types.Bob = &types.X{} //@prepare("ypes","types", "types")
+ if _, ok := b.(*types.X); ok { //@complete("X", X_struct, Y_struct, Bob_interface, CoolAlias)
+ _ = 0 // suppress "empty branch" diagnostic
+ }
+
+ return y
+}
diff --git a/gopls/internal/lsp/testdata/highlights/highlights.go b/gopls/internal/lsp/testdata/highlights/highlights.go
new file mode 100644
index 000000000..55ae68aa1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/highlights/highlights.go
@@ -0,0 +1,151 @@
+package highlights
+
+import (
+ "fmt" //@mark(fmtImp, "\"fmt\""),highlight(fmtImp, fmtImp, fmt1, fmt2, fmt3, fmt4)
+ h2 "net/http" //@mark(hImp, "h2"),highlight(hImp, hImp, hUse)
+ "sort"
+)
+
+type F struct{ bar int } //@mark(barDeclaration, "bar"),highlight(barDeclaration, barDeclaration, bar1, bar2, bar3)
+
+func _() F {
+ return F{
+ bar: 123, //@mark(bar1, "bar"),highlight(bar1, barDeclaration, bar1, bar2, bar3)
+ }
+}
+
+var foo = F{bar: 52} //@mark(fooDeclaration, "foo"),mark(bar2, "bar"),highlight(fooDeclaration, fooDeclaration, fooUse),highlight(bar2, barDeclaration, bar1, bar2, bar3)
+
+func Print() { //@mark(printFunc, "Print"),highlight(printFunc, printFunc, printTest)
+ _ = h2.Client{} //@mark(hUse, "h2"),highlight(hUse, hImp, hUse)
+
+ fmt.Println(foo) //@mark(fooUse, "foo"),highlight(fooUse, fooDeclaration, fooUse),mark(fmt1, "fmt"),highlight(fmt1, fmtImp, fmt1, fmt2, fmt3, fmt4)
+ fmt.Print("yo") //@mark(printSep, "Print"),highlight(printSep, printSep, print1, print2),mark(fmt2, "fmt"),highlight(fmt2, fmtImp, fmt1, fmt2, fmt3, fmt4)
+}
+
+func (x *F) Inc() { //@mark(xRightDecl, "x"),mark(xLeftDecl, " *"),highlight(xRightDecl, xRightDecl, xUse),highlight(xLeftDecl, xRightDecl, xUse)
+ x.bar++ //@mark(xUse, "x"),mark(bar3, "bar"),highlight(xUse, xRightDecl, xUse),highlight(bar3, barDeclaration, bar1, bar2, bar3)
+}
+
+func testFunctions() {
+ fmt.Print("main start") //@mark(print1, "Print"),highlight(print1, printSep, print1, print2),mark(fmt3, "fmt"),highlight(fmt3, fmtImp, fmt1, fmt2, fmt3, fmt4)
+ fmt.Print("ok") //@mark(print2, "Print"),highlight(print2, printSep, print1, print2),mark(fmt4, "fmt"),highlight(fmt4, fmtImp, fmt1, fmt2, fmt3, fmt4)
+ Print() //@mark(printTest, "Print"),highlight(printTest, printFunc, printTest)
+}
+
+func toProtocolHighlight(rngs []int) []DocumentHighlight { //@mark(doc1, "DocumentHighlight"),mark(docRet1, "[]DocumentHighlight"),highlight(doc1, docRet1, doc1, doc2, doc3, result)
+ result := make([]DocumentHighlight, 0, len(rngs)) //@mark(doc2, "DocumentHighlight"),highlight(doc2, doc1, doc2, doc3)
+ for _, rng := range rngs {
+ result = append(result, DocumentHighlight{ //@mark(doc3, "DocumentHighlight"),highlight(doc3, doc1, doc2, doc3)
+ Range: rng,
+ })
+ }
+ return result //@mark(result, "result")
+}
+
+func testForLoops() {
+ for i := 0; i < 10; i++ { //@mark(forDecl1, "for"),highlight(forDecl1, forDecl1, brk1, cont1)
+ if i > 8 {
+ break //@mark(brk1, "break"),highlight(brk1, forDecl1, brk1, cont1)
+ }
+ if i < 2 {
+ for j := 1; j < 10; j++ { //@mark(forDecl2, "for"),highlight(forDecl2, forDecl2, cont2)
+ if j < 3 {
+ for k := 1; k < 10; k++ { //@mark(forDecl3, "for"),highlight(forDecl3, forDecl3, cont3)
+ if k < 3 {
+ continue //@mark(cont3, "continue"),highlight(cont3, forDecl3, cont3)
+ }
+ }
+ continue //@mark(cont2, "continue"),highlight(cont2, forDecl2, cont2)
+ }
+ }
+ continue //@mark(cont1, "continue"),highlight(cont1, forDecl1, brk1, cont1)
+ }
+ }
+
+ arr := []int{}
+ for i := range arr { //@mark(forDecl4, "for"),highlight(forDecl4, forDecl4, brk4, cont4)
+ if i > 8 {
+ break //@mark(brk4, "break"),highlight(brk4, forDecl4, brk4, cont4)
+ }
+ if i < 4 {
+ continue //@mark(cont4, "continue"),highlight(cont4, forDecl4, brk4, cont4)
+ }
+ }
+
+Outer:
+ for i := 0; i < 10; i++ { //@mark(forDecl5, "for"),highlight(forDecl5, forDecl5, brk5, brk6, brk8)
+ break //@mark(brk5, "break"),highlight(brk5, forDecl5, brk5, brk6, brk8)
+ for { //@mark(forDecl6, "for"),highlight(forDecl6, forDecl6, cont5)
+ if i == 1 {
+ break Outer //@mark(brk6, "break Outer"),highlight(brk6, forDecl5, brk5, brk6, brk8)
+ }
+ switch i { //@mark(switch1, "switch"),highlight(switch1, switch1, brk7)
+ case 5:
+ break //@mark(brk7, "break"),highlight(brk7, switch1, brk7)
+ case 6:
+ continue //@mark(cont5, "continue"),highlight(cont5, forDecl6, cont5)
+ case 7:
+ break Outer //@mark(brk8, "break Outer"),highlight(brk8, forDecl5, brk5, brk6, brk8)
+ }
+ }
+ }
+}
+
+func testSwitch() {
+ var i, j int
+
+L1:
+ for { //@mark(forDecl7, "for"),highlight(forDecl7, forDecl7, brk10, cont6)
+ L2:
+ switch i { //@mark(switch2, "switch"),highlight(switch2, switch2, brk11, brk12, brk13)
+ case 1:
+ switch j { //@mark(switch3, "switch"),highlight(switch3, switch3, brk9)
+ case 1:
+ break //@mark(brk9, "break"),highlight(brk9, switch3, brk9)
+ case 2:
+ break L1 //@mark(brk10, "break L1"),highlight(brk10, forDecl7, brk10, cont6)
+ case 3:
+ break L2 //@mark(brk11, "break L2"),highlight(brk11, switch2, brk11, brk12, brk13)
+ default:
+ continue //@mark(cont6, "continue"),highlight(cont6, forDecl7, brk10, cont6)
+ }
+ case 2:
+ break //@mark(brk12, "break"),highlight(brk12, switch2, brk11, brk12, brk13)
+ default:
+ break L2 //@mark(brk13, "break L2"),highlight(brk13, switch2, brk11, brk12, brk13)
+ }
+ }
+}
+
+func testReturn() bool { //@mark(func1, "func"),mark(bool1, "bool"),highlight(func1, func1, fullRet11, fullRet12),highlight(bool1, bool1, false1, bool2, true1)
+ if 1 < 2 {
+ return false //@mark(ret11, "return"),mark(fullRet11, "return false"),mark(false1, "false"),highlight(ret11, func1, fullRet11, fullRet12)
+ }
+ candidates := []int{}
+ sort.SliceStable(candidates, func(i, j int) bool { //@mark(func2, "func"),mark(bool2, "bool"),highlight(func2, func2, fullRet2)
+ return candidates[i] > candidates[j] //@mark(ret2, "return"),mark(fullRet2, "return candidates[i] > candidates[j]"),highlight(ret2, func2, fullRet2)
+ })
+ return true //@mark(ret12, "return"),mark(fullRet12, "return true"),mark(true1, "true"),highlight(ret12, func1, fullRet11, fullRet12)
+}
+
+func testReturnFields() float64 { //@mark(retVal1, "float64"),highlight(retVal1, retVal1, retVal11, retVal21)
+ if 1 < 2 {
+ return 20.1 //@mark(retVal11, "20.1"),highlight(retVal11, retVal1, retVal11, retVal21)
+ }
+ z := 4.3 //@mark(zDecl, "z")
+ return z //@mark(retVal21, "z"),highlight(retVal21, retVal1, retVal11, zDecl, retVal21)
+}
+
+func testReturnMultipleFields() (float32, string) { //@mark(retVal31, "float32"),mark(retVal32, "string"),highlight(retVal31, retVal31, retVal41, retVal51),highlight(retVal32, retVal32, retVal42, retVal52)
+ y := "im a var" //@mark(yDecl, "y"),
+ if 1 < 2 {
+ return 20.1, y //@mark(retVal41, "20.1"),mark(retVal42, "y"),highlight(retVal41, retVal31, retVal41, retVal51),highlight(retVal42, retVal32, yDecl, retVal42, retVal52)
+ }
+ return 4.9, "test" //@mark(retVal51, "4.9"),mark(retVal52, "\"test\""),highlight(retVal51, retVal31, retVal41, retVal51),highlight(retVal52, retVal32, retVal42, retVal52)
+}
+
+func testReturnFunc() int32 { //@mark(retCall, "int32")
+ mulch := 1 //@mark(mulchDec, "mulch"),highlight(mulchDec, mulchDec, mulchRet)
+ return int32(mulch) //@mark(mulchRet, "mulch"),mark(retFunc, "int32"),mark(retTotal, "int32(mulch)"),highlight(mulchRet, mulchDec, mulchRet),highlight(retFunc, retCall, retFunc, retTotal)
+}
diff --git a/gopls/internal/lsp/testdata/implementation/implementation.go b/gopls/internal/lsp/testdata/implementation/implementation.go
new file mode 100644
index 000000000..4c1a22dd4
--- /dev/null
+++ b/gopls/internal/lsp/testdata/implementation/implementation.go
@@ -0,0 +1,37 @@
+package implementation
+
+import "golang.org/lsptests/implementation/other"
+
+type ImpP struct{} //@ImpP,implementations("ImpP", Laugher, OtherLaugher)
+
+func (*ImpP) Laugh() { //@mark(LaughP, "Laugh"),implementations("Laugh", Laugh, OtherLaugh)
+}
+
+type ImpS struct{} //@ImpS,implementations("ImpS", Laugher, OtherLaugher)
+
+func (ImpS) Laugh() { //@mark(LaughS, "Laugh"),implementations("Laugh", Laugh, OtherLaugh)
+}
+
+type Laugher interface { //@Laugher,implementations("Laugher", ImpP, OtherImpP, ImpS, OtherImpS, embedsImpP)
+ Laugh() //@Laugh,implementations("Laugh", LaughP, OtherLaughP, LaughS, OtherLaughS)
+}
+
+type Foo struct { //@implementations("Foo", Joker)
+ other.Foo
+}
+
+type Joker interface { //@Joker
+ Joke() //@Joke,implementations("Joke", ImpJoker)
+}
+
+type cryer int //@implementations("cryer", Cryer)
+
+func (cryer) Cry(other.CryType) {} //@mark(CryImpl, "Cry"),implementations("Cry", Cry)
+
+type Empty interface{} //@implementations("Empty")
+
+var _ interface{ Joke() } //@implementations("Joke", ImpJoker)
+
+type embedsImpP struct { //@embedsImpP
+ ImpP //@implementations("ImpP", Laugher, OtherLaugher)
+}
diff --git a/gopls/internal/lsp/testdata/implementation/implementation_generics.go b/gopls/internal/lsp/testdata/implementation/implementation_generics.go
new file mode 100644
index 000000000..1f02d166b
--- /dev/null
+++ b/gopls/internal/lsp/testdata/implementation/implementation_generics.go
@@ -0,0 +1,16 @@
+//go:build go1.18
+// +build go1.18
+
+package implementation
+
+// -- generics --
+
+type GenIface[T any] interface { //@mark(GenIface, "GenIface"),implementations("GenIface", GC)
+ F(int, string, T) //@mark(GenIfaceF, "F"),implementations("F", GCF)
+}
+
+type GenConc[U any] int //@mark(GenConc, "GenConc"),implementations("GenConc", GI)
+
+func (GenConc[V]) F(int, string, V) {} //@mark(GenConcF, "F"),implementations("F", GIF)
+
+type GenConcString struct{ GenConc[string] } //@mark(GenConcString, "GenConcString"),implementations(GenConcString, GIString)
diff --git a/gopls/internal/lsp/testdata/implementation/other/other.go b/gopls/internal/lsp/testdata/implementation/other/other.go
new file mode 100644
index 000000000..aff825e91
--- /dev/null
+++ b/gopls/internal/lsp/testdata/implementation/other/other.go
@@ -0,0 +1,27 @@
+package other
+
+type ImpP struct{} //@mark(OtherImpP, "ImpP")
+
+func (*ImpP) Laugh() { //@mark(OtherLaughP, "Laugh")
+}
+
+type ImpS struct{} //@mark(OtherImpS, "ImpS")
+
+func (ImpS) Laugh() { //@mark(OtherLaughS, "Laugh")
+}
+
+type ImpI interface { //@mark(OtherLaugher, "ImpI")
+ Laugh() //@mark(OtherLaugh, "Laugh")
+}
+
+type Foo struct { //@implementations("Foo", Joker)
+}
+
+func (Foo) Joke() { //@mark(ImpJoker, "Joke"),implementations("Joke", Joke)
+}
+
+type CryType int
+
+type Cryer interface { //@Cryer
+ Cry(CryType) //@Cry,implementations("Cry", CryImpl)
+}
diff --git a/gopls/internal/lsp/testdata/implementation/other/other_generics.go b/gopls/internal/lsp/testdata/implementation/other/other_generics.go
new file mode 100644
index 000000000..4b4c29f7d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/implementation/other/other_generics.go
@@ -0,0 +1,16 @@
+//go:build go1.18
+// +build go1.18
+
+package other
+
+// -- generics (limited support) --
+
+type GI[T any] interface { //@mark(GI, "GI"),implementations("GI", GenConc)
+ F(int, string, T) //@mark(GIF, "F"),implementations("F", GenConcF)
+}
+
+type GIString GI[string] //@mark(GIString, "GIString"),implementations("GIString", GenConcString)
+
+type GC[U any] int //@mark(GC, "GC"),implementations("GC", GenIface)
+
+func (GC[V]) F(int, string, V) {} //@mark(GCF, "F"),implementations("F", GenIfaceF)
diff --git a/gopls/internal/lsp/testdata/implementation/other/other_test.go b/gopls/internal/lsp/testdata/implementation/other/other_test.go
new file mode 100644
index 000000000..846e0d591
--- /dev/null
+++ b/gopls/internal/lsp/testdata/implementation/other/other_test.go
@@ -0,0 +1,10 @@
+package other
+
+import (
+ "testing"
+)
+
+// This exists so the other.test package comes into existence.
+
+func TestOther(t *testing.T) {
+}
diff --git a/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in b/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in
new file mode 100644
index 000000000..2f4cbada1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in
@@ -0,0 +1,42 @@
+package importedcomplit
+
+import (
+ "golang.org/lsptests/foo"
+
+ // import completions
+ "fm" //@complete("\" //", fmtImport)
+ "go/pars" //@complete("\" //", parserImport)
+ "golang.org/lsptests/signa" //@complete("na\" //", signatureImport)
+ "golang.org/lspte" //@complete("\" //", lsptestsImport)
+ "crypto/elli" //@complete("\" //", cryptoImport)
+ "golang.org/lsptests/sign" //@complete("\" //", signatureImport)
+ "golang.org/lsptests/sign" //@complete("ests", lsptestsImport)
+ namedParser "go/pars" //@complete("\" //", parserImport)
+)
+
+func _() {
+ var V int //@item(icVVar, "V", "int", "var")
+ _ = foo.StructFoo{V} //@complete("}", Value, icVVar)
+}
+
+func _() {
+ var (
+ aa string //@item(icAAVar, "aa", "string", "var")
+ ab int //@item(icABVar, "ab", "int", "var")
+ )
+
+ _ = foo.StructFoo{a} //@complete("}", abVar, aaVar)
+
+ var s struct {
+ AA string //@item(icFieldAA, "AA", "string", "field")
+ AB int //@item(icFieldAB, "AB", "int", "field")
+ }
+
+ _ = foo.StructFoo{s.} //@complete("}", icFieldAB, icFieldAA)
+}
+
+/* "fmt" */ //@item(fmtImport, "fmt", "\"fmt\"", "package")
+/* "go/parser" */ //@item(parserImport, "parser", "\"go/parser\"", "package")
+/* "golang.org/lsptests/signature" */ //@item(signatureImport, "signature", "\"golang.org/lsptests/signature\"", "package")
+/* "golang.org/lsptests/" */ //@item(lsptestsImport, "lsptests/", "\"golang.org/lsptests/\"", "package")
+/* "crypto/elliptic" */ //@item(cryptoImport, "elliptic", "\"crypto/elliptic\"", "package")
diff --git a/gopls/internal/lsp/testdata/imports/add_import.go.golden b/gopls/internal/lsp/testdata/imports/add_import.go.golden
new file mode 100644
index 000000000..16af110a0
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/add_import.go.golden
@@ -0,0 +1,13 @@
+-- goimports --
+package imports //@import("package")
+
+import (
+ "bytes"
+ "fmt"
+)
+
+func _() {
+ fmt.Println("")
+ bytes.NewBuffer(nil)
+}
+
diff --git a/gopls/internal/lsp/testdata/imports/add_import.go.in b/gopls/internal/lsp/testdata/imports/add_import.go.in
new file mode 100644
index 000000000..7928e6f71
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/add_import.go.in
@@ -0,0 +1,10 @@
+package imports //@import("package")
+
+import (
+ "fmt"
+)
+
+func _() {
+ fmt.Println("")
+ bytes.NewBuffer(nil)
+}
diff --git a/gopls/internal/lsp/testdata/imports/good_imports.go.golden b/gopls/internal/lsp/testdata/imports/good_imports.go.golden
new file mode 100644
index 000000000..2abdae4d7
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/good_imports.go.golden
@@ -0,0 +1,9 @@
+-- goimports --
+package imports //@import("package")
+
+import "fmt"
+
+func _() {
+fmt.Println("")
+}
+
diff --git a/gopls/internal/lsp/testdata/imports/good_imports.go.in b/gopls/internal/lsp/testdata/imports/good_imports.go.in
new file mode 100644
index 000000000..a03c06c6d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/good_imports.go.in
@@ -0,0 +1,7 @@
+package imports //@import("package")
+
+import "fmt"
+
+func _() {
+fmt.Println("")
+}
diff --git a/gopls/internal/lsp/testdata/imports/issue35458.go.golden b/gopls/internal/lsp/testdata/imports/issue35458.go.golden
new file mode 100644
index 000000000..f0772606b
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/issue35458.go.golden
@@ -0,0 +1,20 @@
+-- goimports --
+// package doc
+package imports //@import("package")
+
+
+
+
+
+
+func _() {
+ println("Hello, world!")
+}
+
+
+
+
+
+
+
+
diff --git a/gopls/internal/lsp/testdata/imports/issue35458.go.in b/gopls/internal/lsp/testdata/imports/issue35458.go.in
new file mode 100644
index 000000000..7420c212c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/issue35458.go.in
@@ -0,0 +1,23 @@
+
+
+
+
+
+// package doc
+package imports //@import("package")
+
+
+
+
+
+
+func _() {
+ println("Hello, world!")
+}
+
+
+
+
+
+
+
diff --git a/gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden
new file mode 100644
index 000000000..d37a6c751
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden
@@ -0,0 +1,9 @@
+-- goimports --
+package imports //@import("package")
+
+import "fmt"
+
+func _() {
+ fmt.Println("")
+}
+
diff --git a/gopls/internal/lsp/testdata/imports/multiple_blocks.go.in b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.in
new file mode 100644
index 000000000..3f2fb99ea
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.in
@@ -0,0 +1,9 @@
+package imports //@import("package")
+
+import "fmt"
+
+import "bytes"
+
+func _() {
+ fmt.Println("")
+}
diff --git a/gopls/internal/lsp/testdata/imports/needs_imports.go.golden b/gopls/internal/lsp/testdata/imports/needs_imports.go.golden
new file mode 100644
index 000000000..fd6032874
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/needs_imports.go.golden
@@ -0,0 +1,13 @@
+-- goimports --
+package imports //@import("package")
+
+import (
+ "fmt"
+ "log"
+)
+
+func goodbye() {
+ fmt.Printf("HI")
+ log.Printf("byeeeee")
+}
+
diff --git a/gopls/internal/lsp/testdata/imports/needs_imports.go.in b/gopls/internal/lsp/testdata/imports/needs_imports.go.in
new file mode 100644
index 000000000..949d56a64
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/needs_imports.go.in
@@ -0,0 +1,6 @@
+package imports //@import("package")
+
+func goodbye() {
+ fmt.Printf("HI")
+ log.Printf("byeeeee")
+}
diff --git a/gopls/internal/lsp/testdata/imports/remove_import.go.golden b/gopls/internal/lsp/testdata/imports/remove_import.go.golden
new file mode 100644
index 000000000..3df80882c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/remove_import.go.golden
@@ -0,0 +1,11 @@
+-- goimports --
+package imports //@import("package")
+
+import (
+ "fmt"
+)
+
+func _() {
+ fmt.Println("")
+}
+
diff --git a/gopls/internal/lsp/testdata/imports/remove_import.go.in b/gopls/internal/lsp/testdata/imports/remove_import.go.in
new file mode 100644
index 000000000..09060bada
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/remove_import.go.in
@@ -0,0 +1,10 @@
+package imports //@import("package")
+
+import (
+ "bytes"
+ "fmt"
+)
+
+func _() {
+ fmt.Println("")
+}
diff --git a/gopls/internal/lsp/testdata/imports/remove_imports.go.golden b/gopls/internal/lsp/testdata/imports/remove_imports.go.golden
new file mode 100644
index 000000000..530c8c09f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/remove_imports.go.golden
@@ -0,0 +1,6 @@
+-- goimports --
+package imports //@import("package")
+
+func _() {
+}
+
diff --git a/gopls/internal/lsp/testdata/imports/remove_imports.go.in b/gopls/internal/lsp/testdata/imports/remove_imports.go.in
new file mode 100644
index 000000000..44d065f25
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/remove_imports.go.in
@@ -0,0 +1,9 @@
+package imports //@import("package")
+
+import (
+ "bytes"
+ "fmt"
+)
+
+func _() {
+}
diff --git a/gopls/internal/lsp/testdata/imports/two_lines.go.golden b/gopls/internal/lsp/testdata/imports/two_lines.go.golden
new file mode 100644
index 000000000..ec118a4dd
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/two_lines.go.golden
@@ -0,0 +1,4 @@
+-- goimports --
+package main
+func main() {} //@import("main")
+
diff --git a/gopls/internal/lsp/testdata/imports/two_lines.go.in b/gopls/internal/lsp/testdata/imports/two_lines.go.in
new file mode 100644
index 000000000..eee534569
--- /dev/null
+++ b/gopls/internal/lsp/testdata/imports/two_lines.go.in
@@ -0,0 +1,2 @@
+package main
+func main() {} //@import("main")
diff --git a/gopls/internal/lsp/testdata/index/index.go b/gopls/internal/lsp/testdata/index/index.go
new file mode 100644
index 000000000..a2656893c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/index/index.go
@@ -0,0 +1,25 @@
+package index
+
+func _() {
+ var (
+ aa = "123" //@item(indexAA, "aa", "string", "var")
+ ab = 123 //@item(indexAB, "ab", "int", "var")
+ )
+
+ var foo [1]int
+ foo[a] //@complete("]", indexAB, indexAA)
+ foo[:a] //@complete("]", indexAB, indexAA)
+ a[:a] //@complete("[", indexAA, indexAB)
+ a[a] //@complete("[", indexAA, indexAB)
+
+ var bar map[string]int
+ bar[a] //@complete("]", indexAA, indexAB)
+
+ type myMap map[string]int
+ var baz myMap
+ baz[a] //@complete("]", indexAA, indexAB)
+
+ type myInt int
+ var mi myInt //@item(indexMyInt, "mi", "myInt", "var")
+ foo[m] //@snippet("]", indexMyInt, "mi", "mi")
+}
diff --git a/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go
new file mode 100644
index 000000000..b05c95ec8
--- /dev/null
+++ b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go
@@ -0,0 +1,27 @@
+package inlayHint //@inlayHint("package")
+
+import "fmt"
+
+func fieldNames() {
+ for _, c := range []struct {
+ in, want string
+ }{
+ struct{ in, want string }{"Hello, world", "dlrow ,olleH"},
+ {"Hello, 世界", "界世 ,olleH"},
+ {"", ""},
+ } {
+ fmt.Println(c.in == c.want)
+ }
+}
+
+func fieldNamesPointers() {
+ for _, c := range []*struct {
+ in, want string
+ }{
+ &struct{ in, want string }{"Hello, world", "dlrow ,olleH"},
+ {"Hello, 世界", "界世 ,olleH"},
+ {"", ""},
+ } {
+ fmt.Println(c.in == c.want)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden
new file mode 100644
index 000000000..eb2febdb6
--- /dev/null
+++ b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden
@@ -0,0 +1,29 @@
+-- inlayHint --
+package inlayHint //@inlayHint("package")
+
+import "fmt"
+
+func fieldNames() {
+ for _< int>, c< struct{in string; want string}> := range []struct {
+ in, want string
+ }{
+ struct{ in, want string }{<in: >"Hello, world", <want: >"dlrow ,olleH"},
+ <struct{in string; want string}>{<in: >"Hello, 世界", <want: >"界世 ,olleH"},
+ <struct{in string; want string}>{<in: >"", <want: >""},
+ } {
+ fmt.Println(<a...: >c.in == c.want)
+ }
+}
+
+func fieldNamesPointers() {
+ for _< int>, c< *struct{in string; want string}> := range []*struct {
+ in, want string
+ }{
+ &struct{ in, want string }{<in: >"Hello, world", <want: >"dlrow ,olleH"},
+ <&struct{in string; want string}>{<in: >"Hello, 世界", <want: >"界世 ,olleH"},
+ <&struct{in string; want string}>{<in: >"", <want: >""},
+ } {
+ fmt.Println(<a...: >c.in == c.want)
+ }
+}
+
diff --git a/gopls/internal/lsp/testdata/inlay_hint/constant_values.go b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go
new file mode 100644
index 000000000..e3339b0f3
--- /dev/null
+++ b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go
@@ -0,0 +1,45 @@
+package inlayHint //@inlayHint("package")
+
+const True = true
+
+type Kind int
+
+const (
+ KindNone Kind = iota
+ KindPrint
+ KindPrintf
+ KindErrorf
+)
+
+const (
+ u = iota * 4
+ v float64 = iota * 42
+ w = iota * 42
+)
+
+const (
+ a, b = 1, 2
+ c, d
+ e, f = 5 * 5, "hello" + "world"
+ g, h
+ i, j = true, f
+)
+
+// No hint
+const (
+ Int = 3
+ Float = 3.14
+ Bool = true
+ Rune = '3'
+ Complex = 2.7i
+ String = "Hello, world!"
+)
+
+var (
+ varInt = 3
+ varFloat = 3.14
+ varBool = true
+ varRune = '3' + '4'
+ varComplex = 2.7i
+ varString = "Hello, world!"
+)
diff --git a/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden
new file mode 100644
index 000000000..edc46debc
--- /dev/null
+++ b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden
@@ -0,0 +1,47 @@
+-- inlayHint --
+package inlayHint //@inlayHint("package")
+
+const True = true
+
+type Kind int
+
+const (
+ KindNone Kind = iota< = 0>
+ KindPrint< = 1>
+ KindPrintf< = 2>
+ KindErrorf< = 3>
+)
+
+const (
+ u = iota * 4< = 0>
+ v float64 = iota * 42< = 42>
+ w = iota * 42< = 84>
+)
+
+const (
+ a, b = 1, 2
+ c, d< = 1, 2>
+ e, f = 5 * 5, "hello" + "world"< = 25, "helloworld">
+ g, h< = 25, "helloworld">
+ i, j = true, f< = true, "helloworld">
+)
+
+// No hint
+const (
+ Int = 3
+ Float = 3.14
+ Bool = true
+ Rune = '3'
+ Complex = 2.7i
+ String = "Hello, world!"
+)
+
+var (
+ varInt = 3
+ varFloat = 3.14
+ varBool = true
+ varRune = '3' + '4'
+ varComplex = 2.7i
+ varString = "Hello, world!"
+)
+
diff --git a/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go
new file mode 100644
index 000000000..0d930e5d4
--- /dev/null
+++ b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go
@@ -0,0 +1,50 @@
+package inlayHint //@inlayHint("package")
+
+import "fmt"
+
+func hello(name string) string {
+ return "Hello " + name
+}
+
+func helloWorld() string {
+ return hello("World")
+}
+
+type foo struct{}
+
+func (*foo) bar(baz string, qux int) int {
+ if baz != "" {
+ return qux + 1
+ }
+ return qux
+}
+
+func kase(foo int, bar bool, baz ...string) {
+ fmt.Println(foo, bar, baz)
+}
+
+func kipp(foo string, bar, baz string) {
+ fmt.Println(foo, bar, baz)
+}
+
+func plex(foo, bar string, baz string) {
+ fmt.Println(foo, bar, baz)
+}
+
+func tars(foo string, bar, baz string) {
+ fmt.Println(foo, bar, baz)
+}
+
+func foobar() {
+ var x foo
+ x.bar("", 1)
+ kase(0, true, "c", "d", "e")
+ kipp("a", "b", "c")
+ plex("a", "b", "c")
+ tars("a", "b", "c")
+ foo, bar, baz := "a", "b", "c"
+ kipp(foo, bar, baz)
+ plex("a", bar, baz)
+ tars(foo+foo, (bar), "c")
+
+}
diff --git a/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden
new file mode 100644
index 000000000..4e93a4f92
--- /dev/null
+++ b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden
@@ -0,0 +1,52 @@
+-- inlayHint --
+package inlayHint //@inlayHint("package")
+
+import "fmt"
+
+func hello(name string) string {
+ return "Hello " + name
+}
+
+func helloWorld() string {
+ return hello(<name: >"World")
+}
+
+type foo struct{}
+
+func (*foo) bar(baz string, qux int) int {
+ if baz != "" {
+ return qux + 1
+ }
+ return qux
+}
+
+func kase(foo int, bar bool, baz ...string) {
+ fmt.Println(<a...: >foo, bar, baz)
+}
+
+func kipp(foo string, bar, baz string) {
+ fmt.Println(<a...: >foo, bar, baz)
+}
+
+func plex(foo, bar string, baz string) {
+ fmt.Println(<a...: >foo, bar, baz)
+}
+
+func tars(foo string, bar, baz string) {
+ fmt.Println(<a...: >foo, bar, baz)
+}
+
+func foobar() {
+ var x foo
+ x.bar(<baz: >"", <qux: >1)
+ kase(<foo: >0, <bar: >true, <baz...: >"c", "d", "e")
+ kipp(<foo: >"a", <bar: >"b", <baz: >"c")
+ plex(<foo: >"a", <bar: >"b", <baz: >"c")
+ tars(<foo: >"a", <bar: >"b", <baz: >"c")
+ foo< string>, bar< string>, baz< string> := "a", "b", "c"
+ kipp(foo, bar, baz)
+ plex(<foo: >"a", bar, baz)
+ tars(<foo: >foo+foo, <bar: >(bar), <baz: >"c")
+
+}
+
diff --git a/gopls/internal/lsp/testdata/inlay_hint/type_params.go b/gopls/internal/lsp/testdata/inlay_hint/type_params.go
new file mode 100644
index 000000000..3a3c7e537
--- /dev/null
+++ b/gopls/internal/lsp/testdata/inlay_hint/type_params.go
@@ -0,0 +1,45 @@
+//go:build go1.18
+// +build go1.18
+
+package inlayHint //@inlayHint("package")
+
+func main() {
+ ints := map[string]int64{
+ "first": 34,
+ "second": 12,
+ }
+
+ floats := map[string]float64{
+ "first": 35.98,
+ "second": 26.99,
+ }
+
+ SumIntsOrFloats[string, int64](ints)
+ SumIntsOrFloats[string, float64](floats)
+
+ SumIntsOrFloats(ints)
+ SumIntsOrFloats(floats)
+
+ SumNumbers(ints)
+ SumNumbers(floats)
+}
+
+type Number interface {
+ int64 | float64
+}
+
+func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
+ var s V
+ for _, v := range m {
+ s += v
+ }
+ return s
+}
+
+func SumNumbers[K comparable, V Number](m map[K]V) V {
+ var s V
+ for _, v := range m {
+ s += v
+ }
+ return s
+}
diff --git a/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden b/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden
new file mode 100644
index 000000000..4819963b7
--- /dev/null
+++ b/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden
@@ -0,0 +1,47 @@
+-- inlayHint --
+//go:build go1.18
+// +build go1.18
+
+package inlayHint //@inlayHint("package")
+
+func main() {
+ ints< map[string]int64> := map[string]int64{
+ "first": 34,
+ "second": 12,
+ }
+
+ floats< map[string]float64> := map[string]float64{
+ "first": 35.98,
+ "second": 26.99,
+ }
+
+ SumIntsOrFloats[string, int64](<m: >ints)
+ SumIntsOrFloats[string, float64](<m: >floats)
+
+ SumIntsOrFloats<[string, int64]>(<m: >ints)
+ SumIntsOrFloats<[string, float64]>(<m: >floats)
+
+ SumNumbers<[string, int64]>(<m: >ints)
+ SumNumbers<[string, float64]>(<m: >floats)
+}
+
+type Number interface {
+ int64 | float64
+}
+
+func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
+ var s V
+ for _< K>, v< V> := range m {
+ s += v
+ }
+ return s
+}
+
+func SumNumbers[K comparable, V Number](m map[K]V) V {
+ var s V
+ for _< K>, v< V> := range m {
+ s += v
+ }
+ return s
+}
+
diff --git a/gopls/internal/lsp/testdata/inlay_hint/variable_types.go b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go
new file mode 100644
index 000000000..219af7059
--- /dev/null
+++ b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go
@@ -0,0 +1,20 @@
+package inlayHint //@inlayHint("package")
+
+func assignTypes() {
+ i, j := 0, len([]string{})-1
+ println(i, j)
+}
+
+func rangeTypes() {
+ for k, v := range []string{} {
+ println(k, v)
+ }
+}
+
+func funcLitType() {
+ myFunc := func(a string) string { return "" }
+}
+
+func compositeLitType() {
+ foo := map[string]interface{}{"": ""}
+}
diff --git a/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden
new file mode 100644
index 000000000..6039950d5
--- /dev/null
+++ b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden
@@ -0,0 +1,22 @@
+-- inlayHint --
+package inlayHint //@inlayHint("package")
+
+func assignTypes() {
+ i< int>, j< int> := 0, len([]string{})-1
+ println(i, j)
+}
+
+func rangeTypes() {
+ for k< int>, v< string> := range []string{} {
+ println(k, v)
+ }
+}
+
+func funcLitType() {
+ myFunc< func(a string) string> := func(a string) string { return "" }
+}
+
+func compositeLitType() {
+ foo< map[string]interface{}> := map[string]interface{}{"": ""}
+}
+
diff --git a/gopls/internal/lsp/testdata/interfacerank/interface_rank.go b/gopls/internal/lsp/testdata/interfacerank/interface_rank.go
new file mode 100644
index 000000000..acb5a42e0
--- /dev/null
+++ b/gopls/internal/lsp/testdata/interfacerank/interface_rank.go
@@ -0,0 +1,23 @@
+package interfacerank
+
+type foo interface {
+ foo()
+}
+
+type fooImpl int
+
+func (*fooImpl) foo() {}
+
+func wantsFoo(foo) {}
+
+func _() {
+ var (
+ aa string //@item(irAA, "aa", "string", "var")
+ ab *fooImpl //@item(irAB, "ab", "*fooImpl", "var")
+ )
+
+ wantsFoo(a) //@complete(")", irAB, irAA)
+
+ var ac fooImpl //@item(irAC, "ac", "fooImpl", "var")
+ wantsFoo(&a) //@complete(")", irAC, irAA, irAB)
+}
diff --git a/gopls/internal/lsp/testdata/issues/issue56505.go b/gopls/internal/lsp/testdata/issues/issue56505.go
new file mode 100644
index 000000000..8c641bfb8
--- /dev/null
+++ b/gopls/internal/lsp/testdata/issues/issue56505.go
@@ -0,0 +1,8 @@
+package issues
+
+// Test for golang/go#56505: completion on variables of type *error should not
+// panic.
+func _() {
+ var e *error
+ e.x //@complete(" //")
+}
diff --git a/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in b/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in
new file mode 100644
index 000000000..3833081c4
--- /dev/null
+++ b/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in
@@ -0,0 +1,31 @@
+package keywords
+
+// non-matching candidate - shouldn't show up as completion
+var apple = "apple"
+
+func _() {
+ foo.bar() // insert some extra statements to exercise our AST surgery
+ variance := 123 //@item(kwVariance, "variance", "int", "var")
+ foo.bar()
+ println(var) //@complete(")", kwVariance)
+}
+
+func _() {
+ foo.bar()
+ var s struct { variance int } //@item(kwVarianceField, "variance", "int", "field")
+ foo.bar()
+ s.var //@complete(" //", kwVarianceField)
+}
+
+func _() {
+ channel := 123 //@item(kwChannel, "channel", "int", "var")
+ chan //@complete(" //", kwChannel)
+ foo.bar()
+}
+
+func _() {
+ foo.bar()
+ var typeName string //@item(kwTypeName, "typeName", "string", "var")
+ foo.bar()
+ type //@complete(" //", kwTypeName)
+}
diff --git a/gopls/internal/lsp/testdata/keywords/empty_select.go b/gopls/internal/lsp/testdata/keywords/empty_select.go
new file mode 100644
index 000000000..17ca3ec9d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/keywords/empty_select.go
@@ -0,0 +1,7 @@
+package keywords
+
+func _() {
+ select {
+ c //@complete(" //", case)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/keywords/empty_switch.go b/gopls/internal/lsp/testdata/keywords/empty_switch.go
new file mode 100644
index 000000000..2004d5541
--- /dev/null
+++ b/gopls/internal/lsp/testdata/keywords/empty_switch.go
@@ -0,0 +1,11 @@
+package keywords
+
+func _() {
+ switch {
+ //@complete("", case, default)
+ }
+
+ switch test.(type) {
+ d //@complete(" //", default)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/keywords/keywords.go b/gopls/internal/lsp/testdata/keywords/keywords.go
new file mode 100644
index 000000000..0bcaa63bf
--- /dev/null
+++ b/gopls/internal/lsp/testdata/keywords/keywords.go
@@ -0,0 +1,100 @@
+package keywords
+
+//@rank("", type),rank("", func),rank("", var),rank("", const),rank("", import)
+
+func _() {
+ var test int //@rank(" //", int, interface)
+ var tChan chan int
+ var _ m //@complete(" //", map)
+ var _ f //@complete(" //", func)
+ var _ c //@complete(" //", chan)
+
+ var _ str //@rank(" //", string, struct)
+
+ type _ int //@rank(" //", interface, int)
+
+ type _ str //@rank(" //", struct, string)
+
+ switch test {
+ case 1: // TODO: trying to complete case here will break because the parser won't return *ast.Ident
+ b //@complete(" //", break)
+ case 2:
+ f //@complete(" //", fallthrough, for)
+ r //@complete(" //", return)
+ d //@complete(" //", default, defer)
+ c //@complete(" //", case, const)
+ }
+
+ switch test.(type) {
+ case fo: //@complete(":")
+ case int:
+ b //@complete(" //", break)
+ case int32:
+ f //@complete(" //", for)
+ d //@complete(" //", default, defer)
+ r //@complete(" //", return)
+ c //@complete(" //", case, const)
+ }
+
+ select {
+ case <-tChan:
+ b //@complete(" //", break)
+ c //@complete(" //", case, const)
+ }
+
+ for index := 0; index < test; index++ {
+ c //@complete(" //", const, continue)
+ b //@complete(" //", break)
+ }
+
+ for range []int{} {
+ c //@complete(" //", const, continue)
+ b //@complete(" //", break)
+ }
+
+ // Test function level keywords
+
+ //Using 2 characters to test because map output order is random
+ sw //@complete(" //", switch)
+ se //@complete(" //", select)
+
+ f //@complete(" //", for)
+ d //@complete(" //", defer)
+ g //@rank(" //", go),rank(" //", goto)
+ r //@complete(" //", return)
+ i //@complete(" //", if)
+ e //@complete(" //", else)
+ v //@complete(" //", var)
+ c //@complete(" //", const)
+
+ for i := r //@complete(" //", range)
+}
+
+/* package */ //@item(package, "package", "", "keyword")
+/* import */ //@item(import, "import", "", "keyword")
+/* func */ //@item(func, "func", "", "keyword")
+/* type */ //@item(type, "type", "", "keyword")
+/* var */ //@item(var, "var", "", "keyword")
+/* const */ //@item(const, "const", "", "keyword")
+/* break */ //@item(break, "break", "", "keyword")
+/* default */ //@item(default, "default", "", "keyword")
+/* case */ //@item(case, "case", "", "keyword")
+/* defer */ //@item(defer, "defer", "", "keyword")
+/* go */ //@item(go, "go", "", "keyword")
+/* for */ //@item(for, "for", "", "keyword")
+/* if */ //@item(if, "if", "", "keyword")
+/* else */ //@item(else, "else", "", "keyword")
+/* switch */ //@item(switch, "switch", "", "keyword")
+/* select */ //@item(select, "select", "", "keyword")
+/* fallthrough */ //@item(fallthrough, "fallthrough", "", "keyword")
+/* continue */ //@item(continue, "continue", "", "keyword")
+/* return */ //@item(return, "return", "", "keyword")
+/* var */ //@item(var, "var", "", "keyword")
+/* const */ //@item(const, "const", "", "keyword")
+/* goto */ //@item(goto, "goto", "", "keyword")
+/* struct */ //@item(struct, "struct", "", "keyword")
+/* interface */ //@item(interface, "interface", "", "keyword")
+/* map */ //@item(map, "map", "", "keyword")
+/* func */ //@item(func, "func", "", "keyword")
+/* chan */ //@item(chan, "chan", "", "keyword")
+/* range */ //@item(range, "range", "", "keyword")
diff --git a/gopls/internal/lsp/testdata/labels/labels.go b/gopls/internal/lsp/testdata/labels/labels.go
new file mode 100644
index 000000000..b9effb6d0
--- /dev/null
+++ b/gopls/internal/lsp/testdata/labels/labels.go
@@ -0,0 +1,49 @@
+package labels
+
+func _() {
+ goto F //@complete(" //", label1, label5)
+
+Foo1: //@item(label1, "Foo1", "label", "const")
+ for a, b := range []int{} {
+ Foo2: //@item(label2, "Foo2", "label", "const")
+ switch {
+ case true:
+ break F //@complete(" //", label2, label1)
+
+ continue F //@complete(" //", label1)
+
+ {
+ FooUnjumpable:
+ }
+
+ goto F //@complete(" //", label1, label2, label4, label5)
+
+ func() {
+ goto F //@complete(" //", label3)
+
+ break F //@complete(" //")
+
+ continue F //@complete(" //")
+
+ Foo3: //@item(label3, "Foo3", "label", "const")
+ }()
+ }
+
+ Foo4: //@item(label4, "Foo4", "label", "const")
+ switch interface{}(a).(type) {
+ case int:
+ break F //@complete(" //", label4, label1)
+ }
+ }
+
+ break F //@complete(" //")
+
+ continue F //@complete(" //")
+
+Foo5: //@item(label5, "Foo5", "label", "const")
+ for {
+ break F //@complete(" //", label5)
+ }
+
+ return
+}
diff --git a/gopls/internal/lsp/testdata/links/links.go b/gopls/internal/lsp/testdata/links/links.go
new file mode 100644
index 000000000..378134341
--- /dev/null
+++ b/gopls/internal/lsp/testdata/links/links.go
@@ -0,0 +1,26 @@
+package links
+
+import (
+ "fmt" //@link(`fmt`,"https://pkg.go.dev/fmt")
+
+ "golang.org/lsptests/foo" //@link(`golang.org/lsptests/foo`,`https://pkg.go.dev/golang.org/lsptests/foo`)
+
+ _ "database/sql" //@link(`database/sql`, `https://pkg.go.dev/database/sql`)
+)
+
+var (
+ _ fmt.Formatter
+ _ foo.StructFoo
+ _ errors.Formatter
+)
+
+// Foo function
+func Foo() string {
+ /*https://example.com/comment */ //@link("https://example.com/comment","https://example.com/comment")
+
+ url := "https://example.com/string_literal" //@link("https://example.com/string_literal","https://example.com/string_literal")
+ return url
+
+ // TODO(golang/go#1234): Link the relevant issue. //@link("golang/go#1234", "https://github.com/golang/go/issues/1234")
+ // TODO(microsoft/vscode-go#12): Another issue. //@link("microsoft/vscode-go#12", "https://github.com/microsoft/vscode-go/issues/12")
+}
diff --git a/gopls/internal/lsp/testdata/maps/maps.go.in b/gopls/internal/lsp/testdata/maps/maps.go.in
new file mode 100644
index 000000000..eeb5576b0
--- /dev/null
+++ b/gopls/internal/lsp/testdata/maps/maps.go.in
@@ -0,0 +1,18 @@
+package maps
+
+func _() {
+ var aVar int //@item(mapVar, "aVar", "int", "var")
+
+ // not comparabale
+ type aSlice []int //@item(mapSliceType, "aSlice", "[]int", "type")
+
+ *aSlice //@item(mapSliceTypePtr, "*aSlice", "[]int", "type")
+
+ // comparable
+ type aStruct struct{} //@item(mapStructType, "aStruct", "struct{...}", "struct")
+
+ map[]a{} //@complete("]", mapSliceType, mapStructType),snippet("]", mapSliceType, "*aSlice", "*aSlice")
+
+ map[a]a{} //@complete("]", mapSliceType, mapStructType)
+ map[a]a{} //@complete("{", mapSliceType, mapStructType)
+}
diff --git a/gopls/internal/lsp/testdata/missingfunction/channels.go b/gopls/internal/lsp/testdata/missingfunction/channels.go
new file mode 100644
index 000000000..303770cd7
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/channels.go
@@ -0,0 +1,9 @@
+package missingfunction
+
+func channels(s string) {
+ undefinedChannels(c()) //@suggestedfix("undefinedChannels", "quickfix", "")
+}
+
+func c() (<-chan string, chan string) {
+ return make(<-chan string), make(chan string)
+}
diff --git a/gopls/internal/lsp/testdata/missingfunction/channels.go.golden b/gopls/internal/lsp/testdata/missingfunction/channels.go.golden
new file mode 100644
index 000000000..998ce589e
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/channels.go.golden
@@ -0,0 +1,15 @@
+-- suggestedfix_channels_4_2 --
+package missingfunction
+
+func channels(s string) {
+ undefinedChannels(c()) //@suggestedfix("undefinedChannels", "quickfix", "")
+}
+
+func undefinedChannels(ch1 <-chan string, ch2 chan string) {
+ panic("unimplemented")
+}
+
+func c() (<-chan string, chan string) {
+ return make(<-chan string), make(chan string)
+}
+
diff --git a/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go
new file mode 100644
index 000000000..f2fb3c041
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go
@@ -0,0 +1,6 @@
+package missingfunction
+
+func consecutiveParams() {
+ var s string
+ undefinedConsecutiveParams(s, s) //@suggestedfix("undefinedConsecutiveParams", "quickfix", "")
+}
diff --git a/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden
new file mode 100644
index 000000000..4b852ce14
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden
@@ -0,0 +1,12 @@
+-- suggestedfix_consecutive_params_5_2 --
+package missingfunction
+
+func consecutiveParams() {
+ var s string
+ undefinedConsecutiveParams(s, s) //@suggestedfix("undefinedConsecutiveParams", "quickfix", "")
+}
+
+func undefinedConsecutiveParams(s1, s2 string) {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/missingfunction/error_param.go b/gopls/internal/lsp/testdata/missingfunction/error_param.go
new file mode 100644
index 000000000..d0484f0ff
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/error_param.go
@@ -0,0 +1,6 @@
+package missingfunction
+
+func errorParam() {
+ var err error
+ undefinedErrorParam(err) //@suggestedfix("undefinedErrorParam", "quickfix", "")
+}
diff --git a/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden b/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden
new file mode 100644
index 000000000..de78646a5
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden
@@ -0,0 +1,12 @@
+-- suggestedfix_error_param_5_2 --
+package missingfunction
+
+func errorParam() {
+ var err error
+ undefinedErrorParam(err) //@suggestedfix("undefinedErrorParam", "quickfix", "")
+}
+
+func undefinedErrorParam(err error) {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/missingfunction/literals.go b/gopls/internal/lsp/testdata/missingfunction/literals.go
new file mode 100644
index 000000000..0099b1a08
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/literals.go
@@ -0,0 +1,7 @@
+package missingfunction
+
+type T struct{}
+
+func literals() {
+ undefinedLiterals("hey compiler", T{}, &T{}) //@suggestedfix("undefinedLiterals", "quickfix", "")
+}
diff --git a/gopls/internal/lsp/testdata/missingfunction/literals.go.golden b/gopls/internal/lsp/testdata/missingfunction/literals.go.golden
new file mode 100644
index 000000000..cb85de4eb
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/literals.go.golden
@@ -0,0 +1,13 @@
+-- suggestedfix_literals_6_2 --
+package missingfunction
+
+type T struct{}
+
+func literals() {
+ undefinedLiterals("hey compiler", T{}, &T{}) //@suggestedfix("undefinedLiterals", "quickfix", "")
+}
+
+func undefinedLiterals(s string, t1 T, t2 *T) {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/missingfunction/operation.go b/gopls/internal/lsp/testdata/missingfunction/operation.go
new file mode 100644
index 000000000..a4913ec10
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/operation.go
@@ -0,0 +1,7 @@
+package missingfunction
+
+import "time"
+
+func operation() {
+ undefinedOperation(10 * time.Second) //@suggestedfix("undefinedOperation", "quickfix", "")
+}
diff --git a/gopls/internal/lsp/testdata/missingfunction/operation.go.golden b/gopls/internal/lsp/testdata/missingfunction/operation.go.golden
new file mode 100644
index 000000000..6f9e6ffab
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/operation.go.golden
@@ -0,0 +1,13 @@
+-- suggestedfix_operation_6_2 --
+package missingfunction
+
+import "time"
+
+func operation() {
+ undefinedOperation(10 * time.Second) //@suggestedfix("undefinedOperation", "quickfix", "")
+}
+
+func undefinedOperation(duration time.Duration) {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/missingfunction/selector.go b/gopls/internal/lsp/testdata/missingfunction/selector.go
new file mode 100644
index 000000000..93a040271
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/selector.go
@@ -0,0 +1,6 @@
+package missingfunction
+
+func selector() {
+ m := map[int]bool{}
+ undefinedSelector(m[1]) //@suggestedfix("undefinedSelector", "quickfix", "")
+}
diff --git a/gopls/internal/lsp/testdata/missingfunction/selector.go.golden b/gopls/internal/lsp/testdata/missingfunction/selector.go.golden
new file mode 100644
index 000000000..44e2dde3a
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/selector.go.golden
@@ -0,0 +1,12 @@
+-- suggestedfix_selector_5_2 --
+package missingfunction
+
+func selector() {
+ m := map[int]bool{}
+ undefinedSelector(m[1]) //@suggestedfix("undefinedSelector", "quickfix", "")
+}
+
+func undefinedSelector(b bool) {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/missingfunction/slice.go b/gopls/internal/lsp/testdata/missingfunction/slice.go
new file mode 100644
index 000000000..48b1a52b3
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/slice.go
@@ -0,0 +1,5 @@
+package missingfunction
+
+func slice() {
+ undefinedSlice([]int{1, 2}) //@suggestedfix("undefinedSlice", "quickfix", "")
+}
diff --git a/gopls/internal/lsp/testdata/missingfunction/slice.go.golden b/gopls/internal/lsp/testdata/missingfunction/slice.go.golden
new file mode 100644
index 000000000..2a05d9a0f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/slice.go.golden
@@ -0,0 +1,11 @@
+-- suggestedfix_slice_4_2 --
+package missingfunction
+
+func slice() {
+ undefinedSlice([]int{1, 2}) //@suggestedfix("undefinedSlice", "quickfix", "")
+}
+
+func undefinedSlice(i []int) {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/missingfunction/tuple.go b/gopls/internal/lsp/testdata/missingfunction/tuple.go
new file mode 100644
index 000000000..4059ced98
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/tuple.go
@@ -0,0 +1,9 @@
+package missingfunction
+
+func tuple() {
+ undefinedTuple(b()) //@suggestedfix("undefinedTuple", "quickfix", "")
+}
+
+func b() (string, error) {
+ return "", nil
+}
diff --git a/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden b/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden
new file mode 100644
index 000000000..e1118a3f3
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden
@@ -0,0 +1,15 @@
+-- suggestedfix_tuple_4_2 --
+package missingfunction
+
+func tuple() {
+ undefinedTuple(b()) //@suggestedfix("undefinedTuple", "quickfix", "")
+}
+
+func undefinedTuple(s string, err error) {
+ panic("unimplemented")
+}
+
+func b() (string, error) {
+ return "", nil
+}
+
diff --git a/gopls/internal/lsp/testdata/missingfunction/unique_params.go b/gopls/internal/lsp/testdata/missingfunction/unique_params.go
new file mode 100644
index 000000000..00479bf75
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/unique_params.go
@@ -0,0 +1,7 @@
+package missingfunction
+
+func uniqueArguments() {
+ var s string
+ var i int
+ undefinedUniqueArguments(s, i, s) //@suggestedfix("undefinedUniqueArguments", "quickfix", "")
+}
diff --git a/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden b/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden
new file mode 100644
index 000000000..8d6352cde
--- /dev/null
+++ b/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden
@@ -0,0 +1,13 @@
+-- suggestedfix_unique_params_6_2 --
+package missingfunction
+
+func uniqueArguments() {
+ var s string
+ var i int
+ undefinedUniqueArguments(s, i, s) //@suggestedfix("undefinedUniqueArguments", "quickfix", "")
+}
+
+func undefinedUniqueArguments(s1 string, i int, s2 string) {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/multireturn/multi_return.go.in b/gopls/internal/lsp/testdata/multireturn/multi_return.go.in
new file mode 100644
index 000000000..c302f3815
--- /dev/null
+++ b/gopls/internal/lsp/testdata/multireturn/multi_return.go.in
@@ -0,0 +1,48 @@
+package multireturn
+
+func f0() {} //@item(multiF0, "f0", "func()", "func")
+
+func f1(int) int { return 0 } //@item(multiF1, "f1", "func(int) int", "func")
+
+func f2(int, int) (int, int) { return 0, 0 } //@item(multiF2, "f2", "func(int, int) (int, int)", "func")
+
+func f2Str(string, string) (string, string) { return "", "" } //@item(multiF2Str, "f2Str", "func(string, string) (string, string)", "func")
+
+func f3(int, int, int) (int, int, int) { return 0, 0, 0 } //@item(multiF3, "f3", "func(int, int, int) (int, int, int)", "func")
+
+func _() {
+ _ := f //@rank(" //", multiF1, multiF2)
+
+ _, _ := f //@rank(" //", multiF2, multiF0),rank(" //", multiF1, multiF0)
+
+ _, _ := _, f //@rank(" //", multiF1, multiF2),rank(" //", multiF1, multiF0)
+
+ _, _ := f, abc //@rank(", abc", multiF1, multiF2)
+
+ f1() //@rank(")", multiF1, multiF0)
+ f1(f) //@rank(")", multiF1, multiF2)
+ f2(f) //@rank(")", multiF2, multiF3),rank(")", multiF1, multiF3)
+ f2(1, f) //@rank(")", multiF1, multiF2),rank(")", multiF1, multiF0)
+ f2(1, ) //@rank(")", multiF1, multiF2),rank(")", multiF1, multiF0)
+ f2Str() //@rank(")", multiF2Str, multiF2)
+
+ var i int
+ i, _ := f //@rank(" //", multiF2, multiF2Str)
+
+ var s string
+ _, s := f //@rank(" //", multiF2Str, multiF2)
+
+ banana, s = f //@rank(" //", multiF2, multiF3)
+
+ var variadic func(int, ...int)
+ variadic() //@rank(")", multiF1, multiF0),rank(")", multiF2, multiF0),rank(")", multiF3, multiF0)
+}
+
+func _() {
+ var baz func(...interface{})
+
+ var otterNap func() (int, int) //@item(multiTwo, "otterNap", "func() (int, int)", "var")
+ var one int //@item(multiOne, "one", "int", "var")
+
+ baz(on) //@rank(")", multiOne, multiTwo)
+}
diff --git a/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in b/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in
new file mode 100644
index 000000000..3ad2d213e
--- /dev/null
+++ b/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in
@@ -0,0 +1,15 @@
+package nested_complit
+
+type ncFoo struct {} //@item(structNCFoo, "ncFoo", "struct{...}", "struct")
+
+type ncBar struct { //@item(structNCBar, "ncBar", "struct{...}", "struct")
+ baz []ncFoo
+}
+
+func _() {
+ []ncFoo{} //@item(litNCFoo, "[]ncFoo{}", "", "var")
+ _ := ncBar{
+ // disabled - see issue #54822
+ baz: [] // complete(" //", structNCFoo, structNCBar)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/nodisk/empty b/gopls/internal/lsp/testdata/nodisk/empty
new file mode 100644
index 000000000..0c10a42f9
--- /dev/null
+++ b/gopls/internal/lsp/testdata/nodisk/empty
@@ -0,0 +1 @@
+an empty file so that this directory exists \ No newline at end of file
diff --git a/gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go b/gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go
new file mode 100644
index 000000000..08aebd12f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go
@@ -0,0 +1,9 @@
+package nodisk
+
+import (
+ "golang.org/lsptests/foo"
+)
+
+func _() {
+ foo.Foo() //@complete("F", Foo, IntFoo, StructFoo)
+}
diff --git a/gopls/internal/lsp/testdata/noparse/noparse.go.in b/gopls/internal/lsp/testdata/noparse/noparse.go.in
new file mode 100644
index 000000000..8b0bfaa03
--- /dev/null
+++ b/gopls/internal/lsp/testdata/noparse/noparse.go.in
@@ -0,0 +1,24 @@
+package noparse
+
+// The type error was chosen carefully to exercise a type-error analyzer.
+// We use the 'nonewvars' analyzer because the other candidates are tricky:
+//
+// - The 'unusedvariable' analyzer is disabled by default, so it is not
+// consistently enabled across Test{LSP,CommandLine} tests, which
+// both process this file.
+// - The 'undeclaredname' analyzer depends on the text of the go/types
+// "undeclared name" error, which changed in go1.20.
+// - The 'noresultvalues' analyzer produces a diagnostic containing newlines,
+// which breaks the parser used by TestCommandLine.
+//
+// This comment is all that remains of my afternoon.
+
+func bye(x int) {
+ x := 123 //@diag(":=", "nonewvars", "no new variables", "warning")
+}
+
+func stuff() {
+
+}
+
+func .() {} //@diag(".", "syntax", "expected 'IDENT', found '.'", "error")
diff --git a/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden
new file mode 100644
index 000000000..0060c5c92
--- /dev/null
+++ b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden
@@ -0,0 +1,2 @@
+-- gofmt --
+
diff --git a/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in
new file mode 100644
index 000000000..311a99aaf
--- /dev/null
+++ b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in
@@ -0,0 +1,14 @@
+// +build go1.11
+
+package noparse_format //@format("package")
+
+// The nonewvars expectation asserts that the go/analysis framework ran.
+// See comments in badstmt.
+
+func what() {
+ var hi func()
+ if { hi() //@diag("{", "syntax", "missing condition in if statement", "error")
+ }
+ hi := nil //@diag(":=", "nonewvars", "no new variables", "warning")
+}
+
diff --git a/gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden
new file mode 100644
index 000000000..667c90b22
--- /dev/null
+++ b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden
@@ -0,0 +1,7 @@
+-- gofmt --
+package noparse_format //@format("package")
+
+func _() {
+ f()
+}
+
diff --git a/gopls/internal/lsp/testdata/noparse_format/parse_format.go.in b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.in
new file mode 100644
index 000000000..4b98cf8d0
--- /dev/null
+++ b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.in
@@ -0,0 +1,5 @@
+package noparse_format //@format("package")
+
+func _() {
+f()
+} \ No newline at end of file
diff --git a/gopls/internal/lsp/testdata/printf/printf.go b/gopls/internal/lsp/testdata/printf/printf.go
new file mode 100644
index 000000000..6e56549c1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/printf/printf.go
@@ -0,0 +1,33 @@
+package printf
+
+import "fmt"
+
+func myPrintf(string, ...interface{}) {}
+
+func _() {
+ var (
+ aInt int //@item(printfInt, "aInt", "int", "var")
+ aFloat float64 //@item(printfFloat, "aFloat", "float64", "var")
+ aString string //@item(printfString, "aString", "string", "var")
+ aBytes []byte //@item(printfBytes, "aBytes", "[]byte", "var")
+ aStringer fmt.Stringer //@item(printfStringer, "aStringer", "fmt.Stringer", "var")
+ aError error //@item(printfError, "aError", "error", "var")
+ aBool bool //@item(printfBool, "aBool", "bool", "var")
+ )
+
+ myPrintf("%d", a) //@rank(")", printfInt, printfFloat)
+ myPrintf("%s", a) //@rank(")", printfString, printfInt),rank(")", printfBytes, printfInt),rank(")", printfStringer, printfInt),rank(")", printfError, printfInt)
+ myPrintf("%w", a) //@rank(")", printfError, printfInt)
+ myPrintf("%x %[1]b", a) //@rank(")", printfInt, printfString)
+
+ fmt.Printf("%t", a) //@rank(")", printfBool, printfInt)
+
+ fmt.Fprintf(nil, "%f", a) //@rank(")", printfFloat, printfInt)
+
+ fmt.Sprintf("%[2]q %[1]*.[3]*[4]f",
+ a, //@rank(",", printfInt, printfFloat)
+ a, //@rank(",", printfString, printfFloat)
+ a, //@rank(",", printfInt, printfFloat)
+ a, //@rank(",", printfFloat, printfInt)
+ )
+}
diff --git a/gopls/internal/lsp/testdata/rank/assign_rank.go.in b/gopls/internal/lsp/testdata/rank/assign_rank.go.in
new file mode 100644
index 000000000..5c51910d4
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rank/assign_rank.go.in
@@ -0,0 +1,19 @@
+package rank
+
+var (
+ apple int = 3 //@item(apple, "apple", "int", "var")
+ pear string = "hello" //@item(pear, "pear", "string", "var")
+)
+
+func _() {
+ orange := 1 //@item(orange, "orange", "int", "var")
+ grape := "hello" //@item(grape, "grape", "string", "var")
+ orange, grape = 2, "hello" //@complete(" \"", grape, pear, orange, apple)
+}
+
+func _() {
+ var pineapple int //@item(pineapple, "pineapple", "int", "var")
+ pineapple = 1 //@complete(" 1", pineapple, apple, pear)
+
+ y := //@complete(" /", pineapple, apple, pear)
+}
diff --git a/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in b/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in
new file mode 100644
index 000000000..60b2cc1bc
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in
@@ -0,0 +1,8 @@
+package rank
+
+func _() {
+ _ = 5 + ; //@complete(" ;", apple, pear)
+ y := + 5; //@complete(" +", apple, pear)
+
+ if 6 == {} //@complete(" {", apple, pear)
+}
diff --git a/gopls/internal/lsp/testdata/rank/boolexpr_rank.go b/gopls/internal/lsp/testdata/rank/boolexpr_rank.go
new file mode 100644
index 000000000..fe512eee1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rank/boolexpr_rank.go
@@ -0,0 +1,11 @@
+package rank
+
+func _() {
+ someRandomBoolFunc := func() bool { //@item(boolExprFunc, "someRandomBoolFunc", "func() bool", "var")
+ return true
+ }
+
+ var foo, bar int //@item(boolExprBar, "bar", "int", "var")
+ if foo == 123 && b { //@rank(" {", boolExprBar, boolExprFunc)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/rank/convert_rank.go.in b/gopls/internal/lsp/testdata/rank/convert_rank.go.in
new file mode 100644
index 000000000..c43004833
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rank/convert_rank.go.in
@@ -0,0 +1,54 @@
+package rank
+
+import "time"
+
+func _() {
+ type strList []string
+ wantsStrList := func(strList) {}
+
+ var (
+ convA string //@item(convertA, "convA", "string", "var")
+ convB []string //@item(convertB, "convB", "[]string", "var")
+ )
+ wantsStrList(strList(conv)) //@complete("))", convertB, convertA)
+}
+
+func _() {
+ type myInt int
+
+ const (
+ convC = "hi" //@item(convertC, "convC", "string", "const")
+ convD = 123 //@item(convertD, "convD", "int", "const")
+ convE int = 123 //@item(convertE, "convE", "int", "const")
+ convF string = "there" //@item(convertF, "convF", "string", "const")
+ convG myInt = 123 //@item(convertG, "convG", "myInt", "const")
+ )
+
+ var foo int
+ foo = conv //@rank(" //", convertE, convertD)
+
+ var mi myInt
+ mi = conv //@rank(" //", convertG, convertD, convertE)
+ mi + conv //@rank(" //", convertG, convertD, convertE)
+
+ 1 + conv //@rank(" //", convertD, convertC),rank(" //", convertE, convertC),rank(" //", convertG, convertC)
+
+ type myString string
+ var ms myString
+ ms = conv //@rank(" //", convertC, convertF)
+
+ type myUint uint32
+ var mu myUint
+ mu = conv //@rank(" //", convertD, convertE)
+
+ // don't downrank constants when assigning to interface{}
+ var _ interface{} = c //@rank(" //", convertD, complex)
+
+ var _ time.Duration = conv //@rank(" //", convertD, convertE),snippet(" //", convertE, "time.Duration(convE)", "time.Duration(convE)")
+
+ var convP myInt //@item(convertP, "convP", "myInt", "var")
+ var _ *int = conv //@snippet(" //", convertP, "(*int)(&convP)", "(*int)(&convP)")
+
+ var ff float64 //@item(convertFloat, "ff", "float64", "var")
+ f == convD //@snippet(" =", convertFloat, "ff", "ff")
+}
diff --git a/gopls/internal/lsp/testdata/rank/struct/struct_rank.go b/gopls/internal/lsp/testdata/rank/struct/struct_rank.go
new file mode 100644
index 000000000..e0bdd38a8
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rank/struct/struct_rank.go
@@ -0,0 +1,11 @@
+package struct_rank
+
+type foo struct {
+ c int //@item(c_rank, "c", "int", "field")
+ b int //@item(b_rank, "b", "int", "field")
+ a int //@item(a_rank, "a", "int", "field")
+}
+
+func f() {
+ foo := foo{} //@rank("}", c_rank, b_rank, a_rank)
+}
diff --git a/gopls/internal/lsp/testdata/rank/switch_rank.go.in b/gopls/internal/lsp/testdata/rank/switch_rank.go.in
new file mode 100644
index 000000000..b828528da
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rank/switch_rank.go.in
@@ -0,0 +1,29 @@
+package rank
+
+import "time"
+
+func _() {
+ switch pear {
+ case _: //@rank("_", pear, apple)
+ }
+
+ time.Monday //@item(timeMonday, "time.Monday", "time.Weekday", "const"),item(monday ,"Monday", "time.Weekday", "const")
+ time.Friday //@item(timeFriday, "time.Friday", "time.Weekday", "const"),item(friday ,"Friday", "time.Weekday", "const")
+
+ now := time.Now()
+ now.Weekday //@item(nowWeekday, "now.Weekday", "func() time.Weekday", "method")
+
+ then := time.Now()
+ then.Weekday //@item(thenWeekday, "then.Weekday", "func() time.Weekday", "method")
+
+ switch time.Weekday(0) {
+ case time.Monday, time.Tuesday:
+ case time.Wednesday, time.Thursday:
+ case time.Saturday, time.Sunday:
+ case t: //@rank(":", timeFriday, timeMonday)
+ case time.: //@rank(":", friday, monday)
+
+ case now.Weekday():
+ case week: //@rank(":", thenWeekday, nowWeekday)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in b/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in
new file mode 100644
index 000000000..416541cdd
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in
@@ -0,0 +1,8 @@
+package rank
+
+func _() {
+ type flower int //@item(flower, "flower", "int", "type")
+ var fig string //@item(fig, "fig", "string", "var")
+
+ _ = interface{}(nil).(f) //@complete(") //", flower)
+}
diff --git a/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in b/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in
new file mode 100644
index 000000000..1ed12b7c1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in
@@ -0,0 +1,31 @@
+package rank
+
+import (
+ "fmt"
+ "go/ast"
+)
+
+func _() {
+ type basket int //@item(basket, "basket", "int", "type")
+ var banana string //@item(banana, "banana", "string", "var")
+
+ switch interface{}(pear).(type) {
+ case b: //@complete(":", basket)
+ b //@complete(" //", banana, basket)
+ }
+
+ Ident //@item(astIdent, "Ident", "struct{...}", "struct")
+ IfStmt //@item(astIfStmt, "IfStmt", "struct{...}", "struct")
+
+ switch ast.Node(nil).(type) {
+ case *ast.Ident:
+ case *ast.I: //@rank(":", astIfStmt, astIdent)
+ }
+
+ Stringer //@item(fmtStringer, "Stringer", "interface{...}", "interface")
+ GoStringer //@item(fmtGoStringer, "GoStringer", "interface{...}", "interface")
+
+ switch interface{}(nil).(type) {
+ case fmt.Stringer: //@rank(":", fmtStringer, fmtGoStringer)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/references/another/another.go b/gopls/internal/lsp/testdata/references/another/another.go
new file mode 100644
index 000000000..20e3ebca1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/references/another/another.go
@@ -0,0 +1,13 @@
+// Package another has another type.
+package another
+
+import (
+ other "golang.org/lsptests/references/other"
+)
+
+func _() {
+ xes := other.GetXes()
+ for _, x := range xes { //@mark(defX, "x")
+ _ = x.Y //@mark(useX, "x"),mark(anotherXY, "Y"),refs("Y", typeXY, anotherXY, GetXesY),refs(".", defX, useX),refs("x", defX, useX)
+ }
+}
diff --git a/gopls/internal/lsp/testdata/references/interfaces/interfaces.go b/gopls/internal/lsp/testdata/references/interfaces/interfaces.go
new file mode 100644
index 000000000..6661dcc5d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/references/interfaces/interfaces.go
@@ -0,0 +1,34 @@
+package interfaces
+
+type first interface {
+ common() //@mark(firCommon, "common"),refs("common", firCommon, xCommon, zCommon)
+ firstMethod() //@mark(firMethod, "firstMethod"),refs("firstMethod", firMethod, xfMethod, zfMethod)
+}
+
+type second interface {
+ common() //@mark(secCommon, "common"),refs("common", secCommon, yCommon, zCommon)
+ secondMethod() //@mark(secMethod, "secondMethod"),refs("secondMethod", secMethod, ysMethod, zsMethod)
+}
+
+type s struct {}
+
+func (*s) common() {} //@mark(sCommon, "common"),refs("common", sCommon, xCommon, yCommon, zCommon)
+
+func (*s) firstMethod() {} //@mark(sfMethod, "firstMethod"),refs("firstMethod", sfMethod, xfMethod, zfMethod)
+
+func (*s) secondMethod() {} //@mark(ssMethod, "secondMethod"),refs("secondMethod", ssMethod, ysMethod, zsMethod)
+
+func main() {
+ var x first = &s{}
+ var y second = &s{}
+
+ x.common() //@mark(xCommon, "common"),refs("common", firCommon, xCommon, zCommon)
+ x.firstMethod() //@mark(xfMethod, "firstMethod"),refs("firstMethod", firMethod, xfMethod, zfMethod)
+ y.common() //@mark(yCommon, "common"),refs("common", secCommon, yCommon, zCommon)
+ y.secondMethod() //@mark(ysMethod, "secondMethod"),refs("secondMethod", secMethod, ysMethod, zsMethod)
+
+ var z *s = &s{}
+ z.firstMethod() //@mark(zfMethod, "firstMethod"),refs("firstMethod", sfMethod, xfMethod, zfMethod)
+ z.secondMethod() //@mark(zsMethod, "secondMethod"),refs("secondMethod", ssMethod, ysMethod, zsMethod)
+ z.common() //@mark(zCommon, "common"),refs("common", sCommon, xCommon, yCommon, zCommon)
+}
diff --git a/gopls/internal/lsp/testdata/references/other/other.go b/gopls/internal/lsp/testdata/references/other/other.go
new file mode 100644
index 000000000..daac1a028
--- /dev/null
+++ b/gopls/internal/lsp/testdata/references/other/other.go
@@ -0,0 +1,19 @@
+package other
+
+import (
+ references "golang.org/lsptests/references"
+)
+
+func GetXes() []references.X {
+ return []references.X{
+ {
+ Y: 1, //@mark(GetXesY, "Y"),refs("Y", typeXY, GetXesY, anotherXY)
+ },
+ }
+}
+
+func _() {
+ references.Q = "hello" //@mark(assignExpQ, "Q")
+ bob := func(_ string) {}
+ bob(references.Q) //@mark(bobExpQ, "Q")
+}
diff --git a/gopls/internal/lsp/testdata/references/refs.go b/gopls/internal/lsp/testdata/references/refs.go
new file mode 100644
index 000000000..e7ff50494
--- /dev/null
+++ b/gopls/internal/lsp/testdata/references/refs.go
@@ -0,0 +1,53 @@
+// Package refs is a package used to test find references.
+package refs
+
+import "os" //@mark(osDecl, `"os"`),refs("os", osDecl, osUse)
+
+type i int //@mark(typeI, "i"),refs("i", typeI, argI, returnI, embeddedI)
+
+type X struct {
+ Y int //@mark(typeXY, "Y")
+}
+
+func _(_ i) []bool { //@mark(argI, "i")
+ return nil
+}
+
+func _(_ []byte) i { //@mark(returnI, "i")
+ return 0
+}
+
+var q string //@mark(declQ, "q"),refs("q", declQ, assignQ, bobQ)
+
+var Q string //@mark(declExpQ, "Q"),refs("Q", declExpQ, assignExpQ, bobExpQ)
+
+func _() {
+ q = "hello" //@mark(assignQ, "q")
+ bob := func(_ string) {}
+ bob(q) //@mark(bobQ, "q")
+}
+
+type e struct {
+ i //@mark(embeddedI, "i"),refs("i", embeddedI, embeddedIUse)
+}
+
+func _() {
+ _ = e{}.i //@mark(embeddedIUse, "i")
+}
+
+const (
+ foo = iota //@refs("iota")
+)
+
+func _(x interface{}) {
+ // We use the _ prefix because the markers inhabit a single
+ // namespace and yDecl is already used in ../highlights/highlights.go.
+ switch _y := x.(type) { //@mark(_yDecl, "_y"),refs("_y", _yDecl, _yInt, _yDefault)
+ case int:
+ println(_y) //@mark(_yInt, "_y"),refs("_y", _yDecl, _yInt, _yDefault)
+ default:
+ println(_y) //@mark(_yDefault, "_y")
+ }
+
+ os.Getwd() //@mark(osUse, "os")
+}
diff --git a/gopls/internal/lsp/testdata/references/refs_test.go b/gopls/internal/lsp/testdata/references/refs_test.go
new file mode 100644
index 000000000..08c0db1f0
--- /dev/null
+++ b/gopls/internal/lsp/testdata/references/refs_test.go
@@ -0,0 +1,10 @@
+package references
+
+import (
+ "testing"
+)
+
+// This test exists to bring the test package into existence.
+
+func TestReferences(t *testing.T) {
+}
diff --git a/gopls/internal/lsp/testdata/rename/a/random.go.golden b/gopls/internal/lsp/testdata/rename/a/random.go.golden
new file mode 100644
index 000000000..7459863ec
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/a/random.go.golden
@@ -0,0 +1,616 @@
+-- GetSum-rename --
+package a
+
+import (
+ lg "log"
+ "fmt" //@rename("fmt", "fmty")
+ f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) GetSum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.GetSum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- f2name-rename --
+package a
+
+import (
+ lg "log"
+ "fmt" //@rename("fmt", "fmty")
+ f2name "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2name.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- f2y-rename --
+package a
+
+import (
+ lg "log"
+ "fmt" //@rename("fmt", "fmty")
+ f2y "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2y.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- fmt2-rename --
+package a
+
+import (
+ lg "log"
+ "fmt" //@rename("fmt", "fmty")
+ fmt2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
+ default:
+ fmt2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- fmty-rename --
+package a
+
+import (
+ lg "log"
+ fmty "fmt" //@rename("fmt", "fmty")
+ f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y := x.(type) { //@rename("y", "y0")
+ case int:
+ fmty.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- format-rename --
+package a
+
+import (
+ lg "log"
+ format "fmt" //@rename("fmt", "fmty")
+ f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y := x.(type) { //@rename("y", "y0")
+ case int:
+ format.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- log-rename --
+package a
+
+import (
+ "log"
+ "fmt" //@rename("fmt", "fmty")
+ f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ log.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- myX-rename --
+package a
+
+import (
+ lg "log"
+ "fmt" //@rename("fmt", "fmty")
+ f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ myX, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.myX + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- pos-rename --
+package a
+
+import (
+ lg "log"
+ "fmt" //@rename("fmt", "fmty")
+ f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var pos Pos //@rename("p", "pos")
+ _ = pos.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- y0-rename --
+package a
+
+import (
+ lg "log"
+ "fmt" //@rename("fmt", "fmty")
+ f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y0 := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y0) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y0) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2.Printf("%v", y0) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- y1-rename --
+package a
+
+import (
+ lg "log"
+ "fmt" //@rename("fmt", "fmty")
+ f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y1 := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y1) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y1) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2.Printf("%v", y1) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- y2-rename --
+package a
+
+import (
+ lg "log"
+ "fmt" //@rename("fmt", "fmty")
+ f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y2 := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y2) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y2) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2.Printf("%v", y2) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- y3-rename --
+package a
+
+import (
+ lg "log"
+ "fmt" //@rename("fmt", "fmty")
+ f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y3 := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y3) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y3) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2.Printf("%v", y3) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- z-rename --
+package a
+
+import (
+ lg "log"
+ "fmt" //@rename("fmt", "fmty")
+ f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(z int) int { //@rename("y", "z")
+ return z
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
diff --git a/gopls/internal/lsp/testdata/rename/a/random.go.in b/gopls/internal/lsp/testdata/rename/a/random.go.in
new file mode 100644
index 000000000..069db27ba
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/a/random.go.in
@@ -0,0 +1,42 @@
+package a
+
+import (
+ lg "log"
+ "fmt" //@rename("fmt", "fmty")
+ f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y")
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
diff --git a/gopls/internal/lsp/testdata/rename/b/b.go b/gopls/internal/lsp/testdata/rename/b/b.go
new file mode 100644
index 000000000..8455f035b
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/b/b.go
@@ -0,0 +1,20 @@
+package b
+
+var c int //@rename("int", "uint")
+
+func _() {
+ a := 1 //@rename("a", "error")
+ a = 2
+ _ = a
+}
+
+var (
+ // Hello there.
+ // Foo does the thing.
+ Foo int //@rename("Foo", "Bob")
+)
+
+/*
+Hello description
+*/
+func Hello() {} //@rename("Hello", "Goodbye")
diff --git a/gopls/internal/lsp/testdata/rename/b/b.go.golden b/gopls/internal/lsp/testdata/rename/b/b.go.golden
new file mode 100644
index 000000000..add4049cd
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/b/b.go.golden
@@ -0,0 +1,78 @@
+-- Bob-rename --
+package b
+
+var c int //@rename("int", "uint")
+
+func _() {
+ a := 1 //@rename("a", "error")
+ a = 2
+ _ = a
+}
+
+var (
+ // Hello there.
+ // Bob does the thing.
+ Bob int //@rename("Foo", "Bob")
+)
+
+/*
+Hello description
+*/
+func Hello() {} //@rename("Hello", "Goodbye")
+
+-- Goodbye-rename --
+b.go:
+package b
+
+var c int //@rename("int", "uint")
+
+func _() {
+ a := 1 //@rename("a", "error")
+ a = 2
+ _ = a
+}
+
+var (
+ // Hello there.
+ // Foo does the thing.
+ Foo int //@rename("Foo", "Bob")
+)
+
+/*
+Goodbye description
+*/
+func Goodbye() {} //@rename("Hello", "Goodbye")
+
+c.go:
+package c
+
+import "golang.org/lsptests/rename/b"
+
+func _() {
+ b.Goodbye() //@rename("Hello", "Goodbye")
+}
+
+-- error-rename --
+package b
+
+var c int //@rename("int", "uint")
+
+func _() {
+ error := 1 //@rename("a", "error")
+ error = 2
+ _ = error
+}
+
+var (
+ // Hello there.
+ // Foo does the thing.
+ Foo int //@rename("Foo", "Bob")
+)
+
+/*
+Hello description
+*/
+func Hello() {} //@rename("Hello", "Goodbye")
+
+-- uint-rename --
+int is built in and cannot be renamed
diff --git a/gopls/internal/lsp/testdata/rename/bad/bad.go.golden b/gopls/internal/lsp/testdata/rename/bad/bad.go.golden
new file mode 100644
index 000000000..1b27e1782
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/bad/bad.go.golden
@@ -0,0 +1,2 @@
+-- rFunc-rename --
+renaming "sFunc" to "rFunc" not possible because "golang.org/lsptests/rename/bad" has errors
diff --git a/gopls/internal/lsp/testdata/rename/bad/bad.go.in b/gopls/internal/lsp/testdata/rename/bad/bad.go.in
new file mode 100644
index 000000000..56dbee74e
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/bad/bad.go.in
@@ -0,0 +1,8 @@
+package bad
+
+type myStruct struct {
+}
+
+func (s *myStruct) sFunc() bool { //@rename("sFunc", "rFunc")
+ return s.Bad
+}
diff --git a/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in b/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in
new file mode 100644
index 000000000..e695db14b
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in
@@ -0,0 +1 @@
+package bad \ No newline at end of file
diff --git a/gopls/internal/lsp/testdata/rename/c/c.go b/gopls/internal/lsp/testdata/rename/c/c.go
new file mode 100644
index 000000000..6332c78f3
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/c/c.go
@@ -0,0 +1,7 @@
+package c
+
+import "golang.org/lsptests/rename/b"
+
+func _() {
+ b.Hello() //@rename("Hello", "Goodbye")
+}
diff --git a/gopls/internal/lsp/testdata/rename/c/c.go.golden b/gopls/internal/lsp/testdata/rename/c/c.go.golden
new file mode 100644
index 000000000..d56250693
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/c/c.go.golden
@@ -0,0 +1,32 @@
+-- Goodbye-rename --
+b.go:
+package b
+
+var c int //@rename("int", "uint")
+
+func _() {
+ a := 1 //@rename("a", "error")
+ a = 2
+ _ = a
+}
+
+var (
+ // Hello there.
+ // Foo does the thing.
+ Foo int //@rename("Foo", "Bob")
+)
+
+/*
+Goodbye description
+*/
+func Goodbye() {} //@rename("Hello", "Goodbye")
+
+c.go:
+package c
+
+import "golang.org/lsptests/rename/b"
+
+func _() {
+ b.Goodbye() //@rename("Hello", "Goodbye")
+}
+
diff --git a/gopls/internal/lsp/testdata/rename/c/c2.go b/gopls/internal/lsp/testdata/rename/c/c2.go
new file mode 100644
index 000000000..4fc484a1a
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/c/c2.go
@@ -0,0 +1,4 @@
+package c
+
+//go:embed Static/*
+var Static embed.FS //@rename("Static", "static") \ No newline at end of file
diff --git a/gopls/internal/lsp/testdata/rename/c/c2.go.golden b/gopls/internal/lsp/testdata/rename/c/c2.go.golden
new file mode 100644
index 000000000..e509227a9
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/c/c2.go.golden
@@ -0,0 +1,5 @@
+-- static-rename --
+package c
+
+//go:embed Static/*
+var static embed.FS //@rename("Static", "static")
diff --git a/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go
new file mode 100644
index 000000000..9b50af2cb
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go
@@ -0,0 +1,13 @@
+package another
+
+type (
+ I interface{ F() }
+ C struct{ I }
+)
+
+func (C) g()
+
+func _() {
+ var x I = C{}
+ x.F() //@rename("F", "G")
+}
diff --git a/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden
new file mode 100644
index 000000000..d3fccdaf1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden
@@ -0,0 +1,15 @@
+-- G-rename --
+package another
+
+type (
+ I interface{ G() }
+ C struct{ I }
+)
+
+func (C) g()
+
+func _() {
+ var x I = C{}
+ x.G() //@rename("F", "G")
+}
+
diff --git a/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go
new file mode 100644
index 000000000..8510bcfe0
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go
@@ -0,0 +1,7 @@
+package crosspkg
+
+func Foo() { //@rename("Foo", "Dolphin")
+
+}
+
+var Bar int //@rename("Bar", "Tomato")
diff --git a/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden
new file mode 100644
index 000000000..49ff7f841
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden
@@ -0,0 +1,40 @@
+-- Dolphin-rename --
+crosspkg.go:
+package crosspkg
+
+func Dolphin() { //@rename("Foo", "Dolphin")
+
+}
+
+var Bar int //@rename("Bar", "Tomato")
+
+other.go:
+package other
+
+import "golang.org/lsptests/rename/crosspkg"
+
+func Other() {
+ crosspkg.Bar
+ crosspkg.Dolphin() //@rename("Foo", "Flamingo")
+}
+
+-- Tomato-rename --
+crosspkg.go:
+package crosspkg
+
+func Foo() { //@rename("Foo", "Dolphin")
+
+}
+
+var Tomato int //@rename("Bar", "Tomato")
+
+other.go:
+package other
+
+import "golang.org/lsptests/rename/crosspkg"
+
+func Other() {
+ crosspkg.Tomato
+ crosspkg.Foo() //@rename("Foo", "Flamingo")
+}
+
diff --git a/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go
new file mode 100644
index 000000000..5fd147da6
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go
@@ -0,0 +1,8 @@
+package other
+
+import "golang.org/lsptests/rename/crosspkg"
+
+func Other() {
+ crosspkg.Bar
+ crosspkg.Foo() //@rename("Foo", "Flamingo")
+}
diff --git a/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden
new file mode 100644
index 000000000..f7b4aaad4
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden
@@ -0,0 +1,20 @@
+-- Flamingo-rename --
+crosspkg.go:
+package crosspkg
+
+func Flamingo() { //@rename("Foo", "Dolphin")
+
+}
+
+var Bar int //@rename("Bar", "Tomato")
+
+other.go:
+package other
+
+import "golang.org/lsptests/rename/crosspkg"
+
+func Other() {
+ crosspkg.Bar
+ crosspkg.Flamingo() //@rename("Foo", "Flamingo")
+}
+
diff --git a/gopls/internal/lsp/testdata/rename/generics/embedded.go b/gopls/internal/lsp/testdata/rename/generics/embedded.go
new file mode 100644
index 000000000..b44bab880
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/generics/embedded.go
@@ -0,0 +1,10 @@
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type foo[P any] int //@rename("foo","bar")
+
+var x struct{ foo[int] }
+
+var _ = x.foo
diff --git a/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden b/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden
new file mode 100644
index 000000000..faa9afb69
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden
@@ -0,0 +1,12 @@
+-- bar-rename --
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type bar[P any] int //@rename("foo","bar")
+
+var x struct{ bar[int] }
+
+var _ = x.bar
+
diff --git a/gopls/internal/lsp/testdata/rename/generics/generics.go b/gopls/internal/lsp/testdata/rename/generics/generics.go
new file mode 100644
index 000000000..977589c0c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/generics/generics.go
@@ -0,0 +1,25 @@
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type G[P any] struct {
+ F int
+}
+
+func (G[_]) M() {}
+
+func F[P any](P) {
+ var p P //@rename("P", "Q")
+ _ = p
+}
+
+func _() {
+ var x G[int] //@rename("G", "H")
+ _ = x.F //@rename("F", "K")
+ x.M() //@rename("M", "N")
+
+ var y G[string]
+ _ = y.F
+ y.M()
+}
diff --git a/gopls/internal/lsp/testdata/rename/generics/generics.go.golden b/gopls/internal/lsp/testdata/rename/generics/generics.go.golden
new file mode 100644
index 000000000..7d39813e1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/generics/generics.go.golden
@@ -0,0 +1,108 @@
+-- H-rename --
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type H[P any] struct {
+ F int
+}
+
+func (H[_]) M() {}
+
+func F[P any](P) {
+ var p P //@rename("P", "Q")
+ _ = p
+}
+
+func _() {
+ var x H[int] //@rename("G", "H")
+ _ = x.F //@rename("F", "K")
+ x.M() //@rename("M", "N")
+
+ var y H[string]
+ _ = y.F
+ y.M()
+}
+
+-- K-rename --
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type G[P any] struct {
+ K int
+}
+
+func (G[_]) M() {}
+
+func F[P any](P) {
+ var p P //@rename("P", "Q")
+ _ = p
+}
+
+func _() {
+ var x G[int] //@rename("G", "H")
+ _ = x.K //@rename("F", "K")
+ x.M() //@rename("M", "N")
+
+ var y G[string]
+ _ = y.K
+ y.M()
+}
+
+-- N-rename --
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type G[P any] struct {
+ F int
+}
+
+func (G[_]) N() {}
+
+func F[P any](P) {
+ var p P //@rename("P", "Q")
+ _ = p
+}
+
+func _() {
+ var x G[int] //@rename("G", "H")
+ _ = x.F //@rename("F", "K")
+ x.N() //@rename("M", "N")
+
+ var y G[string]
+ _ = y.F
+ y.N()
+}
+
+-- Q-rename --
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type G[P any] struct {
+ F int
+}
+
+func (G[_]) M() {}
+
+func F[Q any](Q) {
+ var p Q //@rename("P", "Q")
+ _ = p
+}
+
+func _() {
+ var x G[int] //@rename("G", "H")
+ _ = x.F //@rename("F", "K")
+ x.M() //@rename("M", "N")
+
+ var y G[string]
+ _ = y.F
+ y.M()
+}
+
diff --git a/gopls/internal/lsp/testdata/rename/generics/unions.go b/gopls/internal/lsp/testdata/rename/generics/unions.go
new file mode 100644
index 000000000..c737b5c27
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/generics/unions.go
@@ -0,0 +1,10 @@
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type T string //@rename("T", "R")
+
+type C interface {
+ T | ~int //@rename("T", "S")
+}
diff --git a/gopls/internal/lsp/testdata/rename/generics/unions.go.golden b/gopls/internal/lsp/testdata/rename/generics/unions.go.golden
new file mode 100644
index 000000000..463289629
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/generics/unions.go.golden
@@ -0,0 +1,24 @@
+-- R-rename --
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type R string //@rename("T", "R")
+
+type C interface {
+ R | ~int //@rename("T", "S")
+}
+
+-- S-rename --
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type S string //@rename("T", "R")
+
+type C interface {
+ S | ~int //@rename("T", "S")
+}
+
diff --git a/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden
new file mode 100644
index 000000000..d87c58e83
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden
@@ -0,0 +1,10 @@
+-- bar-rename --
+package issue39614
+
+func fn() {
+ var bar bool //@rename("foo","bar")
+ make(map[string]bool
+ if true {
+ }
+}
+
diff --git a/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in
new file mode 100644
index 000000000..8222db2c4
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in
@@ -0,0 +1,8 @@
+package issue39614
+
+func fn() {
+ var foo bool //@rename("foo","bar")
+ make(map[string]bool
+ if true {
+ }
+}
diff --git a/gopls/internal/lsp/testdata/rename/issue42134/1.go b/gopls/internal/lsp/testdata/rename/issue42134/1.go
new file mode 100644
index 000000000..056f8476a
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/issue42134/1.go
@@ -0,0 +1,8 @@
+package issue42134
+
+func _() {
+ // foo computes things.
+ foo := func() {}
+
+ foo() //@rename("foo", "bar")
+}
diff --git a/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden
new file mode 100644
index 000000000..266aeef4b
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden
@@ -0,0 +1,10 @@
+-- bar-rename --
+package issue42134
+
+func _() {
+ // bar computes things.
+ bar := func() {}
+
+ bar() //@rename("foo", "bar")
+}
+
diff --git a/gopls/internal/lsp/testdata/rename/issue42134/2.go b/gopls/internal/lsp/testdata/rename/issue42134/2.go
new file mode 100644
index 000000000..e9f639575
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/issue42134/2.go
@@ -0,0 +1,12 @@
+package issue42134
+
+import "fmt"
+
+func _() {
+ // minNumber is a min number.
+ // Second line.
+ minNumber := min(1, 2)
+ fmt.Println(minNumber) //@rename("minNumber", "res")
+}
+
+func min(a, b int) int { return a }
diff --git a/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden
new file mode 100644
index 000000000..406a3833c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden
@@ -0,0 +1,14 @@
+-- res-rename --
+package issue42134
+
+import "fmt"
+
+func _() {
+ // res is a min number.
+ // Second line.
+ res := min(1, 2)
+ fmt.Println(res) //@rename("minNumber", "res")
+}
+
+func min(a, b int) int { return a }
+
diff --git a/gopls/internal/lsp/testdata/rename/issue42134/3.go b/gopls/internal/lsp/testdata/rename/issue42134/3.go
new file mode 100644
index 000000000..7666f57d3
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/issue42134/3.go
@@ -0,0 +1,11 @@
+package issue42134
+
+func _() {
+ /*
+ tests contains test cases
+ */
+ tests := []struct { //@rename("tests", "testCases")
+ in, out string
+ }{}
+ _ = tests
+}
diff --git a/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden
new file mode 100644
index 000000000..cdcae1808
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden
@@ -0,0 +1,13 @@
+-- testCases-rename --
+package issue42134
+
+func _() {
+ /*
+ testCases contains test cases
+ */
+ testCases := []struct { //@rename("tests", "testCases")
+ in, out string
+ }{}
+ _ = testCases
+}
+
diff --git a/gopls/internal/lsp/testdata/rename/issue42134/4.go b/gopls/internal/lsp/testdata/rename/issue42134/4.go
new file mode 100644
index 000000000..c953520bc
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/issue42134/4.go
@@ -0,0 +1,8 @@
+package issue42134
+
+func _() {
+ // a is equal to 5. Comment must stay the same
+
+ a := 5
+ _ = a //@rename("a", "b")
+}
diff --git a/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden
new file mode 100644
index 000000000..2086cf74c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden
@@ -0,0 +1,10 @@
+-- b-rename --
+package issue42134
+
+func _() {
+ // a is equal to 5. Comment must stay the same
+
+ b := 5
+ _ = b //@rename("a", "b")
+}
+
diff --git a/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden
new file mode 100644
index 000000000..34d03ba7a
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden
@@ -0,0 +1,13 @@
+-- bar-rename --
+package issue43616
+
+type bar int //@rename("foo","bar"),prepare("oo","foo","foo")
+
+var x struct{ bar } //@rename("foo","baz")
+
+var _ = x.bar //@rename("foo","quux")
+
+-- baz-rename --
+can't rename embedded fields: rename the type directly or name the field
+-- quux-rename --
+can't rename embedded fields: rename the type directly or name the field
diff --git a/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in
new file mode 100644
index 000000000..aaad531b7
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in
@@ -0,0 +1,7 @@
+package issue43616
+
+type foo int //@rename("foo","bar"),prepare("oo","foo","foo")
+
+var x struct{ foo } //@rename("foo","baz")
+
+var _ = x.foo //@rename("foo","quux")
diff --git a/gopls/internal/lsp/testdata/rename/shadow/shadow.go b/gopls/internal/lsp/testdata/rename/shadow/shadow.go
new file mode 100644
index 000000000..38329b4fe
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/shadow/shadow.go
@@ -0,0 +1,20 @@
+package shadow
+
+func _() {
+ a := true
+ b, c, _ := A(), B(), D() //@rename("A", "a"),rename("B", "b"),rename("b", "c"),rename("D", "d")
+ d := false
+ _, _, _, _ = a, b, c, d
+}
+
+func A() int {
+ return 0
+}
+
+func B() int {
+ return 0
+}
+
+func D() int {
+ return 0
+}
diff --git a/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden b/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden
new file mode 100644
index 000000000..a34b5c0fe
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden
@@ -0,0 +1,51 @@
+-- a-rename --
+shadow/shadow.go:10:6: renaming this func "A" to "a"
+shadow/shadow.go:5:13: would cause this reference to become shadowed
+shadow/shadow.go:4:2: by this intervening var definition
+-- b-rename --
+package shadow
+
+func _() {
+ a := true
+ b, c, _ := A(), b(), D() //@rename("A", "a"),rename("B", "b"),rename("b", "c"),rename("D", "d")
+ d := false
+ _, _, _, _ = a, b, c, d
+}
+
+func A() int {
+ return 0
+}
+
+func b() int {
+ return 0
+}
+
+func D() int {
+ return 0
+}
+
+-- c-rename --
+shadow/shadow.go:5:2: renaming this var "b" to "c"
+shadow/shadow.go:5:5: conflicts with var in same block
+-- d-rename --
+package shadow
+
+func _() {
+ a := true
+ b, c, _ := A(), B(), d() //@rename("A", "a"),rename("B", "b"),rename("b", "c"),rename("D", "d")
+ d := false
+ _, _, _, _ = a, b, c, d
+}
+
+func A() int {
+ return 0
+}
+
+func B() int {
+ return 0
+}
+
+func d() int {
+ return 0
+}
+
diff --git a/gopls/internal/lsp/testdata/rename/testy/testy.go b/gopls/internal/lsp/testdata/rename/testy/testy.go
new file mode 100644
index 000000000..e46dc06cd
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/testy/testy.go
@@ -0,0 +1,7 @@
+package testy
+
+type tt int //@rename("tt", "testyType")
+
+func a() {
+ foo := 42 //@rename("foo", "bar")
+}
diff --git a/gopls/internal/lsp/testdata/rename/testy/testy.go.golden b/gopls/internal/lsp/testdata/rename/testy/testy.go.golden
new file mode 100644
index 000000000..288dfee96
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/testy/testy.go.golden
@@ -0,0 +1,18 @@
+-- bar-rename --
+package testy
+
+type tt int //@rename("tt", "testyType")
+
+func a() {
+ bar := 42 //@rename("foo", "bar")
+}
+
+-- testyType-rename --
+package testy
+
+type testyType int //@rename("tt", "testyType")
+
+func a() {
+ foo := 42 //@rename("foo", "bar")
+}
+
diff --git a/gopls/internal/lsp/testdata/rename/testy/testy_test.go b/gopls/internal/lsp/testdata/rename/testy/testy_test.go
new file mode 100644
index 000000000..3d86e8455
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/testy/testy_test.go
@@ -0,0 +1,8 @@
+package testy
+
+import "testing"
+
+func TestSomething(t *testing.T) {
+ var x int //@rename("x", "testyX")
+ a() //@rename("a", "b")
+}
diff --git a/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden b/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden
new file mode 100644
index 000000000..480c8e995
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden
@@ -0,0 +1,30 @@
+-- b-rename --
+testy.go:
+package testy
+
+type tt int //@rename("tt", "testyType")
+
+func b() {
+ foo := 42 //@rename("foo", "bar")
+}
+
+testy_test.go:
+package testy
+
+import "testing"
+
+func TestSomething(t *testing.T) {
+ var x int //@rename("x", "testyX")
+ b() //@rename("a", "b")
+}
+
+-- testyX-rename --
+package testy
+
+import "testing"
+
+func TestSomething(t *testing.T) {
+ var testyX int //@rename("x", "testyX")
+ a() //@rename("a", "b")
+}
+
diff --git a/gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go b/gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go
new file mode 100644
index 000000000..783e9a55f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go
@@ -0,0 +1,14 @@
+package rundespiteerrors
+
+// This test verifies that analyzers without RunDespiteErrors are not
+// executed on a package containing type errors (see issue #54762).
+func _() {
+ // A type error.
+ _ = 1 + "" //@diag("1", "compiler", "mismatched types|cannot convert", "error")
+
+ // A violation of an analyzer for which RunDespiteErrors=false:
+ // no diagnostic is produced; the diag comment is merely illustrative.
+ for _ = range "" { //diag("for _", "simplifyrange", "simplify range expression", "warning")
+
+ }
+}
diff --git a/gopls/internal/lsp/testdata/selectionrange/foo.go b/gopls/internal/lsp/testdata/selectionrange/foo.go
new file mode 100644
index 000000000..1bf41340c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/selectionrange/foo.go
@@ -0,0 +1,13 @@
+package foo
+
+import "time"
+
+func Bar(x, y int, t time.Time) int {
+ zs := []int{1, 2, 3} //@selectionrange("1")
+
+ for _, z := range zs {
+ x = x + z + y + zs[1] //@selectionrange("1")
+ }
+
+ return x + y //@selectionrange("+")
+}
diff --git a/gopls/internal/lsp/testdata/selectionrange/foo.go.golden b/gopls/internal/lsp/testdata/selectionrange/foo.go.golden
new file mode 100644
index 000000000..fe70b30b7
--- /dev/null
+++ b/gopls/internal/lsp/testdata/selectionrange/foo.go.golden
@@ -0,0 +1,29 @@
+-- selectionrange_foo_12_11 --
+Ranges 0:
+ 11:8-11:13 "x + y"
+ 11:1-11:13 "return x + y"
+ 4:36-12:1 "{\\n\tzs := []int{...ionrange(\"+\")\\n}"
+ 4:0-12:1 "func Bar(x, y i...ionrange(\"+\")\\n}"
+ 0:0-12:1 "package foo\\n\\nim...ionrange(\"+\")\\n}"
+
+-- selectionrange_foo_6_14 --
+Ranges 0:
+ 5:13-5:14 "1"
+ 5:7-5:21 "[]int{1, 2, 3}"
+ 5:1-5:21 "zs := []int{1, 2, 3}"
+ 4:36-12:1 "{\\n\tzs := []int{...ionrange(\"+\")\\n}"
+ 4:0-12:1 "func Bar(x, y i...ionrange(\"+\")\\n}"
+ 0:0-12:1 "package foo\\n\\nim...ionrange(\"+\")\\n}"
+
+-- selectionrange_foo_9_22 --
+Ranges 0:
+ 8:21-8:22 "1"
+ 8:18-8:23 "zs[1]"
+ 8:6-8:23 "x + z + y + zs[1]"
+ 8:2-8:23 "x = x + z + y + zs[1]"
+ 7:22-9:2 "{\\n\t\tx = x + z +...onrange(\"1\")\\n\t}"
+ 7:1-9:2 "for _, z := ran...onrange(\"1\")\\n\t}"
+ 4:36-12:1 "{\\n\tzs := []int{...ionrange(\"+\")\\n}"
+ 4:0-12:1 "func Bar(x, y i...ionrange(\"+\")\\n}"
+ 0:0-12:1 "package foo\\n\\nim...ionrange(\"+\")\\n}"
+
diff --git a/gopls/internal/lsp/testdata/selector/selector.go.in b/gopls/internal/lsp/testdata/selector/selector.go.in
new file mode 100644
index 000000000..b1498a08c
--- /dev/null
+++ b/gopls/internal/lsp/testdata/selector/selector.go.in
@@ -0,0 +1,66 @@
+// +build go1.11
+
+package selector
+
+import (
+ "golang.org/lsptests/bar"
+)
+
+type S struct {
+ B, A, C int //@item(Bf, "B", "int", "field"),item(Af, "A", "int", "field"),item(Cf, "C", "int", "field")
+}
+
+func _() {
+ _ = S{}.; //@complete(";", Af, Bf, Cf)
+}
+
+type bob struct { a int } //@item(a, "a", "int", "field")
+type george struct { b int }
+type jack struct { c int } //@item(c, "c", "int", "field")
+type jill struct { d int }
+
+func (b *bob) george() *george {} //@item(george, "george", "func() *george", "method")
+func (g *george) jack() *jack {}
+func (j *jack) jill() *jill {} //@item(jill, "jill", "func() *jill", "method")
+
+func _() {
+ b := &bob{}
+ y := b.george().
+ jack();
+ y.; //@complete(";", c, jill)
+}
+
+func _() {
+ bar. //@complete(" /", Bar)
+ x := 5
+
+ var b *bob
+ b. //@complete(" /", a, george)
+ y, z := 5, 6
+
+ b. //@complete(" /", a, george)
+ y, z, a, b, c := 5, 6
+}
+
+func _() {
+ bar. //@complete(" /", Bar)
+ bar.Bar()
+
+ bar. //@complete(" /", Bar)
+ go f()
+}
+
+func _() {
+ var b *bob
+ if y != b. //@complete(" /", a, george)
+ z := 5
+
+ if z + y + 1 + b. //@complete(" /", a, george)
+ r, s, t := 4, 5
+
+ if y != b. //@complete(" /", a, george)
+ z = 5
+
+ if z + y + 1 + b. //@complete(" /", a, george)
+ r = 4
+}
diff --git a/gopls/internal/lsp/testdata/semantic/README.md b/gopls/internal/lsp/testdata/semantic/README.md
new file mode 100644
index 000000000..00ec19af1
--- /dev/null
+++ b/gopls/internal/lsp/testdata/semantic/README.md
@@ -0,0 +1,2 @@
+The golden files are the output of `gopls semtok <src-file>`, with `-- semantic --`
+inserted as the first line (the spaces are mandatory) and an extra newline at the end.
diff --git a/gopls/internal/lsp/testdata/semantic/a.go b/gopls/internal/lsp/testdata/semantic/a.go
new file mode 100644
index 000000000..54d6c8a62
--- /dev/null
+++ b/gopls/internal/lsp/testdata/semantic/a.go
@@ -0,0 +1,81 @@
+package semantictokens //@ semantic("")
+
+import (
+ _ "encoding/utf8"
+ utf "encoding/utf8"
+ "fmt" //@ semantic("fmt")
+ . "fmt"
+ "unicode/utf8"
+)
+
+var (
+ a = fmt.Print
+ b []string = []string{"foo"}
+ c1 chan int
+ c2 <-chan int
+ c3 = make([]chan<- int)
+ b = A{X: 23}
+ m map[bool][3]*float64
+)
+
+const (
+ xx F = iota
+ yy = xx + 3
+ zz = ""
+ ww = "not " + zz
+)
+
+type A struct {
+ X int `foof`
+}
+type B interface {
+ A
+ sad(int) bool
+}
+
+type F int
+
+func (a *A) f() bool {
+ var z string
+ x := "foo"
+ a(x)
+ y := "bar" + x
+ switch z {
+ case "xx":
+ default:
+ }
+ select {
+ case z := <-c3[0]:
+ default:
+ }
+ for k, v := range m {
+ return (!k) && v[0] == nil
+ }
+ c2 <- A.X
+ w := b[4:]
+ j := len(x)
+ j--
+ q := []interface{}{j, 23i, &y}
+ g(q...)
+ return true
+}
+
+func g(vv ...interface{}) {
+ ff := func() {}
+ defer ff()
+ go utf.RuneCount("")
+ go utf8.RuneCount(vv.(string))
+ if true {
+ } else {
+ }
+Never:
+ for i := 0; i < 10; {
+ break Never
+ }
+ _, ok := vv[0].(A)
+ if !ok {
+ switch x := vv[0].(type) {
+ }
+ goto Never
+ }
+}
diff --git a/gopls/internal/lsp/testdata/semantic/a.go.golden b/gopls/internal/lsp/testdata/semantic/a.go.golden
new file mode 100644
index 000000000..047a031a7
--- /dev/null
+++ b/gopls/internal/lsp/testdata/semantic/a.go.golden
@@ -0,0 +1,83 @@
+-- semantic --
+/*⇒7,keyword,[]*/package /*⇒14,namespace,[]*/semantictokens /*⇒16,comment,[]*///@ semantic("")
+
+/*⇒6,keyword,[]*/import (
+ _ "encoding/utf8"
+ /*⇒3,namespace,[]*/utf "encoding/utf8"
+ "fmt"/*⇐3,namespace,[]*/ /*⇒19,comment,[]*///@ semantic("fmt")
+ . "fmt"
+ "unicode/utf8"/*⇐4,namespace,[]*/
+)
+
+/*⇒3,keyword,[]*/var (
+ /*⇒1,variable,[definition]*/a = /*⇒3,namespace,[]*/fmt./*⇒5,function,[]*/Print
+ /*⇒1,variable,[definition]*/b []/*⇒6,type,[defaultLibrary]*/string = []/*⇒6,type,[defaultLibrary]*/string{/*⇒5,string,[]*/"foo"}
+ /*⇒2,variable,[definition]*/c1 /*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int
+ /*⇒2,variable,[definition]*/c2 /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int
+ /*⇒2,variable,[definition]*/c3 = /*⇒4,function,[defaultLibrary]*/make([]/*⇒4,keyword,[]*/chan/*⇒2,operator,[]*/<- /*⇒3,type,[defaultLibrary]*/int)
+ /*⇒1,variable,[definition]*/b = /*⇒1,type,[]*/A{/*⇒1,variable,[]*/X: /*⇒2,number,[]*/23}
+ /*⇒1,variable,[definition]*/m /*⇒3,keyword,[]*/map[/*⇒4,type,[defaultLibrary]*/bool][/*⇒1,number,[]*/3]/*⇒1,operator,[]*/*/*⇒7,type,[defaultLibrary]*/float64
+)
+
+/*⇒5,keyword,[]*/const (
+ /*⇒2,variable,[definition readonly]*/xx /*⇒1,type,[]*/F = /*⇒4,variable,[readonly]*/iota
+ /*⇒2,variable,[definition readonly]*/yy = /*⇒2,variable,[readonly]*/xx /*⇒1,operator,[]*/+ /*⇒1,number,[]*/3
+ /*⇒2,variable,[definition readonly]*/zz = /*⇒2,string,[]*/""
+ /*⇒2,variable,[definition readonly]*/ww = /*⇒6,string,[]*/"not " /*⇒1,operator,[]*/+ /*⇒2,variable,[readonly]*/zz
+)
+
+/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/A /*⇒6,keyword,[]*/struct {
+ /*⇒1,variable,[definition]*/X /*⇒3,type,[defaultLibrary]*/int /*⇒6,string,[]*/`foof`
+}
+/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/B /*⇒9,keyword,[]*/interface {
+ /*⇒1,type,[]*/A
+ /*⇒3,method,[definition]*/sad(/*⇒3,type,[defaultLibrary]*/int) /*⇒4,type,[defaultLibrary]*/bool
+}
+
+/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/F /*⇒3,type,[defaultLibrary]*/int
+
+/*⇒4,keyword,[]*/func (/*⇒1,variable,[]*/a /*⇒1,operator,[]*/*/*⇒1,type,[]*/A) /*⇒1,method,[definition]*/f() /*⇒4,type,[defaultLibrary]*/bool {
+ /*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/z /*⇒6,type,[defaultLibrary]*/string
+ /*⇒1,variable,[definition]*/x /*⇒2,operator,[]*/:= /*⇒5,string,[]*/"foo"
+ /*⇒1,variable,[]*/a(/*⇒1,variable,[]*/x)
+ /*⇒1,variable,[definition]*/y /*⇒2,operator,[]*/:= /*⇒5,string,[]*/"bar" /*⇒1,operator,[]*/+ /*⇒1,variable,[]*/x
+ /*⇒6,keyword,[]*/switch /*⇒1,variable,[]*/z {
+ /*⇒4,keyword,[]*/case /*⇒4,string,[]*/"xx":
+ /*⇒7,keyword,[]*/default:
+ }
+ /*⇒6,keyword,[]*/select {
+ /*⇒4,keyword,[]*/case /*⇒1,variable,[definition]*/z /*⇒2,operator,[]*/:= /*⇒2,operator,[]*/<-/*⇒2,variable,[]*/c3[/*⇒1,number,[]*/0]:
+ /*⇒7,keyword,[]*/default:
+ }
+ /*⇒3,keyword,[]*/for /*⇒1,variable,[definition]*/k, /*⇒1,variable,[definition]*/v := /*⇒5,keyword,[]*/range /*⇒1,variable,[]*/m {
+ /*⇒6,keyword,[]*/return (/*⇒1,operator,[]*/!/*⇒1,variable,[]*/k) /*⇒2,operator,[]*/&& /*⇒1,variable,[]*/v[/*⇒1,number,[]*/0] /*⇒2,operator,[]*/== /*⇒3,variable,[readonly defaultLibrary]*/nil
+ }
+ /*⇒2,variable,[]*/c2 /*⇒2,operator,[]*/<- /*⇒1,type,[]*/A./*⇒1,variable,[]*/X
+ /*⇒1,variable,[definition]*/w /*⇒2,operator,[]*/:= /*⇒1,variable,[]*/b[/*⇒1,number,[]*/4:]
+ /*⇒1,variable,[definition]*/j /*⇒2,operator,[]*/:= /*⇒3,function,[defaultLibrary]*/len(/*⇒1,variable,[]*/x)
+ /*⇒1,variable,[]*/j/*⇒2,operator,[]*/--
+ /*⇒1,variable,[definition]*/q /*⇒2,operator,[]*/:= []/*⇒9,keyword,[]*/interface{}{/*⇒1,variable,[]*/j, /*⇒3,number,[]*/23i, /*⇒1,operator,[]*/&/*⇒1,variable,[]*/y}
+ /*⇒1,function,[]*/g(/*⇒1,variable,[]*/q/*⇒3,operator,[]*/...)
+ /*⇒6,keyword,[]*/return /*⇒4,variable,[readonly]*/true
+}
+
+/*⇒4,keyword,[]*/func /*⇒1,function,[definition]*/g(/*⇒2,parameter,[definition]*/vv /*⇒3,operator,[]*/.../*⇒9,keyword,[]*/interface{}) {
+ /*⇒2,variable,[definition]*/ff /*⇒2,operator,[]*/:= /*⇒4,keyword,[]*/func() {}
+ /*⇒5,keyword,[]*/defer /*⇒2,function,[]*/ff()
+ /*⇒2,keyword,[]*/go /*⇒3,namespace,[]*/utf./*⇒9,function,[]*/RuneCount(/*⇒2,string,[]*/"")
+ /*⇒2,keyword,[]*/go /*⇒4,namespace,[]*/utf8./*⇒9,function,[]*/RuneCount(/*⇒2,parameter,[]*/vv.(/*⇒6,type,[]*/string))
+ /*⇒2,keyword,[]*/if /*⇒4,variable,[readonly]*/true {
+ } /*⇒4,keyword,[]*/else {
+ }
+/*⇒5,parameter,[definition]*/Never:
+ /*⇒3,keyword,[]*/for /*⇒1,variable,[definition]*/i /*⇒2,operator,[]*/:= /*⇒1,number,[]*/0; /*⇒1,variable,[]*/i /*⇒1,operator,[]*/< /*⇒2,number,[]*/10; {
+ /*⇒5,keyword,[]*/break Never
+ }
+ _, /*⇒2,variable,[definition]*/ok /*⇒2,operator,[]*/:= /*⇒2,parameter,[]*/vv[/*⇒1,number,[]*/0].(/*⇒1,type,[]*/A)
+ /*⇒2,keyword,[]*/if /*⇒1,operator,[]*/!/*⇒2,variable,[]*/ok {
+ /*⇒6,keyword,[]*/switch /*⇒1,variable,[definition]*/x /*⇒2,operator,[]*/:= /*⇒2,parameter,[]*/vv[/*⇒1,number,[]*/0].(/*⇒4,keyword,[]*/type) {
+ }
+ /*⇒4,keyword,[]*/goto Never
+ }
+}
+
diff --git a/gopls/internal/lsp/testdata/semantic/b.go b/gopls/internal/lsp/testdata/semantic/b.go
new file mode 100644
index 000000000..496b0863d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/semantic/b.go
@@ -0,0 +1,38 @@
+package semantictokens //@ semantic("")
+
+func f(x ...interface{}) {
+}
+
+func weirⰀd() { /*😀*/ // comment
+ const (
+ snil = nil
+ nil = true
+ true = false
+ false = snil
+ cmd = `foof`
+ double = iota
+ iota = copy
+ four = (len(cmd)/2 < 5)
+ five = four
+ )
+ f(cmd, nil, double, iota)
+}
+
+/*
+
+multiline */ /*
+multiline
+*/
+type AA int
+type BB struct {
+ AA
+}
+type CC struct {
+ AA int
+}
+type D func(aa AA) (BB error)
+type E func(AA) BB
+
+var a chan<- chan int
+var b chan<- <-chan int
+var c <-chan <-chan int
diff --git a/gopls/internal/lsp/testdata/semantic/b.go.golden b/gopls/internal/lsp/testdata/semantic/b.go.golden
new file mode 100644
index 000000000..59071374b
--- /dev/null
+++ b/gopls/internal/lsp/testdata/semantic/b.go.golden
@@ -0,0 +1,40 @@
+-- semantic --
+/*⇒7,keyword,[]*/package /*⇒14,namespace,[]*/semantictokens /*⇒16,comment,[]*///@ semantic("")
+
+/*⇒4,keyword,[]*/func /*⇒1,function,[definition]*/f(/*⇒1,parameter,[definition]*/x /*⇒3,operator,[]*/.../*⇒9,keyword,[]*/interface{}) {
+}
+
+/*⇒4,keyword,[]*/func /*⇒6,function,[definition]*/weirⰀd() { /*⇒5,comment,[]*//*😀*/ /*⇒10,comment,[]*/// comment
+ /*⇒5,keyword,[]*/const (
+ /*⇒4,variable,[definition readonly]*/snil = /*⇒3,variable,[readonly defaultLibrary]*/nil
+ /*⇒3,variable,[definition readonly]*/nil = /*⇒4,variable,[readonly]*/true
+ /*⇒4,variable,[definition readonly]*/true = /*⇒5,variable,[readonly]*/false
+ /*⇒5,variable,[definition readonly]*/false = /*⇒4,variable,[readonly]*/snil
+ /*⇒3,variable,[definition readonly]*/cmd = /*⇒6,string,[]*/`foof`
+ /*⇒6,variable,[definition readonly]*/double = /*⇒4,variable,[readonly]*/iota
+ /*⇒4,variable,[definition readonly]*/iota = /*⇒4,function,[defaultLibrary]*/copy
+ /*⇒4,variable,[definition readonly]*/four = (/*⇒3,function,[defaultLibrary]*/len(/*⇒3,variable,[readonly]*/cmd)/*⇒1,operator,[]*// /*⇒1,number,[]*/2 /*⇒1,operator,[]*/< /*⇒1,number,[]*/5)
+ /*⇒4,variable,[definition readonly]*/five = /*⇒4,variable,[readonly]*/four
+ )
+ /*⇒1,function,[]*/f(/*⇒3,variable,[readonly]*/cmd, /*⇒3,variable,[readonly]*/nil, /*⇒6,variable,[readonly]*/double, /*⇒4,variable,[readonly]*/iota)
+}
+
+/*⇒2,comment,[]*//*
+/*⇒0,comment,[]*/
+/*⇒12,comment,[]*/multiline */ /*⇒2,comment,[]*//*
+/*⇒9,comment,[]*/multiline
+/*⇒2,comment,[]*/*/
+/*⇒4,keyword,[]*/type /*⇒2,type,[definition]*/AA /*⇒3,type,[defaultLibrary]*/int
+/*⇒4,keyword,[]*/type /*⇒2,type,[definition]*/BB /*⇒6,keyword,[]*/struct {
+ /*⇒2,type,[]*/AA
+}
+/*⇒4,keyword,[]*/type /*⇒2,type,[definition]*/CC /*⇒6,keyword,[]*/struct {
+ /*⇒2,variable,[definition]*/AA /*⇒3,type,[defaultLibrary]*/int
+}
+/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/D /*⇒4,keyword,[]*/func(/*⇒2,parameter,[definition]*/aa /*⇒2,type,[]*/AA) (/*⇒2,parameter,[definition]*/BB /*⇒5,type,[]*/error)
+/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/E /*⇒4,keyword,[]*/func(/*⇒2,type,[]*/AA) /*⇒2,type,[]*/BB
+
+/*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/a /*⇒4,keyword,[]*/chan/*⇒2,operator,[]*/<- /*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int
+/*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/b /*⇒4,keyword,[]*/chan/*⇒2,operator,[]*/<- /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int
+/*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/c /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int
+
diff --git a/gopls/internal/lsp/testdata/semantic/semantic_test.go b/gopls/internal/lsp/testdata/semantic/semantic_test.go
new file mode 100644
index 000000000..63d59f666
--- /dev/null
+++ b/gopls/internal/lsp/testdata/semantic/semantic_test.go
@@ -0,0 +1,13 @@
+package semantictokens
+
+import (
+ "os"
+ "testing"
+)
+
+func TestSemanticTokens(t *testing.T) {
+ a, _ := os.Getwd()
+ // climb up to find internal/lsp
+ // find all the .go files
+
+}
diff --git a/gopls/internal/lsp/testdata/signature/signature.go b/gopls/internal/lsp/testdata/signature/signature.go
new file mode 100644
index 000000000..4e2b12bc4
--- /dev/null
+++ b/gopls/internal/lsp/testdata/signature/signature.go
@@ -0,0 +1,85 @@
+// Package signature has tests for signature help.
+package signature
+
+import (
+ "bytes"
+ "encoding/json"
+ "math/big"
+)
+
+func Foo(a string, b int) (c bool) {
+ return
+}
+
+func Bar(float64, ...byte) {
+}
+
+type myStruct struct{}
+
+func (*myStruct) foo(e *json.Decoder) (*big.Int, error) {
+ return nil, nil
+}
+
+type MyType struct{}
+
+type MyFunc func(foo int) string
+
+type Alias = int
+type OtherAlias = int
+type StringAlias = string
+
+func AliasSlice(a []*Alias) (b Alias) { return 0 }
+func AliasMap(a map[*Alias]StringAlias) (b, c map[*Alias]StringAlias) { return nil, nil }
+func OtherAliasMap(a, b map[Alias]OtherAlias) map[Alias]OtherAlias { return nil }
+
+func Qux() {
+ Foo("foo", 123) //@signature("(", "Foo(a string, b int) (c bool)", 0)
+ Foo("foo", 123) //@signature("123", "Foo(a string, b int) (c bool)", 1)
+ Foo("foo", 123) //@signature(",", "Foo(a string, b int) (c bool)", 0)
+ Foo("foo", 123) //@signature(" 1", "Foo(a string, b int) (c bool)", 1)
+ Foo("foo", 123) //@signature(")", "Foo(a string, b int) (c bool)", 1)
+
+ Bar(13.37, 0x13) //@signature("13.37", "Bar(float64, ...byte)", 0)
+ Bar(13.37, 0x37) //@signature("0x37", "Bar(float64, ...byte)", 1)
+ Bar(13.37, 1, 2, 3, 4) //@signature("4", "Bar(float64, ...byte)", 1)
+
+ fn := func(hi, there string) func(i int) rune {
+ return func(int) rune { return 0 }
+ }
+
+ fn("hi", "there") //@signature("hi", "", 0)
+ fn("hi", "there") //@signature(",", "fn(hi string, there string) func(i int) rune", 0)
+ fn("hi", "there")(1) //@signature("1", "func(i int) rune", 0)
+
+ fnPtr := &fn
+ (*fnPtr)("hi", "there") //@signature(",", "func(hi string, there string) func(i int) rune", 0)
+
+ var fnIntf interface{} = Foo
+ fnIntf.(func(string, int) bool)("hi", 123) //@signature("123", "func(string, int) bool", 1)
+
+ (&bytes.Buffer{}).Next(2) //@signature("2", "Next(n int) []byte", 0)
+
+ myFunc := MyFunc(func(n int) string { return "" })
+ myFunc(123) //@signature("123", "myFunc(foo int) string", 0)
+
+ var ms myStruct
+ ms.foo(nil) //@signature("nil", "foo(e *json.Decoder) (*big.Int, error)", 0)
+
+ _ = make([]int, 1, 2) //@signature("2", "make(t Type, size ...int) Type", 1)
+
+ Foo(myFunc(123), 456) //@signature("myFunc", "Foo(a string, b int) (c bool)", 0)
+ Foo(myFunc(123), 456) //@signature("123", "myFunc(foo int) string", 0)
+
+ panic("oops!") //@signature(")", "panic(v interface{})", 0)
+ println("hello", "world") //@signature(",", "println(args ...Type)", 0)
+
+ Hello(func() {
+ //@signature("//", "", 0)
+ })
+
+ AliasSlice() //@signature(")", "AliasSlice(a []*Alias) (b Alias)", 0)
+ AliasMap() //@signature(")", "AliasMap(a map[*Alias]StringAlias) (b map[*Alias]StringAlias, c map[*Alias]StringAlias)", 0)
+ OtherAliasMap() //@signature(")", "OtherAliasMap(a map[Alias]OtherAlias, b map[Alias]OtherAlias) map[Alias]OtherAlias", 0)
+}
+
+func Hello(func()) {}
diff --git a/gopls/internal/lsp/testdata/signature/signature.go.golden b/gopls/internal/lsp/testdata/signature/signature.go.golden
new file mode 100644
index 000000000..90a4facf9
--- /dev/null
+++ b/gopls/internal/lsp/testdata/signature/signature.go.golden
@@ -0,0 +1,53 @@
+-- AliasMap(a map[*Alias]StringAlias) (b map[*Alias]StringAlias, c map[*Alias]StringAlias)-signature --
+AliasMap(a map[*Alias]StringAlias) (b map[*Alias]StringAlias, c map[*Alias]StringAlias)
+
+-- AliasSlice(a []*Alias) (b Alias)-signature --
+AliasSlice(a []*Alias) (b Alias)
+
+-- Bar(float64, ...byte)-signature --
+Bar(float64, ...byte)
+
+-- Foo(a string, b int) (c bool)-signature --
+Foo(a string, b int) (c bool)
+
+-- Next(n int) []byte-signature --
+Next(n int) []byte
+
+Next returns a slice containing the next n bytes from the buffer, advancing the buffer as if the bytes had been returned by Read.
+
+-- OtherAliasMap(a map[Alias]OtherAlias, b map[Alias]OtherAlias) map[Alias]OtherAlias-signature --
+OtherAliasMap(a map[Alias]OtherAlias, b map[Alias]OtherAlias) map[Alias]OtherAlias
+
+-- fn(hi string, there string) func(i int) rune-signature --
+fn(hi string, there string) func(i int) rune
+
+-- foo(e *json.Decoder) (*big.Int, error)-signature --
+foo(e *json.Decoder) (*big.Int, error)
+
+-- func(hi string, there string) func(i int) rune-signature --
+func(hi string, there string) func(i int) rune
+
+-- func(i int) rune-signature --
+func(i int) rune
+
+-- func(string, int) bool-signature --
+func(string, int) bool
+
+-- make(t Type, size ...int) Type-signature --
+make(t Type, size ...int) Type
+
+The make built-in function allocates and initializes an object of type slice, map, or chan (only).
+
+-- myFunc(foo int) string-signature --
+myFunc(foo int) string
+
+-- panic(v interface{})-signature --
+panic(v any)
+
+The panic built-in function stops normal execution of the current goroutine.
+
+-- println(args ...Type)-signature --
+println(args ...Type)
+
+The println built-in function formats its arguments in an implementation-specific way and writes the result to standard error.
+
diff --git a/gopls/internal/lsp/testdata/signature/signature2.go.golden b/gopls/internal/lsp/testdata/signature/signature2.go.golden
new file mode 100644
index 000000000..e8102584f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/signature/signature2.go.golden
@@ -0,0 +1,3 @@
+-- Foo(a string, b int) (c bool)-signature --
+Foo(a string, b int) (c bool)
+
diff --git a/gopls/internal/lsp/testdata/signature/signature2.go.in b/gopls/internal/lsp/testdata/signature/signature2.go.in
new file mode 100644
index 000000000..16355ffc0
--- /dev/null
+++ b/gopls/internal/lsp/testdata/signature/signature2.go.in
@@ -0,0 +1,5 @@
+package signature
+
+func _() {
+ Foo(//@signature("//", "Foo(a string, b int) (c bool)", 0)
+}
diff --git a/gopls/internal/lsp/testdata/signature/signature3.go.golden b/gopls/internal/lsp/testdata/signature/signature3.go.golden
new file mode 100644
index 000000000..e8102584f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/signature/signature3.go.golden
@@ -0,0 +1,3 @@
+-- Foo(a string, b int) (c bool)-signature --
+Foo(a string, b int) (c bool)
+
diff --git a/gopls/internal/lsp/testdata/signature/signature3.go.in b/gopls/internal/lsp/testdata/signature/signature3.go.in
new file mode 100644
index 000000000..032be1304
--- /dev/null
+++ b/gopls/internal/lsp/testdata/signature/signature3.go.in
@@ -0,0 +1,5 @@
+package signature
+
+func _() {
+ Foo("hello",//@signature("//", "Foo(a string, b int) (c bool)", 1)
+} \ No newline at end of file
diff --git a/gopls/internal/lsp/testdata/signature/signature_test.go b/gopls/internal/lsp/testdata/signature/signature_test.go
new file mode 100644
index 000000000..500247dbd
--- /dev/null
+++ b/gopls/internal/lsp/testdata/signature/signature_test.go
@@ -0,0 +1,13 @@
+package signature_test
+
+import (
+ "testing"
+
+ sig "golang.org/lsptests/signature"
+)
+
+func TestSignature(t *testing.T) {
+ sig.AliasSlice() //@signature(")", "AliasSlice(a []*sig.Alias) (b sig.Alias)", 0)
+ sig.AliasMap() //@signature(")", "AliasMap(a map[*sig.Alias]sig.StringAlias) (b map[*sig.Alias]sig.StringAlias, c map[*sig.Alias]sig.StringAlias)", 0)
+ sig.OtherAliasMap() //@signature(")", "OtherAliasMap(a map[sig.Alias]sig.OtherAlias, b map[sig.Alias]sig.OtherAlias) map[sig.Alias]sig.OtherAlias", 0)
+}
diff --git a/gopls/internal/lsp/testdata/signature/signature_test.go.golden b/gopls/internal/lsp/testdata/signature/signature_test.go.golden
new file mode 100644
index 000000000..9e6561ac5
--- /dev/null
+++ b/gopls/internal/lsp/testdata/signature/signature_test.go.golden
@@ -0,0 +1,9 @@
+-- AliasMap(a map[*sig.Alias]sig.StringAlias) (b map[*sig.Alias]sig.StringAlias, c map[*sig.Alias]sig.StringAlias)-signature --
+AliasMap(a map[*sig.Alias]sig.StringAlias) (b map[*sig.Alias]sig.StringAlias, c map[*sig.Alias]sig.StringAlias)
+
+-- AliasSlice(a []*sig.Alias) (b sig.Alias)-signature --
+AliasSlice(a []*sig.Alias) (b sig.Alias)
+
+-- OtherAliasMap(a map[sig.Alias]sig.OtherAlias, b map[sig.Alias]sig.OtherAlias) map[sig.Alias]sig.OtherAlias-signature --
+OtherAliasMap(a map[sig.Alias]sig.OtherAlias, b map[sig.Alias]sig.OtherAlias) map[sig.Alias]sig.OtherAlias
+
diff --git a/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in b/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in
new file mode 100644
index 000000000..d4933689d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in
@@ -0,0 +1,19 @@
+// +build go1.18
+//go:build go1.18
+
+package snippets
+
+type SyncMap[K comparable, V any] struct{}
+
+func NewSyncMap[K comparable, V any]() (result *SyncMap[K, V]) { //@item(NewSyncMap, "NewSyncMap", "", "")
+ return
+}
+
+func Identity[P ~int](p P) P { //@item(Identity, "Identity", "", "")
+ return p
+}
+
+func _() {
+ _ = NewSyncM //@snippet(" //", NewSyncMap, "NewSyncMap[${1:}]()", "NewSyncMap[${1:K comparable}, ${2:V any}]()")
+ _ = Identi //@snippet(" //", Identity, "Identity[${1:}](${2:})", "Identity[${1:P ~int}](${2:p P})")
+}
diff --git a/gopls/internal/lsp/testdata/snippets/literal.go b/gopls/internal/lsp/testdata/snippets/literal.go
new file mode 100644
index 000000000..fbb642f08
--- /dev/null
+++ b/gopls/internal/lsp/testdata/snippets/literal.go
@@ -0,0 +1,22 @@
+package snippets
+
+import (
+ "golang.org/lsptests/signature"
+ t "golang.org/lsptests/types"
+)
+
+type structy struct {
+ x signature.MyType
+}
+
+func X(_ map[signature.Alias]t.CoolAlias) (map[signature.Alias]t.CoolAlias) {
+ return nil
+}
+
+func _() {
+ X() //@signature(")", "X(_ map[signature.Alias]t.CoolAlias) map[signature.Alias]t.CoolAlias", 0)
+ _ = signature.MyType{} //@item(literalMyType, "signature.MyType{}", "", "var")
+ s := structy{
+ x: //@snippet(" //", literalMyType, "signature.MyType{\\}", "signature.MyType{\\}")
+ }
+} \ No newline at end of file
diff --git a/gopls/internal/lsp/testdata/snippets/literal.go.golden b/gopls/internal/lsp/testdata/snippets/literal.go.golden
new file mode 100644
index 000000000..c91e5e9e0
--- /dev/null
+++ b/gopls/internal/lsp/testdata/snippets/literal.go.golden
@@ -0,0 +1,3 @@
+-- X(_ map[signature.Alias]t.CoolAlias) map[signature.Alias]t.CoolAlias-signature --
+X(_ map[signature.Alias]t.CoolAlias) map[signature.Alias]t.CoolAlias
+
diff --git a/gopls/internal/lsp/testdata/snippets/literal_snippets.go.in b/gopls/internal/lsp/testdata/snippets/literal_snippets.go.in
new file mode 100644
index 000000000..c6e6c0fbd
--- /dev/null
+++ b/gopls/internal/lsp/testdata/snippets/literal_snippets.go.in
@@ -0,0 +1,233 @@
+package snippets
+
+import (
+ "bytes"
+ "context"
+ "go/ast"
+ "net/http"
+ "sort"
+
+ "golang.org/lsptests/foo"
+)
+
+func _() {
+ []int{} //@item(litIntSlice, "[]int{}", "", "var")
+ &[]int{} //@item(litIntSliceAddr, "&[]int{}", "", "var")
+ make([]int, 0) //@item(makeIntSlice, "make([]int, 0)", "", "func")
+
+ var _ *[]int = in //@snippet(" //", litIntSliceAddr, "&[]int{$0\\}", "&[]int{$0\\}")
+ var _ **[]int = in //@complete(" //")
+
+ var slice []int
+ slice = i //@snippet(" //", litIntSlice, "[]int{$0\\}", "[]int{$0\\}")
+ slice = m //@snippet(" //", makeIntSlice, "make([]int, ${1:})", "make([]int, ${1:0})")
+}
+
+func _() {
+ type namedInt []int
+
+ namedInt{} //@item(litNamedSlice, "namedInt{}", "", "var")
+ make(namedInt, 0) //@item(makeNamedSlice, "make(namedInt, 0)", "", "func")
+
+ var namedSlice namedInt
+ namedSlice = n //@snippet(" //", litNamedSlice, "namedInt{$0\\}", "namedInt{$0\\}")
+ namedSlice = m //@snippet(" //", makeNamedSlice, "make(namedInt, ${1:})", "make(namedInt, ${1:0})")
+}
+
+func _() {
+ make(chan int) //@item(makeChan, "make(chan int)", "", "func")
+
+ var ch chan int
+ ch = m //@snippet(" //", makeChan, "make(chan int)", "make(chan int)")
+}
+
+func _() {
+ map[string]struct{}{} //@item(litMap, "map[string]struct{}{}", "", "var")
+ make(map[string]struct{}) //@item(makeMap, "make(map[string]struct{})", "", "func")
+
+ var m map[string]struct{}
+ m = m //@snippet(" //", litMap, "map[string]struct{\\}{$0\\}", "map[string]struct{\\}{$0\\}")
+ m = m //@snippet(" //", makeMap, "make(map[string]struct{\\})", "make(map[string]struct{\\})")
+
+ struct{}{} //@item(litEmptyStruct, "struct{}{}", "", "var")
+
+ m["hi"] = s //@snippet(" //", litEmptyStruct, "struct{\\}{\\}", "struct{\\}{\\}")
+}
+
+func _() {
+ type myStruct struct{ i int } //@item(myStructType, "myStruct", "struct{...}", "struct")
+
+ myStruct{} //@item(litStruct, "myStruct{}", "", "var")
+ &myStruct{} //@item(litStructPtr, "&myStruct{}", "", "var")
+
+ var ms myStruct
+ ms = m //@snippet(" //", litStruct, "myStruct{$0\\}", "myStruct{$0\\}")
+
+ var msPtr *myStruct
+ msPtr = m //@snippet(" //", litStructPtr, "&myStruct{$0\\}", "&myStruct{$0\\}")
+
+ msPtr = &m //@snippet(" //", litStruct, "myStruct{$0\\}", "myStruct{$0\\}")
+
+ type myStructCopy struct { i int } //@item(myStructCopyType, "myStructCopy", "struct{...}", "struct")
+
+ // Don't offer literal completion for convertible structs.
+ ms = myStruct //@complete(" //", litStruct, myStructType, myStructCopyType)
+}
+
+type myImpl struct{}
+
+func (myImpl) foo() {}
+
+func (*myImpl) bar() {}
+
+type myBasicImpl string
+
+func (myBasicImpl) foo() {}
+
+func _() {
+ type myIntf interface {
+ foo()
+ }
+
+ myImpl{} //@item(litImpl, "myImpl{}", "", "var")
+
+ var mi myIntf
+ mi = m //@snippet(" //", litImpl, "myImpl{\\}", "myImpl{\\}")
+
+ myBasicImpl() //@item(litBasicImpl, "myBasicImpl()", "string", "var")
+
+ mi = m //@snippet(" //", litBasicImpl, "myBasicImpl($0)", "myBasicImpl($0)")
+
+ // only satisfied by pointer to myImpl
+ type myPtrIntf interface {
+ bar()
+ }
+
+ &myImpl{} //@item(litImplPtr, "&myImpl{}", "", "var")
+
+ var mpi myPtrIntf
+ mpi = m //@snippet(" //", litImplPtr, "&myImpl{\\}", "&myImpl{\\}")
+}
+
+func _() {
+ var s struct{ i []int } //@item(litSliceField, "i", "[]int", "field")
+ var foo []int
+ // no literal completions after selector
+ foo = s.i //@complete(" //", litSliceField)
+}
+
+func _() {
+ type myStruct struct{ i int } //@item(litMyStructType, "myStruct", "struct{...}", "struct")
+ myStruct{} //@item(litMyStruct, "myStruct{}", "", "var")
+
+ foo := func(s string, args ...myStruct) {}
+ // Don't give literal slice candidate for variadic arg.
+ // Do give literal candidates for variadic element.
+ foo("", myStruct) //@complete(")", litMyStruct, litMyStructType)
+}
+
+func _() {
+ Buffer{} //@item(litBuffer, "Buffer{}", "", "var")
+
+ var b *bytes.Buffer
+ b = bytes.Bu //@snippet(" //", litBuffer, "Buffer{\\}", "Buffer{\\}")
+}
+
+func _() {
+ _ = "func(...) {}" //@item(litFunc, "func(...) {}", "", "var")
+
+ sort.Slice(nil, fun) //@complete(")", litFunc),snippet(")", litFunc, "func(i, j int) bool {$0\\}", "func(i, j int) bool {$0\\}")
+
+ http.HandleFunc("", f) //@snippet(")", litFunc, "func(w http.ResponseWriter, r *http.Request) {$0\\}", "func(${1:w} http.ResponseWriter, ${2:r} *http.Request) {$0\\}")
+
+ // no literal "func" completions
+ http.Handle("", fun) //@complete(")")
+
+ http.HandlerFunc() //@item(handlerFunc, "http.HandlerFunc()", "", "var")
+ http.Handle("", h) //@snippet(")", handlerFunc, "http.HandlerFunc($0)", "http.HandlerFunc($0)")
+ http.Handle("", http.HandlerFunc()) //@snippet("))", litFunc, "func(w http.ResponseWriter, r *http.Request) {$0\\}", "func(${1:w} http.ResponseWriter, ${2:r} *http.Request) {$0\\}")
+
+ var namedReturn func(s string) (b bool)
+ namedReturn = f //@snippet(" //", litFunc, "func(s string) (b bool) {$0\\}", "func(s string) (b bool) {$0\\}")
+
+ var multiReturn func() (bool, int)
+ multiReturn = f //@snippet(" //", litFunc, "func() (bool, int) {$0\\}", "func() (bool, int) {$0\\}")
+
+ var multiNamedReturn func() (b bool, i int)
+ multiNamedReturn = f //@snippet(" //", litFunc, "func() (b bool, i int) {$0\\}", "func() (b bool, i int) {$0\\}")
+
+ var duplicateParams func(myImpl, int, myImpl)
+ duplicateParams = f //@snippet(" //", litFunc, "func(mi1 myImpl, i int, mi2 myImpl) {$0\\}", "func(${1:mi1} myImpl, ${2:i} int, ${3:mi2} myImpl) {$0\\}")
+
+ type aliasImpl = myImpl
+ var aliasParams func(aliasImpl) aliasImpl
+ aliasParams = f //@snippet(" //", litFunc, "func(ai aliasImpl) aliasImpl {$0\\}", "func(${1:ai} aliasImpl) aliasImpl {$0\\}")
+
+ const two = 2
+ var builtinTypes func([]int, [two]bool, map[string]string, struct{ i int }, interface{ foo() }, <-chan int)
+ builtinTypes = f //@snippet(" //", litFunc, "func(i1 []int, b [two]bool, m map[string]string, s struct{ i int \\}, i2 interface{ foo() \\}, c <-chan int) {$0\\}", "func(${1:i1} []int, ${2:b} [two]bool, ${3:m} map[string]string, ${4:s} struct{ i int \\}, ${5:i2} interface{ foo() \\}, ${6:c} <-chan int) {$0\\}")
+
+ var _ func(ast.Node) = f //@snippet(" //", litFunc, "func(n ast.Node) {$0\\}", "func(${1:n} ast.Node) {$0\\}")
+ var _ func(error) = f //@snippet(" //", litFunc, "func(err error) {$0\\}", "func(${1:err} error) {$0\\}")
+ var _ func(context.Context) = f //@snippet(" //", litFunc, "func(ctx context.Context) {$0\\}", "func(${1:ctx} context.Context) {$0\\}")
+
+ type context struct {}
+ var _ func(context) = f //@snippet(" //", litFunc, "func(ctx context) {$0\\}", "func(${1:ctx} context) {$0\\}")
+}
+
+func _() {
+ StructFoo{} //@item(litStructFoo, "StructFoo{}", "struct{...}", "struct")
+
+ var sfp *foo.StructFoo
+ // Don't insert the "&" before "StructFoo{}".
+ sfp = foo.Str //@snippet(" //", litStructFoo, "StructFoo{$0\\}", "StructFoo{$0\\}")
+
+ var sf foo.StructFoo
+ sf = foo.Str //@snippet(" //", litStructFoo, "StructFoo{$0\\}", "StructFoo{$0\\}")
+ sf = foo. //@snippet(" //", litStructFoo, "StructFoo{$0\\}", "StructFoo{$0\\}")
+}
+
+func _() {
+ float64() //@item(litFloat64, "float64()", "float64", "var")
+
+ // don't complete to "&float64()"
+ var _ *float64 = float64 //@complete(" //")
+
+ var f float64
+ f = fl //@complete(" //", litFloat64),snippet(" //", litFloat64, "float64($0)", "float64($0)")
+
+ type myInt int
+ myInt() //@item(litMyInt, "myInt()", "", "var")
+
+ var mi myInt
+ mi = my //@snippet(" //", litMyInt, "myInt($0)", "myInt($0)")
+}
+
+func _() {
+ type ptrStruct struct {
+ p *ptrStruct
+ }
+
+ ptrStruct{} //@item(litPtrStruct, "ptrStruct{}", "", "var")
+
+ ptrStruct{
+ p: &ptrSt, //@rank(",", litPtrStruct)
+ }
+
+ &ptrStruct{} //@item(litPtrStructPtr, "&ptrStruct{}", "", "var")
+
+ &ptrStruct{
+ p: ptrSt, //@rank(",", litPtrStructPtr)
+ }
+}
+
+func _() {
+ f := func(...[]int) {}
+ f() //@snippet(")", litIntSlice, "[]int{$0\\}", "[]int{$0\\}")
+}
+
+
+func _() {
+ // don't complete to "untyped int()"
+ []int{}[untyped] //@complete("] //")
+}
diff --git a/gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in b/gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in
new file mode 100644
index 000000000..8251a6384
--- /dev/null
+++ b/gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in
@@ -0,0 +1,14 @@
+// +build go1.18
+//go:build go1.18
+
+package snippets
+
+type Tree[T any] struct{}
+
+func (tree Tree[T]) Do(f func(s T)) {}
+
+func _() {
+ _ = "func(...) {}" //@item(litFunc, "func(...) {}", "", "var")
+ var t Tree[string]
+ t.Do(fun) //@complete(")", litFunc),snippet(")", litFunc, "func(s string) {$0\\}", "func(s string) {$0\\}")
+}
diff --git a/gopls/internal/lsp/testdata/snippets/postfix.go b/gopls/internal/lsp/testdata/snippets/postfix.go
new file mode 100644
index 000000000..d29694e83
--- /dev/null
+++ b/gopls/internal/lsp/testdata/snippets/postfix.go
@@ -0,0 +1,42 @@
+package snippets
+
+// These tests check that postfix completions do and do not show up in
+// certain cases. Tests for the postfix completion contents are under
+// regtest.
+
+func _() {
+ /* append! */ //@item(postfixAppend, "append!", "append and re-assign slice", "snippet")
+ var foo []int
+ foo.append //@rank(" //", postfixAppend)
+
+ []int{}.append //@complete(" //")
+
+ []int{}.last //@complete(" //")
+
+ /* copy! */ //@item(postfixCopy, "copy!", "duplicate slice", "snippet")
+
+ foo.copy //@rank(" //", postfixCopy)
+
+ var s struct{ i []int }
+ s.i.copy //@rank(" //", postfixCopy)
+
+ var _ []int = s.i.copy //@complete(" //")
+
+ var blah func() []int
+ blah().append //@complete(" //")
+}
+
+func _() {
+ /* append! */ //@item(postfixAppend, "append!", "append and re-assign slice", "snippet")
+ /* last! */ //@item(postfixLast, "last!", "s[len(s)-1]", "snippet")
+ /* print! */ //@item(postfixPrint, "print!", "print to stdout", "snippet")
+ /* range! */ //@item(postfixRange, "range!", "range over slice", "snippet")
+ /* reverse! */ //@item(postfixReverse, "reverse!", "reverse slice", "snippet")
+ /* sort! */ //@item(postfixSort, "sort!", "sort.Slice()", "snippet")
+ /* var! */ //@item(postfixVar, "var!", "assign to variable", "snippet")
+
+ var foo []int
+ foo. //@complete(" //", postfixAppend, postfixCopy, postfixLast, postfixPrint, postfixRange, postfixReverse, postfixSort, postfixVar)
+
+ foo = nil
+}
diff --git a/gopls/internal/lsp/testdata/snippets/snippets.go.golden b/gopls/internal/lsp/testdata/snippets/snippets.go.golden
new file mode 100644
index 000000000..3f20ba50b
--- /dev/null
+++ b/gopls/internal/lsp/testdata/snippets/snippets.go.golden
@@ -0,0 +1,3 @@
+-- baz(at AliasType, b bool)-signature --
+baz(at AliasType, b bool)
+
diff --git a/gopls/internal/lsp/testdata/snippets/snippets.go.in b/gopls/internal/lsp/testdata/snippets/snippets.go.in
new file mode 100644
index 000000000..58150c644
--- /dev/null
+++ b/gopls/internal/lsp/testdata/snippets/snippets.go.in
@@ -0,0 +1,61 @@
+package snippets
+
+type AliasType = int //@item(sigAliasType, "AliasType", "AliasType", "type")
+
+func foo(i int, b bool) {} //@item(snipFoo, "foo", "func(i int, b bool)", "func")
+func bar(fn func()) func() {} //@item(snipBar, "bar", "func(fn func())", "func")
+func baz(at AliasType, b bool) {} //@item(snipBaz, "baz", "func(at AliasType, b bool)", "func")
+
+type Foo struct {
+ Bar int //@item(snipFieldBar, "Bar", "int", "field")
+ Func func(at AliasType) error //@item(snipFieldFunc, "Func", "func(at AliasType) error", "field")
+}
+
+func (Foo) Baz() func() {} //@item(snipMethodBaz, "Baz", "func() func()", "method")
+func (Foo) BazBar() func() {} //@item(snipMethodBazBar, "BazBar", "func() func()", "method")
+func (Foo) BazBaz(at AliasType) func() {} //@item(snipMethodBazBaz, "BazBaz", "func(at AliasType) func()", "method")
+
+func _() {
+ f //@snippet(" //", snipFoo, "foo(${1:})", "foo(${1:i int}, ${2:b bool})")
+
+ bar //@snippet(" //", snipBar, "bar(${1:})", "bar(${1:fn func()})")
+
+ baz //@snippet(" //", snipBaz, "baz(${1:})", "baz(${1:at AliasType}, ${2:b bool})")
+ baz() //@signature("(", "baz(at AliasType, b bool)", 0)
+
+ bar(nil) //@snippet("(", snipBar, "bar", "bar")
+ bar(ba) //@snippet(")", snipBar, "bar(${1:})", "bar(${1:fn func()})")
+ var f Foo
+ bar(f.Ba) //@snippet(")", snipMethodBaz, "Baz()", "Baz()")
+ (bar)(nil) //@snippet(")", snipBar, "bar(${1:})", "bar(${1:fn func()})")
+ (f.Ba)() //@snippet(")", snipMethodBaz, "Baz()", "Baz()")
+
+ Foo{
+ B //@snippet(" //", snipFieldBar, "Bar: ${1:},", "Bar: ${1:int},")
+ }
+
+ Foo{
+ F //@snippet(" //", snipFieldFunc, "Func: ${1:},", "Func: ${1:func(at AliasType) error},")
+ }
+
+ Foo{B} //@snippet("}", snipFieldBar, "Bar: ${1:}", "Bar: ${1:int}")
+ Foo{} //@snippet("}", snipFieldBar, "Bar: ${1:}", "Bar: ${1:int}")
+
+ Foo{Foo{}.B} //@snippet("} ", snipFieldBar, "Bar", "Bar")
+
+ var err error
+ err.Error() //@snippet("E", Error, "Error()", "Error()")
+ f.Baz() //@snippet("B", snipMethodBaz, "Baz()", "Baz()")
+
+ f.Baz() //@snippet("(", snipMethodBazBar, "BazBar", "BazBar")
+
+ f.Baz() //@snippet("B", snipMethodBazBaz, "BazBaz(${1:})", "BazBaz(${1:at AliasType})")
+}
+
+func _() {
+ type bar struct {
+ a int
+ b float64 //@item(snipBarB, "b", "float64", "field")
+ }
+ bar{b} //@snippet("}", snipBarB, "b: ${1:}", "b: ${1:float64}")
+}
diff --git a/gopls/internal/lsp/testdata/statements/append.go b/gopls/internal/lsp/testdata/statements/append.go
new file mode 100644
index 000000000..0eea85a28
--- /dev/null
+++ b/gopls/internal/lsp/testdata/statements/append.go
@@ -0,0 +1,42 @@
+package statements
+
+func _() {
+ type mySlice []int
+
+ var (
+ abc []int //@item(stmtABC, "abc", "[]int", "var")
+ abcdef mySlice //@item(stmtABCDEF, "abcdef", "mySlice", "var")
+ )
+
+ /* abcdef = append(abcdef, ) */ //@item(stmtABCDEFAssignAppend, "abcdef = append(abcdef, )", "", "func")
+
+ // don't offer "abc = append(abc, )" because "abc" isn't necessarily
+ // better than "abcdef".
+ abc //@complete(" //", stmtABC, stmtABCDEF)
+
+ abcdef //@complete(" //", stmtABCDEF, stmtABCDEFAssignAppend)
+
+ /* append(abc, ) */ //@item(stmtABCAppend, "append(abc, )", "", "func")
+
+ abc = app //@snippet(" //", stmtABCAppend, "append(abc, ${1:})", "append(abc, ${1:})")
+}
+
+func _() {
+ var s struct{ xyz []int }
+
+ /* xyz = append(s.xyz, ) */ //@item(stmtXYZAppend, "xyz = append(s.xyz, )", "", "func")
+
+ s.x //@snippet(" //", stmtXYZAppend, "xyz = append(s.xyz, ${1:})", "xyz = append(s.xyz, ${1:})")
+
+ /* s.xyz = append(s.xyz, ) */ //@item(stmtDeepXYZAppend, "s.xyz = append(s.xyz, )", "", "func")
+
+ sx //@snippet(" //", stmtDeepXYZAppend, "s.xyz = append(s.xyz, ${1:})", "s.xyz = append(s.xyz, ${1:})")
+}
+
+func _() {
+ var foo [][]int
+
+ /* append(foo[0], ) */ //@item(stmtFooAppend, "append(foo[0], )", "", "func")
+
+ foo[0] = app //@complete(" //"),snippet(" //", stmtFooAppend, "append(foo[0], ${1:})", "append(foo[0], ${1:})")
+}
diff --git a/gopls/internal/lsp/testdata/statements/if_err_check_return.go b/gopls/internal/lsp/testdata/statements/if_err_check_return.go
new file mode 100644
index 000000000..e82b78333
--- /dev/null
+++ b/gopls/internal/lsp/testdata/statements/if_err_check_return.go
@@ -0,0 +1,27 @@
+package statements
+
+import (
+ "bytes"
+ "io"
+ "os"
+)
+
+func one() (int, float32, io.Writer, *int, []int, bytes.Buffer, error) {
+ /* if err != nil { return err } */ //@item(stmtOneIfErrReturn, "if err != nil { return err }", "", "")
+ /* err != nil { return err } */ //@item(stmtOneErrReturn, "err != nil { return err }", "", "")
+
+ _, err := os.Open("foo")
+ //@snippet("", stmtOneIfErrReturn, "", "if err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}")
+
+ _, err = os.Open("foo")
+ i //@snippet(" //", stmtOneIfErrReturn, "", "if err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}")
+
+ _, err = os.Open("foo")
+ if er //@snippet(" //", stmtOneErrReturn, "", "err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}")
+
+ _, err = os.Open("foo")
+ if //@snippet(" //", stmtOneIfErrReturn, "", "if err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}")
+
+ _, err = os.Open("foo")
+ if //@snippet("//", stmtOneIfErrReturn, "", "if err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}")
+}
diff --git a/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go b/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go
new file mode 100644
index 000000000..e2dce804f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go
@@ -0,0 +1,12 @@
+package statements
+
+import "os"
+
+func two() error {
+ var s struct{ err error }
+
+ /* if s.err != nil { return s.err } */ //@item(stmtTwoIfErrReturn, "if s.err != nil { return s.err }", "", "")
+
+ _, s.err = os.Open("foo")
+ //@snippet("", stmtTwoIfErrReturn, "", "if s.err != nil {\n\treturn ${1:s.err}\n\\}")
+}
diff --git a/gopls/internal/lsp/testdata/statements/if_err_check_test.go b/gopls/internal/lsp/testdata/statements/if_err_check_test.go
new file mode 100644
index 000000000..6de587879
--- /dev/null
+++ b/gopls/internal/lsp/testdata/statements/if_err_check_test.go
@@ -0,0 +1,20 @@
+package statements
+
+import (
+ "os"
+ "testing"
+)
+
+func TestErr(t *testing.T) {
+ /* if err != nil { t.Fatal(err) } */ //@item(stmtOneIfErrTFatal, "if err != nil { t.Fatal(err) }", "", "")
+
+ _, err := os.Open("foo")
+ //@snippet("", stmtOneIfErrTFatal, "", "if err != nil {\n\tt.Fatal(err)\n\\}")
+}
+
+func BenchmarkErr(b *testing.B) {
+ /* if err != nil { b.Fatal(err) } */ //@item(stmtOneIfErrBFatal, "if err != nil { b.Fatal(err) }", "", "")
+
+ _, err := os.Open("foo")
+ //@snippet("", stmtOneIfErrBFatal, "", "if err != nil {\n\tb.Fatal(err)\n\\}")
+}
diff --git a/gopls/internal/lsp/testdata/stub/other/other.go b/gopls/internal/lsp/testdata/stub/other/other.go
new file mode 100644
index 000000000..ba3c1747a
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/other/other.go
@@ -0,0 +1,10 @@
+package other
+
+import (
+ "bytes"
+ renamed_context "context"
+)
+
+type Interface interface {
+ Get(renamed_context.Context) *bytes.Buffer
+}
diff --git a/gopls/internal/lsp/testdata/stub/stub_add_selector.go b/gopls/internal/lsp/testdata/stub/stub_add_selector.go
new file mode 100644
index 000000000..4037b7ad3
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_add_selector.go
@@ -0,0 +1,12 @@
+package stub
+
+import "io"
+
+// This file tests that if an interface
+// method references a type from its own package
+// then our implementation must add the import/package selector
+// in the concrete method if the concrete type is outside of the interface
+// package
+var _ io.ReaderFrom = &readerFrom{} //@suggestedfix("&readerFrom", "refactor.rewrite", "")
+
+type readerFrom struct{}
diff --git a/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden b/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden
new file mode 100644
index 000000000..8f08ca1ef
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden
@@ -0,0 +1,19 @@
+-- suggestedfix_stub_add_selector_10_23 --
+package stub
+
+import "io"
+
+// This file tests that if an interface
+// method references a type from its own package
+// then our implementation must add the import/package selector
+// in the concrete method if the concrete type is outside of the interface
+// package
+var _ io.ReaderFrom = &readerFrom{} //@suggestedfix("&readerFrom", "refactor.rewrite", "")
+
+type readerFrom struct{}
+
+// ReadFrom implements io.ReaderFrom
+func (*readerFrom) ReadFrom(r io.Reader) (n int64, err error) {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_assign.go b/gopls/internal/lsp/testdata/stub/stub_assign.go
new file mode 100644
index 000000000..d3f09313f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_assign.go
@@ -0,0 +1,10 @@
+package stub
+
+import "io"
+
+func main() {
+ var br io.ByteWriter
+ br = &byteWriter{} //@suggestedfix("&", "refactor.rewrite", "")
+}
+
+type byteWriter struct{}
diff --git a/gopls/internal/lsp/testdata/stub/stub_assign.go.golden b/gopls/internal/lsp/testdata/stub/stub_assign.go.golden
new file mode 100644
index 000000000..f15354241
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_assign.go.golden
@@ -0,0 +1,17 @@
+-- suggestedfix_stub_assign_7_7 --
+package stub
+
+import "io"
+
+func main() {
+ var br io.ByteWriter
+ br = &byteWriter{} //@suggestedfix("&", "refactor.rewrite", "")
+}
+
+type byteWriter struct{}
+
+// WriteByte implements io.ByteWriter
+func (*byteWriter) WriteByte(c byte) error {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go
new file mode 100644
index 000000000..bd36d6833
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go
@@ -0,0 +1,11 @@
+package stub
+
+import "io"
+
+func main() {
+ var br io.ByteWriter
+ var i int
+ i, br = 1, &multiByteWriter{} //@suggestedfix("&", "refactor.rewrite", "")
+}
+
+type multiByteWriter struct{}
diff --git a/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden
new file mode 100644
index 000000000..425d11746
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden
@@ -0,0 +1,18 @@
+-- suggestedfix_stub_assign_multivars_8_13 --
+package stub
+
+import "io"
+
+func main() {
+ var br io.ByteWriter
+ var i int
+ i, br = 1, &multiByteWriter{} //@suggestedfix("&", "refactor.rewrite", "")
+}
+
+type multiByteWriter struct{}
+
+// WriteByte implements io.ByteWriter
+func (*multiByteWriter) WriteByte(c byte) error {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_call_expr.go b/gopls/internal/lsp/testdata/stub/stub_call_expr.go
new file mode 100644
index 000000000..0c3094665
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_call_expr.go
@@ -0,0 +1,13 @@
+package stub
+
+func main() {
+ check(&callExpr{}) //@suggestedfix("&", "refactor.rewrite", "")
+}
+
+func check(err error) {
+ if err != nil {
+ panic(err)
+ }
+}
+
+type callExpr struct{}
diff --git a/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden b/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden
new file mode 100644
index 000000000..c82d22440
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden
@@ -0,0 +1,20 @@
+-- suggestedfix_stub_call_expr_4_8 --
+package stub
+
+func main() {
+ check(&callExpr{}) //@suggestedfix("&", "refactor.rewrite", "")
+}
+
+func check(err error) {
+ if err != nil {
+ panic(err)
+ }
+}
+
+type callExpr struct{}
+
+// Error implements error
+func (*callExpr) Error() string {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_embedded.go b/gopls/internal/lsp/testdata/stub/stub_embedded.go
new file mode 100644
index 000000000..f66989e9f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_embedded.go
@@ -0,0 +1,15 @@
+package stub
+
+import (
+ "io"
+ "sort"
+)
+
+var _ embeddedInterface = (*embeddedConcrete)(nil) //@suggestedfix("(", "refactor.rewrite", "")
+
+type embeddedConcrete struct{}
+
+type embeddedInterface interface {
+ sort.Interface
+ io.Reader
+}
diff --git a/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden b/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden
new file mode 100644
index 000000000..c1ec219e9
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden
@@ -0,0 +1,37 @@
+-- suggestedfix_stub_embedded_8_27 --
+package stub
+
+import (
+ "io"
+ "sort"
+)
+
+var _ embeddedInterface = (*embeddedConcrete)(nil) //@suggestedfix("(", "refactor.rewrite", "")
+
+type embeddedConcrete struct{}
+
+// Len implements embeddedInterface
+func (*embeddedConcrete) Len() int {
+ panic("unimplemented")
+}
+
+// Less implements embeddedInterface
+func (*embeddedConcrete) Less(i int, j int) bool {
+ panic("unimplemented")
+}
+
+// Read implements embeddedInterface
+func (*embeddedConcrete) Read(p []byte) (n int, err error) {
+ panic("unimplemented")
+}
+
+// Swap implements embeddedInterface
+func (*embeddedConcrete) Swap(i int, j int) {
+ panic("unimplemented")
+}
+
+type embeddedInterface interface {
+ sort.Interface
+ io.Reader
+}
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_err.go b/gopls/internal/lsp/testdata/stub/stub_err.go
new file mode 100644
index 000000000..121f0e794
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_err.go
@@ -0,0 +1,7 @@
+package stub
+
+func main() {
+ var br error = &customErr{} //@suggestedfix("&", "refactor.rewrite", "")
+}
+
+type customErr struct{}
diff --git a/gopls/internal/lsp/testdata/stub/stub_err.go.golden b/gopls/internal/lsp/testdata/stub/stub_err.go.golden
new file mode 100644
index 000000000..0b441bdaa
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_err.go.golden
@@ -0,0 +1,14 @@
+-- suggestedfix_stub_err_4_17 --
+package stub
+
+func main() {
+ var br error = &customErr{} //@suggestedfix("&", "refactor.rewrite", "")
+}
+
+type customErr struct{}
+
+// Error implements error
+func (*customErr) Error() string {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_function_return.go b/gopls/internal/lsp/testdata/stub/stub_function_return.go
new file mode 100644
index 000000000..41f17645e
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_function_return.go
@@ -0,0 +1,11 @@
+package stub
+
+import (
+ "io"
+)
+
+func newCloser() io.Closer {
+ return closer{} //@suggestedfix("c", "refactor.rewrite", "")
+}
+
+type closer struct{}
diff --git a/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden b/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden
new file mode 100644
index 000000000..e90712e69
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden
@@ -0,0 +1,18 @@
+-- suggestedfix_stub_function_return_8_9 --
+package stub
+
+import (
+ "io"
+)
+
+func newCloser() io.Closer {
+ return closer{} //@suggestedfix("c", "refactor.rewrite", "")
+}
+
+type closer struct{}
+
+// Close implements io.Closer
+func (closer) Close() error {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go
new file mode 100644
index 000000000..1c00569ea
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go
@@ -0,0 +1,15 @@
+//go:build go1.18
+// +build go1.18
+
+package stub
+
+import "io"
+
+// This file tests that that the stub method generator accounts for concrete
+// types that have type parameters defined.
+var _ io.ReaderFrom = &genReader[string, int]{} //@suggestedfix("&genReader", "refactor.rewrite", "Implement io.ReaderFrom")
+
+type genReader[T, Y any] struct {
+ T T
+ Y Y
+}
diff --git a/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden
new file mode 100644
index 000000000..97935d47e
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden
@@ -0,0 +1,22 @@
+-- suggestedfix_stub_generic_receiver_10_23 --
+//go:build go1.18
+// +build go1.18
+
+package stub
+
+import "io"
+
+// This file tests that that the stub method generator accounts for concrete
+// types that have type parameters defined.
+var _ io.ReaderFrom = &genReader[string, int]{} //@suggestedfix("&genReader", "refactor.rewrite", "Implement io.ReaderFrom")
+
+type genReader[T, Y any] struct {
+ T T
+ Y Y
+}
+
+// ReadFrom implements io.ReaderFrom
+func (*genReader[T, Y]) ReadFrom(r io.Reader) (n int64, err error) {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go
new file mode 100644
index 000000000..ca95d2a71
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go
@@ -0,0 +1,18 @@
+package stub
+
+import (
+ "compress/zlib"
+ . "io"
+ _ "io"
+)
+
+// This file tests that dot-imports and underscore imports
+// are properly ignored and that a new import is added to
+// reference method types
+
+var (
+ _ Reader
+ _ zlib.Resetter = (*ignoredResetter)(nil) //@suggestedfix("(", "refactor.rewrite", "")
+)
+
+type ignoredResetter struct{}
diff --git a/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden
new file mode 100644
index 000000000..d4ab9d86a
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden
@@ -0,0 +1,25 @@
+-- suggestedfix_stub_ignored_imports_15_20 --
+package stub
+
+import (
+ "compress/zlib"
+ . "io"
+ _ "io"
+)
+
+// This file tests that dot-imports and underscore imports
+// are properly ignored and that a new import is added to
+// reference method types
+
+var (
+ _ Reader
+ _ zlib.Resetter = (*ignoredResetter)(nil) //@suggestedfix("(", "refactor.rewrite", "")
+)
+
+type ignoredResetter struct{}
+
+// Reset implements zlib.Resetter
+func (*ignoredResetter) Reset(r Reader, dict []byte) error {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_issue2606.go b/gopls/internal/lsp/testdata/stub/stub_issue2606.go
new file mode 100644
index 000000000..66ef2b24b
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_issue2606.go
@@ -0,0 +1,7 @@
+package stub
+
+type I interface{ error }
+
+type C int
+
+var _ I = C(0) //@suggestedfix("C", "refactor.rewrite", "")
diff --git a/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden b/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden
new file mode 100644
index 000000000..4db266346
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden
@@ -0,0 +1,14 @@
+-- suggestedfix_stub_issue2606_7_11 --
+package stub
+
+type I interface{ error }
+
+type C int
+
+// Error implements I
+func (C) Error() string {
+ panic("unimplemented")
+}
+
+var _ I = C(0) //@suggestedfix("C", "refactor.rewrite", "")
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_multi_var.go b/gopls/internal/lsp/testdata/stub/stub_multi_var.go
new file mode 100644
index 000000000..06702b222
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_multi_var.go
@@ -0,0 +1,11 @@
+package stub
+
+import "io"
+
+// This test ensures that a variable declaration that
+// has multiple values on the same line can still be
+// analyzed correctly to target the interface implementation
+// diagnostic.
+var one, two, three io.Reader = nil, &multiVar{}, nil //@suggestedfix("&", "refactor.rewrite", "")
+
+type multiVar struct{}
diff --git a/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden b/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden
new file mode 100644
index 000000000..804c7eec6
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden
@@ -0,0 +1,18 @@
+-- suggestedfix_stub_multi_var_9_38 --
+package stub
+
+import "io"
+
+// This test ensures that a variable declaration that
+// has multiple values on the same line can still be
+// analyzed correctly to target the interface implementation
+// diagnostic.
+var one, two, three io.Reader = nil, &multiVar{}, nil //@suggestedfix("&", "refactor.rewrite", "")
+
+type multiVar struct{}
+
+// Read implements io.Reader
+func (*multiVar) Read(p []byte) (n int, err error) {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_pointer.go b/gopls/internal/lsp/testdata/stub/stub_pointer.go
new file mode 100644
index 000000000..e9d8bc688
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_pointer.go
@@ -0,0 +1,9 @@
+package stub
+
+import "io"
+
+func getReaderFrom() io.ReaderFrom {
+ return &pointerImpl{} //@suggestedfix("&", "refactor.rewrite", "")
+}
+
+type pointerImpl struct{}
diff --git a/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden b/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden
new file mode 100644
index 000000000..a4d765dd4
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden
@@ -0,0 +1,16 @@
+-- suggestedfix_stub_pointer_6_9 --
+package stub
+
+import "io"
+
+func getReaderFrom() io.ReaderFrom {
+ return &pointerImpl{} //@suggestedfix("&", "refactor.rewrite", "")
+}
+
+type pointerImpl struct{}
+
+// ReadFrom implements io.ReaderFrom
+func (*pointerImpl) ReadFrom(r io.Reader) (n int64, err error) {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_renamed_import.go b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go
new file mode 100644
index 000000000..54dd59801
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go
@@ -0,0 +1,11 @@
+package stub
+
+import (
+ "compress/zlib"
+ myio "io"
+)
+
+var _ zlib.Resetter = &myIO{} //@suggestedfix("&", "refactor.rewrite", "")
+var _ myio.Reader
+
+type myIO struct{}
diff --git a/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden
new file mode 100644
index 000000000..8182d2b36
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden
@@ -0,0 +1,18 @@
+-- suggestedfix_stub_renamed_import_8_23 --
+package stub
+
+import (
+ "compress/zlib"
+ myio "io"
+)
+
+var _ zlib.Resetter = &myIO{} //@suggestedfix("&", "refactor.rewrite", "")
+var _ myio.Reader
+
+type myIO struct{}
+
+// Reset implements zlib.Resetter
+func (*myIO) Reset(r myio.Reader, dict []byte) error {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go
new file mode 100644
index 000000000..0f1758685
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go
@@ -0,0 +1,13 @@
+package stub
+
+import (
+ "golang.org/lsptests/stub/other"
+)
+
+// This file tests that if an interface
+// method references an import from its own package
+// that the concrete type does not yet import, and that import happens
+// to be renamed, then we prefer the renaming of the interface.
+var _ other.Interface = &otherInterfaceImpl{} //@suggestedfix("&otherInterfaceImpl", "refactor.rewrite", "")
+
+type otherInterfaceImpl struct{}
diff --git a/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden
new file mode 100644
index 000000000..d9c621584
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden
@@ -0,0 +1,22 @@
+-- suggestedfix_stub_renamed_import_iface_11_25 --
+package stub
+
+import (
+ "bytes"
+ "context"
+ "golang.org/lsptests/stub/other"
+)
+
+// This file tests that if an interface
+// method references an import from its own package
+// that the concrete type does not yet import, and that import happens
+// to be renamed, then we prefer the renaming of the interface.
+var _ other.Interface = &otherInterfaceImpl{} //@suggestedfix("&otherInterfaceImpl", "refactor.rewrite", "")
+
+type otherInterfaceImpl struct{}
+
+// Get implements other.Interface
+func (*otherInterfaceImpl) Get(context.Context) *bytes.Buffer {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_stdlib.go b/gopls/internal/lsp/testdata/stub/stub_stdlib.go
new file mode 100644
index 000000000..463cf78a3
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_stdlib.go
@@ -0,0 +1,9 @@
+package stub
+
+import (
+ "io"
+)
+
+var _ io.Writer = writer{} //@suggestedfix("w", "refactor.rewrite", "")
+
+type writer struct{}
diff --git a/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden b/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden
new file mode 100644
index 000000000..55592501a
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden
@@ -0,0 +1,16 @@
+-- suggestedfix_stub_stdlib_7_19 --
+package stub
+
+import (
+ "io"
+)
+
+var _ io.Writer = writer{} //@suggestedfix("w", "refactor.rewrite", "")
+
+type writer struct{}
+
+// Write implements io.Writer
+func (writer) Write(p []byte) (n int, err error) {
+ panic("unimplemented")
+}
+
diff --git a/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go
new file mode 100644
index 000000000..f82401faf
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go
@@ -0,0 +1,27 @@
+package stub
+
+// Regression test for Issue #56825: file corrupted by insertion of
+// methods after TypeSpec in a parenthesized TypeDecl.
+
+import "io"
+
+func newReadCloser() io.ReadCloser {
+ return rdcloser{} //@suggestedfix("rd", "refactor.rewrite", "")
+}
+
+type (
+ A int
+ rdcloser struct{}
+ B int
+)
+
+func _() {
+ // Local types can't be stubbed as there's nowhere to put the methods.
+ // The suggestedfix assertion can't express this yet. TODO(adonovan): support it.
+ type local struct{}
+ var _ io.ReadCloser = local{} // want error: `local type "local" cannot be stubbed`
+}
+
+type (
+ C int
+)
diff --git a/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden
new file mode 100644
index 000000000..0848789ea
--- /dev/null
+++ b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden
@@ -0,0 +1,39 @@
+-- suggestedfix_stub_typedecl_group_9_9 --
+package stub
+
+// Regression test for Issue #56825: file corrupted by insertion of
+// methods after TypeSpec in a parenthesized TypeDecl.
+
+import "io"
+
+func newReadCloser() io.ReadCloser {
+ return rdcloser{} //@suggestedfix("rd", "refactor.rewrite", "")
+}
+
+type (
+ A int
+ rdcloser struct{}
+ B int
+)
+
+// Close implements io.ReadCloser
+func (rdcloser) Close() error {
+ panic("unimplemented")
+}
+
+// Read implements io.ReadCloser
+func (rdcloser) Read(p []byte) (n int, err error) {
+ panic("unimplemented")
+}
+
+func _() {
+ // Local types can't be stubbed as there's nowhere to put the methods.
+ // The suggestedfix assertion can't express this yet. TODO(adonovan): support it.
+ type local struct{}
+ var _ io.ReadCloser = local{} // want error: `local type "local" cannot be stubbed`
+}
+
+type (
+ C int
+)
+
diff --git a/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go
new file mode 100644
index 000000000..7ff524479
--- /dev/null
+++ b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go
@@ -0,0 +1,11 @@
+package suggestedfix
+
+import (
+ "log"
+)
+
+func goodbye() {
+ s := "hiiiiiii"
+ s = s //@suggestedfix("s = s", "quickfix", "")
+ log.Print(s)
+}
diff --git a/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden
new file mode 100644
index 000000000..e7e84fc22
--- /dev/null
+++ b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden
@@ -0,0 +1,13 @@
+-- suggestedfix_has_suggested_fix_9_2 --
+package suggestedfix
+
+import (
+ "log"
+)
+
+func goodbye() {
+ s := "hiiiiiii"
+ //@suggestedfix("s = s", "quickfix", "")
+ log.Print(s)
+}
+
diff --git a/gopls/internal/lsp/testdata/summary.txt.golden b/gopls/internal/lsp/testdata/summary.txt.golden
new file mode 100644
index 000000000..985361ba7
--- /dev/null
+++ b/gopls/internal/lsp/testdata/summary.txt.golden
@@ -0,0 +1,32 @@
+-- summary --
+CallHierarchyCount = 2
+CodeLensCount = 5
+CompletionsCount = 263
+CompletionSnippetCount = 106
+UnimportedCompletionsCount = 5
+DeepCompletionsCount = 5
+FuzzyCompletionsCount = 8
+RankedCompletionsCount = 164
+CaseSensitiveCompletionsCount = 4
+DiagnosticsCount = 42
+FoldingRangesCount = 2
+FormatCount = 6
+ImportCount = 8
+SemanticTokenCount = 3
+SuggestedFixCount = 65
+FunctionExtractionCount = 27
+MethodExtractionCount = 6
+DefinitionsCount = 47
+TypeDefinitionsCount = 18
+HighlightsCount = 69
+InlayHintsCount = 4
+ReferencesCount = 30
+RenamesCount = 41
+PrepareRenamesCount = 7
+SymbolsCount = 1
+WorkspaceSymbolsCount = 20
+SignaturesCount = 33
+LinksCount = 7
+ImplementationsCount = 16
+SelectionRangesCount = 3
+
diff --git a/gopls/internal/lsp/testdata/summary_go1.18.txt.golden b/gopls/internal/lsp/testdata/summary_go1.18.txt.golden
new file mode 100644
index 000000000..9ae4d1364
--- /dev/null
+++ b/gopls/internal/lsp/testdata/summary_go1.18.txt.golden
@@ -0,0 +1,32 @@
+-- summary --
+CallHierarchyCount = 2
+CodeLensCount = 5
+CompletionsCount = 264
+CompletionSnippetCount = 115
+UnimportedCompletionsCount = 5
+DeepCompletionsCount = 5
+FuzzyCompletionsCount = 8
+RankedCompletionsCount = 174
+CaseSensitiveCompletionsCount = 4
+DiagnosticsCount = 42
+FoldingRangesCount = 2
+FormatCount = 6
+ImportCount = 8
+SemanticTokenCount = 3
+SuggestedFixCount = 71
+FunctionExtractionCount = 27
+MethodExtractionCount = 6
+DefinitionsCount = 47
+TypeDefinitionsCount = 18
+HighlightsCount = 69
+InlayHintsCount = 5
+ReferencesCount = 30
+RenamesCount = 48
+PrepareRenamesCount = 7
+SymbolsCount = 2
+WorkspaceSymbolsCount = 20
+SignaturesCount = 33
+LinksCount = 7
+ImplementationsCount = 26
+SelectionRangesCount = 3
+
diff --git a/gopls/internal/lsp/testdata/symbols/go1.18.go b/gopls/internal/lsp/testdata/symbols/go1.18.go
new file mode 100644
index 000000000..cdf99dc20
--- /dev/null
+++ b/gopls/internal/lsp/testdata/symbols/go1.18.go
@@ -0,0 +1,16 @@
+//go:build go1.18
+// +build go1.18
+
+package main
+
+type T[P any] struct { //@symbol("T", "T", "Struct", "struct{...}", "T", "")
+ F P //@symbol("F", "F", "Field", "P", "", "T")
+}
+
+type Constraint interface { //@symbol("Constraint", "Constraint", "Interface", "interface{...}", "Constraint", "")
+ ~int | struct{ int } //@symbol("~int | struct{int}", "~int | struct{ int }", "Field", "", "", "Constraint")
+
+ // TODO(rfindley): the selection range below is the entire interface field.
+ // Can we reduce it?
+ interface{ M() } //@symbol("interface{...}", "interface{ M() }", "Field", "", "iFaceField", "Constraint"), symbol("M", "M", "Method", "func()", "", "iFaceField")
+}
diff --git a/gopls/internal/lsp/testdata/symbols/go1.18.go.golden b/gopls/internal/lsp/testdata/symbols/go1.18.go.golden
new file mode 100644
index 000000000..5a0c1a94d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/symbols/go1.18.go.golden
@@ -0,0 +1,7 @@
+-- symbols --
+T Struct 6:6-6:7
+ F Field 7:2-7:3
+Constraint Interface 10:6-10:16
+ interface{...} Field 15:2-15:18
+ ~int | struct{int} Field 11:2-11:22
+
diff --git a/gopls/internal/lsp/testdata/symbols/main.go b/gopls/internal/lsp/testdata/symbols/main.go
new file mode 100644
index 000000000..65e0869fd
--- /dev/null
+++ b/gopls/internal/lsp/testdata/symbols/main.go
@@ -0,0 +1,91 @@
+package main
+
+import (
+ "io"
+)
+
+// Each symbol marker in this file defines the following information:
+// symbol(name, selectionSpan, kind, detail, id, parentID)
+// - name: DocumentSymbol.Name
+// - selectionSpan: DocumentSymbol.SelectionRange
+// - kind: DocumentSymbol.Kind
+// - detail: DocumentSymbol.Detail
+// - id: if non-empty, a unique identifier for this symbol
+// - parentID: if non-empty, the id of the parent of this symbol
+//
+// This data in aggregate defines a set of document symbols and their
+// parent-child relationships, which is compared against the DocummentSymbols
+// response from gopls for the current file.
+//
+// TODO(rfindley): the symbol annotations here are complicated and difficult to
+// maintain. It would be simpler to just write out the full expected response
+// in the golden file, perhaps as raw JSON.
+
+var _ = 1
+
+var x = 42 //@symbol("x", "x", "Variable", "", "", "")
+
+var nested struct { //@symbol("nested", "nested", "Variable", "struct{...}", "nested", "")
+ nestedField struct { //@symbol("nestedField", "nestedField", "Field", "struct{...}", "nestedField", "nested")
+ f int //@symbol("f", "f", "Field", "int", "", "nestedField")
+ }
+}
+
+const y = 43 //@symbol("y", "y", "Constant", "", "", "")
+
+type Number int //@symbol("Number", "Number", "Class", "int", "", "")
+
+type Alias = string //@symbol("Alias", "Alias", "Class", "string", "", "")
+
+type NumberAlias = Number //@symbol("NumberAlias", "NumberAlias", "Class", "Number", "", "")
+
+type (
+ Boolean bool //@symbol("Boolean", "Boolean", "Class", "bool", "", "")
+ BoolAlias = bool //@symbol("BoolAlias", "BoolAlias", "Class", "bool", "", "")
+)
+
+type Foo struct { //@symbol("Foo", "Foo", "Struct", "struct{...}", "Foo", "")
+ Quux //@symbol("Quux", "Quux", "Field", "Quux", "", "Foo")
+ W io.Writer //@symbol("W", "W", "Field", "io.Writer", "", "Foo")
+ Bar int //@symbol("Bar", "Bar", "Field", "int", "", "Foo")
+ baz string //@symbol("baz", "baz", "Field", "string", "", "Foo")
+ funcField func(int) int //@symbol("funcField", "funcField", "Field", "func(int) int", "", "Foo")
+}
+
+type Quux struct { //@symbol("Quux", "Quux", "Struct", "struct{...}", "Quux", "")
+ X, Y float64 //@symbol("X", "X", "Field", "float64", "", "Quux"), symbol("Y", "Y", "Field", "float64", "", "Quux")
+}
+
+type EmptyStruct struct{} //@symbol("EmptyStruct", "EmptyStruct", "Struct", "struct{}", "", "")
+
+func (f Foo) Baz() string { //@symbol("(Foo).Baz", "Baz", "Method", "func() string", "", "")
+ return f.baz
+}
+
+func _() {}
+
+func (q *Quux) Do() {} //@symbol("(*Quux).Do", "Do", "Method", "func()", "", "")
+
+func main() { //@symbol("main", "main", "Function", "func()", "", "")
+}
+
+type Stringer interface { //@symbol("Stringer", "Stringer", "Interface", "interface{...}", "Stringer", "")
+ String() string //@symbol("String", "String", "Method", "func() string", "", "Stringer")
+}
+
+type ABer interface { //@symbol("ABer", "ABer", "Interface", "interface{...}", "ABer", "")
+ B() //@symbol("B", "B", "Method", "func()", "", "ABer")
+ A() string //@symbol("A", "A", "Method", "func() string", "", "ABer")
+}
+
+type WithEmbeddeds interface { //@symbol("WithEmbeddeds", "WithEmbeddeds", "Interface", "interface{...}", "WithEmbeddeds", "")
+ Do() //@symbol("Do", "Do", "Method", "func()", "", "WithEmbeddeds")
+ ABer //@symbol("ABer", "ABer", "Field", "ABer", "", "WithEmbeddeds")
+ io.Writer //@symbol("Writer", "Writer", "Field", "io.Writer", "", "WithEmbeddeds")
+}
+
+type EmptyInterface interface{} //@symbol("EmptyInterface", "EmptyInterface", "Interface", "interface{}", "", "")
+
+func Dunk() int { return 0 } //@symbol("Dunk", "Dunk", "Function", "func() int", "", "")
+
+func dunk() {} //@symbol("dunk", "dunk", "Function", "func()", "", "")
diff --git a/gopls/internal/lsp/testdata/symbols/main.go.golden b/gopls/internal/lsp/testdata/symbols/main.go.golden
new file mode 100644
index 000000000..98009b02d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/symbols/main.go.golden
@@ -0,0 +1,36 @@
+-- symbols --
+x Variable 26:5-26:6
+nested Variable 28:5-28:11
+ nestedField Field 29:2-29:13
+y Constant 34:7-34:8
+Number Class 36:6-36:12
+Alias Class 38:6-38:11
+NumberAlias Class 40:6-40:17
+Boolean Class 43:2-43:9
+BoolAlias Class 44:2-44:11
+Foo Struct 47:6-47:9
+ Bar Field 50:2-50:5
+ Quux Field 48:2-48:6
+ W Field 49:2-49:3
+ baz Field 51:2-51:5
+ funcField Field 52:2-52:11
+Quux Struct 55:6-55:10
+ X Field 56:2-56:3
+ Y Field 56:5-56:6
+EmptyStruct Struct 59:6-59:17
+(Foo).Baz Method 61:14-61:17
+(*Quux).Do Method 67:16-67:18
+main Function 69:6-69:10
+Stringer Interface 72:6-72:14
+ String Method 73:2-73:8
+ABer Interface 76:6-76:10
+ A Method 78:2-78:3
+ B Method 77:2-77:3
+WithEmbeddeds Interface 81:6-81:19
+ ABer Field 83:2-83:6
+ Do Method 82:2-82:4
+ Writer Field 84:5-84:11
+EmptyInterface Interface 87:6-87:20
+Dunk Function 89:6-89:10
+dunk Function 91:6-91:10
+
diff --git a/gopls/internal/lsp/testdata/testy/testy.go b/gopls/internal/lsp/testdata/testy/testy.go
new file mode 100644
index 000000000..1a738d7d7
--- /dev/null
+++ b/gopls/internal/lsp/testdata/testy/testy.go
@@ -0,0 +1,5 @@
+package testy
+
+func a() { //@mark(identA, "a"),item(funcA, "a", "func()", "func"),refs("a", identA, testyA)
+ //@complete("", funcA)
+}
diff --git a/gopls/internal/lsp/testdata/testy/testy_test.go b/gopls/internal/lsp/testdata/testy/testy_test.go
new file mode 100644
index 000000000..a7e897840
--- /dev/null
+++ b/gopls/internal/lsp/testdata/testy/testy_test.go
@@ -0,0 +1,18 @@
+package testy
+
+import (
+ "testing"
+
+ sig "golang.org/lsptests/signature"
+ "golang.org/lsptests/snippets"
+)
+
+func TestSomething(t *testing.T) { //@item(TestSomething, "TestSomething(t *testing.T)", "", "func")
+ var x int //@mark(testyX, "x"),diag("x", "compiler", "x declared (and|but) not used", "error"),refs("x", testyX)
+ a() //@mark(testyA, "a")
+}
+
+func _() {
+ _ = snippets.X(nil) //@signature("nil", "X(_ map[sig.Alias]types.CoolAlias) map[sig.Alias]types.CoolAlias", 0)
+ var _ sig.Alias
+}
diff --git a/gopls/internal/lsp/testdata/testy/testy_test.go.golden b/gopls/internal/lsp/testdata/testy/testy_test.go.golden
new file mode 100644
index 000000000..cafc380d0
--- /dev/null
+++ b/gopls/internal/lsp/testdata/testy/testy_test.go.golden
@@ -0,0 +1,3 @@
+-- X(_ map[sig.Alias]types.CoolAlias) map[sig.Alias]types.CoolAlias-signature --
+X(_ map[sig.Alias]types.CoolAlias) map[sig.Alias]types.CoolAlias
+
diff --git a/gopls/internal/lsp/testdata/typdef/typdef.go b/gopls/internal/lsp/testdata/typdef/typdef.go
new file mode 100644
index 000000000..bd2ea4b00
--- /dev/null
+++ b/gopls/internal/lsp/testdata/typdef/typdef.go
@@ -0,0 +1,65 @@
+package typdef
+
+type Struct struct { //@item(Struct, "Struct", "struct{...}", "struct")
+ Field string
+}
+
+type Int int //@item(Int, "Int", "int", "type")
+
+func _() {
+ var (
+ value Struct
+ point *Struct
+ )
+ _ = value //@typdef("value", Struct)
+ _ = point //@typdef("point", Struct)
+
+ var (
+ array [3]Struct
+ slice []Struct
+ ch chan Struct
+ complex [3]chan *[5][]Int
+ )
+ _ = array //@typdef("array", Struct)
+ _ = slice //@typdef("slice", Struct)
+ _ = ch //@typdef("ch", Struct)
+ _ = complex //@typdef("complex", Int)
+
+ var s struct {
+ x struct {
+ xx struct {
+ field1 []Struct
+ field2 []Int
+ }
+ }
+ }
+ s.x.xx.field1 //@typdef("field1", Struct)
+ s.x.xx.field2 //@typdef("field2", Int)
+}
+
+func F1() Int { return 0 }
+func F2() (Int, float64) { return 0, 0 }
+func F3() (Struct, int, bool, error) { return Struct{}, 0, false, nil }
+func F4() (**int, Int, bool, *error) { return nil, Struct{}, false, nil }
+func F5() (int, float64, error, Struct) { return 0, 0, nil, Struct{} }
+func F6() (int, float64, ***Struct, error) { return 0, 0, nil, nil }
+
+func _() {
+ F1() //@typdef("F1", Int)
+ F2() //@typdef("F2", Int)
+ F3() //@typdef("F3", Struct)
+ F4() //@typdef("F4", Int)
+ F5() //@typdef("F5", Struct)
+ F6() //@typdef("F6", Struct)
+
+ f := func() Int { return 0 }
+ f() //@typdef("f", Int)
+}
+
+// https://github.com/golang/go/issues/38589#issuecomment-620350922
+func _() {
+ type myFunc func(int) Int //@item(myFunc, "myFunc", "func", "type")
+
+ var foo myFunc
+ bar := foo() //@typdef("foo", myFunc)
+}
diff --git a/gopls/internal/lsp/testdata/typeassert/type_assert.go b/gopls/internal/lsp/testdata/typeassert/type_assert.go
new file mode 100644
index 000000000..e24b68a07
--- /dev/null
+++ b/gopls/internal/lsp/testdata/typeassert/type_assert.go
@@ -0,0 +1,24 @@
+package typeassert
+
+type abc interface { //@item(abcIntf, "abc", "interface{...}", "interface")
+ abc()
+}
+
+type abcImpl struct{} //@item(abcImpl, "abcImpl", "struct{...}", "struct")
+func (abcImpl) abc()
+
+type abcPtrImpl struct{} //@item(abcPtrImpl, "abcPtrImpl", "struct{...}", "struct")
+func (*abcPtrImpl) abc()
+
+type abcNotImpl struct{} //@item(abcNotImpl, "abcNotImpl", "struct{...}", "struct")
+
+func _() {
+ var a abc
+ switch a.(type) {
+ case ab: //@complete(":", abcImpl, abcPtrImpl, abcIntf, abcNotImpl)
+ case *ab: //@complete(":", abcImpl, abcPtrImpl, abcIntf, abcNotImpl)
+ }
+
+ a.(ab) //@complete(")", abcImpl, abcPtrImpl, abcIntf, abcNotImpl)
+ a.(*ab) //@complete(")", abcImpl, abcPtrImpl, abcIntf, abcNotImpl)
+}
diff --git a/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go
new file mode 100644
index 000000000..729e7bbcc
--- /dev/null
+++ b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go
@@ -0,0 +1,5 @@
+package typeerrors
+
+func x() { return nil } //@suggestedfix("nil", "quickfix", "")
+
+func y() { return nil, "hello" } //@suggestedfix("nil", "quickfix", "")
diff --git a/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden
new file mode 100644
index 000000000..48409a0b7
--- /dev/null
+++ b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden
@@ -0,0 +1,14 @@
+-- suggestedfix_noresultvalues_3_19 --
+package typeerrors
+
+func x() { return } //@suggestedfix("nil", "quickfix", "")
+
+func y() { return nil, "hello" } //@suggestedfix("nil", "quickfix", "")
+
+-- suggestedfix_noresultvalues_5_19 --
+package typeerrors
+
+func x() { return nil } //@suggestedfix("nil", "quickfix", "")
+
+func y() { return } //@suggestedfix("nil", "quickfix", "")
+
diff --git a/gopls/internal/lsp/testdata/typemods/type_mods.go b/gopls/internal/lsp/testdata/typemods/type_mods.go
new file mode 100644
index 000000000..f5f0f8076
--- /dev/null
+++ b/gopls/internal/lsp/testdata/typemods/type_mods.go
@@ -0,0 +1,21 @@
+package typemods
+
+func fooFunc() func() int { //@item(modFooFunc, "fooFunc", "func() func() int", "func")
+ return func() int {
+ return 0
+ }
+}
+
+func fooPtr() *int { //@item(modFooPtr, "fooPtr", "func() *int", "func")
+ return nil
+}
+
+func _() {
+ var _ int = foo //@snippet(" //", modFooFunc, "fooFunc()()", "fooFunc()()"),snippet(" //", modFooPtr, "*fooPtr()", "*fooPtr()")
+}
+
+func _() {
+ var m map[int][]chan int //@item(modMapChanPtr, "m", "map[int]chan *int", "var")
+
+ var _ int = m //@snippet(" //", modMapChanPtr, "<-m[${1:}][${2:}]", "<-m[${1:}][${2:}]")
+}
diff --git a/gopls/internal/lsp/testdata/typeparams/type_params.go b/gopls/internal/lsp/testdata/typeparams/type_params.go
new file mode 100644
index 000000000..21fc7049f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/typeparams/type_params.go
@@ -0,0 +1,61 @@
+//go:build go1.18
+// +build go1.18
+
+package typeparams
+
+func one[a int | string]() {}
+func two[a int | string, b float64 | int]() {}
+
+func _() {
+ one[]() //@rank("]", string, float64)
+ two[]() //@rank("]", int, float64)
+ two[int, f]() //@rank("]", float64, float32)
+}
+
+func slices[a []int | []float64]() {} //@item(tpInts, "[]int", "[]int", "type"),item(tpFloats, "[]float64", "[]float64", "type")
+
+func _() {
+ slices[]() //@rank("]", tpInts),rank("]", tpFloats)
+}
+
+type s[a int | string] struct{}
+
+func _() {
+ s[]{} //@rank("]", int, float64)
+}
+
+func takesGeneric[a int | string](s[a]) {
+ "s[a]{}" //@item(tpInScopeLit, "s[a]{}", "", "var")
+ takesGeneric() //@rank(")", tpInScopeLit),snippet(")", tpInScopeLit, "s[a]{\\}", "s[a]{\\}")
+}
+
+func _() {
+ s[int]{} //@item(tpInstLit, "s[int]{}", "", "var")
+ takesGeneric[int]() //@rank(")", tpInstLit),snippet(")", tpInstLit, "s[int]{\\}", "s[int]{\\}")
+
+ "s[...]{}" //@item(tpUninstLit, "s[...]{}", "", "var")
+ takesGeneric() //@rank(")", tpUninstLit),snippet(")", tpUninstLit, "s[${1:}]{\\}", "s[${1:a}]{\\}")
+}
+
+func returnTP[A int | float64](a A) A { //@item(returnTP, "returnTP", "something", "func")
+ return a
+}
+
+func _() {
+ // disabled - see issue #54822
+ var _ int = returnTP // snippet(" //", returnTP, "returnTP[${1:}](${2:})", "returnTP[${1:A int|float64}](${2:a A})")
+
+ var aa int //@item(tpInt, "aa", "int", "var")
+ var ab float64 //@item(tpFloat, "ab", "float64", "var")
+ returnTP[int](a) //@rank(")", tpInt, tpFloat)
+}
+
+func takesFunc[T any](func(T) T) {
+ var _ func(t T) T = f //@snippet(" //", tpLitFunc, "func(t T) T {$0\\}", "func(t T) T {$0\\}")
+}
+
+func _() {
+ _ = "func(...) {}" //@item(tpLitFunc, "func(...) {}", "", "var")
+ takesFunc() //@snippet(")", tpLitFunc, "func(${1:}) ${2:} {$0\\}", "func(${1:t} ${2:T}) ${3:T} {$0\\}")
+ takesFunc[int]() //@snippet(")", tpLitFunc, "func(i int) int {$0\\}", "func(${1:i} int) int {$0\\}")
+}
diff --git a/gopls/internal/lsp/testdata/types/types.go b/gopls/internal/lsp/testdata/types/types.go
new file mode 100644
index 000000000..c60d4b2e4
--- /dev/null
+++ b/gopls/internal/lsp/testdata/types/types.go
@@ -0,0 +1,18 @@
+package types
+
+type CoolAlias = int //@item(CoolAlias, "CoolAlias", "int", "type")
+
+type X struct { //@item(X_struct, "X", "struct{...}", "struct")
+ x int
+}
+
+type Y struct { //@item(Y_struct, "Y", "struct{...}", "struct")
+ y int
+}
+
+type Bob interface { //@item(Bob_interface, "Bob", "interface{...}", "interface")
+ Bobby()
+}
+
+func (*X) Bobby() {}
+func (*Y) Bobby() {}
diff --git a/gopls/internal/lsp/testdata/undeclared/var.go b/gopls/internal/lsp/testdata/undeclared/var.go
new file mode 100644
index 000000000..3fda582ce
--- /dev/null
+++ b/gopls/internal/lsp/testdata/undeclared/var.go
@@ -0,0 +1,14 @@
+package undeclared
+
+func m() int {
+ z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "")
+ if 100 < 90 {
+ z = 1
+ } else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "")
+ z = 4
+ }
+ for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "")
+ }
+ r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error")
+ return z
+}
diff --git a/gopls/internal/lsp/testdata/undeclared/var.go.golden b/gopls/internal/lsp/testdata/undeclared/var.go.golden
new file mode 100644
index 000000000..de5cbb42f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/undeclared/var.go.golden
@@ -0,0 +1,51 @@
+-- suggestedfix_var_10_6 --
+package undeclared
+
+func m() int {
+ z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "")
+ if 100 < 90 {
+ z = 1
+ } else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "")
+ z = 4
+ }
+ i :=
+ for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "")
+ }
+ r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error")
+ return z
+}
+
+-- suggestedfix_var_4_12 --
+package undeclared
+
+func m() int {
+ y :=
+ z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "")
+ if 100 < 90 {
+ z = 1
+ } else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "")
+ z = 4
+ }
+ for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "")
+ }
+ r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error")
+ return z
+}
+
+-- suggestedfix_var_7_18 --
+package undeclared
+
+func m() int {
+ z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "")
+ n :=
+ if 100 < 90 {
+ z = 1
+ } else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "")
+ z = 4
+ }
+ for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "")
+ }
+ r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error")
+ return z
+}
+
diff --git a/gopls/internal/lsp/testdata/unimported/export_test.go b/gopls/internal/lsp/testdata/unimported/export_test.go
new file mode 100644
index 000000000..707768e1d
--- /dev/null
+++ b/gopls/internal/lsp/testdata/unimported/export_test.go
@@ -0,0 +1,3 @@
+package unimported
+
+var TestExport int //@item(testexport, "TestExport", "var (from \"golang.org/lsptests/unimported\")", "var")
diff --git a/gopls/internal/lsp/testdata/unimported/unimported.go.in b/gopls/internal/lsp/testdata/unimported/unimported.go.in
new file mode 100644
index 000000000..74d51ffe8
--- /dev/null
+++ b/gopls/internal/lsp/testdata/unimported/unimported.go.in
@@ -0,0 +1,23 @@
+package unimported
+
+func _() {
+ http //@unimported("p", nethttp)
+ // container/ring is extremely unlikely to be imported by anything, so shouldn't have type information.
+ ring.Ring //@unimported("Ring", ringring)
+ signature.Foo //@unimported("Foo", signaturefoo)
+
+ context.Bac //@unimported(" //", contextBackground)
+}
+
+// Create markers for unimported std lib packages. Only for use by this test.
+/* http */ //@item(nethttp, "http", "\"net/http\"", "package")
+
+/* ring.Ring */ //@item(ringring, "Ring", "(from \"container/ring\")", "var")
+
+/* signature.Foo */ //@item(signaturefoo, "Foo", "func (from \"golang.org/lsptests/signature\")", "func")
+
+/* context.Background */ //@item(contextBackground, "Background", "func (from \"context\")", "func")
+
+// Now that we no longer type-check imported completions,
+// we don't expect the context.Background().Err method (see golang/go#58663).
+/* context.Background().Err */ //@item(contextBackgroundErr, "Background().Err", "func (from \"context\")", "method")
diff --git a/gopls/internal/lsp/testdata/unimported/unimported_cand_type.go b/gopls/internal/lsp/testdata/unimported/unimported_cand_type.go
new file mode 100644
index 000000000..554c426a9
--- /dev/null
+++ b/gopls/internal/lsp/testdata/unimported/unimported_cand_type.go
@@ -0,0 +1,16 @@
+package unimported
+
+import (
+ _ "context"
+
+ "golang.org/lsptests/baz"
+ _ "golang.org/lsptests/signature" // provide type information for unimported completions in the other file
+)
+
+func _() {
+ foo.StructFoo{} //@item(litFooStructFoo, "foo.StructFoo{}", "struct{...}", "struct")
+
+ // We get the literal completion for "foo.StructFoo{}" even though we haven't
+ // imported "foo" yet.
+ baz.FooStruct = f //@snippet(" //", litFooStructFoo, "foo.StructFoo{$0\\}", "foo.StructFoo{$0\\}")
+}
diff --git a/gopls/internal/lsp/testdata/unimported/x_test.go b/gopls/internal/lsp/testdata/unimported/x_test.go
new file mode 100644
index 000000000..681dcb253
--- /dev/null
+++ b/gopls/internal/lsp/testdata/unimported/x_test.go
@@ -0,0 +1,9 @@
+package unimported_test
+
+import (
+ "testing"
+)
+
+func TestSomething(t *testing.T) {
+ _ = unimported.TestExport //@unimported("TestExport", testexport)
+}
diff --git a/gopls/internal/lsp/testdata/unresolved/unresolved.go.in b/gopls/internal/lsp/testdata/unresolved/unresolved.go.in
new file mode 100644
index 000000000..e1daecc2e
--- /dev/null
+++ b/gopls/internal/lsp/testdata/unresolved/unresolved.go.in
@@ -0,0 +1,6 @@
+package unresolved
+
+func foo(interface{}) {
+ // don't crash on fake "resolved" type
+ foo(func(i, j f //@complete(" //")
+}
diff --git a/gopls/internal/lsp/testdata/unsafe/unsafe.go b/gopls/internal/lsp/testdata/unsafe/unsafe.go
new file mode 100644
index 000000000..5d5e43407
--- /dev/null
+++ b/gopls/internal/lsp/testdata/unsafe/unsafe.go
@@ -0,0 +1,13 @@
+package unsafe
+
+import (
+ "unsafe"
+)
+
+// Pre-set this marker, as we don't have a "source" for it in this package.
+/* unsafe.Sizeof */ //@item(Sizeof, "Sizeof", "invalid type", "text")
+
+func _() {
+ x := struct{}{}
+ _ = unsafe.Sizeof(x) //@complete("z", Sizeof)
+}
diff --git a/gopls/internal/lsp/testdata/variadic/variadic.go.in b/gopls/internal/lsp/testdata/variadic/variadic.go.in
new file mode 100644
index 000000000..4787498ce
--- /dev/null
+++ b/gopls/internal/lsp/testdata/variadic/variadic.go.in
@@ -0,0 +1,38 @@
+package variadic
+
+func foo(i int, strs ...string) {}
+
+func bar() []string { //@item(vFunc, "bar", "func() []string", "func")
+ return nil
+}
+
+func _() {
+ var (
+ i int //@item(vInt, "i", "int", "var")
+ s string //@item(vStr, "s", "string", "var")
+ ss []string //@item(vStrSlice, "ss", "[]string", "var")
+ v interface{} //@item(vIntf, "v", "interface{}", "var")
+ )
+
+ foo() //@rank(")", vInt, vStr),rank(")", vInt, vStrSlice)
+ foo(123, ) //@rank(")", vStr, vInt),rank(")", vStrSlice, vInt)
+ foo(123, "", ) //@rank(")", vStr, vInt),rank(")", vStr, vStrSlice)
+ foo(123, s, "") //@rank(", \"", vStr, vStrSlice)
+
+ // snippet will add the "..." for you
+ foo(123, ) //@snippet(")", vStrSlice, "ss...", "ss..."),snippet(")", vFunc, "bar()...", "bar()..."),snippet(")", vStr, "s", "s")
+
+ // don't add "..." for interface{}
+ foo(123, ) //@snippet(")", vIntf, "v", "v")
+}
+
+func qux(...func()) {}
+func f() {} //@item(vVarArg, "f", "func()", "func")
+
+func _() {
+ qux(f) //@snippet(")", vVarArg, "f", "f")
+}
+
+func _() {
+ foo(0, []string{}...) //@complete(")")
+}
diff --git a/gopls/internal/lsp/testdata/variadic/variadic_intf.go b/gopls/internal/lsp/testdata/variadic/variadic_intf.go
new file mode 100644
index 000000000..6e23fc996
--- /dev/null
+++ b/gopls/internal/lsp/testdata/variadic/variadic_intf.go
@@ -0,0 +1,21 @@
+package variadic
+
+type baz interface {
+ baz()
+}
+
+func wantsBaz(...baz) {}
+
+type bazImpl int
+
+func (bazImpl) baz() {}
+
+func _() {
+ var (
+ impls []bazImpl //@item(vImplSlice, "impls", "[]bazImpl", "var")
+ impl bazImpl //@item(vImpl, "impl", "bazImpl", "var")
+ bazes []baz //@item(vIntfSlice, "bazes", "[]baz", "var")
+ )
+
+ wantsBaz() //@rank(")", vImpl, vImplSlice),rank(")", vIntfSlice, vImplSlice)
+}
diff --git a/gopls/internal/lsp/testdata/workspacesymbol/a/a.go b/gopls/internal/lsp/testdata/workspacesymbol/a/a.go
new file mode 100644
index 000000000..4ae9997a0
--- /dev/null
+++ b/gopls/internal/lsp/testdata/workspacesymbol/a/a.go
@@ -0,0 +1,9 @@
+package a
+
+var RandomGopherVariableA = "a"
+
+const RandomGopherConstantA = "a"
+
+const (
+ randomgopherinvariable = iota
+)
diff --git a/gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go b/gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go
new file mode 100644
index 000000000..0d97c50d6
--- /dev/null
+++ b/gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go
@@ -0,0 +1,3 @@
+package a
+
+var RandomGopherTestVariableA = "a"
diff --git a/gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go b/gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go
new file mode 100644
index 000000000..747cd17ec
--- /dev/null
+++ b/gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go
@@ -0,0 +1,3 @@
+package a_test
+
+var RandomGopherXTestVariableA = "a"
diff --git a/gopls/internal/lsp/testdata/workspacesymbol/b/b.go b/gopls/internal/lsp/testdata/workspacesymbol/b/b.go
new file mode 100644
index 000000000..b2e2092ee
--- /dev/null
+++ b/gopls/internal/lsp/testdata/workspacesymbol/b/b.go
@@ -0,0 +1,7 @@
+package b
+
+var RandomGopherVariableB = "b"
+
+type RandomGopherStructB struct {
+ Bar int
+}
diff --git a/gopls/internal/lsp/testdata/workspacesymbol/issue44806.go b/gopls/internal/lsp/testdata/workspacesymbol/issue44806.go
new file mode 100644
index 000000000..6a6e03a5f
--- /dev/null
+++ b/gopls/internal/lsp/testdata/workspacesymbol/issue44806.go
@@ -0,0 +1,10 @@
+package main
+
+type T struct{}
+
+// We should accept all valid receiver syntax when scanning symbols.
+func (*(T)) m1() {}
+func (*T) m2() {}
+func (T) m3() {}
+func ((T)) m4() {}
+func ((*T)) m5() {}
diff --git a/gopls/internal/lsp/testdata/workspacesymbol/main.go b/gopls/internal/lsp/testdata/workspacesymbol/main.go
new file mode 100644
index 000000000..36ec8f1a5
--- /dev/null
+++ b/gopls/internal/lsp/testdata/workspacesymbol/main.go
@@ -0,0 +1,47 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+)
+
+func main() { // function
+ fmt.Println("Hello")
+}
+
+var myvar int // variable
+
+type myType string // basic type
+
+type myDecoder json.Decoder // to use the encoding/json import
+
+func (m *myType) Blahblah() {} // method
+
+type myStruct struct { // struct type
+ myStructField int // struct field
+}
+
+type myInterface interface { // interface
+ DoSomeCoolStuff() string // interface method
+}
+
+type embed struct {
+ myStruct
+
+ nestedStruct struct {
+ nestedField int
+
+ nestedStruct2 struct {
+ int
+ }
+ }
+
+ nestedInterface interface {
+ myInterface
+ nestedMethod()
+ }
+}
+
+func Dunk() int { return 0 }
+
+func dunk() {}
diff --git a/gopls/internal/lsp/testdata/workspacesymbol/p/p.go b/gopls/internal/lsp/testdata/workspacesymbol/p/p.go
new file mode 100644
index 000000000..409cc3547
--- /dev/null
+++ b/gopls/internal/lsp/testdata/workspacesymbol/p/p.go
@@ -0,0 +1,3 @@
+package p
+
+const Message = "Hello World." // constant
diff --git a/gopls/internal/lsp/testdata/workspacesymbol/query.go b/gopls/internal/lsp/testdata/workspacesymbol/query.go
new file mode 100644
index 000000000..883aae268
--- /dev/null
+++ b/gopls/internal/lsp/testdata/workspacesymbol/query.go
@@ -0,0 +1,29 @@
+package main
+
+// Contains all of the workspace symbol queries.
+
+// -- Fuzzy matching --
+//@workspacesymbolfuzzy("rgop")
+//@workspacesymbolfuzzy("randoma")
+//@workspacesymbolfuzzy("randomb")
+
+// -- Case sensitive --
+//@workspacesymbolcasesensitive("main.main")
+//@workspacesymbolcasesensitive("p.Message")
+//@workspacesymbolcasesensitive("main.myvar")
+//@workspacesymbolcasesensitive("main.myType")
+//@workspacesymbolcasesensitive("main.myType.Blahblah")
+//@workspacesymbolcasesensitive("main.myStruct")
+//@workspacesymbolcasesensitive("main.myStruct.myStructField")
+//@workspacesymbolcasesensitive("main.myInterface")
+//@workspacesymbolcasesensitive("main.myInterface.DoSomeCoolStuff")
+//@workspacesymbolcasesensitive("main.embed.myStruct")
+//@workspacesymbolcasesensitive("main.embed.nestedStruct.nestedStruct2.int")
+//@workspacesymbolcasesensitive("main.embed.nestedInterface.myInterface")
+//@workspacesymbolcasesensitive("main.embed.nestedInterface.nestedMethod")
+//@workspacesymbolcasesensitive("dunk")
+//@workspacesymbolcasesensitive("Dunk")
+
+// -- Standard --
+//@workspacesymbol("")
+//@workspacesymbol("randomgophervar")
diff --git a/gopls/internal/lsp/testdata/workspacesymbol/query.go.golden b/gopls/internal/lsp/testdata/workspacesymbol/query.go.golden
new file mode 100644
index 000000000..4c6d470f7
--- /dev/null
+++ b/gopls/internal/lsp/testdata/workspacesymbol/query.go.golden
@@ -0,0 +1,83 @@
+-- workspace_symbol-caseinsensitive- --
+
+
+-- workspace_symbol-caseinsensitive-randomgophervar --
+workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable
+workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable
+
+-- workspace_symbol-casesensitive-Dunk --
+workspacesymbol/main.go:45:6-10 Dunk Function
+
+-- workspace_symbol-casesensitive-dunk --
+workspacesymbol/main.go:47:6-10 dunk Function
+
+-- workspace_symbol-casesensitive-main.embed.myStruct --
+workspacesymbol/main.go:29:2-10 main.embed.myStruct Field
+
+-- workspace_symbol-casesensitive-main.embed.nestedInterface.myInterface --
+workspacesymbol/main.go:40:3-14 main.embed.nestedInterface.myInterface Interface
+
+-- workspace_symbol-casesensitive-main.embed.nestedInterface.nestedMethod --
+workspacesymbol/main.go:41:3-15 main.embed.nestedInterface.nestedMethod Method
+
+-- workspace_symbol-casesensitive-main.embed.nestedStruct.nestedStruct2.int --
+workspacesymbol/main.go:35:4-7 main.embed.nestedStruct.nestedStruct2.int Field
+
+-- workspace_symbol-casesensitive-main.main --
+workspacesymbol/main.go:8:6-10 main.main Function
+
+-- workspace_symbol-casesensitive-main.myInterface --
+workspacesymbol/main.go:24:6-17 main.myInterface Interface
+workspacesymbol/main.go:25:2-17 main.myInterface.DoSomeCoolStuff Method
+
+-- workspace_symbol-casesensitive-main.myInterface.DoSomeCoolStuff --
+workspacesymbol/main.go:25:2-17 main.myInterface.DoSomeCoolStuff Method
+
+-- workspace_symbol-casesensitive-main.myStruct --
+workspacesymbol/main.go:20:6-14 main.myStruct Struct
+workspacesymbol/main.go:21:2-15 main.myStruct.myStructField Field
+
+-- workspace_symbol-casesensitive-main.myStruct.myStructField --
+workspacesymbol/main.go:21:2-15 main.myStruct.myStructField Field
+
+-- workspace_symbol-casesensitive-main.myType --
+workspacesymbol/main.go:14:6-12 main.myType Class
+workspacesymbol/main.go:18:18-26 main.myType.Blahblah Method
+
+-- workspace_symbol-casesensitive-main.myType.Blahblah --
+workspacesymbol/main.go:18:18-26 main.myType.Blahblah Method
+
+-- workspace_symbol-casesensitive-main.myvar --
+workspacesymbol/main.go:12:5-10 main.myvar Variable
+
+-- workspace_symbol-casesensitive-p.Message --
+workspacesymbol/p/p.go:3:7-14 p.Message Constant
+
+-- workspace_symbol-fuzzy-randoma --
+workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable
+workspacesymbol/a/a.go:5:7-28 RandomGopherConstantA Constant
+workspacesymbol/a/a.go:8:2-24 randomgopherinvariable Constant
+workspacesymbol/a/a_test.go:3:5-30 RandomGopherTestVariableA Variable
+workspacesymbol/a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable
+workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable
+workspacesymbol/b/b.go:6:2-5 RandomGopherStructB.Bar Field
+
+-- workspace_symbol-fuzzy-randomb --
+workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable
+workspacesymbol/a/a.go:8:2-24 randomgopherinvariable Constant
+workspacesymbol/a/a_test.go:3:5-30 RandomGopherTestVariableA Variable
+workspacesymbol/a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable
+workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable
+workspacesymbol/b/b.go:5:6-25 RandomGopherStructB Struct
+workspacesymbol/b/b.go:6:2-5 RandomGopherStructB.Bar Field
+
+-- workspace_symbol-fuzzy-rgop --
+workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable
+workspacesymbol/a/a.go:5:7-28 RandomGopherConstantA Constant
+workspacesymbol/a/a.go:8:2-24 randomgopherinvariable Constant
+workspacesymbol/a/a_test.go:3:5-30 RandomGopherTestVariableA Variable
+workspacesymbol/a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable
+workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable
+workspacesymbol/b/b.go:5:6-25 RandomGopherStructB Struct
+workspacesymbol/b/b.go:6:2-5 RandomGopherStructB.Bar Field
+