使用 Golang Analysis 包查找范围级别

问题描述 投票:0回答:1

我在使用 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 analyzer golangci-lint
1个回答
0
投票

在 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
}
© www.soinside.com 2019 - 2024. All rights reserved.