<commit_before>package commands

import (
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"go/types"
	"nvim-go/internal/guru"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"golang.org/x/tools/go/ast/astutil"
	"golang.org/x/tools/go/buildutil"
	"golang.org/x/tools/go/loader"
)

// A QueryPos represents the position provided as input to a query:
// a textual extent in the program's source code, the AST node it
// corresponds to, and the package to which it belongs.
// Instances are created by parseQueryPos.
type queryPos struct {
	fset       *token.FileSet
	start, end token.Pos           // source extent of query
	path       []ast.Node          // AST path from query node to root of ast.File
	exact      bool                // 2nd result of PathEnclosingInterval
	info       *loader.PackageInfo // type info for the queried package (nil for fastQueryPos)
}

// TypeString prints type T relative to the query position.
func (qpos *queryPos) typeString(T types.Type) string {
	return types.TypeString(T, types.RelativeTo(qpos.info.Pkg))
}

// ObjectString prints object obj relative to the query position.
func (qpos *queryPos) ObjectString(obj types.Object) string {
	return types.ObjectString(obj, types.RelativeTo(qpos.info.Pkg))
}

// SelectionString prints selection sel relative to the query position.
func (qpos *queryPos) selectionString(sel *types.Selection) string {<commit_msg>cmds/guru: Add original Definition func for benchmarking<commit_after>package commands

import (
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"go/types"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"nvim-go/internal/guru"
	"nvim-go/internal/guru/serial"

	"github.com/juju/errors"
	"golang.org/x/tools/go/ast/astutil"
	"golang.org/x/tools/go/buildutil"
	"golang.org/x/tools/go/loader"
)

func Definition(q *guru.Query) (*serial.Definition, error) {
	// First try the simple resolution done by parser.
	// It only works for intra-file references but it is very fast.
	// (Extending this approach to all the files of the package,
	// resolved using ast.NewPackage, was not worth the effort.)
	{
		qpos, err := fastQueryPos(q.Build, q.Pos)
		if err != nil {
			// nvim.ErrorWrap(v, errors.Annotate(err, pkgGuru))
			return nil, err
		}

		id, _ := qpos.path[0].(*ast.Ident)
		if id == nil {
			err := errors.New("no identifier here")
			// nvim.ErrorWrap(v, errors.Annotate(err, pkgGuru))
			return nil, err
			// return nil, nil
		}

		// Did the parser resolve it to a local object?
		if obj := id.Obj; obj != nil && obj.Pos().IsValid() {
			return &serial.Definition{
				ObjPos: qpos.fset.Position(obj.Pos()).String(),
				Desc:   fmt.Sprintf("%s %s", obj.Kind, obj.Name),
			}, nil
		}

		// Qualified identifier?
		if pkg := guru.PackageForQualIdent(qpos.path, id); pkg != "" {
			srcdir := filepath.Dir(qpos.fset.File(qpos.start).Name())
			tok, pos, err := guru.FindPackageMember(q.Build, qpos.fset, srcdir, pkg, id.Name)
			if err != nil {
				// nvim.ErrorWrap(v, errors.Annotate(err, pkgGuru))
				return nil, err
			}
			return &serial.Definition{
				ObjPos: qpos.fset.Position(pos).String(),
				Desc:   fmt.Sprintf("%s %s.%s", tok, pkg, id.Name),
			}, nil
		}

		// Fall back on the type checker.
	}

	// Run the type checker.
	lconf := loader.Config{Build: q.Build}
	allowErrors(&lconf)

	if _, err := importQueryPackage(q.Pos, &lconf); err != nil {
		// nvim.ErrorWrap(v, errors.Annotate(err, pkgGuru))
		return nil, err
	}

	// Load/parse/type-check the program.
	lprog, err := lconf.Load()
	if err != nil {
		// nvim.ErrorWrap(v, errors.Annotate(err, pkgGuru))
		return nil, err
	}

	qpos, err := parseQueryPos(lprog, q.Pos, false)
	if err != nil {
		// nvim.ErrorWrap(v, errors.Annotate(err, pkgGuru))
		return nil, err
	}

	id, _ := qpos.path[0].(*ast.Ident)
	if id == nil {
		err := errors.New("no identifier here")
		// nvim.ErrorWrap(v, errors.Annotate(err, pkgGuru))
		// return nil, nil
		return nil, err
	}

	obj := qpos.info.ObjectOf(id)
	if obj == nil {
		// Happens for y in "switch y := x.(type)",
		// and the package declaration,
		// but I think that's all.
		err := errors.New("no object for identifier")
		// nvim.ErrorWrap(v, errors.Annotate(err, pkgGuru))
		// return nil, nil
		return nil, err
	}

	if !obj.Pos().IsValid() {
		err := errors.Errorf("%s is built in", obj.Name())
		// nvim.ErrorWrap(v, errors.Annotate(err, pkgGuru))
		// return nil, nil
		return nil, err
	}

	return &serial.Definition{
		ObjPos: qpos.fset.Position(obj.Pos()).String(),
		Desc:   qpos.ObjectString(obj),
	}, nil
}

// A QueryPos represents the position provided as input to a query:
// a textual extent in the program's source code, the AST node it
// corresponds to, and the package to which it belongs.
// Instances are created by parseQueryPos.
type queryPos struct {
	fset       *token.FileSet
	start, end token.Pos           // source extent of query
	path       []ast.Node          // AST path from query node to root of ast.File
	exact      bool                // 2nd result of PathEnclosingInterval
	info       *loader.PackageInfo // type info for the queried package (nil for fastQueryPos)
}

// TypeString prints type T relative to the query position.
func (qpos *queryPos) typeString(T types.Type) string {
	return types.TypeString(T, types.RelativeTo(qpos.info.Pkg))
}

// ObjectString prints object obj relative to the query position.
func (qpos *queryPos) ObjectString(obj types.Object) string {
	return types.ObjectString(obj, types.RelativeTo(qpos.info.Pkg))
}

// SelectionString prints selection sel relative to the query position.
func (qpos *queryPos) selectionString(sel *types.Selection) string {
{'fraction_non_alphanumeric': 0.13448947089010793, 'fraction_numerical': 0.0007078393204742523, 'mean_word_length': 3.249624060150376, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7375665', 'n_tokens_mistral': 2077, 'n_tokens_neox': 1932, 'n_words': 565}