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

如何通过静态分析判断变量的类型?


假设我有以下代码:


func doSomething(x interface{}) {}


func main() {

  p := Person()

  doSomething(p)

}

而我想分析一下doSomething(person),是否可以通过静态分析得到Person的类型?


如果有多个级别的分配怎么办?


p1 := Person()

p2 := p1

doSomething(p2)

要么


parent := Parent()

p := Parent.Child() // type Person

doSomething(p)

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


// old

DB.InsertRow(person)


// new

Person.InsertRow(person)


手掌心
浏览 78回答 2
2回答

尚方宝剑之说

通过静态分析查找表达式的类型非常重要,有时甚至是不可能的,有关详细信息,请参阅Golang static identifier resolution。用例是我有一个在整个(非常大的)代码库中常用的通用函数,并且想引入该函数的新类型安全版本。为此,我希望自动确定函数的“类型”并相应地重构它:// oldDB.InsertRow(person)// newPerson.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 类型

HUX布斯

使用Golang static identifier resolution to use的建议golang.org/x/tools/go/types,我发现这对golang.org/x/tools/go/analysis包来说非常简单,它具有可用的类型信息以及解析的 ast。这是我的解决方案:package rewriterimport (    "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)。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go