Skip to content

Add exclude-private option #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Or using package manager `brew` on OS X

-L="": source file names are read from the specified file. If file is "-", input is read from standard in.
-R=false: recurse into directories in the file list.
-exclude-private=false: exclude private symbols.
-f="": write output to specified file. If file is "-", output is written to standard out.
-silent=false: do not produce any output on error.
-sort=true: sort tags.
Expand Down
22 changes: 12 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,16 @@ const (
)

var (
printVersion bool
inputFile string
outputFile string
recurse bool
sortOutput bool
silent bool
relative bool
listLangs bool
fields string
printVersion bool
inputFile string
outputFile string
recurse bool
sortOutput bool
silent bool
relative bool
listLangs bool
fields string
excludePrivate bool
)

// ignore unknown flags
Expand All @@ -47,6 +48,7 @@ func init() {
flags.BoolVar(&relative, "tag-relative", false, "file paths should be relative to the directory containing the tag file.")
flags.BoolVar(&listLangs, "list-languages", false, "list supported languages.")
flags.StringVar(&fields, "fields", "", "include selected extension fields (only +l).")
flags.BoolVar(&excludePrivate, "exclude-private", false, "exclude private symbols.")

flags.Usage = func() {
fmt.Fprintf(os.Stderr, "gotags version %s\n\n", Version)
Expand Down Expand Up @@ -180,7 +182,7 @@ func main() {

tags := []Tag{}
for _, file := range files {
ts, err := Parse(file, relative, basedir)
ts, err := Parse(file, relative, basedir, excludePrivate)
if err != nil {
if !silent {
fmt.Fprintf(os.Stderr, "parse error: %s\n\n", err)
Expand Down
50 changes: 31 additions & 19 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,25 @@ import (

// tagParser contains the data needed while parsing.
type tagParser struct {
fset *token.FileSet
tags []Tag // list of created tags
types []string // all types we encounter, used to determine the constructors
relative bool // should filenames be relative to basepath
basepath string // output file directory
fset *token.FileSet
tags []Tag // list of created tags
types []string // all types we encounter, used to determine the constructors
relative bool // should filenames be relative to basepath
basepath string // output file directory
excludePrivate bool // exclude private symbols
}

// Parse parses the source in filename and returns a list of tags. If relative
// is true, the filenames in the list of tags are relative to basepath.
func Parse(filename string, relative bool, basepath string) ([]Tag, error) {
// Parse parses the source in filename and returns a list of tags.
// If relative is true, the filenames in the list of tags are relative to basepath.
// If excludePrivate is true, any symbols that are not exported will be excluded.
func Parse(filename string, relative bool, basepath string, excludePrivate bool) ([]Tag, error) {
p := &tagParser{
fset: token.NewFileSet(),
tags: []Tag{},
types: make([]string, 0),
relative: relative,
basepath: basepath,
fset: token.NewFileSet(),
tags: []Tag{},
types: make([]string, 0),
relative: relative,
basepath: basepath,
excludePrivate: excludePrivate,
}

f, err := parser.ParseFile(p.fset, filename, nil, 0)
Expand Down Expand Up @@ -104,7 +107,7 @@ func (p *tagParser) parseFunction(f *ast.FuncDecl) {
tag.Type = Function
}

p.tags = append(p.tags, tag)
p.addTag(tag)
}

// parseTypeDeclaration creates a tag for type declaration ts and for each
Expand All @@ -127,7 +130,7 @@ func (p *tagParser) parseTypeDeclaration(ts *ast.TypeSpec) {
tag.Fields[TypeField] = getType(ts.Type, true)
}

p.tags = append(p.tags, tag)
p.addTag(tag)
}

// parseValueDeclaration creates a tag for each variable or constant declaration,
Expand All @@ -151,7 +154,8 @@ func (p *tagParser) parseValueDeclaration(v *ast.ValueSpec) {
case ast.Con:
tag.Type = Constant
}
p.tags = append(p.tags, tag)

p.addTag(tag)
}
}

Expand All @@ -166,15 +170,15 @@ func (p *tagParser) parseStructFields(name string, s *ast.StructType) {
tag.Fields[Access] = getAccess(tag.Name)
tag.Fields[ReceiverType] = name
tag.Fields[TypeField] = getType(f.Type, true)
p.tags = append(p.tags, tag)
p.addTag(tag)
}
} else {
// embedded field
tag = p.createTag(getType(f.Type, true), f.Pos(), Embedded)
tag.Fields[Access] = getAccess(tag.Name)
tag.Fields[ReceiverType] = name
tag.Fields[TypeField] = getType(f.Type, true)
p.tags = append(p.tags, tag)
p.addTag(tag)
}
}
}
Expand All @@ -200,7 +204,7 @@ func (p *tagParser) parseInterfaceMethods(name string, s *ast.InterfaceType) {

tag.Fields[InterfaceType] = name

p.tags = append(p.tags, tag)
p.addTag(tag)
}
}

Expand Down Expand Up @@ -249,6 +253,14 @@ func (p *tagParser) belongsToReceiver(types *ast.FieldList) (name string, ok boo
return "", false
}

// addTag adds tag to the list or is skipped if exclude private and tag is private
func (p *tagParser) addTag(tag Tag) {
if p.excludePrivate && tag.Fields[Access] != "public" {
return
}
p.tags = append(p.tags, tag)
}

// getTypes returns a comma separated list of types in fields. If includeNames is
// true each type is preceded by a comma separated list of parameter names.
func getTypes(fields *ast.FieldList, includeNames bool) string {
Expand Down
68 changes: 61 additions & 7 deletions parser_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"fmt"
"path/filepath"
"runtime"
"strconv"
Expand All @@ -10,11 +11,12 @@ import (
type F map[TagField]string

var testCases = []struct {
filename string
relative bool
basepath string
minversion string
tags []Tag
filename string
relative bool
basepath string
minversion string
tags []Tag
excludePrivate bool
}{
{filename: "tests/const.go-src", tags: []Tag{
tag("Test", 1, "p", F{}),
Expand Down Expand Up @@ -95,6 +97,51 @@ var testCases = []struct {
tag("fmt", 3, "i", F{}),
tag("main", 5, "f", F{"access": "private", "signature": "()"}),
}},
// excludePrivate tests
{filename: "tests/func.go-src", excludePrivate: true, tags: []Tag{
tag("Test", 1, "p", F{}),
tag("Function1", 3, "f", F{"access": "public", "signature": "()", "type": "string"}),
}},
{filename: "tests/interface.go-src", excludePrivate: true, tags: []Tag{
tag("Test", 1, "p", F{}),
tag("InterfaceMethod", 4, "m", F{"access": "public", "signature": "(int)", "ntype": "Interface", "type": "string"}),
tag("OtherMethod", 5, "m", F{"access": "public", "signature": "()", "ntype": "Interface"}),
tag("io.Reader", 6, "e", F{"access": "public", "ntype": "Interface"}),
tag("Interface", 3, "n", F{"access": "public", "type": "interface"}),
}},
{filename: "tests/struct.go-src", excludePrivate: true, tags: []Tag{
tag("Test", 1, "p", F{}),
tag("Field1", 4, "w", F{"access": "public", "ctype": "Struct", "type": "int"}),
tag("Field2", 4, "w", F{"access": "public", "ctype": "Struct", "type": "int"}),
tag("Struct", 3, "t", F{"access": "public", "type": "struct"}),
tag("Struct", 20, "e", F{"access": "public", "ctype": "TestEmbed", "type": "Struct"}),
tag("*io.Writer", 21, "e", F{"access": "public", "ctype": "TestEmbed", "type": "*io.Writer"}),
tag("TestEmbed", 19, "t", F{"access": "public", "type": "struct"}),
tag("Struct2", 27, "t", F{"access": "public", "type": "struct"}),
tag("Connection", 36, "t", F{"access": "public", "type": "struct"}),
tag("NewStruct", 9, "f", F{"access": "public", "ctype": "Struct", "signature": "()", "type": "*Struct"}),
tag("F1", 13, "m", F{"access": "public", "ctype": "Struct", "signature": "()", "type": "[]bool, [2]*string"}),
tag("F2", 16, "m", F{"access": "public", "ctype": "Struct", "signature": "()", "type": "bool"}),
tag("NewTestEmbed", 24, "f", F{"access": "public", "ctype": "TestEmbed", "signature": "()", "type": "TestEmbed"}),
tag("NewStruct2", 30, "f", F{"access": "public", "ctype": "Struct2", "signature": "()", "type": "*Struct2, error"}),
tag("Dial", 33, "f", F{"access": "public", "ctype": "Connection", "signature": "()", "type": "*Connection, error"}),
tag("Dial2", 39, "f", F{"access": "public", "ctype": "Connection", "signature": "()", "type": "*Connection, *Struct2"}),
tag("Dial3", 42, "f", F{"access": "public", "signature": "()", "type": "*Connection, *Connection"}),
}},
{filename: "tests/type.go-src", excludePrivate: true, tags: []Tag{
tag("Test", 1, "p", F{}),
}},
{filename: "tests/var.go-src", excludePrivate: true, tags: []Tag{
tag("Test", 1, "p", F{}),
tag("A", 7, "v", F{"access": "public"}),
tag("B", 8, "v", F{"access": "public"}),
tag("C", 8, "v", F{"access": "public"}),
tag("D", 9, "v", F{"access": "public"}),
}},
{filename: "tests/range.go-src", excludePrivate: true, minversion: "go1.4", tags: []Tag{
tag("main", 1, "p", F{}),
tag("fmt", 3, "i", F{}),
}},
}

func TestParse(t *testing.T) {
Expand All @@ -110,14 +157,21 @@ func TestParse(t *testing.T) {
continue
}

tags, err := Parse(testCase.filename, testCase.relative, basepath)
tags, err := Parse(testCase.filename, testCase.relative, basepath, testCase.excludePrivate)
if err != nil {
t.Errorf("[%s] Parse error: %s", testCase.filename, err)
continue
}

if len(tags) != len(testCase.tags) {
t.Errorf("[%s] len(tags) == %d, want %d", testCase.filename, len(tags), len(testCase.tags))
msg := fmt.Sprintf("[%s] len(tags) == %d, want %d",
testCase.filename,
len(tags),
len(testCase.tags))
if testCase.excludePrivate {
msg += " (exclude private)"
}
t.Error(msg)
continue
}

Expand Down