117 lines
2.2 KiB
Go
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 ""
|
|
}
|