List all imported types given an import path

Viewed 400

I am trying to list all imported types from a given import path at runtime. Sample code:

package main

import (
    "fmt"
    "go/importer"
)

func main() {
    pkg, err := importer.Default().Import("github.com/aler9/goroslib/pkg/msgs/std_msgs") 
    if err != nil {
        fmt.Println("error:", err)
        return
    }
    for _, declName := range pkg.Scope().Names() {
        fmt.Println(declName)
    }
}

This results in error:

error: can't find import: "github.com/aler9/goroslib/pkg/msgs/std_msgs"

It is possbile to achieve what I want with Golang?


Note:

I am aware of the post: How to use go importer

By using pkg, err := importer.Default().Import("github.com/aler9/goroslib") the binary returns a few types but they are not what I want.


1 Answers

I don't know how to do it with go/importer, or even if it's possible.

However, you could, for example, use the golang.org/x/tools/go/packages package to load a package's AST and then traverse that tree to print out any type declarations you find.

package main

import (
    "fmt"
    "go/ast"
    "go/token"
    "golang.org/x/tools/go/packages"
)

func main() {
    loadConfig := new(packages.Config)
    loadConfig.Mode = packages.NeedSyntax
    loadConfig.Fset = token.NewFileSet()
    pkgs, err := packages.Load(loadConfig, "encoding/json")
    if err != nil {
        panic(err)
    }

    for _, pkg := range pkgs {
        for _, syn := range pkg.Syntax {
            for _, dec := range syn.Decls {
                if gen, ok := dec.(*ast.GenDecl); ok && gen.Tok == token.TYPE {
                    for _, spec := range gen.Specs {
                        if ts, ok := spec.(*ast.TypeSpec); ok {
                            fmt.Println(ts.Name)
                        }
                    }
                }
            }
        }
    }
}

NOTE #1: The above example will print exported and unexported types. If you want to print exported only you can add an if condition to check for ts.Name.IsExported.

NOTE #2: The package you want to load, if I'm not mistaken, must already be in your module cache because packages.Load will not go over the network and download it if it's not there.

Related