我正在尝试查找将context.Context
作为第一个参数的func
的函数调用。
我已经能够完成下面显示的操作,但我一直在从*types.Named
中获取底层类型。我该怎么做?
package main
import (
"bytes"
"context"
"fmt"
"go/ast"
"go/printer"
"go/token"
"go/types"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/singlechecker"
)
var Analyzer = &analysis.Analyzer{
Name: "addlint",
Doc: "reports integer additions",
Run: run,
}
func main() {
singlechecker.Main(Analyzer)
}
func funcHasContextContextAsFirstParam(pass *analysis.Pass, expr ast.Expr) bool {
t := pass.TypesInfo.TypeOf(expr)
if t == nil {
return false
}
bt, ok := t.Underlying().(*types.Signature)
if !ok {
return false
}
fmt.Printf("signature: %+v - %Tn", bt, bt)
params := bt.Params()
for i := 0; i < params.Len(); i++ {
v := params.At(i)
fmt.Printf("Type : %Tn", v.Type())
if named, ok := v.Type().(*types.Named); ok {
// fmt.Printf("named : %v - %Tn", named.Obj(), named.Obj())
fmt.Printf("named : %Tn", named)
fmt.Printf("named.Obj() : %Tn", named.Obj())
typ := named.Underlying()
fmt.Printf("typ: %Tn", typ.Underlying())
if _, ok = typ.(context.Context); ok {
fmt.Printf("context.Context type!n")
}
}
}
return true
}
func run(pass *analysis.Pass) (interface{}, error) {
for _, file := range pass.Files {
ast.Inspect(file, func(n ast.Node) bool {
be, ok := n.(*ast.CallExpr)
if !ok {
return true
}
fmt.Printf("call expression %+vn", be)
funcHasContextContextAsFirstParam(pass, be.Fun)
return true
})
}
return nil, nil
}
这就是我得到的输出:
call expression &{Fun:foo Lparen:6160580 Args:[c 0xc0003c5780 0xc0003c57c0] Ellipsis:0 Rparen:6160596}
signature: func(ctx context.Context, n int, str string) - *types.Signature
Type : *types.Named
named : *types.Named
named.Obj() : *types.TypeName
typ: *types.Interface
我最终得到了这样的东西:
func funcHasContextContextAsFirstParam(pass *analysis.Pass, expr ast.Expr) bool {
t := pass.TypesInfo.TypeOf(expr)
if t == nil {
return false
}
bt, ok := t.Underlying().(*types.Signature)
if !ok {
return false
}
params := bt.Params()
if params.Len() < 1 {
return false
}
param := params.At(0)
named, ok := param.Type().(*types.Named)
if !ok {
return false
}
namedObj := named.Obj()
if namedObj.Name() != "Context" || namedObj.Pkg().Name() != "context" {
return false
}
return true
}