This test ports some arbitrary tests from the old marker framework, that were
*mostly* about completion.

-- flags --
-ignore_extra_diags

-- settings.json --
{
	"completeUnimported": false,
	"deepCompletion": false,
	"experimentalPostfixCompletions": false
}

-- go.mod --
module foobar.test

go 1.18

-- foo/foo.go --
package foo //@loc(PackageFoo, "foo"),item(PackageFooItem, "foo", "\"foobar.test/foo\"", "package")

type StructFoo struct { //@loc(StructFooLoc, "StructFoo"), 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(re"()E", Error)
}

func _() {
	var sFoo StructFoo           //@complete(re"()t", StructFoo)
	if x := sFoo; x.Value == 1 { //@complete(re"()V", Value), typedef("sFoo", StructFooLoc)
		return
	}
}

func _() {
	shadowed := 123
	{
		shadowed := "hi" //@item(shadowed, "shadowed", "string", "var")
		sha              //@complete(re"()a", shadowed), diag("sha", re"(undefined|undeclared)")
		_ = shadowed
	}
}

type IntFoo int //@loc(IntFooLoc, "IntFoo"), item(IntFoo, "IntFoo", "int", "type")

-- bar/bar.go --
package bar

import (
	"foobar.test/foo" //@item(foo, "foo", "\"foobar.test/foo\"", "package")
)

func helper(i foo.IntFoo) {} //@item(helper, "helper", "func(i foo.IntFoo)", "func")

func _() {
	help //@complete(re"()l", helper)
	_ = foo.StructFoo{} //@complete(re"()S", IntFoo, StructFoo)
}

// Bar is a function.
func Bar() { //@item(Bar, "Bar", "func()", "func", "Bar is a function.")
	foo.Foo()        //@complete(re"()F", Foo, IntFoo, StructFoo)
	var _ foo.IntFoo //@complete(re"()I", IntFoo, StructFoo)
	foo.()           //@complete(re"()\\(", Foo, IntFoo, StructFoo), diag(")", re"expected type")
}

// These items weren't present in the old marker tests (due to settings), but
// we may as well include them.
//@item(intConversion, "int()"), item(fooFoo, "foo.Foo")
//@item(fooIntFoo, "foo.IntFoo"), item(fooStructFoo, "foo.StructFoo")

func _() {
	var Valentine int //@item(Valentine, "Valentine", "int", "var")

	_ = foo.StructFoo{ //@diag("foo", re"unkeyed fields")
		Valu //@complete(re"() \\/\\/", Value)
	}
  	_ = foo.StructFoo{ //@diag("foo", re"unkeyed fields")
		Va        //@complete(re"()a", Value, Valentine)

	}
	_ = foo.StructFoo{
		Value: 5, //@complete(re"()a", Value)
	}
	_ = foo.StructFoo{
		//@complete(re"()//", Value, Valentine, intConversion, foo, helper, Bar)
	}
	_ = foo.StructFoo{
		Value: Valen //@complete(re"()le", Valentine)
	}
	_ = foo.StructFoo{
		Value:       //@complete(re"() \\/\\/", Valentine, intConversion, foo, helper, Bar)
	}
	_ = foo.StructFoo{
		Value:       //@complete(re"() ", Valentine, intConversion, foo, helper, Bar)
	}
}

-- baz/baz.go --
package baz

import (
	"foobar.test/bar"

	f "foobar.test/foo"
)

var FooStruct f.StructFoo

func Baz() {
	defer bar.Bar() //@complete(re"()B", Bar)
	// TODO: Test completion here.
	defer bar.B //@diag(re"bar.B()", re"must be function call")
	var x f.IntFoo  //@complete(re"()n", IntFoo), typedef("x", IntFooLoc)
	bar.Bar()       //@complete(re"()B", Bar)
}

func _() {
	bob := f.StructFoo{Value: 5}
	if x := bob. //@complete(re"() \\/\\/", Value)
	switch true == false {
		case true:
			if x := bob. //@complete(re"() \\/\\/", Value)
		case false:
	}
	if x := bob.Va //@complete(re"()a", Value)
	switch true == true {
		default:
	}
}

-- arraytype/arraytype.go --
package arraytype

import (
	"foobar.test/foo"
)

func _() {
	var (
		val string //@item(atVal, "val", "string", "var")
	)

	[] //@complete(re"() \\/\\/", atVal, PackageFooItem)

	[]val //@complete(re"() \\/\\/")

	[]foo.StructFoo //@complete(re"() \\/\\/", StructFoo)

	[]foo.StructFoo(nil) //@complete(re"()\\(", StructFoo)

	[]*foo.StructFoo //@complete(re"() \\/\\/", StructFoo)

	[...]foo.StructFoo //@complete(re"() \\/\\/", StructFoo)

	[2][][4]foo.StructFoo //@complete(re"() \\/\\/", StructFoo)

	[]struct { f []foo.StructFoo } //@complete(re"() }", 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(re"() \\/\\/", atMyInt)

	var a [1]myInt
	a = [1]m //@complete(re"() \\/\\/", atMyInt)

	var ds [][]myInt
	ds = [][]m //@complete(re"() \\/\\/", atMyInt)
}

func _() {
	var b [0]byte //@item(atByte, "b", "[0]byte", "var")
	var _ []byte = b //@snippet(re"() \\/\\/", atByte, "b[:]")
}

-- badstmt/badstmt.go --
package badstmt

import (
	"foobar.test/foo"
)

// (The syntax error causes suppression of diagnostics for type errors.
// See issue #59888.)

func _(x int) {
	defer foo.F //@complete(re"() \\/\\/", Foo, IntFoo, StructFoo)
	defer foo.F //@complete(re"() \\/\\/", Foo, IntFoo, StructFoo)
}

func _() {
	switch true {
	case true:
		go foo.F //@complete(re"() \\/\\/", Foo, IntFoo, StructFoo)
	}
}

func _() {
	defer func() {
		foo.F //@complete(re"() \\/\\/", Foo, IntFoo, StructFoo), snippet(re"() \\/\\/", Foo, "Foo()")

		foo. //@rank(re"() \\/\\/", Foo)
	}
}

-- badstmt/badstmt_2.go --
package badstmt

import (
	"foobar.test/foo"
)

func _() {
	defer func() { foo. } //@rank(re"() }", Foo)
}

-- badstmt/badstmt_3.go --
package badstmt

import (
	"foobar.test/foo"
)

func _() {
	go foo. //@rank(re"() \\/\\/", Foo, IntFoo), snippet(re"() \\/\\/", Foo, "Foo()")
}

-- badstmt/badstmt_4.go --
package badstmt

import (
	"foobar.test/foo"
)

func _() {
	go func() {
		defer foo. //@rank(re"() \\/\\/", Foo, IntFoo)
	}
}

-- selector/selector.go --
package selector

import (
	"foobar.test/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(re"();", 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(re"();", c, jill)
}

func _() {
	bar. //@complete(re"() \\/", Bar)
	x := 5

	var b *bob
	b. //@complete(re"() \\/", a, george)
	y, z := 5, 6

	b. //@complete(re"() \\/", a, george)
	y, z, a, b, c := 5, 6
}

func _() {
	bar. //@complete(re"() \\/", Bar)
	bar.Bar()

	bar. //@complete(re"() \\/", Bar)
	go f()
}

func _() {
	var b *bob
	if y != b. //@complete(re"() \\/", a, george)
	z := 5

	if z + y + 1 + b. //@complete(re"() \\/", a, george)
	r, s, t := 4, 5

	if y != b. //@complete(re"() \\/", a, george)
	z = 5

	if z + y + 1 + b. //@complete(re"() \\/", a, george)
	r = 4
}

-- literal_snippets/literal_snippets.go --
package literal_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(re"() \\/\\/", litIntSliceAddr, "&[]int{$0\\}")
	var _ **[]int = in //@complete(re"() \\/\\/")

	var slice []int
	slice = i //@snippet(re"() \\/\\/", litIntSlice, "[]int{$0\\}")
	slice = m //@snippet(re"() \\/\\/", makeIntSlice, "make([]int, ${1:})")
}

func _() {
	type namedInt []int

	namedInt{}        //@item(litNamedSlice, "namedInt{}", "", "var")
	make(namedInt, 0) //@item(makeNamedSlice, "make(namedInt, 0)", "", "func")

	var namedSlice namedInt
	namedSlice = n //@snippet(re"() \\/\\/", litNamedSlice, "namedInt{$0\\}")
	namedSlice = m //@snippet(re"() \\/\\/", makeNamedSlice, "make(namedInt, ${1:})")
}

func _() {
	make(chan int) //@item(makeChan, "make(chan int)", "", "func")

	var ch chan int
	ch = m //@snippet(re"() \\/\\/", makeChan, "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(re"() \\/\\/", litMap, "map[string]struct{\\}{$0\\}")
	m = m //@snippet(re"() \\/\\/", makeMap, "make(map[string]struct{\\})")

	struct{}{} //@item(litEmptyStruct, "struct{}{}", "", "var")

	m["hi"] = s //@snippet(re"() \\/\\/", litEmptyStruct, "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(re"() \\/\\/", litStruct, "myStruct{$0\\}")

	var msPtr *myStruct
	msPtr = m //@snippet(re"() \\/\\/", litStructPtr, "&myStruct{$0\\}")

	msPtr = &m //@snippet(re"() \\/\\/", litStruct, "myStruct{$0\\}")

	type myStructCopy struct { i int } //@item(myStructCopyType, "myStructCopy", "struct{...}", "struct")

	// Don't offer literal completion for convertible structs.
	ms = myStruct //@complete(re"() \\/\\/", 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(re"() \\/\\/", litImpl, "myImpl{\\}")

	myBasicImpl() //@item(litBasicImpl, "myBasicImpl()", "string", "var")

	mi = m //@snippet(re"() \\/\\/", litBasicImpl, "myBasicImpl($0)")

	// only satisfied by pointer to myImpl
	type myPtrIntf interface {
		bar()
	}

	&myImpl{} //@item(litImplPtr, "&myImpl{}", "", "var")

	var mpi myPtrIntf
	mpi = m //@snippet(re"() \\/\\/", litImplPtr, "&myImpl{\\}")
}

func _() {
	var s struct{ i []int } //@item(litSliceField, "i", "[]int", "field")
	var foo []int
	// no literal completions after selector
	foo = s.i //@complete(re"() \\/\\/", 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(re"()\\)", litMyStruct, litMyStructType)
}

func _() {
	Buffer{} //@item(litBuffer, "Buffer{}", "", "var")

	var b *bytes.Buffer
	b = bytes.Bu //@snippet(re"() \\/\\/", litBuffer, "Buffer{\\}")
}

func _() {
	_ = "func(...) {}" //@item(litFunc, "func(...) {}", "", "var")

	// no literal "func" completions
	http.Handle("", fun) //@complete(re"()\\)")

	var namedReturn func(s string) (b bool)
	namedReturn = f //@snippet(re"() \\/\\/", litFunc, "func(s string) (b bool) {$0\\}")

	var multiReturn func() (bool, int)
	multiReturn = f //@snippet(re"() \\/\\/", litFunc, "func() (bool, int) {$0\\}")

	var multiNamedReturn func() (b bool, i int)
	multiNamedReturn = f //@snippet(re"() \\/\\/", litFunc, "func() (b bool, i int) {$0\\}")

	var duplicateParams func(myImpl, int, myImpl)
	duplicateParams = f //@snippet(re"() \\/\\/", litFunc, "func(mi1 myImpl, i int, mi2 myImpl) {$0\\}")

	type aliasImpl = myImpl
	var aliasParams func(aliasImpl) aliasImpl
	aliasParams = f //@snippet(re"() \\/\\/", litFunc, "func(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(re"() \\/\\/", litFunc, "func(i1 []int, b [2]bool, m map[string]string, s struct{i int\\}, i2 interface{foo()\\}, c <-chan int) {$0\\}")

	var _ func(ast.Node) = f //@snippet(re"() \\/\\/", litFunc, "func(n ast.Node) {$0\\}")
	var _ func(error) = f //@snippet(re"() \\/\\/", litFunc, "func(err error) {$0\\}")
	var _ func(context.Context) = f //@snippet(re"() \\/\\/", litFunc, "func(ctx context.Context) {$0\\}")

	type context struct {}
	var _ func(context) = f //@snippet(re"() \\/\\/", litFunc, "func(ctx context) {$0\\}")
}

func _() {
	float64() //@item(litFloat64, "float64()", "float64", "var")

	// don't complete to "&float64()"
	var _ *float64 = float64 //@complete(re"() \\/\\/")

	var f float64
	f = fl //@complete(re"() \\/\\/", litFloat64),snippet(re"() \\/\\/", litFloat64, "float64($0)")

	type myInt int
	myInt() //@item(litMyInt, "myInt()", "", "var")

	var mi myInt
	mi = my //@snippet(re"() \\/\\/", litMyInt, "myInt($0)")
}

func _() {
	type ptrStruct struct {
		p *ptrStruct
	}

	ptrStruct{} //@item(litPtrStruct, "ptrStruct{}", "", "var")

	ptrStruct{
		p: &ptrSt, //@rank(re"(),", litPtrStruct)
	}

	&ptrStruct{} //@item(litPtrStructPtr, "&ptrStruct{}", "", "var")

	&ptrStruct{
		p: ptrSt, //@rank(re"(),", litPtrStructPtr)
	}
}

func _() {
	f := func(...[]int) {}
	f() //@snippet(re"()\\)", litIntSlice, "[]int{$0\\}")
}


func _() {
	// don't complete to "untyped int()"
	[]int{}[untyped] //@complete(re"()\\] \\/\\/")
}

type Tree[T any] struct{}

func (tree Tree[T]) Do(f func(s T)) {}

func _() {
	var t Tree[string]
	t.Do(fun) //@complete(re"()\\)", litFunc), snippet(re"()\\)", litFunc, "func(s string) {$0\\}")
}
