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, ¶m)
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)
}
04-23
409

08-09
1686

11-13
1104

07-27
495

09-30
3148
