What's the recommended way to determine if a type.Type is exported?

281 views
Skip to first unread message

m...@tejas.io

unread,
Apr 24, 2017, 1:06:23 AM4/24/17
to golang-nuts
https://golang.org/pkg/go/types/#Type

Is there a helper function to determine whether a types.Type is exported? It seems like I can do some string parsing like

t := something.Type()
parts
:= strings.Split(t.String(), ".") // go/ast.Node => ["go/ast", "Node"]
ident
:= parts[len(parts)-1] // "Node"
exported
:= strings.IsUpper(ident[0])

but I imagine there's a simpler, more robust way. The end goal is to find out whether a type of a method argument is exported-- e.g.
namedType := obj.Type().(*types.Named)
method
:= namedType.Method(0)
signature
:= method.Type().(*types.Signature)
signature
.Params().At(0).Type() // is this exported?

And, for some context, all of this is from walking go/ast

Axel Wagner

unread,
Apr 24, 2017, 2:11:13 AM4/24/17
to m...@tejas.io, golang-nuts
I'd say, probably type-asserting to a *types.TypeName and then use Exported() (the code of which also leads to ast.IsExported).

Side-note: You probably shouldn't rely on parsing the output of String() of any value, just as you shouldn't rely on parsing the output of error.Error().

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Tejas Manohar

unread,
Apr 24, 2017, 3:49:19 AM4/24/17
to Axel Wagner, golang-nuts
Agreed! I ended up casting to types.NamedType (or pointer then elem())... I'll try your method too!
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--

Best regards,

Tejas Manohar

Kevin Conway

unread,
Apr 24, 2017, 3:55:49 AM4/24/17
to Tejas Manohar, Axel Wagner, golang-nuts
Alternatively, if you are walking an AST and only interested in the exported names then you can use https://golang.org/pkg/go/ast/#PackageExports . It will filter your tree to only elements that are exported before you begin traversal.

As to your specific case of determining if a type used in a method signature is exported, I'd ask: Does it matter if the source package is the same one where the method is defined or is it any non-builtin, exported types used in the signature?

I believe the case of "exported name used in a method within the same package" can be determined by iterating of the 'Params.List' attribute of the ast.FuncType and looking for elements of the slice that are of type '*ast.Ident' and checking the corresponding 'IsExported' method call results. For complete coverage, you'd also need to check for *ast.ArrayType, *ast.ChanType, *ast.MapType, *ast.Ellipsis (for uses of the type as a variadic), *ast.FuncType (and its corresponding arguments and return types), and *ast.StarExpr (for uses of the type as a pointer).

The case of "any non-builtin, exported type from any package" would use the previous logic but also add in checking for elements of 'Params.List' that are of type '*ast.SelectorExpr'. While I'm sure there is a case where this is not true, the elements of type *ast.SelectorExpr in the parameter list of an *ast.FuncType are usually references to a type exported by another package (think "http.Handler"). The 'X' attribute can be converted to *ast.Ident for the source package name and the 'Sel' attribute contains the name of the referenced type. Note that the package name might actually be a local alias when the file imports with ' import myname "net/http" '.


PS the implementation of 'IsExported' used by everything checks the capitalisation of the first letter to make its choice: https://golang.org/src/go/ast/ast.go?s=16357:16390#L516  

m...@tejas.io

unread,
Apr 29, 2017, 8:05:59 PM4/29/17
to golang-nuts, m...@tejas.io
What exactly would you cast to *types.TypeName, btw? Looks like *types.TypeName is not a types.Type (missing Underlying() method).
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Axel Wagner

unread,
Apr 30, 2017, 1:58:47 AM4/30/17
to Tejas Manohar, golang-nuts
Ah sorry, I apparently didn't pay close attention then. The correct way is to type-assert to *types.Named and then use it's Obj() method, I guess. :)


BTW: It's not "casting", but "type-asserting". "casting" (go calls it "converting") is, when you have something with concrete type T1 and convert it into something of concrete type T2 (changing the underlying representation, if necessary), so e.g.
x := 42
y := float64(x)
"Type-asserting" is, when you have an interface type and are saying "please unpack this interface; I think the concrete type X is in it" and entails a runtime-check that the interface actually has that concrete value and then unpack it.

i.e. type conversion ("casting") is to go from concrete type T1 to concrete type T2, type-assertions are to go from interface type IT to concrete type CT.

To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages