cmd/stringer: add flag to use line comment as str
This can be very helpful if you lay out each value's string
representation like this:
and // &
andAnd // &&
or // |
orOr // ||
Without the use of comments, it's impossible to use stringer with these
names as the characters & and | cannot form valid identifiers in a Go
program.
Fixes #20483.
Change-Id: I4d36c74059dd48ae3a5e09b70a429a75853ef179
Reviewed-on: https://go-review.googlesource.com/44076
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/cmd/stringer/golden_test.go b/cmd/stringer/golden_test.go
index 12bd538..4ba7788 100644
--- a/cmd/stringer/golden_test.go
+++ b/cmd/stringer/golden_test.go
@@ -16,20 +16,22 @@
// Golden represents a test case.
type Golden struct {
- name string
- trimPrefix string
- input string // input; the package clause is provided when running the test.
- output string // exected output.
+ name string
+ trimPrefix string
+ lineComment bool
+ input string // input; the package clause is provided when running the test.
+ output string // exected output.
}
var golden = []Golden{
- {"day", "", day_in, day_out},
- {"offset", "", offset_in, offset_out},
- {"gap", "", gap_in, gap_out},
- {"num", "", num_in, num_out},
- {"unum", "", unum_in, unum_out},
- {"prime", "", prime_in, prime_out},
- {"prefix", "Type", prefix_in, prefix_out},
+ {"day", "", false, day_in, day_out},
+ {"offset", "", false, offset_in, offset_out},
+ {"gap", "", false, gap_in, gap_out},
+ {"num", "", false, num_in, num_out},
+ {"unum", "", false, unum_in, unum_out},
+ {"prime", "", false, prime_in, prime_out},
+ {"prefix", "Type", false, prefix_in, prefix_out},
+ {"tokens", "", true, tokens_in, tokens_out},
}
// Each example starts with "type XXX [u]int", with a single space separating them.
@@ -264,9 +266,42 @@
}
`
+const tokens_in = `type Token int
+const (
+ And Token = iota // &
+ Or // |
+ Add // +
+ Sub // -
+ Ident
+ Period // .
+
+ // not to be used
+ SingleBefore
+ // not to be used
+ BeforeAndInline // inline
+ InlineGeneral /* inline general */
+)
+`
+
+const tokens_out = `
+const _Token_name = "&|+-Ident.SingleBeforeinlineinline general"
+
+var _Token_index = [...]uint8{0, 1, 2, 3, 4, 9, 10, 22, 28, 42}
+
+func (i Token) String() string {
+ if i < 0 || i >= Token(len(_Token_index)-1) {
+ return "Token(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _Token_name[_Token_index[i]:_Token_index[i+1]]
+}
+`
+
func TestGolden(t *testing.T) {
for _, test := range golden {
- g := Generator{trimPrefix: test.trimPrefix}
+ g := Generator{
+ trimPrefix: test.trimPrefix,
+ lineComment: test.lineComment,
+ }
input := "package test\n" + test.input
file := test.name + ".go"
g.parsePackage(".", []string{file}, input)
diff --git a/cmd/stringer/stringer.go b/cmd/stringer/stringer.go
index 90c81bf..4b8d1ba 100644
--- a/cmd/stringer/stringer.go
+++ b/cmd/stringer/stringer.go
@@ -78,9 +78,10 @@
)
var (
- typeNames = flag.String("type", "", "comma-separated list of type names; must be set")
- output = flag.String("output", "", "output file name; default srcdir/<type>_string.go")
- trimprefix = flag.String("trimprefix", "", "trim the `prefix` from the generated constant names")
+ typeNames = flag.String("type", "", "comma-separated list of type names; must be set")
+ output = flag.String("output", "", "output file name; default srcdir/<type>_string.go")
+ trimprefix = flag.String("trimprefix", "", "trim the `prefix` from the generated constant names")
+ linecomment = flag.Bool("linecomment", false, "use line comment text as printed text when present")
)
// Usage is a replacement usage function for the flags package.
@@ -114,7 +115,10 @@
// Parse the package once.
var dir string
- g := Generator{trimPrefix: *trimprefix}
+ g := Generator{
+ trimPrefix: *trimprefix,
+ lineComment: *linecomment,
+ }
if len(args) == 1 && isDirectory(args[0]) {
dir = args[0]
g.parsePackageDir(args[0])
@@ -165,7 +169,8 @@
buf bytes.Buffer // Accumulated output.
pkg *Package // Package we are scanning.
- trimPrefix string
+ trimPrefix string
+ lineComment bool
}
func (g *Generator) Printf(format string, args ...interface{}) {
@@ -180,7 +185,8 @@
typeName string // Name of the constant type.
values []Value // Accumulator for constant values of that type.
- trimPrefix string
+ trimPrefix string
+ lineComment bool
}
type Package struct {
@@ -237,15 +243,16 @@
if !strings.HasSuffix(name, ".go") {
continue
}
- parsedFile, err := parser.ParseFile(fs, name, text, 0)
+ parsedFile, err := parser.ParseFile(fs, name, text, parser.ParseComments)
if err != nil {
log.Fatalf("parsing package: %s: %s", name, err)
}
astFiles = append(astFiles, parsedFile)
files = append(files, &File{
- file: parsedFile,
- pkg: g.pkg,
- trimPrefix: g.trimPrefix,
+ file: parsedFile,
+ pkg: g.pkg,
+ trimPrefix: g.trimPrefix,
+ lineComment: g.lineComment,
})
}
if len(astFiles) == 0 {
@@ -457,6 +464,9 @@
signed: info&types.IsUnsigned == 0,
str: value.String(),
}
+ if c := vspec.Comment; f.lineComment && c != nil && len(c.List) == 1 {
+ v.name = strings.TrimSpace(c.Text())
+ }
v.name = strings.TrimPrefix(v.name, f.trimPrefix)
f.values = append(f.values, v)
}