1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
// Copyright (c) 2018-2021, Maxime Soulé
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.
package location
import (
"fmt"
"runtime"
"strings"
)
// Location records a place in a source file.
type Location struct {
File string // File name
Func string // Function name
Line int // Line number inside file
Inside string // Inside is used when Location is inside something else
BehindCmp bool // BehindCmp is true when operator is behind a Cmp* function
}
// GetLocationer is the interface that wraps the basic GetLocation method.
type GetLocationer interface {
GetLocation() Location
}
// New returns a new [Location]. callDepth is the number of
// stack frames to ascend to get the calling function (Func field),
// added to 1 to get the File & Line fields.
//
// If the location can not be determined, ok is false and location is
// not valid.
func New(callDepth int) (loc Location, ok bool) {
_, loc.File, loc.Line, ok = runtime.Caller(callDepth + 1)
if !ok {
return
}
if index := strings.LastIndexAny(loc.File, `/\`); index >= 0 {
loc.File = loc.File[index+1:]
}
pc, _, _, ok := runtime.Caller(callDepth)
if !ok {
return
}
loc.Func = runtime.FuncForPC(pc).Name()
return
}
// IsInitialized returns true if l is initialized
// (e.g. [NewLocation] called without an error), false otherwise.
func (l Location) IsInitialized() bool {
return l.File != ""
}
// Implements [fmt.Stringer].
func (l Location) String() string {
return fmt.Sprintf("%s %sat %s:%d", l.Func, l.Inside, l.File, l.Line)
}
|