You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Go语言AST判断CallExpr调用的是自定义还是内置函数

判断Go AST中len调用是自定义函数还是内置函数

先看示例代码:

package main

import "fmt"

func len(s []int) string {
    return "xyz"
}

func main() {
    s := []int{1, 2, 3}
    fmt.Println(len(s))
}

这段代码里自定义的len([]int)会覆盖内置len,输出xyz。现在已知len(s)对应的ast.CallExpr节点,怎么通过Go的AST+类型检查判断调用的是自定义还是内置函数?


核心思路:语法AST不够,必须结合类型检查

单纯的AST语法分析只能看到一个名为len的标识符调用,没法区分是内置还是自定义——因为内置函数不会在AST里生成对应的函数定义节点,而自定义函数会有ast.FuncDecl。要确定实际调用的是哪个,必须用go/types包做类型检查,它会帮我们绑定标识符到实际的对象。

具体步骤

  1. 解析AST并做类型检查:用parser.ParseFile解析代码得到AST,再用types.Config.Check进行类型检查,同时传入types.Info对象来记录每个标识符的绑定信息。
  2. 定位ast.CallExpr的标识符:从ast.CallExpr的Fun字段取出对应的ast.Ident(也就是调用的函数名len)。
  3. 通过类型信息判断对象类型:
    • 如果标识符绑定的是*types.Builtin类型,说明调用的是内置函数;
    • 如果是*types.Func类型,说明调用的是自定义函数(同名覆盖场景下即为用户自定义的函数)。

示例实现代码

package main

import (
	"go/ast"
	"go/parser"
	"go/token"
	"go/types"
	"log"
)

func main() {
	fset := token.NewFileSet()
	src := `package main

import "fmt"

func len(s []int) string {
	return "xyz"
}

func main() {
	s := []int{1, 2, 3}
	fmt.Println(len(s))
}`
	// 解析代码生成AST
	file, err := parser.ParseFile(fset, "main.go", src, parser.AllErrors)
	if err != nil {
		log.Fatalf("解析失败: %v", err)
	}

	// 初始化类型检查配置
	conf := types.Config{}
	info := &types.Info{
		Uses: make(map[*ast.Ident]types.Object), // 记录标识符的使用信息
	}
	// 执行类型检查
	if _, err := conf.Check("main", fset, []*ast.File{file}, info); err != nil {
		log.Fatalf("类型检查失败: %v", err)
	}

	// 遍历AST找到目标CallExpr
	ast.Inspect(file, func(n ast.Node) bool {
		callExpr, ok := n.(*ast.CallExpr)
		if !ok {
			return true
		}
		// 确认调用的函数是标识符len
		funcIdent, ok := callExpr.Fun.(*ast.Ident)
		if !ok || funcIdent.Name != "len" {
			return true
		}

		// 获取标识符绑定的对象
		if obj, exists := info.Uses[funcIdent]; exists {
			switch obj.(type) {
			case *types.Builtin:
				log.Println("当前调用的是内置len函数")
			case *types.Func:
				log.Println("当前调用的是自定义len函数")
			default:
				log.Println("未知的函数类型")
			}
		}
		return false // 找到目标后停止遍历
	})
}

这段代码运行后会输出当前调用的是自定义len函数,因为类型检查器识别到当前作用域中存在自定义的len函数,优先级高于内置函数。


内容的提问来源于stack exchange,提问作者Rasel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 23:45:42