ast解析go文件

func main() {

	filepath.Walk("{项目路径}",
		func(path string, info os.FileInfo, err error) error {
			if !info.IsDir() {
				if strings.Contains(path, ".go") {
					fileAnalysis(path)
				}

			}
			return nil
		})

}

func fileAnalysis(path string) {
	fmt.Printf("当前文件路径:	%s\n", path)

	// package外部的包
	importPkgList := make([]string, 0)
	// 保存变量->包的映射关系
	referenceMapping := make(map[string]string, 0)
	// 函数内参数, 包含函数入参及函数内创建的新变量,在函数结束时需清除
	funcParam := make([]string, 0)
	// 记录函数的起始和结束位置
	funcStart, funcEnd := 0, 0
	funcName := ""
	// 函数内变量->包的映射关系,在函数结束时需清除
	var funcReferenceMapping map[string]string

	fset := token.NewFileSet()
	f, _ := parser.ParseFile(fset, path, nil, 0)

	ast.Inspect(f, func(node ast.Node) bool {
		if nil == node {
			return true
		}
		switch value := node.(type) {
		case *ast.File: // 入口文件,能拿到所有函数声明和函数:Decls、Scope.Objects、Unresolved
			// Decls: 包含GenDecl、FuncDecl
			// Scope.Objects: 文件内声明的变量、静态函数
			// Unresolved: 调用其他文件的包名
		case *ast.ImportSpec:
			// import文件
			referencePath := strings.Trim(value.Path.Value, "\"") // 被调包路径
			pathList := strings.Split(referencePath, "/")
			pathListLen := len(pathList)
			referenceName := pathList[pathListLen-1] // 被调用包的使用名称
			if nil != value.Name {
				// 别名
				referenceName = value.Name.Name
			}
			// 原生包不做处理
			if !isContain(basePkg, referencePath) {
				importPkgList = append(importPkgList, referenceName)
			}

			fmt.Printf("import文件:	%s  %s\n", referenceName, referencePath)
		case *ast.BasicLit:
			// 同import,简化内容
		case *ast.ValueSpec:
			// 变量声明
			switch childValue := value.Type.(type) {
			case *ast.Ident:
				// var aa, bb Xxx
				variableType := childValue.Name
				for _, variableName := range value.Names {
					funcParam = append(funcParam, variableName.Name)
					fmt.Printf("声明变量/类型:	%s:%s\n", variableName.Name, variableType)
				}
			case *ast.SelectorExpr:
				// var xx Xxx.Xxx
				for _, variableName := range value.Names {
					funcParam = append(funcParam, variableName.Name)
					fmt.Printf("声明变量/类型:	%s:%s.%s\n", variableName.Name, childValue.X.(*ast.Ident).Name, childValue.Sel.Name)
				}
			case *ast.StarExpr:
				// 引用型调用
				switch childValue.X.(type) {
				case *ast.Ident:
					// var aa, bb *Xxx
					variableType := childValue.X.(*ast.Ident).Name
					for _, variableName := range value.Names {
						fmt.Printf("声明变量/类型:	%s:%s\n", variableName.Name, variableType)
					}
				case *ast.SelectorExpr:
					// var aa, bb *xx.Xxx
					vType := childValue.X.(*ast.SelectorExpr)
					pkName := vType.X.(*ast.Ident).Name
					for _, variableName := range value.Names {
					fmt.Printf("声明变量/类型:	%s:%s.%s\n", variableName.Name, pkName, vType.Sel.Name)
					}
				}
			case nil:
				for _, variableName := range value.Names {
					funcParam = append(funcParam, variableName.Name)
					fmt.Printf("声明变量:	%s\n", variableName.Name)
				}
			}
		case *ast.TypeSpec:
			// type xx {}
			structName := value.Name.Name
			fmt.Printf("声明结构体:	%s\n", structName)
			// 结构体参数: paramList := value.Type.(*ast.StructType).Fields.List
		case *ast.FuncDecl:
			// 函数声明: 函数的具体使用
			// Name.Name 函数名
			// Type 函数解释Params、Results
			// Body.List 函数体
			fmt.Printf("函数名:  %s,起始:%v, 结束:%v\n", value.Name.Name, value.Pos(), value.End())
			funcName = value.Name.Name
			funcStart, _ = fmt.Printf("%v", value.Pos())
			funcEnd, _ = fmt.Printf("%v", value.End())
			funcParam = importPkgList
			funcReferenceMapping = referenceMapping
			// 函数入参处理
			for _, param := range value.Type.Params.List {
				switch param.Type.(type) {
				case *ast.StarExpr:
					// 指针型入参
					switch paramType := param.Type.(*ast.StarExpr).X.(type) {
					case *ast.SelectorExpr:
						// xx, *xx.Xxx
						pkgName := paramType.X.(*ast.Ident).Name
						funcName := paramType.Sel.Name
						for _, paramName := range param.Names {
							funcParam = append(funcParam, paramName.Name)
							fmt.Printf("函数入参/类型:	%s:%s.%s\n", paramName.Name, pkgName, funcName)
							referenceMapping[paramName.Name] = pkgName
						}
					case *ast.Ident:
						// xx, *Xxx
						pType := param.Type.(*ast.StarExpr).X.(*ast.Ident).Name
						for _, paramName := range param.Names {
							funcParam = append(funcParam, paramName.Name)
							fmt.Printf("函数入参/类型:	%s:%s\n", paramName.Name, pType)
							referenceMapping[paramName.Name] = pType
						}
					}
				case *ast.Ident:
					paramType := param.Type.(*ast.Ident).Name
					for _, paramName := range param.Names {
						funcParam = append(funcParam, paramName.Name)
						fmt.Printf("函数入参/类型:	%s:%s\n", paramName.Name, paramType)
					}
				}
			}
		case *ast.AssignStmt:
			// 变量初始化 xx := Xxxx   或  xx = Xxx
			switch value.Lhs[0].(type) {
			case *ast.SelectorExpr:
				// 变量赋值
				return true
			case *ast.Ident:
				variableName := value.Lhs[0].(*ast.Ident).Name
				funcParam = append(funcParam, variableName)
				switch rhs := value.Rhs[0].(type) {
				case *ast.CompositeLit:
					switch rhs.Type.(type) {
					case *ast.Ident:
						variableType := rhs.Type.(*ast.Ident).Name
						fmt.Printf("新变量/类型:  %s:%s\n", variableName, variableType)
					case *ast.SelectorExpr:
						return true
					}
				case *ast.CallExpr:
					//类似于 err := middleware.Decode(c.Request.Body, &param)
					return true
				}
			}
		case *ast.SelectorExpr:
			// 函数调用
			switch value.X.(type) {
			case *ast.SelectorExpr:
				// 存在SelectorExpr包SelectorExpr的情况,直接跳过交给下一级处理
				// TODO:存在多级调用的情况,这里不能跳过
				return true
			case *ast.Ident:
				pkName := value.X.(*ast.Ident).Name
				fuName := value.Sel.Name
				fmt.Printf("调用方法:	%s.%s\n", pkName, fuName)
				//if !isContain(funcParam, pkgName) {
				//	fmt.Printf("调用方法:	%s.%s\n", pkgName, funcName)
				//}
			}
		case *ast.Ident:
			// 所有节点的声明,无实际使用价值
			//fmt.Printf("Ident:	%s\n", value.Name)
		case *ast.GenDecl:
			// 导入声明: ast.GenDecl代表除函数以外的所有声明,即import、const、var和type
			// 子类型太多所以不考虑使用GenDecl
		case *ast.IfStmt:
			// 条件语句
			//for _, ifV := range value.Body.List {
			//	parsingExprStmt(ifV.(*ast.ExprStmt))
			//}
		case *ast.DeclStmt:
			// 变量声明 var xx Xxx,这里只有声明,没有类型,所以不做处理,交给ValueSpec进行解析
			//for _, param := range value.Decl.(*ast.GenDecl).Specs {
			//	for _, na := range param.(*ast.ValueSpec).Names {
			//		fmt.Printf("声明变量: %s\n", na.Name)
			//	}
			//}
		case *ast.CallExpr:
			// 内部调用,含私有函数和原生函数,因不涉及外部文件固不做处理
			switch value.Fun.(type) {
			case *ast.Ident:
				fmt.Printf("内部调用:  %s\n", value.Fun.(*ast.Ident).Name)
			}
		}

		return true
	})

	fmt.Printf("外部调用包: %s\n", importPkgList)

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值