How to use the Golang FileExports function in ast package
The Abstract Syntax Tree
The abstract syntax tree (AST) is an abstract representation of the source code. Here abstract means this representation discards all the information that does not change the semantic of the source code (braces, semicolons, parentheses, etc.).
Many code editors, linters, and formatters use AST to inspect or analyze the source code.
Listing all the exported function names with ast package
In Go, a name is exported if it begins with a capital letter. Let’s use ast package to get all the exported function names in the source code. The ast package provides the following function:
func FileExports(src *File) bool
FileExports trims the AST for a Go source file in place, such that only exported nodes/names remain. We can use this function and filter function declaration nodes that are exported.
The following function takes a source filename and mode exportOnly.
If exportOnly is set to true, then it returns exported function names only. When set to false, all the function names are returned.
func funcNames(filename string, exportOnly bool) []string {
fset := token.NewFileSet()
file , _ := parser.ParseFile(fset, filename, nil, 0)
if exportOnly {
ast.FileExports(ast) // trim AST
}
funcNames := []string{}
for _, decl := range ast.Decls {
fn, ok := decl.(*ast.FuncDecl) // assert type of declaration
if !ok {
continue
}
funcNames = append(funcNames, fn.Name.Name)
}
return funcNames
}
The function does the following:
- Create a
FileSetto store source file. - Parse the source file using
ParseFilethat returns*ast.Filenode. - Trim the AST based on
exportedOnlymode. - Loop over all declaration in the file.
- Assert if the node is a function declaration type. If not, then check the next declaration.
- Otherwise, access the name of the function and append it to the result.
- Return the list of function names.
This is the complete source code. This is where to inspect the source.go file, which contains two exported and two un-exported functions.
package mainimport ("fmt""go/ast""go/parser""go/token")func main() {path := "source.go"names := funcNames(path, false)fmt.Println("All functions")printSlice(names)names = funcNames(path, true)fmt.Println("Exported functions:")printSlice(names)}func funcNames(filename string, exportOnly bool) []string {fset := token.NewFileSet()file , _ := parser.ParseFile(fset, filename, nil, 0)if exportOnly {ast.FileExports(file) // trim AST}funcNames := []string{}for _, decl := range file.Decls {fn, ok := decl.(*ast.FuncDecl) // assert type of declarationif !ok {continue}funcNames = append(funcNames, fn.Name.Name)}return funcNames}
You can learn more about this topic from the following: