2016-05-17 4 views
0

私は、ユーザーが1)Goファイルを含むディレクトリを指定するコマンドラインアプリケーションを作成しています。2)変数名はhttp.Handler動的に指定されたGo変数に特定の型があるかどうかを確認します。

go run cli.go /path/to/a/go/library MyCustomHandler 

は私が

  • は、指定された名前の変数を見つけるのファイル解析

    • にしようとしている
    • はそれが私が最初に行うことができますhttp.Handler

    だことを確認してください2つの問題はありません - 私はparser.ParseDirと呼んで、私が希望するパッケージを*ast.Package、t

    func findHttpHandler(pkg *ast.Package, handlerName string) (*ast.FuncDecl, error) { 
        for _, file := range pkg.Files { 
         for _, decl := range file.Decls { 
          gd, ok := decl.(*ast.GenDecl) 
          if !ok || gd.Tok != token.VAR { 
           continue 
          } 
          if len(gd.Specs) != 1 { 
           continue 
          } 
          spec0 := gd.Specs[0] 
          vs, ok := spec0.(*ast.ValueSpec) 
          if !ok { 
           continue 
          } 
          if len(vs.Names) != 1 { 
           continue 
          } 
          ident := vs.Names[0] 
          if ident.Name != handlerName { 
           continue 
          } 
          // ... 
         } 
        } 
    } 
    

    問題は、この時点でValueSpec.Typeがnilされ、これはhttp.Handlerであるかどうかを把握するためにどのような方法があるように表示されません。このような、それ以上の鶏ループ。

    go/typesパッケージにはタイプを確認するためのツールがありますが、プログラム全体を解析してタイプチェックするためには、さらに多くの設定作業が必要になるようです。私はこの道を行く必要があるのでしょうか、それとももっと簡単な方法ですか、ちょうどパッケージを使用していますか、何とかgo buildを使用していますか?

  • +0

    こんにちはケビンを期待して、いくつかのトレースを行なったし、方法を見つけます! :)それはこの質問に近いと思われる:http://stackoverflow.com/questions/27976493/golang-static-identifier-resolution 私はそれが助けてくれることを望む。 – gbin

    答えて

    1

    は助け

    https://play.golang.org/p/f4XF8K_FbL

    package main 
    
    import (
        "go/parser" 
        "go/token" 
        "os" 
        "go/ast" 
        "log" 
        "net/http" 
        //"reflect" 
    ) 
    
    func MyCustomHandler(w http.ResponseWriter, r* http.Request){ 
    
    } 
    
    func findHttpHandler(pkg *ast.Package, handlerName string) (*ast.FuncDecl, error) { 
        for _, file := range pkg.Files { 
         for _, decl := range file.Decls { 
          fd, ok := decl.(*ast.FuncDecl) 
          if !ok || fd == nil{ 
           continue 
          } 
          if fd.Name.Name != handlerName{ 
           continue 
          } 
          if len(fd.Type.Params.List) == 2 { 
           p1 := fd.Type.Params.List[0] 
           p2 := fd.Type.Params.List[1] 
    
           exp, ok := p1.Type.(*ast.SelectorExpr) 
           if !ok{ 
            break; 
           } 
           ident, ok := exp.X.(*ast.Ident) 
           if !ok{ 
            break 
           } 
           if ident.Name!="http" || exp.Sel.Name != "ResponseWriter"{ 
            break; 
           } 
    
           exp2, ok := p2.Type.(*ast.StarExpr) 
           if !ok{ 
            break; 
           } 
           exp = exp2.X.(*ast.SelectorExpr) 
           ident, ok = exp.X.(*ast.Ident) 
           if !ok{ 
            break 
           } 
           if ident.Name!="http" || exp.Sel.Name != "Request"{ 
            break; 
           } 
           return fd, nil 
          } 
         } 
        } 
        return nil, nil 
    } 
    
    func main() { 
        fs := token.NewFileSet() 
        pkgs, err := parser.ParseDir(fs, os.Args[1], nil, parser.Trace) 
        if err != nil{ 
         log.Fatalln(err) 
        } 
        for _,pkg:=range pkgs{ 
         d, _ := findHttpHandler(pkg, "MyCustomHandler"); 
         log.Println(d) 
        } 
    } 
    
    関連する問題