Files
chatservice_concept/vendor/github.com/go-chi/docgen/funcinfo.go
2024-12-29 23:29:33 -05:00

117 lines
2.2 KiB
Go

package docgen
import (
"go/parser"
"go/token"
"path/filepath"
"reflect"
"runtime"
"strings"
)
type FuncInfo struct {
Pkg string `json:"pkg"`
Func string `json:"func"`
Comment string `json:"comment"`
File string `json:"file,omitempty"`
Line int `json:"line,omitempty"`
Anonymous bool `json:"anonymous,omitempty"`
Unresolvable bool `json:"unresolvable,omitempty"`
}
func GetFuncInfo(i interface{}) FuncInfo {
fi := FuncInfo{}
frame := getCallerFrame(i)
goPathSrc := filepath.Join(getGoPath(), "src")
if frame == nil {
fi.Unresolvable = true
return fi
}
pkgName := getPkgName(frame.File)
if pkgName == "chi" {
fi.Unresolvable = true
}
funcPath := frame.Func.Name()
idx := strings.Index(funcPath, "/"+pkgName)
if idx > 0 {
fi.Pkg = funcPath[:idx+1+len(pkgName)]
fi.Func = funcPath[idx+2+len(pkgName):]
} else {
fi.Func = funcPath
}
if strings.Index(fi.Func, ".func") > 0 {
fi.Anonymous = true
}
fi.File = frame.File
fi.Line = frame.Line
if filepath.HasPrefix(fi.File, goPathSrc) {
fi.File = fi.File[len(goPathSrc)+1:]
}
// Check if file info is unresolvable
if strings.Index(funcPath, pkgName) < 0 {
fi.Unresolvable = true
}
if !fi.Unresolvable {
fi.Comment = getFuncComment(frame.File, frame.Line)
}
return fi
}
func getCallerFrame(i interface{}) *runtime.Frame {
value := reflect.ValueOf(i)
if value.Kind() != reflect.Func {
return nil
}
pc := value.Pointer()
frames := runtime.CallersFrames([]uintptr{pc})
if frames == nil {
return nil
}
frame, _ := frames.Next()
if frame.Entry == 0 {
return nil
}
return &frame
}
func getPkgName(file string) string {
fset := token.NewFileSet()
astFile, err := parser.ParseFile(fset, file, nil, parser.PackageClauseOnly)
if err != nil {
return ""
}
if astFile.Name == nil {
return ""
}
return astFile.Name.Name
}
func getFuncComment(file string, line int) string {
fset := token.NewFileSet()
astFile, err := parser.ParseFile(fset, file, nil, parser.ParseComments)
if err != nil {
return ""
}
if len(astFile.Comments) == 0 {
return ""
}
for _, cmt := range astFile.Comments {
if fset.Position(cmt.End()).Line+1 == line {
return cmt.Text()
}
}
return ""
}