Go 代码 "grep" :向我显示返回名为 FooBar 的结构的所有函数



是否有一种方法来搜索(又名"grep")一些Go代码,并显示所有函数/方法返回一个名为"FooBar"结构?

命令行工具就可以了,或者在vscode中也可以。

在vscode中,如果我使用"Go to References"我也看到了这个结构体的方法(我不想看到的)

更新:我知道如何通过vscode终端使用grep。但使用greprg进行此任务容易出错。我正在寻找一个基于ast的解决方案。

您可以尝试使用callgraph和grep组合来解析go代码,并在函数签名中找到所需的返回值。

安装::

go install golang.org/x/tools/cmd/callgraph@latest

例子:

✳️项目结构

.
├── main.go
├── go.mod
├── service
│   └── service.go
└── types
   └── type.go

✳️service.go

package service
import "github.com/some/project/types"
func ReturnX() types.X {
return types.X{}
}
type Service struct {
}
func (Service) ReturnX() types.X {
return types.X{}
}
func (Service) ReturnPtrX() *types.X {
return &types.X{}
}

✳️type.go

package types
type X struct {
}

✳️main.go

package main
import (
"github.com/some/project/service"
)
func main() {
A()
s := service.Service{}
s.ReturnX()
s.ReturnPtrX()
}
func A() string {
service.ReturnX()
return ""
}
% callgraph -format '{{.Caller}}--{{.Dynamic}}-{{.Line}}:{{.Column}}-->{{.Callee}} - {{.Callee.Signature.Results}}}' main.go | grep types.X
command-line-arguments.A--static-16:17-->github.com/some/project/service.ReturnX - (github.com/some/project/types.X)}
command-line-arguments.main--static-11:11-->(github.com/some/project/service.Service).ReturnX - (github.com/some/project/types.X)}
command-line-arguments.main--static-12:14-->(github.com/some/project/service.Service).ReturnPtrX - (*github.com/some/project/types.X)}

配置格式查看源代码。例如,.Callee为ssa。函数类型->你可以使用text/template语法来达到它的值({{.Callee.Signature.Results}}})

总结:

  • 加载活动目录
  • 跳过不在路径中的任何节点:Package > File > FuncDecl
  • 用DFS遍历AST
  • 打印找到的函数名。
  • 可以使用FooBar的变体,如*FooBar, []FooBar, map[FooBar]any

func recursivelySearchForIdent(node ast.Node, identName string) bool {
matchFound := false
ast.Inspect(node, func(n ast.Node) bool {
if n == nil {
return false
}
if n, ok := n.(*ast.Ident); ok {
if n.Name == identName {
matchFound = true
}
}
return true
})
return matchFound
}
func main() {
packageName := "my_package"
structName := "FooBar"
pkgs, err := parser.ParseDir(token.NewFileSet(), ".", nil, parser.AllErrors)
if err != nil {
log.Println(errors.Wrap(err, "failed to load directory"))
}
if _, ok := pkgs[packageName]; !ok {
log.Fatalln("failed to load package")
}
pkg := pkgs[packageName]
selectedFuncDecls := []*ast.FuncDecl{}
ast.Inspect(pkg, func(n ast.Node) bool {
if n == nil {
return false
}
switch n := n.(type) {
case *ast.Package, *ast.File:
return true
case *ast.FuncDecl:
if n.Type.Results != nil {
if recursivelySearchForIdent(n.Type.Results, structName) {
selectedFuncDecls = append(selectedFuncDecls, n)
}
}
}
return false
})
for _, funcDecl := range selectedFuncDecls {
fmt.Println(funcDecl.Name)
}
}

我认为ast-grep正是可以解决你的问题的工具。它是一个基于抽象语法树搜索代码的命令行工具。

根据文档,这个查询应该匹配所有返回FooBar的Golang函数。

func $A($$$) *FooBar

解释:

  • 这是一个函数声明,用于匹配任何返回FooBar指针的函数。
  • func后面的$A表示匹配任何名称的通配符。
  • $$$类似于*重复符号,用于匹配零个或多个AST节点。它可以匹配任何函数,不管它的参数。

参见在线游乐场示例

如果您还需要匹配方法语法,我认为YAML可以帮助您。

rule:
any:
- pattern: func $A($$$) *FooBar
- pattern: func ($S $TYPE) $M($$$) *FooBar

操场上演示

最新更新