136 lines
2.8 KiB
Go
136 lines
2.8 KiB
Go
|
// Copyright 2011-2015 visualfc <visualfc@gmail.com>. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
package finddecl
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"go/ast"
|
||
|
"go/parser"
|
||
|
"go/token"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strconv"
|
||
|
|
||
|
"github.com/visualfc/gotools/command"
|
||
|
)
|
||
|
|
||
|
var Command = &command.Command{
|
||
|
Run: runFindDecl,
|
||
|
UsageLine: "finddecl",
|
||
|
Short: "golang finddecl util",
|
||
|
Long: `golang finddecl util.`,
|
||
|
}
|
||
|
var (
|
||
|
filePath string
|
||
|
fileLine int
|
||
|
)
|
||
|
|
||
|
func init() {
|
||
|
Command.Flag.StringVar(&filePath, "file", "", "file path")
|
||
|
Command.Flag.IntVar(&fileLine, "line", -1, "file line")
|
||
|
}
|
||
|
|
||
|
func runFindDecl(cmd *command.Command, args []string) error {
|
||
|
if len(filePath) == 0 || fileLine == -1 {
|
||
|
cmd.Usage()
|
||
|
return os.ErrInvalid
|
||
|
}
|
||
|
if !filepath.IsAbs(filePath) {
|
||
|
dir, err := os.Getwd()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
filePath = filepath.Join(dir, filePath)
|
||
|
}
|
||
|
|
||
|
fset := token.NewFileSet()
|
||
|
f, err := parser.ParseFile(fset, filePath, nil, 0)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
decl := findDecl(fset, f, fileLine)
|
||
|
if decl == nil {
|
||
|
fmt.Println("-")
|
||
|
return errors.New("error find decl")
|
||
|
}
|
||
|
printDecl(fset, decl, fileLine)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type Info struct {
|
||
|
Type string
|
||
|
Name string
|
||
|
BeginLine int
|
||
|
EndLine int
|
||
|
}
|
||
|
|
||
|
func printDecl(fset *token.FileSet, decl ast.Decl, line int) {
|
||
|
var tag string
|
||
|
var name string
|
||
|
|
||
|
tag = "-"
|
||
|
name = "-"
|
||
|
switch d := decl.(type) {
|
||
|
case *ast.GenDecl:
|
||
|
switch d.Tok {
|
||
|
case token.IMPORT:
|
||
|
tag = "import"
|
||
|
if len(d.Specs) > 0 {
|
||
|
if ts := d.Specs[0].(*ast.ImportSpec); ts != nil {
|
||
|
name, _ = strconv.Unquote(ts.Path.Value)
|
||
|
}
|
||
|
}
|
||
|
case token.TYPE:
|
||
|
tag = "type"
|
||
|
if len(d.Specs) > 0 {
|
||
|
if ts := d.Specs[0].(*ast.TypeSpec); ts != nil {
|
||
|
name = ts.Name.Name
|
||
|
switch ts.Type.(type) {
|
||
|
case *ast.StructType:
|
||
|
tag = "struct"
|
||
|
case *ast.InterfaceType:
|
||
|
tag = "interface"
|
||
|
default:
|
||
|
tag = "type"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
case token.VAR, token.CONST:
|
||
|
tag = d.Tok.String()
|
||
|
var testName string
|
||
|
for _, ds := range d.Specs {
|
||
|
if ts := ds.(*ast.ValueSpec); ts != nil {
|
||
|
name = ts.Names[0].Name
|
||
|
for _, n := range ts.Names {
|
||
|
if line >= fset.Position(n.Pos()).Line && line <= fset.Position(n.End()).Line {
|
||
|
testName = n.Name
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if testName != "" {
|
||
|
name = testName
|
||
|
}
|
||
|
default:
|
||
|
tag = d.Tok.String()
|
||
|
}
|
||
|
case *ast.FuncDecl:
|
||
|
tag = "func"
|
||
|
name = d.Name.Name
|
||
|
}
|
||
|
fmt.Println(tag, name, fset.Position(decl.Pos()).Line, fset.Position(decl.End()).Line)
|
||
|
}
|
||
|
|
||
|
func findDecl(fset *token.FileSet, file *ast.File, line int) ast.Decl {
|
||
|
for _, decl := range file.Decls {
|
||
|
if line >= fset.Position(decl.Pos()).Line && line <= fset.Position(decl.End()).Line {
|
||
|
return decl
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|