I am having trouble finding scope level using the Go Analyze package.
Given an example.go
package main
import "log"
var myglobalvar = "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)
myLog(myglobalvar)
}
I'm trying to find the scope level on the arguments of a called function to determine if it is a global var or local var. I'm currently stuck at the argument's object decl and not sure how to proceed from here. In the end I want to build a custom linter for golangci-lint.
How can I find the argument's scope?
I have tried using the recommended golang analyze package.
My analyze.go:
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
}
EDIT: After a deeper dive I have discovered that once the object.Decl is created, it is assignStmt if it is a local scope and valueSpec if it's global.
if obj != nil {
if obj.Kind == ast.Var {
fmt.Println("V: ")
switch v := obj.Decl.(type) {
case *ast.AssignStmt:
fmt.Println("assignstmt")
fmt.Println("local assignment")
case *ast.ValueSpec:
fmt.Println("valuespec")
fmt.Println("global assignment")
default:
fmt.Printf("No idea: %s.\n", v)
}
}