我在使用 Go Analytics 包查找范围级别时遇到问题。
举个例子。去
package main
import "log"
var mylocalvar = "hello from global"
func myLog(format string, args ...interface{}) {
const prefix = "[my] "
mylocalvar := "hello from local"
log.Printf(prefix+myglobalvar+mylocalvar+format, args...)
}
func main() {
mystring := "HELLO FROM MAIN"
myLog(mystring)
}
我试图找到被调用函数的参数的作用域级别,以确定它是全局变量还是局部变量。我目前陷入了
argument's object decl
,不知道如何从这里继续。最后我想为 golangci-lint 构建一个自定义的 linter。
如何找到参数的范围?
我尝试过使用推荐的 golang 分析包。
我的分析:
func run(pass *analysis.Pass) (interface{}, error) {
inspect := func(node ast.Node) bool {
// find all callexprs
callExpr, ok := node.(*ast.CallExpr)
if !ok {
return true
}
// find function identity
funcIdent, ok := callExpr.Fun.(*ast.Ident)
if !ok {
return true
}
// if function name matches
if funcIdent.Name == "myLog" {
funcArgs := callExpr.Args
for _, s := range funcArgs {
argObject, ok := s.(*ast.Ident)
if !ok {
return true
}
declObj, ok := argObject.Obj.Decl.(*ast.Ident)
if !ok {
return true
}
fmt.Println(declObj) // I am stuck here
}
}
return true
}
for _, f := range pass.Files {
ast.Inspect(f, inspect)
}
return nil, nil
}
在 Go 代码分析场景中,您尝试确定函数调用中变量的范围。您正确使用 Go ast 包来遍历 Go 代码的 AST(抽象语法树)。然而,该方法需要一些改进才能准确识别变量的范围。
这是分析函数的修订版本,可以帮助您识别函数参数是全局变量还是局部变量:
func run(pass *analysis.Pass) (interface{}, error) {
inspect := func(node ast.Node) bool {
// Find all call expressions.
callExpr, ok := node.(*ast.CallExpr)
if !ok {
return true
}
// Find function identity.
funcIdent, ok := callExpr.Fun.(*ast.Ident)
if !ok {
return true
}
// If function name matches "myLog".
if funcIdent.Name == "myLog" {
for _, arg := range callExpr.Args {
argIdent, ok := arg.(*ast.Ident)
if !ok {
continue // If not an identifier, skip.
}
obj := argIdent.Obj
if obj != nil {
if obj.Kind == ast.Var {
scope := pass.TypesInfo.Scopes[obj.Decl.Pos()]
if scope != nil && scope.Pos() == pass.Pkg.Scope().Pos() {
fmt.Printf("%s is a global variable\n", argIdent.Name)
} else {
fmt.Printf("%s is a local variable\n", argIdent.Name)
}
}
}
}
}
return true
}
for _, f := range pass.Files {
ast.Inspect(f, inspect)
}
return nil, nil
}