为了账号安全,请及时绑定邮箱和手机立即绑定

通过静态分析查找变量的类型?

通过静态分析查找变量的类型?

Go
手掌心 2022-12-19 10:51:49
如何通过静态分析判断变量的类型?假设我有以下代码:func doSomething(x interface{}) {}func main() {  p := Person()  doSomething(p)}而我想分析一下doSomething(person),是否可以通过静态分析得到Person的类型?如果有多个级别的分配怎么办?p1 := Person()p2 := p1doSomething(p2)要么parent := Parent()p := Parent.Child() // type PersondoSomething(p)用例是我有一个在整个(非常大的)代码库中常用的通用函数,并且想引入该函数的新类型安全版本。为此,我希望自动确定函数的“类型”并相应地重构它:// oldDB.InsertRow(person)// newPerson.InsertRow(person)
查看完整描述

2 回答

?
尚方宝剑之说

TA贡献1788条经验 获得超4个赞

通过静态分析查找表达式的类型非常重要,有时甚至是不可能的,有关详细信息,请参阅Golang static identifier resolution。


用例是我有一个在整个(非常大的)代码库中常用的通用函数,并且想引入该函数的新类型安全版本。为此,我希望自动确定函数的“类型”并相应地重构它:


// old

DB.InsertRow(person)


// new

Person.InsertRow(person)

仅出于重构目的,我认为不值得费心去实施它。


您可以做的是DB.InsertRow()临时更改签名以仅接受特定类型,例如int您确定未在任何地方使用的自定义类型(例如type tempFoo struct{})。


为了什么目的?这样做,编译器将为您完成艰苦的工作。您将看到错误消息准确显示您的代码库试图传递给的类型DB.InsertRow(),所以我想说任务已完成。


例如这段代码编译:


func doSomething(x interface{}) {}


func main() {

    doSomething(image.Pt(1, 2))

    doSomething("abc")

    doSomething(image.Rect) // image.Rect is a function which we don't call,

                            // so we're passing a value of a function type here

}

如果我们改变doSomething():


func doSomething(x int) {}

我们从编译器中得到我们正在寻找的类型:


./prog.go:10:14: 不能使用 image.Pt(1, 2)(image.Point类型的值)作为 doSomething 参数中的 int 类型


./prog.go:11:14: 不能在 doSomething 的参数中使用“abc”(无类型字符串常量)作为 int 值


./prog.go:12:14: 不能使用 image.Rect(类型func(x0 int, y0 int, x1 int, y1 int) image.Rectangle 的值)作为 doSomething 参数中的 int 类型


查看完整回答
反对 回复 2022-12-19
?
HUX布斯

TA贡献1876条经验 获得超6个赞

使用Golang static identifier resolution to use的建议golang.org/x/tools/go/types,我发现这对golang.org/x/tools/go/analysis包来说非常简单,它具有可用的类型信息以及解析的 ast

这是我的解决方案:

package rewriter


import (

    "go/ast"


    "golang.org/x/tools/go/analysis"


    "golang.org/x/tools/go/analysis/passes/inspect"


    "golang.org/x/tools/go/ast/inspector"

)


func run(pass *analysis.Pass) (interface{}, error) {

    inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)


    nodeFilter := []ast.Node{

        (*ast.CallExpr)(nil),

    }


    inspect.Nodes(nodeFilter, func(node ast.Node, push bool) bool {

        callExpr, ok := node.(*ast.CallExpr)

        if !ok {

            return true

        }


        funcExpr, ok := callExpr.Fun.(*ast.SelectorExpr)

        if !ok {

            return true

        }


        // check method name

        if funcExpr.Sel.Name != "doSomething" {

            return true

        }


        for _, arg := range callExpr.Args {

            // lookup type of the arg

            argType := pass.TypesInfo.Types[arg].Type

            if argType.String() == "*rewriter.Person" {

                // do whatever you want here

            }

        }

        return false

    })

    return nil, nil

}

可以扩充它以查看方法的接收者并根据需要添加重构逻辑(使用analysis.Diagnostic)。



查看完整回答
反对 回复 2022-12-19
  • 2 回答
  • 0 关注
  • 77 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信