diff --git a/cmd/stringer/stringer.go b/cmd/stringer/stringer.go index 5edea7bf..57d3a723 100644 --- a/cmd/stringer/stringer.go +++ b/cmd/stringer/stringer.go @@ -428,10 +428,24 @@ func (f *File) genDecl(node ast.Node) bool { for _, spec := range decl.Specs { vspec := spec.(*ast.ValueSpec) // Guaranteed to succeed as this is CONST. if vspec.Type == nil && len(vspec.Values) > 0 { - // "X = 1". With no type but a value, the constant is untyped. - // Skip this vspec and reset the remembered type. + // "X = 1". With no type but a value. If the constant is untyped, + // skip this vspec and reset the remembered type. typ = "" - continue + + // If this is a simple type conversion, remember the type. + // We don't mind if this is actually a call; a qualified call won't + // be matched (that will be SelectorExpr, not Ident), and only unusual + // situations will result in a function call that appears to be + // a type conversion. + ce, ok := vspec.Values[0].(*ast.CallExpr) + if !ok { + continue + } + id, ok := ce.Fun.(*ast.Ident) + if !ok { + continue + } + typ = id.Name } if vspec.Type != nil { // "X T". We have a type. Remember it. diff --git a/cmd/stringer/testdata/conv.go b/cmd/stringer/testdata/conv.go new file mode 100644 index 00000000..9a9dc644 --- /dev/null +++ b/cmd/stringer/testdata/conv.go @@ -0,0 +1,41 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Check that constants defined as a conversion are accepted. + +package main + +import "fmt" + +type Other int // Imagine this is in another package. + +const ( + alpha Other = iota + beta + gamma + delta +) + +type Conv int + +const ( + Alpha = Conv(alpha) + Beta = Conv(beta) + Gamma = Conv(gamma) + Delta = Conv(delta) +) + +func main() { + ck(Alpha, "Alpha") + ck(Beta, "Beta") + ck(Gamma, "Gamma") + ck(Delta, "Delta") + ck(42, "Conv(42)") +} + +func ck(c Conv, str string) { + if fmt.Sprint(c) != str { + panic("conv.go: " + str) + } +}