// 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 source

import (
	"context"
	"go/ast"
	"go/token"
	"go/types"

	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/telemetry/event"
	"golang.org/x/xerrors"
)

// ReferenceInfo holds information about reference to an identifier in Go source.
type ReferenceInfo struct {
	Name string
	mappedRange
	ident         *ast.Ident
	obj           types.Object
	pkg           Package
	isDeclaration bool
}

// References returns a list of references for a given identifier within the packages
// containing i.File. Declarations appear first in the result.
func References(ctx context.Context, s Snapshot, f FileHandle, pp protocol.Position, includeDeclaration bool) ([]*ReferenceInfo, error) {
	ctx, done := event.StartSpan(ctx, "source.References")
	defer done()

	qualifiedObjs, err := qualifiedObjsAtProtocolPos(ctx, s, f, pp)
	// Don't return references for builtin types.
	if xerrors.Is(err, errBuiltin) {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}
	return references(ctx, s, qualifiedObjs, includeDeclaration)
}

// references is a helper function used by both References and Rename,
// to avoid recomputing qualifiedObjsAtProtocolPos.
func references(ctx context.Context, s Snapshot, qos []qualifiedObject, includeDeclaration bool) ([]*ReferenceInfo, error) {
	var (
		references []*ReferenceInfo
		seen       = make(map[token.Position]bool)
		fset       = s.View().Session().Cache().FileSet()
	)

	// Make sure declaration is the first item in the response.
	if includeDeclaration {
		rng, err := objToMappedRange(s.View(), qos[0].pkg, qos[0].obj)
		if err != nil {
			return nil, err
		}
		ident, _ := qos[0].node.(*ast.Ident)
		references = append(references, &ReferenceInfo{
			mappedRange:   rng,
			Name:          qos[0].obj.Name(),
			ident:         ident,
			obj:           qos[0].obj,
			pkg:           qos[0].pkg,
			isDeclaration: true,
		})
	}
	for _, qo := range qos {
		var searchPkgs []Package

		// Only search dependents if the object is exported.
		if qo.obj.Exported() {
			reverseDeps, err := s.GetReverseDependencies(ctx, qo.pkg.ID())
			if err != nil {
				return nil, err
			}
			for _, ph := range reverseDeps {
				pkg, err := ph.Check(ctx)
				if err != nil {
					return nil, err
				}
				searchPkgs = append(searchPkgs, pkg)
			}
		}
		// Add the package in which the identifier is declared.
		searchPkgs = append(searchPkgs, qo.pkg)
		for _, pkg := range searchPkgs {
			for ident, obj := range pkg.GetTypesInfo().Uses {
				if obj != qo.obj {
					continue
				}
				pos := fset.Position(ident.Pos())
				if seen[pos] {
					continue
				}
				seen[pos] = true
				rng, err := posToMappedRange(s.View(), pkg, ident.Pos(), ident.End())
				if err != nil {
					return nil, err
				}
				references = append(references, &ReferenceInfo{
					Name:        ident.Name,
					ident:       ident,
					pkg:         pkg,
					obj:         obj,
					mappedRange: rng,
				})
			}
		}
	}
	return references, nil
}
